mirror of https://github.com/rancher/dashboard.git
319 lines
6.3 KiB
Vue
319 lines
6.3 KiB
Vue
<script>
|
|
import YamlEditor, { EDITOR_MODES } from '@/components/YamlEditor';
|
|
import Footer from '@/components/form/Footer';
|
|
|
|
import {
|
|
_CREATE,
|
|
_VIEW,
|
|
PREVIEW,
|
|
_FLAGGED,
|
|
_UNFLAG,
|
|
} from '@/config/query-params';
|
|
|
|
export default {
|
|
components: {
|
|
Footer,
|
|
YamlEditor
|
|
},
|
|
|
|
props: {
|
|
mode: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
|
|
value: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
|
|
yaml: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
|
|
doneRoute: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
|
|
offerPreview: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
|
|
parentParams: {
|
|
type: Object,
|
|
default: null,
|
|
},
|
|
|
|
doneOverride: {
|
|
type: Function,
|
|
default: null
|
|
},
|
|
|
|
showFooter: {
|
|
type: Boolean,
|
|
default: true
|
|
}
|
|
},
|
|
|
|
data() {
|
|
// Initial load with a preview showing no diff isn't very useful
|
|
this.$router.applyQuery({ [PREVIEW]: _UNFLAG });
|
|
|
|
return {
|
|
currentYaml: this.value.cleanYaml(this.yaml, this.mode),
|
|
showPreview: false,
|
|
errors: null
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
schema() {
|
|
return this.$store.getters['cluster/schemaFor'](this.value.type);
|
|
},
|
|
|
|
cmOptions() {
|
|
const readOnly = this.mode === _VIEW;
|
|
const gutters = ['CodeMirror-lint-markers'];
|
|
|
|
if ( !readOnly ) {
|
|
gutters.push('CodeMirror-foldgutter');
|
|
}
|
|
|
|
return {
|
|
readOnly,
|
|
gutters,
|
|
mode: 'yaml',
|
|
lint: true,
|
|
lineNumbers: !readOnly,
|
|
extraKeys: { 'Ctrl-Space': 'autocomplete' },
|
|
cursorBlinkRate: ( readOnly ? -1 : 530 )
|
|
};
|
|
},
|
|
|
|
isCreate() {
|
|
return this.mode === _CREATE;
|
|
},
|
|
|
|
isView() {
|
|
return this.mode === _VIEW;
|
|
},
|
|
|
|
editorMode() {
|
|
return this.isView
|
|
? EDITOR_MODES.VIEW_CODE
|
|
: this.showPreview
|
|
? EDITOR_MODES.DIFF_CODE
|
|
: EDITOR_MODES.EDIT_CODE;
|
|
},
|
|
},
|
|
|
|
watch: {
|
|
mode(neu) {
|
|
this.currentYaml = this.value.cleanYaml(this.yaml, neu);
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
onInput(yaml) {
|
|
this.currentYaml = yaml;
|
|
},
|
|
|
|
onReady(cm) {
|
|
cm.getMode().fold = 'yaml';
|
|
|
|
if ( this.isCreate ) {
|
|
cm.execCommand('foldAll');
|
|
}
|
|
},
|
|
|
|
onChanges(cm, changes) {
|
|
if ( changes.length !== 1 ) {
|
|
return;
|
|
}
|
|
|
|
const change = changes[0];
|
|
|
|
if ( change.from.line !== change.to.line ) {
|
|
return;
|
|
}
|
|
|
|
let line = change.from.line;
|
|
let str = cm.getLine(line);
|
|
let maxIndent = indentChars(str);
|
|
|
|
if ( maxIndent === null ) {
|
|
return;
|
|
}
|
|
|
|
cm.replaceRange('', { line, ch: 0 }, { line, ch: 1 }, '+input');
|
|
|
|
while ( line > 0 ) {
|
|
line--;
|
|
str = cm.getLine(line);
|
|
const indent = indentChars(str);
|
|
|
|
if ( indent === null ) {
|
|
break;
|
|
}
|
|
|
|
if ( indent < maxIndent ) {
|
|
cm.replaceRange('', { line, ch: 0 }, { line, ch: 1 }, '+input');
|
|
|
|
if ( indent === 0 ) {
|
|
break;
|
|
}
|
|
|
|
maxIndent = indent;
|
|
}
|
|
}
|
|
|
|
function indentChars(str) {
|
|
const match = str.match(/^#(\s+)/);
|
|
|
|
if ( match ) {
|
|
return match[1].length;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
},
|
|
|
|
readFromFile() {
|
|
this.$refs.yamleditor.readFromFile();
|
|
},
|
|
|
|
preview() {
|
|
this.showPreview = true;
|
|
this.$router.applyQuery({ [PREVIEW]: _FLAGGED });
|
|
},
|
|
|
|
unpreview() {
|
|
this.showPreview = false;
|
|
this.$router.applyQuery({ [PREVIEW]: _UNFLAG });
|
|
},
|
|
|
|
async save(buttonDone) {
|
|
const yaml = this.value.yamlForSave(this.currentYaml) || this.currentYaml;
|
|
let res;
|
|
|
|
try {
|
|
if ( this.isCreate ) {
|
|
res = await this.schema.followLink('collection', {
|
|
method: 'POST',
|
|
headers: {
|
|
'content-type': 'application/yaml',
|
|
accept: 'application/json',
|
|
},
|
|
data: yaml
|
|
});
|
|
} else {
|
|
const link = this.value.hasLink('rioupdate') ? 'rioupdate' : 'update';
|
|
|
|
res = await this.value.followLink(link, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'content-type': 'application/yaml',
|
|
accept: 'application/json',
|
|
},
|
|
data: yaml
|
|
});
|
|
}
|
|
|
|
if ( res && res.kind !== 'Table') {
|
|
await this.$store.dispatch('cluster/load', { data: res, existing: (this.isCreate ? this.value : undefined) });
|
|
}
|
|
|
|
buttonDone(true);
|
|
this.done();
|
|
} catch (err) {
|
|
if ( err && err.response && err.response.data ) {
|
|
const body = err.response.data;
|
|
|
|
if ( body && body.message ) {
|
|
this.errors = [body.message];
|
|
} else {
|
|
this.errors = [err];
|
|
}
|
|
} else {
|
|
this.errors = [err];
|
|
}
|
|
buttonDone(false);
|
|
}
|
|
},
|
|
done() {
|
|
if (this.doneOverride) {
|
|
return this.doneOverride();
|
|
}
|
|
if ( !this.doneRoute ) {
|
|
return;
|
|
}
|
|
this.$router.replace({
|
|
name: this.doneRoute,
|
|
params: { resource: this.value.type }
|
|
});
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="root resource-yaml">
|
|
<YamlEditor
|
|
ref="yamleditor"
|
|
v-model="currentYaml"
|
|
class="yaml-editor"
|
|
:editor-mode="editorMode"
|
|
@onInput="onInput"
|
|
@onReady="onReady"
|
|
@onChanges="onChanges"
|
|
/>
|
|
<Footer
|
|
v-if="showFooter"
|
|
:mode="mode"
|
|
:errors="errors"
|
|
@save="save"
|
|
@done="done"
|
|
>
|
|
<template v-if="!isView" #middle>
|
|
<button
|
|
v-if="showPreview"
|
|
type="button"
|
|
class="btn role-secondary"
|
|
@click="unpreview"
|
|
>
|
|
<t k="resourceYaml.buttons.continue" />
|
|
</button>
|
|
<button
|
|
v-else-if="offerPreview"
|
|
:disabled="yaml === currentYaml"
|
|
type="button"
|
|
class="btn role-secondary"
|
|
@click="preview"
|
|
>
|
|
<t k="resourceYaml.buttons.diff" />
|
|
</button>
|
|
</template>
|
|
</Footer>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss">
|
|
.resource-yaml {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
.yaml-editor {
|
|
flex: 1;
|
|
min-height: 200px;
|
|
}
|
|
|
|
footer .actions {
|
|
text-align: center;
|
|
}
|
|
}
|
|
</style>
|