From be6e7ed5279edf37c1015b69e1fe98eae5ef3cc9 Mon Sep 17 00:00:00 2001 From: Roly Gutierrez Date: Fri, 11 Sep 2026 16:36:51 -0400 Subject: [PATCH 1/3] fix(FOUR-27647): prevent nested screen watchers from running in design mode Skip loading watchers when FormNestedScreen is rendered inside VueFormBuilder. Watchers with run_onload were executing during parent screen design, showing synchronous watcher messages outside runtime. Detect VueFormBuilder in the component parent chain and assign an empty watchers array on screen load in that context. Preview and request runtime behavior is unchanged. https://processmaker.atlassian.net/browse/FOUR-27647 --- src/components/renderer/form-nested-screen.vue | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/renderer/form-nested-screen.vue b/src/components/renderer/form-nested-screen.vue index 4c7ca872c..17aeceea2 100644 --- a/src/components/renderer/form-nested-screen.vue +++ b/src/components/renderer/form-nested-screen.vue @@ -72,6 +72,16 @@ export default { }, }, methods: { + isInScreenBuilder() { + let parent = this.$parent; + while (parent) { + if (parent.$options._componentTag === 'VueFormBuilder') { + return true; + } + parent = parent.$parent; + } + return false; + }, isSubmitButton(item) { return item.config && item.component === 'FormButton' && item.config.event === 'submit'; }, @@ -130,7 +140,7 @@ export default { this.hideSubmitButtons(this.config); this.computed = response.data.computed; this.customCSS = response.data.custom_css; - this.watchers = response.data.watchers; + this.watchers = this.isInScreenBuilder() ? [] : (response.data.watchers || []); this.screenTitle = response.data.title; if (this.$attrs['disabled']) { From 1a7b153d97fe88d12633fbe583307e0ae1e261c5 Mon Sep 17 00:00:00 2001 From: Roly Gutierrez Date: Tue, 22 Sep 2026 01:12:29 -0400 Subject: [PATCH 2/3] fix(FOUR-27647): prevent nested screen watchers from running in design mode Correct VueFormBuilder detection in FormNestedScreen.isInScreenBuilder(). The previous check only matched _componentTag === 'VueFormBuilder', but PM4 renders the builder as , so watchers were still loaded and run_onload scripts executed during parent screen design. - Match vue-form-builder, VueFormBuilder tag, and VueFormBuilder name in the parent chain - Set name: 'VueFormBuilder' on vue-form-builder for reliable detection - Add unit tests for design, preview, deep nesting, and loadScreen behavior https://processmaker.atlassian.net/browse/FOUR-27647 --- .../renderer/form-nested-screen.vue | 3 +- src/components/vue-form-builder.vue | 1 + tests/unit/FormNestedScreen.spec.js | 173 ++++++++++++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 tests/unit/FormNestedScreen.spec.js diff --git a/src/components/renderer/form-nested-screen.vue b/src/components/renderer/form-nested-screen.vue index 17aeceea2..aed6e4735 100644 --- a/src/components/renderer/form-nested-screen.vue +++ b/src/components/renderer/form-nested-screen.vue @@ -75,7 +75,8 @@ export default { isInScreenBuilder() { let parent = this.$parent; while (parent) { - if (parent.$options._componentTag === 'VueFormBuilder') { + const { _componentTag: tag, name } = parent.$options; + if (tag === 'vue-form-builder' || tag === 'VueFormBuilder' || name === 'VueFormBuilder') { return true; } parent = parent.$parent; diff --git a/src/components/vue-form-builder.vue b/src/components/vue-form-builder.vue index 1f616fb13..b959d8cae 100644 --- a/src/components/vue-form-builder.vue +++ b/src/components/vue-form-builder.vue @@ -615,6 +615,7 @@ const defaultGroupOrder = { const DEFAULT_GROUP = "Advanced"; export default { + name: 'VueFormBuilder', components: { TabsBar, draggable, diff --git a/tests/unit/FormNestedScreen.spec.js b/tests/unit/FormNestedScreen.spec.js new file mode 100644 index 000000000..cab3a9fbd --- /dev/null +++ b/tests/unit/FormNestedScreen.spec.js @@ -0,0 +1,173 @@ +const fs = require('fs'); +const path = require('path'); +const vm = require('vm'); + +const componentPath = path.join( + process.cwd(), + 'src/components/renderer/form-nested-screen.vue', +); + +const source = fs.readFileSync(componentPath, 'utf8'); + +function getComponentOptions() { + const scriptMatch = source.match(/