dashboard/components/form/NameNsDescription.vue

254 lines
6.2 KiB
Vue

<script>
import { get } from '../../utils/object';
import { sortBy } from '../../utils/sort';
import { NAMESPACE, ANNOTATION } from '~/config/types';
import { NAMESPACES } from '@/store/prefs';
import { _CREATE, _VIEW } from '~/config/query-params';
import LabeledInput from '@/components/form/LabeledInput';
import LabeledSelect from '@/components/form/LabeledSelect';
import { escapeRegex } from '@/utils/string';
export default {
components: { LabeledInput, LabeledSelect },
props: {
value: {
type: Object,
required: true,
},
mode: {
type: String,
required: true,
},
namespaced: {
type: Boolean,
default: true,
},
extraColumns: {
type: Array,
default: () => []
},
nameLabel: {
type: String,
default: 'Name'
},
namePlaceholder: {
type: String,
default: ''
},
descriptionPlaceholder: {
type: String,
default: 'Any text you want that better describes this resource'
},
useGeneratedName: {
type: Boolean,
default: false,
},
generatedSuffix: {
type: String,
default: '-'
},
alwaysDescribe: {
type: Boolean,
default: false
},
registerBeforeHook: {
type: Function,
default: null
}
},
data() {
let metadata = this.value.metadata;
if ( !metadata ) {
metadata = {};
this.value.metadata = metadata;
}
if ( !metadata.annotations ) {
metadata.annotations = {};
}
if ( !metadata.namespace) {
const selectedNS = this.$store.getters['prefs/get'](NAMESPACES)[0] || 'default';
metadata.namespace = selectedNS;
}
let name;
if ( this.useGeneratedName ) {
name = metadata.generateName || '';
const re = new RegExp(`${ escapeRegex(this.generatedSuffix) }$`, 'i');
name = name.replace(re, '');
} else {
name = metadata.name || '';
}
return {
name,
ANNOTATION_DESCRIPTION: ANNOTATION.DESCRIPTION,
createNS: false,
toCreate: ''
};
},
computed: {
namespaces() {
const choices = this.$store.getters['cluster/all'](NAMESPACE);
return sortBy(choices.map((obj) => {
return {
label: obj.nameDisplay,
value: obj.id,
};
}), 'label');
},
onlyForCreate() {
if ( this.mode === _CREATE ) {
return _CREATE;
}
return _VIEW;
},
notView() {
return this.mode !== _VIEW;
},
colSpan() {
const cols = 1 + (this.namespaced ? 1 : 0) + this.extraColumns.length;
const span = 12 / cols;
return `span-${ span }`;
},
description: {
get() {
return this.value.metadata.annotations[ANNOTATION.DESCRIPTION];
},
set(val) {
this.value.metadata.annotations[ANNOTATION.DESCRIPTION] = val;
}
},
wantDescription() {
const description = get(this.value, `metadata.annotations.${ ANNOTATION.DESCRIPTION }`);
return !!description || this.alwaysDescribe;
}
},
watch: {
name(neu) {
if ( this.useGeneratedName ) {
this.value.metadata.generateName = neu + this.generatedSuffix;
delete this.value.metadata.name;
} else {
this.value.metadata.name = neu;
}
},
},
created() {
if (this.registerBeforeHook) {
this.registerBeforeHook(this.createNamespace);
}
},
methods: {
toggleNSMode() {
this.createNS = !this.createNS;
},
async createNamespace() {
if (this.createNS) {
if (!this.toCreate) {
throw new Error('no namespace name provided');
} else {
try {
const nsSchema = this.$store.getters['cluster/schemaFor'](NAMESPACE);
const data = { metadata: { name: this.toCreate } };
await nsSchema.followLink('collection', {
method: 'POST',
data
});
this.value.metadata.namespace = this.toCreate;
} catch (err) {
throw err;
}
}
}
}
}
};
</script>
<template>
<div>
<div class="row">
<div :class="{col: true, [colSpan]: true}">
<slot name="name">
<LabeledInput
key="name"
v-model="name"
:mode="onlyForCreate"
:label="nameLabel"
:placeholder="namePlaceholder"
:required="true"
>
<template v-if="notView && !wantDescription" #corner>
<a href="#" @click.prevent="wantDescription=true">Add a description</a>
</template>
</LabeledInput>
</slot>
</div>
<div v-if="namespaced" :class="{col: true, [colSpan]: true}">
<slot name="namespace">
<LabeledInput v-if="createNS" v-model="toCreate" required label="Namespace" placeholder="e.g. myapp">
<template #corner>
<a href="#" @click.prevent="toggleNSMode">
Use an existing namespace
</a>
</template>
</LabeledInput>
<LabeledSelect
v-else
key="namespace"
v-model="value.metadata.namespace"
:mode="onlyForCreate"
:options="namespaces"
:required="true"
label="Namespace"
placeholder="Select a namespace"
>
<template #corner>
<a v-if="registerBeforeHook" href="#" @click.prevent="toggleNSMode">
Create new namespace
</a>
</template>
</LabeledSelect>
</slot>
</div>
<div v-for="slot in extraColumns" :key="slot" :class="{col: true, [colSpan]: true}">
<slot :name="slot">
</slot>
</div>
</div>
<div v-if="wantDescription" class="row">
<div class="col span-12">
<div>
<LabeledInput
key="description"
v-model="description"
type="multiline"
label="Description"
:mode="mode"
:placeholder="descriptionPlaceholder"
:min-height="30"
/>
</div>
</div>
</div>
</div>
</template>