4343
4444 <!-- Select All and Search Section -->
4545 <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"
5152 data-cy =" variables-to-submit-select-all"
5253 >
5354 {{ $t('Select All') }}
54- </button >
55+ </b-form-checkbox >
5556 <button
5657 type =" button"
5758 class =" search-button"
@@ -164,10 +165,13 @@ export default {
164165
165166 // Extract calculated variables (computed properties)
166167 Object .assign (variables, this .extractCalculatedVariables ());
168+
169+ // Extract watcher output variables
170+ Object .assign (variables, this .extractWatcherVariables ());
167171
168- // Filter: exclude _parent variables, include all others
172+ // Filter: exclude _parent variables and invalid variable names
169173 return Object .keys (variables)
170- .filter (variable => ! variable . startsWith ( ' _parent. ' ))
174+ .filter (variable => this . isValidVariableName (variable ))
171175 .sort ();
172176 },
173177
@@ -211,6 +215,22 @@ export default {
211215 return this .requiredVariables .filter (
212216 variable => ! this .selectedVariables .includes (variable)
213217 );
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 ;
214234 }
215235 },
216236 watch: {
@@ -231,8 +251,13 @@ export default {
231251 this .$emit (' change' , []);
232252 }
233253 },
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) {
236261 // When disabled, clear selection to submit all variables
237262 this .selectedVariables = [];
238263 this .$emit (' input' , []);
@@ -250,6 +275,11 @@ export default {
250275 ' $root.computed' () {
251276 // Force recomputation when computed properties change
252277 this .$forceUpdate ();
278+ },
279+ // Watch for watchers changes in App.vue
280+ ' $root.watchers' () {
281+ // Force recomputation when watchers change
282+ this .$forceUpdate ();
253283 }
254284 },
255285 methods: {
@@ -289,13 +319,38 @@ export default {
289319 this .selectedVariables = this .selectedVariables .filter (v => ! filteredSet .has (v));
290320 },
291321
322+ toggleSelectAll (checked ) {
323+ if (checked) {
324+ this .selectAll ();
325+ } else {
326+ this .deselectAll ();
327+ }
328+ },
329+
292330 toggleSearch () {
293331 this .showSearch = ! this .showSearch ;
294332 if (! this .showSearch ) {
295333 this .searchQuery = ' ' ;
296334 }
297335 },
298336
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+
299354 /**
300355 * Extract calculated variables (computed properties) from the screen
301356 * Searches in multiple locations: App.vue, builder, or parent components
@@ -348,6 +403,47 @@ export default {
348403
349404 return [];
350405 },
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+ },
351447
352448 /**
353449 * Extract variables from form config
@@ -634,25 +730,16 @@ export default {
634730 margin- top: 0 ;
635731}
636732
637- .select - all- button {
638- background: none;
639- border: none;
640- padding: 0 ;
641- color: #0d6efd ;
642- font- size: 15px ;
733+ .select - all- checkbox {
734+ margin: 0 ;
735+ font- size: 14px ;
643736 font- weight: 600 ;
644- cursor: pointer;
645- text- decoration: none;
646- }
647-
648- .select - all- button: hover: not (: disabled ) {
649- color: #0a58ca ;
650- text- decoration: none;
737+ color: #495057 ;
651738}
652739
653- .select - all- button : disabled {
654- color : #adb5bd ;
655- cursor : not - allowed ;
740+ .select - all- checkbox >>> . custom - control - label {
741+ cursor : pointer ;
742+ user - select : none ;
656743}
657744
658745.search - button {
0 commit comments