1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import React from 'react';
6 import { WrappedFieldProps, Field, FormName, reset, change, WrappedFieldInputProps, WrappedFieldMetaProps } from 'redux-form';
7 import { memoize } from 'lodash';
8 import { Autocomplete } from 'components/autocomplete/autocomplete';
16 } from 'models/vocabulary';
24 } from 'views-components/resource-properties-form/property-field-common';
25 import { TAG_KEY_VALIDATION } from 'validators/validators';
26 import { escapeRegExp } from 'common/regexp';
27 import { ChangeEvent } from 'react';
29 export const PROPERTY_KEY_FIELD_NAME = 'key';
30 export const PROPERTY_KEY_FIELD_ID = 'keyID';
32 export const PropertyKeyField = connectVocabulary(
33 ({ vocabulary, skipValidation }: VocabularyProp & ValidationProp) =>
34 <span data-cy='property-field-key'>
36 name={PROPERTY_KEY_FIELD_NAME}
37 component={PropertyKeyInput}
38 vocabulary={vocabulary}
39 validate={skipValidation ? undefined : getValidation(vocabulary)} />
43 const PropertyKeyInput = ({ vocabulary, ...props }: WrappedFieldProps & VocabularyProp) =>
44 <FormName children={data => (
46 {...buildProps(props)}
48 suggestions={getSuggestions(props.input.value, vocabulary)}
50 (s: PropFieldSuggestion) => s.synonyms && s.synonyms.length > 0
51 ? `${s.label} (${s.synonyms.join('; ')})`
54 onSelect={handleSelect(PROPERTY_KEY_FIELD_ID, data.form, props.input, props.meta)}
56 // Case-insensitive search for the key in the vocabulary
57 const foundKeyID = getTagKeyID(props.input.value, vocabulary);
58 if (foundKeyID !== '') {
59 props.input.value = getTagKeyLabel(foundKeyID, vocabulary);
61 handleBlur(PROPERTY_KEY_FIELD_ID, data.form, props.meta, props.input, foundKeyID)();
63 onChange={(e: ChangeEvent<HTMLInputElement>) => {
64 const newValue = e.currentTarget.value;
65 handleChange(data.form, props.input, props.meta, newValue);
70 const getValidation = memoize(
71 (vocabulary: Vocabulary) =>
72 vocabulary.strict_tags
73 ? [...TAG_KEY_VALIDATION, matchTags(vocabulary)]
74 : TAG_KEY_VALIDATION);
76 const matchTags = (vocabulary: Vocabulary) =>
78 getTags(vocabulary).find(tag => tag.label === value)
82 const getSuggestions = (value: string, vocabulary: Vocabulary): PropFieldSuggestion[] => {
83 const re = new RegExp(escapeRegExp(value), "i");
84 return getPreferredTags(vocabulary, value).filter(
85 tag => (tag.label !== value && re.test(tag.label)) ||
86 (tag.synonyms && tag.synonyms.some(s => re.test(s))));
89 const handleChange = (
91 { onChange }: WrappedFieldInputProps,
92 { dispatch }: WrappedFieldMetaProps,
94 // Properties' values are dependant on the keys, if any value is
95 // pre-existant, a change on the property key should mean that the
96 // previous value is invalid, so we better reset the whole form before
97 // setting the new tag key.
98 dispatch(reset(formName));
101 dispatch(change(formName, PROPERTY_KEY_FIELD_NAME, value));