1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
6 view: function(vnode) {
7 return m("input.form-control", {
12 placeholder: vnode.attrs.placeholder,
13 value: vnode.attrs.value,
14 onchange: function() {
15 console.log(this.value)
16 if (this.value != '') {
17 vnode.attrs.value(this.value)
22 oncreate: function(vnode) {
23 if (vnode.attrs.setFocus) {
29 window.SelectOrAutocomplete = {
30 onFocus: function(vnode) {
31 // Allow the user to edit an already entered value by removing it
32 // and filling the input field with the same text
33 activeSelect = vnode.state.selectized[0].selectize
34 value = activeSelect.getValue()
35 if (value.length > 0) {
36 activeSelect.clear(silent = true)
37 activeSelect.setTextboxValue(value)
40 view: function(vnode) {
46 value: vnode.attrs.value
49 oncreate: function(vnode) {
50 vnode.state.selectized = $(vnode.dom).selectize({
60 placeholder: vnode.attrs.placeholder,
61 create: vnode.attrs.create ? function(input) {
64 items: [vnode.attrs.value()],
65 options: vnode.attrs.options.map(function(option) {
66 return {value: option}
68 onChange: function(val) {
70 vnode.attrs.value(val)
74 vnode.state.onFocus(vnode)
77 if (vnode.attrs.setFocus) {
78 vnode.state.selectized[0].selectize.focus()
83 window.TagEditorRow = {
84 view: function(vnode) {
85 var nameOpts = Object.keys(vnode.attrs.vocabulary().tags)
87 var inputComponent = SelectOrAutocomplete
88 if (nameOpts.length === 0) {
89 // If there's not vocabulary defined, switch to a simple input field
90 inputComponent = SimpleInput
93 if (vnode.attrs.name() != '' && !(vnode.attrs.name() in vnode.attrs.vocabulary().tags)) {
94 nameOpts.push(vnode.attrs.name())
97 if (vnode.attrs.name() in vnode.attrs.vocabulary().tags &&
98 'values' in vnode.attrs.vocabulary().tags[vnode.attrs.name()]) {
99 valueOpts = vnode.attrs.vocabulary().tags[vnode.attrs.name()].values
101 if (vnode.attrs.value() != '') {
102 valueOpts.push(vnode.attrs.value())
108 vnode.attrs.editMode &&
109 m('div.text-center', m('a.btn.btn-default.btn-sm', {
113 onclick: function(e) { vnode.attrs.removeTag() }
114 }, m('i.fa.fa-fw.fa-trash-o')))
118 vnode.attrs.editMode ?
119 m("div", {key: 'name-'+vnode.attrs.name()},[
122 value: vnode.attrs.name,
123 // Allow any tag name unless "strict" is set to true.
124 create: !vnode.attrs.vocabulary().strict,
125 placeholder: 'new tag',
126 // Focus on tag name field when adding a new tag that's
127 // not the first one.
128 setFocus: vnode.attrs.name() === ''
135 vnode.attrs.editMode ?
136 m("div", {key: 'value-'+vnode.attrs.name()}, [
139 value: vnode.attrs.value,
140 placeholder: 'new value',
141 // Allow any value on tags not listed on the vocabulary.
142 // Allow any value on tags without values, or the ones
143 // that aren't explicitly declared to be strict.
144 create: !(vnode.attrs.name() in vnode.attrs.vocabulary().tags)
145 || !vnode.attrs.vocabulary().tags[vnode.attrs.name()].values
146 || vnode.attrs.vocabulary().tags[vnode.attrs.name()].values.length === 0
147 || !vnode.attrs.vocabulary().tags[vnode.attrs.name()].strict,
148 // Focus on tag value field when new tag name is set
149 setFocus: vnode.attrs.name() !== '' && vnode.attrs.value() === ''
158 window.TagEditorTable = {
159 view: function(vnode) {
160 return m("table.table.table-condensed.table-justforlayout", [
162 m("col", {width:"5%"}),
163 m("col", {width:"25%"}),
164 m("col", {width:"70%"}),
174 vnode.attrs.tags.length > 0
175 ? vnode.attrs.tags.map(function(tag, idx) {
176 return m(TagEditorRow, {
178 removeTag: function() {
179 vnode.attrs.tags.splice(idx, 1)
180 vnode.attrs.dirty(true)
182 editMode: vnode.attrs.editMode,
185 vocabulary: vnode.attrs.vocabulary
188 : m("tr", m("td[colspan=3]", m("center","loading tags...")))
194 window.TagEditorApp = {
195 appendTag: function(vnode, name, value) {
196 var tag = {name: m.stream(name), value: m.stream(value)}
197 vnode.state.tags.push(tag)
198 // Set dirty flag when any of name/value changes to non empty string
199 tag.name.map(function(v) {
201 vnode.state.dirty(true)
204 tag.value.map(function(v) {
206 vnode.state.dirty(true)
209 tag.name.map(m.redraw)
211 oninit: function(vnode) {
212 vnode.state.sessionDB = new SessionDB()
214 vnode.state.vocabulary = m.stream({"strict":false, "tags":{}})
215 m.request('/vocabulary.json').then(vnode.state.vocabulary)
216 vnode.state.editMode = vnode.attrs.targetEditable
217 vnode.state.tags = []
218 vnode.state.dirty = m.stream(false)
219 vnode.state.dirty.map(m.redraw)
220 vnode.state.objPath = '/arvados/v1/'+vnode.attrs.targetController+'/'+vnode.attrs.targetUuid
222 vnode.state.sessionDB.request(
223 vnode.state.sessionDB.loadLocal(),
224 '/arvados/v1/'+vnode.attrs.targetController,
227 filters: JSON.stringify([['uuid', '=', vnode.attrs.targetUuid]]),
228 select: JSON.stringify(['properties'])
230 }).then(function(obj) {
231 if (obj.items.length == 1) {
233 Object.keys(o.properties).forEach(function(k) {
234 vnode.state.appendTag(vnode, k, o.properties[k])
236 // Data synced with server, so dirty state should be false
237 vnode.state.dirty(false)
238 // Add new tag row when the last one is completed
239 vnode.state.dirty.map(function() {
240 if (!vnode.state.editMode) { return }
241 lastTag = vnode.state.tags.slice(-1).pop()
242 if (lastTag === undefined || (lastTag.name() !== '' && lastTag.value() !== '')) {
243 vnode.state.appendTag(vnode, '', '')
250 view: function(vnode) {
252 vnode.state.editMode &&
254 m("a.btn.btn-primary.btn-sm"+(vnode.state.dirty() ? '' : '.disabled'), {
258 onclick: function(e) {
260 vnode.state.tags.forEach(function(t) {
261 if (t.name() != '' && t.value() != '') {
262 tags[t.name()] = t.value()
265 vnode.state.sessionDB.request(
266 vnode.state.sessionDB.loadLocal(),
267 vnode.state.objPath, {
269 data: {properties: JSON.stringify(tags)}
272 vnode.state.dirty(false)
275 }, vnode.state.dirty() ? ' Save changes ' : ' Saved ')
279 editMode: vnode.state.editMode,
280 tags: vnode.state.tags,
281 vocabulary: vnode.state.vocabulary,
282 dirty: vnode.state.dirty