@5minds/node-red-dashboard-2-processcube-dynamic-form 2.0.3-feature-7ea503-mcdeghjp → 2.0.3

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.
@@ -2,37 +2,39 @@
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
4
  <UIDynamicFormTitleText
5
- v-if="props.title_style === 'outside' && hasUserTask" :style="props.title_style"
6
- :title="props.title_text" :customStyles="props.title_custom_text_styling" :titleIcon="props.title_icon"
7
- :collapsible="props.collapsible || (props.collapse_when_finished && formIsFinished)" :collapsed="collapsed"
5
+ v-if="props.title_style === 'outside' && hasUserTask"
6
+ :style="props.title_style"
7
+ :title="props.title_text"
8
+ :customStyles="props.title_custom_text_styling"
9
+ :titleIcon="props.title_icon"
10
+ :collapsible="props.collapsible || (props.collapse_when_finished && formIsFinished)"
11
+ :collapsed="collapsed"
8
12
  :toggleCollapse="toggleCollapse"
9
13
  />
10
14
  <div className="ui-dynamic-form-wrapper">
11
- <p v-if="hasUserTask" style="margin-bottom: 0px">
15
+ <p v-if="hasUserTask" style="margin-bottom: 0px;">
12
16
  <v-form ref="form" v-model="form" :class="dynamicClass">
13
17
  <UIDynamicFormTitleText
14
- v-if="props.title_style != 'outside'" :style="props.title_style"
15
- :title="props.title_text" :customStyles="props.title_custom_text_styling"
18
+ v-if="props.title_style != 'outside'"
19
+ :style="props.title_style"
20
+ :title="props.title_text"
21
+ :customStyles="props.title_custom_text_styling"
16
22
  :titleIcon="props.title_icon"
17
23
  :collapsible="props.collapsible || (props.collapse_when_finished && formIsFinished)"
18
- :collapsed="collapsed" :toggleCollapse="toggleCollapse"
24
+ :collapsed="collapsed"
25
+ :toggleCollapse="toggleCollapse"
19
26
  />
20
27
  <Transition name="cardCollapse">
21
28
  <div v-if="!collapsed">
22
- <div className="ui-dynamic-form-formfield-positioner" :style="props.inner_card_styling">
29
+ <div className="ui-dynamic-form-formfield-positioner">
23
30
  <FormKit id="form" type="group">
24
- <v-row
25
- v-for="(field, index) in fields()" :key="field"
26
- :style="getRowWidthStyling(field, index)"
27
- >
31
+ <v-row v-for="(field, index) in fields()" :key="field" :style="getRowWidthStyling(field, index)">
28
32
  <v-col cols="12">
29
33
  <component
30
34
  :is="createComponent(field).type"
31
35
  v-if="createComponent(field).innerText"
32
- v-bind="createComponent(field).props" :ref="(el) => {
33
- if (index === 0) firstFormFieldRef = el;
34
- }
35
- " v-model="formData[field.id]"
36
+ v-bind="createComponent(field).props"
37
+ v-model="formData[field.id]"
36
38
  >
37
39
  {{ createComponent(field).innerText }}
38
40
  </component>
@@ -40,22 +42,18 @@
40
42
  <p class="formkit-label">{{ field.label }}</p>
41
43
  <component
42
44
  :is="createComponent(field).type"
43
- v-bind="createComponent(field).props" :ref="(el) => {
44
- if (index === 0) firstFormFieldRef = el;
45
- }
46
- " v-model="field.defaultValue"
45
+ v-bind="createComponent(field).props"
46
+ v-model="field.defaultValue"
47
47
  />
48
48
  <p class="formkit-help">
49
- {{ field.customForm ? JSON.parse(field.customForm).hint : undefined
50
- }}
49
+ {{ field.customForm ? JSON.parse(field.customForm).hint : undefined }}
51
50
  </p>
52
51
  </div>
53
52
  <component
54
- :is="createComponent(field).type" v-else
55
- v-bind="createComponent(field).props" :ref="(el) => {
56
- if (index === 0) firstFormFieldRef = el;
57
- }
58
- " v-model="formData[field.id]"
53
+ :is="createComponent(field).type"
54
+ v-else
55
+ v-bind="createComponent(field).props"
56
+ v-model="formData[field.id]"
59
57
  />
60
58
  </v-col>
