@5minds/node-red-dashboard-2-processcube-dynamic-form 1.1.2 → 2.0.0-develop-5015e2-madmxd10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,770 +1,852 @@
1
1
  <template>
2
- <!-- Component must be wrapped in a block so props such as className and style can be passed in from parent -->
3
- <div className="ui-dynamic-form-wrapper">
4
- <p v-if="hasFields()">
5
- <v-form ref="form" v-model="form" :class="dynamicClass">
6
- <h3 style="padding: 16px">{{ this.props.name }}</h3>
7
- <div style="padding: 16px; max-height: 550px; overflow-y: auto">
8
- <FormKit type="group" id="form">
9
- <v-row v-for="(field, index) in fields()" :key="field">
10
- <v-col cols="12">
11
- <component
12
- v-if="createComponent(field).innerText"
13
- :is="createComponent(field).type"
14
- v-bind="createComponent(field).props"
15
- v-model="formData[field.id]"
16
- >
17
- {{ createComponent(field).innerText }}
18
- </component>
19
- <div v-else-if="createComponent(field).type == 'v-slider'">
20
- <p class="formkit-label">{{ field.label }}</p>
21
- <component
22
- :is="createComponent(field).type"
23
- v-bind="createComponent(field).props"
24
- v-model="field.defaultValue"
25
- />
26
- <p class="formkit-help">
27
- {{ field.customForm ? JSON.parse(field.customForm).hint : undefined }}
28
- </p>
29
- </div>
30
- <component
31
- v-else
32
- :is="createComponent(field).type"
33
- v-bind="createComponent(field).props"
34
- v-model="formData[field.id]"
35
- />
36
- </v-col>
37
- </v-row>
38
- </FormKit>
2
+ <div className="ui-dynamic-form-external-sizing-wrapper" :style="props.card_size_styling">
3
+ <!-- Component must be wrapped in a block so props such as className and style can be passed in from parent -->
4
+ <UIDynamicFormTitleText
5
+ v-if="props.title_style === 'outside' && hasUserTask"
6
+ :style="props.title_style"
7
+ :title="props.title_text"
8
+ :customStyles="props.title_custom_text_styling"
9
+ :titleIcon="props.title_icon"
10
+ :collapsible="props.collapsible || (props.collapse_when_finished && formIsFinished)"
11
+ :collapsed="collapsed"
12
+ :toggleCollapse="toggleCollapse"
13
+ />
14
+ <div className="ui-dynamic-form-wrapper">
15
+ <p v-if="hasUserTask" style="margin-bottom: 0px;">
16
+ <v-form ref="form" v-model="form" :class="dynamicClass">
17
+ <UIDynamicFormTitleText
18
+ v-if="props.title_style != 'outside'"
19
+ :style="props.title_style"
20
+ :title="props.title_text"
21
+ :customStyles="props.title_custom_text_styling"
22
+ :titleIcon="props.title_icon"
23
+ :collapsible="props.collapsible || (props.collapse_when_finished && formIsFinished)"
24
+ :collapsed="collapsed"
25
+ :toggleCollapse="toggleCollapse"
26
+ />
27
+ <Transition name="cardCollapse">
28
+ <div v-if="!collapsed">
29
+ <div className="ui-dynamic-form-formfield-positioner">
30
+ <FormKit id="form" type="group">
31
+ <v-row v-for="(field, index) in fields()" :key="field" :style="getRowWidthStyling(field, index)">
32
+ <v-col cols="12">
33
+ <component
34
+ :is="createComponent(field).type"
35
+ v-if="createComponent(field).innerText"
36
+ v-bind="createComponent(field).props"
37
+ v-model="formData[field.id]"
38
+ >
39
+ {{ createComponent(field).innerText }}
40
+ </component>
41
+ <div v-else-if="createComponent(field).type == 'v-slider'">
42
+ <p class="formkit-label">{{ field.label }}</p>
43
+ <component
44
+ :is="createComponent(field).type"
45
+ v-bind="createComponent(field).props"
46
+ v-model="field.defaultValue"
47
+ />
48
+ <p class="formkit-help">
49
+ {{ field.customForm ? JSON.parse(field.customForm).hint : undefined }}
50
+ </p>
51
+ </div>
52
+ <component
53
+ :is="createComponent(field).type"
54
+ v-else
55
+ v-bind="createComponent(field).props"
56
+ v-model="formData[field.id]"
57
+ />
58
+ </v-col>
59
+ </v-row>
60
+ </FormKit>
61
+ </div>
62
+ <v-row :class="dynamicFooterClass">
63
+ <v-row v-if="errorMsg.length > 0" style="padding: 12px">
64
+ <v-alert type="error">Error: {{ errorMsg }}</v-alert>
65
+ </v-row>
66
+ <UIDynamicFormFooterAction v-if="props.actions_inside_card && actions.length > 0" :actions="actions" :actionCallback="actionFn" :formIsFinished="formIsFinished" style="padding: 16px; padding-top: 0px;" />
67
+ </v-row>
68
+ </div>
69
+ </Transition>
70
+ </v-form>
71
+ </p>
72
+ <p v-else>
73
+ <v-alert v-if="props.waiting_info.length > 0 || props.waiting_title.length > 0" :text="props.waiting_info" :title="props.waiting_title" />
74
+ </p>
39
75
  </div>
40
- <v-row :class="dynamicFooterClass">
41
- <v-row v-if="error" style="padding: 12px">
42
- <v-alert v-if="error" type="error">Error: {{ errorMsg }}</v-alert>
43
- </v-row>
44
- <div style="display: flex; gap: 8px">
45
- <div v-for="(action, index) in actions" :key="index" style="flex-grow: 1">
46
- <v-btn :key="index" style="width: 100% !important; min-height: 36px" @click="actionFn(action)">
47
- {{ action.label }}
48
- </v-btn>
49
- </div>
50
- </div>
51
- </v-row>
52
- </v-form>
53
- </p>
54
- <p v-else>
55
- <v-alert :text="waiting_info" :title="waiting_title" />
56
- </p>
57
- </div>
76
+ <div v-if="!props.actions_inside_card && actions.length > 0 && hasUserTask" style="padding-top: 32px;">
77
+ <UIDynamicFormFooterAction :actions="actions" :actionCallback="actionFn" />
78
+ </div>
79
+ </div>
58
80
  </template>
59
81
 
82
+ <!-- eslint-disable no-case-declarations -->
60
83
  <script>
