dashboard/components/Import.vue

208 lines
4.9 KiB
Vue

<script>
import { mapGetters } from 'vuex';
import Card from '@/components/Card';
import Banner from '@/components/Banner';
import Loading from '@/components/Loading';
import YamlEditor from '@/components/YamlEditor';
import FileSelector from '@/components/form/FileSelector';
import AsyncButton from '@/components/AsyncButton';
import LabeledSelect from '@/components/form/LabeledSelect';
import SortableTable from '@/components/SortableTable';
import { sortBy } from '@/utils/sort';
import { exceptionToErrorsArray } from '@/utils/error';
import { NAMESPACE } from '@/config/types';
import {
NAME as NAME_COL, STATE, TYPE, NAMESPACE as NAMESPACE_COL, AGE
} from '@/config/table-headers';
export default {
components: {
AsyncButton,
Banner,
Card,
Loading,
YamlEditor,
FileSelector,
LabeledSelect,
SortableTable
},
async fetch() {
this.allNamespaces = await this.$store.dispatch('cluster/findAll', { type: NAMESPACE, opt: { url: 'namespaces' } });
},
data() {
return {
currentYaml: '',
defaultNamespace: 'default',
allNamespaces: null,
errors: null,
rows: null,
done: false,
};
},
computed: {
...mapGetters(['currentCluster']),
namespaceOptions() {
const out = this.allNamespaces.map((obj) => {
return {
label: obj.name,
value: obj.name,
};
});
return sortBy(out, 'label');
},
headers() {
return [
STATE,
TYPE,
NAME_COL,
NAMESPACE_COL,
AGE
];
},
},
methods: {
close() {
this.$emit('close');
},
onFileSelected(value) {
// const component = this.$refs.yamleditor;
// if (component) {
// component.updateValue(value);
// }
this.currentYaml = value;
},
async importYaml(btnCb) {
try {
this.errors = [];
const res = await this.currentCluster.doAction('apply', {
yaml: this.currentYaml,
defaultNamespace: this.defaultNamespace,
});
btnCb(true);
this.rows = res;
this.done = true;
} catch (err) {
this.errors = exceptionToErrorsArray(err);
this.done = false;
btnCb(false);
}
},
rowClick(e) {
if ( e.target.tagName === 'A' ) {
this.close();
}
},
},
};
</script>
<template>
<Loading v-if="$fetchState.pending" />
<Card v-else :show-highlight-border="false">
<template #title>
<div style="display: block; width: 100%;">
<template v-if="done">
<h4>{{ t('import.success', {count: rows.length}) }}</h4>
</template>
<template v-else>
<h4 v-t="'import.title'"></h4>
<div class="row">
<div class="col span-6">
<FileSelector
class="btn role-secondary pull-left"
:label="t('generic.readFromFile')"
@selected="onFileSelected"
/>
</div>
<div class="col span-6">
<LabeledSelect
v-model="defaultNamespace"
class="pull-right"
:options="namespaceOptions"
label-key="import.defaultNamespace.label"
mode="edit"
/>
</div>
</div>
</template>
</div>
</template>
<template #body>
<template v-if="done">
<div class="results">
<SortableTable
:rows="rows"
:headers="headers"
mode="view"
key-field="_key"
:search="false"
:paging="true"
:row-actions="false"
:table-actions="false"
@rowClick="rowClick"
/>
</div>
</template>
<YamlEditor
v-else
ref="yamleditor"
v-model="currentYaml"
class="yaml-editor"
/>
<Banner v-for="(err, i) in errors" :key="i" color="error" :label="err" />
</template>
<template #actions>
<div v-if="done" class="text-center" style="width: 100%">
<button type="button" class="btn role-primary" @click="close">
{{ t('generic.close') }}
</button>
</div>
<div v-else class="text-center" style="width: 100%">
<button type="button" class="btn role-secondary" @click="close">
{{ t('generic.cancel') }}
</button>
<AsyncButton v-if="!done" mode="import" :disabled="!currentYaml.length" @click="importYaml" />
</div>
</template>
</Card>
</template>
<style lang='scss' scoped>
$min: 50vh;
$max: 50vh;
.yaml-editor {
flex: 1;
min-height: $min;
max-height: $max;
::v-deep .code-mirror {
.CodeMirror {
position: initial;
}
.CodeMirror,
.CodeMirror-scroll,
.CodeMirror-gutters {
min-height: $min;
max-height: $max;
}
}
}
</style>