@5minds/node-red-dashboard-2-processcube-dynamic-form 2.0.8-file-preview-3eb8ad-mdijpkne → 2.1.0-develop-7297c2-mdiwcn5m

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,86 +1,52 @@
1
1
  <template>
2
2
  <div className="ui-dynamic-form-external-sizing-wrapper" :style="props.card_size_styling">
3
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="effectiveTitle"
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
- />
4
+ <UIDynamicFormTitleText v-if="props.title_style === 'outside' && hasUserTask" :style="props.title_style"
5
+ :title="effectiveTitle" :customStyles="props.title_custom_text_styling" :titleIcon="props.title_icon"
6
+ :collapsible="props.collapsible || (props.collapse_when_finished && formIsFinished)" :collapsed="collapsed"
7
+ :toggleCollapse="toggleCollapse" />
14
8
  <div className="ui-dynamic-form-wrapper">
15
9
  <p v-if="hasUserTask" style="margin-bottom: 0px">
16
10
  <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="effectiveTitle"
21
- :customStyles="props.title_custom_text_styling"
11
+ <UIDynamicFormTitleText v-if="props.title_style != 'outside'" :style="props.title_style"
12
+ :title="effectiveTitle" :customStyles="props.title_custom_text_styling"
22
13
  :titleIcon="props.title_icon"
23
14
  :collapsible="props.collapsible || (props.collapse_when_finished && formIsFinished)"
24
- :collapsed="collapsed"
25
- :toggleCollapse="toggleCollapse"
26
- />
15
+ :collapsed="collapsed" :toggleCollapse="toggleCollapse" />
27
16
  <Transition name="cardCollapse">
28
17
  <div v-if="!collapsed">
29
- <div
30
- className="ui-dynamic-form-formfield-positioner"
31
- :style="props.inner_card_styling"
32
- :data-columns="props.form_columns || 1"
33
- >
18
+ <div className="ui-dynamic-form-formfield-positioner" :style="props.inner_card_styling"
19
+ :data-columns="props.form_columns || 1">
34
20
  <FormKit id="form" type="group">
35
- <v-row
36
- v-for="(field, index) in fields()"
37
- :key="field"
21
+ <v-row v-for="(field, index) in fields()" :key="field"
38
22
  :class="field.type === 'header' ? 'ui-dynamic-form-header-row' : ''"
39
- :style="getRowWidthStyling(field, index)"
40
- >
23
+ :style="getRowWidthStyling(field, index)">
41
24
  <v-col cols="12">
42
- <component
43
- :is="getFieldComponent(field).type"
44
- v-if="getFieldComponent(field).innerText"
45
- v-bind="getFieldComponent(field).props"
46
- :ref="
47
- (el) => {
48
- if (index === 0) firstFormFieldRef = el;
49
- }
50
- "
51
- v-model="formData[field.id]"
52
- >
53
- {{ getFieldComponent(field).innerText }}
25
+ <component :is="createComponent(field).type"
26
+ v-if="createComponent(field).innerText"
27
+ v-bind="createComponent(field).props" :ref="(el) => {
28
+ if (index === 0) firstFormFieldRef = el;
29
+ }
30
+ " v-model="formData[field.id]">
31
+ {{ createComponent(field).innerText }}
54
32
  </component>
55
- <div v-else-if="getFieldComponent(field).type == 'v-slider'">
33
+ <div v-else-if="createComponent(field).type == 'v-slider'">
56
34
  <p class="formkit-label">{{ field.label }}</p>
57
- <component
58
- :is="getFieldComponent(field).type"
59
- v-bind="getFieldComponent(field).props"
60
- :ref="
61
- (el) => {
62
- if (index === 0) firstFormFieldRef = el;
63
- }
64
- "
65
- v-model="field.defaultValue"
66
- />
35
+ <component :is="createComponent(field).type"
36
+ v-bind="createComponent(field).props" :ref="(el) => {
37
+ if (index === 0) firstFormFieldRef = el;
38
+ }
39
+ " v-model="field.defaultValue" />
67
40
  <p class="formkit-help">
