311 lines
8.6 KiB
Vue
311 lines
8.6 KiB
Vue
<template>
|
|
<q-dialog ref="dialog" @hide="onHide" persistent :maximized="maximized">
|
|
<q-card class="q-dialog-plugin" :style="getMaxWidth">
|
|
<q-bar>
|
|
{{ title }}
|
|
<q-space />
|
|
<q-btn dense flat icon="minimize" @click="maximized = false" :disable="!maximized">
|
|
<q-tooltip v-if="maximized" class="bg-white text-primary">Minimize</q-tooltip>
|
|
</q-btn>
|
|
<q-btn dense flat icon="crop_square" @click="maximized = true" :disable="maximized">
|
|
<q-tooltip v-if="!maximized" class="bg-white text-primary">Maximize</q-tooltip>
|
|
</q-btn>
|
|
<q-btn dense flat icon="close" v-close-popup>
|
|
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
|
</q-btn>
|
|
</q-bar>
|
|
<q-form @submit="submit">
|
|
<q-card-section class="row">
|
|
<div class="q-pa-sm col-1" style="width: auto">
|
|
<q-icon
|
|
class="cursor-pointer"
|
|
:name="favoriteIcon"
|
|
size="md"
|
|
color="yellow-8"
|
|
@[clickEvent]="localScript.favorite = !localScript.favorite"
|
|
/>
|
|
</div>
|
|
<div class="q-pa-sm col-2">
|
|
<q-input
|
|
filled
|
|
dense
|
|
:readonly="readonly"
|
|
v-model="localScript.name"
|
|
label="Name"
|
|
:rules="[val => !!val || '*Required']"
|
|
/>
|
|
</div>
|
|
<div class="q-pa-sm col-2">
|
|
<q-select
|
|
:readonly="readonly"
|
|
options-dense
|
|
filled
|
|
dense
|
|
v-model="localScript.shell"
|
|
:options="shellOptions"
|
|
emit-value
|
|
map-options
|
|
label="Shell Type"
|
|
/>
|
|
</div>
|
|
<div class="q-pa-sm col-2">
|
|
<q-input
|
|
type="number"
|
|
filled
|
|
dense
|
|
:readonly="readonly"
|
|
v-model.number="localScript.default_timeout"
|
|
label="Timeout (seconds)"
|
|
:rules="[val => val >= 5 || 'Minimum is 5']"
|
|
/>
|
|
</div>
|
|
<div class="q-pa-sm col-3">
|
|
<q-select
|
|
hint="Press Enter or Tab when adding a new value"
|
|
dense
|
|
options-dense
|
|
filled
|
|
v-model="localScript.category"
|
|
:options="filterOptions"
|
|
use-input
|
|
clearable
|
|
new-value-mode="add-unique"
|
|
debounce="0"
|
|
@filter="filterFn"
|
|
label="Category"
|
|
:readonly="readonly"
|
|
/>
|
|
</div>
|
|
<div class="q-pa-sm col-2">
|
|
<q-input filled dense :readonly="readonly" v-model="localScript.description" label="Description" />
|
|
</div>
|
|
</q-card-section>
|
|
<div class="q-px-sm q-pt-none q-pb-sm q-mt-none row">
|
|
<q-select
|
|
label="Script Arguments (press Enter after typing each argument)"
|
|
class="col-12"
|
|
filled
|
|
v-model="localScript.args"
|
|
use-input
|
|
use-chips
|
|
multiple
|
|
dense
|
|
hide-dropdown-icon
|
|
input-debounce="0"
|
|
new-value-mode="add"
|
|
/>
|
|
</div>
|
|
<prism-editor
|
|
class="editor"
|
|
:readonly="readonly"
|
|
v-model="localScript.code"
|
|
:highlight="highlighter"
|
|
:style="heightVar"
|
|
line-numbers
|
|
@click="focusTextArea"
|
|
/>
|
|
<q-card-actions v-if="!readonly" align="right">
|
|
<q-btn dense flat label="Cancel" v-close-popup />
|
|
<q-btn dense flat label="Save" color="primary" type="submit" />
|
|
</q-card-actions>
|
|
</q-form>
|
|
</q-card>
|
|
</q-dialog>
|
|
</template>
|
|
|
|
<script>
|
|
import mixins from "@/mixins/mixins";
|
|
import { PrismEditor } from "vue-prism-editor";
|
|
import "vue-prism-editor/dist/prismeditor.min.css";
|
|
|
|
import { highlight, languages } from "prismjs/components/prism-core";
|
|
import "prismjs/components/prism-batch";
|
|
import "prismjs/components/prism-python";
|
|
import "prismjs/components/prism-powershell";
|
|
import "prismjs/themes/prism-tomorrow.css";
|
|
|
|
export default {
|
|
name: "ScriptFormModal",
|
|
emits: ["hide", "ok", "cancel"],
|
|
mixins: [mixins],
|
|
components: {
|
|
PrismEditor,
|
|
},
|
|
props: {
|
|
script: Object,
|
|
categories: !Array,
|
|
readonly: Boolean,
|
|
},
|
|
data() {
|
|
return {
|
|
localScript: {
|
|
name: "",
|
|
code: "",
|
|
shell: "powershell",
|
|
description: "",
|
|
args: [],
|
|
category: "",
|
|
favorite: false,
|
|
script_type: "userdefined",
|
|
default_timeout: 90,
|
|
},
|
|
maximized: false,
|
|
filterOptions: [],
|
|
shellOptions: [
|
|
{ label: "Powershell", value: "powershell" },
|
|
{ label: "Batch", value: "cmd" },
|
|
{ label: "Python", value: "python" },
|
|
],
|
|
};
|
|
},
|
|
methods: {
|
|
submit() {
|
|
this.$q.loading.show();
|
|
|
|
if (!!this.script) {
|
|
this.$axios
|
|
.put(`/scripts/${this.script.id}/script/`, this.localScript)
|
|
.then(r => {
|
|
this.$q.loading.hide();
|
|
this.onOk();
|
|
this.notifySuccess(r.data);
|
|
})
|
|
.catch(e => {
|
|
this.$q.loading.hide();
|
|
});
|
|
} else {
|
|
this.$axios
|
|
.post(`/scripts/scripts/`, this.localScript)
|
|
.then(r => {
|
|
this.$q.loading.hide();
|
|
this.onOk();
|
|
this.notifySuccess(r.data);
|
|
})
|
|
.catch(e => {
|
|
this.$q.loading.hide();
|
|
});
|
|
}
|
|
},
|
|
getCode() {
|
|
this.$q.loading.show();
|
|
this.$axios
|
|
.get(`/scripts/${this.script.id}/download/`)
|
|
.then(r => {
|
|
this.$q.loading.hide();
|
|
this.localScript.code = r.data.code;
|
|
})
|
|
.catch(e => {
|
|
this.$q.loading.hide();
|
|
});
|
|
},
|
|
highlighter(code) {
|
|
let lang = this.localScript.shell === "cmd" ? "batch" : this.localScript.shell;
|
|
return highlight(code, languages[lang]);
|
|
},
|
|
show() {
|
|
this.$refs.dialog.show();
|
|
},
|
|
hide() {
|
|
this.$refs.dialog.hide();
|
|
},
|
|
onHide() {
|
|
this.$emit("hide");
|
|
},
|
|
onOk() {
|
|
this.$emit("ok");
|
|
this.hide();
|
|
},
|
|
onCancel() {
|
|
this.hide();
|
|
},
|
|
filterFn(val, update) {
|
|
update(() => {
|
|
if (val === "") {
|
|
this.filterOptions = this.categories;
|
|
} else {
|
|
const needle = val.toLowerCase();
|
|
this.filterOptions = this.categories.filter(v => v.toLowerCase().indexOf(needle) > -1);
|
|
}
|
|
});
|
|
},
|
|
focusTextArea() {
|
|
document.getElementsByClassName("prism-editor__textarea")[0].focus();
|
|
},
|
|
},
|
|
computed: {
|
|
favoriteIcon() {
|
|
return this.localScript.favorite ? "star" : "star_outline";
|
|
},
|
|
title() {
|
|
if (!!this.script) {
|
|
return this.readonly ? `Viewing ${this.script.name}` : `Editing ${this.script.name}`;
|
|
} else {
|
|
return "Adding new script";
|
|
}
|
|
},
|
|
clickEvent() {
|
|
return !this.readonly ? "click" : null;
|
|
},
|
|
getMaxWidth() {
|
|
return this.maximized ? "" : "width: 70vw; max-width: 90vw";
|
|
},
|
|
heightVar() {
|
|
return this.maximized ? "--prism-height: 76vh" : "--prism-height: 70vh";
|
|
},
|
|
},
|
|
created() {
|
|
if (!!this.script) {
|
|
this.localScript.id = this.script.id;
|
|
this.localScript.name = this.script.name;
|
|
this.localScript.description = this.script.description;
|
|
this.localScript.favorite = this.script.favorite;
|
|
this.localScript.shell = this.script.shell;
|
|
this.localScript.category = this.script.category;
|
|
this.localScript.script_type = this.script.script_type;
|
|
this.localScript.default_timeout = this.script.default_timeout;
|
|
this.localScript.args = this.script.args;
|
|
this.getCode();
|
|
}
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style>
|
|
/* required class */
|
|
.editor {
|
|
/* we dont use `language-` classes anymore so thats why we need to add background and text color manually */
|
|
background: #2d2d2d;
|
|
color: #ccc;
|
|
|
|
/* you must provide font-family font-size line-height. Example: */
|
|
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
padding: 5px;
|
|
height: var(--prism-height);
|
|
}
|
|
|
|
/* optional class for removing the outline */
|
|
.prism-editor__textarea:focus {
|
|
outline: none;
|
|
}
|
|
|
|
.prism-editor__textarea,
|
|
.prism-editor__container {
|
|
width: 500em !important;
|
|
-ms-overflow-style: none;
|
|
scrollbar-width: none;
|
|
}
|
|
|
|
.prism-editor__container::-webkit-scrollbar,
|
|
.prism-editor__textarea::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
.prism-editor__editor {
|
|
white-space: pre !important;
|
|
}
|
|
.prism-editor__container {
|
|
overflow-x: auto !important;
|
|
}
|
|
</style> |