summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUdo Walter2019-10-24 16:40:41 +0200
committerUdo Walter2019-10-24 16:40:41 +0200
commit0dcbc17552e4f99692ad9daa793b78909e497b32 (patch)
tree6061fb4f0218ed93298845aa07a120c1f011eeb9
parent[configloader] new confighelper and test api to get a priority list of loaded... (diff)
downloadbas-0dcbc17552e4f99692ad9daa793b78909e497b32.tar.gz
bas-0dcbc17552e4f99692ad9daa793b78909e497b32.tar.xz
bas-0dcbc17552e4f99692ad9daa793b78909e497b32.zip
[groups] Add first implementation of the new config path ui
-rw-r--r--server/api/configloader.js18
-rw-r--r--server/lib/confighelper.js39
-rw-r--r--webapp/src/components/ConfigChip.vue98
-rw-r--r--webapp/src/components/GroupModuleClientView.vue86
-rw-r--r--webapp/src/components/GroupModuleGroupInfo.vue54
-rw-r--r--webapp/src/store/groups.js6
6 files changed, 253 insertions, 48 deletions
diff --git a/server/api/configloader.js b/server/api/configloader.js
index 4059e5b..f6c4597 100644
--- a/server/api/configloader.js
+++ b/server/api/configloader.js
@@ -9,8 +9,21 @@ const url = config.https.host + ':' + config.https.port
const configHelper = require(path.join(__appdir, 'lib', 'confighelper'))
-// if client in db -> load script (default if none is found), else load registration script
-noAuthRouter.getAsync('/test/:uuid', async (req, res) => {
+
+noAuthRouter.getAsync(['/test/group/:id', '/test/group/'], async (req, res) => {
+ const list = req.query.list !== undefined && req.query.list !== 'false'
+ const config = await configHelper.getGroupConfig(req.params.id, list)
+ if (!config) return res.status(404).end()
+ if (!list) {
+ res.set('Content-Type', 'text/plain')
+ res.send(config.script)
+ } else {
+ res.send(config)
+ }
+})
+
+
+noAuthRouter.getAsync(['/test/:uuid', '/test/'], async (req, res) => {
const list = req.query.list !== undefined && req.query.list !== 'false'
const config = await configHelper.getConfig(req.params.uuid, list)
if (!list) {
@@ -21,6 +34,7 @@ noAuthRouter.getAsync('/test/:uuid', async (req, res) => {
}
})
+
// if client in db -> load script (default if none is found), else load registration script
noAuthRouter.getAsync('/:uuid', async (req, res) => {
const uuid = req.params.uuid
diff --git a/server/lib/confighelper.js b/server/lib/confighelper.js
index 2771596..0e152a8 100644
--- a/server/lib/confighelper.js
+++ b/server/lib/confighelper.js
@@ -8,12 +8,12 @@ const url = config.https.host + ':' + config.https.port
async function getConfig (uuid, list) {
- const client = await db.client.findOne({ where: { uuid: uuid }, include: ['groups', 'events'] })
+ const client = await db.client.findOne({ where: { uuid: uuid } })
let configPath = []
// client not known, start registration
if (client === null) {
- let config = { id: 'REGISTRATION', name: 'Registration Script' }
+ let config = { id: 'REGISTRATION', name: 'Client Registration' }
if (!list) {
config.script = fs.readFileSync(path.join(__appdir, 'ipxe', 'registration.ipxe'), 'utf8')
return config
@@ -49,7 +49,35 @@ async function getConfig (uuid, list) {
else if (eventList.length) return eventList[0]
else if (configList.length) return configList[0]
} else {
- configPath = configPath.concat(importantList, eventList, configList)
+ configPath.push(...importantList, ...eventList, ...configList)
+ }
+
+ // No config found, use default config
+ let config = await _prepareConfig({ id: 'DEFAULT', source: { type: 'DEFAULT' } })
+ if (!list) return config
+
+ configPath.push(config)
+ return configPath
+}
+
+
+async function getGroupConfig (groupId, list) {
+ const group = await db.group.findOne({ where: { id: groupId } })
+ if (!group) return
+ let configPath = []
+
+ // Check for event or direct configs
+ let importantList = []
+ let eventList = []
+ let configList = []
+ await _checkParentConfigs([group.id], importantList, eventList, configList, !list)
+
+ if (!list) {
+ if (importantList.length) return importantList[0]
+ else if (eventList.length) return eventList[0]
+ else if (configList.length) return configList[0]
+ } else {
+ configPath.push(...importantList, ...eventList, ...configList)
}
// No config found, use default config
@@ -183,6 +211,8 @@ async function _createDynamicMenu (configInfos, noScript) {
const ids = []
const idSourceMap = {}
+ console.log(configInfos)
+
configInfos.forEach(configInfo => {
ids.push(configInfo.id)
idSourceMap[configInfo.id] = configInfo.source
@@ -192,6 +222,7 @@ async function _createDynamicMenu (configInfos, noScript) {
const result = {
merged: true,
id: JSON.stringify(configs.map(x => x.id)),
+ name: configs.map(x => x.name).join(' + '),
configs: configs.map(x => ({ id: x.id, name: x.name, source: idSourceMap[x.id] }))
}
if (noScript) return result
@@ -224,4 +255,4 @@ async function _createDynamicMenu (configInfos, noScript) {
}
-module.exports = { getConfig } \ No newline at end of file
+module.exports = { getConfig, getGroupConfig } \ No newline at end of file
diff --git a/webapp/src/components/ConfigChip.vue b/webapp/src/components/ConfigChip.vue
new file mode 100644
index 0000000..f278fe3
--- /dev/null
+++ b/webapp/src/components/ConfigChip.vue
@@ -0,0 +1,98 @@
+<i18n>
+{
+ "en": {
+ "assigned": "Assigned",
+ "active": "Active",
+ "source": "Source",
+ "id": "ID",
+ "name": "Name"
+ },
+ "de": {
+ "assigned": "Zugewiesen",
+ "active": "Aktiv",
+ "source": "Quelle",
+ "id": "ID",
+ "name": "Name"
+ }
+}
+</i18n>
+
+<template>
+ <v-tooltip top open-delay="200">
+ <template #activator="{ on }">
+ <v-chip v-on="on" small :color="color" :text-color="color ? 'white' : ''" :label="isEvent">
+ <span class="chip-text">{{ config.name || config.id }}</span>
+ </v-chip>
+ </template>
+ <div>
+ <div v-if="active" class="success--text" style="text-align: center; font-weight: bold; font-size: 1.2em">{{ $t('active') }}</div>
+ <div v-if="assigned" class="primary--text" style="text-align: center; font-weight: bold; font-size: 1.2em">{{ $t('assigned') }}</div>
+ <div v-if="config.source">
+ <table>
+ <tr><td class="config-source-key">{{ $t('source') }}</td><td>{{ config.source.type }}</td></tr>
+ <tr v-if="config.source.id"><td class="config-source-key">{{ $t('id') }}</td><td>{{ config.source.id }}</td></tr>
+ <tr v-if="config.source.name"><td class="config-source-key">{{ $t('name') }}</td><td>{{ config.source.name }}</td></tr>
+ </table>
+ </div>
+ <div v-else-if="config.configs">
+ <div v-for="(subConfig, index) in config.configs" :key="subConfig.id">
+ <v-divider v-if="index > 0" style="margin-bottom: 4px"></v-divider>
+ <div style="text-align: center; font-weight: bold;">[{{ subConfig.id}}] {{ subConfig.name }}</div>
+ <table>
+ <tr><td class="config-source-key">{{ $t('source') }}</td><td>{{ subConfig.source.type }}</td></tr>
+ <tr v-if="subConfig.source.id"><td class="config-source-key">{{ $t('id') }}</td><td>{{ subConfig.source.id }}</td></tr>
+ <tr v-if="subConfig.source.name"><td class="config-source-key">{{ $t('name') }}</td><td>{{ subConfig.source.name }}</td></tr>
+ </table>
+ </div>
+ </div>
+ <span v-else>{{ config.name || config.id }}</span>
+ </div>
+ </v-tooltip>
+</template>
+
+<script>
+
+export default {
+ name: 'ConfigChip',
+ props: {
+ config: {
+ type: Object,
+ default: () => {}
+ },
+ active: {
+ type: Boolean,
+ default: false
+ },
+ assigned: {
+ type: Boolean,
+ default: false
+ }
+ },
+ data () {
+ return {
+ }
+ },
+ computed: {
+ color () {
+ if (this.assigned) return 'primary'
+ if (this.active) return 'success'
+ return ''
+ },
+ isEvent () {
+ return this.config.source && (this.config.source.type === 'IMPORTANT_EVENT' || this.config.source.type === 'EVENT')
+ }
+ },
+ methods: {
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.config-source-key {
+ vertical-align: top;
+ font-weight: bold;
+ text-align: right;
+ padding-right: 16px;
+}
+</style>
diff --git a/webapp/src/components/GroupModuleClientView.vue b/webapp/src/components/GroupModuleClientView.vue
index fae52fe..db8a2c6 100644
--- a/webapp/src/components/GroupModuleClientView.vue
+++ b/webapp/src/components/GroupModuleClientView.vue
@@ -26,6 +26,13 @@
<template>
<div>
<v-card style="margin-top: 24px">
+ <div class="header-div">
+ <div class="header-div-text">
+ <v-icon class="mr-2">list_alt</v-icon>
+ <span>Info</span>
+ </div>
+ </div>
+ <v-divider></v-divider>
<v-card-text>
<v-layout wrap>
<v-flex lg4 sm6 xs12 order-lg1 order-xs2>
@@ -60,27 +67,10 @@
</div>
</div>
</v-flex>
- <v-flex>
- <div class="info-box">
- <div class="body-2 info-heading"><v-icon>list</v-icon><span>{{ $t('config') }}</span></div>
- <div class="info-text">
- <v-select v-if="editMode"
- class="info-input"
- clearable
- item-text="name"
- item-value="id"
- :menu-props="{ offsetY: '' }"
- hide-details
- color="primary"
- v-model="info.configId"
- :items="configList"
- ></v-select>
- <div v-else>{{ client.config ? (client.config.name || client.config.id) : '-' }}</div>
- </div>
- </div>
- </v-flex>
+
</v-layout>
</v-flex>
+
<v-flex lg4 sm6 xs12 order-lg2 order-xs3>
<div class="info-box">
<div class="body-2 info-heading"><v-icon>description</v-icon><span>{{ $t('description') }}</span></div>
@@ -109,6 +99,39 @@
</div>
</v-flex>
</v-layout>
+
+ <v-layout>
+ <v-flex :lg4="editMode" :sm6="editMode" :xs12="editMode">
+ <div class="info-box">
+ <div class="body-2 info-heading"><v-icon>list</v-icon><span>{{ $t('config') }}</span></div>
+ <div class="info-text">
+ <v-select v-if="editMode"
+ class="info-input"
+ clearable
+ item-text="name"
+ item-value="id"
+ :menu-props="{ offsetY: '' }"
+ hide-details
+ color="primary"
+ v-model="info.configId"
+ :items="configList"
+ ></v-select>
+ <div v-else style="display: flex">
+ <template v-for="(config, index) in client.configPath">
+ <v-icon :key="index + 'icon'" v-if="index" style="margin: 0 -6px">keyboard_arrow_left</v-icon>
+ <config-chip
+ :key="index"
+ :config="config"
+ :assigned="config.source && config.source.type === 'CLIENT' && config.source.id === client.id"
+ :active="index === 0"
+ ></config-chip>
+ </template>
+ </div>
+ </div>
+ </div>
+ </v-flex>
+ </v-layout>
+
<v-layout wrap>
<v-flex lg4 sm6 xs12>
<div class="info-box">
@@ -145,6 +168,7 @@
<script>
import SelectBox from '@/components/SelectBox'
+import ConfigChip from '@/components/ConfigChip'
import { mapState, mapMutations } from 'vuex'
export default {
@@ -159,7 +183,8 @@ export default {
}
},
components: {
- SelectBox
+ SelectBox,
+ ConfigChip
},
data () {
return {
@@ -234,6 +259,10 @@ export default {
},
openGroup (group) {
this.$store.dispatch('groups/loadGroup', { id: group.id, name: group.name, tabIndex: this.tabIndex, asParent: true, switchTab: true })
+ },
+ getConfigChipColor (index, config) {
+ if (config.source && config.source.type === 'CLIENT' && config.source.id === this.client.id) return 'primary'
+ if (index === 0) return 'success'
}
},
created () {
@@ -244,8 +273,21 @@ export default {
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
-.info-buttons {
- margin: 0;
+.header-div {
+ user-select: none;
+ padding-left: 16px;
+ height: 48px;
+ font-weight: bold;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.header-div > .header-div-text {
+ flex: 1;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
}
.chip-container {
diff --git a/webapp/src/components/GroupModuleGroupInfo.vue b/webapp/src/components/GroupModuleGroupInfo.vue
index 141fd13..bcefe7f 100644
--- a/webapp/src/components/GroupModuleGroupInfo.vue
+++ b/webapp/src/components/GroupModuleGroupInfo.vue
@@ -67,25 +67,6 @@
</div>
</div>
</v-flex>
- <v-flex>
- <div class="info-box">
- <div class="body-2 info-heading"><v-icon>list</v-icon><span>{{ $t('config') }}</span></div>
- <div class="info-text">
- <v-select v-if="editMode"
- class="info-input"
- clearable
- item-text="name"
- item-value="id"
- :menu-props="{ offsetY: '' }"
- hide-details
- color="primary"
- v-model="info.configId"
- :items="configList"
- ></v-select>
- <div v-else>{{ group.config ? (group.config.name || group.config.id) : '-' }}</div>
- </div>
- </div>
- </v-flex>
</v-layout>
</v-flex>
<v-flex lg4 sm6 xs12 order-lg2 order-xs3>
@@ -146,12 +127,44 @@
</div>
</v-flex>
</v-layout>
+ <v-layout>
+ <v-flex :lg4="editMode" :sm6="editMode" :xs12="editMode">
+ <div class="info-box">
+ <div class="body-2 info-heading"><v-icon>list</v-icon><span>{{ $t('config') }}</span></div>
+ <div class="info-text">
+ <v-select v-if="editMode"
+ class="info-input"
+ clearable
+ item-text="name"
+ item-value="id"
+ :menu-props="{ offsetY: '' }"
+ hide-details
+ color="primary"
+ v-model="info.configId"
+ :items="configList"
+ ></v-select>
+ <div v-else style="display: flex">
+ <template v-for="(config, index) in group.configPath">
+ <v-icon :key="index + 'icon'" v-if="index" style="margin: 0 -6px">keyboard_arrow_left</v-icon>
+ <config-chip
+ :key="index"
+ :config="config"
+ :assigned="config.source && config.source.type === 'GROUP' && config.source.id === group.id"
+ :active="index === 0"
+ ></config-chip>
+ </template>
+ </div>
+ </div>
+ </div>
+ </v-flex>
+ </v-layout>
</v-card-text>
</div>
</template>
<script>
import SelectBox from '@/components/SelectBox'
+import ConfigChip from '@/components/ConfigChip'
import { mapState, mapMutations } from 'vuex'
export default {
@@ -166,7 +179,8 @@ export default {
}
},
components: {
- SelectBox
+ SelectBox,
+ ConfigChip
},
data () {
return {
diff --git a/webapp/src/store/groups.js b/webapp/src/store/groups.js
index 7948e31..6c349f8 100644
--- a/webapp/src/store/groups.js
+++ b/webapp/src/store/groups.js
@@ -102,6 +102,10 @@ export default {
res.data.subgroups = Object.freeze(res.data.subgroups)
res.data.gotoInfo = asParent || gotoInfo
res.data.autoGoto = autoGoto
+ if (id > 0) {
+ const configRes = await axios.get('/api/configloader/test/group/' + id + '?list')
+ res.data.configPath = configRes.data
+ }
context.commit('setTab', { index: tabIndex, item: res.data })
} catch (e) {
if (switchTab) context.commit('setActiveTab', srcTabIndex)
@@ -117,6 +121,8 @@ export default {
try {
const res = await axios.get('/api/clients/' + id)
res.data.tabType = 'client'
+ const configRes = await axios.get('/api/configloader/test/' + (res.data.uuid || '') + '?list')
+ res.data.configPath = configRes.data
context.commit('setTab', { index: tabIndex, item: res.data })
} catch (e) {
if (switchTab) context.commit('setActiveTab', srcTabIndex)