68
- {{
69
- field.customForm ? JSON.parse(field.customForm).hint : undefined
41
+ {{ field.customForm ? JSON.parse(field.customForm).hint : undefined
70
42
  }}
71
43
  </p>
72
44
  </div>
73
- <component
74
- :is="getFieldComponent(field).type"
75
- v-else
76
- v-bind="getFieldComponent(field).props"
77
- :ref="
78
- (el) => {
79
- if (index === 0) firstFormFieldRef = el;
80
- }
81
- "
82
- v-model="formData[field.id]"
83
- />
45
+ <component :is="createComponent(field).type" v-else
46
+ v-bind="createComponent(field).props" :ref="(el) => {
47
+ if (index === 0) firstFormFieldRef = el;
48
+ }
49
+ " v-model="formData[field.id]" />
84
50
  </v-col>
85
51
  </v-row>
86
52
  </FormKit>
@@ -89,24 +55,17 @@
89
55
  <v-row v-if="errorMsg.length > 0" style="padding: 12px">
90
56
  <v-alert type="error">Error: {{ errorMsg }}</v-alert>
91
57
  </v-row>
92
- <UIDynamicFormFooterAction
93
- v-if="props.actions_inside_card && actions.length > 0"
94
- :actions="actions"
95
- :actionCallback="actionFn"
96
- :formIsFinished="formIsFinished"
97
- style="padding: 16px; padding-top: 0px"
98
- />
58
+ <UIDynamicFormFooterAction v-if="props.actions_inside_card && actions.length > 0"
59
+ :actions="actions" :actionCallback="actionFn" :formIsFinished="formIsFinished"
60
+ style="padding: 16px; padding-top: 0px" />
99
61
  </v-row>
100
62
  </div>
101
63
  </Transition>
102
64
  </v-form>
103
65
  </p>
104
66
  <p v-else>
105
- <v-alert
106
- v-if="props.waiting_info.length > 0 || props.waiting_title.length > 0"
107
- :text="props.waiting_info"
108
- :title="props.waiting_title"
109
- />
67
+ <v-alert v-if="props.waiting_info.length > 0 || props.waiting_title.length > 0"
68
+ :text="props.waiting_info" :title="props.waiting_title" />
110
69
  </p>
111
70
  </div>
112
71
  <div v-if="!props.actions_inside_card && actions.length > 0 && hasUserTask" style="padding-top: 32px">
@@ -117,27 +76,27 @@
117
76
 
118
77
  <!-- eslint-disable no-case-declarations -->
119
78
  <script>
120
- import { de } from '@formkit/i18n';
121
- import { FormKit, defaultConfig, plugin } from '@formkit/vue';
122
- import { getCurrentInstance, markRaw, nextTick } from 'vue';
79
+ import { de } from '@formkit/i18n'
80
+ import { FormKit, defaultConfig, plugin } from '@formkit/vue'
81
+ import { getCurrentInstance, markRaw, nextTick } from 'vue'
123
82
 
124
83
  // eslint-disable-next-line import/no-unresolved
125
- import '@formkit/themes/genesis';
126
- import UIDynamicFormFooterAction from './FooterActions.vue';
127
- import UIDynamicFormTitleText from './TitleText.vue';
84
+ import '@formkit/themes/genesis'
85
+ import UIDynamicFormFooterAction from './FooterActions.vue'
86
+ import UIDynamicFormTitleText from './TitleText.vue'
128
87
 
129
88
  // eslint-disable-next-line no-unused-vars
130
89
  function requiredIf({ value }, [targetField, expectedValue], node) {
131
- console.debug(arguments);
90
+ console.debug(arguments)
132
91
 
133
- const actual = node?.root?.value?.[targetField];
134
- const isEmpty = value === '' || value === null || value === undefined;
92
+ const actual = node?.root?.value?.[targetField]
93
+ const isEmpty = value === '' || value === null || value === undefined
135
94
 
136
95
  if (actual === expectedValue && isEmpty) {
137
- return false; // oder: `return "Dieses Feld ist erforderlich."`
96
+ return false // oder: `return "Dieses Feld ist erforderlich."`
138
97
  }
139
98
 
140
- return true;
99
+ return true
141
100
  }
142
101
 
143
102
  export default {
@@ -145,7 +104,7 @@ export default {
145
104
  components: {
146
105
  FormKit,
147
106
  UIDynamicFormFooterAction,
148
- UIDynamicFormTitleText,
107
+ UIDynamicFormTitleText
149
108
  },
150
109
  inject: ['$socket'],
151
110
  props: {
@@ -154,24 +113,24 @@ export default {
154
113
  props: { type: Object, default: () => ({}) },
155
114
  state: {
156
115
  type: Object,
157
- default: () => ({ enabled: false, visible: false }),
158
- },
116
+ default: () => ({ enabled: false, visible: false })
117
+ }
159
118
  },
160
119
  setup(props) {
161
- console.info('UIDynamicForm setup with:', props);
162
- console.debug('Vue function loaded correctly', markRaw);
120
+ console.info('UIDynamicForm setup with:', props)
121
+ console.debug('Vue function loaded correctly', markRaw)
163
122
 
164
- const instance = getCurrentInstance();
165
- const app = instance.appContext.app;
123
+ const instance = getCurrentInstance()
124
+ const app = instance.appContext.app
166
125
 
167
126
  const formkitConfig = defaultConfig({
168
127
  theme: 'genesis',
169
128
  locales: { de },
170
129
  locale: 'de',
171
130
  // eslint-disable-next-line object-shorthand
172
- rules: { requiredIf: requiredIf },
173
- });
174
- app.use(plugin, formkitConfig);
131
+ rules: { requiredIf: requiredIf }
132
+ })
133
+ app.use(plugin, formkitConfig)
175
134
  },
176
135
  data() {
177
136
  return {
@@ -183,143 +142,120 @@ export default {
183
142
  formIsFinished: false,
184
143
  msg: null,
185
144
  collapsed: false,
186
- firstFormFieldRef: null,
187
- componentCache: new Map(), // Add caching for components
188
- };
145
+ firstFormFieldRef: null
146
+ }
189
147
  },
190
148
  computed: {
191
149
  dynamicClass() {
192
- return `ui-dynamic-form-${this.theme} ui-dynamic-form-common`;
150
+ return `ui-dynamic-form-${this.theme} ui-dynamic-form-common`
193
151
  },
194
152
  dynamicFooterClass() {
195
- return `ui-dynamic-form-footer-${this.theme} ui-dynamic-form-footer-common`;
153
+ return `ui-dynamic-form-footer-${this.theme} ui-dynamic-form-footer-common`
196
154
  },
197
155
  hasUserTask() {
198
- return !!this.userTask;
156
+ return !!this.userTask
199
157
  },
200
158
  totalOutputs() {
201
159
  return (
202
160
  this.props.options.length +
203
161
  (this.props.handle_confirmation_dialogs ? 2 : 0) +
204
162
  (this.props.trigger_on_change ? 1 : 0)
205
- );
163
+ )
206
164
  },
207
165
  isConfirmDialog() {
208
- return this.userTask.userTaskConfig.formFields.some((field) => field.type === 'confirm');
166
+ return this.userTask.userTaskConfig.formFields.some((field) => field.type === 'confirm')
209
167
  },
210
168
  effectiveTitle() {
211
169
  if (this.props.title_text_type === 'str') {
212
- return this.props.title_text;
170
+ return this.props.title_text
213
171
  } else if (this.props.title_text_type === 'msg') {
214
- return this.msg.dynamicTitle;
172
+ return this.msg.dynamicTitle
215
173
  } else {
216
- return '';
174
+ return ''
217
175
  }
218
- },
176
+ }
219
177
  },
220
178
  watch: {
221
179
  formData: {
222
180
  handler(newData, oldData) {
223
181
  if (this.props.trigger_on_change) {
224
- const res = { payload: { formData: newData, userTask: this.userTask } };
225
- this.send(res, this.totalOutputs - 1);
182
+ const res = { payload: { formData: newData, userTask: this.userTask } }
183
+ this.send(res, this.totalOutputs - 1)
226
184
  }
227
185
  },
228
186
  collapsed(newVal) {
229
187
  if (!newVal && this.hasUserTask) {
230
188
  nextTick(() => {
231
- this.focusFirstFormField();
232
- });
189
+ this.focusFirstFormField()
190
+ })
233
191
  }
234
192
  },
235
193
  userTask(newVal) {
236
194
  if (newVal && !this.collapsed) {
237
195
  nextTick(() => {
238
- this.focusFirstFormField();
239
- });
196
+ this.focusFirstFormField()
197
+ })
240
198
  }
241
199
  },
242
- deep: true,
243
- },
200
+ deep: true
201
+ }
244
202
  },
