summaryrefslogtreecommitdiffstats
path: root/webapp
diff options
context:
space:
mode:
authorChristian Hofmaier2018-11-19 15:53:29 +0100
committerChristian Hofmaier2018-11-19 15:53:29 +0100
commit58e708e5dd2b3f8c14faba8f48f62792fbd206ab (patch)
treea1f76c92b4ec336d1a92bb531e70cf77a69faccd /webapp
parentmerge (diff)
parent[webapp/groups] add loading indicator to the group and client tables (diff)
downloadbas-58e708e5dd2b3f8c14faba8f48f62792fbd206ab.tar.gz
bas-58e708e5dd2b3f8c14faba8f48f62792fbd206ab.tar.xz
bas-58e708e5dd2b3f8c14faba8f48f62792fbd206ab.zip
merge
Diffstat (limited to 'webapp')
-rw-r--r--webapp/package-lock.json50
-rw-r--r--webapp/package.json14
-rw-r--r--webapp/src/components/BackendModule.vue2
-rw-r--r--webapp/src/components/ComponentSearchTable.vue5
-rw-r--r--webapp/src/components/ConfiguratorModuleConfig.vue2
-rw-r--r--webapp/src/components/GroupModuleClientList.vue5
-rw-r--r--webapp/src/components/GroupModuleGroupList.vue5
-rw-r--r--webapp/src/components/PermissionModule.vue2
-rw-r--r--webapp/src/components/RegistrationModule.vue137
-rw-r--r--webapp/src/components/RegistrationModuleDelete.vue63
-rw-r--r--webapp/src/components/RegistrationModuleEdit.vue120
-rw-r--r--webapp/src/components/SettingsModule.vue2
-rw-r--r--webapp/src/config/dashboard.js2
-rw-r--r--webapp/src/config/i18n.js2
-rw-r--r--webapp/src/config/store.js2
-rw-r--r--webapp/src/store/groups.js5
-rw-r--r--webapp/src/store/registration.js40
17 files changed, 420 insertions, 38 deletions
diff --git a/webapp/package-lock.json b/webapp/package-lock.json
index b97dd0d..4d73910 100644
--- a/webapp/package-lock.json
+++ b/webapp/package-lock.json
@@ -2221,9 +2221,9 @@
"dev": true
},
"copy-webpack-plugin": {
- "version": "4.5.2",
- "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.5.2.tgz",
- "integrity": "sha512-zmC33E8FFSq3AbflTvqvPvBo621H36Afsxlui91d+QyZxPIuXghfnTsa1CuqiAaCPgJoSUWfTFbKJnadZpKEbQ==",
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz",
+ "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==",
"dev": true,
"requires": {
"cacache": "^10.0.4",
@@ -6503,13 +6503,13 @@
}
},
"node-notifier": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz",
- "integrity": "sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz",
+ "integrity": "sha512-AhENzCSGZnZJgBARsUjnQ7DnZbzyP+HxlVXuD0xqAnvL8q+OqtSX7lGg9e8nHzwXkMMXNdVeqq4E2M3EUAqX6Q==",
"dev": true,
"requires": {
"growly": "^1.3.0",
- "semver": "^5.4.1",
+ "semver": "^5.5.0",
"shellwords": "^0.1.1",
"which": "^1.3.0"
}
@@ -7005,9 +7005,9 @@
"dev": true
},
"portfinder": {
- "version": "1.0.17",
- "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.17.tgz",
- "integrity": "sha512-syFcRIRzVI1BoEFOCaAiizwDolh1S1YXSodsVhncbhjzjZQulhczNRbqnUl9N31Q4dKGOXsNDqxC2BWBgSMqeQ==",
+ "version": "1.0.19",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.19.tgz",
+ "integrity": "sha512-23aeQKW9KgHe6citUrG3r9HjeX6vls0h713TAa+CwTKZwNIr/pD2ApaxYF4Um3ZZyq4ar+Siv3+fhoHaIwSOSw==",
"dev": true,
"requires": {
"async": "^1.5.2",
@@ -9969,9 +9969,9 @@
}
},
"semver": {
- "version": "5.5.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz",
- "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==",
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+ "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
"dev": true
},
"send": {
@@ -11046,9 +11046,9 @@
}
},
"url-loader": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.1.tgz",
- "integrity": "sha512-vugEeXjyYFBCUOpX+ZuaunbK3QXMKaQ3zUnRfIpRBlGkY7QizCnzyyn2ASfcxsvyU3ef+CJppVywnl3Kgf13Gg==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz",
+ "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==",
"dev": true,
"requires": {
"loader-utils": "^1.1.0",
@@ -11057,9 +11057,9 @@
},
"dependencies": {
"ajv": {
- "version": "6.5.3",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz",
- "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==",
+ "version": "6.5.5",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz",
+ "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==",
"dev": true,
"requires": {
"fast-deep-equal": "^2.0.1",
@@ -11323,9 +11323,9 @@
}
},
"vue2-hammer": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/vue2-hammer/-/vue2-hammer-1.0.6.tgz",
- "integrity": "sha512-MfRDkMdQoEng/BRe7moIDbiMgcPqgclVD3WqNfnQ6JlKtTOyMV/X5Z8/IEySa8QGHDVDOp9fI3WmwEoKxnZQ3g==",
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/vue2-hammer/-/vue2-hammer-1.0.7.tgz",
+ "integrity": "sha512-ClD5i3MEDhITE5Jmc1ZtTx6q8wJeymv13FWXlj9iDxORfajF0N4DT7j5Q4dIwEwT4lXzYtNh739cIUUCw5UjKA==",
"requires": {
"hammerjs": "^2.0.8"
}
@@ -11339,9 +11339,9 @@
}
},
"vuetify": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-1.2.3.tgz",
- "integrity": "sha512-ssMsLVwth62T4usPAFbn8yk69qqBDp4VWPmlY4XiYZ7aGMPoa/sQ08BlAeG8J81y+K60bY88FZ2gquQKlGqlsg=="
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-1.3.7.tgz",
+ "integrity": "sha512-EXKQggY+SPTBlmzmcFcNI6h/xdZLv6vr9VBcos8+kUumftIG7HDqqtFdRVNCco4EPrQgiG5sWDm5raM07NDvBg=="
},
"vuex": {
"version": "3.0.1",
diff --git a/webapp/package.json b/webapp/package.json
index a1a3ff9..bc4513b 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -16,9 +16,9 @@
"vue-i18n": "^7.8.1",
"vue-router": "^3.0.1",
"vue-touch": "^2.0.0-beta.4",
- "vue2-hammer": "^1.0.6",
+ "vue2-hammer": "^1.0.7",
"vuedraggable": "^2.16.0",
- "vuetify": "^1.2.3",
+ "vuetify": "^1.3.7",
"vuex": "^3.0.1"
},
"devDependencies": {
@@ -34,7 +34,7 @@
"babel-preset-env": "^1.3.2",
"babel-preset-stage-2": "^6.22.0",
"chalk": "^2.0.1",
- "copy-webpack-plugin": "^4.5.2",
+ "copy-webpack-plugin": "^4.6.0",
"css-loader": "^0.28.0",
"eslint": "^4.15.0",
"eslint-config-standard": "^10.2.1",
@@ -49,18 +49,18 @@
"file-loader": "^1.1.4",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.30.1",
- "node-notifier": "^5.1.2",
+ "node-notifier": "^5.3.0",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"ora": "^1.2.0",
- "portfinder": "^1.0.17",
+ "portfinder": "^1.0.19",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.1.6",
"postcss-url": "^7.2.1",
"rimraf": "^2.6.0",
- "semver": "^5.5.1",
+ "semver": "^5.6.0",
"shelljs": "^0.7.6",
"uglifyjs-webpack-plugin": "^1.3.0",
- "url-loader": "^1.1.1",
+ "url-loader": "^1.1.2",
"vue-loader": "^13.7.3",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.17",
diff --git a/webapp/src/components/BackendModule.vue b/webapp/src/components/BackendModule.vue
index c21ac42..874110c 100644
--- a/webapp/src/components/BackendModule.vue
+++ b/webapp/src/components/BackendModule.vue
@@ -83,7 +83,7 @@ export default {
data () {
return {
component: 'BackendModuleTable',
- tab: ''
+ tab: 0
}
},
methods: {
diff --git a/webapp/src/components/ComponentSearchTable.vue b/webapp/src/components/ComponentSearchTable.vue
index 30c3600..23aa071 100644
--- a/webapp/src/components/ComponentSearchTable.vue
+++ b/webapp/src/components/ComponentSearchTable.vue
@@ -61,6 +61,7 @@
:items="items"
:select-all="selectAll"
:item-key="itemKey"
+ :loading="loading"
v-bind="dataTableProps"
:value="value"
@input="$emit('input', $event)"
@@ -102,6 +103,10 @@ export default {
type: String,
default: () => 'id'
},
+ loading: {
+ type: Boolean,
+ default: () => false
+ },
dataTableProps: {
type: Object,
default: () => {}
diff --git a/webapp/src/components/ConfiguratorModuleConfig.vue b/webapp/src/components/ConfiguratorModuleConfig.vue
index 3e6abb4..5253086 100644
--- a/webapp/src/components/ConfiguratorModuleConfig.vue
+++ b/webapp/src/components/ConfiguratorModuleConfig.vue
@@ -20,7 +20,7 @@
"description": "Beschreibung",
"timeout": "Timeout",
"expertMode": "Expertenmodus",
- "script": "iPXE Script",
+ "script": "iPXE Skript",
"titleNew": "Konfiguration erstellen",
"titleExisting": "Konfiguration bearbeiten",
"entries": "Einträge",
diff --git a/webapp/src/components/GroupModuleClientList.vue b/webapp/src/components/GroupModuleClientList.vue
index f64563c..35819d5 100644
--- a/webapp/src/components/GroupModuleClientList.vue
+++ b/webapp/src/components/GroupModuleClientList.vue
@@ -28,7 +28,7 @@
<template>
<div>
<v-card>
- <component-search-table v-model="selected" :headers="headers" :items="clients" select-all>
+ <component-search-table v-model="selected" :headers="headers" :items="clients" select-all :loading="loading">
<template slot="items" slot-scope="row">
<tr :style="row.color" @click="row.data.selected = !row.data.selected" @dblclick="loadClient(row.data.item)">
<td class="narrow-td">
@@ -90,6 +90,9 @@ export default {
{ text: this.$t('uuid'), value: 'uuid' },
{ sortable: false }
]
+ },
+ loading () {
+ return this.$store.state.groups.tabChain[this.tabIndex].loading
}
},
watch: {
diff --git a/webapp/src/components/GroupModuleGroupList.vue b/webapp/src/components/GroupModuleGroupList.vue
index 1984ef8..896eeaa 100644
--- a/webapp/src/components/GroupModuleGroupList.vue
+++ b/webapp/src/components/GroupModuleGroupList.vue
@@ -24,7 +24,7 @@
<template>
<div>
<v-card>
- <component-search-table v-model="selected" :headers="headers" :items="groups" select-all>
+ <component-search-table v-model="selected" :headers="headers" :items="groups" select-all :loading="loading">
<template slot="items" slot-scope="row">
<tr :style="row.color" @click="row.data.selected = !row.data.selected" @dblclick="loadGroup(row.data.item)">
<td class="narrow-td">
@@ -82,6 +82,9 @@ export default {
{ text: this.$t('description'), value: 'description' },
{ sortable: false }
]
+ },
+ loading () {
+ return this.$store.state.groups.tabChain[this.tabIndex].loading
}
},
watch: {
diff --git a/webapp/src/components/PermissionModule.vue b/webapp/src/components/PermissionModule.vue
index 5abe7d6..26d4792 100644
--- a/webapp/src/components/PermissionModule.vue
+++ b/webapp/src/components/PermissionModule.vue
@@ -95,7 +95,7 @@ export default {
data () {
return {
components: ['PermissionModuleRoleList', 'PermissionModuleUserList'],
- tab: ''
+ tab: 0
}
},
computed: {
diff --git a/webapp/src/components/RegistrationModule.vue b/webapp/src/components/RegistrationModule.vue
new file mode 100644
index 0000000..f9b857f
--- /dev/null
+++ b/webapp/src/components/RegistrationModule.vue
@@ -0,0 +1,137 @@
+<i18n>
+{
+ "en": {
+ "hooks": "Registration hooks",
+ "createHook": "Create hook"
+ },
+ "de": {
+ "hooks": "Registrierungs Hooks ",
+ "createHook": "Hook erstellen"
+ }
+}
+</i18n>
+
+<template>
+ <v-container fill-height>
+ <v-layout>
+ <v-flex class="tabs-wrapper" xl10 offset-xl1 lg12>
+ <v-card>
+ <v-tabs v-model="tabs" centered :dark="tabsDark" :color="tabsColor" :slider-color="tabsSliderColor">
+ <v-tab>{{ $t('hooks') }}</v-tab>
+ </v-tabs>
+ </v-card>
+ <v-tabs-items v-model="tabs" style="padding-bottom: 20px">
+ <v-tab-item>
+ <v-subheader>{{ $t('hooks') }}</v-subheader>
+ <v-card v-if="hooks.length > 0">
+ <v-list two-line>
+ <draggable :value="hooks" @input="setHooks($event)" :options="{ handle:'.handle' }">
+ <v-list-tile v-for="hook in hooks" :key="hook.id" @click.stop @dblclick="editHook(hook)">
+ <v-list-tile-action class="handle">
+ <v-icon>drag_handle</v-icon>
+ </v-list-tile-action>
+ <v-list-tile-content>
+ <v-list-tile-title>{{ hook.name }}<small class="type">{{ hook.type }}</small></v-list-tile-title>
+ <v-list-tile-sub-title>{{ hook.description }}</v-list-tile-sub-title>
+ </v-list-tile-content>
+ <v-icon v-if="hook.groups.length > 0">device_hub</v-icon>
+ <v-list-tile-action>
+ <v-btn @click="editHook(hook)" icon><v-icon color="primary">edit</v-icon></v-btn>
+ </v-list-tile-action>
+ <v-list-tile-action class="delete">
+ <v-btn @click="deleteHook(hook)" icon><v-icon color="error">delete</v-icon></v-btn>
+ </v-list-tile-action>
+ </v-list-tile>
+ </draggable>
+ </v-list>
+ </v-card>
+ <div class="text-xs-right">
+ <v-btn flat color="success" @click="createHook"><v-icon left>create</v-icon>{{ $t('createHook') }}</v-btn>
+ </div>
+ </v-tab-item>
+ </v-tabs-items>
+ </v-flex>
+ </v-layout>
+ <v-dialog
+ :value="dialog.show"
+ @input="setDialog({ show: $event })"
+ :max-width="dialog.type === 'delete' ? '500px' : '1000px'"
+ scrollable
+ :persistent="dialog.type !== 'delete'"
+ >
+ <registration-module-delete v-if="dialog.type === 'delete'" />
+ <registration-module-edit v-else-if="dialog.type === 'edit'"/>
+ </v-dialog>
+ </v-container>
+</template>
+
+<script>
+import draggable from 'vuedraggable'
+import RegistrationModuleDelete from '@/components/RegistrationModuleDelete'
+import RegistrationModuleEdit from '@/components/RegistrationModuleEdit'
+import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
+
+export default {
+ name: 'RegistrationModule',
+ components: {
+ draggable,
+ RegistrationModuleDelete,
+ RegistrationModuleEdit
+ },
+ data () {
+ return {
+ tabs: 0
+ }
+ },
+ computed: {
+ ...mapGetters(['tabsDark', 'tabsColor', 'tabsSliderColor']),
+ ...mapState('registration', ['hooks', 'dialog'])
+ },
+ methods: {
+ ...mapMutations('registration', ['setDialog']),
+ ...mapActions('registration', ['setHooks']),
+ deleteHook (hook) {
+ this.setDialog({ show: true, type: 'delete', info: hook })
+ },
+ editHook (hook) {
+ this.setDialog({ show: true, type: 'edit', info: hook })
+ },
+ createHook () {
+ this.setDialog({ show: true, type: 'edit', info: {} })
+ }
+ },
+ created () {
+ this.$store.dispatch('registration/loadGroupList')
+ this.$store.dispatch('registration/loadHooks')
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.handle {
+ margin-left: 12px;
+}
+.delete {
+ margin-right: 12px;
+}
+.type {
+ margin-left: 24px;
+}
+.hook-info {
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+}
+.hook-info > .hook-type {
+ min-width: 60px;
+}
+.hook-info > .hook-name {
+ white-space: nowrap;
+}
+.hook-info > .hook-description {
+ margin-left: 40px;
+ overflow: hidden;
+ white-space: nowrap;
+}
+</style>
diff --git a/webapp/src/components/RegistrationModuleDelete.vue b/webapp/src/components/RegistrationModuleDelete.vue
new file mode 100644
index 0000000..002e629
--- /dev/null
+++ b/webapp/src/components/RegistrationModuleDelete.vue
@@ -0,0 +1,63 @@
+<i18n>
+{
+ "en": {
+ "title": "Delete this hook?"
+ },
+ "de": {
+ "title": "Diesen Hook löschen?"
+ }
+}
+</i18n>
+
+<template>
+ <v-card>
+ <v-card-title primary-title class="dialog-title elevation-3">
+ <div class="headline">{{ $t('title') }}</div>
+ </v-card-title>
+ <v-card-text>
+ {{ dialog.info.type }} {{ dialog.info.name }}
+ </v-card-text>
+ <v-divider></v-divider>
+ <v-card-actions>
+ <v-spacer></v-spacer>
+ <v-btn flat="flat" @click="setDialog({ show: false })">{{ $t('cancel') }}</v-btn>
+ <v-btn color="error" @click="deleteItems">{{ $t('delete') }}</v-btn>
+ </v-card-actions>
+ </v-card>
+</template>
+
+<script>
+import axios from 'axios'
+import { mapState } from 'vuex'
+
+export default {
+ name: 'RegistrationModuleDelete',
+ data () {
+ return {
+ }
+ },
+ computed: {
+ ...mapState('registration', ['dialog'])
+ },
+ methods: {
+ setDialog (data) {
+ this.$store.commit('registration/setDialog', data)
+ },
+ async deleteItems () {
+ await axios.delete('/api/registrations/hooks/' + this.dialog.info.id)
+ this.$store.dispatch('registration/loadHooks')
+ this.setDialog({ show: false })
+ }
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.dialog-title {
+ z-index: 1;
+}
+.selected-list {
+ padding: 30px;
+}
+</style>
diff --git a/webapp/src/components/RegistrationModuleEdit.vue b/webapp/src/components/RegistrationModuleEdit.vue
new file mode 100644
index 0000000..302cc2e
--- /dev/null
+++ b/webapp/src/components/RegistrationModuleEdit.vue
@@ -0,0 +1,120 @@
+<i18n>
+{
+ "en": {
+ "name": "Name",
+ "description": "Description",
+ "type": "Script type",
+ "groups": "Groups",
+ "script": "Script",
+ "titleNew": "Create hook",
+ "titleExisting": "Edit hook"
+ },
+ "de": {
+ "name": "Name",
+ "description": "Beschreibung",
+ "type": "Skript Art",
+ "groups": "Gruppen",
+ "script": "Skript",
+ "titleNew": "Hook erstellen",
+ "titleExisting": "Hook bearbeiten"
+ }
+}
+</i18n>
+
+<template>
+ <v-card>
+ <v-card-title primary-title class="dialog-title elevation-3">
+ <div class="headline">{{ dialog.info.id ? $t('titleExisting') : $t('titleNew') }}</div>
+ </v-card-title>
+ <v-card-text>
+ <v-layout row wrap>
+ <v-flex xs12 sm9>
+ <v-text-field prepend-icon="label" :label="$t('name')" color="primary" v-model="name"></v-text-field>
+ </v-flex>
+ <v-flex xs12 sm2 offset-sm1>
+ <v-select prepend-icon="label" color="primary" :items="types" :label="$t('type')" v-model="type" menu-props="offsetY"></v-select>
+ </v-flex>
+ </v-layout>
+ <v-autocomplete
+ prepend-icon="device_hub"
+ :items="groupList"
+ v-model="groups"
+ :label="$t('groups')"
+ color="primary"
+ multiple
+ item-value="id"
+ item-text="name"
+ small-chips
+ 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>
+ </v-card-text>
+ <v-divider></v-divider>
+ <v-card-actions>
+ <v-spacer></v-spacer>
+ <v-btn flat="flat" @click="setDialog({ show: false })">{{ $t('cancel') }}</v-btn>
+ <v-btn :color="dialog.info.id ? 'primary' : 'success'" @click="saveHook">{{ dialog.info.id ? $t('save') : $t('create') }}</v-btn>
+ </v-card-actions>
+ </v-card>
+</template>
+
+<script>
+import axios from 'axios'
+import { mapState } from 'vuex'
+
+export default {
+ name: 'RegistrationModuleEdit',
+ data () {
+ return {
+ name: '',
+ description: '',
+ type: '',
+ groups: [],
+ script: '',
+ types: ['BASH', 'IPXE']
+ }
+ },
+ computed: {
+ ...mapState('registration', ['dialog', 'groupList'])
+ },
+ watch: {
+ dialog: {
+ immediate: true,
+ deep: true,
+ handler (value) {
+ if (value.type === 'edit' && value.show) {
+ 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
+ }
+ }
+ }
+ },
+ methods: {
+ setDialog (data) {
+ this.$store.commit('registration/setDialog', data)
+ },
+ async saveHook () {
+ await axios.post('/api/registrations/hooks/' + this.dialog.info.id, {
+ name: this.name,
+ description: this.description,
+ type: this.type,
+ groups: this.groups,
+ script: this.script
+ })
+ this.$store.dispatch('registration/loadHooks')
+ this.setDialog({ show: false })
+ }
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.dialog-title {
+ z-index: 1;
+}
+</style>
diff --git a/webapp/src/components/SettingsModule.vue b/webapp/src/components/SettingsModule.vue
index ed23cc9..642e52a 100644
--- a/webapp/src/components/SettingsModule.vue
+++ b/webapp/src/components/SettingsModule.vue
@@ -74,7 +74,7 @@ export default {
data () {
return {
langChoices: [ { text: 'Deutsch', value: 'de' }, { text: 'English', value: 'en' } ],
- tab: ''
+ tab: 0
}
},
computed: {
diff --git a/webapp/src/config/dashboard.js b/webapp/src/config/dashboard.js
index 44c894f..a092cdc 100644
--- a/webapp/src/config/dashboard.js
+++ b/webapp/src/config/dashboard.js
@@ -1,11 +1,13 @@
import GroupModule from '@/components/GroupModule'
import ConfiguratorModule from '@/components/ConfiguratorModule'
+import RegistrationModule from '@/components/RegistrationModule'
import BackendModule from '@/components/BackendModule'
import PermissionModule from '@/components/PermissionModule'
export default [
{ path: 'groups', component: GroupModule, icon: 'category' },
{ path: 'configurator', component: ConfiguratorModule, icon: 'list' },
+ { path: 'registration', component: RegistrationModule, icon: 'assignment' },
{ path: 'backends', component: BackendModule, icon: 'cloud' },
{ path: 'permissions', component: PermissionModule, icon: 'lock_open' }
]
diff --git a/webapp/src/config/i18n.js b/webapp/src/config/i18n.js
index 91f8a79..818f57c 100644
--- a/webapp/src/config/i18n.js
+++ b/webapp/src/config/i18n.js
@@ -25,6 +25,7 @@ export default {
'$dashboardModules': {
'GroupModule': 'Groups / Clients',
'ConfiguratorModule': 'iPXE Configurator',
+ 'RegistrationModule': 'Client Registration',
'BackendModule': 'External Backends',
'PermissionModule': 'Permission Manager'
}
@@ -55,6 +56,7 @@ export default {
'$dashboardModules': {
'GroupModule': 'Gruppen / Clienten',
'ConfiguratorModule': 'iPXE Konfigurator',
+ 'RegistrationModule': 'Client Registrierung',
'BackendModule': 'Externe Backends',
'PermissionModule': 'Rechteverwaltung'
}
diff --git a/webapp/src/config/store.js b/webapp/src/config/store.js
index ca6b01f..710a07b 100644
--- a/webapp/src/config/store.js
+++ b/webapp/src/config/store.js
@@ -1,11 +1,13 @@
import groups from '@/store/groups'
import configurator from '@/store/configurator'
+import registration from '@/store/registration'
import backends from '@/store/backends'
import permissions from '@/store/permissions'
export default {
groups,
configurator,
+ registration,
backends,
permissions
}
diff --git a/webapp/src/store/groups.js b/webapp/src/store/groups.js
index 12eea4f..1bbded9 100644
--- a/webapp/src/store/groups.js
+++ b/webapp/src/store/groups.js
@@ -1,3 +1,4 @@
+import Vue from 'vue'
import axios from 'axios'
export default {
@@ -34,6 +35,9 @@ export default {
}
state.tabChain.splice(index, 1, item)
},
+ setTabLoading (state, index) {
+ if (state.tabChain.length > index) Vue.set(state.tabChain[index], 'loading', true)
+ },
setDialog (state, { show, info }) {
if (info !== undefined) state.dialog.info = info
if (show !== undefined) state.dialog.show = show
@@ -61,6 +65,7 @@ export default {
if (context.state.tabChain.length <= tabIndex || context.state.tabChain[tabIndex].id !== id) {
context.commit('setTab', { index: tabIndex, item: { id, name, tabType: 'group', tabShowAll: showAll, subgroups: [], clients: [] } })
}
+ context.commit('setTabLoading', tabIndex)
if (switchTab) context.commit('setActiveTab', tabIndex)
axios.get('/api/groups/getGroup?id=' + id + (showAll ? '&all=true' : '')).then(res => {
res.data.tabType = 'group'
diff --git a/webapp/src/store/registration.js b/webapp/src/store/registration.js
new file mode 100644
index 0000000..388558d
--- /dev/null
+++ b/webapp/src/store/registration.js
@@ -0,0 +1,40 @@
+import axios from 'axios'
+
+export default {
+ namespaced: true,
+ state: {
+ hooks: [],
+ groupList: [],
+ dialog: {
+ show: false,
+ type: null,
+ info: {}
+ }
+ },
+ mutations: {
+ setHooks (state, hooks) { state.hooks = hooks },
+ setGroupList (state, groupList) { state.groupList = groupList },
+ setDialog (state, { show, type, info }) {
+ if (info !== undefined) state.dialog.info = info
+ if (type !== undefined) state.dialog.type = type
+ if (show !== undefined) state.dialog.show = show
+ }
+ },
+ actions: {
+ loadHooks (context) {
+ axios.get('/api/registrations/hooks').then(result => {
+ context.commit('setHooks', result.data)
+ })
+ },
+ loadGroupList (context) {
+ axios.get('/api/groups/getList').then(result => {
+ context.commit('setGroupList', result.data)
+ })
+ },
+ setHooks (context, hooks) {
+ axios.post('/api/registrations/hookorder', { ids: hooks.map(x => x.id) }).then(result => {
+ context.commit('setHooks', hooks)
+ })
+ }
+ }
+}