@5minds/node-red-dashboard-2-processcube-dynamic-form 1.1.1 → 1.1.2-develop-3b99b7-m7bxlaek

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