summaryrefslogtreecommitdiffstats
path: root/webapp
diff options
context:
space:
mode:
authorUdo Walter2018-11-22 05:27:34 +0100
committerUdo Walter2018-11-22 05:27:34 +0100
commit5b315f938afddad911f2c69a2deca2ca5b3f8c17 (patch)
tree7f314825e61ff7da08a46ee7d116e72831bb10aa /webapp
parent[external-backends] Fix: Delete clients in the backend is now working properly. (diff)
downloadbas-5b315f938afddad911f2c69a2deca2ca5b3f8c17.tar.gz
bas-5b315f938afddad911f2c69a2deca2ca5b3f8c17.tar.xz
bas-5b315f938afddad911f2c69a2deca2ca5b3f8c17.zip
[webapp] replace script textareas with a code editor
npm install is necessary to load the editor module
Diffstat (limited to 'webapp')
-rw-r--r--webapp/package-lock.json19
-rw-r--r--webapp/package.json1
-rw-r--r--webapp/src/assets/styles.css5
-rw-r--r--webapp/src/components/ConfiguratorModule.vue2
-rw-r--r--webapp/src/components/ConfiguratorModuleConfig.vue37
-rw-r--r--webapp/src/components/ConfiguratorModuleEntry.vue33
-rw-r--r--webapp/src/components/RegistrationModule.vue6
-rw-r--r--webapp/src/components/RegistrationModuleEdit.vue35
-rw-r--r--webapp/src/main.js13
9 files changed, 133 insertions, 18 deletions
diff --git a/webapp/package-lock.json b/webapp/package-lock.json
index 4d73910..83b8532 100644
--- a/webapp/package-lock.json
+++ b/webapp/package-lock.json
@@ -2005,6 +2005,11 @@
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true
},
+ "codemirror": {
+ "version": "5.42.0",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.42.0.tgz",
+ "integrity": "sha512-pbApC8zDzItP3HRphD6kQVwS976qB5Qi0hU3MZMixLk+AyugOW1RF+8XJEjeyl5yWsHNe88tDUxzeRh5AOxPRw=="
+ },
"collection-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -2831,6 +2836,11 @@
"integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
"dev": true
},
+ "diff-match-patch": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz",
+ "integrity": "sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg=="
+ },
"diffie-hellman": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
@@ -11223,6 +11233,15 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-2.5.17.tgz",
"integrity": "sha512-mFbcWoDIJi0w0Za4emyLiW72Jae0yjANHbCVquMKijcavBGypqlF7zHRgMa5k4sesdv7hv2rB4JPdZfR+TPfhQ=="
},
+ "vue-codemirror": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/vue-codemirror/-/vue-codemirror-4.0.6.tgz",
+ "integrity": "sha512-ilU7Uf0mqBNSSV3KT7FNEeRIxH4s1fmpG4TfHlzvXn0QiQAbkXS9lLfwuZpaBVEnpP5CSE62iGJjoliTuA8poQ==",
+ "requires": {
+ "codemirror": "^5.41.0",
+ "diff-match-patch": "^1.0.0"
+ }
+ },
"vue-eslint-parser": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz",
diff --git a/webapp/package.json b/webapp/package.json
index bc4513b..73d6809 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -13,6 +13,7 @@
"dependencies": {
"axios": "^0.18.0",
"vue": "^2.5.17",
+ "vue-codemirror": "^4.0.6",
"vue-i18n": "^7.8.1",
"vue-router": "^3.0.1",
"vue-touch": "^2.0.0-beta.4",
diff --git a/webapp/src/assets/styles.css b/webapp/src/assets/styles.css
index 94be2f2..0df7f2a 100644
--- a/webapp/src/assets/styles.css
+++ b/webapp/src/assets/styles.css
@@ -41,3 +41,8 @@ html {
.element-container {
padding: 26px;
}
+
+.CodeMirror {
+ min-height: 200px;
+ height: auto;
+} \ No newline at end of file
diff --git a/webapp/src/components/ConfiguratorModule.vue b/webapp/src/components/ConfiguratorModule.vue
index 0f79a30..51889de 100644
--- a/webapp/src/components/ConfiguratorModule.vue
+++ b/webapp/src/components/ConfiguratorModule.vue
@@ -101,7 +101,7 @@
<v-dialog
:value="dialog.show"
@input="setDialog({ show: $event })"
- :max-width="dialog.type === 'delete' ? '500px' : '1000px'"
+ :max-width="dialog.type === 'delete' ? '500px' : '1200px'"
scrollable
:persistent="dialog.type !== 'delete'"
>
diff --git a/webapp/src/components/ConfiguratorModuleConfig.vue b/webapp/src/components/ConfiguratorModuleConfig.vue
index 5253086..b8bb793 100644
--- a/webapp/src/components/ConfiguratorModuleConfig.vue
+++ b/webapp/src/components/ConfiguratorModuleConfig.vue
@@ -53,7 +53,10 @@
</v-flex>
</v-layout>
<v-textarea prepend-icon="description" rows="1" :label="$t('description')" color="primary" v-model="description"></v-textarea>
- <v-textarea v-if="expertMode" prepend-icon="code" rows="20" :label="$t('script')" color="primary" v-model="script"></v-textarea>
+ <div v-if="expertMode">
+ <div class="body-1 script-heading"><v-icon>code</v-icon><span>{{ $t('script') }}</span></div>
+ <codemirror class="script-editor" ref="editor" v-model="script"></codemirror>
+ </div>
<div v-else class="text-xs-right">
<v-subheader>{{ $t('entries') }}</v-subheader>
<v-list>
@@ -113,7 +116,11 @@ export default {
timeout: '',
script: '',
expertMode: false,
- items: []
+ items: [],
+ interval: {
+ id: null,
+ counter: 0
+ }
}
},
computed: {
@@ -129,11 +136,11 @@ export default {
deep: true,
async handler (value) {
if (value.type === 'config' && value.show) {
- this.name = value.info.name
- this.description = value.info.description
+ this.name = value.info.name || ''
+ this.description = value.info.description || ''
this.defaultEntry = value.info.defaultEntry
this.timeout = value.info.timeout
- this.script = value.info.script
+ this.script = value.info.script || ''
if (this.script) this.expertMode = true
else this.expertMode = false
this.items = []
@@ -143,6 +150,8 @@ export default {
customName: x.config_x_entry.customName,
keyBind: x.config_x_entry.keyBind
}))
+ this.interval.id = setInterval(this.refreshEditor, 50)
+ this.interval.counter = 0
}
}
}
@@ -172,6 +181,11 @@ export default {
})
this.$store.dispatch('configurator/loadData')
this.setDialog({ show: false })
+ },
+ refreshEditor () {
+ this.interval.counter++
+ if (this.$refs.editor) this.$refs.editor.codemirror.refresh()
+ if (this.interval.counter >= 15) clearInterval(this.interval.id)
}
}
}
@@ -191,4 +205,17 @@ export default {
margin-left: 20px;
margin-right: 20px;
}
+
+.script-heading {
+ display: flex;
+ align-items: center;
+}
+
+.script-heading > span {
+ margin-left: 9px;
+}
+
+.script-editor {
+ margin-top: 8px;
+}
</style>
diff --git a/webapp/src/components/ConfiguratorModuleEntry.vue b/webapp/src/components/ConfiguratorModuleEntry.vue
index 7907742..3bb03a3 100644
--- a/webapp/src/components/ConfiguratorModuleEntry.vue
+++ b/webapp/src/components/ConfiguratorModuleEntry.vue
@@ -22,7 +22,8 @@
</v-card-title>
<v-card-text>
<v-text-field prepend-icon="label" :label="$t('name')" color="primary" v-model="name"></v-text-field>
- <v-textarea prepend-icon="code" rows="20" :label="$t('script')" color="primary" v-model="script"></v-textarea>
+ <div class="body-1 script-heading"><v-icon>code</v-icon><span>{{ $t('script') }}</span></div>
+ <codemirror class="script-editor" ref="editor" v-model="script"></codemirror>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
@@ -42,7 +43,11 @@ export default {
data () {
return {
name: '',
- script: ''
+ script: '',
+ interval: {
+ id: null,
+ counter: 0
+ }
}
},
computed: {
@@ -54,8 +59,10 @@ export default {
deep: true,
handler (value) {
if (value.type === 'entry' && value.show) {
- this.name = value.info.name
- this.script = value.info.script
+ this.name = value.info.name || ''
+ this.script = value.info.script || ''
+ this.interval.id = setInterval(this.refreshEditor, 50)
+ this.interval.counter = 0
}
}
}
@@ -71,6 +78,11 @@ export default {
})
this.$store.dispatch('configurator/loadData')
this.setDialog({ show: false })
+ },
+ refreshEditor () {
+ this.interval.counter++
+ if (this.$refs.editor) this.$refs.editor.codemirror.refresh()
+ if (this.interval.counter >= 15) clearInterval(this.interval.id)
}
}
}
@@ -81,4 +93,17 @@ export default {
.dialog-title {
z-index: 1;
}
+
+.script-heading {
+ display: flex;
+ align-items: center;
+}
+
+.script-heading > span {
+ margin-left: 9px;
+}
+
+.script-editor {
+ margin-top: 8px;
+}
</style>
diff --git a/webapp/src/components/RegistrationModule.vue b/webapp/src/components/RegistrationModule.vue
index f9b857f..8ba3c58 100644
--- a/webapp/src/components/RegistrationModule.vue
+++ b/webapp/src/components/RegistrationModule.vue
@@ -55,12 +55,12 @@
<v-dialog
:value="dialog.show"
@input="setDialog({ show: $event })"
- :max-width="dialog.type === 'delete' ? '500px' : '1000px'"
+ :max-width="dialog.type === 'delete' ? '500px' : '1200px'"
scrollable
:persistent="dialog.type !== 'delete'"
>
- <registration-module-delete v-if="dialog.type === 'delete'" />
- <registration-module-edit v-else-if="dialog.type === 'edit'"/>
+ <registration-module-delete v-show="dialog.type === 'delete'" />
+ <registration-module-edit v-show="dialog.type === 'edit'"/>
</v-dialog>
</v-container>
</template>
diff --git a/webapp/src/components/RegistrationModuleEdit.vue b/webapp/src/components/RegistrationModuleEdit.vue
index 302cc2e..7adee37 100644
--- a/webapp/src/components/RegistrationModuleEdit.vue
+++ b/webapp/src/components/RegistrationModuleEdit.vue
@@ -48,7 +48,8 @@
deletable-chips
></v-autocomplete>
<v-textarea prepend-icon="description" rows="3" :label="$t('description')" color="primary" v-model="description"></v-textarea>
- <v-textarea prepend-icon="code" rows="20" :label="$t('script')" color="primary" v-model="script"></v-textarea>
+ <div class="body-1 script-heading"><v-icon>code</v-icon><span>{{ $t('script') }}</span></div>
+ <codemirror class="script-editor" ref="editor" v-model="script"></codemirror>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
@@ -72,7 +73,11 @@ export default {
type: '',
groups: [],
script: '',
- types: ['BASH', 'IPXE']
+ types: ['BASH', 'IPXE'],
+ interval: {
+ id: null,
+ counter: 0
+ }
}
},
computed: {
@@ -84,11 +89,13 @@ export default {
deep: true,
handler (value) {
if (value.type === 'edit' && value.show) {
- this.name = value.info.name
- this.description = value.info.description
+ this.name = value.info.name || ''
+ this.description = value.info.description || ''
this.type = value.info.type || 'BASH'
this.groups = value.info.groups ? value.info.groups.map(x => x.id) : []
- this.script = value.info.script
+ this.script = value.info.script || ''
+ this.interval.id = setInterval(this.refreshEditor, 50)
+ this.interval.counter = 0
}
}
}
@@ -107,6 +114,11 @@ export default {
})
this.$store.dispatch('registration/loadHooks')
this.setDialog({ show: false })
+ },
+ refreshEditor () {
+ this.interval.counter++
+ if (this.$refs.editor) this.$refs.editor.codemirror.refresh()
+ if (this.interval.counter >= 15) clearInterval(this.interval.id)
}
}
}
@@ -117,4 +129,17 @@ export default {
.dialog-title {
z-index: 1;
}
+
+.script-heading {
+ display: flex;
+ align-items: center;
+}
+
+.script-heading > span {
+ margin-left: 9px;
+}
+
+.script-editor {
+ margin-top: 8px;
+}
</style>
diff --git a/webapp/src/main.js b/webapp/src/main.js
index 4193481..030f9f7 100644
--- a/webapp/src/main.js
+++ b/webapp/src/main.js
@@ -1,6 +1,10 @@
import Vue from 'vue'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.min.css'
+import VueCodemirror from 'vue-codemirror'
+import 'codemirror/mode/shell/shell.js'
+import 'codemirror/lib/codemirror.css'
+import 'codemirror/theme/monokai.css'
import VueTouch from 'vue-touch'
import Vuex from 'vuex'
import globalStore from '@/store/global'
@@ -38,6 +42,15 @@ Vue.use(Vuetify, {
}
})
+Vue.use(VueCodemirror, {
+ options: {
+ theme: 'monokai',
+ mode: 'shell',
+ lineNumbers: true,
+ viewportMargin: Infinity
+ }
+})
+
Vue.use(VueTouch)
axios.interceptors.response.use(null, error => {