Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@
"onloadend",
"onopen",
"openapi",
"openbis",
"papermill",
"pathname",
"pdfjs",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import {
import KeywordBadge from "~/components/keywords/KeywordBadge";
import KeywordContainer from "~/components/keywords/KeywordContainer";
import ChevronFlippedIcon from "../../../../components/icons/ChevronFlippedIcon";
import { ErrorAlert, WarnAlert } from "../../../../components/Alert";
import { Loader } from "../../../../components/Loader";
import { ErrorAlert, InfoAlert, WarnAlert } from "../../../../components/Alert";
import useAppDispatch from "../../../../utils/customHooks/useAppDispatch.hook";
import useAppSelector from "../../../../utils/customHooks/useAppSelector.hook";
import { slugFromTitle } from "../../../../utils/helpers/HelperFunctions";
Expand All @@ -49,7 +49,10 @@ import type {
AddCloudStorageState,
CloudStorageDetails,
} from "../../../project/components/cloudStorage/projectCloudStorage.types";
import { getSchemaOptions } from "../../../project/utils/projectCloudStorage.utils";
import {
getSchema,
getSchemaOptions,
} from "../../../project/utils/projectCloudStorage.utils";
import type { Project } from "../../../projectsV2/api/projectV2.api";
import { ProjectNamespaceControl } from "../../../projectsV2/fields/ProjectNamespaceFormField";
import SlugPreviewFormField from "../../../projectsV2/fields/SlugPreviewFormField";
Expand Down Expand Up @@ -294,16 +297,19 @@ export function DataConnectorMount({
const { validationResult } = useAppSelector(
(state) => state.dataConnectorFormSlice
);
const options = getSchemaOptions(
const schema = getSchema(schemata, flatDataConnector.schema);
const schemaOptions = getSchemaOptions(
schemata,
true,
flatDataConnector.schema,
flatDataConnector.provider
);
const secretFields =
options == null
schemaOptions == null
? []
: Object.values(options).filter((o) => o && o.convertedType === "secret");
: Object.values(schemaOptions).filter(
(o) => o && o.convertedType === "secret"
);
const hasPasswordFieldWithInput = secretFields.some(
(o) => flatDataConnector.options && flatDataConnector.options[o.name]
);
Expand Down Expand Up @@ -514,6 +520,7 @@ export function DataConnectorMount({
field.onChange(e);
onFieldValueChange("readOnly", !!e.target.value);
}}
disabled={schema?.forceReadOnly ?? false}
/>
<Label
for="data-connector-readonly-true"
Expand All @@ -535,6 +542,7 @@ export function DataConnectorMount({
field.onChange(e);
onFieldValueChange("readOnly", false);
}}
disabled={schema?.forceReadOnly ?? false}
/>
<Label
for="data-connector-readonly-false"
Expand All @@ -548,26 +556,34 @@ export function DataConnectorMount({
)}
rules={{ required: true }}
/>
{!flatDataConnector.readOnly &&
!hasPasswordFieldWithInput &&
flatDataConnector.visibility === "public" ? (
<ErrorAlert className="mt-1" dismissible={false}>
{schema?.forceReadOnly ? (
<InfoAlert className="mt-1" dismissible={false} timeout={0}>
<p className="mb-0">
Data security warning: This public and writable data connector
is not protected by a password. Anyone on RenkuLab will be able
to edit the data connected here. Protect your data with a
password, select private visibility, or limit access to
read-only.
This cloud storage only supports read-only access.
</p>
</ErrorAlert>
</InfoAlert>
) : (
<WarnAlert className="mt-1" dismissible={false}>
<p className="mb-0">
You are mounting this storage in read-write mode. If you have
read-only access, please select &quot;Read Only&quot; to prevent
errors with some storage types.
</p>
</WarnAlert>
!flatDataConnector.readOnly &&
(!hasPasswordFieldWithInput &&
flatDataConnector.visibility === "public" ? (
<ErrorAlert className="mt-1" dismissible={false}>
<p className="mb-0">
Data security warning: This public and writable data connector
is not protected by a password. Anyone on RenkuLab will be
able to edit the data connected here. Protect your data with a
password, select private visibility, or limit access to
read-only.
</p>
</ErrorAlert>
) : (
<WarnAlert className="mt-1" dismissible={false}>
<p className="mb-0">
You are mounting this storage in read-write mode. If you have
read-only access, please select &quot;Read Only&quot; to
prevent errors with some storage types.
</p>
</WarnAlert>
))
)}
<div className={cx("form-text", "text-muted")}>
Select &quot;Read Only&quot; to mount the storage without write
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {

import {
findSensitive,
getSchemaOptions,
hasProviderShortlist,
} from "../../../project/utils/projectCloudStorage.utils";

Expand Down Expand Up @@ -307,10 +308,32 @@ function DataConnectorCreateFooter({
]);

// Visual elements
const disableContinueButton =
cloudStorageState.step === 1 &&
(!flatDataConnector.schema ||
(schemaRequiresProvider && !flatDataConnector.provider));
const disableContinueButton = useMemo(() => {
return (
(cloudStorageState.step === 1 &&
(!flatDataConnector.schema ||
(schemaRequiresProvider && !flatDataConnector.provider))) ||
(cloudStorageState.step === 2 &&
!getSchemaOptions(
schemata,
true,
flatDataConnector.schema,
flatDataConnector.provider
)?.every((o) => {
return (
!o.required ||
(flatDataConnector.options && flatDataConnector.options[o.name])
);
}))
);
}, [
cloudStorageState.step,
flatDataConnector.schema,
schemaRequiresProvider,
flatDataConnector.provider,
schemata,
flatDataConnector.options,
]);

const isAddResultLoading = createResult.isLoading;
const actionError = createResult.error;
Expand Down Expand Up @@ -490,10 +513,32 @@ function DataConnectorEditFooter({
}, [dispatch, updateResult]);

// Visual elements
const disableContinueButton =
cloudStorageState.step === 1 &&
(!flatDataConnector.schema ||
(schemaRequiresProvider && !flatDataConnector.provider));
const disableContinueButton = useMemo(() => {
return (
(cloudStorageState.step === 1 &&
(!flatDataConnector.schema ||
(schemaRequiresProvider && !flatDataConnector.provider))) ||
(cloudStorageState.step === 2 &&
!getSchemaOptions(
schemata,
true,
flatDataConnector.schema,
flatDataConnector.provider
)?.every((o) => {
return (
!o.required ||
(flatDataConnector.options && flatDataConnector.options[o.name])
);
}))
);
}, [
cloudStorageState.step,
flatDataConnector.schema,
schemaRequiresProvider,
flatDataConnector.provider,
schemata,
flatDataConnector.options,
]);

const isModifyResultLoading = updateResult.isLoading;
const actionError = updateResult.error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,18 +176,15 @@ export function DataConnectorModalContinueButton({
continueId="add-data-connector-continue"
step={cloudStorageState.step}
testId="test-data-connector"
disableContinueButton={disableContinueButton}
editDataConnector={addOrEditStorage}
/>
{disableContinueButton && (
<UncontrolledTooltip
placement="top"
target={`${continueButtonId}-div`}
>
{!flatDataConnector.schema
? "Please select a storage type"
: selectedSchemaHasAccessMode
? "Please select a mode or change storage type"
: "Please select a provider or change storage type"}
Please fill out all fields labeled as required
</UncontrolledTooltip>
)}
</div>
Expand All @@ -211,10 +208,19 @@ export function DataConnectorModalContinueButton({
id="add-data-connector-continue-button"
data-cy="add-data-connector-continue-button"
className={cx("btn-primary")}
disabled={disableContinueButton}
onClick={addOrEditStorage}
>
<PencilSquare className={cx("bi", "me-1")} /> Update connector
</Button>
{disableContinueButton && (
<UncontrolledTooltip
placement="top"
target="add-data-connector-continue-div"
>
Please fill out all fields labeled as required
</UncontrolledTooltip>
)}
</div>
</div>
);
Expand Down Expand Up @@ -294,12 +300,14 @@ interface TestConnectionAndContinueButtonsProps
continueId: string;
step: number;
testId: string;
disableContinueButton: boolean;
editDataConnector?: () => void;
}
function TestConnectionAndContinueButtons({
continueId,
step,
testId,
disableContinueButton,
editDataConnector,
}: TestConnectionAndContinueButtonsProps) {
const dispatch = useAppDispatch();
Expand Down Expand Up @@ -395,7 +403,7 @@ function TestConnectionAndContinueButtons({
color={testConnectionColor}
id={buttonTestId}
data-cy={buttonTestId}
disabled={validationResult.isLoading}
disabled={disableContinueButton || validationResult.isLoading}
onClick={() => validateConnection()}
>
{testConnectionContent}
Expand Down
Loading
Loading