Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c3fc023
feat: add multi-enum support for survey variables
Arielgordon123 Feb 19, 2025
7f28134
fix: fix multi enum type
blackb1rd Feb 19, 2025
fbc2d03
fix: update survey variable types from 'multi_enum' to 'select' in Te…
blackb1rd Oct 7, 2025
4f7625c
feat: enhance select type handling in SurveyVars component with defau…
blackb1rd Oct 7, 2025
7bd6424
fix: normalize default value handling in onTypeChange method for sele…
blackb1rd Oct 7, 2025
d4685be
fix: improve default value normalization for select type in SurveyVar…
blackb1rd Oct 7, 2025
3022928
feat: implement SurveyVarDefaultValue for flexible JSON handling in S…
blackb1rd Oct 7, 2025
8d72ee5
feat: enhance handling of select type variables in TaskParamsForm for…
blackb1rd Oct 10, 2025
44f3e8e
fix: ensure proper handling of select type variables in TaskParamsFor…
blackb1rd Oct 10, 2025
7a6757d
Update web/src/components/TaskParamsForm.vue
blackb1rd Oct 11, 2025
456466d
Update web/src/components/TaskForm.vue
blackb1rd Oct 11, 2025
273397b
Update web/src/components/TaskParamsForm.vue
blackb1rd Oct 11, 2025
451a724
Update web/src/components/TaskForm.vue
blackb1rd Oct 11, 2025
1728366
fix: improve validation rules and refactor removeSelectedItem method …
blackb1rd Oct 11, 2025
493be20
fix: improve readability of warning message in removeSelectedItem method
blackb1rd Oct 11, 2025
0e3baf2
fix: refactor validation rules and improve default variable handling …
blackb1rd Oct 14, 2025
e886d6f
fix: streamline axios calls in afterLoadData method for improved read…
blackb1rd Oct 14, 2025
ff2bf5b
fix: update SurveyVarStr type to 'str' for consistency and improve ha…
blackb1rd Oct 14, 2025
a20b687
fix: update SurveyVarType constants and improve default variable matc…
blackb1rd Oct 14, 2025
07a5e4a
fix: update SurveyVarStr type to empty string for consistency
blackb1rd Oct 14, 2025
05919c8
fix: improve default variable handling in TaskParamsForm.vue by filte…
blackb1rd Oct 14, 2025
bd8037e
fix: update SurveyVarStr type to "str" for consistency and adjust Sur…
blackb1rd Oct 14, 2025
8850c2f
fix: adjust selection template condition for v-select in TaskParamsFo…
blackb1rd Oct 14, 2025
b9e542d
fix: update environment handling to ensure reactivity and prevent nul…
blackb1rd Oct 14, 2025
01af6f6
fix: update editedEnvironment and editedSecretEnvironment initializat…
blackb1rd Oct 14, 2025
9e11916
fix: simplify reactive updates for editedEnvironment and editedSecret…
blackb1rd Oct 14, 2025
8a657a7
fix: refactor selection template for v-select in TaskForm.vue
blackb1rd Oct 14, 2025
0e0947d
Update web/src/components/TaskParamsForm.vue
blackb1rd Oct 14, 2025
b6619eb
fix: update v-select template to display item name correctly
blackb1rd Oct 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 64 additions & 10 deletions db/Template.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package db

import (
"bytes"
"encoding/json"
"fmt"
)

