@processmaker/screen-builder 3.8.16 → 3.8.18

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@processmaker/screen-builder",
3
- "version": "3.8.16",
3
+ "version": "3.8.18",
4
4
  "scripts": {
5
5
  "dev": "VITE_COVERAGE=true vite",
6
6
  "build": "vite build",
@@ -70,26 +70,6 @@ export default [
70
70
  "defaultValue",
71
71
  "showForDesktop",
72
72
  {name: "customFormatter", showFor: "FormInput"},
73
- {name: "ariaLabel", showFor: "FormInput"},
74
- {name: "ariaLabel", showFor: "FormSelectList"},
75
- {name: "ariaLabel", showFor: "FormDatePicker"},
76
- {name: "ariaLabel", showFor: "FormCheckbox"},
77
- {name: "ariaLabel", showFor: "FormDatePicker"},
78
- {name: "ariaLabel", showFor: "FileUpload"},
79
- {name: "ariaLabel", showFor: "FileDownload"},
80
- {name: "ariaLabel", showFor: "FormSelectList"},
81
- {name: "ariaLabel", showFor: "FormButton"},
82
- {name: "ariaLabel", showFor: "FormTextArea"},
83
- {name: "tabindex", showFor: "FormInput"},
84
- {name: "tabindex", showFor: "FormSelectList"},
85
- {name: "tabindex", showFor: "FormDatePicker"},
86
- {name: "tabindex", showFor: "FormCheckbox"},
87
- {name: "tabindex", showFor: "FormDatePicker"},
88
- {name: "tabindex", showFor: "FileUpload"},
89
- {name: "tabindex", showFor: "FileDownload"},
90
- {name: "tabindex", showFor: "FormSelectList"},
91
- {name: "tabindex", showFor: "FormButton"},
92
- {name: "tabindex", showFor: "FormTextArea"},
93
73
  {name: "encryptedConfig", showFor: "FormInput"},
94
74
  {name: "variablesToSubmit", showFor: "FormButton"},
95
75
  ],
@@ -43,15 +43,16 @@
43
43
 
44
44
  <!-- Select All and Search Section -->
45
45
  <div class="controls-section">
46
- <button
47
- type="button"
48
- class="select-all-button"
49
- @click="selectAll"
50
- :disabled="filteredVariables.length === 0 || selectedVariables.length === filteredVariables.length"
46
+ <b-form-checkbox
47
+ :checked="allSelected"
48
+ :indeterminate="someSelected"
49
+ @change="toggleSelectAll"
50
+ :disabled="filteredVariables.length === 0"
51
+ class="select-all-checkbox"
51
52
  data-cy="variables-to-submit-select-all"
52
53
  >
53
54
  {{ $t('Select All') }}
54
- </button>
55
+ </b-form-checkbox>
55
56
  <button
56
57
  type="button"
57
58
  class="search-button"
@@ -164,10 +165,13 @@ export default {
164
165
 
165
166
  // Extract calculated variables (computed properties)
166
167
  Object.assign(variables, this.extractCalculatedVariables());
168
+
169
+ // Extract watcher output variables
170
+ Object.assign(variables, this.extractWatcherVariables());
167
171
 
168
- // Filter: exclude _parent variables, include all others
172
+ // Filter: exclude _parent variables and invalid variable names
169
173
  return Object.keys(variables)
170
- .filter(variable => !variable.startsWith('_parent.'))
174
+ .filter(variable => this.isValidVariableName(variable))
171
175
  .sort();
172
176
  },
173
177
 
@@ -211,6 +215,22 @@ export default {
211
215
  return this.requiredVariables.filter(
212
216
  variable => !this.selectedVariables.includes(variable)
213
217
  );
218
+ },
219
+
220
+ /**
221
+ * Check if all filtered variables are selected
222
+ */
223
+ allSelected() {
224
+ return this.filteredVariables.length > 0 &&
225
+ this.filteredVariables.every(v => this.selectedVariables.includes(v));
226
+ },
227
+
228
+ /**
229
+ * Check if some (but not all) filtered variables are selected
230
+ */
231
+ someSelected() {
232
+ const selectedCount = this.filteredVariables.filter(v => this.selectedVariables.includes(v)).length;
233
+ return selectedCount > 0 && selectedCount < this.filteredVariables.length;
214
234
  }
215
235
  },
