) => void;
+ state: AddCloudStorageState;
+ storage: CloudStorageDetails;
+ storageSecrets: CloudStorageSecretGet[];
+}
+
+interface AddOrEditCloudStoragePropsV2 extends AddOrEditCloudStorageProps {
+ validationSucceeded: boolean;
+}
+
+interface DataConnectorModalBodyProps extends AddCloudStorageBodyContentProps {
+ storageSecrets: CloudStorageSecretGet[];
+}
+
+export default function DataConnectorModalBody({
+ addResultStorageName,
+ credentialSaveStatus,
+ redraw,
+ schema,
+ schemaError,
+ schemaIsFetching,
+ setStateSafe,
+ setStorageDetailsSafe,
+ state,
+ storageDetails,
+ storageId,
+ storageSecrets,
+ success,
+ validationSucceeded,
+}: DataConnectorModalBodyProps) {
+ if (redraw) return ;
+ if (success) {
+ return (
+
+ );
+ }
+ if (schemaIsFetching || !schema) return ;
+ if (schemaError) return ;
+ return (
+ <>
+ {!storageId && (
+
+ Add published datasets from data repositories for use in your project.
+ Or, connect to cloud storage to read and write custom data.
+
+ )}
+
+ >
+ );
+}
+
+function AddOrEditCloudStorageV2({
+ schema,
+ setStorage,
+ setState,
+ state,
+ storage,
+ storageSecrets,
+ validationSucceeded,
+}: AddOrEditCloudStoragePropsV2) {
+ const ContentByStep =
+ state.step >= 0 && state.step <= CLOUD_STORAGE_TOTAL_STEPS
+ ? mapStepToElement[state.step]
+ : null;
+
+ if (ContentByStep)
+ return (
+ <>
+
+
+ >
+ );
+ return Error - not implemented yet
;
+}
+
+// *** Add storage: helpers *** //
+interface AddStorageStepProps {
+ schema: CloudStorageSchema[];
+ setStorage: (newDetails: Partial) => void;
+ setState: (newState: Partial) => void;
+ state: AddCloudStorageState;
+ storage: CloudStorageDetails;
+ storageSecrets: CloudStorageSecretGet[];
+ isV2?: boolean;
+ validationSucceeded: boolean;
+}
+
+const mapStepToElement: {
+ [key: number]: React.ComponentType;
+} = {
+ 0: AddStorageAdvanced,
+ 1: AddStorageType,
+ 2: AddStorageOptions,
+ 3: AddStorageMount,
+};
diff --git a/client/src/features/project/components/cloudStorage/AddOrEditCloudStorage.tsx b/client/src/features/project/components/cloudStorage/AddOrEditCloudStorage.tsx
index 578c03266..f70e5071f 100644
--- a/client/src/features/project/components/cloudStorage/AddOrEditCloudStorage.tsx
+++ b/client/src/features/project/components/cloudStorage/AddOrEditCloudStorage.tsx
@@ -35,8 +35,6 @@ import {
import { Control, Controller, FieldValues, useForm } from "react-hook-form";
import {
Badge,
- Breadcrumb,
- BreadcrumbItem,
Button,
Input,
InputGroup,
@@ -70,6 +68,7 @@ import { ExternalLink } from "../../../../components/ExternalLinks";
import { WarnAlert } from "../../../../components/Alert";
import type { CloudStorageSecretGet } from "../../../../features/projectsV2/api/storagesV2.api";
+import AddStorageBreadcrumbNavbar from "./AddStorageBreadcrumbNavbar";
import AddStorageMountSaveCredentialsInfo from "./AddStorageMountSaveCredentialsInfo";
import styles from "./CloudStorage.module.scss";
@@ -114,104 +113,11 @@ export default function AddOrEditCloudStorage({
return Error - not implemented yet
;
}
-interface AddOrEditCloudStoragePropsV2 extends AddOrEditCloudStorageProps {
- validationSucceeded: boolean;
-}
-
-export function AddOrEditCloudStorageV2({
- schema,
- setStorage,
- setState,
- state,
- storage,
- storageSecrets,
- validationSucceeded,
-}: AddOrEditCloudStoragePropsV2) {
- const ContentByStep =
- state.step >= 0 && state.step <= CLOUD_STORAGE_TOTAL_STEPS
- ? mapStepToElement[state.step]
- : null;
-
- if (ContentByStep)
- return (
- <>
-
-
- >
- );
- return Error - not implemented yet
;
-}
-
-// *** Navigation: breadcrumbs and advanced mode selector *** //
-
-interface AddStorageBreadcrumbNavbarProps {
- setState: (newState: Partial) => void;
- state: AddCloudStorageState;
-}
-
-export function AddStorageBreadcrumbNavbar({
- setState,
- state,
-}: AddStorageBreadcrumbNavbarProps) {
- const { step, completedSteps } = state;
- const items = useMemo(() => {
- const steps = state.advancedMode
- ? [0, CLOUD_STORAGE_TOTAL_STEPS]
- : Array.from(
- { length: CLOUD_STORAGE_TOTAL_STEPS },
- (_, index) => index + 1
- );
- const items = steps.map((stepNumber) => {
- const active = stepNumber === step;
- const disabled = stepNumber > completedSteps + 1;
- return (
-
- {active ? (
- <>{mapStepToName[stepNumber]}>
- ) : (
- <>
-
- >
- )}
-
- );
- });
- return items;
- }, [completedSteps, setState, step, state.advancedMode]);
-
- return (
- {items}
- );
-}
-
interface AddStorageAdvancedToggleProps {
setState: (newState: Partial) => void;
state: AddCloudStorageState;
}
-function AddStorageAdvancedToggle({
+export function AddStorageAdvancedToggle({
setState,
state,
}: AddStorageAdvancedToggleProps) {
@@ -275,18 +181,15 @@ const mapStepToElement: {
2: AddStorageOptions,
3: AddStorageMount,
};
-const mapStepToName: { [key: number]: string } = {
- 0: "Advanced configuration",
- 1: "Storage",
- 2: "Options",
- 3: "Mount",
-};
interface AddStorageAdvancedForm {
sourcePath: string;
configuration: string;
}
-function AddStorageAdvanced({ storage, setStorage }: AddStorageStepProps) {
+export function AddStorageAdvanced({
+ storage,
+ setStorage,
+}: AddStorageStepProps) {
const {
control,
formState: { errors },
@@ -707,7 +610,7 @@ function InputOptionItem({
// *** Add storage: page 1 of 3, with storage type and provider *** //
-function AddStorageType({
+export function AddStorageType({
schema,
state,
storage,
@@ -937,7 +840,7 @@ function AddStorageType({
}
// *** Add storage: page 2 of 3, with storage options *** //
-function AddStorageOptions({
+export function AddStorageOptions({
isV2,
schema,
setState,
@@ -1110,7 +1013,7 @@ type AddStorageMountFormFields =
| "mountPoint"
| "readOnly"
| "saveCredentials";
-function AddStorageMount({
+export function AddStorageMount({
isV2,
schema,
setStorage,
diff --git a/client/src/features/project/components/cloudStorage/AddOrEditCloudStorageButton.tsx b/client/src/features/project/components/cloudStorage/AddOrEditCloudStorageButton.tsx
index 86b64bcc9..34500c6a1 100644
--- a/client/src/features/project/components/cloudStorage/AddOrEditCloudStorageButton.tsx
+++ b/client/src/features/project/components/cloudStorage/AddOrEditCloudStorageButton.tsx
@@ -72,7 +72,6 @@ export default function AddOrEditCloudStorageButton({
isOpen={isOpen}
toggle={toggle}
projectId={projectId}
- isV2={false}
/>
>
diff --git a/client/src/features/project/components/cloudStorage/AddStorageBreadcrumbNavbar.tsx b/client/src/features/project/components/cloudStorage/AddStorageBreadcrumbNavbar.tsx
new file mode 100644
index 000000000..c99681629
--- /dev/null
+++ b/client/src/features/project/components/cloudStorage/AddStorageBreadcrumbNavbar.tsx
@@ -0,0 +1,85 @@
+/*!
+ * Copyright 2024 - Swiss Data Science Center (SDSC)
+ * A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and
+ * Eidgenössische Technische Hochschule Zürich (ETHZ).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import cx from "classnames";
+import { useMemo } from "react";
+import { Breadcrumb, BreadcrumbItem, Button } from "reactstrap";
+
+import { CLOUD_STORAGE_TOTAL_STEPS } from "./projectCloudStorage.constants";
+import { AddCloudStorageState } from "./projectCloudStorage.types";
+
+// *** Navigation: breadcrumbs and advanced mode selector *** //
+
+interface AddStorageBreadcrumbNavbarProps {
+ setState: (newState: Partial) => void;
+ state: AddCloudStorageState;
+}
+
+export default function AddStorageBreadcrumbNavbar({
+ setState,
+ state,
+}: AddStorageBreadcrumbNavbarProps) {
+ const { step, completedSteps } = state;
+ const items = useMemo(() => {
+ const steps = state.advancedMode
+ ? [0, CLOUD_STORAGE_TOTAL_STEPS]
+ : Array.from(
+ { length: CLOUD_STORAGE_TOTAL_STEPS },
+ (_, index) => index + 1
+ );
+ const items = steps.map((stepNumber) => {
+ const active = stepNumber === step;
+ const disabled = stepNumber > completedSteps + 1;
+ return (
+
+ {active ? (
+ <>{mapStepToName[stepNumber]}>
+ ) : (
+ <>
+
+ >
+ )}
+
+ );
+ });
+ return items;
+ }, [completedSteps, setState, step, state.advancedMode]);
+
+ return (
+ {items}
+ );
+}
+
+const mapStepToName: { [key: number]: string } = {
+ 0: "Advanced configuration",
+ 1: "Storage",
+ 2: "Options",
+ 3: "Mount",
+};
diff --git a/client/src/features/project/components/cloudStorage/CloudStorageModal.tsx b/client/src/features/project/components/cloudStorage/CloudStorageModal.tsx
index 34d34bd99..e40e4ed85 100644
--- a/client/src/features/project/components/cloudStorage/CloudStorageModal.tsx
+++ b/client/src/features/project/components/cloudStorage/CloudStorageModal.tsx
@@ -24,16 +24,6 @@ import { ArrowCounterclockwise } from "react-bootstrap-icons";
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from "reactstrap";
import { RtkOrNotebooksError } from "../../../../components/errors/RtkErrorAlert";
-import { usePostStoragesV2ByStorageIdSecretsMutation } from "../../../projectsV2/api/projectV2.enhanced-api";
-import {
- CloudStorageGetRead,
- CloudStorageGetV2Read,
- CloudStoragePatch,
- PostStoragesV2ApiArg,
- RCloneConfig,
- usePatchStoragesV2ByStorageIdMutation,
- usePostStoragesV2Mutation,
-} from "../../../projectsV2/api/storagesV2.api";
import {
findSensitive,
@@ -41,7 +31,6 @@ import {
getSchemaProviders,
hasProviderShortlist,
} from "../../utils/projectCloudStorage.utils";
-import { AddStorageBreadcrumbNavbar } from "./AddOrEditCloudStorage";
import {
useAddCloudStorageForProjectMutation,
useGetCloudStorageSchemaQuery,
@@ -76,22 +65,16 @@ import {
import styles from "./CloudStorage.module.scss";
interface CloudStorageModalProps {
- currentStorage?:
- | CloudStorage
- | CloudStorageGetRead
- | CloudStorageGetV2Read
- | null;
+ currentStorage?: CloudStorage | null;
isOpen: boolean;
toggle: () => void;
projectId: string;
- isV2: boolean;
}
export default function CloudStorageModal({
currentStorage = null,
isOpen,
toggle: originalToggle,
projectId,
- isV2 = false,
}: CloudStorageModalProps) {
const storageId = currentStorage?.storage.storage_id ?? null;
// Fetch available schema when users open the modal
@@ -179,14 +162,8 @@ export default function CloudStorageModal({
// Mutations
const [addCloudStorageForProject, addResult] =
useAddCloudStorageForProjectMutation();
- const [addCloudStorageForProjectV2, addResultV2] =
- usePostStoragesV2Mutation();
const [modifyCloudStorageForProject, modifyResult] =
useUpdateCloudStorageMutation();
- const [modifyCloudStorageV2ForProject, modifyResultV2] =
- usePatchStoragesV2ByStorageIdMutation();
- const [saveCredentials, saveCredentialsResult] =
- usePostStoragesV2ByStorageIdSecretsMutation();
const [validateCloudStorageConnection, validationResult] =
useTestCloudStorageConnectionMutation();
@@ -203,14 +180,13 @@ export default function CloudStorageModal({
...EMPTY_CLOUD_STORAGE_STATE,
}
);
- addResultV2.reset();
validationResult.reset();
setStorageDetails(resetStatus);
setSuccess(false);
setCredentialSaveStatus("none");
setValidationSucceeded(false);
setRedraw(true); // This forces re-loading the useForm fields
- }, [addResultV2, currentStorage, validationResult]);
+ }, [currentStorage, validationResult]);
const setStorageDetailsSafe = useCallback(
(newStorageDetails: Partial) => {
@@ -262,10 +238,7 @@ export default function CloudStorageModal({
}, [storageDetails, validateCloudStorageConnection]);
const addOrEditStorage = useCallback(() => {
- const storageParameters:
- | AddCloudStorageForProjectParams
- | CloudStorage
- | CloudStoragePatch = {
+ const storageParameters: AddCloudStorageForProjectParams | CloudStorage = {
name: storageDetails.name as string,
readonly: storageDetails.readOnly ?? true,
project_id: `${projectId}`,
@@ -313,59 +286,26 @@ export default function CloudStorageModal({
// We manually set success only when we get an ID back. That's just to sho a success message
if (storageId) {
// v1
- if (isV2) {
- const cloudStoragePatch: CloudStoragePatch = {
- project_id: projectId,
- name: storageParameters.name,
- configuration: storageParameters.configuration as RCloneConfig,
- source_path: storageParameters.source_path,
- target_path: storageParameters.target_path,
- readonly: storageParameters.readonly,
- };
- modifyCloudStorageV2ForProject({
- storageId: storageId,
- cloudStoragePatch,
- }).then((result) => {
- if ("data" in result && result.data.storage.storage_id) {
- setSuccess(true);
- }
- });
- } else {
- const storageParametersWithId: UpdateCloudStorageParams = {
- ...storageParameters,
- storage_id: storageId as string,
- };
- modifyCloudStorageForProject(storageParametersWithId).then((result) => {
- if ("data" in result && result.data.storage.storage_id) {
- setSuccess(true);
- }
- });
- }
+ const storageParametersWithId: UpdateCloudStorageParams = {
+ ...storageParameters,
+ storage_id: storageId as string,
+ };
+ modifyCloudStorageForProject(storageParametersWithId).then((result) => {
+ if ("data" in result && result.data.storage.storage_id) {
+ setSuccess(true);
+ }
+ });
} else {
- if (isV2) {
- const parameterV2 = {
- body: storageParameters,
- } as PostStoragesV2ApiArg;
- addCloudStorageForProjectV2(parameterV2).then((result) => {
- if ("data" in result && result.data.storage.storage_id) {
- setSuccess(true);
- }
- });
- } else {
- addCloudStorageForProject(storageParameters).then((result) => {
- if ("data" in result && result.data.storage.storage_id) {
- setSuccess(true);
- }
- });
- }
+ addCloudStorageForProject(storageParameters).then((result) => {
+ if ("data" in result && result.data.storage.storage_id) {
+ setSuccess(true);
+ }
+ });
}
}, [
addCloudStorageForProject,
- addCloudStorageForProjectV2,
currentStorage,
- isV2,
modifyCloudStorageForProject,
- modifyCloudStorageV2ForProject,
projectId,
schema,
storageDetails,
@@ -380,10 +320,9 @@ export default function CloudStorageModal({
setSuccess(false);
reset();
} else {
- addResultV2.reset();
validationResult.reset();
}
- }, [addResultV2, originalToggle, reset, success, validationResult]);
+ }, [originalToggle, reset, success, validationResult]);
// Handle unmount
useEffect(() => {
@@ -399,89 +338,17 @@ export default function CloudStorageModal({
[storageDetails.schema]
);
- useEffect(() => {
- const storageId = addResultV2.data?.storage?.storage_id;
- if (storageId == null) return;
- const shouldSaveCredentials = shouldSaveCredentialsV2(
- isV2,
- storageDetails.options,
- state.saveCredentials,
- validationSucceeded
- );
- if (!shouldSaveCredentials) {
- return;
- }
- const options = storageDetails.options as CloudStorageDetailsOptions;
- if (!schema) return;
- const sensitiveFieldNames = findSensitive(
- schema.find((s) => s.prefix === storageDetails.schema)
- );
- const cloudStorageSecretPostList = sensitiveFieldNames
- .map((name) => ({
- name,
- value: options[name],
- }))
- .filter((secret) => secret.value != undefined && secret.value != "")
- .map((secret) => ({
- name: secret.name,
- value: "" + secret.value,
- }));
- saveCredentials({
- storageId,
- cloudStorageSecretPostList,
- });
- }, [
- addResultV2.data?.storage?.storage_id,
- isV2,
- saveCredentials,
- state.saveCredentials,
- schema,
- storageDetails.options,
- storageDetails.schema,
- validationSucceeded,
- ]);
-
- useEffect(() => {
- if (!validationSucceeded) {
- setCredentialSaveStatus("none");
- return;
- }
- if (
- addResultV2.data?.storage?.storage_id == null ||
- saveCredentialsResult.isUninitialized
- ) {
- setCredentialSaveStatus("none");
- return;
- }
- if (saveCredentialsResult.isLoading) {
- setCredentialSaveStatus("trying");
- return;
- }
- if (saveCredentialsResult.isSuccess) {
- setCredentialSaveStatus("success");
- return;
- }
- if (saveCredentialsResult.isError) {
- setCredentialSaveStatus("failure");
- return;
- }
- setCredentialSaveStatus("none");
- }, [addResultV2, saveCredentialsResult, validationSucceeded]);
-
// Visual elements
const disableContinueButton =
state.step === 1 &&
(!storageDetails.schema ||
(schemaRequiresProvider && !storageDetails.provider));
- const isAddResultLoading = addResult.isLoading || addResultV2.isLoading;
- const isModifyResultLoading =
- modifyResult.isLoading || modifyResultV2.isLoading;
- const addResultError = isV2 ? addResultV2.error : addResult.error;
- const modifyResultError = isV2 ? modifyResultV2.error : modifyResult.error;
- const addResultStorageName = isV2
- ? addResultV2?.data?.storage?.name
- : addResult?.data?.storage?.name;
+ const isAddResultLoading = addResult.isLoading;
+ const isModifyResultLoading = modifyResult.isLoading;
+ const addResultError = addResult.error;
+ const modifyResultError = modifyResult.error;
+ const addResultStorageName = addResult?.data?.storage?.name;
const disableAddButton =
isAddResultLoading ||
@@ -503,12 +370,6 @@ export default function CloudStorageModal({
: "Please go back and select a provider";
const isResultLoading = isAddResultLoading || isModifyResultLoading;
- const storageSecrets =
- currentStorage != null && "secrets" in currentStorage
- ? currentStorage.secrets ?? []
- : [];
- const hasStoredCredentialsInConfig = storageSecrets.length > 0;
-
return (
-
+
)}
- {isV2 && (
-
- )}
{!isResultLoading && !success && (