61
- import { markRaw, h, getCurrentInstance } from 'vue';
62
- import { mapState } from 'vuex';
63
- import { plugin, defaultConfig } from '@formkit/vue';
64
- import '@formkit/themes/genesis';
65
- import { FormKit } from '@formkit/vue';
66
- import { getNode } from '@formkit/core';
84
+ import { FormKit, defaultConfig, plugin } from '@formkit/vue'
85
+ import { getCurrentInstance, markRaw } from 'vue'
86
+
87
+ // eslint-disable-next-line import/no-unresolved
88
+ import '@formkit/themes/genesis'
89
+ import UIDynamicFormFooterAction from './FooterActions.vue'
90
+ import UIDynamicFormTitleText from './TitleText.vue'
67
91
 
68
92
  export default {
69
- name: 'UIDynamicForm',
70
- inject: ['$socket'],
71
- props: {
93
+ name: 'UIDynamicForm',
94
+ components: {
95
+ FormKit, UIDynamicFormFooterAction, UIDynamicFormTitleText
96
+ },
97
+ inject: ['$socket'],
98
+ props: {
72
99
  /* do not remove entries from this - Dashboard's Layout Manager's will pass this data to your component */
73
- id: { type: String, required: true },
74
- props: { type: Object, default: () => ({}) },
75
- state: {
76
- type: Object,
77
- default: () => ({ enabled: false, visible: false }),
100
+ id: { type: String, required: true },
101
+ props: { type: Object, default: () => ({}) },
102
+ state: {
103
+ type: Object,
104
+ default: () => ({ enabled: false, visible: false })
105
+ }
78
106
  },
79
- },
80
- setup(props) {
81
- console.info('UIDynamicForm setup with:', props);
82
- console.debug('Vue function loaded correctly', markRaw);
83
- const instance = getCurrentInstance();
84
- const app = instance.appContext.app;
85
- const formkitConfig = defaultConfig({
86
- theme: 'genesis',
87
- });
88
- app.use(plugin, formkitConfig);
89
- },
90
- data() {
91
- return {
92
- actions: [],
93
- form: {},
94
- formData: {},
95
- taskInput: {},
96
- theme: '',
97
- error: false,
98
- errorMsg: '',
99
- };
100
- },
101
- created() {
102
- const currentPath = window.location.pathname;
103
- const lastPart = currentPath.substring(currentPath.lastIndexOf('/'));
104
-
105
- const store = this.$store.state;
106
-
107
- for (let key in store.ui.pages) {
108
- if (store.ui.pages[key].path === lastPart) {
109
- const theme = store.ui.pages[key].theme;
110
- if (store.ui.themes[theme].name === 'ProcessCube Lightmode') {
111
- this.theme = 'light';
112
- } else if (store.ui.themes[theme].name === 'ProcessCube Darkmode') {
113
- this.theme = 'dark';
114
- } else {
115
- this.theme = 'default';
107
+ setup (props) {
108
+ console.info('UIDynamicForm setup with:', props)
109
+ console.debug('Vue function loaded correctly', markRaw)
110
+ const instance = getCurrentInstance()
111
+ const app = instance.appContext.app
112
+ const formkitConfig = defaultConfig({
113
+ theme: 'genesis'
114
+ })
115
+ app.use(plugin, formkitConfig)
116
+ },
117
+ data () {
118
+ return {
119
+ actions: [],
120
+ formData: {},
121
+ userTask: null,
122
+ theme: '',
123
+ errorMsg: '',
124
+ formIsFinished: false,
125
+ msg: null,
126
+ collapsed: false
116
127
  }
117
- break;
118
- }
119
- }
120
- },
121
- computed: {
122
- ...mapState('data', ['messages']),
123
- waiting_title() {
124
- return this.props.waiting_title || 'Warten auf den Usertask...';
125
128
  },
126
- waiting_info() {
127
- return (
128
- this.props.waiting_info ||
129
- 'Der Usertask wird automatisch angezeigt, wenn ein entsprechender Task vorhanden ist.'
130
- );
129
+ computed: {
130
+ dynamicClass () {
131
+ return `ui-dynamic-form-${this.theme} ui-dynamic-form-common`
132
+ },
133
+ dynamicFooterClass () {
134
+ return `ui-dynamic-form-footer-${this.theme} ui-dynamic-form-footer-common`
135
+ },
136
+ hasUserTask () {
137
+ return !!this.userTask
138
+ }
131
139
  },
132
-
133
- dynamicClass() {
134
- return `ui-dynamic-form-${this.theme}`;
140
+ watch: {
141
+ formData: {
142
+ handler (newData, oldData) {
143
+ if (this.props.trigger_on_change) {
144
+ const res = { payload: { formData: newData, userTask: this.userTask } }
145
+ this.send(res, this.actions.length)
146
+ }
147
+ },
148
+ deep: true
149
+ }
135
150
  },
151
+ created () {
152
+ const currentPath = window.location.pathname
153
+ const lastPart = currentPath.substring(currentPath.lastIndexOf('/'))
136
154
 
137
- dynamicFooterClass() {
138
- return `ui-dynamic-form-footer-${this.theme}`;
139
- },
140
- },
141
- mounted() {
142
- const elements = document.querySelectorAll('.formkit-input');
155
+ const store = this.$store.state
143
156
 
144
- elements.forEach((element) => {
145
- element.classList.add('test');
146
- });
157
+ for (const key in store.ui.pages) {
158
+ if (store.ui.pages[key].path === lastPart) {
159
+ const theme = store.ui.pages[key].theme
160
+ if (store.ui.themes[theme].name === 'ProcessCube Lightmode') {
161
+ this.theme = 'light'
162
+ } else if (store.ui.themes[theme].name === 'ProcessCube Darkmode') {
163
+ this.theme = 'dark'
164
+ } else {
165
+ this.theme = 'default'
166
+ }
167
+ break
168
+ }
169
+ }
170
+ },
171
+ mounted () {
172
+ const elements = document.querySelectorAll('.formkit-input')
147
173
 
148
- this.$socket.on('widget-load:' + this.id, (msg) => {
149
- this.init();
150
- this.$store.commit('data/bind', {
151
- widgetId: this.id,
152
- msg,
153
- });
154
- });
155
- this.$socket.on('msg-input:' + this.id, (msg) => {
156
- // store the latest message in our client-side vuex store when we receive a new message
157
- this.init();
174
+ elements.forEach((element) => {
175
+ element.classList.add('test')
176
+ })
158
177
 
159
- this.messages[this.id] = msg;
178
+ this.$socket.on('widget-load:' + this.id, (msg) => {
179
+ this.init(msg)
180
+ })
181
+ this.$socket.on('msg-input:' + this.id, (msg) => {
182
+ // store the latest message in our client-side vuex store when we receive a new message
183
+ this.init(msg)
184
+ })
185
+ // tell Node-RED that we're loading a new instance of this widget
186
+ this.$socket.emit('widget-load', this.id)
187
+ },
188
+ unmounted () {
189
+ /* Make sure, any events you subscribe to on SocketIO are unsubscribed to here */
190
+ this.$socket?.off('widget-load' + this.id)
191
+ this.$socket?.off('msg-input:' + this.id)
192
+ },
193
+ methods: {
194
+ createComponent (field) {
195
+ const customForm = field.customForm ? JSON.parse(field.customForm) : {}
196
+ const hint = customForm.hint
197
+ const placeholder = customForm.placeholder
198
+ const validation = customForm.validation
199
+ const name = field.id
200
+ const customProperties = customForm.customProperties ?? []
201
+ const isReadOnly = (
202
+ this.props.readonly || this.formIsFinished || customProperties.find(entry => ['readOnly', 'readonly'].includes(entry.name) && entry.value === 'true'))
203
+ ? 'true'
204
+ : undefined
205
+ switch (field.type) {
206
+ case 'long':
207
+ return {
208
+ type: 'FormKit',
209
+ props: {
210
+ type: 'number',
211
+ id: field.id,
212
+ name,
213
+ label: field.label,
214
+ required: field.required,
215
+ value: this.formData[field.id],
216
+ number: 'integer',
217
+ help: hint,
218
+ wrapperClass: '$remove:formkit-wrapper',
219
+ labelClass: 'ui-dynamic-form-input-label',
220
+ inputClass: `input-${this.theme}`,
221
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
222
+ readonly: isReadOnly,
223
+ validation,
224
+ validationVisibility: 'live'
225
+ }
226
+ }
227
+ case 'number':
228
+ const step = field.customForm ? JSON.parse(field.customForm).step : undefined
229
+ return {
230
+ type: 'FormKit',
231
+ props: {
232
+ type: 'number',
233
+ id: field.id,
234
+ name,
235
+ label: field.label,
236
+ required: field.required,
237
+ value: this.formData[field.id],
238
+ step,
239
+ help: hint,
240
+ wrapperClass: '$remove:formkit-wrapper',
241
+ labelClass: 'ui-dynamic-form-input-label',
242
+ inputClass: `input-${this.theme}`,
243
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
244
+ readonly: isReadOnly,
245
+ validation,
246
+ validationVisibility: 'live'
247
+ }
248
+ }
249
+ case 'date':
250
+ return {
251
+ type: 'FormKit',
252
+ props: {
253
+ type: 'date',
254
+ id: field.id,
255
+ name,
256
+ label: field.label,
257
+ required: field.required,
258
+ value: this.formData[field.id],
259
+ help: hint,
260
+ wrapperClass: '$remove:formkit-wrapper',
261
+ labelClass: 'ui-dynamic-form-input-label',
262
+ inputClass: `input-${this.theme}`,
263
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
264
+ readonly: isReadOnly,
265
+ validation,
266
+ validationVisibility: 'live'
267
+ }
268
+ }
269
+ case 'enum':
270
+ const enums = field.enumValues.map((obj) => {
271
+ return { value: obj.id, label: obj.name }
272
+ })
273
+ return {
274
+ type: 'FormKit',
275
+ props: {
276
+ type: 'select', // JSON.parse(field.customForm).displayAs
277
+ id: field.id,
278
+ name,
279
+ label: field.label,
280
+ required: field.required,
281
+ value: this.formData[field.id],
282
+ options: enums,
283
+ help: hint,
284
+ wrapperClass: '$remove:formkit-wrapper',
285
+ labelClass: 'ui-dynamic-form-input-label',
286
+ inputClass: `input-${this.theme}`,
287
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
288
+ readonly: isReadOnly,
289
+ disabled: isReadOnly,
290
+ validation,
291
+ validationVisibility: 'live'
292
+ }
293
+ }
294
+ case 'select':
295
+ const selections = JSON.parse(field.customForm).entries.map((obj) => {
296
+ return { value: obj.key, label: obj.value }
297
+ })
298
+ return {
299
+ type: 'FormKit',
300
+ props: {
301
+ type: 'select', // JSON.parse(field.customForm).displayAs
302
+ id: field.id,
303
+ name,
304
+ label: field.label,
305
+ required: field.required,
306
+ value: this.formData[field.id],
307
+ options: selections,
308
+ placeholder,
309
+ help: hint,
310
+ wrapperClass: '$remove:formkit-wrapper',
311
+ labelClass: 'ui-dynamic-form-input-label',
312
+ inputClass: `input-${this.theme}`,
313
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
314
+ readonly: isReadOnly,
315
+ disabled: isReadOnly,
316
+ validation,
317
+ validationVisibility: 'live'
318
+ }
319
+ }
320
+ case 'string':
321
+ return {
322
+ type: 'FormKit',
323
+ props: {
324
+ type: 'text',
325
+ id: field.id,
326
+ name,
327
+ label: field.label,
328
+ required: field.required,
329
+ value: this.formData[field.id],
330
+ help: hint,
331
+ placeholder,
332
+ wrapperClass: '$remove:formkit-wrapper',
333
+ labelClass: 'ui-dynamic-form-input-label',
334
+ inputClass: `input-${this.theme}`,
335
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
336
+ readonly: isReadOnly,
337
+ validation,
338
+ validationVisibility: 'live'
339
+ }
340
+ }
341
+ case 'boolean':
342
+ return {
343
+ type: 'FormKit',
344
+ props: {
345
+ type: 'checkbox',
346
+ id: field.id,
347
+ name,
348
+ label: field.label,
349
+ required: field.required,
350
+ value: this.formData[field.id],
351
+ help: hint,
352
+ labelClass: 'ui-dynamic-form-input-label',
353
+ inputClass: `input-${this.theme}`,
354
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
355
+ readonly: isReadOnly,
356
+ disabled: isReadOnly,
357
+ validation,
358
+ validationVisibility: 'live'
359
+ }
360
+ }
361
+ case 'file':
362
+ return {
363
+ type: 'FormKit',
364
+ props: {
365
+ type: 'file',
366
+ id: field.id,
367
+ name,
368
+ label: field.label,
369
+ required: field.required,
370
+ value: this.formData[field.id],
371
+ help: hint,
372
+ innerClass: 'reset-background',
373
+ wrapperClass: '$remove:formkit-wrapper',
374
+ labelClass: 'ui-dynamic-form-input-label',
375
+ inputClass: `input-${this.theme}`,
376
+ // innerClass: ui-dynamic-form-input-outlines `${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
377
+ readonly: isReadOnly,
378
+ disabled: isReadOnly,
379
+ validation,
380
+ validationVisibility: 'live'
381
+ }
382
+ }
383
+ case 'checkbox':
384
+ const options = JSON.parse(field.customForm).entries.map((obj) => {
385
+ return { value: obj.key, label: obj.value }
386
+ })
387
+ return {
388
+ type: 'FormKit',
389
+ props: {
390
+ type: 'checkbox',
391
+ id: field.id,
392
+ name,
393
+ label: field.label,
394
+ required: field.required,
395
+ value: this.formData[field.id],
396
+ options,
397
+ help: hint,
398
+ fieldsetClass: 'custom-fieldset',
399
+ labelClass: 'ui-dynamic-form-input-label',
400
+ inputClass: `input-${this.theme}`,
401
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
402
+ readonly: isReadOnly,
403
+ disabled: isReadOnly,
404
+ validation,
405
+ validationVisibility: 'live'
406
+ }
407
+ }
408
+ case 'color':
409
+ return {
410
+ type: 'FormKit',
411
+ props: {
412
+ type: 'color',
413
+ id: field.id,
414
+ name,
415
+ label: field.label,
416
+ required: field.required,
417
+ value: this.formData[field.id],
418
+ help: hint,
419
+ readonly: isReadOnly,
420
+ disabled: isReadOnly,
421
+ validation,
422
+ validationVisibility: 'live'
423
+ }
424
+ }
425
+ case 'datetime-local':
426
+ return {
427
+ type: 'FormKit',
428
+ props: {
429
+ type: 'datetime-local',
430
+ id: field.id,
431
+ name,
432
+ label: field.label,
433
+ required: field.required,
434
+ value: this.formData[field.id],
435
+ help: hint,
436
+ wrapperClass: '$remove:formkit-wrapper',
437
+ labelClass: 'ui-dynamic-form-input-label',
438
+ inputClass: `input-${this.theme}`,
439
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
440
+ readonly: isReadOnly,
441
+ validation,
442
+ validationVisibility: 'live'
443
+ }
444
+ }
445
+ case 'email':
446
+ return {
447
+ type: 'FormKit',
448
+ props: {
449
+ type: 'email',
450
+ id: field.id,
451
+ name,
452
+ label: field.label,
453
+ required: field.required,
454
+ value: this.formData[field.id],
455
+ help: hint,
456
+ placeholder,
457
+ wrapperClass: '$remove:formkit-wrapper',
458
+ labelClass: 'ui-dynamic-form-input-label',
459
+ inputClass: `input-${this.theme}`,
460
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
461
+ readonly: isReadOnly,
462
+ validation,
463
+ validationVisibility: 'live'
464
+ }
465
+ }
466
+ case 'header':
467
+ let typeToUse = 'h1'
468
+ if (field.customForm && JSON.parse(field.customForm).style === 'heading_2') {
469
+ typeToUse = 'h2'
470
+ }
471
+ if (field.customForm && JSON.parse(field.customForm).style === 'heading_3') {
472
+ typeToUse = 'h3'
473
+ }
474
+ return {
475
+ type: typeToUse,
476
+ innerText: this.formData[field.id]
477
+ }
478
+ case 'hidden':
479
+ return {
480
+ type: 'input',
481
+ props: {
482
+ type: 'hidden',
483
+ value: this.formData[field.id]
484
+ }
485
+ }
486
+ case 'month':
487
+ return {
488
+ type: 'FormKit',
489
+ props: {
490
+ type: 'month',
491
+ id: field.id,
492
+ name,
493
+ label: field.label,
494
+ required: field.required,
495
+ value: this.formData[field.id],
496
+ help: hint,
497
+ wrapperClass: '$remove:formkit-wrapper',
498
+ labelClass: 'ui-dynamic-form-input-label',
499
+ inputClass: `input-${this.theme}`,
500
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
501
+ readonly: isReadOnly,
502
+ validation,
503
+ validationVisibility: 'live'
504
+ }
505
+ }
506
+ case 'paragraph':
507
+ return {
508
+ type: 'p',
509
+ innerText: this.formData[field.id]
510
+ }
511
+ case 'password':
512
+ return {
513
+ type: 'FormKit',
514
+ props: {
515
+ type: 'password',
516
+ id: field.id,
517
+ name,
518
+ label: field.label,
519
+ required: field.required,
520
+ value: this.formData[field.id],
521
+ help: hint,
522
+ placeholder,
523
+ wrapperClass: '$remove:formkit-wrapper',
524
+ labelClass: 'ui-dynamic-form-input-label',
525
+ inputClass: `input-${this.theme}`,
526
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
527
+ readonly: isReadOnly,
528
+ validation,
529
+ validationVisibility: 'live'
530
+ }
531
+ }
532
+ case 'radio':
533
+ const radioOptions = JSON.parse(field.customForm).entries.map((obj) => {
534
+ return { value: obj.key, label: obj.value }
535
+ })
536
+ return {
537
+ type: 'FormKit',
538
+ props: {
539
+ type: 'radio',
540
+ id: field.id,
541
+ name,
542
+ label: field.label,
543
+ required: field.required,
544
+ value: this.formData[field.id],
545
+ options: radioOptions,
546
+ help: hint,
547
+ fieldsetClass: 'custom-fieldset',
548
+ labelClass: 'ui-dynamic-form-input-label',
549
+ inputClass: `input-${this.theme}`,
550
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
551
+ readonly: isReadOnly,
552
+ disabled: isReadOnly,
553
+ validation,
554
+ validationVisibility: 'live'
555
+ }
556
+ }
557
+ case 'range':
558
+ const customForm = JSON.parse(field.customForm)
559
+ return {
560
+ type: 'v-slider',
561
+ props: {
562
+ id: field.id,
563
+ name,
564
+ // label: field.label,
565
+ required: field.required,
566
+ // value: this.formData[field.id],
567
+ // help: hint,
568
+ min: customForm.min,
569
+ max: customForm.max,
570
+ step: customForm.step,
571
+ thumbLabel: true,
572
+ // wrapperClass: '$remove:formkit-wrapper',
573
+ labelClass: 'ui-dynamic-form-input-label',
574
+ // inputClass: `input-${this.theme}`,
575
+ // innerClass: ui-dynamic-form-input-outlines `${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
576
+ readonly: isReadOnly,
577
+ disabled: isReadOnly,
578
+ validation,
579
+ validationVisibility: 'live'
580
+ }
581
+ }
582
+ case 'tel':
583
+ return {
584
+ type: 'FormKit',
585
+ props: {
586
+ type: 'tel' /* with pro component mask more good */,
587
+ id: field.id,
588
+ name,
589
+ label: field.label,
590
+ required: field.required,
591
+ value: this.formData[field.id],
592
+ help: hint,
593
+ placeholder,
594
+ wrapperClass: '$remove:formkit-wrapper',
595
+ labelClass: 'ui-dynamic-form-input-label',
596
+ inputClass: `input-${this.theme}`,
597
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
598
+ readonly: isReadOnly,
599
+ validation,
600
+ validationVisibility: 'live'
601
+ }
602
+ }
603
+ case 'textarea':
604
+ const rows = field.customForm ? JSON.parse(field.customForm).rows : undefined
605
+ return {
606
+ type: 'FormKit',
607
+ props: {
608
+ type: 'textarea' /* with pro component mask more good */,
609
+ id: field.id,
610
+ name,
611
+ label: field.label,
612
+ required: field.required,
613
+ value: this.formData[field.id],
614
+ rows,
615
+ help: hint,
616
+ placeholder,
617
+ wrapperClass: '$remove:formkit-wrapper',
618
+ labelClass: 'ui-dynamic-form-input-label',
619
+ inputClass: `input-${this.theme}`,
620
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
621
+ readonly: isReadOnly,
622
+ validation,
623
+ validationVisibility: 'live'
624
+ }
625
+ }
626
+ case 'time':
627
+ return {
628
+ type: 'FormKit',
629
+ props: {
630
+ type: 'time' /* with pro component mask more good */,
631
+ id: field.id,
632
+ name,
633
+ label: field.label,
634
+ required: field.required,
635
+ value: this.formData[field.id],
636
+ help: hint,
637
+ placeholder,
638
+ wrapperClass: '$remove:formkit-wrapper',
639
+ labelClass: 'ui-dynamic-form-input-label',
640
+ inputClass: `input-${this.theme}`,
641
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
642
+ readonly: isReadOnly,
643
+ validation,
644
+ validationVisibility: 'live'
645
+ }
646
+ }
647
+ case 'url':
648
+ return {
649
+ type: 'FormKit',
650
+ props: {
651
+ type: 'url',
652
+ id: field.id,
653
+ name,
654
+ label: field.label,
655
+ required: field.required,
656
+ value: this.formData[field.id],
657
+ help: hint,
658
+ placeholder,
659
+ wrapperClass: '$remove:formkit-wrapper',
660
+ labelClass: 'ui-dynamic-form-input-label',
661
+ inputClass: `input-${this.theme}`,
662
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
663
+ readonly: isReadOnly,
664
+ validation,
665
+ validationVisibility: 'live'
666
+ }
667
+ }
668
+ case 'week':
669
+ return {
670
+ type: 'FormKit',
671
+ props: {
672
+ type: 'week',
673
+ id: field.id,
674
+ name,
675
+ label: field.label,
676
+ required: field.required,
677
+ value: this.formData[field.id],
678
+ help: hint,
679
+ placeholder,
680
+ wrapperClass: '$remove:formkit-wrapper',
681
+ labelClass: 'ui-dynamic-form-input-label',
682
+ inputClass: `input-${this.theme}`,
683
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
684
+ readonly: isReadOnly,
685
+ validation,
686
+ validationVisibility: 'live'
687
+ }
688
+ }
689
+ default:
690
+ return {
691
+ type: 'FormKit',
692
+ props: {
693
+ type: field.type,
694
+ id: field.id,
695
+ name,
696
+ label: field.label,
697
+ required: field.required,
698
+ value: this.formData[field.id],
699
+ help: hint,
700
+ labelClass: 'ui-dynamic-form-input-label',
701
+ inputClass: `input-${this.theme}`,
702
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
703
+ readonly: isReadOnly,
704
+ validation,
705
+ validationVisibility: 'live'
706
+ }
707
+ }
708
+ }
709
+ },
710
+ toggleCollapse () {
711
+ this.collapsed = !this.collapsed
712
+ },
713
+ getRowWidthStyling (field, index) {
714
+ let style = ''
715
+ if (index === 0) {
716
+ style += 'margin-top: 12px;'
717
+ }
718
+ if (field.type === 'header') {
719
+ style += 'flex-basis: 100%;'
720
+ } else {
721
+ style += `flex-basis: ${1 / this.props.form_columns * 100}%;`
722
+ }
723
+ return style
724
+ },
725
+ fields () {
726
+ const aFields = this.userTask.userTaskConfig?.formFields ?? []
727
+ const fieldMap = aFields.map((field) => ({
728
+ ...field,
729
+ items: mapItems(field.type, field)
730
+ }))
160
731
 
161
- const hasTask = msg.payload && msg.payload.userTask;
162
- const defaultValues = msg.payload.userTask.userTaskConfig.formFields;
163
- const initialValues = msg.payload.userTask.startToken;
732
+ return fieldMap
733
+ },
734
+ /*
735
+ widget-action just sends a msg to Node-RED, it does not store the msg state server-side
736
+ alternatively, you can use widget-change, which will also store the msg in the Node's datastore
737
+ */
738
+ send (msg, index) {
739
+ const msgArr = []
740
+ msgArr[index] = msg
741
+ this.$socket.emit('widget-action', this.id, msgArr)
742
+ },
743
+ init (msg) {
744
+ this.msg = msg
745
+ if (!msg) {
746
+ return
747
+ }
164
748
 
165
- if (hasTask) {
166
- this.taskInput = msg.payload.userTask;
167
- }
749
+ this.actions = this.props.options
168
750
 
169
- if (hasTask && defaultValues) {
170
- defaultValues.forEach((field) => {
171
- this.formData[field.id] = field.defaultValue;
172
- });
173
- }
751
+ const hasTask = msg.payload && msg.payload.userTask
174
752
 
175
- if (hasTask && initialValues) {
176
- Object.keys(initialValues).forEach((key) => {
177
- this.formData[key] = initialValues[key];
178
- });
179
- }
753
+ if (hasTask) {
754
+ this.userTask = msg.payload.userTask
755
+ } else {
756
+ this.userTask = null
757
+ this.formData = {}
758
+ return
759
+ }
180
760
 
181
- this.$store.commit('data/bind', {
182
- widgetId: this.id,
183
- msg,
184
- });
185
- });
186
- // tell Node-RED that we're loading a new instance of this widget
187
- this.$socket.emit('widget-load', this.id);
188
- },
189
- unmounted() {
190
- /* Make sure, any events you subscribe to on SocketIO are unsubscribed to here */
191
- this.$socket?.off('widget-load' + this.id);
192
- this.$socket?.off('msg-input:' + this.id);
193
- },
194
- components: {
195
- FormKit,
196
- },
197
- methods: {
198
- createComponent(field) {
199
- const hint = field.customForm ? JSON.parse(field.customForm).hint : undefined;
200
- const placeholder = field.customForm ? JSON.parse(field.customForm).placeholder : undefined;
201
- const validation = field.customForm ? JSON.parse(field.customForm).validation : undefined;
202
- const name = field.id;
761
+ const formFields = this.userTask.userTaskConfig.formFields
762
+ const formFieldIds = formFields.map(ff => ff.id)
763
+ const initialValues = this.userTask.startToken
764
+ const finishedFormData = msg.payload.formData
765
+ this.formIsFinished = !!msg.payload.formData
766
+ if (this.formIsFinished) {
767
+ this.collapsed = this.props.collapse_when_finished
768
+ }
203
769
 
204
- switch (field.type) {
205
- case 'long':
206
- return {
207
- type: 'FormKit',
208
- props: {
209
- type: 'number',
210
- id: field.id,
211
- name: name,
212
- label: field.label,
213
- required: field.required,
214
- value: field.defaultValue,
215
- number: 'integer',
216
- help: hint,
217
- wrapperClass: '$remove:formkit-wrapper',
218
- inputClass: `input-${this.theme}`,
219
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
220
- validation: validation,
221
- validationVisibility: 'live',
222
- },
223
- };
224
- case 'number':
225
- const step = field.customForm ? JSON.parse(field.customForm).step : undefined;
226
- return {
227
- type: 'FormKit',
228
- props: {
229
- type: 'number',
230
- id: field.id,
231
- name: name,
232
- label: field.label,
233
- required: field.required,
234
- value: field.defaultValue,
235
- step: step,
236
- help: hint,
237
- wrapperClass: '$remove:formkit-wrapper',
238
- inputClass: `input-${this.theme}`,
239
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
240
- validation: validation,
241
- validationVisibility: 'live',
242
- },
243
- };
244
- case 'date':
245
- return {
246
- type: 'FormKit',
247
- props: {
248
- type: 'date',
249
- id: field.id,
250
- name: name,
251
- label: field.label,
252
- required: field.required,
253
- value: field.defaultValue,
254
- help: hint,
255
- wrapperClass: '$remove:formkit-wrapper',
256
- inputClass: `input-${this.theme}`,
257
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
258
- validation: validation,
259
- validationVisibility: 'live',
260
- },
261
- };
262
- case 'enum':
263
- const enums = field.enumValues.map((obj) => {
264
- return { value: obj.id, label: obj.name };
265
- });
266
- return {
267
- type: 'FormKit',
268
- props: {
269
- type: 'select', // JSON.parse(field.customForm).displayAs
270
- id: field.id,
271
- name: name,
272
- label: field.label,
273
- required: field.required,
274
- value: field.defaultValue,
275
- options: enums,
276
- help: hint,
277
- wrapperClass: '$remove:formkit-wrapper',
278
- inputClass: `input-${this.theme}`,
279
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
280
- validation: validation,
281
- validationVisibility: 'live',
282
- },
283
- };
284
- case 'select':
285
- const selections = JSON.parse(field.customForm).entries.map((obj) => {
286
- return { value: obj.key, label: obj.value };
287
- });
288
- return {
289
- type: 'FormKit',
290
- props: {
291
- type: 'select', // JSON.parse(field.customForm).displayAs
292
- id: field.id,
293
- name: name,
294
- label: field.label,
295
- required: field.required,
296
- value: field.defaultValue,
297
- options: selections,
298
- placeholder: placeholder,
299
- help: hint,
300
- wrapperClass: '$remove:formkit-wrapper',
301
- inputClass: `input-${this.theme}`,
302
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
303
- validation: validation,
304
- validationVisibility: 'live',
305
- },
306
- };
307
- case 'string':
308
- return {
309
- type: 'FormKit',
310
- props: {
311
- type: 'text',
312
- id: field.id,
313
- name: name,
314
- label: field.label,
315
- required: field.required,
316
- value: field.defaultValue,
317
- help: hint,
318
- placeholder: placeholder,
319
- wrapperClass: '$remove:formkit-wrapper',
320
- inputClass: `input-${this.theme}`,
321
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
322
- validation: validation,
323
- validationVisibility: 'live',
324
- },
325
- };
326
- case 'boolean':
327
- return {
328
- type: 'FormKit',
329
- props: {
330
- type: 'checkbox',
331
- id: field.id,
332
- name: name,
333
- label: field.label,
334
- required: field.required,
335
- value: field.defaultValue,
336
- help: hint,
337
- inputClass: `input-${this.theme}`,
338
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
339
- validation: validation,
340
- validationVisibility: 'live',
341
- },
342
- };
343
- case 'file':
344
- return {
345
- type: 'FormKit',
346
- props: {
347
- type: 'file',
348
- id: field.id,
349
- name: name,
350
- label: field.label,
351
- required: field.required,
352
- value: field.defaultValue,
353
- help: hint,
354
- innerClass: 'reset-background',
355
- wrapperClass: '$remove:formkit-wrapper',
356
- inputClass: `input-${this.theme}`,
357
- // innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
358
- validation: validation,
359
- validationVisibility: 'live',
360
- },
361
- };
362
- case 'checkbox':
363
- const options = JSON.parse(field.customForm).entries.map((obj) => {
364
- return { value: obj.key, label: obj.value };
365
- });
366
- return {
367
- type: 'FormKit',
368
- props: {
369
- type: 'checkbox',
370
- id: field.id,
371
- name: name,
372
- label: field.label,
373
- required: field.required,
374
- value: field.defaultValue,
375
- options: options,
376
- help: hint,
377
- fieldsetClass: 'custom-fieldset',
378
- inputClass: `input-${this.theme}`,
379
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
380
- validation: validation,
381
- validationVisibility: 'live',
382
- },
383
- };
384
- case 'color':
385
- return {
386
- type: 'FormKit',
387
- props: {
388
- type: 'color',
389
- id: field.id,
390
- name: name,
391
- label: field.label,
392
- required: field.required,
393
- value: field.defaultValue,
394
- help: hint,
395
- validation: validation,
396
- validationVisibility: 'live',
397
- },
398
- };
399
- case 'datetime-local':
400
- return {
401
- type: 'FormKit',
402
- props: {
403
- type: 'datetime-local',
404
- id: field.id,
405
- name: name,
406
- label: field.label,
407
- required: field.required,
408
- value: field.defaultValue,
409
- help: hint,
410
- wrapperClass: '$remove:formkit-wrapper',
411
- inputClass: `input-${this.theme}`,
412
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
413
- validation: validation,
414
- validationVisibility: 'live',
415
- },
416
- };
417
- case 'email':
418
- return {
419
- type: 'FormKit',
420
- props: {
421
- type: 'email',
422
- id: field.id,
423
- name: name,
424
- label: field.label,
425
- required: field.required,
426
- value: field.defaultValue,
427
- help: hint,
428
- validation: 'email',
429
- validationVisibility: 'live',
430
- placeholder: placeholder,
431
- wrapperClass: '$remove:formkit-wrapper',
432
- inputClass: `input-${this.theme}`,
433
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
434
- validation: validation,
435
- validationVisibility: 'live',
436
- },
437
- };
438
- case 'header':
439
- let typeToUse = 'h1';
440
- if (field.customForm && JSON.parse(field.customForm).style == 'heading_2') {
441
- typeToUse = 'h2';
442
- }
443
- if (field.customForm && JSON.parse(field.customForm).style == 'heading_3') {
444
- typeToUse = 'h3';
445
- }
446
- return {
447
- type: typeToUse,
448
- innerText: field.defaultValue,
449
- };
450
- case 'hidden':
451
- return {
452
- type: 'input',
453
- props: {
454
- type: 'hidden',
455
- value: field.defaultValue,
456
- },
457
- };
458
- case 'month':
459
- return {
460
- type: 'FormKit',
461
- props: {
462
- type: 'month',
463
- id: field.id,
464
- name: name,
465
- label: field.label,
466
- required: field.required,
467
- value: field.defaultValue,
468
- help: hint,
469
- wrapperClass: '$remove:formkit-wrapper',
470
- inputClass: `input-${this.theme}`,
471
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
472
- validation: validation,
473
- validationVisibility: 'live',
474
- },
475
- };
476
- case 'paragraph':
477
- return {
478
- type: 'p',
479
- innerText: field.defaultValue,
480
- };
481
- case 'password':
482
- return {
483
- type: 'FormKit',
484
- props: {
485
- type: 'password',
486
- id: field.id,
487
- name: name,
488
- label: field.label,
489
- required: field.required,
490
- value: field.defaultValue,
491
- help: hint,
492
- placeholder: placeholder,
493
- wrapperClass: '$remove:formkit-wrapper',
494
- inputClass: `input-${this.theme}`,
495
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
496
- validation: validation,
497
- validationVisibility: 'live',
498
- },
499
- };
500
- case 'radio':
501
- const radioOptions = JSON.parse(field.customForm).entries.map((obj) => {
502
- return { value: obj.key, label: obj.value };
503
- });
504
- return {
505
- type: 'FormKit',
506
- props: {
507
- type: 'radio',
508
- id: field.id,
509
- name: name,
510
- label: field.label,
511
- required: field.required,
512
- value: field.defaultValue,
513
- options: radioOptions,
514
- help: hint,
515
- fieldsetClass: 'custom-fieldset',
516
- inputClass: `input-${this.theme}`,
517
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
518
- validation: validation,
519
- validationVisibility: 'live',
520
- },
521
- };
522
- case 'range':
523
- const customForm = JSON.parse(field.customForm);
524
- return {
525
- type: 'v-slider',
526
- props: {
527
- id: field.id,
528
- name: name,
529
- // label: field.label,
530
- required: field.required,
531
- // value: field.defaultValue,
532
- // help: hint,
533
- min: customForm.min,
534
- max: customForm.max,
535
- step: customForm.step,
536
- thumbLabel: true,
537
- // wrapperClass: '$remove:formkit-wrapper',
538
- // inputClass: `input-${this.theme}`,
539
- // innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
540
- validation: validation,
541
- validationVisibility: 'live',
542
- },
543
- };
544
- case 'tel':
545
- return {
546
- type: 'FormKit',
547
- props: {
548
- type: 'tel' /* with pro component mask more good */,
549
- id: field.id,
550
- name: name,
551
- label: field.label,
552
- required: field.required,
553
- value: field.defaultValue,
554
- help: hint,
555
- placeholder: placeholder,
556
- wrapperClass: '$remove:formkit-wrapper',
557
- inputClass: `input-${this.theme}`,
558
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
559
- validation: validation,
560
- validationVisibility: 'live',
561
- },
562
- };
563
- case 'textarea':
564
- const rows = field.customForm ? JSON.parse(field.customForm).rows : undefined;
565
- return {
566
- type: 'FormKit',
567
- props: {
568
- type: 'textarea' /* with pro component mask more good */,
569
- id: field.id,
570
- name: name,
571
- label: field.label,
572
- required: field.required,
573
- value: field.defaultValue,
574
- rows: rows,
575
- help: hint,
576
- placeholder: placeholder,
577
- wrapperClass: '$remove:formkit-wrapper',
578
- inputClass: `input-${this.theme}`,
579
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
580
- validation: validation,
581
- validationVisibility: 'live',
582
- },
583
- };
584
- case 'time':
585
- return {
586
- type: 'FormKit',
587
- props: {
588
- type: 'time' /* with pro component mask more good */,
589
- id: field.id,
590
- name: name,
591
- label: field.label,
592
- required: field.required,
593
- value: field.defaultValue,
594
- help: hint,
595
- placeholder: placeholder,
596
- wrapperClass: '$remove:formkit-wrapper',
597
- inputClass: `input-${this.theme}`,
598
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
599
- validation: validation,
600
- validationVisibility: 'live',
601
- },
602
- };
603
- case 'url':
604
- return {
605
- type: 'FormKit',
606
- props: {
607
- type: 'url',
608
- id: field.id,
609
- name: name,
610
- label: field.label,
611
- required: field.required,
612
- value: field.defaultValue,
613
- help: hint,
614
- placeholder: placeholder,
615
- validation: 'url',
616
- validationVisibility: 'live',
617
- wrapperClass: '$remove:formkit-wrapper',
618
- inputClass: `input-${this.theme}`,
619
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
620
- validation: validation,
621
- validationVisibility: 'live',
622
- },
623
- };
624
- case 'week':
625
- return {
626
- type: 'FormKit',
627
- props: {
628
- type: 'week',
629
- id: field.id,
630
- name: name,
631
- label: field.label,
632
- required: field.required,
633
- value: field.defaultValue,
634
- help: hint,
635
- placeholder: placeholder,
636
- wrapperClass: '$remove:formkit-wrapper',
637
- inputClass: `input-${this.theme}`,
638
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
639
- validation: validation,
640
- validationVisibility: 'live',
641
- },
642
- };
643
- default:
644
- return {
645
- type: 'FormKit',
646
- props: {
647
- type: field.type,
648
- id: field.id,
649
- name: name,
650
- label: field.label,
651
- required: field.required,
652
- value: field.defaultValue,
653
- help: hint,
654
- inputClass: `input-${this.theme}`,
655
- innerClass: `${this.theme == 'dark' ? '$remove:formkit-inner' : ''}`,
656
- validation: validation,
657
- validationVisibility: 'live',
658
- },
659
- };
660
- }
661
- },
662
- checkFormState(state) {
663
- // const field = this.$formkit.get('field_01');
664
- // console.info(field.context.state.valid);
770
+ if (formFields) {
771
+ formFields.forEach((field) => {
772
+ this.formData[field.id] = field.defaultValue
773
+ })
774
+ }
665
775
 
666
- return true;
776
+ if (initialValues) {
777
+ Object.keys(initialValues).filter(key => formFieldIds.includes(key)).forEach((key) => {
778
+ this.formData[key] = initialValues[key]
779
+ })
780
+ }
667
781
 
668
- // loop over fields then this.$formkit.get(this.id) -> check error state if all ok return true else return false
669
- // ?? wie unterscheiden wir welche actions dieser validierungsfehler betrifft ??
670
- // ?? wie machen wir formkit validierung auch im Studio available ??
671
- // \_ vllt macht es sinn das schema von formkit zu übernehmen oder alternativ nur unsere validierung zu nutzen.
672
- },
673
- hasUserTask() {
674
- return this.messages && this.messages[this.id] && this.messages[this.id].payload.userTask;
675
- },
676
- userTask() {
677
- return this.hasUserTask() ? this.messages[this.id].payload.userTask : {};
678
- },
679
- fields() {
680
- const aFields = this.hasUserTask() ? this.userTask().userTaskConfig.formFields : [];
681
- const fieldMap = aFields.map((field) => ({
682
- ...field,
683
- items: mapItems(field.type, field),
684
- }));
782
+ if (this.formIsFinished) {
783
+ Object.keys(finishedFormData).filter(key => formFieldIds.includes(key)).forEach(key => {
784
+ this.formData[key] = finishedFormData[key]
785
+ })
786
+ }
787
+ },
788
+ actionFn (action) {
789
+ if (action.label === 'Speichern' || action.label === 'Speichern und nächster') {
790
+ const formkitInputs = this.$refs.form.$el.querySelectorAll('.formkit-outer')
791
+ let allComplete = true
685
792
 
686
- return fieldMap;
687
- },
688
- hasFields() {
689
- return this.messages && this.messages[this.id] && this.messages[this.id].payload.userTask !== undefined;
690
- },
691
- /*
692
- widget-action just sends a msg to Node-RED, it does not store the msg state server-side
693
- alternatively, you can use widget-change, which will also store the msg in the Node's datastore
694
- */
695
- send(msg, index) {
696
- const msgArr = [];
697
- msgArr[index] = msg;
698
- this.$socket.emit('widget-action', this.id, msgArr);
699
- },
700
- init() {
701
- this.actions = this.props.options;
702
- },
703
- actionFn(action) {
704
- // this.checkFormState();
793
+ formkitInputs.forEach((input) => {
794
+ const dataComplete = input.getAttribute('data-complete')
795
+ const dataInvalid = input.getAttribute('data-invalid')
705
796
 
706
- if (action.label === 'Speichern' || action.label === 'Speichern und nächster') {
707
- const formkitInputs = this.$refs.form.$el.querySelectorAll('.formkit-outer');
708
- let allComplete = true;
797
+ if (dataComplete == null && dataInvalid === 'true') {
798
+ allComplete = false
799
+ }
800
+ })
709
801
 
710
- formkitInputs.forEach((input) => {
711
- const dataComplete = input.getAttribute('data-complete');
712
- const dataInvalid = input.getAttribute('data-invalid')
713
-
714
- if (dataComplete == null && dataInvalid === "true") {
715
- allComplete = false;
802
+ if (!allComplete) return
716
803
  }
717
- });
718
-
719
- if (!allComplete) return;
720
- }
721
804
 
722
- if (this.checkCondition(action.condition)) {
723
- this.showError(false, '');
724
- // TODO: MM - begin
725
- // this.send(
726
- // { payload: { formData: this.formData, userTask: this.userTask() } },
727
- // this.actions.findIndex((element) => element.label === action.label)
728
- // );
729
- const msg = this.messages[this.id] || {};
730
- msg.payload = { formData: this.formData, userTask: this.userTask() };
731
- this.send(
732
- msg,
733
- this.actions.findIndex((element) => element.label === action.label)
734
- );
735
- // TODO: mm - end
736
- } else {
737
- this.showError(true, action.errorMessage);
738
- }
739
- },
740
- checkCondition(condition) {
741
- if (condition == '') return true;
742
- try {
743
- const func = Function('fields', 'userTask', 'msg', '"use strict"; return (' + condition + ')');
744
- const result = func(this.formData, this.taskInput, this.messages[this.id]);
745
- console.log(this.formData, result);
746
- return Boolean(result);
747
- } catch (err) {
748
- console.error('Error while evaluating condition: ' + err);
749
- return false;
750
- }
751
- },
752
- showError(bool, errMsg) {
753
- this.error = bool;
754
- this.errorMsg = errMsg;
755
- },
756
- },
757
- };
805
+ if (this.checkCondition(action.condition)) {
806
+ this.showError('')
807
+ // TODO: MM - begin
808
+ // this.send(
809
+ // { payload: { formData: this.formData, userTask: this.userTask } },
810
+ // this.actions.findIndex((element) => element.label === action.label)
811
+ // );
812
+ const msg = this.msg ?? {}
813
+ msg.payload = { formData: this.formData, userTask: this.userTask }
814
+ this.send(
815
+ msg,
816
+ this.actions.findIndex((element) => element.label === action.label)
817
+ )
818
+ // TODO: mm - end
819
+ } else {
820
+ this.showError(action.errorMessage)
821
+ }
822
+ },
823
+ checkCondition (condition) {
824
+ if (condition === '') return true
825
+ try {
826
+ // eslint-disable-next-line no-new-func
827
+ const func = Function('fields', 'userTask', 'msg', '"use strict"; return (' + condition + ')')
828
+ const result = func(this.formData, this.userTask, this.msg)
829
+ return Boolean(result)
830
+ } catch (err) {
831
+ console.error('Error while evaluating condition: ' + err)
832
+ return false
833
+ }
834
+ },
835
+ showError (errMsg) {
836
+ this.errorMsg = errMsg
837
+ }
838
+ }
839
+ }
758
840
 
759
- function mapItems(type, field) {
760
- if (type === 'enum') {
761
- return field.enumValues.map((enumValue) => ({
762
- title: enumValue.name,
763
- value: enumValue.id,
764
- }));
765
- } else {
766
- return null;
767
- }
841
+ function mapItems (type, field) {
842
+ if (type === 'enum') {
843
+ return field.enumValues.map((enumValue) => ({
844
+ title: enumValue.name,
845
+ value: enumValue.id
846
+ }))
847
+ } else {
848
+ return null
849
+ }
768
850
  }
769
851
  </script>
770
852