From 92b4ae921e7393c504d846c6476766aec57da313 Mon Sep 17 00:00:00 2001 From: Lucas Di Pentima Date: Mon, 25 Jan 2021 17:33:55 -0300 Subject: [PATCH] 17266: Avoids adding a property value without a key. Also resets the form whenever a property key changes, this avoids a previously validated property value to be taken as valid with a different property key. Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima --- src/components/autocomplete/autocomplete.tsx | 2 ++ .../property-field-common.tsx | 21 ++++++++++-- .../property-key-field.tsx | 6 +++- .../property-value-field.tsx | 34 ++++++++++++------- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/components/autocomplete/autocomplete.tsx b/src/components/autocomplete/autocomplete.tsx index e01673b7..67bc9fa1 100644 --- a/src/components/autocomplete/autocomplete.tsx +++ b/src/components/autocomplete/autocomplete.tsx @@ -18,6 +18,7 @@ export interface AutocompleteProps { label?: string; value: string; items: Item[]; + disabled?: boolean; suggestions?: Suggestion[]; error?: boolean; helperText?: string; @@ -67,6 +68,7 @@ export class Autocomplete extends React.Component export const buildProps = ({ input, meta }: WrappedFieldProps) => { return { value: input.value, - onChange: input.onChange, items: ITEMS_PLACEHOLDER, renderSuggestion: (item: PropFieldSuggestion) => item.label, error: hasError(meta), @@ -69,3 +70,19 @@ export const handleSelect = ( dispatch(change(formName, fieldName, item.id)); } }; + +export const handleChange = ( + fieldName: string, + formName: string, + { onChange }: WrappedFieldInputProps, + { dispatch }: WrappedFieldMetaProps) => + (value: ChangeEvent) => { + if (fieldName === PROPERTY_KEY_FIELD_ID) { + // Properties' values are dependant on the keys, if any value is + // pre-existant, a change on the property key should mean that the + // previous value is invalid. + dispatch(reset(formName)); + } + onChange(value); + dispatch(change(formName, fieldName, value)); + }; \ No newline at end of file diff --git a/src/views-components/resource-properties-form/property-key-field.tsx b/src/views-components/resource-properties-form/property-key-field.tsx index d17f50d4..0c3a49be 100644 --- a/src/views-components/resource-properties-form/property-key-field.tsx +++ b/src/views-components/resource-properties-form/property-key-field.tsx @@ -7,9 +7,10 @@ import { WrappedFieldProps, Field, FormName } from 'redux-form'; import { memoize } from 'lodash'; import { Autocomplete } from '~/components/autocomplete/autocomplete'; import { Vocabulary, getTags, getTagKeyID } from '~/models/vocabulary'; -import { handleSelect, handleBlur, connectVocabulary, VocabularyProp, ValidationProp, buildProps } from '~/views-components/resource-properties-form/property-field-common'; +import { handleSelect, handleBlur, connectVocabulary, VocabularyProp, ValidationProp, buildProps, handleChange } from '~/views-components/resource-properties-form/property-field-common'; import { TAG_KEY_VALIDATION } from '~/validators/validators'; import { escapeRegExp } from '~/common/regexp.ts'; +import { ChangeEvent } from 'react'; export const PROPERTY_KEY_FIELD_NAME = 'key'; export const PROPERTY_KEY_FIELD_ID = 'keyID'; @@ -32,6 +33,9 @@ const PropertyKeyInput = ({ vocabulary, ...props }: WrappedFieldProps & Vocabula suggestions={getSuggestions(props.input.value, vocabulary)} onSelect={handleSelect(PROPERTY_KEY_FIELD_ID, data.form, props.input, props.meta)} onBlur={handleBlur(PROPERTY_KEY_FIELD_ID, data.form, props.meta, props.input, getTagKeyID(props.input.value, vocabulary))} + onChange={(value: ChangeEvent) => { + handleChange(PROPERTY_KEY_FIELD_ID, data.form, props.input, props.meta)(value); + }} {...buildProps(props)} /> )} />; diff --git a/src/views-components/resource-properties-form/property-value-field.tsx b/src/views-components/resource-properties-form/property-value-field.tsx index c5a5071f..9ce9d521 100644 --- a/src/views-components/resource-properties-form/property-value-field.tsx +++ b/src/views-components/resource-properties-form/property-value-field.tsx @@ -7,23 +7,31 @@ import { WrappedFieldProps, Field, formValues, FormName } from 'redux-form'; import { compose } from 'redux'; import { Autocomplete } from '~/components/autocomplete/autocomplete'; import { Vocabulary, isStrictTag, getTagValues, getTagValueID } from '~/models/vocabulary'; -import { PROPERTY_KEY_FIELD_ID } from '~/views-components/resource-properties-form/property-key-field'; -import { handleSelect, handleBlur, VocabularyProp, ValidationProp, connectVocabulary, buildProps } from '~/views-components/resource-properties-form/property-field-common'; +import { PROPERTY_KEY_FIELD_ID, PROPERTY_KEY_FIELD_NAME } from '~/views-components/resource-properties-form/property-key-field'; +import { handleSelect, handleBlur, VocabularyProp, ValidationProp, connectVocabulary, buildProps, handleChange } from '~/views-components/resource-properties-form/property-field-common'; import { TAG_VALUE_VALIDATION } from '~/validators/validators'; import { escapeRegExp } from '~/common/regexp.ts'; interface PropertyKeyProp { - propertyKey: string; + propertyKeyId: string; + propertyKeyName: string; } -type PropertyValueFieldProps = VocabularyProp & PropertyKeyProp & ValidationProp; +interface PropertyValueInputProp { + disabled: boolean; +} + +type PropertyValueFieldProps = VocabularyProp & PropertyKeyProp & ValidationProp & PropertyValueInputProp; export const PROPERTY_VALUE_FIELD_NAME = 'value'; export const PROPERTY_VALUE_FIELD_ID = 'valueID'; const connectVocabularyAndPropertyKey = compose( connectVocabulary, - formValues({ propertyKey: PROPERTY_KEY_FIELD_ID }), + formValues({ + propertyKeyId: PROPERTY_KEY_FIELD_ID, + propertyKeyName: PROPERTY_KEY_FIELD_NAME, + }), ); export const PropertyValueField = connectVocabularyAndPropertyKey( @@ -33,29 +41,31 @@ export const PropertyValueField = connectVocabularyAndPropertyKey( name={PROPERTY_VALUE_FIELD_NAME} component={PropertyValueInput} validate={skipValidation ? undefined : getValidation(props)} - {...props} /> + {...{...props, disabled: !props.propertyKeyName}} /> ); -const PropertyValueInput = ({ vocabulary, propertyKey, ...props }: WrappedFieldProps & PropertyValueFieldProps) => +const PropertyValueInput = ({ vocabulary, propertyKeyId, propertyKeyName, ...props }: WrappedFieldProps & PropertyValueFieldProps) => ( )} />; const getValidation = (props: PropertyValueFieldProps) => - isStrictTag(props.propertyKey, props.vocabulary) + isStrictTag(props.propertyKeyId, props.vocabulary) ? [...TAG_VALUE_VALIDATION, matchTagValues(props)] : TAG_VALUE_VALIDATION; -const matchTagValues = ({ vocabulary, propertyKey }: PropertyValueFieldProps) => +const matchTagValues = ({ vocabulary, propertyKeyId }: PropertyValueFieldProps) => (value: string) => - getTagValues(propertyKey, vocabulary).find(v => v.label === value) + getTagValues(propertyKeyId, vocabulary).find(v => v.label === value) ? undefined : 'Incorrect value'; -- 2.39.5