245
203
  created() {
246
- const currentPath = window.location.pathname;
247
- const lastPart = currentPath.substring(currentPath.lastIndexOf('/'));
204
+ const currentPath = window.location.pathname
205
+ const lastPart = currentPath.substring(currentPath.lastIndexOf('/'))
248
206
 
249
- const store = this.$store.state;
207
+ const store = this.$store.state
250
208
 
251
209
  for (const key in store.ui.pages) {
252
210
  if (store.ui.pages[key].path === lastPart) {
253
- const theme = store.ui.pages[key].theme;
211
+ const theme = store.ui.pages[key].theme
254
212
  if (store.ui.themes[theme].name === 'ProcessCube Lightmode') {
255
- this.theme = 'light';
213
+ this.theme = 'light'
256
214
  } else if (store.ui.themes[theme].name === 'ProcessCube Darkmode') {
257
- this.theme = 'dark';
215
+ this.theme = 'dark'
258
216
  } else {
259
- this.theme = 'default';
217
+ this.theme = 'default'
260
218
  }
261
- break;
219
+ break
262
220
  }
263
221
  }
264
222
  },
265
223
  mounted() {
266
- const elements = document.querySelectorAll('.formkit-input');
224
+ const elements = document.querySelectorAll('.formkit-input')
267
225
 
268
226
  elements.forEach((element) => {
269
- element.classList.add('test');
270
- });
227
+ element.classList.add('test')
228
+ })
271
229
 
272
230
  this.$socket.on('widget-load:' + this.id, (msg) => {
273
- this.init(msg);
274
- });
231
+ this.init(msg)
232
+ })
275
233
  this.$socket.on('msg-input:' + this.id, (msg) => {
276
234
  // store the latest message in our client-side vuex store when we receive a new message
277
- this.init(msg);
278
- });
235
+ this.init(msg)
236
+ })
279
237
  // tell Node-RED that we're loading a new instance of this widget
280
- this.$socket.emit('widget-load', this.id);
238
+ this.$socket.emit('widget-load', this.id)
281
239
  },
282
240
  unmounted() {
283
241
  /* Make sure, any events you subscribe to on SocketIO are unsubscribed to here */
284
- this.$socket?.off('widget-load' + this.id);
285
- this.$socket?.off('msg-input:' + this.id);
242
+ this.$socket?.off('widget-load' + this.id)
243
+ this.$socket?.off('msg-input:' + this.id)
286
244
  },
287
245
  methods: {
288
- // Performance optimized component caching
289
- getFieldComponent(field) {
290
- const cacheKey = `${field.id}_${JSON.stringify(this.formData[field.id])}_${this.formIsFinished}_${
291
- this.theme
292
- }`;
293
-
294
- if (this.componentCache.has(cacheKey)) {
295
- return this.componentCache.get(cacheKey);
296
- }
297
-
298
- const component = this.createComponent(field);
299
- this.componentCache.set(cacheKey, component);
300
- return component;
301
- },
302
-
303
- // Clear cache when form data changes
304
- clearComponentCache() {
305
- this.componentCache.clear();
306
- },
307
-
308
246
  createComponent(field) {
309
- const customForm = field.customForm ? JSON.parse(field.customForm) : {};
310
- const hint = customForm.hint;
311
- const placeholder = customForm.placeholder;
312
- const validation = customForm.validation;
313
- const name = field.id;
314
- const customProperties = customForm.customProperties ?? [];
247
+ const customForm = field.customForm ? JSON.parse(field.customForm) : {}
248
+ const hint = customForm.hint
249
+ const placeholder = customForm.placeholder
250
+ const validation = customForm.validation
251
+ const name = field.id
252
+ const customProperties = customForm.customProperties ?? []
315
253
  const isReadOnly =
316
254
  this.props.readonly ||
317
- this.formIsFinished ||
318
- customProperties.find(
319
- (entry) => ['readOnly', 'readonly'].includes(entry.name) && entry.value === 'true'
320
- )
255
+ this.formIsFinished ||
256
+ customProperties.find((entry) => ['readOnly', 'readonly'].includes(entry.name) && entry.value === 'true')
321
257
  ? 'true'
322
- : undefined;
258
+ : undefined
323
259
  switch (field.type) {
324
260
  case 'long':
325
261
  return {
@@ -338,15 +274,13 @@ export default {
338
274
  wrapperClass: '$remove:formkit-wrapper',
339
275
  labelClass: 'ui-dynamic-form-input-label',
340
276
  inputClass: `input-${this.theme}`,
341
- innerClass: `ui-dynamic-form-input-outlines ${
342
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
343
- }`,
277
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
344
278
  readonly: isReadOnly,
345
- validationVisibility: 'live',
346
- },
347
- };
279
+ validationVisibility: 'live'
280
+ }
281
+ }
348
282
  case 'number':
349
- const step = field.customForm ? JSON.parse(field.customForm).step : undefined;
283
+ const step = field.customForm ? JSON.parse(field.customForm).step : undefined
350
284
  return {
351
285
  type: 'FormKit',
352
286
  props: {
@@ -363,13 +297,11 @@ export default {
363
297
  wrapperClass: '$remove:formkit-wrapper',
364
298
  labelClass: 'ui-dynamic-form-input-label',
365
299
  inputClass: `input-${this.theme}`,
366
- innerClass: `ui-dynamic-form-input-outlines ${
367
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
368
- }`,
300
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
369
301
  readonly: isReadOnly,
370
- validationVisibility: 'live',
371
- },
372
- };
302
+ validationVisibility: 'live'
303
+ }
304
+ }
373
305
  case 'date':
374
306
  return {
375
307
  type: 'FormKit',
@@ -384,18 +316,16 @@ export default {
384
316
  wrapperClass: '$remove:formkit-wrapper',
385
317
  labelClass: 'ui-dynamic-form-input-label',
386
318
  inputClass: `input-${this.theme}`,
387
- innerClass: `ui-dynamic-form-input-outlines ${
388
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
389
- }`,
319
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
390
320
  readonly: isReadOnly,
391
321
  validation,
392
- validationVisibility: 'live',
393
- },
394
- };
322
+ validationVisibility: 'live'
323
+ }
324
+ }
395
325
  case 'enum':