216
236
  watch: {
@@ -231,8 +251,13 @@ export default {
231
251
  this.$emit('change', []);
232
252
  }
233
253
  },
234
- isEnabled(newValue) {
235
- if (!newValue) {
254
+ isEnabled(newValue, oldValue) {
255
+ if (newValue && !oldValue) {
256
+ // When enabled for the first time, select all variables
257
+ this.selectedVariables = [...this.availableVariables];
258
+ this.$emit('input', this.selectedVariables);
259
+ this.$emit('change', this.selectedVariables);
260
+ } else if (!newValue) {
236
261
  // When disabled, clear selection to submit all variables
237
262
  this.selectedVariables = [];
238
263
  this.$emit('input', []);
@@ -250,6 +275,11 @@ export default {
250
275
  '$root.computed'() {
251
276
  // Force recomputation when computed properties change
252
277
  this.$forceUpdate();
278
+ },
279
+ // Watch for watchers changes in App.vue
280
+ '$root.watchers'() {
281
+ // Force recomputation when watchers change
282
+ this.$forceUpdate();
253
283
  }
254
284
  },
255
285
  methods: {
@@ -289,6 +319,14 @@ export default {
289
319
  this.selectedVariables = this.selectedVariables.filter(v => !filteredSet.has(v));
290
320
  },
291
321
 
322
+ toggleSelectAll(checked) {
323
+ if (checked) {
324
+ this.selectAll();
325
+ } else {
326
+ this.deselectAll();
327
+ }
328
+ },
329
+
292
330
  toggleSearch() {
293
331
  this.showSearch = !this.showSearch;
294
332
  if (!this.showSearch) {
@@ -296,6 +334,23 @@ export default {
296
334
  }
297
335
  },
298
336
 
337
+ /**
338
+ * Check if a variable name is valid
339
+ * Uses same logic as dot_notation validation rule
340
+ */
341
+ isValidVariableName(name) {
342
+ if (!name || typeof name !== 'string') {
343
+ return false;
344
+ }
345
+ if (name.startsWith('_parent.')) {
346
+ return false;
347
+ }
348
+ // Same regex as dot_notation: starts with letter, followed by letters, numbers, or underscores
349
+ const validPartRegex = /^[a-zA-Z][a-zA-Z0-9_]*$/;
350
+ const parts = name.split('.');
351
+ return parts.every(part => validPartRegex.test(part));
352
+ },
353
+
299
354
  /**
300
355
  * Extract calculated variables (computed properties) from the screen
301
356
  * Searches in multiple locations: App.vue, builder, or parent components
@@ -348,6 +403,47 @@ export default {
348
403
 
349
404
  return [];
350
405
  },
406
+
407
+ /**
408
+ * Extract watcher output variables from the screen
409
+ */
410
+ extractWatcherVariables() {
411
+ const watcherVars = {};
412
+ const watchers = this.getWatchers() || [];
413
+
414
+ watchers.forEach(watcher => {
415
+ if (watcher.byPass) return;
416
+
417
+ // Output variable (for scripts)
418
+ if (watcher.output_variable) {
419
+ watcherVars[watcher.output_variable] = null;
420
+ }
421
+
422
+ // Data mapping variables (for data sources)
423
+ try {
424
+ const config = typeof watcher.script_configuration === 'string'
425
+ ? JSON.parse(watcher.script_configuration)
426
+ : watcher.script_configuration;
427
+ (config?.dataMapping || []).forEach(m => {
428
+ if (m.key) watcherVars[m.key] = null;
429
+ });
430
+ } catch {
431
+ console.error('Invalid JSON in script_configuration for watcher:', watcher.name);
432
+ }
433
+ });
434
+
435
+ return watcherVars;
436
+ },
437
+
438
+ /**
439
+ * Get watchers from various sources
440
+ */
441
+ getWatchers() {
442
+ return this.$root?.$data?.watchers
443
+ || this.$root?.$children?.[0]?.watchers
444
+ || this.$root?.$children?.[0]?.$data?.watchers
445
+ || [];
446
+ },
351
447
 
352
448
  /**
353
449
  * Extract variables from form config
@@ -392,6 +488,23 @@ export default {
392
488
  * Single Responsibility: Only handles variable name extraction
393
489
  */
394
490
  extractVariableFromItem(item, variables) {
491
+ // Components that don't have submittable variables
492
+ const displayOnlyComponents = [
493
+ 'FormNestedScreen',
494
+ 'FormHtmlViewer',
495
+ 'FormMultiColumn',
496
+ 'FormCollectionRecordControl',
497
+ 'FormCollectionViewControl',
498
+ 'FormAvatar',
499
+ 'FormListTable',
500
+ 'FormAnalyticsChart',
501
+ 'CaseProgressBar',
502
+ 'FileDownload',
503
+ ];
504
+ // Skip display-only and container components that don't have submittable variables
505
+ if (displayOnlyComponents.includes(item.component)) {
506
+ return;
507
+ }
395
508
  const variableName = item.config?.name;
396
509
  if (variableName && !variableName.startsWith('_parent.')) {
397
510
  variables[variableName] = null;
@@ -617,25 +730,16 @@ export default {
617
730
  margin-top: 0;
618
731
  }
619
732
 
620
- .select-all-button {
621
- background: none;
622
- border: none;
623
- padding: 0;
624
- color: #0d6efd;
625
- font-size: 15px;
733
+ .select-all-checkbox {
734
+ margin: 0;
735
+ font-size: 14px;
626
736
  font-weight: 600;
627
- cursor: pointer;
628
- text-decoration: none;
629
- }
630
-
631
- .select-all-button:hover:not(:disabled) {
632
- color: #0a58ca;
633
- text-decoration: none;
737
+ color: #495057;
634
738
  }
635
739
 
636
- .select-all-button:disabled {
637
- color: #adb5bd;
638
- cursor: not-allowed;
740
+ .select-all-checkbox >>> .custom-control-label {
741
+ cursor: pointer;
742
+ user-select: none;
639
743
  }
640
744
 
641
745
  .search-button {
@@ -692,7 +692,7 @@ export default {
692
692
  return null;
693
693
  }
694
694
  },
695
-
695
+
696
696
  /**
697
697
  * Handles redirection upon process completion, considering destination type and user task validation.
698
698
  * @async
@@ -831,20 +831,7 @@ export default {
831
831
  * @param {Object} data - The event data received from the socket listener.
832
832
  */
833
833
  handleProcessUpdate(data) {
834
- const { event, elementDestination, tokenId } = data;
835
-
836
- // If the activity is completed and there is an element destination, set the element destination to the task
837
- if (
838
- event === "ACTIVITY_COMPLETED" &&
839
- this.task.id === tokenId &&
840
- elementDestination
841
- ) {
842
- this.task.elementDestination = elementDestination;
843
- // update allow_interstitial based on the element destination change after the submit
844
- this.task.allow_interstitial = elementDestination.type === "displayNextAssignedTask";
845
- }
846
-
847
- if (event === 'ACTIVITY_EXCEPTION') {
834
+ if (data.event === 'ACTIVITY_EXCEPTION') {
848
835
  this.$emit('error', this.requestId);
849
836
  window.location.href = `/requests/${this.requestId}`;
850
837
  }