@5minds/node-red-dashboard-2-processcube-dynamic-form 2.0.7-feature-386fff-md7hlyoo → 2.0.7-feature-62dabd-md8rsz8b

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,29 +1,18 @@
1
1
  <template>
2
- <div style="display: flex; justify-content: space-between; width: 100%">
3
- <div style="display: flex; gap: 8px; flex-wrap: wrap">
2
+ <div class="ui-dynamic-form-footer-actions-container">
3
+ <div class="ui-dynamic-form-footer-actions-left">
4
4
  <div v-for="(action, index) in actions" :key="index">
5
- <v-btn
6
- v-if="action.alignment === 'left' || !action.alignment"
7
- :key="index"
8
- style="min-height: 36px"
9
- :class="getActionButtonClass(action)"
10
- :disabled="formIsFinished"
11
- @click="actionCallback(action)"
12
- >
5
+ <v-btn v-if="action.alignment === 'left' || !action.alignment" :key="index"
6
+ class="ui-dynamic-form-footer-action-button" :class="getActionButtonClass(action)"
7
+ :disabled="formIsFinished" @click="actionCallback(action)">
13
8
  {{ action.label }}
14
9
  </v-btn>
15
10
  </div>
16
11
  </div>
17
- <div style="display: flex; gap: 8px;">
12
+ <div class="ui-dynamic-form-footer-actions-right">
18
13
  <div v-for="(action, index) in actions" :key="index">
19
- <v-btn
20
- v-if="action.alignment === 'right'"
21
- :key="index"
22
- style="min-height: 36px"
23
- :class="getActionButtonClass(action)"
24
- :disabled="formIsFinished"
25
- @click="actionCallback(action)"
26
- >
14
+ <v-btn v-if="action.alignment === 'right'" :key="index" class="ui-dynamic-form-footer-action-button"
15
+ :class="getActionButtonClass(action)" :disabled="formIsFinished" @click="actionCallback(action)">
27
16
  {{ action.label }}
28
17
  </v-btn>
29
18
  </div>