type TemplateType string
Expand Down Expand Up @@ -59,11 +61,63 @@ func (t TemplateApp) IsTerraform() bool {
type SurveyVarType string

const (
SurveyVarStr TemplateType = ""
SurveyVarInt TemplateType = "int"
SurveyVarEnum TemplateType = "enum"
SurveyVarStr SurveyVarType = "str"
SurveyVarInt SurveyVarType = "int"
SurveyVarEnum SurveyVarType = "enum"
SurveyVarSelect SurveyVarType = "select"
)

// SurveyVarDefaultValue supports both a single string or an array of strings in JSON.
// It preserves whether the original JSON was an array so encoding will keep the
// original shape when possible (single value -> string, multiple -> array).
type SurveyVarDefaultValue struct {
Values []string `json:"-"`
originalWasArray bool `json:"-"`
}

func (d *SurveyVarDefaultValue) UnmarshalJSON(b []byte) error {
if len(bytes.TrimSpace(b)) == 0 || bytes.Equal(bytes.TrimSpace(b), []byte("null")) {
d.Values = nil
d.originalWasArray = false
return nil
}

// try string
var s string
if err := json.Unmarshal(b, &s); err == nil {
d.Values = []string{s}
d.originalWasArray = false
return nil
}

// try []string
var arr []string
if err := json.Unmarshal(b, &arr); err == nil {
d.Values = arr
d.originalWasArray = true
return nil
}

return fmt.Errorf("invalid default_value: must be string or []string")
}

func (d SurveyVarDefaultValue) MarshalJSON() ([]byte, error) {
if d.Values == nil {
return []byte("null"), nil
}
if len(d.Values) == 1 && !d.originalWasArray {
return json.Marshal(d.Values[0])
}
return json.Marshal(d.Values)
}

func (d SurveyVarDefaultValue) String() string {
if len(d.Values) == 0 {
return ""
}
return d.Values[0]
}

type AnsibleTemplateParams struct {
AllowDebug bool `json:"allow_debug"`
AllowOverrideInventory bool `json:"allow_override_inventory"`
Expand All @@ -89,13 +143,13 @@ type SurveyVarEnumValue struct {
}

type SurveyVar struct {
Name string `json:"name" backup:"name"`
Title string `json:"title" backup:"title"`
Required bool `json:"required,omitempty" backup:"required"`
Type SurveyVarType `json:"type,omitempty" backup:"type"`
Description string `json:"description,omitempty" backup:"description"`
Values []SurveyVarEnumValue `json:"values,omitempty" backup:"values"`
DefaultValue string `json:"default_value,omitempty" backup:"default_value"`
Name string `json:"name" backup:"name"`
Title string `json:"title" backup:"title"`
Required bool `json:"required,omitempty" backup:"required"`
Type SurveyVarType `json:"type,omitempty" backup:"type"`
Description string `json:"description,omitempty" backup:"description"`
Values []SurveyVarEnumValue `json:"values,omitempty" backup:"values"`
DefaultValue *SurveyVarDefaultValue `json:"default_value,omitempty" backup:"default_value"`
}

type TemplateFilter struct {
Expand Down
86 changes: 81 additions & 5 deletions web/src/components/SurveyVars.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
></v-select>

<v-data-table
v-if="editedVar.type === 'enum'"
v-if="editedVar.type === 'enum' || editedVar.type === 'select'"
:items="editedValues"
:items-per-page="-1"
class="elevation-1 FieldTable"
Expand Down Expand Up @@ -93,20 +93,34 @@
<div class="text-right mt-2">
<v-btn
color="primary"
v-if="editedVar.type === 'enum'"
class="d-block"
v-if="editedVar.type === 'enum' || editedVar.type === 'select'"
@click="addEditedVarValue()"
>Add Value</v-btn>
</div>

<v-select
v-if="editedVar.type === 'enum'"
v-if="editedVar.type === 'enum' || editedVar.type === 'select'"
v-model="editedVar.default_value"
:label="$t('default_value')"
:items="editedValues"
item-value="value"
item-text="name"
clearable
></v-select>
:multiple="editedVar.type === 'select'"
:chips="editedVar.type === 'select'"
>
<template
v-slot:selection="{ item, index }"
v-if="editedVar.type === 'select'">
<v-chip
small
close
@click:close="removeDefaultItem(index)"
>{{ selectedItemLabel(item) }}
</v-chip>
</template>
</v-select>

<v-text-field
type="number"
Expand Down Expand Up @@ -206,6 +220,9 @@ export default {
}, {
id: 'enum',
name: 'Enum',
}, {
id: 'select',
name: 'Select',
}],
formError: null,
};
Expand All @@ -232,6 +249,20 @@ export default {
this.editedValues.push(...(this.editedVar.values || []));
this.editedVar.values = this.editedValues;

// normalize default_value for select vs enum
if (this.editedVar.type === 'select') {
if (this.editedVar.default_value == null) {
this.editedVar.default_value = [];
} else if (!Array.isArray(this.editedVar.default_value)) {
const dv = this.editedVar.default_value;
this.editedVar.default_value = dv === '' ? [] : [dv];
}
} else if (Array.isArray(this.editedVar.default_value)) {
this.editedVar.default_value = this.editedVar.default_value.length > 0
? this.editedVar.default_value[0]
: '';
}

this.editedVarIndex = index;

if (this.$refs.form) {
Expand All @@ -248,7 +279,7 @@ export default {
return;
}

if (this.editedVar.type === 'enum') {
if (this.editedVar.type === 'enum' || this.editedVar.type === 'select') {
if (this.editedValues.length === 0) {
this.formError = 'Enumeration must have values.';
return;
Expand All @@ -274,6 +305,18 @@ export default {
this.editedVar.values = [];
}

// normalize default_value before saving: select keeps array, others use string
if (this.editedVar.type === 'select') {
if (!Array.isArray(this.editedVar.default_value)) {
const dv = this.editedVar.default_value;
this.editedVar.default_value = dv == null || dv === '' ? [] : [dv];
}
} else if (Array.isArray(this.editedVar.default_value)) {
this.editedVar.default_value = this.editedVar.default_value.length > 0
? this.editedVar.default_value[0]
: '';
}

if (this.editedVarIndex != null) {
this.modifiedVars[this.editedVarIndex] = this.editedVar;
} else {
Expand All @@ -289,6 +332,39 @@ export default {
this.modifiedVars.splice(index, 1);
this.$emit('change', this.modifiedVars);
},

// remove one selected default item (for multiple select)
removeDefaultItem(index) {
if (!this.editedVar || !Array.isArray(this.editedVar.default_value)) {
return;
}

if (index >= 0 && index < this.editedVar.default_value.length) {
this.editedVar.default_value.splice(index, 1);
}
},

// label shown in selection chips - item could be the value or an object
selectedItemLabel(item) {
if (!item) return '';
if (typeof item === 'object' && item.name) return item.name;
const found = this.editedValues.find((v) => v.value === item || v.name === item);
return (found && found.name) || String(item);
},

onTypeChange(newType) {
if (!this.editedVar) return;
if (newType === 'select') {
if (!Array.isArray(this.editedVar.default_value)) {
const dv = this.editedVar.default_value;
this.editedVar.default_value = dv == null || dv === '' ? [] : [dv];
}
} else if (Array.isArray(this.editedVar.default_value)) {
this.editedVar.default_value = this.editedVar.default_value.length > 0
? this.editedVar.default_value[0]
: '';
}
},
},
};
</script>
22 changes: 20 additions & 2 deletions web/src/components/TaskForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@

<v-select
clearable
v-else-if="v.type === 'enum'"
v-else-if="v.type === 'enum' || v.type === 'select'"
:label="v.title + (v.required ? ' *' : '')"
:hint="v.description"
v-model="editedEnvironment[v.name]"
Expand All @@ -93,7 +93,19 @@
item-value="value"
outlined
dense
/>
:multiple="v.type === 'select'"
:chips="v.type === 'select'"
>
<template v-if="v.type === 'select'" v-slot:selection="{ item, index }">
<v-chip
small
close
@click:close="deleteItem(v.name, index)"
>
{{ item.name }}
</v-chip>
</template>
</v-select>

<v-text-field
v-else
Expand Down Expand Up @@ -289,6 +301,12 @@ export default {
this.item.arguments = JSON.stringify(args || []);
},

deleteItem(name, index) {
if (Array.isArray(this.editedEnvironment?.[name])) {
this.editedEnvironment[name].splice(index, 1);
}
},

getTaskMessage(task) {
let buildTask = task;

Expand Down
Loading
Loading