4949 cursor : grab ;
5050 display : flex ;
5151 align-items : center ;
52+ justify-content : space-between ;
5253 margin-bottom : 5px ;
5354 "
5455 >
55- <v-icon left >mdi-drag-horizontal</v-icon >
56- {{ index + 1 }}. {{ module.id || module.module_id }}
56+ <div style =" display : flex ; align-items : center ;" >
57+ <v-icon left >mdi-drag-horizontal</v-icon >
58+ {{ index + 1 }}. {{ module.id || module.module_id }}
59+ </div >
60+ <div style =" display : flex ; gap : 10px ;" >
61+ <v-btn
62+ small
63+ color =" primary"
64+ @click =" openOptionsDialog(module, index)"
65+ >
66+ Edit Options
67+ </v-btn >
68+ <v-btn
69+ small
70+ color =" red"
71+ @click =" removeModuleFromList(index)"
72+ >
73+ Delete
74+ </v-btn >
75+ </div >
5776 </div >
58- <v-btn small color =" primary" @click =" openOptionsDialog(module)" >
59- Edit Options
60- </v-btn >
61- <v-btn
62- small
63- color =" red"
64- style =" margin-left : 20px "
65- @click =" removeModuleFromList(index)"
66- >
67- Delete
68- </v-btn >
6977 </v-card >
7078 </div >
7179 </draggable >
8694 </v-row >
8795
8896 <!-- Options Dialog -->
89- <v-dialog v-model =" showDialog" max-width =" 600px " >
90- <v-card >
97+ <v-dialog v-model =" showDialog" max-width =" 900px " >
98+ <v-card class = " autorun-options-card " >
9199 <v-card-title >
92100 <span class =" headline" >Options</span >
93101 </v-card-title >
94102
95103 <v-card-text >
96- <v-form ref =" optionsForm" >
97- <v-row >
98- <v-col
99- v-for =" field in filteredOptions"
100- :key =" field.name"
101- cols =" 12"
102- >
103- <dynamic-form-input
104- v-model =" selectedModuleForEdit.options[field.name].value"
105- :suggested-values =" field.suggested_values"
106- :strict =" strictForField(field)"
107- :name =" field.name"
108- :type =" fieldType(field)"
109- />
110- <v-subheader >{{ field.description }}</v-subheader >
111- </v-col >
112- </v-row >
104+ <v-form ref =" optionsForm" @submit.prevent >
105+ <general-form
106+ v-if =" dialogOptions"
107+ :key =" dialogFormKey"
108+ ref =" generalform"
109+ v-model =" selectedModuleForm"
110+ :options =" dialogOptions"
111+ :readonly =" false"
112+ />
113113 </v-form >
114114 </v-card-text >
115115
116116 <v-card-actions >
117- <v-btn color =" blue darken-1" text @click =" showDialog = false"
118- >Cancel</v-btn
119- >
120- <v-btn color =" blue darken-1" text @click =" saveOptions" >Save</v-btn >
117+ <v-spacer />
118+ <v-btn color =" blue darken-1" text @click =" showDialog = false" >
119+ Cancel
120+ </v-btn >
121+ <v-btn color =" orange darken-1" dark @click =" saveOptions" >
122+ Save
123+ </v-btn >
121124 </v-card-actions >
122125 </v-card >
123126 </v-dialog >
127130<script >
128131import draggable from " vuedraggable" ;
129132import { useModuleStore } from " @/stores/module-module" ;
130- import DynamicFormInput from " @/components/DynamicFormInput .vue" ;
133+ import GeneralForm from " @/components/GeneralForm .vue" ;
131134import { getAutorunTasks , saveAutorunTasks } from " @/api/listener-api" ; // Import the correct API methods
132135
133136export default {
134137 name: " AutoRunModules" ,
135- components: { draggable, DynamicFormInput },
138+ components: { draggable, GeneralForm },
136139 props: {
137140 selectedListener: {
138141 type: Object ,
@@ -147,6 +150,10 @@ export default {
147150 showDialog: false , // Show/Hide options dialog
148151 selectedModuleForEdit: null , // Module selected for editing options
149152 searchText: " " , // Track search input for autocomplete
153+ selectedModuleForm: {},
154+ dialogOptions: null ,
155+ dialogFormKey: 0 ,
156+ editingModuleIndex: - 1 ,
150157 };
151158 },
152159 computed: {
@@ -168,15 +175,6 @@ export default {
168175 name: ` ${ module .id } ` ,
169176 }));
170177 },
171- filteredOptions () {
172- if (! this .selectedModuleForEdit ) return [];
173- return Object .keys (this .selectedModuleForEdit .options )
174- .map ((key ) => ({
175- name: key,
176- ... this .selectedModuleForEdit .options [key],
177- }))
178- .filter ((field ) => field .name .toLowerCase () !== " agent" );
179- },
180178 },
181179 watch: {
182180 selectedListener: {
@@ -253,6 +251,26 @@ export default {
253251 }
254252 },
255253 async saveAutorunTasks () {
254+ const modulesWithMissing = this .moduleList
255+ .map ((module ) => ({
256+ module ,
257+ missing: this .getMissingRequiredOptions (module ),
258+ }))
259+ .filter ((item ) => item .missing .length > 0 );
260+
261+ if (modulesWithMissing .length > 0 ) {
262+ const details = modulesWithMissing
263+ .map (
264+ ({ module , missing }) =>
265+ ` ${ module .id || module .module_id } : ${ missing .join (" , " )} ` ,
266+ )
267+ .join (" | " );
268+ this .$snack .error (
269+ ` Missing required options for autorun modules → ${ details} ` ,
270+ );
271+ return ;
272+ }
273+
256274 // Always send the cleaned modules to the API, even if the list is empty
257275 const cleanedModules = this .moduleList .map ((module ) => {
258276 // Extract only the key-value pairs from the options object
@@ -281,39 +299,78 @@ export default {
281299 console .error (" Failed to save autorun modules" , error);
282300 }
283301 },
284- openOptionsDialog (module ) {
285- this .selectedModuleForEdit = {
286- ... module,
287- options: { ... module .options },
288- };
302+ openOptionsDialog (module , index ) {
303+ this .selectedModuleForEdit = { ... module };
304+ this .editingModuleIndex = index;
305+ this .dialogOptions = this .cloneModuleOptions (module .options || {});
306+ this .dialogFormKey += 1 ;
307+ this .selectedModuleForm = {};
289308 this .showDialog = true ;
290309 },
291310 saveOptions () {
292- const index = this .moduleList .findIndex (
293- (mod ) => mod .id === this .selectedModuleForEdit .id ,
294- );
295- if (index !== - 1 ) {
296- this .$set (this .moduleList , index, this .selectedModuleForEdit );
311+ if (this .editingModuleIndex === - 1 ) {
312+ this .showDialog = false ;
313+ return ;
314+ }
315+
316+ const isValid = this .$refs .generalform ? .$refs .form .validate ? .();
317+ if (isValid === false ) {
318+ return ;
297319 }
320+
321+ const updatedModule = {
322+ ... this .moduleList [this .editingModuleIndex ],
323+ options: this .applyFormValuesToOptions (
324+ this .moduleList [this .editingModuleIndex ].options || {},
325+ this .selectedModuleForm ,
326+ ),
327+ };
328+
329+ this .$set (this .moduleList , this .editingModuleIndex , updatedModule);
298330 this .showDialog = false ;
331+ this .editingModuleIndex = - 1 ;
332+ this .dialogOptions = null ;
333+ },
334+ cloneModuleOptions (options ) {
335+ const cloned = JSON .parse (JSON .stringify (options || {}));
336+ if (cloned .Agent ) {
337+ delete cloned .Agent ;
338+ }
339+ return cloned;
340+ },
341+ applyFormValuesToOptions (options , formValues ) {
342+ const updatedOptions = JSON .parse (JSON .stringify (options));
343+ Object .keys (updatedOptions).forEach ((key ) => {
344+ if (key === " Agent" ) return ;
345+ if (formValues[key] !== undefined ) {
346+ updatedOptions[key].value = formValues[key];
347+ }
348+ });
349+ return updatedOptions;
299350 },
300351 removeModuleFromList (index ) {
301352 // Remove the module at the given index
302353 this .moduleList .splice (index, 1 );
303354 },
304- fieldType (field ) {
305- return (
306- {
307- INTEGER : " number" ,
308- FLOAT : " float" ,
309- BOOLEAN : " boolean" ,
310- STRING : " string" ,
311- FILE : " file" ,
312- }[field .value_type ] || " string"
313- );
314- },
315- strictForField (field ) {
316- return field .strict || false ;
355+ getMissingRequiredOptions (module ) {
356+ if (! module || ! module .options ) return [];
357+
358+ return Object .entries (module .options )
359+ .filter (
360+ ([key , option ]) => option .required === true && key .toLowerCase () !== " agent" ,
361+ )
362+ .reduce ((missing , [key , option ]) => {
363+ const value = option .value ;
364+ const isEmptyString = typeof value === " string" && value .trim () === " " ;
365+ const isEmptyArray = Array .isArray (value) && value .length === 0 ;
366+ const isUnset = value === null || value === undefined ;
367+
368+ if (isUnset || isEmptyString || isEmptyArray) {
369+ missing .push (key);
370+ }
371+
372+ return missing;
373+ }, []);
317374 },
318375 },
319376};
@@ -336,4 +393,8 @@ export default {
336393.v - icon {
337394 margin- right: 10px ; /* Add some spacing to the icon */
338395}
396+
397+ .autorun - options- card {
398+ padding: 20px ;
399+ }
339400< / style>
0 commit comments