61
59
  </v-row>
@@ -65,24 +63,17 @@
65
63
  <v-row v-if="errorMsg.length > 0" style="padding: 12px">
66
64
  <v-alert type="error">Error: {{ errorMsg }}</v-alert>
67
65
  </v-row>
68
- <UIDynamicFormFooterAction
69
- v-if="props.actions_inside_card && actions.length > 0"
70
- :actions="actions" :actionCallback="actionFn" :formIsFinished="formIsFinished"
71
- style="padding: 16px; padding-top: 0px"
72
- />
66
+ <UIDynamicFormFooterAction v-if="props.actions_inside_card && actions.length > 0" :actions="actions" :actionCallback="actionFn" :formIsFinished="formIsFinished" style="padding: 16px; padding-top: 0px;" />
73
67
  </v-row>
74
68
  </div>
75
69
  </Transition>
76
70
  </v-form>
77
71
  </p>
78
72
  <p v-else>
79
- <v-alert
80
- v-if="props.waiting_info.length > 0 || props.waiting_title.length > 0"
81
- :text="props.waiting_info" :title="props.waiting_title"
82
- />
73
+ <v-alert v-if="props.waiting_info.length > 0 || props.waiting_title.length > 0" :text="props.waiting_info" :title="props.waiting_title" />
83
74
  </p>
84
75
  </div>
85
- <div v-if="!props.actions_inside_card && actions.length > 0 && hasUserTask" style="padding-top: 32px">
76
+ <div v-if="!props.actions_inside_card && actions.length > 0 && hasUserTask" style="padding-top: 32px;">
86
77
  <UIDynamicFormFooterAction :actions="actions" :actionCallback="actionFn" />
87
78
  </div>
88
79
  </div>
@@ -90,39 +81,22 @@
90
81
 
91
82
  <!-- eslint-disable no-case-declarations -->
92
83
  <script>
93
- import { de } from '@formkit/i18n'
94
84
  import { FormKit, defaultConfig, plugin } from '@formkit/vue'
95
- import { getCurrentInstance, markRaw, nextTick } from 'vue'
85
+ import { getCurrentInstance, markRaw } from 'vue'
96
86
 
97
87
  // eslint-disable-next-line import/no-unresolved
98
88
  import '@formkit/themes/genesis'
99
89
  import UIDynamicFormFooterAction from './FooterActions.vue'
100
90
  import UIDynamicFormTitleText from './TitleText.vue'
101
91
 
