Create PropertyKeyField
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Tue, 27 Nov 2018 20:10:22 +0000 (21:10 +0100)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Tue, 27 Nov 2018 20:10:22 +0000 (21:10 +0100)
Feature #14393

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

src/views-components/resource-properties-form/property-key-field.tsx [new file with mode: 0644]

diff --git a/src/views-components/resource-properties-form/property-key-field.tsx b/src/views-components/resource-properties-form/property-key-field.tsx
new file mode 100644 (file)
index 0000000..fdd89d0
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { WrappedFieldProps, Field } from 'redux-form';
+import { connect } from 'react-redux';
+import { identity, memoize } from 'lodash';
+import { RootState } from '~/store/store';
+import { getVocabulary } from '~/store/vocabulary/vocabulary-selctors';
+import { Autocomplete } from '~/components/autocomplete/autocomplete';
+import { Vocabulary } from '~/models/vocabulary';
+import { require } from '~/validators/require';
+
+interface VocabularyProp {
+    vocabulary: Vocabulary;
+}
+
+const mapStateToProps = (state: RootState): VocabularyProp => ({
+    vocabulary: getVocabulary(state.properties),
+});
+
+export const PropertyKeyField = connect(mapStateToProps)(
+    ({ vocabulary }: VocabularyProp) =>
+        <Field
+            name='key'
+            component={PropertyKeyInput}
+            vocabulary={vocabulary}
+            validate={getValidation(vocabulary)} />);
+
+const PropertyKeyInput = ({ input, meta, vocabulary }: WrappedFieldProps & VocabularyProp) =>
+    <Autocomplete
+        value={input.value}
+        onChange={input.onChange}
+        label='Key'
+        suggestions={getSuggestions(input.value, vocabulary)}
+        items={ITEMS_PLACEHOLDER}
+        onSelect={input.onChange}
+        renderSuggestion={identity}
+        error={meta.invalid}
+        helperText={meta.error}
+    />;
+
+const getValidation = memoize(
+    (vocabulary: Vocabulary) =>
+        vocabulary.strict
+            ? [require, matchTags(vocabulary)]
+            : [require]);
+
+const matchTags = (vocabulary: Vocabulary) =>
+    (value: string) =>
+        getTagsList(vocabulary).find(tag => tag.includes(value))
+            ? undefined
+            : 'Incorrect key';
+
+const getSuggestions = (value: string, vocabulary: Vocabulary) => 
+    getTagsList(vocabulary).filter(tag => tag.includes(value) && tag !== value);
+
+const getTagsList = ({ tags }: Vocabulary) =>
+    Object.keys(tags);
+
+const ITEMS_PLACEHOLDER: string[] = [];