396
326
  const enums = field.enumValues.map((obj) => {
397
- return { value: obj.id, label: obj.name };
398
- });
327
+ return { value: obj.id, label: obj.name }
328
+ })
399
329
  return {
400
330
  type: 'FormKit',
401
331
  props: {
@@ -410,19 +340,17 @@ export default {
410
340
  wrapperClass: '$remove:formkit-wrapper',
411
341
  labelClass: 'ui-dynamic-form-input-label',
412
342
  inputClass: `input-${this.theme}`,
413
- innerClass: `ui-dynamic-form-input-outlines ${
414
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
415
- }`,
343
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
416
344
  readonly: isReadOnly,
417
345
  disabled: isReadOnly,
418
346
  validation,
419
- validationVisibility: 'live',
420
- },
421
- };
347
+ validationVisibility: 'live'
348
+ }
349
+ }
422
350
  case 'select':
423
351
  const selections = JSON.parse(field.customForm).entries.map((obj) => {
424
- return { value: obj.key, label: obj.value };
425
- });
352
+ return { value: obj.key, label: obj.value }
353
+ })
426
354
  return {
427
355
  type: 'FormKit',
428
356
  props: {
@@ -438,15 +366,13 @@ export default {
438
366
  wrapperClass: '$remove:formkit-wrapper',
439
367
  labelClass: 'ui-dynamic-form-input-label',
440
368
  inputClass: `input-${this.theme}`,
441
- innerClass: `ui-dynamic-form-input-outlines ${
442
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
443
- }`,
369
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
444
370
  readonly: isReadOnly,
445
371
  disabled: isReadOnly,
446
372
  validation,
447
- validationVisibility: 'live',
448
- },
449
- };
373
+ validationVisibility: 'live'
374
+ }
375
+ }
450
376
  case 'string':
451
377
  return {
452
378
  type: 'FormKit',
@@ -462,19 +388,17 @@ export default {
462
388
  wrapperClass: '$remove:formkit-wrapper',
463
389
  labelClass: 'ui-dynamic-form-input-label',
464
390
  inputClass: `input-${this.theme}`,
465
- innerClass: `ui-dynamic-form-input-outlines ${
466
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
467
- }`,
391
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
468
392
  readonly: isReadOnly,
469
393
  validation,
470
- validationVisibility: 'live',
471
- },
472
- };
394
+ validationVisibility: 'live'
395
+ }
396
+ }
473
397
  case 'confirm':
474
398
  return {
475
399
  type: 'h3',
476
- innerText: field.label,
477
- };
400
+ innerText: field.label
401
+ }
478
402
  case 'boolean':
479
403
  return {
480
404
  type: 'FormKit',
@@ -488,133 +412,15 @@ export default {
488
412
  help: hint,
489
413
  labelClass: 'ui-dynamic-form-input-label',
490
414
  inputClass: `input-${this.theme}`,
491
- innerClass: `ui-dynamic-form-input-outlines ${
492
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
493
- }`,
415
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
494
416
  readonly: isReadOnly,
495
417
  disabled: isReadOnly,
496
418
  validation,
497
- validationVisibility: 'live',
498
- },
499
- };
500
- case 'file-preview':
501
- // Handle file preview display only (no upload functionality)
502
- const originalFieldId = field.id.replace('_preview', '');
503
- if (this.formData && this.formData[originalFieldId] && this.formData[originalFieldId].length != 0) {
504
- const fileDataArray = Array.isArray(this.formData[originalFieldId])
505
- ? this.formData[originalFieldId]
506
- : [this.formData[originalFieldId]];
507
-
508
- // Separate images from other files
509
- const images = [];
510
- const otherFiles = [];
511
-
512
- fileDataArray.forEach((fileData) => {
513
- const fileName = fileData.name || '';
514
- const isImage = fileName.toLowerCase().match(/\.(png|jpg|jpeg|gif|webp)$/);
515
-
516
- if (isImage && fileData.file && fileData.file.data) {
517
- // Convert buffer to base64 data URL for image display - safe for large files
518
- const uint8Array = new Uint8Array(fileData.file.data);
519
- let binaryString = '';
520
-
521
- // Process in chunks to avoid call stack overflow
522
- const chunkSize = 1024;
523
- for (let i = 0; i < uint8Array.length; i += chunkSize) {
524
- const chunk = uint8Array.slice(i, i + chunkSize);
525
- binaryString += String.fromCharCode.apply(null, chunk);
526
- }
527
-
528
- const base64String = btoa(binaryString);
529
- const mimeType = fileName.toLowerCase().endsWith('.png')
530
- ? 'image/png'
531
- : fileName.toLowerCase().endsWith('.gif')
532
- ? 'image/gif'
533
- : 'image/jpeg';
534
- const dataURL = `data:${mimeType};base64,${base64String}`;
535
-
536
- images.push({ fileName, dataURL, fileData });
537
- } else {
538
- otherFiles.push({ fileName, fileData });
539
- }
540
- });
541
-
542
- let content = `<label class="ui-dynamic-form-input-label">${field.label} (Vorschau)${
543
- field.required ? ' *' : ''
544
- }</label>`;
545
-
546
- // Display images
547
- if (images.length > 0) {
548
- content += '<div style="margin-top: 8px;">';
549
- content += '<div style="font-weight: bold; margin-bottom: 8px;">Bilder:</div>';
550
- images.forEach((img, index) => {
551
- const downloadId = `download-img-${field.id}-${index}`;
552
- content += `
553
- <div style="display: inline-block; margin: 8px; text-align: center; vertical-align: top;">
554
- <img src="${img.dataURL}" alt="${img.fileName}"
555
- style="max-width: 300px; max-height: 200px; border: 1px solid #ccc; display: block; cursor: pointer;"
556
- onclick="document.getElementById('${downloadId}').click();" />
557
- <div style="margin-top: 4px; font-size: 0.9em; color: #666; max-width: 300px; word-break: break-word;">
558
- ${img.fileName}
559
- </div>
560
- <a id="${downloadId}" href="${img.dataURL}" download="${img.fileName}" style="display: none;"></a>
561
- </div>
562
- `;
563
- });
564
- content += '</div>';
419
+ validationVisibility: 'live'
565
420
  }
566
-
567
- // Display other files as list
568
- if (otherFiles.length > 0) {
569
- content +=
570
- '<div style="margin-top: 12px; padding: 12px; border: 1px solid #ddd; border-radius: 4px; background: #f9f9f9;">';
571
- content += '<div style="font-weight: bold; margin-bottom: 8px;">Weitere Dateien:</div>';
572
- otherFiles.forEach((file, index) => {
573
- const downloadId = `download-file-${field.id}-${index}`;
574
- const uint8Array = new Uint8Array(file.fileData.file.data);
575
- let binaryString = '';
576
-
577
- // Process in chunks for download
578
- const chunkSize = 1024;
579
- for (let i = 0; i < uint8Array.length; i += chunkSize) {
580
- const chunk = uint8Array.slice(i, i + chunkSize);
581
- binaryString += String.fromCharCode.apply(null, chunk);
582
- }
583
-
584
- const base64String = btoa(binaryString);
585
- const dataURL = `data:application/octet-stream;base64,${base64String}`;
586
-
587
- content += `
588
- <div style="display: flex; align-items: center; gap: 8px; margin-bottom: 4px; padding: 4px; border-radius: 3px; cursor: pointer;"
589
- onclick="document.getElementById('${downloadId}').click();"
590
- onmouseover="this.style.backgroundColor='#e6e6e6';"
591
- onmouseout="this.style.backgroundColor='transparent';">
592
- <span style="font-size: 1.2em;">📎</span>
593
- <span style="flex: 1; word-break: break-word;">${file.fileName}</span>
594
- <span style="font-size: 0.8em; color: #007bff;">Download</span>
595
- <a id="${downloadId}" href="${dataURL}" download="${file.fileName}" style="display: none;"></a>
596
- </div>
597
- `;
598
- });
599
- content += '</div>';
600
- }
601
-
602
- return {
603
- type: 'div',
604
- props: {
605
- innerHTML: content,
606
- },
607
- };
608
421
  }