102
- // eslint-disable-next-line no-unused-vars
103
- function requiredIf ({ value }, [targetField, expectedValue], node) {
104
- console.debug(arguments)
105
-
106
- const actual = node?.root?.value?.[targetField]
107
- const isEmpty = value === '' || value === null || value === undefined
108
-
109
- if (actual === expectedValue && isEmpty) {
110
- return false // oder: `return "Dieses Feld ist erforderlich."`
111
- }
112
-
113
- return true
114
- }
115
-
116
92
  export default {
117
93
  name: 'UIDynamicForm',
118
94
  components: {
119
- FormKit,
120
- UIDynamicFormFooterAction,
121
- UIDynamicFormTitleText
95
+ FormKit, UIDynamicFormFooterAction, UIDynamicFormTitleText
122
96
  },
123
97
  inject: ['$socket'],
124
98
  props: {
125
- /* do not remove entries from this - Dashboard's Layout Manager's will pass this data to your component */
99
+ /* do not remove entries from this - Dashboard's Layout Manager's will pass this data to your component */
126
100
  id: { type: String, required: true },
127
101
  props: { type: Object, default: () => ({}) },
128
102
  state: {
@@ -139,10 +113,20 @@ export default {
139
113
 
140
114
  const formkitConfig = defaultConfig({
141
115
  theme: 'genesis',
142
- locales: { de },
143
- locale: 'de',
144
- // eslint-disable-next-line object-shorthand
145
- rules: { requiredIf: requiredIf }
116
+ rules: {
117
+ requiredIf: ({ value, name }, [targetField, expectedValue], node) => {
118
+ const actual = node?.root?.value?.[targetField]
119
+ if (actual === expectedValue && (!value || value === '')) {
120
+ return `Feld ${name} ist erforderlich, wenn ${targetField} = ${expectedValue}`
121
+ }
122
+ return true
123
+ }
124
+ },
125
+ messages: {
126
+ de: {
127
+ requiredIf: 'Dieses Feld ist erforderlich.'
128
+ }
129
+ }
146
130
  })
147
131
  app.use(plugin, formkitConfig)
148
132
  },
@@ -155,8 +139,7 @@ export default {
155
139
  errorMsg: '',
156
140
  formIsFinished: false,
157
141
  msg: null,
158
- collapsed: false,
159
- firstFormFieldRef: null
142
+ collapsed: false
160
143
  }
161
144
  },
162
145
  computed: {
@@ -170,14 +153,10 @@ export default {
170
153
  return !!this.userTask
171
154
  },
172
155
  totalOutputs () {
173
- return (
174
- this.props.options.length +
175
- (this.props.handle_confirmation_dialogs ? 2 : 0) +
176
- (this.props.trigger_on_change ? 1 : 0)
177
- )
156
+ return this.props.options.length + (this.props.handle_confirmation_dialogs ? 2 : 0) + (this.props.trigger_on_change ? 1 : 0)
178
157
  },
179
158
  isConfirmDialog () {
180
- return this.userTask.userTaskConfig.formFields.some((field) => field.type === 'confirm')
159
+ return this.userTask.userTaskConfig.formFields.some(field => field.type === 'confirm')
181
160
  }
182
161
  },
183
162
  watch: {
@@ -188,20 +167,6 @@ export default {
188
167
  this.send(res, this.totalOutputs - 1)
189
168
  }
190
169
  },
191
- collapsed (newVal) {
192
- if (!newVal && this.hasUserTask) {
193
- nextTick(() => {
194
- this.focusFirstFormField()
195
- })
196
- }
197
- },
198
- userTask (newVal) {
199
- if (newVal && !this.collapsed) {
200
- nextTick(() => {
201
- this.focusFirstFormField()
202
- })
203
- }
204
- },
205
170
  deep: true
206
171
  }
207
172
  },
