@processmaker/screen-builder 3.8.15 → 3.8.16

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;
@@ -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";