Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ui] Supply service chart values when creating a service #300

Merged
merged 9 commits into from
Aug 21, 2023
125 changes: 13 additions & 112 deletions dashboard/pkg/epinio/components/application/AppInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ import ArrayList from '@shell/components/form/ArrayList.vue';
import Loading from '@shell/components/Loading.vue';
import Banner from '@components/Banner/Banner.vue';
import { _EDIT } from '@shell/config/query-params';
import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
import formRulesGenerator from '@shell/utils/validators/formRules';
import ChartValues from '../settings/ChartValues.vue';

import { sortBy } from '@shell/utils/sort';
import { validateKubernetesName } from '@shell/utils/validators/kubernetes-name';
import { EPINIO_TYPES, EpinioNamespace } from '../../types';
import Application from '../../models/applications';
import { objValuesToString } from '../../utils/settings';

export interface EpinioAppInfo {
meta: {
Expand Down Expand Up @@ -46,8 +45,7 @@ export default Vue.extend<Data, any, any, any>({
KeyValue,
Loading,
Banner,
Checkbox,
LabeledSelect
ChartValues,
},

props: {
Expand Down Expand Up @@ -138,7 +136,7 @@ export default Vue.extend<Data, any, any, any>({
const validNamespace = nsErrors.length === 0;
const validInstances = typeof this.values.configuration?.instances !== 'string' && this.values.configuration?.instances >= 0;

return validName && validNamespace && validInstances && Object.values(this.validSettings).every((v) => !!v) ;
return validName && validNamespace && validInstances && Object.values(this.validSettings).every((v) => !!v);
},

showApplicationVariables() {
Expand All @@ -156,7 +154,7 @@ export default Vue.extend<Data, any, any, any>({
meta: this.values.meta,
configuration: {
...this.values.configuration,
settings: this.objValuesToString(this.values.configuration.settings)
settings: objValuesToString(this.values.configuration.settings)
},
});
},
Expand Down Expand Up @@ -197,57 +195,6 @@ export default Vue.extend<Data, any, any, any>({

return Object.fromEntries(entries);
},

objValuesToString(obj: any) {
const copy = { ...obj };

for (const key in copy) {
if (typeof copy[key] !== 'string') {
copy[key] = String(copy[key]);
}
}

return copy;
},

validSettingsRule(key: string, min: any, max: any) {
const frg = formRulesGenerator(this.$store.getters['i18n/t'], { key });
const minRule = frg.minValue(min);
const maxRule = frg.maxValue(max);

return (value: string) => {
const messages = [];

if (value) {
const minRes = minRule(value);

if (minRes) {
messages.push(minRes);
}

const maxRes = maxRule(value);

if (maxRes) {
messages.push(maxRes);
}
}
Vue.set(this.validSettings, key, !messages.length);

return messages.join(',');
};
},

numericPlaceholder(setting: any) {
if (setting.maximum && setting.minimum) {
return `${ setting.minimum } to ${ setting.maximum }`;
} else if (setting.maximum) {
return `<= ${ setting.maximum }`;
} else if (setting.minimum) {
return `>= ${ setting.minimum }`;
} else {
return '';
}
},
},

});
Expand Down Expand Up @@ -305,50 +252,15 @@ export default Vue.extend<Data, any, any, any>({
</div>
<div
v-if="showApplicationVariables"
class="col span-6 settings"
class="col span-6"
>
<h3>{{ t('epinio.applications.create.settingsVars.title') }}</h3>
<div
v-for="(setting, key) in values.chart"
:key="key"
class="settings-item"
>
<LabeledInput
v-if="setting.type === 'number' || setting.type === 'integer'"
:id="key"
v-model="values.configuration.settings[key]"
:label="key"
type="number"
:min="setting.minimum"
:max="setting.maximum"
:rules="[validSettingsRule(key, setting.minimum, setting.maximum)]"
:tooltip="numericPlaceholder(setting)"
:mode="mode"
/>
<Checkbox
v-else-if="setting.type === 'bool'"
:id="key"
:value="values.configuration.settings[key] === 'true'"
:label="key"
:mode="mode"
@input="values.configuration.settings[key] = $event ? 'true' : 'false'"
/>
<LabeledSelect
v-else-if="setting.type === 'string' && setting.enum"
:id="key"
v-model="values.configuration.settings[key]"
:label="key"
:options="setting.enum"
:mode="mode"
/>
<LabeledInput
v-else-if="setting.type === 'string'"
:id="key"
v-model="values.configuration.settings[key]"
:label="key"
:mode="mode"
/>
</div>
<ChartValues
v-model="values.configuration.settings"
:chart="values.chart"
:title="t('epinio.applications.create.settingsVars.title')"
:mode="mode"
@valid="validSettings = $event"
/>
<div class="spacer" />
</div>
<div class="col span-8">
Expand All @@ -365,14 +277,3 @@ export default Vue.extend<Data, any, any, any>({
</div>
</div>
</template>

<style lang="scss" scoped>
.settings {
display: flex;
flex-direction: column;

&-item:not(:last-of-type) {
margin-bottom: 20px;
}
}
</style>
160 changes: 160 additions & 0 deletions dashboard/pkg/epinio/components/settings/ChartValues.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<script lang="ts">
import Vue, { PropType } from 'vue';
import formRulesGenerator from '@shell/utils/validators/formRules';
import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue';

interface Data {
valid: { [key: string]: boolean }
}

// Data, Methods, Computed, Props
export default Vue.extend<Data, any, any, any>({
components: {
Checkbox,
LabeledInput,
LabeledSelect,
},

props: {
chart: {
type: Object as PropType<{ [key: string]: object }>,
required: true
},
value: {
type: Object as PropType<{ [key: string]: any }>,
required: true
},
title: {
type: String,
default: 'Settings'
},
mode: {
type: String,
required: true
},
disabled: {
type: Boolean,
default: false
},
},

data() {
return { valid: {} };
},

watch: {
valid(neu) {
this.$emit('valid', neu);
}
},

methods: {
rules(key: string, min: any, max: any) {
const frg = formRulesGenerator(this.$store.getters['i18n/t'], { key });
const minRule = frg.minValue(min);
const maxRule = frg.maxValue(max);

return (value: string) => {
const messages = [];

if (value) {
const minRes = minRule(value);

if (minRes) {
messages.push(minRes);
}

const maxRes = maxRule(value);

if (maxRes) {
messages.push(maxRes);
}
}
Vue.set(this.valid, key, !messages.length);

return messages.join(',');
};
},

numericPlaceholder(setting: any) {
if (setting.maximum && setting.minimum) {
return `${ setting.minimum } to ${ setting.maximum }`;
} else if (setting.maximum) {
return `<= ${ setting.maximum }`;
} else if (setting.minimum) {
return `>= ${ setting.minimum }`;
} else {
return '';
}
},

onInputCheckbox(key: string, value: boolean) {
Vue.set(this.value, key, value ? 'true' : 'false');
}
},
});
</script>

<template>
<div class="chart-values">
<h3>{{ title }}</h3>
<div
v-for="(setting, key) in chart"
:key="key"
class="chart-values-item"
>
<LabeledInput
v-if="setting.type === 'number' || setting.type === 'integer'"
:id="key"
v-model="value[key]"
:label="key"
type="number"
:min="setting.minimum"
:max="setting.maximum"
:rules="[rules(key, setting.minimum, setting.maximum)]"
:tooltip="numericPlaceholder(setting)"
:mode="mode"
:disabled="disabled"
/>
<Checkbox
v-else-if="setting.type === 'bool'"
:id="key"
:value="value[key] === 'true'"
:label="key"
:mode="mode"
:disabled="disabled"
@input="onInputCheckbox(key, $event)"
/>
<LabeledSelect
v-else-if="setting.type === 'string' && setting.enum"
:id="key"
v-model="value[key]"
:label="key"
:options="setting.enum"
:mode="mode"
:disabled="disabled"
/>
<LabeledInput
v-else-if="setting.type === 'string'"
:id="key"
v-model="value[key]"
:label="key"
:mode="mode"
:disabled="disabled"
/>
</div>
</div>
</template>

<style lang="scss" scoped>
.chart-values {
display: flex;
flex-direction: column;

&-item:not(:last-of-type) {
margin-bottom: 20px;
}
}
</style>
Loading
Loading