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)}
49 renderSuggestion={(s: PropFieldSuggestion) => (s.description || s.label)}
50 onSelect={handleSelect(PROPERTY_KEY_FIELD_ID, data.form, props.input, props.meta)}
52 // Case-insensitive search for the key in the vocabulary
53 const foundKeyID = getTagKeyID(props.input.value, vocabulary);
54 if (foundKeyID !== '') {
55 props.input.value = getTagKeyLabel(foundKeyID, vocabulary);
57 handleBlur(PROPERTY_KEY_FIELD_ID, data.form, props.meta, props.input, foundKeyID)();
59 onChange={(e: ChangeEvent<HTMLInputElement>) => {
60 const newValue = e.currentTarget.value;
61 handleChange(data.form, props.input, props.meta, newValue);
66 const getValidation = memoize(
67 (vocabulary: Vocabulary) =>
68 vocabulary.strict_tags
69 ? [...TAG_KEY_VALIDATION, matchTags(vocabulary)]
70 : TAG_KEY_VALIDATION);
72 const matchTags = (vocabulary: Vocabulary) =>
74 getTags(vocabulary).find(tag => tag.label === value)
78 const getSuggestions = (value: string, vocabulary: Vocabulary): PropFieldSuggestion[] => {
79 const re = new RegExp(escapeRegExp(value), "i");
80 return getPreferredTags(vocabulary, value !== '').filter(
81 tag => re.test((tag.description || tag.label)) && tag.label !== value);
84 const handleChange = (
86 { onChange }: WrappedFieldInputProps,
87 { dispatch }: WrappedFieldMetaProps,
89 // Properties' values are dependant on the keys, if any value is
90 // pre-existant, a change on the property key should mean that the
91 // previous value is invalid, so we better reset the whole form before
92 // setting the new tag key.
93 dispatch(reset(formName));
96 dispatch(change(formName, PROPERTY_KEY_FIELD_NAME, value));