[ARVADOS-WORKBENCH2] created: 1.4.1-185-gc29de730

Git user git at public.arvados.org
Thu Jan 16 23:42:40 UTC 2020


        at  c29de730b2cf8582667e21bc985530a804797186 (commit)


commit c29de730b2cf8582667e21bc985530a804797186
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Thu Jan 16 18:41:30 2020 -0500

    16041: Adjust name validation behavior depending on ForwardSlashNameSubstitution
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/src/common/config.ts b/src/common/config.ts
index 4d4c1be7..f44dc168 100644
--- a/src/common/config.ts
+++ b/src/common/config.ts
@@ -54,6 +54,9 @@ export interface ClusterConfigJSON {
     Login: {
         LoginCluster: string;
     };
+    Collections: {
+        ForwardSlashNameSubstitution: string;
+    };
 }
 
 export class Config {
@@ -164,6 +167,9 @@ export const mockClusterConfigJSON = (config: Partial<ClusterConfigJSON>): Clust
     Login: {
         LoginCluster: "",
     },
+    Collections: {
+        ForwardSlashNameSubstitution: "",
+    },
     ...config
 });
 
diff --git a/src/components/warning/warning.tsx b/src/components/warning/warning.tsx
index 9a49ff0f..728cb45a 100644
--- a/src/components/warning/warning.tsx
+++ b/src/components/warning/warning.tsx
@@ -4,7 +4,7 @@
 
 import * as React from "react";
 import { ErrorIcon } from "~/components/icon/icon";
