Mercurial > gemma
view client/src/components/usermanagement/Usermanagement.vue @ 2503:51dbcbf11c5f critical-bottlenecks
client: addendum for e13daf439068
Of course, as you'd expect, this only solves the problem if you don't care about
significant changes in the tables sorting behavior. To point out the difference
this commit shows the other way to solve the problem without changing the tables
behavior.
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Mon, 04 Mar 2019 16:28:49 +0100 |
parents | e13daf439068 |
children | bb5286acfee2 |
line wrap: on
line source
<template> <div class="main d-flex flex-row" style="position: relative;"> <Spacer></Spacer> <div class="d-flex content py-3"> <div :class="userlistStyle"> <div class="card shadow-xs"> <UIBoxHeader icon="users-cog" title="Users" /> <UITableHeader :columns="[ { id: 'role', title: 'Role', class: 'col-1' }, { id: 'user', title: 'Username', class: 'col-3' }, { id: 'country', title: 'Country', class: 'col-2' }, { id: 'email', title: 'Email', class: 'col-3' } ]" @sortingChanged="sortBy" /> <UITableBody :data="sortedUsers" maxHeight="47rem" :active="currentUser" v-slot="{ item: user }" > <div class="py-2 col-1" @click="selectUser(user.user)"> <font-awesome-icon v-tooltip="roleLabel(user.role)" :icon="roleIcon(user.role)" class="fa-lg" ></font-awesome-icon> </div> <div class="py-2 col-3" @click="selectUser(user.user)"> {{ user.user }} </div> <div class="py-2 col-2" @click="selectUser(user.user)"> {{ user.country }} </div> <div class="py-2 col-3" @click="selectUser(user.user)"> {{ user.email }} </div> <div class="py-2 col text-right"> <button @click="sendTestMail(user.user)" class="btn btn-sm btn-dark mr-1" v-tooltip="$gettext('Send testmail')" v-if="user.email" > <font-awesome-icon icon="paper-plane"></font-awesome-icon> </button> <button @click="deleteUser(user.user)" class="btn btn-sm btn-dark" v-tooltip="$gettext('Delete user')" > <font-awesome-icon icon="trash" /> </button> </div> </UITableBody> <div class="d-flex mx-auto align-items-center"> <button @click="prevPage" v-if="this.currentPage !== 1" class="mr-2 btn btn-sm btn-light align-self-center" > <font-awesome-icon icon="angle-left"></font-awesome-icon> </button> {{ this.currentPage }} / {{ this.pages }} <button @click="nextPage" v-if="this.currentPage !== this.pages" class="ml-2 btn btn-sm btn-light align-self-center" > <font-awesome-icon icon="angle-right"></font-awesome-icon> </button> </div> <div class="mr-3 py-3 text-right"> <button @click="addUser" class="btn btn-info addbutton shadow-sm"> <translate>Add User</translate> </button> </div> </div> </div> <Userdetail v-if="isUserDetailsVisible"></Userdetail> </div> </div> </template> <style lang="sass" scoped> .addbutton position: absolute bottom: $offset right: $offset .content width: 100% .userdetails width: 50% .main height: 100% .icon font-size: large .userlist min-width: 520px height: 100% .userlistsmall width: 100% .userlistextended width: 100% .table-body .row > div transition: background-color 0.3s, color 0.3s &.active > div background-color: $color-info color: #fff a color: #fff !important </style> <script> /* This is Free Software under GNU Affero General Public License v >= 3.0 * without warranty, see README.md and license for details. * * SPDX-License-Identifier: AGPL-3.0-or-later * License-Filename: LICENSES/AGPL-3.0.txt * * Copyright (C) 2018 by via donau * – Österreichische Wasserstraßen-Gesellschaft mbH * Software engineering by Intevation GmbH * * Author(s): * Thomas Junk <thomas.junk@intevation.de> */ import store from "@/store"; import { mapGetters, mapState } from "vuex"; import { displayError, displayInfo } from "@/lib/errors.js"; import { HTTP } from "@/lib/http"; import Vue from "vue"; import { VTooltip, VPopover, VClosePopover } from "v-tooltip"; Vue.directive("tooltip", VTooltip); Vue.directive("close-popover", VClosePopover); Vue.component("v-popover", VPopover); export default { name: "userview", data() { return { sortColumn: "user", sortDirection: "ASC", pageSize: 15, currentPage: 1 }; }, components: { Userdetail: () => import("./Userdetail"), Spacer: () => import("@/components/Spacer") }, computed: { ...mapGetters("usermanagement", [ "isUserDetailsVisible", "users", "currentUser" ]), ...mapState("application", ["showSidebar"]), sortedUsers() { const start = (this.currentPage - 1) * this.pageSize; return this.users .filter(u => u) // to clone the array and leave the original store value intact .sort((a, b) => { if ( a[this.sortColumn].toLowerCase() < b[this.sortColumn].toLowerCase() ) return this.sortDirection === "ASC" ? -1 : 1; if ( a[this.sortColumn].toLowerCase() > b[this.sortColumn].toLowerCase() ) return this.sortDirection === "ASC" ? 1 : -1; return 0; }) .slice(start, start + this.pageSize); }, pages() { return Math.ceil(this.users.length / this.pageSize); }, tableStyle() { return { table: true, "table-hover": true, "table-sm": this.isUserDetailsVisible, fadeIn: true, animated: true }; }, userlistStyle() { return [ "userlist mr-3", { userlistsmall: this.isUserDetailsVisible, userlistextended: !this.isUserDetailsVisible } ]; } }, methods: { sendTestMail(user) { HTTP.get("/testmail/" + user, { headers: { "X-Gemma-Auth": localStorage.getItem("token"), "Content-type": "text/xml; charset=UTF-8" } }) .then(() => { displayInfo({ message: this.$gettext("Testmail sent") }); }) .catch(error => { this.loginFailed = true; const { status, data } = error.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); }, nextPage() { if (this.currentPage < this.pages) { this.currentPage += 1; } }, prevPage() { if (this.currentPage > 0) { this.currentPage -= 1; } }, sortBy(sorting) { this.sortColumn = sorting.sortColumn; this.sortDirection = sorting.sortDirection; }, deleteUser(name) { this.$store.commit("application/popup", { icon: "trash", title: this.$gettext("Delete User"), content: this.$gettext( "Do you really want to delete the following user account:" ) + `<br> <b>${name}</b>`, confirm: { label: this.$gettext("Delete"), icon: "trash", callback: () => { this.$store .dispatch("usermanagement/deleteUser", { name }) .then(() => { this.$store .dispatch("usermanagement/loadUsers") .catch(error => { const { status, data } = error.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); }) .catch(error => { const { status, data } = error.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); } }, cancel: { label: this.$gettext("Cancel"), icon: "times" } }); }, addUser() { this.$store.commit("usermanagement/clearCurrentUser"); this.$store.commit("usermanagement/setUserDetailsVisible"); }, selectUser(name) { const user = this.$store.getters["usermanagement/getUserByName"](name); this.$store.commit("usermanagement/setCurrentUser", user); }, roleIcon(role) { if (role === "sys_admin") return "star"; if (role === "waterway_admin") return ["fab", "adn"]; return "user"; }, roleLabel(role) { const labels = { sys_admin: this.$gettext("System-Administrator"), waterway_admin: this.$gettext("Waterway Admin"), waterway_user: this.$gettext("Waterway User") }; return labels[role]; } }, beforeRouteEnter(to, from, next) { store .dispatch("usermanagement/loadUsers") .then(next) .catch(error => { const { status, data } = error.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data}` }); }); }, beforeRouteLeave(to, from, next) { store.commit("usermanagement/clearCurrentUser"); store.commit("usermanagement/setUserDetailsInvisible"); next(); } }; </script>