609
- // If no files to preview, return empty div
610
- return {
611
- type: 'div',
612
- props: {
613
- style: 'display: none;',
614
- },
615
- };
616
422
  case 'file':
617
- const multiple = field.customForm ? JSON.parse(field.customForm).multiple === 'true' : false;
423
+ const multiple = field.customForm ? JSON.parse(field.customForm).multiple === 'true' : false
618
424
  return {
619
425
  type: 'FormKit',
620
426
  props: {
@@ -623,22 +429,24 @@ export default {
623
429
  name,
624
430
  label: field.label,
625
431
  required: field.required,
432
+ value: this.formData[field.id],
626
433
  help: hint,
627
434
  innerClass: 'reset-background',
628
435
  wrapperClass: '$remove:formkit-wrapper',
629
436
  labelClass: 'ui-dynamic-form-input-label',
630
437
  inputClass: `input-${this.theme}`,
438
+ // innerClass: ui-dynamic-form-input-outlines `${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
631
439
  readonly: isReadOnly,
632
440
  disabled: isReadOnly,
633
441
  multiple,
634
442
  validation,
635
- validationVisibility: 'live',
636
- },
637
- };
443
+ validationVisibility: 'live'
444
+ }
445
+ }
638
446
  case 'checkbox':
639
447
  const options = JSON.parse(field.customForm).entries.map((obj) => {
640
- return { value: obj.key, label: obj.value };
641
- });
448
+ return { value: obj.key, label: obj.value }
449
+ })
642
450
  return {
643
451
  type: 'FormKit',
644
452
  props: {
@@ -653,15 +461,13 @@ export default {
653
461
  fieldsetClass: 'custom-fieldset',
654
462
  labelClass: 'ui-dynamic-form-input-label',
655
463
  inputClass: `input-${this.theme}`,
656
- innerClass: `ui-dynamic-form-input-outlines ${
657
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
658
- }`,
464
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
659
465
  readonly: isReadOnly,
660
466
  disabled: isReadOnly,
661
467
  validation,
662
- validationVisibility: 'live',
663
- },
664
- };
468
+ validationVisibility: 'live'
469
+ }
470
+ }
665
471
  case 'color':
666
472
  return {
667
473
  type: 'FormKit',
@@ -676,9 +482,9 @@ export default {
676
482
  readonly: isReadOnly,
677
483
  disabled: isReadOnly,
678
484
  validation,
679
- validationVisibility: 'live',
680
- },
681
- };
485
+ validationVisibility: 'live'
486
+ }
487
+ }
682
488
  case 'datetime-local':
683
489
  return {
684
490
  type: 'FormKit',
@@ -693,14 +499,12 @@ export default {
693
499
  wrapperClass: '$remove:formkit-wrapper',
694
500
  labelClass: 'ui-dynamic-form-input-label',
695
501
  inputClass: `input-${this.theme}`,
696
- innerClass: `ui-dynamic-form-input-outlines ${
697
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
698
- }`,
502
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
699
503
  readonly: isReadOnly,
700
504
  validation,
701
- validationVisibility: 'live',
702
- },
703
- };
505
+ validationVisibility: 'live'
506
+ }
507
+ }
704
508
  case 'email':
705
509
  return {
706
510
  type: 'FormKit',
@@ -716,34 +520,32 @@ export default {
716
520
  wrapperClass: '$remove:formkit-wrapper',
717
521
  labelClass: 'ui-dynamic-form-input-label',
718
522
  inputClass: `input-${this.theme}`,
719
- innerClass: `ui-dynamic-form-input-outlines ${
720
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
721
- }`,
523
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
722
524
  readonly: isReadOnly,
723
525
  validation,
724
- validationVisibility: 'live',
725
- },
726
- };
526
+ validationVisibility: 'live'
527
+ }
528
+ }
727
529
  case 'header':
728
- let typeToUse = 'h1';
530
+ let typeToUse = 'h1'
729
531
  if (field.customForm && JSON.parse(field.customForm).style === 'heading_2') {
730
- typeToUse = 'h2';
532
+ typeToUse = 'h2'
731
533
  }
732
534
  if (field.customForm && JSON.parse(field.customForm).style === 'heading_3') {
733
- typeToUse = 'h3';
535
+ typeToUse = 'h3'
734
536
  }
735
537
  return {
736
538
  type: typeToUse,
737
- innerText: this.formData[field.id],
738
- };
539
+ innerText: this.formData[field.id]
540
+ }
739
541
  case 'hidden':
740
542
  return {
741
543
  type: 'input',
742
544
  props: {
743
545
  type: 'hidden',
744
- value: this.formData[field.id],
745
- },
746
- };
546
+ value: this.formData[field.id]
547
+ }
548
+ }
747
549
  case 'month':
748
550
  return {
749
551
  type: 'FormKit',
@@ -758,19 +560,17 @@ export default {
758
560
  wrapperClass: '$remove:formkit-wrapper',
759
561
  labelClass: 'ui-dynamic-form-input-label',
760
562
  inputClass: `input-${this.theme}`,
761
- innerClass: `ui-dynamic-form-input-outlines ${
762
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
763
- }`,
563
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
764
564
  readonly: isReadOnly,
765
565
  validation,
766
- validationVisibility: 'live',
767
- },
768
- };
566
+ validationVisibility: 'live'
567
+ }
568
+ }
769
569
  case 'paragraph':