@@ -255,12 +220,10 @@ export default {
255
220
  const validation = customForm.validation
256
221
  const name = field.id
257
222
  const customProperties = customForm.customProperties ?? []
258
- const isReadOnly =
259
- this.props.readonly ||
260
- this.formIsFinished ||
261
- customProperties.find((entry) => ['readOnly', 'readonly'].includes(entry.name) && entry.value === 'true')
262
- ? 'true'
263
- : undefined
223
+ const isReadOnly = (
224
+ this.props.readonly || this.formIsFinished || customProperties.find(entry => ['readOnly', 'readonly'].includes(entry.name) && entry.value === 'true'))
225
+ ? 'true'
226
+ : undefined
264
227
  switch (field.type) {
265
228
  case 'long':
266
229
  return {
@@ -423,7 +386,6 @@ export default {
423
386
  }
424
387
  }
425
388
  case 'file':
426
- const multiple = field.customForm ? JSON.parse(field.customForm).multiple === 'true' : false
427
389
  return {
428
390
  type: 'FormKit',
429
391
  props: {
@@ -441,7 +403,6 @@ export default {
441
403
  // innerClass: ui-dynamic-form-input-outlines `${this.theme === 'dark' ? '$remove:formkit-inner' : ''}`,
442
404
  readonly: isReadOnly,
443
405
  disabled: isReadOnly,
444
- multiple,
445
406
  validation,
446
407
  validationVisibility: 'live'
447
408
  }
@@ -784,7 +745,7 @@ export default {
784
745
  if (field.type === 'header') {
785
746
  style += 'flex-basis: 100%;'
786
747
  } else {
787
- style += `flex-basis: ${(1 / this.props.form_columns) * 100}%;`
748
+ style += `flex-basis: ${1 / this.props.form_columns * 100}%;`
788
749
  }
789
750
  return style
790
751
  },
@@ -798,9 +759,9 @@ export default {
798
759
  return fieldMap
799
760
  },
800
761
  /*
801
- widget-action just sends a msg to Node-RED, it does not store the msg state server-side
802
- alternatively, you can use widget-change, which will also store the msg in the Node's datastore
803
- */
762
+ widget-action just sends a msg to Node-RED, it does not store the msg state server-side
763
+ alternatively, you can use widget-change, which will also store the msg in the Node's datastore
764
+ */
804
765
  send (msg, index) {
805
766
  const msgArr = []
806
767
  msgArr[index] = msg
@@ -825,7 +786,7 @@ export default {
825
786
  }
826
787
 
827
788
  const formFields = this.userTask.userTaskConfig.formFields
828
- const formFieldIds = formFields.map((ff) => ff.id)
789
+ const formFieldIds = formFields.map(ff => ff.id)
829
790
  const initialValues = this.userTask.startToken
830
791
  const finishedFormData = msg.payload.formData
831
792
  this.formIsFinished = !!msg.payload.formData
@@ -841,43 +802,32 @@ export default {
841
802
  const customForm = field.customForm ? JSON.parse(field.customForm) : {}
842
803
  const confirmText = customForm.confirmButtonText ?? 'Confirm'
843
804
  const declineText = customForm.declineButtonText ?? 'Decline'
844
- this.actions = [
845
- {
846
- alignment: 'right',
847
- primary: 'false',
848
- label: declineText,
849
- condition: ''
850
- },
851
- {
852
- alignment: 'right',
853
- primary: 'true',
854
- label: confirmText,
855
- condition: ''
856
- }
857
- ]
805
+ this.actions = [{
806
+ alignment: 'right',
807
+ primary: 'false',
808
+ label: declineText,
809
+ condition: ''
810
+ }, {
811
+ alignment: 'right',
812
+ primary: 'true',
813
+ label: confirmText,
814
+ condition: ''
815
+ }]
858
816
  }
859
817
  })
860
818
  }
861
819
 
862
820
  if (initialValues) {
863
- Object.keys(initialValues)
864
- .filter((key) => formFieldIds.includes(key))
865
- .forEach((key) => {
866
- this.formData[key] = initialValues[key]
867
- })
821
+ Object.keys(initialValues).filter(key => formFieldIds.includes(key)).forEach((key) => {
822
+ this.formData[key] = initialValues[key]
823
+ })
868
824
  }
869
825
 
870
826
  if (this.formIsFinished) {
871
- Object.keys(finishedFormData)
872
- .filter((key) => formFieldIds.includes(key))
873
- .forEach((key) => {
874
- this.formData[key] = finishedFormData[key]
875
- })
827
+ Object.keys(finishedFormData).filter(key => formFieldIds.includes(key)).forEach(key => {
828
+ this.formData[key] = finishedFormData[key]
829
+ })
876
830
  }
877
-
878
- nextTick(() => {
879
- this.focusFirstFormField()
880
- })
881
831
  },
882
832
  actionFn (action) {
883
833
  if (action.label === 'Speichern' || action.label === 'Speichern und nächster') {
@@ -907,8 +857,7 @@ export default {
907
857
  msg.payload = { formData: this.formData, userTask: this.userTask }
908
858
  this.send(
909
859
  msg,
910
- this.actions.findIndex((element) => element.label === action.label) +
911
- (this.isConfirmDialog ? this.props.options.length : 0)
860
+ this.actions.findIndex((element) => element.label === action.label) + (this.isConfirmDialog ? this.props.options.length : 0)
912
861
  )
913
862
  // TODO: mm - end
914
863
  } else {
@@ -929,31 +878,6 @@ export default {
929
878
  },
930
879
  showError (errMsg) {
931
880
  this.errorMsg = errMsg
932
- },
933
- focusFirstFormField () {
934
- if (this.collapsed || !this.hasUserTask) {
935
- return
936
- }
937
-
938
- if (this.firstFormFieldRef) {
939
- let inputElement = null
940
-
941
- if (this.firstFormFieldRef.node && this.firstFormFieldRef.node.input instanceof HTMLElement) {
942
- inputElement = this.firstFormFieldRef.node.input
943
- } else if (this.firstFormFieldRef.$el instanceof HTMLElement) {
944
- if (['INPUT', 'TEXTAREA', 'SELECT'].includes(this.firstFormFieldRef.$el.tagName)) {
945
- inputElement = this.firstFormFieldRef.$el
946
- } else {
947
- inputElement = this.firstFormFieldRef.$el.querySelector('input:not([type="hidden"]), textarea, select')
948
- }
949
- }
950
-
951
- if (inputElement) {
952
- inputElement.focus()
953
- } else {
954
- console.warn('Could not find a focusable input element for the first form field.')
955
- }
956
- }
957
881
  }
958
882
  }
959
883
  }