@processmaker/screen-builder 3.8.15 → 3.8.17

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.
@@ -41,7 +41,8 @@ export default {
41
41
  "loading",
42
42
  "loadingLabel",
43
43
  "handler",
44
- "handlerSecurityEnabled"
44
+ "handlerSecurityEnabled",
45
+ "config"
45
46
  ],
46
47
  data() {
47
48
  return {
@@ -86,7 +87,8 @@ export default {
86
87
  return {
87
88
  name: this.name,
88
89
  label: this.label,
89
- value: this.fieldValue
90
+ value: this.fieldValue,
91
+ variablesToSubmit: this.config?.variablesToSubmit
90
92
  };
91
93
  }
92
94
  },
@@ -586,7 +586,9 @@ export default {
586
586
  }
587
587
  this.disabled = true;
588
588
 
589
- if (formData) {
589
+ // Ensure formData is always a valid object (never null, undefined, or false)
590
+ const safeFormData = (formData && typeof formData === 'object') ? formData : (this.requestData || {});
591
+ if (formData && typeof formData === 'object') {
590
592
  this.onUpdate(Object.assign({}, this.requestData, formData));
591
593
  }
592
594
 
@@ -595,7 +597,7 @@ export default {
595
597
  } else {
596
598
  this.loadingButton = false;
597
599
  }
598
- this.$emit('submit', this.task, loading, buttonInfo);
600
+ this.$emit('submit', this.task, safeFormData, loading, buttonInfo);
599
601
 
600
602
  if (this.task?.allow_interstitial && !this.loadingButton && !this.disableInterstitial) {
601
603
  this.task.interstitial_screen['_interstitial'] = true;
@@ -690,7 +692,7 @@ export default {
690
692
  return null;
691
693
  }
692
694
  },
693
-
695
+
694
696
  /**
695
697
  * Handles redirection upon process completion, considering destination type and user task validation.
696
698
  * @async
@@ -829,20 +831,7 @@ export default {
829
831
  * @param {Object} data - The event data received from the socket listener.
830
832
  */
831
833
  handleProcessUpdate(data) {
832
- const { event, elementDestination, tokenId } = data;
833
-
834
- // If the activity is completed and there is an element destination, set the element destination to the task
835
- if (
836
- event === "ACTIVITY_COMPLETED" &&
837
- this.task.id === tokenId &&
838
- elementDestination
839
- ) {
840
- this.task.elementDestination = elementDestination;
841
- // update allow_interstitial based on the element destination change after the submit
842
- this.task.allow_interstitial = elementDestination.type === "displayNextAssignedTask";
843
- }
844
-
845
- if (event === 'ACTIVITY_EXCEPTION') {
834
+ if (data.event === 'ACTIVITY_EXCEPTION') {
846
835
  this.$emit('error', this.requestId);
847
836
  window.location.href = `/requests/${this.requestId}`;
848
837
  }
@@ -38,12 +38,13 @@ import { getItemsFromConfig } from "../itemProcessingUtils";
38
38
  import { ValidatorFactory } from "../factories/ValidatorFactory";
39
39
  import CurrentPageProperty from "../mixins/CurrentPageProperty";
40
40
  import DeviceDetector, { MAX_MOBILE_WIDTH } from "../mixins/DeviceDetector";
41
+ import VariablesToSubmitFilter from "../mixins/VariablesToSubmitFilter";
41
42
  import ScreenRenderer from "@/components/screen-renderer.vue";
42
43
 
43
44
  export default {
44
45
  name: "VueFormRenderer",
45
46
  components: { ScreenRenderer, CustomCssOutput },
46
- mixins: [CurrentPageProperty, DeviceDetector],
47
+ mixins: [CurrentPageProperty, DeviceDetector, VariablesToSubmitFilter],
47
48
  model: {
48
49
  prop: "data",
49
50
  event: "update"
@@ -257,7 +258,8 @@ export default {
257
258
  this.$emit('after-submit', ...arguments);
258
259
  },
259
260
  submit(eventData, loading = false, buttonInfo = null) {
260
- this.$emit("submit", this.data, loading, buttonInfo);
261
+ // eventData is already filtered by ScreenBase.submitForm, just pass it through
262
+ this.$emit("submit", eventData, loading, buttonInfo);
261
263
  },
262
264
  parseCss() {
263
265
  const containerSelector = `.${this.containerClass}`;
@@ -800,6 +800,14 @@ export default [
800
800
  },
801
801
  },
802
802
  buttonVariantStyleProperty,
803
+ {
804
+ type: 'VariablesToSubmit',
805
+ field: 'variablesToSubmit',
806
+ config: {
807
+ label: 'Variables to Submit',
808
+ helper: 'Select which variables should be included in the submission payload. Only variables from the parent (top-level) request can be used.',
809
+ },
810
+ },
803
811
  ],
804
812
  },
805
813
  },
@@ -57,7 +57,8 @@ export default {
57
57
  if (buttonInfo && this.loopContext) {
58
58
  buttonInfo.loopContext = this.loopContext;
59
59
  }
60
- this.$emit('submit', this.value, loading, buttonInfo);
60
+ // Use eventData (already filtered) instead of this.value (unfiltered)
61
+ this.$emit('submit', eventData, loading, buttonInfo);
61
62
  },
62
63
  buildComponent(definition) {
63
64
  if (window.ProcessMaker && window.ProcessMaker.EventBus) {
@@ -4,6 +4,7 @@ import { mapActions, mapGetters, mapState } from 'vuex';
4
4
  import { ValidationMsg } from './ValidationRules';
5
5
  import DataReference from "./DataReference";
6
6
  import computedFields from "./computedFields";
7
+ import VariablesToSubmitFilter from "./VariablesToSubmitFilter";
7
8
  import { findRootScreen } from "./DataReference";
8
9
 
9
10
  const stringFormats = ['string', 'datetime', 'date', 'password'];
@@ -11,7 +12,7 @@ const parentReference = [];
11
12
 
12
13
  export default {
13
14
  name: "ScreenContent",
14
- mixins: [DataReference, computedFields],
15
+ mixins: [DataReference, computedFields, VariablesToSubmitFilter],
15
16
  schema: [
16
17
  function() {
17
18
  if (window.ProcessMaker && window.ProcessMaker.packages && window.ProcessMaker.packages.includes('package-vocabularies')) {
@@ -158,7 +159,19 @@ export default {
158
159
  };
159
160
  this.$emit('after-submit', event, ...arguments);
160
161
  if (event.validation === false) {
161
- this.$emit('submit', this.vdata, loading, buttonInfo);
162
+ // Filter data based on variablesToSubmit configuration (LAYER 1 protection)
163
+ const dataToSubmit = this.filterDataForSubmission(this.vdata, buttonInfo);
164
+
165
+ // Debug logging for variables filtering
166
+ if (buttonInfo?.variablesToSubmit?.length > 0) {
167
+ console.log('[VariablesToSubmit] Filtering enabled (validation bypassed)');
168
+ console.log('[VariablesToSubmit] Original data keys:', Object.keys(this.vdata || {}));
169
+ console.log('[VariablesToSubmit] Selected variables:', buttonInfo.variablesToSubmit);
170
+ console.log('[VariablesToSubmit] Filtered data keys:', Object.keys(dataToSubmit));
171
+ console.log('[VariablesToSubmit] Data to submit:', dataToSubmit);
172
+ }
173
+
174
+ this.$emit('submit', dataToSubmit, loading, buttonInfo);
162
175
  return;
163
176
  }
164
177
  await this.validateNow(findRootScreen(this));
@@ -170,7 +183,19 @@ export default {
170
183
  // if the form is not valid the data is not emitted
171
184
  return;
172
185
  }
173
- this.$emit('submit', this.vdata, loading, buttonInfo);;
186
+ // Filter data based on variablesToSubmit configuration (LAYER 1 protection)
187
+ const dataToSubmit = this.filterDataForSubmission(this.vdata, buttonInfo);
188
+
189
+ // Debug logging for variables filtering
190
+ if (buttonInfo?.variablesToSubmit?.length > 0) {
191
+ console.log('[VariablesToSubmit] Filtering enabled');
192
+ console.log('[VariablesToSubmit] Original data keys:', Object.keys(this.vdata || {}));
193
+ console.log('[VariablesToSubmit] Selected variables:', buttonInfo.variablesToSubmit);
194
+ console.log('[VariablesToSubmit] Filtered data keys:', Object.keys(dataToSubmit));
195
+ console.log('[VariablesToSubmit] Data to submit:', dataToSubmit);
196
+ }
197
+
198
+ this.$emit('submit', dataToSubmit, loading, buttonInfo);
174
199
  },
175
200
  resetValue(safeDotName, variableName) {
176
201
  this.setValue(safeDotName, null);
@@ -0,0 +1,76 @@
1
+ /**
2
+ * VariablesToSubmitFilter Mixin
3
+ *
4
+ * Filters form data before submission based on button configuration.
5
+ * Protects against invalid data (null/undefined/false) and preserves system variables.
6
+ */
7
+
8
+ export default {
9
+ methods: {
10
+ /**
11
+ * Filters data for submission based on variablesToSubmit configuration
12
+ * @param {Object} data - Form data to filter
13
+ * @param {Object} buttonInfo - Button configuration with optional variablesToSubmit array
14
+ * @returns {Object} Filtered data (always returns a valid object)
15
+ */
16
+ filterDataForSubmission(data, buttonInfo) {
17
+ // Normalize invalid data to empty object
18
+ const safeData = this.isValidObject(data) ? data : {};
19
+
20
+ // No filtering: return all data (backward compatibility)
21
+ if (!this.shouldFilterVariables(buttonInfo)) {
22
+ return safeData;
23
+ }
24
+
25
+ // Apply filtering
26
+ const variablesToSubmit = buttonInfo.variablesToSubmit;
27
+ const filteredData = {};
28
+
29
+ // Add requested variables
30
+ variablesToSubmit.forEach(variableName => {
31
+ if (variableName in safeData) {
32
+ filteredData[variableName] = safeData[variableName];
33
+ }
34
+ });
35
+
36
+ // Always preserve system variables (starting with _)
37
+ Object.keys(safeData).forEach(key => {
38
+ if (key.startsWith('_')) {
39
+ filteredData[key] = safeData[key];
40
+ }
41
+ });
42
+
43
+ return filteredData;
44
+ },
45
+
46
+ /**
47
+ * Checks if data is a valid plain object
48
+ * @param {*} data - Data to validate
49
+ * @returns {boolean} True if valid object, false otherwise
50
+ */
51
+ isValidObject(data) {
52
+ return (
53
+ data !== null &&
54
+ data !== undefined &&
55
+ data !== false &&
56
+ typeof data === 'object' &&
57
+ !Array.isArray(data)
58
+ );
59
+ },
60
+
61
+ /**
62
+ * Checks if filtering should be applied
63
+ * @param {Object} buttonInfo - Button configuration
64
+ * @returns {boolean} True if filtering enabled, false otherwise
65
+ */
66
+ shouldFilterVariables(buttonInfo) {
67
+ return (
68
+ buttonInfo &&
69
+ buttonInfo.variablesToSubmit &&
70
+ Array.isArray(buttonInfo.variablesToSubmit) &&
71
+ buttonInfo.variablesToSubmit.length > 0
72
+ );
73
+ }
74
+ }
75
+ };
76
+
@@ -16,6 +16,7 @@ export { default as ScreenBase } from "./ScreenBase";
16
16
  export { default as shouldElementBeVisible } from "./shouldElementBeVisible";
17
17
  export { default as testing } from "./testing";
18
18
  export { ValidationMsg, validators } from "./ValidationRules";
19
+ export { default as VariablesToSubmitFilter } from "./VariablesToSubmitFilter";
19
20
  export { default as VisibilityRule } from "./VisibilityRule";
20
21
  export { default as watchers } from "./watchers";
21
22
  export { default as Clipboard } from "./Clipboard";