770
570
  return {
771
571
  type: 'p',
772
- innerText: this.formData[field.id],
773
- };
572
+ innerText: this.formData[field.id]
573
+ }
774
574
  case 'password':
775
575
  return {
776
576
  type: 'FormKit',
@@ -786,18 +586,16 @@ export default {
786
586
  wrapperClass: '$remove:formkit-wrapper',
787
587
  labelClass: 'ui-dynamic-form-input-label',
788
588
  inputClass: `input-${this.theme}`,
789
- innerClass: `ui-dynamic-form-input-outlines ${
790
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
791
- }`,
589
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
792
590
  readonly: isReadOnly,
793
591
  validation,
794
- validationVisibility: 'live',
795
- },
796
- };
592
+ validationVisibility: 'live'
593
+ }
594
+ }
797
595
  case 'radio':
798
596
  const radioOptions = JSON.parse(field.customForm).entries.map((obj) => {
799
- return { value: obj.key, label: obj.value };
800
- });
597
+ return { value: obj.key, label: obj.value }
598
+ })
801
599
  return {
802
600
  type: 'FormKit',
803
601
  props: {
@@ -812,17 +610,15 @@ export default {
812
610
  fieldsetClass: 'custom-fieldset',
813
611
  labelClass: 'ui-dynamic-form-input-label',
814
612
  inputClass: `input-${this.theme}`,
815
- innerClass: `ui-dynamic-form-input-outlines ${
816
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
817
- }`,
613
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
818
614
  readonly: isReadOnly,
819
615
  disabled: isReadOnly,
820
616
  validation,
821
- validationVisibility: 'live',
822
- },
823
- };
617
+ validationVisibility: 'live'
618
+ }
619
+ }
824
620
  case 'range':
825
- const customForm = JSON.parse(field.customForm);
621
+ const customForm = JSON.parse(field.customForm)
826
622
  return {
827
623
  type: 'v-slider',
828
624
  props: {
@@ -843,9 +639,9 @@ export default {
843
639
  readonly: isReadOnly,
844
640
  disabled: isReadOnly,
845
641
  validation,
846
- validationVisibility: 'live',
847
- },
848
- };
642
+ validationVisibility: 'live'
643
+ }
644
+ }
849
645
  case 'tel':
850
646
  return {
851
647
  type: 'FormKit',
@@ -861,16 +657,14 @@ export default {
861
657
  wrapperClass: '$remove:formkit-wrapper',
862
658
  labelClass: 'ui-dynamic-form-input-label',
863
659
  inputClass: `input-${this.theme}`,
864
- innerClass: `ui-dynamic-form-input-outlines ${
865
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
866
- }`,
660
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
867
661
  readonly: isReadOnly,
868
662
  validation,
869
- validationVisibility: 'live',
870
- },
871
- };
663
+ validationVisibility: 'live'
664
+ }
665
+ }
872
666
  case 'textarea':
873
- const rows = field.customForm ? JSON.parse(field.customForm).rows : undefined;
667
+ const rows = field.customForm ? JSON.parse(field.customForm).rows : undefined
874
668
  return {
875
669
  type: 'FormKit',
876
670
  props: {
@@ -886,14 +680,12 @@ export default {
886
680
  wrapperClass: '$remove:formkit-wrapper',
887
681
  labelClass: 'ui-dynamic-form-input-label',
888
682
  inputClass: `input-${this.theme}`,
889
- innerClass: `ui-dynamic-form-input-outlines ${
890
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
891
- }`,
683
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
892
684
  readonly: isReadOnly,
893
685
  validation,
894
- validationVisibility: 'live',
895
- },
896
- };
686
+ validationVisibility: 'live'
687
+ }
688
+ }
897
689
  case 'time':
898
690
  return {
899
691
  type: 'FormKit',
@@ -909,14 +701,12 @@ export default {
909
701
  wrapperClass: '$remove:formkit-wrapper',
910
702
  labelClass: 'ui-dynamic-form-input-label',
911
703
  inputClass: `input-${this.theme}`,
912
- innerClass: `ui-dynamic-form-input-outlines ${
913
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
914
- }`,
704
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
915
705
  readonly: isReadOnly,
916
706
  validation,
917
- validationVisibility: 'live',
918
- },
919
- };
707
+ validationVisibility: 'live'
708
+ }
709
+ }
920
710
  case 'url':
921
711
  return {
922
712
  type: 'FormKit',
@@ -932,14 +722,12 @@ export default {
932
722
  wrapperClass: '$remove:formkit-wrapper',
933
723
  labelClass: 'ui-dynamic-form-input-label',
934
724
  inputClass: `input-${this.theme}`,
935
- innerClass: `ui-dynamic-form-input-outlines ${
936
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
937
- }`,
725
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
938
726
  readonly: isReadOnly,
939
727
  validation,
940
- validationVisibility: 'live',
941
- },
942
- };
728
+ validationVisibility: 'live'
729
+ }
730
+ }
943
731
  case 'week':
944
732
  return {
945
733
  type: 'FormKit',
@@ -955,14 +743,12 @@ export default {
955
743
  wrapperClass: '$remove:formkit-wrapper',
956
744
  labelClass: 'ui-dynamic-form-input-label',
957
745
  inputClass: `input-${this.theme}`,
958
- innerClass: `ui-dynamic-form-input-outlines ${
959
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
960
- }`,
746
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
961
747
  readonly: isReadOnly,
962
748
  validation,
963
- validationVisibility: 'live',
964
- },
965
- };
749
+ validationVisibility: 'live'
750
+ }
751
+ }
966
752
  default:
967
753
  return {
968
754
  type: 'FormKit',
@@ -976,247 +762,226 @@ export default {
976
762
  help: hint,
977
763
  labelClass: 'ui-dynamic-form-input-label',
978
764
  inputClass: `input-${this.theme}`,
979
- innerClass: `ui-dynamic-form-input-outlines ${
980
- this.theme === 'dark' ? '$remove:formkit-inner' : ''
981
- }`,
765
+ innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
982
766
  readonly: isReadOnly,
983
767
  validation,
984
- validationVisibility: 'live',
985
- },
986
- };
768
+ validationVisibility: 'live'
769
+ }
770
+ }
987
771
  }
