summaryrefslogtreecommitdiffstats
path: root/webapp
diff options
context:
space:
mode:
authorUdo Walter2019-04-12 05:02:30 +0200
committerUdo Walter2019-04-12 05:02:30 +0200
commitac89e1ab6bf4500825fc7fc1ffe0f41821e7909e (patch)
tree5ca736e2f8e1c37dee2a0f0c6d00357453b900d1 /webapp
parent[webapp] npm update (diff)
downloadbas-ac89e1ab6bf4500825fc7fc1ffe0f41821e7909e.tar.gz
bas-ac89e1ab6bf4500825fc7fc1ffe0f41821e7909e.tar.xz
bas-ac89e1ab6bf4500825fc7fc1ffe0f41821e7909e.zip
[webapp/groups] small redesign (better UX and perforance); disable buggy tabs transition;
Diffstat (limited to 'webapp')
-rw-r--r--webapp/src/assets/styles.css7
-rw-r--r--webapp/src/components/ConfiguratorModule.vue4
-rw-r--r--webapp/src/components/DataTable.vue3
-rw-r--r--webapp/src/components/GroupModule.vue4
-rw-r--r--webapp/src/components/GroupModuleClientList.vue28
-rw-r--r--webapp/src/components/GroupModuleClientView.vue3
-rw-r--r--webapp/src/components/GroupModuleGroupList.vue30
-rw-r--r--webapp/src/components/GroupModuleGroupView.vue289
8 files changed, 218 insertions, 150 deletions
diff --git a/webapp/src/assets/styles.css b/webapp/src/assets/styles.css
index 8da9436..451d146 100644
--- a/webapp/src/assets/styles.css
+++ b/webapp/src/assets/styles.css
@@ -9,6 +9,13 @@ html {
user-select: none; /* Standard syntax */
}
+.selectable {
+ -webkit-user-select: auto; /* Safari 3.1+ */
+ -moz-user-select: auto; /* Firefox 2+ */
+ -ms-user-select: auto; /* IE 10+ */
+ user-select: text; /* Standard syntax */
+}
+
.non-draggable {
-webkit-user-drag: none;
user-drag: none;
diff --git a/webapp/src/components/ConfiguratorModule.vue b/webapp/src/components/ConfiguratorModule.vue
index e02dff8..0641221 100644
--- a/webapp/src/components/ConfiguratorModule.vue
+++ b/webapp/src/components/ConfiguratorModule.vue
@@ -36,7 +36,7 @@
</v-tabs>
</v-card>
<v-tabs-items v-model="tabs" style="padding-bottom: 20px" touchless>
- <v-tab-item>
+ <v-tab-item :transition="false" :reverse-transition="false">
<v-subheader>{{ $t('configs') }}</v-subheader>
<v-card>
<data-table v-model="selectedConfigs" :headers="configHeaders" :items="configs" min-width="800px" @dblclick="editConfig($event)">
@@ -57,7 +57,7 @@
<v-btn flat color="success" @click="createConfig"><v-icon left>create</v-icon>{{ $t('createConfig') }}</v-btn>
</div>
</v-tab-item>
- <v-tab-item>
+ <v-tab-item :transition="false" :reverse-transition="false">
<v-subheader>{{ $t('entries') }}</v-subheader>
<v-card>
<data-table v-model="selectedEntries" :headers="entryHeaders" :items="entries" min-width="600px" @dblclick="editEntry($event)">
diff --git a/webapp/src/components/DataTable.vue b/webapp/src/components/DataTable.vue
index d51b735..a537af3 100644
--- a/webapp/src/components/DataTable.vue
+++ b/webapp/src/components/DataTable.vue
@@ -85,7 +85,7 @@
solo flat
class="rowcount-select"
v-model="internalRowCount"
- :items="[ 5, 10, 20, 50, 100, { text: $t('all'), value: '-1' }]"
+ :items="[ 5, 10, 20, 50, { text: $t('all'), value: '-1' }]"
color="primary"
hide-details
:menu-props="{
@@ -101,6 +101,7 @@
<v-divider></v-divider>
<RecycleScroller
+ :key="computedRowCount"
ref="scroller"
class="scroller non-selectable"
:style="scrollerStyle"
diff --git a/webapp/src/components/GroupModule.vue b/webapp/src/components/GroupModule.vue
index ccd98cf..a030d8a 100644
--- a/webapp/src/components/GroupModule.vue
+++ b/webapp/src/components/GroupModule.vue
@@ -24,8 +24,8 @@
</v-tabs>
<v-btn icon :loading="reloading" @click="reload"><v-icon>refresh</v-icon></v-btn>
</v-card>
- <v-tabs-items :value="activeTab" @input="setActiveTab" touchless style="padding-bottom: 20px">
- <v-tab-item v-for="(item, index) in tabChain" :key="index" lazy>
+ <v-tabs-items :value="activeTab" @input="setActiveTab" touchless style="padding-bottom: 12px">
+ <v-tab-item v-for="(item, index) in tabChain" :key="index" lazy :transition="false" :reverse-transition="false">
<group-module-group-view v-if="item.tabType === 'group'" :group="item" :tabIndex="index" />
<group-module-client-view v-if="item.tabType === 'client'" :client="item" :tabIndex="index" />
</v-tab-item>
diff --git a/webapp/src/components/GroupModuleClientList.vue b/webapp/src/components/GroupModuleClientList.vue
index 44cb749..ef01ee3 100644
--- a/webapp/src/components/GroupModuleClientList.vue
+++ b/webapp/src/components/GroupModuleClientList.vue
@@ -29,13 +29,11 @@
<template>
<div>
- <v-card>
- <data-table v-model="selected" :headers="headers" :items="clients" :loading="loading" @dblclick="loadClient($event)" min-width="1300px">
- <div slot="actions" slot-scope="row" style="text-align: right">
- <v-btn icon @click.stop @mousedown="loadClient(row.item)" style="margin: 0"><v-icon>keyboard_arrow_right</v-icon></v-btn>
- </div>
- </data-table>
- </v-card>
+ <data-table class="client-table" v-model="selected" :headers="headers" :items="clients" :loading="loading" @dblclick="loadClient($event)" min-width="1300px">
+ <div slot="actions" slot-scope="row" style="text-align: right">
+ <v-btn icon @click.stop @mousedown="loadClient(row.item)" style="margin: 0"><v-icon>keyboard_arrow_right</v-icon></v-btn>
+ </div>
+ </data-table>
<div class="text-xs-right">
<v-btn flat color="primary" @click="wake" :disabled="selected.length === 0">
<v-icon left>notifications_active</v-icon>{{ $tc('wakeClients', selected.length, [selected.length]) }}
@@ -121,4 +119,20 @@ export default {
margin-left: 20px;
margin-right: -10px;
}
+
+.client-table {
+ position: relative;
+}
+
+.client-table::before {
+ pointer-events: none;
+ z-index: 3;
+ box-shadow: inset 0px 0px 6px rgba(0,0,0,0.5);
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ content: "";
+}
</style>
diff --git a/webapp/src/components/GroupModuleClientView.vue b/webapp/src/components/GroupModuleClientView.vue
index cc648f4..76c7a67 100644
--- a/webapp/src/components/GroupModuleClientView.vue
+++ b/webapp/src/components/GroupModuleClientView.vue
@@ -25,8 +25,7 @@
<template>
<div>
- <v-subheader>Info</v-subheader>
- <v-card>
+ <v-card style="margin-top: 24px">
<v-card-text>
<v-layout wrap>
<v-flex lg4 sm6 xs12 order-lg1 order-xs2>
diff --git a/webapp/src/components/GroupModuleGroupList.vue b/webapp/src/components/GroupModuleGroupList.vue
index a8471e6..dff666d 100644
--- a/webapp/src/components/GroupModuleGroupList.vue
+++ b/webapp/src/components/GroupModuleGroupList.vue
@@ -23,13 +23,13 @@
<template>
<div>
- <v-card>
- <data-table v-model="selected" :headers="headers" :items="groups" :loading="loading" @dblclick="loadGroup($event)">
- <div slot="actions" slot-scope="row" style="text-align: right">
- <v-btn icon @click.stop @mousedown="loadGroup(row.item)" style="margin: 0"><v-icon>keyboard_arrow_right</v-icon></v-btn>
- </div>
- </data-table>
- </v-card>
+ <v-divider></v-divider>
+ <data-table class="group-table" v-model="selected" :headers="headers" :items="groups" :loading="loading" @dblclick="loadGroup($event)">
+ <div slot="actions" slot-scope="row" style="text-align: right">
+ <v-btn icon @click.stop @mousedown="loadGroup(row.item)" style="margin: 0"><v-icon>keyboard_arrow_right</v-icon></v-btn>
+ </div>
+ </data-table>
+ <v-divider></v-divider>
<div v-if="tabIndex === 0" class="text-xs-right">
<v-btn flat color="error" @click="deleteSelected" :disabled="selected.length === 0">
<v-icon left>delete</v-icon>{{ $tc('deleteGroups', selected.length, [selected.length]) }}
@@ -101,4 +101,20 @@ export default {
margin-left: 20px;
margin-right: -10px;
}
+
+.group-table {
+ position: relative;
+}
+
+.group-table::before {
+ pointer-events: none;
+ z-index: 3;
+ box-shadow: inset 0px 0px 6px rgba(0,0,0,0.5);
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ content: "";
+}
</style>
diff --git a/webapp/src/components/GroupModuleGroupView.vue b/webapp/src/components/GroupModuleGroupView.vue
index a5cb9e4..47cd6d9 100644
--- a/webapp/src/components/GroupModuleGroupView.vue
+++ b/webapp/src/components/GroupModuleGroupView.vue
@@ -2,7 +2,7 @@
{
"en": {
"info": "Info",
- "showall": "Show All",
+ "showall": "All",
"groups": "Groups",
"subgroups": "Subgroups",
"clients": "Clients",
@@ -18,7 +18,7 @@
},
"de": {
"info": "Info",
- "showall": "Alle anzeigen",
+ "showall": "Alle",
"groups": "Groups",
"subgroups": "Untergruppen",
"clients": "Clients",
@@ -36,141 +36,161 @@
</i18n>
<template>
- <div>
- <v-subheader v-if="group.id !== 0">Info</v-subheader>
- <v-card v-if="group.id !== 0">
- <v-card-text>
- <v-layout wrap>
- <v-flex lg4 sm6 xs12 order-lg1 order-xs2>
- <v-layout column>
- <v-flex>
- <div class="info-box">
- <div class="body-2 info-heading"><v-icon>label</v-icon><span>{{ $t('name') }}</span></div>
- <div class="info-text">
- <v-text-field v-if="editMode" class="info-input" color="primary" v-model="info.name" hide-details></v-text-field>
- <div v-else>{{ group.name || '-' }}</div>
- </div>
+ <v-expansion-panel style="margin-top: 24px" v-model="section">
+ <v-expansion-panel-content v-if="group.id !== 0" class="non-selectable">
+ <template #header>
+ <div class="panel-header primary--text">Info</div>
+ </template>
+ <v-divider></v-divider>
+ <v-layout wrap style="padding: 16px" class="selectable">
+ <v-flex lg4 sm6 xs12 order-lg1 order-xs2>
+ <v-layout column>
+ <v-flex>
+ <div class="info-box">
+ <div class="body-2 info-heading"><v-icon>label</v-icon><span>{{ $t('name') }}</span></div>
+ <div class="info-text">
+ <v-text-field v-if="editMode" class="info-input" color="primary" v-model="info.name" hide-details></v-text-field>
+ <div v-else>{{ group.name || '-' }}</div>
</div>
- </v-flex>
- <v-flex>
- <div class="info-box">
- <div class="body-2 info-heading"><v-icon>device_hub</v-icon><span>{{ $t('parents') }}</span></div>
- <div class="info-text">
- <select-box v-if="editMode" v-model="parents" :items="groupList" class="info-input" hide-details></select-box>
- <div v-else class="chip-container non-selectable">
- <v-tooltip v-for="parent in firstParents" :key="parent.id" top open-delay="800">
- <template #activator="{ on }">
- <v-chip v-on="on" small label style="width: calc(50% - 8px)" @click="openParent(parent)">
- <span class="chip-text">{{ parent.name || parent.id }}</span>
- </v-chip>
- </template>
- <span>{{ parent.name || parent.id }}</span>
- </v-tooltip>
- <span v-if="group.parents && group.parents.length > 5" class="and-more">+ {{ group.parents.length - 5 }} {{ $t('more') }}</span>
- <span v-else-if="group.parents === undefined || group.parents.length === 0">-</span>
- </div>
+ </div>
+ </v-flex>
+ <v-flex>
+ <div class="info-box">
+ <div class="body-2 info-heading"><v-icon>device_hub</v-icon><span>{{ $t('parents') }}</span></div>
+ <div class="info-text">
+ <select-box v-if="editMode" v-model="parents" :items="groupList" class="info-input" hide-details></select-box>
+ <div v-else class="chip-container non-selectable">
+ <v-tooltip v-for="parent in firstParents" :key="parent.id" top open-delay="800">
+ <template #activator="{ on }">
+ <v-chip v-on="on" small label style="width: calc(50% - 8px)" @click="openParent(parent)">
+ <span class="chip-text">{{ parent.name || parent.id }}</span>
+ </v-chip>
+ </template>
+ <span>{{ parent.name || parent.id }}</span>
+ </v-tooltip>
+ <span v-if="group.parents && group.parents.length > 5" class="and-more">+ {{ group.parents.length - 5 }} {{ $t('more') }}</span>
+ <span v-else-if="group.parents === undefined || group.parents.length === 0">-</span>
</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>{{ configName || '-' }}</div>
- </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>{{ configName || '-' }}</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>
- <div class="info-text">
- <v-textarea v-if="editMode" class="info-input" rows="1" auto-grow hide-details color="primary" v-model="info.description"></v-textarea>
- <div v-else style="white-space: pre-wrap;">{{ group.description || '-' }}</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>
+ <div class="info-text">
+ <v-textarea v-if="editMode" class="info-input" rows="1" auto-grow hide-details color="primary" v-model="info.description"></v-textarea>
+ <div v-else style="white-space: pre-wrap;">{{ group.description || '-' }}</div>
</div>
+ </div>
- <div class="info-box">
- <div class="body-2 info-heading"><v-icon>settings_ethernet</v-icon><span>{{ $t('ipranges') }}</span></div>
- <div class="info-text">
- <div v-if="editMode">
- <div v-for="(iprange, index) in ipranges" :key="index">
- <div class="iprange">
- <v-btn class="iprange-button" small icon @click="removeIprange(index)"><v-icon>remove</v-icon></v-btn>
- <v-text-field solo flat hide-details :label="$t('startIp')" color="primary" v-model="iprange.startIp" single-line></v-text-field>
- <span class="ip-seperator">-</span>
- <v-text-field solo flat hide-details :label="$t('endIp')" color="primary" v-model="iprange.endIp" single-line></v-text-field>
- </div>
- <v-divider></v-divider>
- </div>
- <div class="iprange-add-wrapper">
- <v-btn class="iprange-button" small icon @click="addIprange"><v-icon>add</v-icon></v-btn>
+ <div class="info-box">
+ <div class="body-2 info-heading"><v-icon>settings_ethernet</v-icon><span>{{ $t('ipranges') }}</span></div>
+ <div class="info-text">
+ <div v-if="editMode">
+ <div v-for="(iprange, index) in ipranges" :key="index">
+ <div class="iprange">
+ <v-btn class="iprange-button" small icon @click="removeIprange(index)"><v-icon>remove</v-icon></v-btn>
+ <v-text-field solo flat hide-details :label="$t('startIp')" color="primary" v-model="iprange.startIp" single-line></v-text-field>
+ <span class="ip-seperator">-</span>
+ <v-text-field solo flat hide-details :label="$t('endIp')" color="primary" v-model="iprange.endIp" single-line></v-text-field>
</div>
+ <v-divider></v-divider>
</div>
- <div v-else>
- <table>
- <tr v-for="(iprange, index) in group.ipranges" :key="index">
- <td class="text-xs-right">{{ iprange.startIp }}</td>
- <td class="ip-seperator">-</td>
- <td>{{ iprange.endIp }}</td>
- </tr>
- </table>
- <div v-if="group.ipranges && group.ipranges.length === 0">-</div>
+ <div class="iprange-add-wrapper">
+ <v-btn class="iprange-button" small icon @click="addIprange"><v-icon>add</v-icon></v-btn>
</div>
</div>
- </div>
- </v-flex>
- <v-flex lg4 xs12 order-lg3 order-xs1 class="text-xs-right">
- <div class="info-box">
- <div v-if="!editMode">
- <v-btn color="error" flat @click="deleteGroup" class="info-buttons">
- <v-icon left>delete</v-icon>{{ $t('delete') }}
- </v-btn>
- <v-btn color="primary" flat @click="editInfo" class="info-buttons">
- <v-icon left>create</v-icon>{{ $t('edit') }}
- </v-btn>
- </div>
<div v-else>
- <v-btn color="primary" flat @click="cancelEdit" class="info-buttons">{{ $t('cancel') }}</v-btn>
- <v-btn color="primary" @click="saveData" class="info-buttons">
- <v-icon left>save</v-icon>{{ $t('save') }}
- </v-btn>
+ <table>
+ <tr v-for="(iprange, index) in group.ipranges" :key="index">
+ <td class="text-xs-right">{{ iprange.startIp }}</td>
+ <td class="ip-seperator">-</td>
+ <td>{{ iprange.endIp }}</td>
+ </tr>
+ </table>
+ <div v-if="group.ipranges && group.ipranges.length === 0">-</div>
</div>
</div>
- </v-flex>
- </v-layout>
- </v-card-text>
- </v-card>
- <template v-if="group.id !== 'create'">
- <v-layout>
- <v-spacer></v-spacer>
- <div><v-switch
- :input-value="group.tabShowAll"
- @change="setShowAll"
- class="show-toggle"
- :label="$t('showall')"
- hide-details
- color="primary"
- ></v-switch></div>
+ </div>
+ </v-flex>
+ <v-flex lg4 xs12 order-lg3 order-xs1 class="text-xs-right">
+ <div class="info-box">
+ <div v-if="!editMode">
+ <v-btn color="error" flat @click="deleteGroup" class="info-buttons">
+ <v-icon left>delete</v-icon>{{ $t('delete') }}
+ </v-btn>
+ <v-btn color="primary" flat @click="editInfo" class="info-buttons">
+ <v-icon left>create</v-icon>{{ $t('edit') }}
+ </v-btn>
+ </div>
+ <div v-else>
+ <v-btn color="primary" flat @click="cancelEdit" class="info-buttons">{{ $t('cancel') }}</v-btn>
+ <v-btn color="primary" @click="saveData" class="info-buttons">
+ <v-icon left>save</v-icon>{{ $t('save') }}
+ </v-btn>
+ </div>
+ </div>
+ </v-flex>
</v-layout>
- <v-subheader>{{ group.id > 0 ? $t('subgroups') : $t('groups') }}</v-subheader>
- <group-module-group-list :tabIndex="tabIndex" :groupId="group.id" :groups="group.subgroups || []" />
- <v-subheader>{{ $t('clients') }}</v-subheader>
- <group-module-client-list :tabIndex="tabIndex" :groupId="group.id" :clients="group.clients || []" />
- </template>
- </div>
+ </v-expansion-panel-content>
+ <v-expansion-panel-content lazy class="non-selectable">
+ <template #header>
+ <div class="panel-header primary--text">
+ <span>{{ group.subgroups ? group.subgroups.length : 0 }} {{ group.id > 0 ? $t('subgroups') : $t('groups') }}</span>
+ <v-switch
+ v-if="section === (group.id !== 0 ? 1 : 0)"
+ @click.native.stop
+ :input-value="group.tabShowAll"
+ @change="setShowAll"
+ class="show-toggle"
+ :label="$t('showall')"
+ hide-details
+ color="primary"
+ ></v-switch>
+ </div>
+ </template>
+ <group-module-group-list class="selectable" :tabIndex="tabIndex" :groupId="group.id" :groups="group.subgroups || []" />
+ </v-expansion-panel-content>
+ <v-expansion-panel-content lazy class="non-selectable">
+ <template #header>
+ <div class="panel-header primary--text">
+ <span>{{ group.clients ? group.clients.length : 0 }} {{ $t('clients') }}</span>
+ <v-switch
+ v-if="section === (group.id !== 0 ? 2 : 1)"
+ @click.native.stop
+ :input-value="group.tabShowAll"
+ @change="setShowAll"
+ class="show-toggle"
+ :label="$t('showall')"
+ hide-details
+ color="primary"
+ ></v-switch>
+ </div>
+ </template>
+ <group-module-client-list class="selectable" :tabIndex="tabIndex" :groupId="group.id" :clients="group.clients || []" />
+ </v-expansion-panel-content>
+ </v-expansion-panel>
</template>
<script>
@@ -197,6 +217,7 @@ export default {
},
data () {
return {
+ section: 0,
editMode: false,
info: {
name: '',
@@ -224,7 +245,10 @@ export default {
watch: {
group (newValue, oldValue) {
if (newValue.id === 'create') this.editInfo()
- else if (newValue.id !== oldValue.id) this.editMode = false
+ else if (newValue.id !== oldValue.id) {
+ this.editMode = false
+ this.section = 0
+ }
}
},
methods: {
@@ -288,6 +312,19 @@ export default {
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
+.panel-header {
+ font-weight: bold;
+ display: flex;
+ justify-content: space-between;
+}
+
+.show-toggle {
+ padding: 0;
+ margin: 0;
+ flex: initial;
+ margin-right: 16px;
+}
+
.info-buttons {
margin: 0;
}
@@ -371,10 +408,4 @@ export default {
display: flex;
align-items: center;
}
-
-.show-toggle {
- margin-top: 20px;
- margin-right: 20px;
- margin-bottom: -20px;
-}
</style>