0ed4b3f2338bb8cd5dfe4d590f4b3b040ca557d6
[arvados.git] / apps / workbench / app / assets / javascripts / components / edit_tags.js
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 window.SelectOrAutocomplete = {
6     view: function(vnode) {
7         return m("input", {
8             style: {
9                 width: '100%'
10             },
11             type: 'text',
12             value: vnode.attrs.value
13         }, vnode.attrs.value)
14     },
15     oncreate: function(vnode) {
16         $(vnode.dom).selectize({
17             labelField: 'value',
18             valueField: 'value',
19             searchField: 'value',
20             sortField: 'value',
21             maxItems: 1,
22             create: vnode.attrs.create ? function(input) {
23                 return {value: input}
24             } : false,
25             items: [vnode.attrs.value()],
26             options: vnode.attrs.options.map(function(option) {
27                 return {value: option}
28             }),
29             onChange: function(val) {
30                 vnode.attrs.value(val)
31             }
32         })
33     }
34 }
35
36 // When in edit mode, present a tag name selector and tag value
37 // selector/editor depending of the tag type.
38 window.TagEditorRow = {
39     view: function(vnode) {
40         // Value options list
41         valueOpts = []
42         if (vnode.attrs.name() in vnode.attrs.vocabulary().types &&
43             'options' in vnode.attrs.vocabulary().types[vnode.attrs.name()]) {
44                 valueOpts = vnode.attrs.vocabulary().types[vnode.attrs.name()].options
45         }
46         valueOpts.push(vnode.attrs.value())
47
48         return m("tr", [
49             // Erase tag
50             m("td",
51             vnode.attrs.editMode &&
52                 m('div.text-center', m('a.btn.btn-default.btn-sm', {
53                     style: {
54                         align: 'center'
55                     },
56                     onclick: function(e) { vnode.attrs.removeTag() }
57                 }, m('i.fa.fa-fw.fa-trash-o'))),
58             ),
59             // Tag name
60             m("td",
61             vnode.attrs.editMode ?
62             m("div", {key: 'name-'+vnode.attrs.name()},[m(SelectOrAutocomplete, {
63                 options: (vnode.attrs.name() in vnode.attrs.vocabulary().types)
64                     ? Object.keys(vnode.attrs.vocabulary().types)
65                     : Object.keys(vnode.attrs.vocabulary().types).concat(vnode.attrs.name()),
66                 value: vnode.attrs.name,
67                 create: vnode.attrs.vocabulary().strict
68             })])
69             : vnode.attrs.name),
70             // Tag value
71             m("td",
72             vnode.attrs.editMode ?
73             m("div", {key: 'value-'+vnode.attrs.name()}, [m(SelectOrAutocomplete, {
74                 options: valueOpts,
75                 value: vnode.attrs.value,
76                 create: (vnode.attrs.name() in vnode.attrs.vocabulary().types)
77                     ? (vnode.attrs.vocabulary().types[vnode.attrs.name()].type == 'text') || 
78                         vnode.attrs.vocabulary().types[vnode.attrs.name()].overridable || false
79                     : true, // If tag not in vocabulary, we should accept any value
80                 })
81             ])
82             : vnode.attrs.value)
83         ])
84     }
85 }
86
87 window.TagEditorTable = {
88     view: function(vnode) {
89         return m("table.table.table-condensed", {
90             border: "1"
91         }, [
92             m("colgroup", [
93                 m("col", {width:"5%"}),
94                 m("col", {width:"25%"}),
95                 m("col", {width:"70%"}),
96             ]),
97             m("thead", [
98                 m("tr", [
99                     m("th"),
100                     m("th", "Key"),
101                     m("th", "Value"),
102                 ])
103             ]),
104             m("tbody", [
105                 vnode.attrs.tags.map(function(tag, idx) {
106                     return m(TagEditorRow, {
107                         key: idx,
108                         removeTag: function() { vnode.attrs.tags.splice(idx, 1) },
109                         editMode: vnode.attrs.editMode,
110                         name: tag.name,
111                         value: tag.value,
112                         vocabulary: vnode.attrs.vocabulary
113                     })
114                 })
115             ]),
116         ])
117     }
118 }
119
120 window.TagEditorApp = {
121     oninit: function(vnode) {
122         vnode.state.sessionDB = new SessionDB()
123         // Get vocabulary
124         vnode.state.vocabulary = m.stream({"strict":false, "types":{}})
125         m.request('/vocabulary.json').then(vnode.state.vocabulary)
126         vnode.state.editMode = vnode.attrs.targetEditable
127         // Get tags
128         vnode.state.tags = []
129         vnode.state.isDirty = false
130         vnode.state.objPath = '/arvados/v1/'+vnode.attrs.targetController+'/'+vnode.attrs.targetUuid
131         vnode.state.sessionDB.request(
132             vnode.state.sessionDB.loadLocal(), vnode.state.objPath, {
133                 data: {
134                     select: JSON.stringify(['properties']) // FIXME: not working
135                 },
136             }).then(function(obj) {
137                 console.log(obj)
138                 Object.keys(obj.properties).forEach(function(k) {
139                     vnode.state.tags.push({
140                         name: m.stream(k),
141                         value: m.stream(obj.properties[k])
142                     })
143                 })
144                 vnode.state.dirty = m.stream(null)
145                 vnode.state.tags.map(function(tag) {
146                     console.log('connecting events for tag: '+tag.name())
147                     tag.name.map(m.redraw)
148                     tag.name.map(vnode.state.dirty)
149                     tag.value.map(vnode.state.dirty)
150                 })
151                 vnode.state.dirty.map(function() {
152                     vnode.state.isDirty = true
153                     console.log('dirty!')
154                 })
155                 console.log('Setting up isDirty to false')
156                 vnode.state.isDirty = false
157             }
158         )
159     },
160     view: function(vnode) {
161         return [
162             // Tags table
163             m(TagEditorTable, {
164                 editMode: vnode.state.editMode,
165                 tags: vnode.state.tags,
166                 vocabulary: vnode.state.vocabulary
167             }),
168             vnode.state.editMode &&
169             m("div", [
170                 m("div.pull-left", [
171                     // Add tag button
172                     m("a.btn.btn-primary.btn-sm", {
173                         onclick: function(e) {
174                             vnode.state.tags.push({
175                                 name: m.stream('new tag'),
176                                 value: m.stream('new tag value')
177                             })
178                         }
179                     }, [
180                         m("i.glyphicon.glyphicon-plus"),
181                         " Add new tag "
182                     ])
183                 ]),
184                 m("div.pull-right", [
185                     m("a.btn.btn-primary.btn-sm", {
186                         onclick: function(e) {
187                             var tags = {}
188                             vnode.state.tags.forEach(function(t) {
189                                 tags[t.name()] = t.value()
190                             })
191                             vnode.state.sessionDB.request(
192                                 vnode.state.sessionDB.loadLocal(),
193                                 vnode.state.objPath, {
194                                     method: "PUT",
195                                     data: {properties: JSON.stringify(tags)}
196                                 }
197                             ).then(function(v) {
198                                 console.log('ok!')
199                                 vnode.state.isDirty = false
200                             })
201                         }
202                     }, vnode.state.isDirty ? ' Save changes ' : ' Saved ')
203                 ])
204             ])
205         ]
206     },
207 }