988
772
  },
989
773
  toggleCollapse() {
990
- this.collapsed = !this.collapsed;
774
+ this.collapsed = !this.collapsed
991
775
  },
992
776
  getRowWidthStyling(field, index) {
993
- let style = '';
777
+ let style = ''
994
778
  if (index === 0) {
995
- style += 'margin-top: 12px;';
779
+ style += 'margin-top: 12px;'
996
780
  }
997
781
  if (field.type === 'header') {
998
- style += 'flex-basis: 100%;';
782
+ style += 'flex-basis: 100%;'
999
783
  } else {
1000
- style += `flex-basis: 100%;`;
784
+ style += `flex-basis: 100%;`
1001
785
  }
1002
- return style;
786
+ return style
1003
787
  },
1004
788
  fields() {
1005
- const aFields = this.userTask.userTaskConfig?.formFields ?? [];
789
+ const aFields = this.userTask.userTaskConfig?.formFields ?? []
1006
790
  const fieldMap = aFields.map((field) => ({
1007
791
  ...field,
1008
- items: mapItems(field.type, field),
1009
- }));
792
+ items: mapItems(field.type, field)
793
+ }))
1010
794
 
1011
- return fieldMap;
795
+ return fieldMap
1012
796
  },
1013
797
  /*
1014
798
  widget-action just sends a msg to Node-RED, it does not store the msg state server-side
1015
799
  alternatively, you can use widget-change, which will also store the msg in the Node's datastore
1016
800
  */
1017
801
  send(msg, index) {
1018
- const msgArr = [];
1019
- msgArr[index] = msg;
1020
- this.$socket.emit('widget-action', this.id, msgArr);
802
+ const msgArr = []
803
+ msgArr[index] = msg
804
+ this.$socket.emit('widget-action', this.id, msgArr)
1021
805
  },
1022
806
  init(msg) {
1023
- this.msg = msg;
1024
- // Clear component cache when form data changes for performance
1025
- this.clearComponentCache();
1026
-
807
+ this.msg = msg
1027
808
  if (!msg) {
1028
- return;
809
+ return
1029
810
  }
1030
811
 
1031
- this.actions = this.props.options;
812
+ this.actions = this.props.options
1032
813
 
1033
- const hasTask = msg.payload && msg.payload.userTask;
814
+ const hasTask = msg.payload && msg.payload.userTask
1034
815
 
1035
816
  if (hasTask) {
1036
- this.userTask = msg.payload.userTask;
817
+ this.userTask = msg.payload.userTask
1037
818
  } else {
1038
- this.userTask = null;
1039
- this.formData = {};
1040
- return;
819
+ this.userTask = null
820
+ this.formData = {}
821
+ return
1041
822
  }
1042
823
 
1043
- const formFields = this.userTask.userTaskConfig.formFields;
1044
- const formFieldIds = formFields.map((ff) => ff.id);
1045
- const initialValues = this.userTask.startToken;
1046
- const finishedFormData = msg.payload.formData;
1047
- this.formIsFinished = !!msg.payload.formData;
824
+ const formFields = this.userTask.userTaskConfig.formFields
825
+ const formFieldIds = formFields.map((ff) => ff.id)
826
+ const initialValues = this.userTask.startToken
827
+ const finishedFormData = msg.payload.formData
828
+ this.formIsFinished = !!msg.payload.formData
1048
829
  if (this.formIsFinished) {
1049
- this.collapsed = this.props.collapse_when_finished;
830
+ this.collapsed = this.props.collapse_when_finished
1050
831
  }
1051
832
 
1052
833
  if (formFields) {
1053
834
  formFields.forEach((field) => {
1054
- this.formData[field.id] = field.defaultValue;
835
+ this.formData[field.id] = field.defaultValue
1055
836
 
1056
837
  if (field.type === 'confirm') {
1057
- const customForm = field.customForm ? JSON.parse(field.customForm) : {};
1058
- const confirmText = customForm.confirmButtonText ?? 'Confirm';
1059
- const declineText = customForm.declineButtonText ?? 'Decline';
838
+ const customForm = field.customForm ? JSON.parse(field.customForm) : {}
839
+ const confirmText = customForm.confirmButtonText ?? 'Confirm'
840
+ const declineText = customForm.declineButtonText ?? 'Decline'
1060
841
  this.actions = [
1061
842
  {
1062
843
  alignment: 'right',
1063
844
  primary: 'false',
1064
845
  label: declineText,
1065
- condition: '',
846
+ condition: ''
1066
847
  },
1067
848
  {
1068
849
  alignment: 'right',
1069
850
  primary: 'true',
1070
851
  label: confirmText,
1071
- condition: '',
1072
- },
1073
- ];
1074
- }
1075
- });
1076
-
1077
- // Check for file fields and duplicate them as file-preview if initial values exist
1078
- // Insert preview fields directly before their corresponding file fields
1079
- for (let i = formFields.length - 1; i >= 0; i--) {
1080
- const field = formFields[i];
1081
- if (field.type === 'file' && initialValues && initialValues[field.id]) {
1082
- const previewField = { ...field };
1083
- previewField.type = 'file-preview';
1084
- previewField.id = `${field.id}_preview`; // Give it a unique ID
1085
- this.userTask.userTaskConfig.formFields.splice(i, 0, previewField);
852
+ condition: ''
853
+ }
854
+ ]
1086
855
  }
1087
- }
856
+ })
1088
857
  }
1089
858
 
1090
859
  if (initialValues) {
1091
- if (initialValues) {
1092
- Object.keys(initialValues)
1093
- .filter((key) => formFieldIds.includes(key))
1094
- .forEach((key) => {
1095
- this.formData[key] = initialValues[key];
1096
- });
1097
- }
860
+ Object.keys(initialValues)
861
+ .filter((key) => formFieldIds.includes(key))
862
+ .forEach((key) => {
863
+ this.formData[key] = initialValues[key]
864
+ })
1098
865
  }
1099
866
 
1100
867
  if (this.formIsFinished) {
1101
868
  Object.keys(finishedFormData)
1102
869
  .filter((key) => formFieldIds.includes(key))
1103
870
  .forEach((key) => {
1104
- this.formData[key] = finishedFormData[key];
1105
- });
871
+ this.formData[key] = finishedFormData[key]
872
+ })
1106
873
  }
1107
874
 
1108
875
  nextTick(() => {
1109
- this.focusFirstFormField();
1110
- });
876
+ this.focusFirstFormField()
877
+ })
1111
878
  },
