cy.get('@testWorkflow').then(() => {
cy.loginAs(adminUser);
- cy.get('[data-cy=linear-progress]').should('exist');
- cy.get('[data-cy=linear-progress]').should('not.exist');
-
cy.get('[data-cy=side-panel-button]').click();
cy.get('[data-cy=side-panel-run-process]').click();
strict: false,
labels: [
{label: "Animal" },
- {label: "Creature"}
+ {label: "Creature"},
+ {label: "Beast"},
],
values: {
IDVALANIMALS1: {
labels: [{label: "Sizes"}],
values: {
IDVALSIZES1: {
- labels: [{label: "Small"}]
+ labels: [{label: "Small"}, {label: "S"}, {label: "Little"}]
},
IDVALSIZES2: {
- labels: [{label: "Medium"}]
+ labels: [{label: "Medium"}, {label: "M"}]
},
IDVALSIZES3: {
- labels: [{label: "Large"}]
+ labels: [{label: "Large"}, {label: "L"}]
},
IDVALSIZES4: {
labels: []
// Alphabetically ordered by label
expect(tagKeys).toEqual([
{id: "IDKEYANIMALS", label: "Animal"},
+ {id: "IDKEYANIMALS", label: "Beast"},
{id: "IDKEYANIMALS", label: "Creature"},
{id: "IDKEYCOMMENT", label: "IDKEYCOMMENT"},
{id: "IDKEYSIZES", label: "Sizes"},
]);
});
+ it('returns the list of preferred tag keys', () => {
+ const preferredTagKeys = Vocabulary.getPreferredTags(vocabulary);
+ // Alphabetically ordered by label
+ expect(preferredTagKeys).toEqual([
+ {id: "IDKEYANIMALS", label: "Animal", synonyms: []},
+ {id: "IDKEYCOMMENT", label: "IDKEYCOMMENT", synonyms: []},
+ {id: "IDKEYSIZES", label: "Sizes", synonyms: []},
+ ]);
+ });
+
+ it('returns the list of preferred tag keys with matching synonyms', () => {
+ const preferredTagKeys = Vocabulary.getPreferredTags(vocabulary, 'creat');
+ // Alphabetically ordered by label
+ expect(preferredTagKeys).toEqual([
+ {id: "IDKEYANIMALS", label: "Animal", synonyms: ["Creature"]},
+ {id: "IDKEYCOMMENT", label: "IDKEYCOMMENT", synonyms: []},
+ {id: "IDKEYSIZES", label: "Sizes", synonyms: []},
+ ]);
+ });
+
it('returns the tag values for a given key', () => {
const tagValues = Vocabulary.getTagValues('IDKEYSIZES', vocabulary);
// Alphabetically ordered by label
expect(tagValues).toEqual([
{id: "IDVALSIZES4", label: "IDVALSIZES4"},
+ {id: "IDVALSIZES3", label: "L"},
{id: "IDVALSIZES3", label: "Large"},
+ {id: "IDVALSIZES1", label: "Little"},
+ {id: "IDVALSIZES2", label: "M"},
{id: "IDVALSIZES2", label: "Medium"},
+ {id: "IDVALSIZES1", label: "S"},
{id: "IDVALSIZES1", label: "Small"},
])
});
+ it('returns the preferred tag values for a given key', () => {
+ const preferredTagValues = Vocabulary.getPreferredTagValues('IDKEYSIZES', vocabulary);
+ // Alphabetically ordered by label
+ expect(preferredTagValues).toEqual([
+ {id: "IDVALSIZES4", label: "IDVALSIZES4", synonyms: []},
+ {id: "IDVALSIZES3", label: "Large", synonyms: []},
+ {id: "IDVALSIZES2", label: "Medium", synonyms: []},
+ {id: "IDVALSIZES1", label: "Small", synonyms: []},
+ ])
+ });
+
+ it('returns the preferred tag values with matching synonyms for a given key', () => {
+ const preferredTagValues = Vocabulary.getPreferredTagValues('IDKEYSIZES', vocabulary, 'litt');
+ // Alphabetically ordered by label
+ expect(preferredTagValues).toEqual([
+ {id: "IDVALSIZES4", label: "IDVALSIZES4", synonyms: []},
+ {id: "IDVALSIZES3", label: "Large", synonyms: []},
+ {id: "IDVALSIZES2", label: "Medium", synonyms: []},
+ {id: "IDVALSIZES1", label: "Small", synonyms: ["Little"]},
+ ])
+ });
+
it('returns an empty list of values for an non-existent key', () => {
const tagValues = Vocabulary.getTagValues('IDNONSENSE', vocabulary);
expect(tagValues).toEqual([]);
//
// SPDX-License-Identifier: AGPL-3.0
+import { escapeRegExp } from 'common/regexp';
import { isObject, has, every } from 'lodash/fp';
export interface Vocabulary {
export interface PropFieldSuggestion {
id: string;
label: string;
+ synonyms?: string[];
}
const VOCABULARY_VALIDATORS = [
return 0;
};
-export const getTagValues = (tagKeyID: string, vocabulary: Vocabulary) => {
+export const getTagValues = (tagKeyID: string, vocabulary: Vocabulary): PropFieldSuggestion[] => {
const tag = vocabulary.tags[tagKeyID];
- const ret = tag && tag.values
+ return tag && tag.values
? Object.keys(tag.values).map(
tagValueID => tag.values![tagValueID].labels && tag.values![tagValueID].labels.length > 0
? tag.values![tagValueID].labels.map(
.reduce((prev, curr) => [...prev, ...curr], [])
.sort(compare)
: [];
- return ret;
};
-export const getTags = ({ tags }: Vocabulary) => {
- const ret = tags && Object.keys(tags)
+export const getPreferredTagValues = (tagKeyID: string, vocabulary: Vocabulary, withMatch?: string): PropFieldSuggestion[] => {
+ const tag = vocabulary.tags[tagKeyID];
+ const regex = !!withMatch ? new RegExp(escapeRegExp(withMatch), 'i') : undefined;
+ return tag && tag.values
+ ? Object.keys(tag.values).map(
+ tagValueID => tag.values![tagValueID].labels && tag.values![tagValueID].labels.length > 0
+ ? {
+ "id": tagValueID,
+ "label": tag.values![tagValueID].labels[0].label,
+ "synonyms": !!withMatch && tag.values![tagValueID].labels.length > 1
+ ? tag.values![tagValueID].labels.slice(1)
+ .filter(l => !!regex ? regex.test(l.label) : true)
+ .map(l => l.label)
+ : []
+ }
+ : {"id": tagValueID, "label": tagValueID, "synonyms": []})
+ .sort(compare)
+ : [];
+};
+
+export const getTags = ({ tags }: Vocabulary): PropFieldSuggestion[] => {
+ return tags && Object.keys(tags)
? Object.keys(tags).map(
tagID => tags[tagID].labels && tags[tagID].labels.length > 0
? tags[tagID].labels.map(
.reduce((prev, curr) => [...prev, ...curr], [])
.sort(compare)
: [];
- return ret;
+};
+
+export const getPreferredTags = ({ tags }: Vocabulary, withMatch?: string): PropFieldSuggestion[] => {
+ const regex = !!withMatch ? new RegExp(escapeRegExp(withMatch), 'i') : undefined;
+ return tags && Object.keys(tags)
+ ? Object.keys(tags).map(
+ tagID => tags[tagID].labels && tags[tagID].labels.length > 0
+ ? {
+ "id": tagID,
+ "label": tags[tagID].labels[0].label,
+ "synonyms": !!withMatch && tags[tagID].labels.length > 1
+ ? tags[tagID].labels.slice(1)
+ .filter(l => !!regex ? regex.test(l.label) : true)
+ .map(lbl => lbl.label)
+ : []
+ }
+ : {"id": tagID, "label": tagID, "synonyms": []})
+ .sort(compare)
+ : [];
};
export const getTagKeyID = (tagKeyLabel:string, vocabulary: Vocabulary) =>
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,
const PropertyKeyInput = ({ vocabulary, ...props }: WrappedFieldProps & VocabularyProp) =>
<FormName children={data => (
<Autocomplete
+ {...buildProps(props)}
label='Key'
suggestions={getSuggestions(props.input.value, vocabulary)}
+ renderSuggestion={
+ (s: PropFieldSuggestion) => s.synonyms && s.synonyms.length > 0
+ ? `${s.label} (${s.synonyms.join('; ')})`
+ : s.label
+ }
onSelect={handleSelect(PROPERTY_KEY_FIELD_ID, data.form, props.input, props.meta)}
onBlur={() => {
// Case-insensitive search for the key in the vocabulary
const newValue = e.currentTarget.value;
handleChange(data.form, props.input, props.meta, newValue);
}}
- {...buildProps(props)}
/>
)} />;
? 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 => (tag.label !== value && re.test(tag.label)) ||
+ (tag.synonyms && tag.synonyms.some(s => re.test(s))));
};
const handleChange = (
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,
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.synonyms && s.synonyms.length > 0
+ ? `${s.label} (${s.synonyms.join('; ')})`
+ : s.label
+ }
onSelect={handleSelect(PROPERTY_VALUE_FIELD_ID, data.form, props.input, props.meta)}
onBlur={() => {
// Case-insensitive search for the value in the vocabulary
const tagValueID = getTagValueID(propertyKeyId, newValue, vocabulary);
handleChange(data.form, tagValueID, props.input, props.meta, newValue);
}}
- {...buildProps(props)}
/>
)} />;
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(
+ val => (val.label !== value && re.test(val.label)) ||
+ (val.synonyms && val.synonyms.some(s => re.test(s))));
};
const handleChange = (