changeset 2463:8cc3cd1b27f2

client: usermanagement: implemented new table component
author Markus Kottlaender <markus@intevation.de>
date Mon, 04 Mar 2019 15:59:02 +0100
parents 9ae2a2f758bb
children bc0f1771497a 9d9c6425db82
files client/src/components/usermanagement/Usermanagement.vue
diffstat 1 files changed, 108 insertions(+), 171 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/usermanagement/Usermanagement.vue	Mon Mar 04 14:50:23 2019 +0100
+++ b/client/src/components/usermanagement/Usermanagement.vue	Mon Mar 04 15:59:02 2019 +0100
@@ -5,82 +5,55 @@
       <div :class="userlistStyle">
         <div class="card shadow-xs">
           <UIBoxHeader icon="users-cog" title="Users" />
-          <div class="card-body">
-            <table id="datatable" :class="tableStyle">
-              <thead>
-                <tr>
-                  <th scope="col" @click="sortBy('role')">
-                    <span
-                      >Role&nbsp;
-                      <font-awesome-icon
-                        v-if="sortCriterion == 'role'"
-                        icon="angle-down"
-                      ></font-awesome-icon>
-                    </span>
-                  </th>
-                  <th scope="col" @click="sortBy('user')">
-                    <span
-                      >Username&nbsp;
-                      <font-awesome-icon
-                        v-if="sortCriterion == 'user'"
-                        icon="angle-down"
-                      ></font-awesome-icon>
-                    </span>
-                  </th>
-                  <th scope="col" @click="sortBy('country')">
-                    <span
-                      >Country&nbsp;
-                      <font-awesome-icon
-                        v-if="sortCriterion == 'country'"
-                        icon="angle-down"
-                      ></font-awesome-icon>
-                    </span>
-                  </th>
-                  <th scope="col" @click="sortBy('email')">
-                    <span
-                      >Email&nbsp;
-                      <font-awesome-icon
-                        v-if="sortCriterion == 'email'"
-                        icon="angle-down"
-                      ></font-awesome-icon>
-                    </span>
-                  </th>
-                  <th scope="col"></th>
-                </tr>
-              </thead>
-              <transition-group name="fade" tag="tbody">
-                <tr v-for="user in users" :key="user.user">
-                  <td @click="selectUser(user.user)">
-                    <font-awesome-icon
-                      v-tooltip="roleLabel(user.role)"
-                      :icon="roleIcon(user.role)"
-                      class="fa-lg"
-                    ></font-awesome-icon>
-                  </td>
-                  <td @click="selectUser(user.user)">{{ user.user }}</td>
-                  <td @click="selectUser(user.user)">{{ user.country }}</td>
-                  <td @click="selectUser(user.user)">{{ user.email }}</td>
-                  <td class="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>
-                  </td>
-                </tr>
-              </transition-group>
-            </table>
-          </div>
+          <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"
@@ -110,70 +83,44 @@
   </div>
 </template>
 
-<style lang="scss" scoped>
-.addbutton {
-  position: absolute;
-  bottom: $offset;
-  right: $offset;
-}
+<style lang="sass" scoped>
+.addbutton
+  position: absolute
+  bottom: $offset
+  right: $offset
 
-.content {
-  width: 100%;
-}
-
-.userdetails {
-  width: 50%;
-}
+.content
+  width: 100%
 
-.main {
-  height: 100%;
-}
-
-.icon {
-  font-size: large;
-}
+.userdetails
+  width: 50%
 
-.userlist {
-  min-width: 520px;
-  height: 100%;
-}
+.main
+  height: 100%
 
-.userlistsmall {
-  width: 100%;
-}
+.icon
+  font-size: large
 
-.userlistextended {
-  width: 100%;
-}
-
-.table {
-  margin: auto;
-}
+.userlist
+  min-width: 520px
+  height: 100%
 
-.table th {
-  cursor: pointer;
-}
+.userlistsmall
+  width: 100%
 
-.table th:first-child {
-  width: 50px;
-}
+.userlistextended
+  width: 100%
 
-.table th,
-td {
-  font-size: $smaller;
-  border-top: 0px !important;
-  text-align: left;
-  padding: $small-offset !important;
-}
-
-.table td {
-  font-size: $smaller;
-  cursor: pointer;
-}
-
-tr span {
-  display: flex;
-}
+.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>
@@ -205,11 +152,10 @@
   name: "userview",
   data() {
     return {
-      sortCriterion: "user",
-      pageSize: 20,
-      currentPage: 1,
-      userToDelete: "",
-      showDeleteUserPrompt: false
+      sortColumn: "user",
+      sortDirection: "ASC",
+      pageSize: 15,
+      currentPage: 1
     };
   },
   components: {
@@ -217,29 +163,30 @@
     Spacer: () => import("@/components/Spacer")
   },
   computed: {
-    ...mapGetters("usermanagement", ["isUserDetailsVisible"]),
+    ...mapGetters("usermanagement", [
+      "isUserDetailsVisible",
+      "users",
+      "currentUser"
+    ]),
     ...mapState("application", ["showSidebar"]),
-    users() {
-      let users = [...this.$store.getters["usermanagement/users"]];
-      users.sort((a, b) => {
-        if (
-          a[this.sortCriterion].toLowerCase() <
-          b[this.sortCriterion].toLowerCase()
-        )
-          return -1;
-        if (
-          a[this.sortCriterion].toLowerCase() >
-          b[this.sortCriterion].toLowerCase()
-        )
-          return 1;
-        return 0;
-      });
+    sortedUsers() {
       const start = (this.currentPage - 1) * this.pageSize;
-      return users.slice(start, start + this.pageSize);
+      return this.users
+        .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() {
-      let users = [...this.$store.getters["usermanagement/users"]];
-      return Math.ceil(users.length / this.pageSize);
+      return Math.ceil(this.users.length / this.pageSize);
     },
     tableStyle() {
       return {
@@ -282,29 +229,19 @@
           });
         });
     },
-    tween() {},
     nextPage() {
       if (this.currentPage < this.pages) {
-        document.querySelector("#datatable").classList.add("fadeOut");
-        setTimeout(() => {
-          document.querySelector("#datatable").classList.remove("fadeOut");
-          this.currentPage += 1;
-        }, 10);
+        this.currentPage += 1;
       }
-      return;
     },
     prevPage() {
       if (this.currentPage > 0) {
-        document.querySelector("#datatable").classList.add("fadeOut");
-        setTimeout(() => {
-          document.querySelector("#datatable").classList.remove("fadeOut");
-          this.currentPage -= 1;
-        }, 10);
+        this.currentPage -= 1;
       }
-      return;
     },
-    sortBy(criterion) {
-      this.sortCriterion = criterion;
+    sortBy(sorting) {
+      this.sortColumn = sorting.sortColumn;
+      this.sortDirection = sorting.sortDirection;
     },
     deleteUser(name) {
       this.$store.commit("application/popup", {