1112
879
  actionFn(action) {
1113
880
  if (action.label === 'Speichern' || action.label === 'Speichern und nächster') {
1114
- const formkitInputs = this.$refs.form.$el.querySelectorAll('.formkit-outer');
1115
- let allComplete = true;
881
+ const formkitInputs = this.$refs.form.$el.querySelectorAll('.formkit-outer')
882
+ let allComplete = true
1116
883
 
1117
884
  formkitInputs.forEach((input) => {
1118
- const dataComplete = input.getAttribute('data-complete');
1119
- const dataInvalid = input.getAttribute('data-invalid');
885
+ const dataComplete = input.getAttribute('data-complete')
886
+ const dataInvalid = input.getAttribute('data-invalid')
1120
887
 
1121
888
  if (dataComplete == null && dataInvalid === 'true') {
1122
- allComplete = false;
889
+ allComplete = false
1123
890
  }
1124
- });
891
+ })
1125
892
 
1126
- if (!allComplete) return;
893
+ if (!allComplete) return
1127
894
  }
1128
895
 
1129
896
  if (this.checkCondition(action.condition)) {
1130
- this.showError('');
897
+ this.showError('')
1131
898
 
1132
- const processedFormData = { ...this.formData };
1133
- const formFields = this.userTask.userTaskConfig.formFields;
899
+ const processedFormData = { ...this.formData }
900
+ const formFields = this.userTask.userTaskConfig.formFields
1134
901
 
1135
- formFields.forEach((field) => {
1136
- const fieldValue = processedFormData[field.id];
902
+ formFields.forEach(field => {
903
+ const fieldValue = processedFormData[field.id]
1137
904
 
1138
905
  if (field.type === 'number' || field.type === 'long') {
1139
906
  if (fieldValue !== null && fieldValue !== undefined && fieldValue !== '') {
1140
907
  if (field.type === 'long') {
1141
- const intValue = Number.parseInt(fieldValue, 10);
908
+ const intValue = Number.parseInt(fieldValue, 10)
1142
909
  if (!isNaN(intValue)) {
1143
- processedFormData[field.id] = intValue;
910
+ processedFormData[field.id] = intValue
1144
911
  }
1145
912
  } else {
1146
- const numValue = Number.parseFloat(fieldValue);
913
+ const numValue = Number.parseFloat(fieldValue)
1147
914
  if (!isNaN(numValue)) {
1148
- processedFormData[field.id] = numValue;
915
+ processedFormData[field.id] = numValue
1149
916
  }
1150
917
  }
1151
918
  }
1152
919
  }
1153
- });
920
+ })
1154
921
 
1155
- const msg = this.msg ?? {};
1156
- msg.payload = { formData: processedFormData, userTask: this.userTask };
922
+ const msg = this.msg ?? {}
923
+ msg.payload = { formData: processedFormData, userTask: this.userTask }
1157
924
  this.send(
1158
925
  msg,
1159
926
  this.actions.findIndex((element) => element.label === action.label) +
1160
- (this.isConfirmDialog ? this.props.options.length : 0)
1161
- );
927
+ (this.isConfirmDialog ? this.props.options.length : 0)
928
+ )
1162
929
  // TODO: mm - end
1163
930
  } else {
1164
- this.showError(action.errorMessage);
931
+ this.showError(action.errorMessage)
1165
932
  }
1166
933
  },
1167
934
  checkCondition(condition) {
1168
- if (condition === '') return true;
935
+ if (condition === '') return true
1169
936
  try {
1170
937
  // eslint-disable-next-line no-new-func
1171
- const func = Function('fields', 'userTask', 'msg', '"use strict"; return (' + condition + ')');
1172
- const result = func(this.formData, this.userTask, this.msg);
1173
- return Boolean(result);
938
+ const func = Function('fields', 'userTask', 'msg', '"use strict"; return (' + condition + ')')
939
+ const result = func(this.formData, this.userTask, this.msg)
940
+ return Boolean(result)
1174
941
  } catch (err) {
1175
- console.error('Error while evaluating condition: ' + err);
1176
- return false;
942
+ console.error('Error while evaluating condition: ' + err)
943
+ return false
1177
944
  }
1178
945
  },
1179
946
  showError(errMsg) {
1180
- this.errorMsg = errMsg;
947
+ this.errorMsg = errMsg
1181
948
  },
1182
949
  focusFirstFormField() {
1183
950
  if (this.collapsed || !this.hasUserTask) {
1184
- return;
951
+ return
1185
952
  }
1186
953
 
1187
954
  if (this.firstFormFieldRef) {
1188
- let inputElement = null;
955
+ let inputElement = null
1189
956
 
1190
957
  if (this.firstFormFieldRef.node && this.firstFormFieldRef.node.input instanceof HTMLElement) {
1191
- inputElement = this.firstFormFieldRef.node.input;
958
+ inputElement = this.firstFormFieldRef.node.input
1192
959
  } else if (this.firstFormFieldRef.$el instanceof HTMLElement) {
1193
960
  if (['INPUT', 'TEXTAREA', 'SELECT'].includes(this.firstFormFieldRef.$el.tagName)) {
1194
- inputElement = this.firstFormFieldRef.$el;
961
+ inputElement = this.firstFormFieldRef.$el
1195
962
  } else {
1196
- inputElement = this.firstFormFieldRef.$el.querySelector(
1197
- 'input:not([type="hidden"]), textarea, select'
1198
- );
963
+ inputElement = this.firstFormFieldRef.$el.querySelector('input:not([type="hidden"]), textarea, select')
1199
964
  }
1200
965
  }
1201
966
 
1202
967
  if (inputElement) {
1203
- inputElement.focus();
968
+ inputElement.focus()
1204
969
  } else {
1205
- console.warn('Could not find a focusable input element for the first form field.');
970
+ console.warn('Could not find a focusable input element for the first form field.')
1206
971
  }
1207
972
  }
1208
- },
1209
- },
1210
- };
973
+ }
974
+ }
975
+ }
1211
976
 
1212
977
  function mapItems(type, field) {
1213
978
  if (type === 'enum') {
1214
979
  return field.enumValues.map((enumValue) => ({
1215
980
  title: enumValue.name,
1216
- value: enumValue.id,
1217
- }));
981
+ value: enumValue.id
982
+ }))
1218
983
  } else {
1219
- return null;
984
+ return null
1220
985
  }
1221
986
  }
1222
987
  </script>