dashboard/shell/edit/management.cattle.io.settin...

265 lines
7.2 KiB
Vue

<script>
import CruResource from '@shell/components/CruResource';
import { LabeledInput } from '@components/Form/LabeledInput';
import LabeledSelect from '@shell/components/form/LabeledSelect';
import { Banner } from '@components/Banner';
import CreateEditView from '@shell/mixins/create-edit-view';
import { TextAreaAutoGrow } from '@components/Form/TextArea';
import formRulesGenerator from '@shell/utils/validators/formRules/index';
import { ALLOWED_SETTINGS, SETTING } from '@shell/config/settings';
import { RadioGroup } from '@components/Form/Radio';
import FormValidation from '@shell/mixins/form-validation';
import { setBrand } from '@shell/config/private-label';
import { keyBy, mapValues } from 'lodash';
import { isLocalhost, isServerUrl } from '@shell/utils/validators/setting';
export default {
components: {
CruResource,
LabeledInput,
LabeledSelect,
RadioGroup,
TextAreaAutoGrow,
Banner
},
inheritAttrs: false,
mixins: [CreateEditView, FormValidation],
data() {
const t = this.$store.getters['i18n/t'];
return {
setting: ALLOWED_SETTINGS[this.value.id],
description: t(`advancedSettings.descriptions.${ this.value.id }`),
editHelp: t(`advancedSettings.editHelp.${ this.value.id }`),
enumOptions: [],
canReset: false,
errors: [],
fvFormRuleSets: [],
};
},
created() {
this.value.value = this.value.value || this.value.default;
this.enumOptions = this.setting?.kind === 'enum' ? this.setting.options.map((id) => ({
// i18n-uses advancedSettings.enum.*
label: `advancedSettings.enum.${ this.value.id }.${ id }`,
value: id,
})) : [];
this.canReset = this.setting?.canReset || !!this.value.default;
this.fvFormRuleSets = this.setting?.ruleSet ? [{
path: 'value',
rules: this.setting.ruleSet.map(({ name }) => name)
}] : [];
// Don't allow the user to reset the server URL if there is no default
// helps to ensure that a value is always set
if (isServerUrl(this.value.id) && !this.value.default) {
this.canReset = false;
}
},
computed: {
fvExtraRules() {
const t = this.$store.getters['i18n/t'];
// We map the setting rulesets to use values to define validation from factory
return this.setting?.ruleSet ? mapValues(
keyBy(this.setting.ruleSet, 'name'),
// The validation is curried and may require the factory argument for the ValidatorFactory
({ key, name, factoryArg }) => {
const rule = formRulesGenerator(t, key ? { key } : {})[name];
return factoryArg ? rule(factoryArg) : rule;
}) : {};
},
showLocalhostWarning() {
return isServerUrl(this.value.id) && isLocalhost(this.value.value);
},
showWarningBanner() {
return this.setting?.warning;
},
validationPassed() {
return this.fvFormIsValid && this.fvGetPathErrors(['value']).length === 0;
}
},
methods: {
convertToString(event) {
this.value.value = `${ event.target.value }`;
},
saveSettings(done) {
const t = this.$store.getters['i18n/t'];
// Validate the JSON if the setting is a json value
if (this.setting.kind === 'json') {
try {
JSON.parse(this.value.value);
this.errors = [];
} catch (e) {
this.errors = [t('advancedSettings.edit.invalidJSON')];
return done(false);
}
}
if (this.value?.id === SETTING.BRAND) {
setBrand(this.value.value);
}
this.save(done);
},
useDefault(ev) {
// Lose the focus on the button after click
if (ev && ev.srcElement) {
ev.srcElement.blur();
}
if (isServerUrl(this.value.id) && !this.value.default) {
return;
}
this.value.value = this.value.default;
}
}
};
</script>
<template>
<CruResource
class="route"
:done-route="'c-cluster-product-resource'"
:errors="fvUnreportedValidationErrors"
:mode="mode"
:resource="value"
:subtypes="[]"
:can-yaml="false"
:validation-passed="validationPassed"
@error="e=>errors = e"
@finish="saveSettings"
@cancel="done"
>
<Banner
v-if="showWarningBanner"
color="warning"
:label="t(`advancedSettings.warnings.${ setting.warning }`)"
data-testid="advanced_settings_warning_banner"
/>
<h4>{{ description }}</h4>
<h5
v-if="editHelp"
v-clean-html="editHelp"
class="edit-help"
/>
<div class="edit-change mt-20">
<h5 v-t="'advancedSettings.edit.changeSetting'" />
<button
data-testid="advanced_settings_use_default"
:disabled="!canReset"
type="button"
class="btn role-primary"
@click="useDefault"
>
{{ t('advancedSettings.edit.useDefault') }}
</button>
</div>
<Banner
v-if="showLocalhostWarning"
color="warning"
:label="t('validation.setting.serverUrl.localhost')"
data-testid="setting-serverurl-localhost-warning"
/>
<Banner
v-for="(err, i) in fvGetPathErrors(['value'])"
:key="i"
color="error"
:label="err"
data-testid="setting-error-banner"
/>
<div class="mt-20">
<div v-if="setting.kind === 'enum'">
<LabeledSelect
v-model:value="value.value"
data-testid="input-setting-enum"
:label="t('advancedSettings.edit.value')"
:rules="fvGetAndReportPathRules('value')"
:localized-label="true"
:mode="mode"
:required="true"
:options="enumOptions"
/>
</div>
<div v-else-if="setting.kind === 'boolean'">
<RadioGroup
v-model:value="value.value"
data-testid="input-setting-boolean"
name="settings_value"
:rules="fvGetAndReportPathRules('value')"
:labels="[t('advancedSettings.edit.trueOption'), t('advancedSettings.edit.falseOption')]"
:options="['true', 'false']"
/>
</div>
<div v-else-if="setting.kind === 'multiline' || setting.kind === 'json'">
<TextAreaAutoGrow
v-model:value="value.value"
data-testid="input-setting-json"
:required="true"
:rules="fvGetAndReportPathRules('value')"
:min-height="254"
/>
</div>
<div v-else-if="setting.kind === 'integer'">
<LabeledInput
v-model:value="value.value"
data-testid="input-setting-integer"
:label="t('advancedSettings.edit.value')"
:mode="mode"
type="number"
:rules="fvGetAndReportPathRules('value')"
:required="true"
/>
</div>
<div v-else>
<LabeledInput
v-model:value="value.value"
data-testid="input-setting-generic"
:localized-label="true"
:required="true"
:mode="mode"
:rules="fvGetAndReportPathRules('value')"
:label="t('advancedSettings.edit.value')"
/>
</div>
</div>
</CruResource>
</template>
<style lang="scss" scoped>
.edit-change {
align-items: center;
display: flex;
> h5 {
flex: 1;
}
}
:deep() .edit-help code {
padding: 1px 5px;
}
</style>