Merge branch 'master' into 15067-tag-editing-by-ids
[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 }
31
32 const VOCABULARY_VALIDATORS = [
33     isObject,
34     has('strict_tags'),
35     has('tags'),
36 ];
37
38 export const isVocabulary = (value: any) =>
39     every(validator => validator(value), VOCABULARY_VALIDATORS);
40
41 export const isStrictTag = (tagKeyID: string, vocabulary: Vocabulary) => {
42     const tag = vocabulary.tags[tagKeyID];
43     return tag ? tag.strict : false;
44 };
45
46 export const getTagValueID = (tagKeyID:string, tagValueLabel:string, vocabulary: Vocabulary) =>
47     (tagKeyID && vocabulary.tags[tagKeyID] && vocabulary.tags[tagKeyID].values)
48     ? Object.keys(vocabulary.tags[tagKeyID].values!).find(
49         k => vocabulary.tags[tagKeyID].values![k].labels.find(
50             l => l.label === tagValueLabel) !== undefined) || ''
51     : '';
52
53 const compare = (a: PropFieldSuggestion, b: PropFieldSuggestion) => {
54     if (a.label < b.label) {return -1;}
55     if (a.label > b.label) {return 1;}
56     return 0;
57 };
58
59 export const getTagValues = (tagKeyID: string, vocabulary: Vocabulary) => {
60     const tag = vocabulary.tags[tagKeyID];
61     const ret = tag && tag.values
62         ? Object.keys(tag.values).map(
63             tagValueID => tag.values![tagValueID].labels
64                 ? tag.values![tagValueID].labels.map(
65                     lbl => Object.assign({}, {"id": tagValueID, "label": lbl.label}))
66                 : [{"id": tagValueID, "label": tagValueID}])
67             .reduce((prev, curr) => [...prev, ...curr], [])
68             .sort(compare)
69         : [];
70     return ret;
71 };
72
73 export const getTags = ({ tags }: Vocabulary) => {
74     const ret = tags && Object.keys(tags)
75         ? Object.keys(tags).map(
76             tagID => tags[tagID].labels
77                 ? tags[tagID].labels.map(
78                     lbl => Object.assign({}, {"id": tagID, "label": lbl.label}))
79                 : [{"id": tagID, "label": tagID}])
80             .reduce((prev, curr) => [...prev, ...curr], [])
81             .sort(compare)
82         : [];
83     return ret;
84 };
85
86 export const getTagKeyID = (tagKeyLabel:string, vocabulary: Vocabulary) =>
87     Object.keys(vocabulary.tags).find(
88         k => vocabulary.tags[k].labels.find(
89             l => l.label === tagKeyLabel) !== undefined) || '';