@@ -36,12 +25,12 @@
36
25
  export default {
37
26
  name: 'UIDynamicFormFooterAction',
38
27
  props: {
39
- actions: { type: Array, default () { return [] } },
40
- actionCallback: { type: Function, default (action) {} },
41
- formIsFinished: { type: Boolean, default () { return false } }
28
+ actions: { type: Array, default() { return [] } },
29
+ actionCallback: { type: Function, default(action) { } },
30
+ formIsFinished: { type: Boolean, default() { return false } }
42
31
  },
43
32
  methods: {
44
- getActionButtonClass (action) {
33
+ getActionButtonClass(action) {
45
34
  return action.primary === 'true' ? 'ui-dynamic-form-footer-action-primary' : 'ui-dynamic-form-footer-action-secondary'
46
35
  }
47
36
  }
@@ -1,25 +1,18 @@
1
1
  <template>
2
2
  <div v-if="title.length > 0">
3
- <h3 :class="typeSpecificStyling" style="display: flex; gap: 25px; align-items: center">
4
- <svg
5
- v-if="collapsible && !collapsed"
6
- style="width: 25px; height: 25px; cursor: pointer;"
7
- xmlns="http://www.w3.org/2000/svg"
8
- viewBox="0 0 448 512"
9
- @click="toggleCollapse"
10
- >
11
- <path :fill="style === 'default' ? 'white' : 'black'" d="M201.4 374.6c12.5 12.5 32.8 12.5 45.3 0l160-160c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 306.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160z"/>
3
+ <h3 :class="typeSpecificStyling" class="ui-dynamic-form-title-responsive"
4
+ style="display: flex; gap: 25px; align-items: center">
5
+ <svg v-if="collapsible && !collapsed" style="width: 25px; height: 25px; cursor: pointer;"
6
+ xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" @click="toggleCollapse">
7
+ <path :fill="style === 'default' ? 'white' : 'black'"
8
+ d="M201.4 374.6c12.5 12.5 32.8 12.5 45.3 0l160-160c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 306.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160z" />
12
9
  </svg>
13
- <svg
14
- v-if="collapsible && collapsed"
15
- style="width: 25px; height: 25px; cursor: pointer;"
16
- xmlns="http://www.w3.org/2000/svg"
17
- viewBox="0 0 320 512"
18
- @click="toggleCollapse"
19
- >
20
- <path :fill="style === 'default' ? 'white' : 'black'" d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/>
10
+ <svg v-if="collapsible && collapsed" style="width: 25px; height: 25px; cursor: pointer;"
11
+ xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" @click="toggleCollapse">
12
+ <path :fill="style === 'default' ? 'white' : 'black'"
13
+ d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z" />
21
14
  </svg>
22
- <div :style="{width: 'fit-content', display: style === 'default' ? '' : 'flex'}">
15
+ <div :style="{ width: 'fit-content', display: style === 'default' ? '' : 'flex' }">
23
16
  <img v-if="titleIcon.length > 0" :src="titleIcon" style="padding-right: 16px;">
24
17
  <span :style="customStyles">{{ title }}</span>
25
18
  <hr v-if="style === 'default'">
@@ -33,16 +26,16 @@
33
26
  export default {
34
27
  name: 'UIDynamicFormTitleText',
35
28
  props: {
36
- style: { type: String, default () { return 'default' } },
37
- title: { type: String, default () { return '' } },
38
- customStyles: { type: String, default () { return '' } },
39
- collapsible: { type: Boolean, default () { return false } },
40
- collapsed: { type: Boolean, default () { return false } },
41
- titleIcon: { type: String, default () { return '' } },
42
- toggleCollapse: { type: Function, default () {} }
29
+ style: { type: String, default() { return 'default' } },
30
+ title: { type: String, default() { return '' } },
31
+ customStyles: { type: String, default() { return '' } },
32
+ collapsible: { type: Boolean, default() { return false } },
33
+ collapsed: { type: Boolean, default() { return false } },
34
+ titleIcon: { type: String, default() { return '' } },
35
+ toggleCollapse: { type: Function, default() { } }
43
36
  },
44
37
  computed: {
45
- typeSpecificStyling () {
38
+ typeSpecificStyling() {
46
39
  return `ui-dynamic-form-title-${this.style}`
47
40
  }
48
41
  }
@@ -15,9 +15,11 @@
15
15
  :collapsed="collapsed" :toggleCollapse="toggleCollapse" />
16
16
  <Transition name="cardCollapse">
17
17
  <div v-if="!collapsed">
18
- <div className="ui-dynamic-form-formfield-positioner" :style="props.inner_card_styling">
18
+ <div className="ui-dynamic-form-formfield-positioner" :style="props.inner_card_styling"
19
+ :data-columns="props.form_columns || 1">
19
20
  <FormKit id="form" type="group">
20
21
  <v-row v-for="(field, index) in fields()" :key="field"
22
+ :class="field.type === 'header' ? 'ui-dynamic-form-header-row' : ''"
21
23
  :style="getRowWidthStyling(field, index)">
22
24
  <v-col cols="12">
23
25
  <component :is="createComponent(field).type"
@@ -266,13 +268,14 @@ export default {
266
268
  required: field.required,
267
269
  value: this.formData[field.id],
268
270
  number: 'integer',
271
+ min: 0,
272
+ validation: validation ? `${validation}|number` : 'number',
269
273
  help: hint,
270
274
  wrapperClass: '$remove:formkit-wrapper',
271
275
  labelClass: 'ui-dynamic-form-input-label',
272
276
  inputClass: `input-${this.theme}`,
273
277
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
274
278
  readonly: isReadOnly,
275
- validation,
276
279
  validationVisibility: 'live'
277
280
  }
278
281
  }
@@ -288,13 +291,14 @@ export default {
288
291
  required: field.required,
289
292
  value: this.formData[field.id],
290
293
  step,
294
+ number: 'float',
295
+ validation: validation ? `${validation}|number` : 'number',
291
296
  help: hint,
292
297
  wrapperClass: '$remove:formkit-wrapper',
293
298
  labelClass: 'ui-dynamic-form-input-label',
294
299
  inputClass: `input-${this.theme}`,
295
300
  innerClass: `ui-dynamic-form-input-outlines ${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
296
301
  readonly: isReadOnly,
297
- validation,
298
302
  validationVisibility: 'live'
299
303
  }
300
304
  }
@@ -777,7 +781,8 @@ export default {
777
781
  if (field.type === 'header') {
778
782
  style += 'flex-basis: 100%;'
779
783
  } else {
780
- style += `flex-basis: ${(1 / this.props.form_columns) * 100}%;`
784
+ // On desktop, use form_columns; on mobile, always 100%
785
+ style += `flex-basis: 100%;` // Mobile default
781
786
  }
782
787
  return style
783
788
  },
@@ -891,13 +896,32 @@ export default {
891
896
 
892
897
  if (this.checkCondition(action.condition)) {
893
898
  this.showError('')
894
- // TODO: MM - begin
895
- // this.send(
896
- // { payload: { formData: this.formData, userTask: this.userTask } },
897
- // this.actions.findIndex((element) => element.label === action.label)
898
- // );
899
+
900
+ const processedFormData = { ...this.formData }
901
+ const formFields = this.userTask.userTaskConfig.formFields
902
+
903
+ formFields.forEach(field => {
904
+ const fieldValue = processedFormData[field.id]
905
+
906
+ if (field.type === 'number' || field.type === 'long') {
907
+ if (fieldValue !== null && fieldValue !== undefined && fieldValue !== '') {
908
+ if (field.type === 'long') {
909
+ const intValue = parseInt(fieldValue, 10)
910
+ if (!isNaN(intValue)) {
911
+ processedFormData[field.id] = intValue
912
+ }
913
+ } else {
914
+ const numValue = parseFloat(fieldValue)
915
+ if (!isNaN(numValue)) {
916
+ processedFormData[field.id] = numValue
917
+ }
918
+ }
919
+ }
920
+ }
921
+ })
922
+
899
923
  const msg = this.msg ?? {}
900
- msg.payload = { formData: this.formData, userTask: this.userTask }
924
+ msg.payload = { formData: processedFormData, userTask: this.userTask }
901
925
  this.send(
902
926
  msg,
903
927
  this.actions.findIndex((element) => element.label === action.label) +
@@ -130,6 +130,43 @@ code {
130
130
  padding: 8px;
131
131
  }
132
132
 
133
+ .ui-dynamic-form-footer-actions-container {
134
+ display: flex;
135
+ justify-content: space-between;
136
+ align-items: center;
137
+ gap: 12px;
138
+ width: 100%;
139
+ box-sizing: border-box;
140
+ }
141
+
142
+ .ui-dynamic-form-footer-actions-left,
143
+ .ui-dynamic-form-footer-actions-right {
144
+ display: flex;
145
+ gap: 8px;
146
+ align-items: center;
147
+ }
148
+
149
+ .ui-dynamic-form-footer-action-button {
150
+ min-height: 36px;
151
+ padding: 8px 12px;
152
+ box-sizing: border-box;
153
+ flex-shrink: 0;
154
+ }
155
+
156
+ /* For very wide desktop layouts with multiple buttons */
157
+ @media screen and (min-width: 600px) {
158
+ .ui-dynamic-form-footer-actions-container {
159
+ flex-wrap: wrap;
160
+ }
161
+
162
+ .ui-dynamic-form-footer-action-button {
163
+ max-width: 200px;
164
+ white-space: nowrap;
165
+ overflow: hidden;
166
+ text-overflow: ellipsis;
167
+ }
168
+ }
169
+
133
170
  .ui-dynamic-form-wrapper {
134
171
  --fk-color-primary: rgb(var(--v-theme-primary)) !important;
135
172
  --fk-color-border: rgb(var(--v-theme-group-outline)); /* Does not work somehow */
@@ -146,6 +183,202 @@ code {
146
183
  }
147
184
  }
148
185
 
186
+ @media only screen and (max-width: 599px) {
187
+ .ui-dynamic-form-external-sizing-wrapper {
188
+ max-width: 100vw;
189
+ margin: 0;
190
+ padding: 0;
191
+ overflow-x: hidden;
192
+ }
193
+
194
+ .ui-dynamic-form-wrapper {
195
+ padding: 8px;
196
+ margin: 0;
197
+ overflow-x: hidden;
198
+ }
199
+
200
+ .ui-dynamic-form-formfield-positioner {
201
+ padding: 16px;
202
+ padding-top: 8px;
203
+ max-height: calc(100vh - 200px);
204
+ column-gap: 0px;
205
+ flex-direction: column;
206
+ border-left: none;
207
+ border-right: none;
208
+ overflow-x: hidden;
209
+ }
210
+
211
+ .ui-dynamic-form-title-default {
212
+ padding: 16px;
213
+ font-size: 24px;
214
+ border-left: none;
215
+ border-right: none;
216
+ }
217
+
218
+ .ui-dynamic-form-title-minimal {
219
+ padding: 12px;
220
+ border-left: none;
221
+ border-right: none;
222
+ }
223
+
224
+ .ui-dynamic-form-title-outside {
225
+ padding: 12px 16px;
226
+ font-size: 20px;
227
+ }
228
+
229
+ .ui-dynamic-form-footer-common {
230
+ padding: 12px 16px;
231
+ gap: 12px;
232
+ margin: 0;
233
+ }
234
+
235
+ .input-light,
236
+ .input-default,
237
+ .input-dark {
238
+ font-size: 16px;
239
+ padding: 12px 8px;
240
+ min-height: 44px;
241
+ }
242
+
243
+ .ui-dynamic-form-input-label {
244
+ font-size: 16px;
245
+ padding-bottom: 8px;
246
+ }
247
+
248
+ .ui-dynamic-form-footer-actions-container {
249
+ flex-direction: column;
250
+ gap: 12px;
251
+ align-items: stretch;
252
+ width: 100%;
253
+ }
254
+
255
+ .ui-dynamic-form-footer-actions-left,
256
+ .ui-dynamic-form-footer-actions-right {
257
+ flex-direction: column;
258
+ gap: 8px;
259
+ width: 100%;
260
+ }
261
+
262
+ .ui-dynamic-form-footer-actions-left > div,
263
+ .ui-dynamic-form-footer-actions-right > div {
264
+ width: 100%;
265
+ }
266
+
267
+ .ui-dynamic-form-footer-action-button {
268
+ min-height: 44px;
269
+ padding: 12px 16px;
270
+ font-size: 16px;
271
+ width: 100%;
272
+ box-sizing: border-box;
273
+ white-space: nowrap;
274
+ overflow: hidden;
275
+ text-overflow: ellipsis;
276
+ }
277
+
278
+ .ui-dynamic-form-footer-action-button .v-btn__content {
279
+ white-space: nowrap !important;
280
+ overflow: hidden !important;
281
+ text-overflow: ellipsis !important;
282
+ max-width: 100% !important;
283
+ display: block !important;
284
+ }
285
+
286
+ .ui-dynamic-form-footer-action-primary,
287
+ .ui-dynamic-form-footer-action-secondary {
288
+ min-height: 44px;
289
+ font-size: 16px;
290
+ width: 100%;
291
+ box-sizing: border-box;
292
+ }
293
+
294
+ .ui-dynamic-form-footer-action-primary .v-btn__content,
295
+ .ui-dynamic-form-footer-action-secondary .v-btn__content {
296
+ white-space: nowrap !important;
297
+ overflow: hidden !important;
298
+ text-overflow: ellipsis !important;
299
+ max-width: 100% !important;
300
+ display: block !important;
301
+ }
302
+
303
+ .ui-dynamic-form-formfield-positioner .v-row {
304
+ margin-bottom: 16px;
305
+ flex-basis: 100% !important;
306
+ }
307
+
308
+ .ui-dynamic-form-formfield-positioner select,
309
+ .ui-dynamic-form-formfield-positioner textarea {
310
+ font-size: 16px;
311
+ min-height: 44px;
312
+ padding: 12px 8px;
313
+ }
314
+
315
+ .ui-dynamic-form-formfield-positioner input[type="checkbox"],
316
+ .ui-dynamic-form-formfield-positioner input[type="radio"] {
317
+ width: 20px;
318
+ height: 20px;
319
+ margin-right: 8px;
320
+ }
321
+
322
+ .ui-dynamic-form-formfield-positioner input[type="file"] {
323
+ font-size: 16px;
324
+ padding: 12px 8px;
325
+ }
326
+
327
+ .ui-dynamic-form-title-default h3 svg,
328
+ .ui-dynamic-form-title-minimal h3 svg,
329
+ .ui-dynamic-form-title-outside h3 svg {
330
+ width: 20px;
331
+ height: 20px;
332
+ }
333
+
334
+ .ui-dynamic-form-title-responsive {
335
+ gap: 15px !important;
336
+ flex-wrap: wrap;
337
+ }
338
+
339
+ .ui-dynamic-form-title-responsive img {
340
+ max-width: 32px;
341
+ height: auto;
342
+ }
343
+
344
+ .ui-dynamic-form-formfield-positioner {
345
+ -webkit-overflow-scrolling: touch;
346
+ }
347
+ }
348
+
349
+ @media only screen and (max-width: 480px) {
350
+ .ui-dynamic-form-formfield-positioner {
351
+ padding: 12px;
352
+ padding-top: 4px;
353
+ }
354
+
355
+ .ui-dynamic-form-title-default {
356
+ padding: 12px;
357
+ font-size: 20px;
358
+ }
359
+
360
+ .ui-dynamic-form-title-outside {
361
+ font-size: 18px;
362
+ }
363
+
364
+ .input-light,
365
+ .input-default,
366
+ .input-dark {
367
+ font-size: 16px;
368
+ padding: 10px 6px;
369
+ }
370
+
371
+ .ui-dynamic-form-input-label {
372
+ font-size: 14px;
373
+ }
374
+
375
+ .ui-dynamic-form-footer-action-button {
376
+ min-height: 48px;
377
+ font-size: 16px;
378
+ padding: 12px 16px;
379
+ }
380
+ }
381
+
149
382
  .cardCollapse-leave-active {
150
383
  transition: max-height 0.5s ease, opacity 0.2s ease;
151
384
  max-height: 100vh;
@@ -176,6 +409,28 @@ code {
176
409
  border-radius: 0px 0px 6px 6px;
177
410
  }
178
411
 
412
+ @media (min-width: 600px) {
413
+ .ui-dynamic-form-formfield-positioner .v-row:not(.ui-dynamic-form-header-row) {
414
+ flex-basis: calc(50% - 10px); /* Default 2 columns, adjust based on form_columns */
415
+ }
416
+
417
+ .ui-dynamic-form-formfield-positioner[data-columns="1"] .v-row:not(.ui-dynamic-form-header-row) {
418
+ flex-basis: 100%;
419
+ }
420
+
421
+ .ui-dynamic-form-formfield-positioner[data-columns="2"] .v-row:not(.ui-dynamic-form-header-row) {
422
+ flex-basis: calc(50% - 10px);
423
+ }
424
+
425
+ .ui-dynamic-form-formfield-positioner[data-columns="3"] .v-row:not(.ui-dynamic-form-header-row) {
426
+ flex-basis: calc(33.333% - 14px);
427
+ }
428
+
429
+ .ui-dynamic-form-formfield-positioner[data-columns="4"] .v-row:not(.ui-dynamic-form-header-row) {
430
+ flex-basis: calc(25% - 15px);
431
+ }
432
+ }
433
+
179
434
  .ui-dynamic-form-formfield-positioner h1,
180
435
  .ui-dynamic-form-formfield-positioner h2,
181
436
  .ui-dynamic-form-formfield-positioner h3 {