55525c22b14f47b36a5a358fa1fbcc20c42a1357
[arvados-workbench2.git] / src / models / vocabulary.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { isObject, has, every } from 'lodash/fp';
6
7 export interface Vocabulary {
8     strict_tags: boolean;
9     tags: Record<string, Tag>;
10 }
11
12 export interface Label {
13     lang?: string;
14     label: string;
15 }
16
17 export interface TagValue {
18     labels: Label[];
19 }
20
21 export interface Tag {
22     strict?: boolean;
23     labels: Label[];
24     values?: Record<string, TagValue>;
25 }
26
27 export interface PropFieldSuggestion {
28     id: string;
29     label: string;
30     description?: string;
31 }
32
33 const VOCABULARY_VALIDATORS = [
34     isObject,
35     has('strict_tags'),
36     has('tags'),
37 ];
38
39 export const isVocabulary = (value: any) =>
40     every(validator => validator(value), VOCABULARY_VALIDATORS);
41
42 export const isStrictTag = (tagKeyID: string, vocabulary: Vocabulary) => {
43     const tag = vocabulary.tags[tagKeyID];
44     return tag ? tag.strict : false;
45 };
46
47 export const getTagValueID = (tagKeyID:string, tagValueLabel:string, vocabulary: Vocabulary) =>
48     (tagKeyID && vocabulary.tags[tagKeyID] && vocabulary.tags[tagKeyID].values)
49     ? Object.keys(vocabulary.tags[tagKeyID].values!).find(
50         k => vocabulary.tags[tagKeyID].values![k].labels.find(
51             l => l.label.toLowerCase() === tagValueLabel.toLowerCase()) !== undefined) || ''
52     : '';
53
54 export const getTagValueLabel = (tagKeyID:string, tagValueID:string, vocabulary: Vocabulary) =>
55     vocabulary.tags[tagKeyID] &&
56     vocabulary.tags[tagKeyID].values &&
57     vocabulary.tags[tagKeyID].values![tagValueID] &&
58     vocabulary.tags[tagKeyID].values![tagValueID].labels.length > 0
59         ? vocabulary.tags[tagKeyID].values![tagValueID].labels[0].label
60         : tagValueID;
61
62 const compare = (a: PropFieldSuggestion, b: PropFieldSuggestion) => {
63     if (a.label < b.label) {return -1;}
64     if (a.label > b.label) {return 1;}
65     return 0;
66 };
67
68 export const getTagValues = (tagKeyID: string, vocabulary: Vocabulary): PropFieldSuggestion[] => {
69     const tag = vocabulary.tags[tagKeyID];
70     return tag && tag.values
71         ? Object.keys(tag.values).map(
72             tagValueID => tag.values![tagValueID].labels && tag.values![tagValueID].labels.length > 0
73                 ? tag.values![tagValueID].labels.map(
74                     lbl => Object.assign({}, {"id": tagValueID, "label": lbl.label}))
75                 : [{"id": tagValueID, "label": tagValueID}])
76             .reduce((prev, curr) => [...prev, ...curr], [])
77             .sort(compare)
78         : [];
79 };
80
81 export const getPreferredTagValues = (tagKeyID: string, vocabulary: Vocabulary, withSynonyms?: boolean): PropFieldSuggestion[] => {
82     const tag = vocabulary.tags[tagKeyID];
83     return tag && tag.values
84         ? Object.keys(tag.values).map(
85             tagValueID => tag.values![tagValueID].labels && tag.values![tagValueID].labels.length > 0
86                 ? {
87                     "id": tagValueID,
88                     "label": tag.values![tagValueID].labels[0].label,
89                     "description": tag.values![tagValueID].labels[0].label + (
90                         withSynonyms && tag.values![tagValueID].labels.length > 1
91                         ? ` (${tag.values![tagValueID].labels.slice(1).map(l => l.label).join(', ')})`
92                         : '')}
93                 : {"id": tagValueID, "label": tagValueID})
94             .sort(compare)
95         : [];
96 };
97
98 export const getTags = ({ tags }: Vocabulary): PropFieldSuggestion[] => {
99     return tags && Object.keys(tags)
100         ? Object.keys(tags).map(
101             tagID => tags[tagID].labels && tags[tagID].labels.length > 0
102                 ? tags[tagID].labels.map(
103                     lbl => Object.assign({}, {"id": tagID, "label": lbl.label}))
104                 : [{"id": tagID, "label": tagID}])
105             .reduce((prev, curr) => [...prev, ...curr], [])
106             .sort(compare)
107         : [];
108 };
109
110 export const getPreferredTags = ({ tags }: Vocabulary, withSynonyms?: boolean): PropFieldSuggestion[] => {
111     return tags && Object.keys(tags)
112         ? Object.keys(tags).map(
113             tagID => tags[tagID].labels && tags[tagID].labels.length > 0
114                 ? {
115                     "id": tagID,
116                     "label": tags[tagID].labels[0].label,
117                     "description": tags[tagID].labels[0].label + (
118                         withSynonyms && tags[tagID].labels.length > 1
119                         ? ` (${tags[tagID].labels.slice(1).map(lbl => lbl.label).join(', ')})`
120                         : ''
121                     )}
122                 : {"id": tagID, "label": tagID})
123             .sort(compare)
124         : [];
125 };
126
127 export const getTagKeyID = (tagKeyLabel:string, vocabulary: Vocabulary) =>
128     Object.keys(vocabulary.tags).find(
129         k => vocabulary.tags[k].labels.find(
130             l => l.label.toLowerCase() === tagKeyLabel.toLowerCase()) !== undefined
131         ) || '';
132
133 export const getTagKeyLabel = (tagKeyID:string, vocabulary: Vocabulary) =>
134     vocabulary.tags[tagKeyID] && vocabulary.tags[tagKeyID].labels.length > 0
135     ? vocabulary.tags[tagKeyID].labels[0].label
136     : tagKeyID;