-import { invalidNamingRules } from "~/validators/valid-name";
+import { disallowSlash } from "~/validators/valid-name";
 import { Tooltip } from "@material-ui/core";
 
 interface WarningComponentProps {
@@ -15,10 +15,10 @@ interface WarningComponentProps {
 
 export const WarningComponent = ({ text, rules, message }: WarningComponentProps) =>
     rules.find(aRule => text.match(aRule) !== null)
-    ? message
-        ? <Tooltip title={message}><ErrorIcon /></Tooltip>
-        : <ErrorIcon />
-    : null;
+        ? message
+            ? <Tooltip title={message}><ErrorIcon /></Tooltip>
+            : <ErrorIcon />
+        : null;
 
 interface IllegalNamingWarningProps {
     name: string;
@@ -26,5 +26,5 @@ interface IllegalNamingWarningProps {
 
 export const IllegalNamingWarning = ({ name }: IllegalNamingWarningProps) =>
     <WarningComponent
-        text={name} rules={invalidNamingRules}
-        message="Names being '.', '..' or including '/' cause issues with WebDAV, please edit it to something different." />;
\ No newline at end of file
+        text={name} rules={[disallowSlash]}
+        message="Names embedding '/' will be renamed or invisible to file system access (arv-mount or WebDAV)" />;
diff --git a/src/validators/valid-name.tsx b/src/validators/valid-name.tsx
index 468811d8..da967123 100644
--- a/src/validators/valid-name.tsx
+++ b/src/validators/valid-name.tsx
@@ -2,13 +2,19 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
+export const disallowDotName = /^\.{1,2}$/;
+export const disallowSlash = /\//;
 
 const ERROR_MESSAGE = "Name cannot be '.' or '..' or contain '/' characters";
 
-export const invalidNamingRules = [/\//, /^\.{1,2}$/];
-
 export const validName = (value: string) => {
-    return invalidNamingRules.find(aRule => value.match(aRule) !== null)
+    return [disallowDotName, disallowSlash].find(aRule => value.match(aRule) !== null)
         ? ERROR_MESSAGE
         : undefined;
 };
+
+export const validNameAllowSlash = (value: string) => {
+    return [disallowDotName].find(aRule => value.match(aRule) !== null)
+        ? "Name cannot be '.' or '..'"
+        : undefined;
+};
diff --git a/src/validators/validators.tsx b/src/validators/validators.tsx
index 13ce4e6a..605d051c 100644
--- a/src/validators/validators.tsx
+++ b/src/validators/validators.tsx
@@ -6,14 +6,16 @@ import { require } from './require';
 import { maxLength } from './max-length';
 import { isRsaKey } from './is-rsa-key';
 import { isRemoteHost } from "./is-remote-host";
-import { validName } from "./valid-name";
+import { validName, validNameAllowSlash } from "./valid-name";
 
 export const TAG_KEY_VALIDATION = [require, maxLength(255)];
 export const TAG_VALUE_VALIDATION = [require, maxLength(255)];
 
 export const PROJECT_NAME_VALIDATION = [require, validName, maxLength(255)];
+export const PROJECT_NAME_VALIDATION_ALLOW_SLASH = [require, validNameAllowSlash, maxLength(255)];
 
 export const COLLECTION_NAME_VALIDATION = [require, validName, maxLength(255)];
+export const COLLECTION_NAME_VALIDATION_ALLOW_SLASH = [require, validNameAllowSlash, maxLength(255)];
 export const COLLECTION_DESCRIPTION_VALIDATION = [maxLength(255)];
 export const COLLECTION_PROJECT_VALIDATION = [require];
 
diff --git a/src/views-components/form-fields/collection-form-fields.tsx b/src/views-components/form-fields/collection-form-fields.tsx
index f6dc5d55..b3a3c224 100644
--- a/src/views-components/form-fields/collection-form-fields.tsx
+++ b/src/views-components/form-fields/collection-form-fields.tsx
@@ -3,19 +3,37 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from "react";
-import { Field } from "redux-form";
+import { Field, Validator } from "redux-form";
 import { TextField } from "~/components/text-field/text-field";
-import { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION, COLLECTION_PROJECT_VALIDATION } from "~/validators/validators";
+import {
+    COLLECTION_NAME_VALIDATION, COLLECTION_NAME_VALIDATION_ALLOW_SLASH,
+    COLLECTION_DESCRIPTION_VALIDATION, COLLECTION_PROJECT_VALIDATION
+} from "~/validators/validators";
 import { ProjectTreePickerField, CollectionTreePickerField } from "~/views-components/projects-tree-picker/tree-picker-field";
 import { PickerIdProp } from '~/store/tree-picker/picker-id';
+import { connect } from "react-redux";
+import { RootState } from "~/store/store";
 
-export const CollectionNameField = () =>
-    <Field
-        name='name'
-        component={TextField}
-        validate={COLLECTION_NAME_VALIDATION}
-        label="Collection Name"
-        autoFocus={true} />;
+interface CollectionNameFieldProps {
+    validate: Validator[];
+}
+
+// See implementation note on declaration of ProjectNameField
+
+export const CollectionNameField = connect(
+    (state: RootState) => {
+        return {
+            validate: (state.auth.config.clusterConfig.Collections.ForwardSlashNameSubstitution === "" ?
+                COLLECTION_NAME_VALIDATION : COLLECTION_NAME_VALIDATION_ALLOW_SLASH)
+        };
+    })((props: CollectionNameFieldProps) =>
+        <Field
+            name='name'
+            component={TextField}
+            validate={props.validate}
+            label="Collection Name"
+            autoFocus={true} />
+    );
 
 export const CollectionDescriptionField = () =>
     <Field
diff --git a/src/views-components/form-fields/project-form-fields.tsx b/src/views-components/form-fields/project-form-fields.tsx
index 8243cfe3..64386ea0 100644
--- a/src/views-components/form-fields/project-form-fields.tsx
+++ b/src/views-components/form-fields/project-form-fields.tsx
@@ -3,17 +3,38 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from "react";
-import { Field } from "redux-form";
+import { Field, Validator } from "redux-form";
 import { TextField, RichEditorTextField } from "~/components/text-field/text-field";
-import { PROJECT_NAME_VALIDATION } from "~/validators/validators";
+import { PROJECT_NAME_VALIDATION, PROJECT_NAME_VALIDATION_ALLOW_SLASH } from "~/validators/validators";
+import { connect } from "react-redux";
+import { RootState } from "~/store/store";
 
-export const ProjectNameField = () =>
-    <Field
-        name='name'
-        component={TextField}
-        validate={PROJECT_NAME_VALIDATION}
-        label="Project Name"
-        autoFocus={true} />;
+interface ProjectNameFieldProps {
+    validate: Validator[];
+}
+
+// Validation behavior depends on the value of ForwardSlashNameSubstitution.
+//
+// Redux form doesn't let you pass anonymous functions to 'validate'
+// -- it fails with a very confusing recursive-update-exceeded error.
+// So we can't construct the validation function on the fly.
+//
+// As a workaround, use ForwardSlashNameSubstitution to choose between one of two const-defined validators.
+
+export const ProjectNameField = connect(
+    (state: RootState) => {
+        return {
+            validate: (state.auth.config.clusterConfig.Collections.ForwardSlashNameSubstitution === "" ?
+                PROJECT_NAME_VALIDATION : PROJECT_NAME_VALIDATION_ALLOW_SLASH)
+        };
+    })((props: ProjectNameFieldProps) =>
+        <Field
+            name='name'
+            component={TextField}
+            validate={props.validate}
+            label="Project Name"
+            autoFocus={true} />
+    );
 
 export const ProjectDescriptionField = () =>
     <Field

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list