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 (tagKeyID && vocabulary.tags[tagKeyID] && vocabulary.tags[tagKeyID].values)
50 ? Object.keys(vocabulary.tags[tagKeyID].values!).find(
51 k => vocabulary.tags[tagKeyID].values![k].labels.find(
52 l => l.label.toLowerCase() === tagValueLabel.toLowerCase()) !== undefined) || ''
55 export const getTagValueLabel = (tagKeyID:string, tagValueID:string, vocabulary: Vocabulary) =>
56 vocabulary.tags[tagKeyID] &&
57 vocabulary.tags[tagKeyID].values &&
58 vocabulary.tags[tagKeyID].values![tagValueID] &&
59 vocabulary.tags[tagKeyID].values![tagValueID].labels.length > 0
60 ? vocabulary.tags[tagKeyID].values![tagValueID].labels[0].label
63 const compare = (a: PropFieldSuggestion, b: PropFieldSuggestion) => {
64 if (a.label < b.label) {return -1;}
65 if (a.label > b.label) {return 1;}
69 export const getTagValues = (tagKeyID: string, vocabulary: Vocabulary): PropFieldSuggestion[] => {
70 const tag = vocabulary.tags[tagKeyID];
71 return tag && tag.values
72 ? Object.keys(tag.values).map(
73 tagValueID => tag.values![tagValueID].labels && tag.values![tagValueID].labels.length > 0
74 ? tag.values![tagValueID].labels.map(
75 lbl => Object.assign({}, {"id": tagValueID, "label": lbl.label}))
76 : [{"id": tagValueID, "label": tagValueID}])
77 .reduce((prev, curr) => [...prev, ...curr], [])
82 export const getPreferredTagValues = (tagKeyID: string, vocabulary: Vocabulary, withMatch?: string): PropFieldSuggestion[] => {
83 const tag = vocabulary.tags[tagKeyID];
84 const regex = !!withMatch ? new RegExp(escapeRegExp(withMatch), 'i') : undefined;
85 return tag && tag.values
86 ? Object.keys(tag.values).map(
87 tagValueID => tag.values![tagValueID].labels && tag.values![tagValueID].labels.length > 0
90 "label": tag.values![tagValueID].labels[0].label,
91 "synonyms": !!withMatch && tag.values![tagValueID].labels.length > 1
92 ? tag.values![tagValueID].labels.slice(1)
93 .filter(l => !!regex ? regex.test(l.label) : true)
97 : {"id": tagValueID, "label": tagValueID, "synonyms": []})
102 export const getTags = ({ tags }: Vocabulary): PropFieldSuggestion[] => {
103 return tags && Object.keys(tags)
104 ? Object.keys(tags).map(
105 tagID => tags[tagID].labels && tags[tagID].labels.length > 0
106 ? tags[tagID].labels.map(
107 lbl => Object.assign({}, {"id": tagID, "label": lbl.label}))
108 : [{"id": tagID, "label": tagID}])
109 .reduce((prev, curr) => [...prev, ...curr], [])
114 export const getPreferredTags = ({ tags }: Vocabulary, withMatch?: string): PropFieldSuggestion[] => {
115 const regex = !!withMatch ? new RegExp(escapeRegExp(withMatch), 'i') : undefined;
116 return tags && Object.keys(tags)
117 ? Object.keys(tags).map(
118 tagID => tags[tagID].labels && tags[tagID].labels.length > 0
121 "label": tags[tagID].labels[0].label,
122 "synonyms": !!withMatch && tags[tagID].labels.length > 1
123 ? tags[tagID].labels.slice(1)
124 .filter(l => !!regex ? regex.test(l.label) : true)
125 .map(lbl => lbl.label)
128 : {"id": tagID, "label": tagID, "synonyms": []})
133 export const getTagKeyID = (tagKeyLabel:string, vocabulary: Vocabulary) =>
134 Object.keys(vocabulary.tags).find(
135 k => vocabulary.tags[k].labels.find(
136 l => l.label.toLowerCase() === tagKeyLabel.toLowerCase()) !== undefined
139 export const getTagKeyLabel = (tagKeyID:string, vocabulary: Vocabulary) =>
140 vocabulary.tags[tagKeyID] && vocabulary.tags[tagKeyID].labels.length > 0
141 ? vocabulary.tags[tagKeyID].labels[0].label