summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/api/clients.js2
-rw-r--r--server/api/groups.js2
-rw-r--r--webapp/src/components/ComponentSearchTable.vue168
-rw-r--r--webapp/src/components/ComponentTableActions.vue126
-rw-r--r--webapp/src/components/GroupModuleClientList.vue57
-rw-r--r--webapp/src/components/GroupModuleClientView.vue1
-rw-r--r--webapp/src/components/GroupModuleGroupList.vue63
-rw-r--r--webapp/src/components/GroupModuleGroupView.vue1
-rw-r--r--webapp/src/components/LoginPage.vue5
9 files changed, 221 insertions, 204 deletions
diff --git a/server/api/clients.js b/server/api/clients.js
index 046bced..862a1a2 100644
--- a/server/api/clients.js
+++ b/server/api/clients.js
@@ -42,7 +42,7 @@ module.exports.post = {
db.client.findOne({ where: { id } }).then(client => {
if (client) {
var promises = []
- if (req.body.info) promises.push([client.update(req.body.info)])
+ if (req.body.info) promises.push(client.update(req.body.info))
if (req.body.groupIds) promises.push(client.setGroups(req.body.groupIds))
Promise.all(promises).then(() => { res.send({ id }) })
} else { res.status(404).end() }
diff --git a/server/api/groups.js b/server/api/groups.js
index 02bfa25..64f49fc 100644
--- a/server/api/groups.js
+++ b/server/api/groups.js
@@ -43,7 +43,7 @@ module.exports.post = {
db.group.findOne({ where: { id } }).then(group => {
if (group) {
var promises = []
- if (req.body.info) promises.push([group.update(req.body.info)])
+ if (req.body.info) promises.push(group.update(req.body.info))
if (req.body.parentIds) promises.push(group.setParents(req.body.parentIds))
Promise.all(promises).then(() => { res.send({id}) })
} else { res.status(404).end() }
diff --git a/webapp/src/components/ComponentSearchTable.vue b/webapp/src/components/ComponentSearchTable.vue
new file mode 100644
index 0000000..2e3846d
--- /dev/null
+++ b/webapp/src/components/ComponentSearchTable.vue
@@ -0,0 +1,168 @@
+<i18n>
+{
+ "en": {
+ "search": "Search",
+ "all": "All",
+ "pageText": "{0}-{1} of {2}",
+ "pageTextZero": "0 of 0",
+ "rowsPerPageText": "Rows per page:"
+ },
+ "de": {
+ "search": "Suche",
+ "all": "Alle",
+ "pageText": "{0}-{1} von {2}",
+ "pageTextZero": "0 von 0",
+ "rowsPerPageText": "Reihen pro page:"
+ }
+}
+</i18n>
+
+<template>
+ <div>
+ <v-layout v-if="actionsNeeded" wrap align-center class="actions-container">
+ <v-flex md3 sm5 xs12 order-md1 order-sm1 order-xs1 class="text-xs-left">
+ <v-text-field
+ class="search-field"
+ :placeholder="$t('search')"
+ v-model="search"
+ hide-details
+ prepend-inner-icon="search"
+ ></v-text-field>
+ </v-flex>
+ <v-flex md4 sm12 xs12 offset-md1 offset-sm0 offset-xs0 order-md2 order-sm3 order-xs3
+ class="text-md-center text-xs-right caption font-weight-thin">
+ {{ $t('rowsPerPageText') }}
+ <v-select
+ class="rows-per-page-select body-1"
+ v-model="pagination.rowsPerPage"
+ :items="rowsPerPageItems.concat({ text: $t('all'), value: -1 })"
+ offset-y
+ color="primary"
+ hide-details
+ content-class="search-table-rows-per-page-select-content"
+ ></v-select>
+ </v-flex>
+ <v-flex md4 sm6 xs12 offset-md0 offset-sm1 offset-xs0 order-md3 order-sm2 order-xs2
+ class="text-xs-right caption font-weight-thin">
+ <span class="page-text">{{
+ pagination.totalItems > 0 ? $t('pageText', [
+ (pagination.page - 1) * pagination.rowsPerPage + 1,
+ Math.min(pagination.page * pagination.rowsPerPage, pagination.totalItems),
+ pagination.totalItems
+ ]) : $t('pageTextZero')
+ }}</span>
+ <v-btn class="page-button" icon @click="prevPage"><v-icon>keyboard_arrow_left</v-icon></v-btn>
+ <v-btn class="page-button" icon @click="nextPage"><v-icon>keyboard_arrow_right</v-icon></v-btn>
+ </v-flex>
+ </v-layout>
+ <v-divider v-if="actionsNeeded"></v-divider>
+ <v-data-table
+ v-bind="computedDataTableProps"
+ :value="value"
+ @input="$emit('input', $event)"
+ :search="search"
+ :pagination.sync="pagination"
+ :custom-filter="customFilter"
+ >
+ <template v-if="$scopedSlots.items" slot="items" slot-scope="props">
+ <slot name="items" :data="props" ></slot>
+ </template>
+ </v-data-table>
+ </div>
+</template>
+
+<script>
+
+export default {
+ name: 'ComponentSearchTable',
+ props: {
+ value: {
+ type: Array,
+ default: () => []
+ },
+ dataTableProps: {
+ type: Object,
+ default: () => {}
+ },
+ rowsPerPageItems: {
+ type: Array,
+ default: () => [10, 25, 50]
+ }
+ },
+ data () {
+ return {
+ search: '',
+ pagination: {},
+ selected: []
+ }
+ },
+ computed: {
+ computedDataTableProps () {
+ return { ...this.dataTableProps, hideActions: true }
+ },
+ headersValues () { return this.dataTableProps.headers.map(x => x.value) },
+ headerCount () { return this.dataTableProps.headers.length + (this.dataTableProps.selectAll ? 1 : 0) },
+ rowsPerPage () { return this.pagination.rowsPerPage },
+ actionsNeeded () {
+ return this.dataTableProps.items && this.rowsPerPageItems.length > 0 && this.dataTableProps.items.length > this.rowsPerPageItems[0]
+ }
+ },
+ watch: {
+ rowsPerPage () {
+ this.pagination.page = 1
+ }
+ },
+ methods: {
+ prevPage () {
+ if (this.pagination.page > 1) this.pagination.page -= 1
+ },
+ nextPage () {
+ if (this.pagination.page * this.pagination.rowsPerPage < this.pagination.totalItems) this.pagination.page += 1
+ },
+ customFilter (items, search) {
+ search = String(search).toLowerCase().trim()
+ let matchedItems = search === '' ? items : items.filter(item => {
+ return Object.keys(item).some(key => {
+ return this.headersValues.includes(key) && String(item[key]).toLowerCase().includes(search)
+ })
+ })
+ this.pagination.totalItems = matchedItems.length
+ return matchedItems
+ }
+ },
+ created () {
+ this.pagination.rowsPerPage = this.rowsPerPageItems[0] || -1
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.actions-container {
+ padding: 20px;
+}
+.search-field {
+ margin-top: 0;
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-bottom: 5px;
+}
+.rows-per-page-select {
+ display: inline-block;
+ margin: 0 10px 0 20px;
+ width: min-content;
+}
+.page-text {
+ margin-right: 20px;
+}
+.page-button {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+</style>
+
+<style>
+.search-table-rows-per-page-select-content .v-list__tile {
+ height: 38px;
+}
+</style> \ No newline at end of file
diff --git a/webapp/src/components/ComponentTableActions.vue b/webapp/src/components/ComponentTableActions.vue
deleted file mode 100644
index 989a83a..0000000
--- a/webapp/src/components/ComponentTableActions.vue
+++ /dev/null
@@ -1,126 +0,0 @@
-<i18n>
-{
- "en": {
- "search": "Search",
- "all": "All",
- "pageText": "{0}-{1} of {2}",
- "pageTextZero": "0 of 0",
- "rowsPerPageText": "Rows per page:"
- },
- "de": {
- "search": "Suche",
- "all": "Alle",
- "pageText": "{0}-{1} von {2}",
- "pageTextZero": "0 von 0",
- "rowsPerPageText": "Reihen pro page:"
- }
-}
-</i18n>
-
-<template>
- <v-layout wrap align-center class="caption font-weight-thin">
- <v-flex md3 sm5 xs12 order-md1 order-sm1 order-xs1 class="text-xs-left">
- <v-text-field
- class="search-field"
- :placeholder="$t('search')"
- :value="search"
- @input="setSearch"
- hide-details
- prepend-inner-icon="search"
- ></v-text-field>
- </v-flex>
- <v-flex md4 sm12 xs12 offset-md1 offset-sm0 offset-xs0 order-md2 order-sm3 order-xs3 class="text-md-center text-xs-right">
- {{ $t('rowsPerPageText') }}
- <v-select
- class="rows-per-page-select body-1"
- :value="pagination.rowsPerPage"
- @input="setRowsPerPage"
- :items="rowsPerPageOptions.concat({ text: $t('all'), value: -1 })"
- offset-y
- color="primary"
- hide-details
- ></v-select>
- </v-flex>
- <v-flex md4 sm6 xs12 offset-md0 offset-sm1 offset-xs0 order-md3 order-sm2 order-xs2 class="text-xs-right">
- <span class="page-text">{{
- pagination.totalItems > 0 ? $t('pageText', [
- (pagination.page - 1) * pagination.rowsPerPage + 1,
- Math.min(pagination.page * pagination.rowsPerPage, pagination.totalItems),
- pagination.totalItems
- ]) : $t('pageTextZero')
- }}</span>
- <v-btn class="page-button" icon @click="prevPage"><v-icon>keyboard_arrow_left</v-icon></v-btn>
- <v-btn class="page-button" icon @click="nextPage"><v-icon>keyboard_arrow_right</v-icon></v-btn>
- </v-flex>
- </v-layout>
-</template>
-
-<script>
-
-export default {
- name: 'ComponentTableActions',
- props: {
- pagination: {
- type: Object,
- required: true
- },
- search: {
- type: String,
- required: true
- },
- itemCount: {
- type: Number,
- required: true
- },
- rowsPerPageOptions: {
- type: Array,
- default: () => [10, 25, 50]
- }
- },
- data () {
- return {
- }
- },
- methods: {
- setRowsPerPage (value) {
- this.$emit('update:pagination', { ...this.pagination, rowsPerPage: value, page: 1 })
- },
- setPage (value) {
- this.$emit('update:pagination', { ...this.pagination, page: value })
- },
- setSearch (value) { this.$emit('update:search', value) },
- prevPage () {
- if (this.pagination.page > 1) this.setPage(this.pagination.page - 1)
- },
- nextPage () {
- if (this.pagination.page * this.pagination.rowsPerPage < this.pagination.totalItems) this.setPage(this.pagination.page + 1)
- }
- },
- created () {
- this.$emit('update:pagination', { ...this.pagination, totalItems: this.itemCount, rowsPerPage: this.rowsPerPageOptions[0] || -1 })
- this.setSearch('')
- }
-}
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped>
-.search-field {
- margin-top: 0;
- margin-left: 10px;
- margin-right: 10px;
- margin-bottom: 5px;
-}
-.rows-per-page-select {
- display: inline-block;
- margin: 0 10px 0 20px;
- width: min-content;
-}
-.page-text {
- margin-right: 20px;
-}
-.page-button {
- margin-top: 0;
- margin-bottom: 0;
-}
-</style>
diff --git a/webapp/src/components/GroupModuleClientList.vue b/webapp/src/components/GroupModuleClientList.vue
index c491b63..101de5a 100644
--- a/webapp/src/components/GroupModuleClientList.vue
+++ b/webapp/src/components/GroupModuleClientList.vue
@@ -28,42 +28,29 @@
<template>
<div>
<v-card>
- <v-card-title v-if="clients.length > 10">
- <component-table-actions :pagination.sync="pagination" :search.sync="search" :item-count="clients.length" />
- </v-card-title>
- <v-divider></v-divider>
- <v-data-table
- :headers="headers"
- :items="clients"
- item-key="id"
- select-all
- hide-actions
- v-model="selected"
- :search="search"
- :pagination.sync="pagination"
- >
- <template slot="items" slot-scope="props">
- <tr @click.stop="props.selected = !props.selected" @dblclick="loadClient(props.item.id)">
+ <component-search-table v-model="selected" :data-table-props="dataTableProps">
+ <template slot="items" slot-scope="table">
+ <tr @click.stop="table.data.selected = !table.data.selected" @dblclick="loadClient(table.data.item.id)">
<td class="narrow-td">
<v-checkbox
color="primary"
- v-model="props.selected"
+ v-model="table.data.selected"
hide-details
@click.native.stop
@dblclick.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">{{ table.data.item.id }}</td>
+ <td>{{ table.data.item.name }}</td>
+ <td>{{ table.data.item.ip }}</td>
+ <td>{{ table.data.item.mac }}</td>
+ <td>{{ table.data.item.uuid }}</td>
<td class="narrow-td">
- <v-btn class="next-arrow" icon @click="loadClient(props.item.id)"><v-icon>keyboard_arrow_right</v-icon></v-btn>
+ <v-btn class="next-arrow" icon @click="loadClient(table.data.item.id)"><v-icon>keyboard_arrow_right</v-icon></v-btn>
</td>
</tr>
</template>
- </v-data-table>
+ </component-search-table>
</v-card>
<div v-if="tabIndex === 0" class="text-xs-right">
<v-btn flat color="error" @click="deleteSelected" :disabled="selected.length === 0">
@@ -81,24 +68,21 @@
</template>
<script>
-import ComponentTableActions from '@/components/ComponentTableActions'
-import { mapState, mapMutations } from 'vuex'
+import ComponentSearchTable from '@/components/ComponentSearchTable'
+import { mapMutations } from 'vuex'
export default {
name: 'GroupModuleClientList',
props: ['tabIndex', 'groupId', 'clients'],
components: {
- ComponentTableActions
+ ComponentSearchTable
},
data () {
return {
- selected: [],
- search: '',
- pagination: {}
+ selected: []
}
},
computed: {
- ...mapState('groups', ['showAll']),
headers () {
return [
{ text: this.$t('id'), value: 'id' },
@@ -108,12 +92,17 @@ export default {
{ text: this.$t('uuid'), value: 'uuid' },
{ sortable: false }
]
+ },
+ dataTableProps () {
+ return {
+ headers: this.headers,
+ items: this.clients,
+ selectAll: true,
+ itemKey: 'id'
+ }
}
},
watch: {
- showAll (value) {
- if (!value) this.search = ''
- },
clients () {
this.selected = []
}
diff --git a/webapp/src/components/GroupModuleClientView.vue b/webapp/src/components/GroupModuleClientView.vue
index ab12ed0..370eb48 100644
--- a/webapp/src/components/GroupModuleClientView.vue
+++ b/webapp/src/components/GroupModuleClientView.vue
@@ -167,7 +167,6 @@ export default {
this.editMode = false
},
updateUrl (id) {
- console.log(id)
this.$router.replace({
name: 'GroupModule.client',
params: { id, noReload: true }
diff --git a/webapp/src/components/GroupModuleGroupList.vue b/webapp/src/components/GroupModuleGroupList.vue
index 2adfcaf..24cd325 100644
--- a/webapp/src/components/GroupModuleGroupList.vue
+++ b/webapp/src/components/GroupModuleGroupList.vue
@@ -24,40 +24,27 @@
<template>
<div>
<v-card>
- <v-card-title v-if="groups.length > 10" class="search-container">
- <component-table-actions :pagination.sync="pagination" :search.sync="search" :item-count="groups.length" />
- </v-card-title>
- <v-divider></v-divider>
- <v-data-table
- :headers="headers"
- :items="groups"
- item-key="id"
- select-all
- hide-actions
- v-model="selected"
- :search="search"
- :pagination.sync="pagination"
- >
- <template slot="items" slot-scope="props">
- <tr @click.stop="props.selected = !props.selected" @dblclick="loadGroup(props.item.id)">
- <td>
+ <component-search-table v-model="selected" :data-table-props="dataTableProps">
+ <template slot="items" slot-scope="table">
+ <tr @click.stop="table.data.selected = !table.data.selected" @dblclick="loadGroup(table.data.item.id)">
+ <td class="narrow-td">
<v-checkbox
color="primary"
- v-model="props.selected"
+ v-model="table.data.selected"
hide-details
@click.native.stop
@dblclick.native.stop
></v-checkbox>
</td>
- <td>{{ props.item.id }}</td>
- <td>{{ props.item.name }}</td>
- <td>{{ props.item.description }}</td>
- <td>
- <v-btn class="next-arrow" icon @click="loadGroup(props.item.id)"><v-icon>keyboard_arrow_right</v-icon></v-btn>
+ <td class="narrow-td">{{ table.data.item.id }}</td>
+ <td>{{ table.data.item.name }}</td>
+ <td>{{ table.data.item.description }}</td>
+ <td class="narrow-td">
+ <v-btn class="next-arrow" icon @click="loadGroup(table.data.item.id)"><v-icon>keyboard_arrow_right</v-icon></v-btn>
</td>
</tr>
</template>
- </v-data-table>
+ </component-search-table>
</v-card>
<div v-if="tabIndex === 0" class="text-xs-right">
<v-btn flat color="error" @click="deleteSelected" :disabled="selected.length === 0">
@@ -75,37 +62,39 @@
</template>
<script>
-import ComponentTableActions from '@/components/ComponentTableActions'
-import { mapState, mapMutations } from 'vuex'
+import ComponentSearchTable from '@/components/ComponentSearchTable'
+import { mapMutations } from 'vuex'
export default {
name: 'GroupModuleGroupList',
props: ['tabIndex', 'groupId', 'groups'],
components: {
- ComponentTableActions
+ ComponentSearchTable
},
data () {
return {
- selected: [],
- search: '',
- pagination: {}
+ selected: []
}
},
computed: {
- ...mapState('groups', ['showAll']),
headers () {
return [
{ text: this.$t('id'), value: 'id' },
{ text: this.$t('name'), value: 'name' },
- { text: this.$t('description'), value: 'description', width: '100000px' },
+ { text: this.$t('description'), value: 'description' },
{ sortable: false }
]
+ },
+ dataTableProps () {
+ return {
+ headers: this.headers,
+ items: this.groups,
+ selectAll: true,
+ itemKey: 'id'
+ }
}
},
watch: {
- showAll (value) {
- if (!value) this.search = ''
- },
groups () {
this.selected = []
}
@@ -134,6 +123,10 @@ export default {
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
+.narrow-td {
+ width: 10px;
+}
+
.next-arrow {
margin-left: 20px;
margin-right: -10px;
diff --git a/webapp/src/components/GroupModuleGroupView.vue b/webapp/src/components/GroupModuleGroupView.vue
index bda2922..b9b81f2 100644
--- a/webapp/src/components/GroupModuleGroupView.vue
+++ b/webapp/src/components/GroupModuleGroupView.vue
@@ -154,7 +154,6 @@ export default {
this.editMode = false
},
updateUrl (id) {
- console.log(id)
this.$router.replace({
name: 'GroupModule.group',
params: { id, noReload: true }
diff --git a/webapp/src/components/LoginPage.vue b/webapp/src/components/LoginPage.vue
index 0ff5d46..aeaf66e 100644
--- a/webapp/src/components/LoginPage.vue
+++ b/webapp/src/components/LoginPage.vue
@@ -94,11 +94,6 @@ export default {
})
}
}
- },
- watch: {
- $route (v) {
- console.log(v)
- }
}
}
</script>