Skip to content

Commit 16c2347

Browse files
authored
Fix the AutoRun module options and require mandatory parameters.
1 parent 38fe21c commit 16c2347

File tree

1 file changed

+131
-70
lines changed

1 file changed

+131
-70
lines changed

src/components/AutoRunModules.vue

Lines changed: 131 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -49,23 +49,31 @@
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>
@@ -86,38 +94,33 @@
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>
@@ -127,12 +130,12 @@
127130
<script>
128131
import draggable from "vuedraggable";
129132
import { useModuleStore } from "@/stores/module-module";
130-
import DynamicFormInput from "@/components/DynamicFormInput.vue";
133+
import GeneralForm from "@/components/GeneralForm.vue";
131134
import { getAutorunTasks, saveAutorunTasks } from "@/api/listener-api"; // Import the correct API methods
132135
133136
export 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

Comments
 (0)