18560: Improves the property form's autocomplete feature.
authorLucas Di Pentima <lucas.dipentima@curii.com>
Thu, 10 Feb 2022 21:18:48 +0000 (18:18 -0300)
committerLucas Di Pentima <lucas.dipentima@curii.com>
Thu, 10 Feb 2022 21:18:48 +0000 (18:18 -0300)
Instead of presenting the whole list of terms and their synonymns to the user,
only show the preferred term (the first defined label in the vocabulary) and
if the user starts typing, also add the synonyms to every preferred term.
This way the list gets a lot smalle and easier to browse.

Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima@curii.com>

src/views-components/resource-properties-form/property-key-field.tsx
src/views-components/resource-properties-form/property-value-field.tsx

index 791949f543fab120457550a0781fa40068127357..e566c7086392aa4538c35abbfd723c1ca24cc917 100644 (file)
@@ -6,7 +6,14 @@ import React from 'react';
 import { WrappedFieldProps, Field, FormName, reset, change, WrappedFieldInputProps, WrappedFieldMetaProps } from 'redux-form';
 import { memoize } from 'lodash';
 import { Autocomplete } from 'components/autocomplete/autocomplete';
-import { Vocabulary, getTags, getTagKeyID, getTagKeyLabel } from 'models/vocabulary';
+import {
+    Vocabulary,
+    getTags,
+    getTagKeyID,
+    getTagKeyLabel,
+    getPreferredTags,
+    PropFieldSuggestion
+} from 'models/vocabulary';
 import {
     handleSelect,
     handleBlur,
@@ -36,8 +43,10 @@ export const PropertyKeyField = connectVocabulary(
 const PropertyKeyInput = ({ vocabulary, ...props }: WrappedFieldProps & VocabularyProp) =>
     <FormName children={data => (
         <Autocomplete
+            {...buildProps(props)}
             label='Key'
             suggestions={getSuggestions(props.input.value, vocabulary)}
+            renderSuggestion={(s: PropFieldSuggestion) => (s.description || s.label)}
             onSelect={handleSelect(PROPERTY_KEY_FIELD_ID, data.form, props.input, props.meta)}
             onBlur={() => {
                 // Case-insensitive search for the key in the vocabulary
@@ -51,7 +60,6 @@ const PropertyKeyInput = ({ vocabulary, ...props }: WrappedFieldProps & Vocabula
                 const newValue = e.currentTarget.value;
                 handleChange(data.form, props.input, props.meta, newValue);
             }}
-            {...buildProps(props)}
         />
     )} />;
 
@@ -67,9 +75,10 @@ const matchTags = (vocabulary: Vocabulary) =>
             ? undefined
             : 'Incorrect key';
 
-const getSuggestions = (value: string, vocabulary: Vocabulary) => {
+const getSuggestions = (value: string, vocabulary: Vocabulary): PropFieldSuggestion[] => {
     const re = new RegExp(escapeRegExp(value), "i");
-    return getTags(vocabulary).filter(tag => re.test(tag.label) && tag.label !== value);
+    return getPreferredTags(vocabulary, value !== '').filter(
+        tag => re.test((tag.description || tag.label)) && tag.label !== value);
 };
 
 const handleChange = (
index b023e412ff533571bfae33443d8061ca9f3201cc..56b7fe05cffc8eec7e33b8eccc5988094feecab2 100644 (file)
@@ -6,7 +6,7 @@ import React from 'react';
 import { WrappedFieldProps, Field, formValues, FormName, WrappedFieldInputProps, WrappedFieldMetaProps, change } from 'redux-form';
 import { compose } from 'redux';
 import { Autocomplete } from 'components/autocomplete/autocomplete';
-import { Vocabulary, isStrictTag, getTagValues, getTagValueID, getTagValueLabel } from 'models/vocabulary';
+import { Vocabulary, isStrictTag, getTagValues, getTagValueID, getTagValueLabel, PropFieldSuggestion, getPreferredTagValues } from 'models/vocabulary';
 import { PROPERTY_KEY_FIELD_ID, PROPERTY_KEY_FIELD_NAME } from 'views-components/resource-properties-form/property-key-field';
 import {
     handleSelect,
@@ -56,9 +56,11 @@ export const PropertyValueField = connectVocabularyAndPropertyKey(
 const PropertyValueInput = ({ vocabulary, propertyKeyId, propertyKeyName, ...props }: WrappedFieldProps & PropertyValueFieldProps) =>
     <FormName children={data => (
         <Autocomplete
+            {...buildProps(props)}
             label='Value'
             disabled={props.disabled}
             suggestions={getSuggestions(props.input.value, propertyKeyId, vocabulary)}
+            renderSuggestion={(s: PropFieldSuggestion) => (s.description || s.label)}
             onSelect={handleSelect(PROPERTY_VALUE_FIELD_ID, data.form, props.input, props.meta)}
             onBlur={() => {
                 // Case-insensitive search for the value in the vocabulary
@@ -73,7 +75,6 @@ const PropertyValueInput = ({ vocabulary, propertyKeyId, propertyKeyName, ...pro
                 const tagValueID = getTagValueID(propertyKeyId, newValue, vocabulary);
                 handleChange(data.form, tagValueID, props.input, props.meta, newValue);
             }}
-            {...buildProps(props)}
         />
     )} />;
 
@@ -90,7 +91,8 @@ const matchTagValues = ({ vocabulary, propertyKeyId }: PropertyValueFieldProps)
 
 const getSuggestions = (value: string, tagName: string, vocabulary: Vocabulary) => {
     const re = new RegExp(escapeRegExp(value), "i");
-    return getTagValues(tagName, vocabulary).filter(v => re.test(v.label) && v.label !== value);
+    return getPreferredTagValues(tagName, vocabulary, value !== '').filter(
+        v => re.test((v.description || v.label)) && v.label !== value);
 };
 
 const handleChange = (