1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import { escapeRegExp } from 'common/regexp';
6 import { isObject, has, every } from 'lodash/fp';
8 export interface Vocabulary {
10 tags: Record<string, Tag>;
13 export interface Label {
18 export interface TagValue {
22 export interface Tag {
25 values?: Record<string, TagValue>;
28 export interface PropFieldSuggestion {
34 const VOCABULARY_VALIDATORS = [
40 export const isVocabulary = (value: any) =>
41 every(validator => validator(value), VOCABULARY_VALIDATORS);
43 export const isStrictTag = (tagKeyID: string, vocabulary: Vocabulary) => {
44 const tag = vocabulary.tags[tagKeyID];
45 return tag ? tag.strict : false;
48 export const getTagValueID = (tagKeyID:string, tagValueLabel:string, vocabulary: Vocabulary) => {
49 if (tagKeyID && vocabulary.tags[tagKeyID] && vocabulary.tags[tagKeyID].values) {
50 const values = vocabulary.tags[tagKeyID].values!;
51 return Object.keys(values).find(k =>
52 (k.toLowerCase() === tagValueLabel.toLowerCase())
53 || values[k].labels.find(
54 l => l.label.toLowerCase() === tagValueLabel.toLowerCase()) !== undefined)
60 export const getTagValueLabel = (tagKeyID:string, tagValueID:string, vocabulary: Vocabulary) =>
61 vocabulary.tags[tagKeyID] &&
62 vocabulary.tags[tagKeyID].values &&
63 vocabulary.tags[tagKeyID].values![tagValueID] &&
64 vocabulary.tags[tagKeyID].values![tagValueID].labels.length > 0
65 ? vocabulary.tags[tagKeyID].values![tagValueID].labels[0].label
68 const compare = (a: PropFieldSuggestion, b: PropFieldSuggestion) => {
69 if (a.label < b.label) {return -1;}
70 if (a.label > b.label) {return 1;}
74 export const getTagValues = (tagKeyID: string, vocabulary: Vocabulary): PropFieldSuggestion[] => {
75 const tag = vocabulary.tags[tagKeyID];
76 return tag && tag.values
77 ? Object.keys(tag.values).map(
78 tagValueID => tag.values![tagValueID].labels && tag.values![tagValueID].labels.length > 0
79 ? tag.values![tagValueID].labels.map(
80 lbl => Object.assign({}, {"id": tagValueID, "label": lbl.label}))
81 : [{"id": tagValueID, "label": tagValueID}])
82 .reduce((prev, curr) => [...prev, ...curr], [])
87 export const getPreferredTagValues = (tagKeyID: string, vocabulary: Vocabulary, withMatch?: string): PropFieldSuggestion[] => {
88 const tag = vocabulary.tags[tagKeyID];
89 const regex = !!withMatch ? new RegExp(escapeRegExp(withMatch), 'i') : undefined;
90 return tag && tag.values
91 ? Object.keys(tag.values).map(
92 tagValueID => tag.values![tagValueID].labels && tag.values![tagValueID].labels.length > 0
95 "label": tag.values![tagValueID].labels[0].label,
96 "synonyms": !!withMatch && tag.values![tagValueID].labels.length > 1
97 ? tag.values![tagValueID].labels.slice(1)
98 .filter(l => !!regex ? regex.test(l.label) : true)
102 : {"id": tagValueID, "label": tagValueID, "synonyms": []})
107 export const getTags = ({ tags }: Vocabulary): PropFieldSuggestion[] => {
108 return tags && Object.keys(tags)
109 ? Object.keys(tags).map(
110 tagID => tags[tagID].labels && tags[tagID].labels.length > 0
111 ? tags[tagID].labels.map(
112 lbl => Object.assign({}, {"id": tagID, "label": lbl.label}))
113 : [{"id": tagID, "label": tagID}])
114 .reduce((prev, curr) => [...prev, ...curr], [])
119 export const getPreferredTags = ({ tags }: Vocabulary, withMatch?: string): PropFieldSuggestion[] => {
120 const regex = !!withMatch ? new RegExp(escapeRegExp(withMatch), 'i') : undefined;
121 return tags && Object.keys(tags)
122 ? Object.keys(tags).map(
123 tagID => tags[tagID].labels && tags[tagID].labels.length > 0
126 "label": tags[tagID].labels[0].label,
127 "synonyms": !!withMatch && tags[tagID].labels.length > 1
128 ? tags[tagID].labels.slice(1)
129 .filter(l => !!regex ? regex.test(l.label) : true)
130 .map(lbl => lbl.label)
133 : {"id": tagID, "label": tagID, "synonyms": []})
138 export const getTagKeyID = (tagKeyLabel: string, vocabulary: Vocabulary) =>
139 Object.keys(vocabulary.tags).find(k => (k.toLowerCase() === tagKeyLabel.toLowerCase())
140 || vocabulary.tags[k].labels.find(
141 l => l.label.toLowerCase() === tagKeyLabel.toLowerCase()) !== undefined)
144 export const getTagKeyLabel = (tagKeyID:string, vocabulary: Vocabulary) =>
145 vocabulary.tags[tagKeyID] && vocabulary.tags[tagKeyID].labels.length > 0
146 ? vocabulary.tags[tagKeyID].labels[0].label