summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/api/clients.js18
-rw-r--r--server/api/groups.js40
-rw-r--r--server/api/locations.js13
-rw-r--r--server/migrations/20180717132233-create-group.js19
-rw-r--r--server/migrations/20180717132333-create-client.js28
-rw-r--r--server/migrations/20180717202333-create-group_x_group.js28
-rw-r--r--server/migrations/20180717202533-create-group_x_client.js28
-rw-r--r--server/models/client.js22
-rw-r--r--server/models/group.js19
-rw-r--r--server/router.js8
-rw-r--r--webapp/config/index.js2
-rw-r--r--webapp/src/assets/styles.css11
-rw-r--r--webapp/src/components/ComponentTemplate.vue2
-rw-r--r--webapp/src/components/GroupModule.vue61
-rw-r--r--webapp/src/components/GroupModuleClientList.vue70
-rw-r--r--webapp/src/components/GroupModuleEdit.vue79
-rw-r--r--webapp/src/components/GroupModuleGroupList.vue75
-rw-r--r--webapp/src/components/GroupModuleGroupView.vue62
18 files changed, 551 insertions, 34 deletions
diff --git a/server/api/clients.js b/server/api/clients.js
index f7fe455..aeb4673 100644
--- a/server/api/clients.js
+++ b/server/api/clients.js
@@ -4,15 +4,15 @@ var db = require(path.join(__appdir, 'lib', 'sequelize'))
module.exports = {
get: function (req, res) {
- // db.sequelize.authenticate()
- // .then(() => { console.log('Connection has been established successfully.'); })
- // .catch(err => { console.error('Unable to connect to the database:', err); });
-
- // db.users2.create({ username: "wasd", password: "wasd", email: "w@a.de", name: "wa"});
- db.users2.findOne({ where: { username: 'wasd' } }).then(user => {
- console.log(user.get('username'))
- })
- res.end()
+ switch (req.query.action) {
+ case 'getInfo':
+ db.client.findOne({ where: { id: req.query.id }}).then(client => {
+ res.send(client)
+ })
+ break
+ default:
+ res.end()
+ }
},
post: function (req, res) {
diff --git a/server/api/groups.js b/server/api/groups.js
new file mode 100644
index 0000000..2d1182b
--- /dev/null
+++ b/server/api/groups.js
@@ -0,0 +1,40 @@
+/* global __appdir */
+var path = require('path')
+var db = require(path.join(__appdir, 'lib', 'sequelize'))
+
+module.exports = {
+ get: function (req, res) {
+ var id = req.query.id > 0 ? req.query.id : null
+ switch (req.query.action) {
+ case 'getInfo':
+ db.group.findOne({ where: { id: req.query.id }}).then(group => {
+ res.send(group)
+ })
+ break
+ case 'getSubGroups':
+ db.group.findAll({ where: { '$parents.id$': id }, include: ['parents'] }).then(result => {
+ res.send(result)
+ })
+ break
+ case 'getClients':
+ db.client.findAll({ where: { '$groups.id$': id }, include: ['groups'] }).then(result => {
+ res.send(result)
+ })
+ break
+ default:
+ res.end()
+ }
+ },
+ post: function (req, res) {
+ var id = req.body.id > 0 ? req.body.id : null
+ switch (req.body.action) {
+ case 'setInfo':
+ if (!id) res.end()
+ db.group.update({ name: req.body.name }, { where: { id: id } })
+ res.end()
+ break
+ default:
+ res.end()
+ }
+ }
+}
diff --git a/server/api/locations.js b/server/api/locations.js
deleted file mode 100644
index 7595837..0000000
--- a/server/api/locations.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// /* global __appdir */
-// var path = require('path');
-
-module.exports = {
- get: function (req, res) {
- console.log('You successfully called an authentication call!')
- res.send('You successfully called an authentication call!')
- },
- post: function (req, res) {
- console.log('You successfully called an unauthentication call!')
- res.send('You successfully called an unauthentication call!')
- }
-}
diff --git a/server/migrations/20180717132233-create-group.js b/server/migrations/20180717132233-create-group.js
new file mode 100644
index 0000000..720a1e7
--- /dev/null
+++ b/server/migrations/20180717132233-create-group.js
@@ -0,0 +1,19 @@
+'use strict'
+module.exports = {
+ up: (queryInterface, Sequelize) => {
+ return queryInterface.createTable('groups', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER
+ },
+ name: {
+ type: Sequelize.STRING
+ }
+ })
+ },
+ down: (queryInterface, Sequelize) => {
+ return queryInterface.dropTable('groups')
+ }
+}
diff --git a/server/migrations/20180717132333-create-client.js b/server/migrations/20180717132333-create-client.js
new file mode 100644
index 0000000..79552c4
--- /dev/null
+++ b/server/migrations/20180717132333-create-client.js
@@ -0,0 +1,28 @@
+'use strict'
+module.exports = {
+ up: (queryInterface, Sequelize) => {
+ return queryInterface.createTable('clients', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER
+ },
+ name: {
+ type: Sequelize.STRING
+ },
+ ip: {
+ type: Sequelize.STRING
+ },
+ mac: {
+ type: Sequelize.STRING
+ },
+ uuid: {
+ type: Sequelize.STRING
+ }
+ })
+ },
+ down: (queryInterface, Sequelize) => {
+ return queryInterface.dropTable('clients')
+ }
+}
diff --git a/server/migrations/20180717202333-create-group_x_group.js b/server/migrations/20180717202333-create-group_x_group.js
new file mode 100644
index 0000000..4263f9a
--- /dev/null
+++ b/server/migrations/20180717202333-create-group_x_group.js
@@ -0,0 +1,28 @@
+'use strict'
+module.exports = {
+ up: (queryInterface, Sequelize) => {
+ return queryInterface.createTable('group_x_group', {
+ parentId: {
+ primaryKey: true,
+ allowNull: false,
+ type: Sequelize.INTEGER,
+ references: {
+ model: 'groups',
+ key: 'id'
+ }
+ },
+ childId: {
+ primaryKey: true,
+ allowNull: false,
+ type: Sequelize.INTEGER,
+ references: {
+ model: 'groups',
+ key: 'id'
+ }
+ }
+ })
+ },
+ down: (queryInterface, Sequelize) => {
+ return queryInterface.dropTable('group_x_group')
+ }
+}
diff --git a/server/migrations/20180717202533-create-group_x_client.js b/server/migrations/20180717202533-create-group_x_client.js
new file mode 100644
index 0000000..e3bd490
--- /dev/null
+++ b/server/migrations/20180717202533-create-group_x_client.js
@@ -0,0 +1,28 @@
+'use strict'
+module.exports = {
+ up: (queryInterface, Sequelize) => {
+ return queryInterface.createTable('group_x_client', {
+ groupId: {
+ primaryKey: true,
+ allowNull: false,
+ type: Sequelize.INTEGER,
+ references: {
+ model: 'groups',
+ key: 'id'
+ }
+ },
+ clientId: {
+ primaryKey: true,
+ allowNull: false,
+ type: Sequelize.INTEGER,
+ references: {
+ model: 'clients',
+ key: 'id'
+ }
+ }
+ })
+ },
+ down: (queryInterface, Sequelize) => {
+ return queryInterface.dropTable('group_x_client')
+ }
+}
diff --git a/server/models/client.js b/server/models/client.js
new file mode 100644
index 0000000..ad3bc28
--- /dev/null
+++ b/server/models/client.js
@@ -0,0 +1,22 @@
+'use strict'
+module.exports = (sequelize, DataTypes) => {
+ var client = sequelize.define('client', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: DataTypes.INTEGER
+ },
+ name: DataTypes.STRING,
+ ip: DataTypes.STRING,
+ mac: DataTypes.STRING,
+ uuid: DataTypes.STRING
+ }, {
+ timestamps: false
+ })
+ var GroupXClient = sequelize.define('group_x_client', {}, { timestamps: false, freezeTableName: true })
+ client.associate = function (models) {
+ client.belongsToMany(models.group, { as: 'groups', through: GroupXClient, foreignKey: 'clientId', otherKey: 'groupId'})
+ }
+ return client
+}
diff --git a/server/models/group.js b/server/models/group.js
new file mode 100644
index 0000000..9151db5
--- /dev/null
+++ b/server/models/group.js
@@ -0,0 +1,19 @@
+'use strict'
+module.exports = (sequelize, DataTypes) => {
+ var group = sequelize.define('group', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: DataTypes.INTEGER
+ },
+ name: DataTypes.STRING
+ }, {
+ timestamps: false
+ })
+ var GroupXGroup = sequelize.define('group_x_group', {}, { timestamps: false, freezeTableName: true })
+ group.associate = function (models) {
+ group.belongsToMany(group, { as: 'parents', through: GroupXGroup, foreignKey: 'childId', otherKey: 'parentId'})
+ }
+ return group
+}
diff --git a/server/router.js b/server/router.js
index 4f8d0bb..7bffb92 100644
--- a/server/router.js
+++ b/server/router.js
@@ -14,10 +14,10 @@ router.post('/changepassword', auth.changePassword)
var user = require(path.join(__dirname, 'api', 'user'))
router.get('/user/info', auth.verifyToken, user.info)
-// Locations API
-var locations = require(path.join(__dirname, 'api', 'locations'))
-router.get('/locations', auth.verifyToken, locations.get)
-router.post('/locations', locations.post)
+// Groups API
+var groups = require(path.join(__dirname, 'api', 'groups'))
+router.get('/groups', groups.get)
+router.post('/groups', groups.post)
// Clients API
var clients = require(path.join(__dirname, 'api', 'clients'))
diff --git a/webapp/config/index.js b/webapp/config/index.js
index 0c04bab..89dda2a 100644
--- a/webapp/config/index.js
+++ b/webapp/config/index.js
@@ -44,7 +44,7 @@ module.exports = {
proxyTable: {
// proxy all requests starting with /api to express server
'/api': {
- target: 'https://bas.stfu-kthx.net:8888/'
+ target: 'https://bas.stfu-kthx.net:8001/'
}
}
},
diff --git a/webapp/src/assets/styles.css b/webapp/src/assets/styles.css
index 3a7da9a..9bb1355 100644
--- a/webapp/src/assets/styles.css
+++ b/webapp/src/assets/styles.css
@@ -25,3 +25,14 @@ html {
::-webkit-scrollbar-button {
display: none;
}
+
+.tabs-wrapper {
+ display: flex;
+ flex-direction: column
+}
+
+.tabs-wrapper > .v-tabs__items {
+ padding: 0 5px;
+ margin: 0 -5px;
+ flex: 1
+} \ No newline at end of file
diff --git a/webapp/src/components/ComponentTemplate.vue b/webapp/src/components/ComponentTemplate.vue
index 3de9b36..9c0ebc6 100644
--- a/webapp/src/components/ComponentTemplate.vue
+++ b/webapp/src/components/ComponentTemplate.vue
@@ -8,7 +8,7 @@
</i18n>
<template>
-
+ <div></div>
</template>
<script>
diff --git a/webapp/src/components/GroupModule.vue b/webapp/src/components/GroupModule.vue
index 2e5070a..09e8050 100644
--- a/webapp/src/components/GroupModule.vue
+++ b/webapp/src/components/GroupModule.vue
@@ -8,22 +8,72 @@
</i18n>
<template>
- <div><v-btn color="primary" @click="newSnackbar">{{ count }}</v-btn></div>
+ <v-container fill-height>
+ <v-layout>
+ <v-flex class="tabs-wrapper" xl10 offset-xl1 lg12>
+ <v-card>
+ <v-tabs v-model="active" slider-color="primary">
+ <template v-for="(group, index) in groupChain">
+ <v-icon v-if="group.id !== 0" :key="2*index">keyboard_arrow_right</v-icon>
+ <v-tab :key="2*index+1" ripple>
+ <v-icon v-if="group.id === 0">home</v-icon>
+ <template v-else>{{ group.name ? group.name : group.id }}</template>
+ </v-tab>
+ </template>
+ </v-tabs>
+ </v-card>
+ <v-tabs-items v-model="active" touchless>
+ <template v-for="(group, index) in groupChain">
+ <v-tab-item :key="index">
+ <group-module-group-view
+ ref="groupViews"
+ :id="group.id"
+ @open-group="openGroup($event, index)"
+ @edit-group="editDialog = true; editClient = false; editId = $event"
+ />
+ </v-tab-item>
+ </template>
+ </v-tabs-items>
+ </v-flex>
+ </v-layout>
+ <v-dialog v-model="editDialog" max-width="600px">
+ <group-module-edit :id="editId" :client="editClient" @close="editDialog = false" @reload="reloadData" />
+ </v-dialog>
+ </v-container>
</template>
<script>
+import GroupModuleGroupView from '@/components/GroupModuleGroupView'
+import GroupModuleEdit from '@/components/GroupModuleEdit'
export default {
name: 'GroupModule',
+ components: {
+ GroupModuleGroupView,
+ GroupModuleEdit
+ },
data () {
return {
- count: 0
+ groupChain: [{ id: 0 }],
+ active: 0,
+ editDialog: false,
+ editId: null,
+ editClient: false
}
},
methods: {
- newSnackbar () {
- this.$store.commit('newSnackbar', this.count)
- this.count++
+ openGroup (group, index) {
+ if (this.groupChain.length <= (index + 1) || this.groupChain[index + 1].id !== group.id) {
+ this.groupChain = this.groupChain.slice(0, index + 1)
+ this.groupChain.push(group)
+ }
+ console.log(this.groupChain)
+ this.active = index + 1
+ },
+ reloadData () {
+ this.$refs.groupViews.forEach(groupView => {
+ groupView.loadData()
+ })
}
}
}
@@ -31,5 +81,4 @@ export default {
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
-
</style>
diff --git a/webapp/src/components/GroupModuleClientList.vue b/webapp/src/components/GroupModuleClientList.vue
new file mode 100644
index 0000000..c67362d
--- /dev/null
+++ b/webapp/src/components/GroupModuleClientList.vue
@@ -0,0 +1,70 @@
+<i18n>
+{
+ "en": {
+ },
+ "de": {
+ }
+}
+</i18n>
+
+<template>
+ <v-data-table stlye="width: 100px"
+ :headers="headers"
+ :items="clients"
+ item-key="id"
+ hide-actions
+ select-all
+ v-model="selected"
+ >
+ <template slot="items" slot-scope="props">
+ <tr @click="props.selected = !props.selected">
+ <td class="narrow-td">
+ <v-checkbox
+ color="primary"
+ v-model="props.selected"
+ hide-details
+ @click.native.stop
+ ></v-checkbox>
+ </td>
+ <td class="narrow-td">{{ props.item.id }}</td>
+ <td>{{ props.item.name }}</td>
+ <td>{{ props.item.ip }}</td>
+ <td>{{ props.item.mac }}</td>
+ <td>{{ props.item.uuid }}</td>
+ <td class="narrow-td">
+ <v-btn icon @click.stop><v-icon color="primary">edit</v-icon></v-btn>
+ </td>
+ </tr>
+ </template>
+ </v-data-table>
+</template>
+
+<script>
+
+export default {
+ name: 'GroupModuleClientList',
+ props: ['clients'],
+ data () {
+ return {
+ headers: [
+ { text: 'ID', value: 'id' },
+ { text: 'Name', value: 'name' },
+ { text: 'IP Address', value: 'ip' },
+ { text: 'MAC Address', value: 'mac' },
+ { text: 'UUID', value: 'uuid' },
+ { sortable: false }
+ ],
+ selected: []
+ }
+ },
+ methods: {
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.narrow-td {
+ width: 10px;
+}
+</style>
diff --git a/webapp/src/components/GroupModuleEdit.vue b/webapp/src/components/GroupModuleEdit.vue
new file mode 100644
index 0000000..4b91269
--- /dev/null
+++ b/webapp/src/components/GroupModuleEdit.vue
@@ -0,0 +1,79 @@
+<i18n>
+{
+ "en": {
+ },
+ "de": {
+ }
+}
+</i18n>
+
+<template>
+ <v-card>
+ <div class="input-fields">
+ <v-text-field v-model="name" label="Name" box color="primary"></v-text-field>
+ </div>
+ <div class="action-buttons text-xs-right">
+ <v-btn flat @click="$emit('close')">Cancel</v-btn>
+ <v-btn color="primary" @click="saveData">Save</v-btn>
+ </div>
+ </v-card>
+</template>
+
+<script>
+
+export default {
+ name: 'GroupModuleEdit',
+ props: ['id', 'client'],
+ data () {
+ return {
+ name: ''
+ }
+ },
+ watch: {
+ id () { this.loadData() }
+ },
+ methods: {
+ loadData () {
+ if (!this.id) return
+ if (this.client) {
+ // TODO
+ } else {
+ this.$http('/api/groups?action=getInfo&id=' + this.id).then(response => {
+ this.name = response.data.name
+ })
+ }
+ },
+ saveData () {
+ if (this.client) {
+ // TODO
+ } else {
+ this.$http.post('/api/groups', {
+ action: 'setInfo',
+ id: this.id,
+ name: this.name
+ }).then(response => {
+ console.log(response)
+ })
+ }
+ this.$emit('close')
+ this.$emit('reload')
+ }
+ },
+ created () {
+ this.loadData()
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.input-fields {
+ padding: 40px;
+ padding-bottom: 0;
+}
+
+.action-buttons {
+ padding: 10px;
+}
+
+</style>
diff --git a/webapp/src/components/GroupModuleGroupList.vue b/webapp/src/components/GroupModuleGroupList.vue
new file mode 100644
index 0000000..b6bcd9c
--- /dev/null
+++ b/webapp/src/components/GroupModuleGroupList.vue
@@ -0,0 +1,75 @@
+<i18n>
+{
+ "en": {
+ },
+ "de": {
+ }
+}
+</i18n>
+
+<template>
+ <div>
+ <v-data-table
+ class="group-table"
+ :headers="headers"
+ :items="groups"
+ item-key="id"
+ hide-actions
+ select-all
+ v-model="selected"
+ >
+ <template slot="items" slot-scope="props">
+ <tr @click="$emit('open-group', props.item)">
+ <td>
+ <v-checkbox
+ color="primary"
+ v-model="props.selected"
+ hide-details
+ @click.native.stop
+ ></v-checkbox>
+ </td>
+ <td>{{ props.item.id }}</td>
+ <td>{{ props.item.name }}</td>
+ <td>
+ <v-layout>
+ <v-btn icon @click.stop="$emit('edit-group', props.item.id)"><v-icon color="primary">edit</v-icon></v-btn>
+ <v-btn class="next-arrow" icon @click.stop="$emit('open-group', props.item)"><v-icon>keyboard_arrow_right</v-icon></v-btn>
+ </v-layout>
+ </td>
+ </tr>
+ </template>
+ </v-data-table>
+ </div>
+</template>
+
+<script>
+import GroupModuleGroupView from '@/components/GroupModuleGroupView'
+
+export default {
+ name: 'GroupModuleGroupList',
+ components: {
+ GroupModuleGroupView
+ },
+ props: ['groups'],
+ data () {
+ return {
+ headers: [
+ { text: 'ID', value: 'id' },
+ { text: 'Name', value: 'name', width: '10000px' },
+ { sortable: false }
+ ],
+ selected: []
+ }
+ },
+ methods: {
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.next-arrow {
+ margin-left: 20px;
+ margin-right: -10px;
+}
+</style>
diff --git a/webapp/src/components/GroupModuleGroupView.vue b/webapp/src/components/GroupModuleGroupView.vue
new file mode 100644
index 0000000..24cbdd1
--- /dev/null
+++ b/webapp/src/components/GroupModuleGroupView.vue
@@ -0,0 +1,62 @@
+<i18n>
+{
+ "en": {
+ },
+ "de": {
+ }
+}
+</i18n>
+
+<template>
+ <div>
+ <v-subheader>Groups</v-subheader>
+ <v-card>
+ <group-module-group-list :groups="subGroups" @open-group="$emit('open-group', $event)" @edit-group="$emit('edit-group', $event)" />
+ </v-card>
+ <v-subheader>Clients</v-subheader>
+ <v-card>
+ <group-module-client-list :clients="clients" @edit-client="$emit('edit-client', $event)" />
+ </v-card>
+ </div>
+</template>
+
+<script>
+import GroupModuleGroupList from '@/components/GroupModuleGroupList'
+import GroupModuleClientList from '@/components/GroupModuleClientList'
+
+export default {
+ name: 'GroupModuleGroupView',
+ props: ['id'],
+ components: {
+ GroupModuleGroupList,
+ GroupModuleClientList
+ },
+ data () {
+ return {
+ subGroups: [],
+ clients: []
+ }
+ },
+ watch: {
+ id () { this.loadData() }
+ },
+ methods: {
+ loadData () {
+ var id = this.id ? this.id : ''
+ this.$http('/api/groups?action=getSubGroups&id=' + id).then(response => {
+ this.subGroups = response.data
+ })
+ this.$http('/api/groups?action=getClients&id=' + id).then(response => {
+ this.clients = response.data
+ })
+ }
+ },
+ created () {
+ this.loadData()
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+</style>