mirror of https://github.com/rancher/dashboard.git
Array and Map support for questions
This commit is contained in:
parent
dedff10ae5
commit
fc92149d0b
|
|
@ -0,0 +1,33 @@
|
|||
<script>
|
||||
import ArrayList from '@/components/form/ArrayList';
|
||||
import Question from './Question';
|
||||
|
||||
export default {
|
||||
components: { ArrayList },
|
||||
mixins: [Question],
|
||||
|
||||
methods: {
|
||||
update(val) {
|
||||
this.$emit('input', val);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<ArrayList
|
||||
:key="question.variable"
|
||||
v-model="value[question.variable]"
|
||||
:title="question.label"
|
||||
:mode="mode"
|
||||
:protip="false"
|
||||
@input="update"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="showDescription" class="col span-6 mt-10">
|
||||
{{ question.description }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -12,6 +12,7 @@ export default {
|
|||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<Checkbox
|
||||
:mode="mode"
|
||||
:label="displayLabel"
|
||||
:value="value"
|
||||
@input="$emit('input', $event)"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export default {
|
|||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<LabeledSelect
|
||||
:mode="mode"
|
||||
:label="displayLabel"
|
||||
:options="question.options"
|
||||
:placeholder="question.description"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
<script>
|
||||
import LabeledInput from '@/components/form/LabeledInput';
|
||||
import Question from './Question';
|
||||
|
||||
// @TODO valid_chars, invalid_chars
|
||||
|
||||
export default {
|
||||
components: { LabeledInput },
|
||||
mixins: [Question]
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<LabeledInput
|
||||
type="text"
|
||||
:mode="mode"
|
||||
:label="displayLabel"
|
||||
:placeholder="question.default"
|
||||
:required="question.required"
|
||||
:value="value"
|
||||
@input="val = parseFloat($event); if ( !isNaN(val) ) { $emit('input', val) }"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="showDescription" class="col span-6 mt-10">
|
||||
{{ question.description }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -15,6 +15,7 @@ export default {
|
|||
<div class="col span-6">
|
||||
<LabeledInput
|
||||
type="text"
|
||||
:mode="mode"
|
||||
:label="displayLabel"
|
||||
:placeholder="question.default"
|
||||
:required="question.required"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<script>
|
||||
import KeyValue from '@/components/form/KeyValue';
|
||||
import Question from './Question';
|
||||
|
||||
export default {
|
||||
components: { KeyValue },
|
||||
mixins: [Question],
|
||||
|
||||
methods: {
|
||||
update(val) {
|
||||
this.$emit('input', val);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="showDescription" class="row mt-10">
|
||||
<div class="col span-12">
|
||||
{{ question.description }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col span-12 mt-10">
|
||||
<KeyValue
|
||||
:key="question.variable"
|
||||
v-model="value[question.variable]"
|
||||
:title="question.label"
|
||||
:mode="mode"
|
||||
:protip="false"
|
||||
@input="update"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import { _EDIT } from '@/config/query-params';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
question: {
|
||||
|
|
@ -5,6 +7,11 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
|
||||
mode: {
|
||||
type: String,
|
||||
default: _EDIT,
|
||||
},
|
||||
|
||||
// targetNamespace: {
|
||||
// type: String,
|
||||
// required: true,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ export default {
|
|||
<div>
|
||||
Secret in namespace {{ targetNamespace }}
|
||||
<LabeledSelect
|
||||
:mode="mode"
|
||||
:disabled="$fetchState.pending"
|
||||
:label="displayLabel"
|
||||
:placeholder="question.description"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export default {
|
|||
<div class="row">
|
||||
<div class="col span-6">
|
||||
<LabeledInput
|
||||
:mode="mode"
|
||||
:type="inputType"
|
||||
:label="displayLabel"
|
||||
:placeholder="question.default"
|
||||
|
|
|
|||
|
|
@ -2,12 +2,17 @@
|
|||
import Jexl from 'jexl';
|
||||
import Tab from '@/components/Tabbed/Tab';
|
||||
import { get, set } from '@/utils/object';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import { _EDIT } from '@/config/query-params';
|
||||
import StringType from './String';
|
||||
import BooleanType from './Boolean';
|
||||
import EnumType from './Enum';
|
||||
import IntType from './Int';
|
||||
import FloatType from './Float';
|
||||
import ArrayType from './Array';
|
||||
import MapType from './Map';
|
||||
|
||||
const knownTypes = {
|
||||
export const knownTypes = {
|
||||
string: StringType,
|
||||
hostname: StringType, // @TODO
|
||||
multiline: StringType,
|
||||
|
|
@ -15,11 +20,40 @@ const knownTypes = {
|
|||
boolean: BooleanType,
|
||||
enum: EnumType,
|
||||
int: IntType,
|
||||
float: FloatType,
|
||||
map: MapType,
|
||||
// storageclass
|
||||
// pvc
|
||||
// secret
|
||||
};
|
||||
|
||||
export function componentForQuestion(q) {
|
||||
if ( knownTypes[q.type] ) {
|
||||
return q.type;
|
||||
} else if ( q.type.startsWith('array[') ) { // This only really works for array[string|multiline], but close enough for now.
|
||||
return ArrayType;
|
||||
} else if ( q.type.startsWith('map[') ) { // Same, only works with map[string|multiline]
|
||||
return MapType;
|
||||
}
|
||||
|
||||
return 'string';
|
||||
}
|
||||
|
||||
export function schemaToQuestions(schema) {
|
||||
const keys = Object.keys(schema.resourceFields);
|
||||
const out = [];
|
||||
|
||||
for ( const k of keys ) {
|
||||
out.push({
|
||||
variable: k,
|
||||
label: k,
|
||||
...schema.resourceFields[k],
|
||||
});
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function evalExpr(expr, values) {
|
||||
try {
|
||||
const out = Jexl.evalSync(expr, values);
|
||||
|
|
@ -120,12 +154,23 @@ export default {
|
|||
components: { Tab, ...knownTypes },
|
||||
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
default: _EDIT,
|
||||
},
|
||||
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
|
||||
chartVersion: {
|
||||
tabbed: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
|
||||
// Can be a chartVersion or a resource Schema
|
||||
source: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
|
|
@ -133,7 +178,12 @@ export default {
|
|||
targetNamespace: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
ignoreVariables: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
@ -142,7 +192,13 @@ export default {
|
|||
|
||||
computed: {
|
||||
allQuestions() {
|
||||
if ( this.source.type === 'schema' ) {
|
||||
return schemaToQuestions(this.source);
|
||||
} else if ( this.source.questions?.questions ) {
|
||||
return this.chartVersion.questions.questions;
|
||||
} else {
|
||||
throw new Error('Must specify sourec as a chartVersion or Schema resource');
|
||||
}
|
||||
},
|
||||
|
||||
shownQuestions() {
|
||||
|
|
@ -156,6 +212,10 @@ export default {
|
|||
const out = [];
|
||||
|
||||
for ( const q of this.allQuestions ) {
|
||||
if ( this.ignoreVariables.includes(q.variable) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addQuestion(q);
|
||||
}
|
||||
|
||||
|
|
@ -185,12 +245,13 @@ export default {
|
|||
let weight = this.shownQuestions.length;
|
||||
|
||||
for ( const q of this.shownQuestions ) {
|
||||
if ( q.group ) {
|
||||
const normalized = q.group.trim().toLowerCase();
|
||||
const group = q.group || defaultGroup;
|
||||
|
||||
const normalized = group.trim().toLowerCase();
|
||||
|
||||
if ( !map[normalized] ) {
|
||||
map[normalized] = {
|
||||
name: q.group || defaultGroup,
|
||||
name: group,
|
||||
questions: [],
|
||||
weight: weight--,
|
||||
};
|
||||
|
|
@ -198,11 +259,10 @@ export default {
|
|||
|
||||
map[normalized].questions.push(q);
|
||||
}
|
||||
}
|
||||
|
||||
const out = Object.values(map);
|
||||
|
||||
return out;
|
||||
return sortBy(out, 'weight:desc');
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -219,20 +279,13 @@ export default {
|
|||
methods: {
|
||||
get,
|
||||
set,
|
||||
|
||||
componentForQuestion(q) {
|
||||
if ( knownTypes[q.type] ) {
|
||||
return q.type;
|
||||
}
|
||||
|
||||
return 'string';
|
||||
}
|
||||
componentForQuestion,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="tabbed">
|
||||
<Tab
|
||||
v-for="g in groups"
|
||||
:key="g.name"
|
||||
|
|
@ -253,6 +306,28 @@ export default {
|
|||
</div>
|
||||
</Tab>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div
|
||||
v-for="g in groups"
|
||||
:key="g.name"
|
||||
>
|
||||
<h3 v-if="groups.length > 1">
|
||||
{{ g.label }}
|
||||
</h3>
|
||||
<div v-for="q in g.questions" :key="q.variable" class="row question">
|
||||
<div class="col span-12">
|
||||
<component
|
||||
:is="componentForQuestion(q)"
|
||||
:question="q"
|
||||
:target-namespace="targetNamespace"
|
||||
:mode="mode"
|
||||
:value="get(value, q.variable)"
|
||||
@input="set(value, q.variable, $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
Loading…
Reference in New Issue