Ver código fonte

feat: admin - UI optimizations + search, auth UI

NGPixel 7 anos atrás
pai
commit
f203173c6c

+ 53 - 0
client/components/admin-auth.vue

@@ -0,0 +1,53 @@
+<template lang='pug'>
+  v-card(flat)
+    v-card(color='grey lighten-5')
+      .pa-3.pt-4
+        .headline.primary--text Authentication
+        .subheading.grey--text Configure the authentication settings of your wiki
+      v-tabs(color='grey lighten-4', grow, slider-color='primary', show-arrows)
+        v-tab(key='settings'): v-icon settings
+        v-tab(key='db') Local
+        v-tab(key='algolia') Auth0
+        v-tab(key='elasticsearch') Azure AD
+        v-tab(key='solr') Discord
+        v-tab(key='solr') Dropbox
+        v-tab(key='solr') Facebook
+        v-tab(key='solr') GitHub
+        v-tab(key='solr') Google
+        v-tab(key='solr') LDAP
+        v-tab(key='solr') Microsoft
+        v-tab(key='solr') OAuth2 Generic
+        v-tab(key='solr') Slack
+        v-tab(key='solr') Twitch
+
+        v-tab-item(key='settings')
+          v-card.pa-3
+            v-form
+              v-checkbox(v-for='(engine, n) in engines', v-model='auths', :key='n', :label='engine.text', :value='engine.value', color='primary')
+              v-divider
+              v-btn(color='primary')
+                v-icon(left) chevron_right
+                | Set Providers
+
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      engines: [
+        { text: 'Local', value: 'local' },
+        { text: 'Auth0', value: 'auth0' },
+        { text: 'Algolia', value: 'algolia' },
+        { text: 'Elasticsearch', value: 'elasticsearch' },
+        { text: 'Solr', value: 'solr' }
+      ],
+      auths: ['local']
+    }
+  }
+}
+</script>
+
+<style lang='scss'>
+
+</style>

+ 1 - 1
client/components/admin-dashboard.vue

@@ -2,7 +2,7 @@
   v-container(fluid, fill-height)
     v-layout(row wrap)
       v-flex(xs12)
-        .headline.blue--text.text--darken-2 Dashboard
+        .headline.primary--text Dashboard
         .subheading.grey--text Coming soon
 </template>
 

+ 1 - 1
client/components/admin-general.vue

@@ -2,7 +2,7 @@
   v-container(fluid, fill-height, grid-list-lg)
     v-layout(row wrap)
       v-flex(xs12)
-        .headline.blue--text.text--darken-2 General
+        .headline.primary--text General
         .subheading.grey--text Main settings of your wiki
         v-form.pt-3
           v-layout(row wrap)

+ 2 - 2
client/components/admin-locale.vue

@@ -2,7 +2,7 @@
   v-container(fluid, fill-height, grid-list-lg)
     v-layout(row wrap)
       v-flex(xs12)
-        .headline.blue--text.text--darken-2 Locale
+        .headline.primary--text Locale
         .subheading.grey--text Set localization options for your wiki
         v-form.pt-3
           v-layout(row wrap)
@@ -21,7 +21,7 @@
                         v-list-tile-title(v-html='data.item.text')
                         v-list-tile-sub-title(v-html='data.item.original')
                   v-divider
-                  v-switch(v-model='rtlEnabled', label='RTL Text Display', color='blue darken-2', persistent-hint, hint='For Right-to-Left languages, e.g. Arabic')
+                  v-switch(v-model='rtlEnabled', label='RTL Text Display', color='primary', persistent-hint, hint='For Right-to-Left languages, e.g. Arabic')
             v-flex(lg6 xs12)
               v-card
                 v-toolbar(color='blue', dark, dense, flat)

+ 54 - 0
client/components/admin-search.vue

@@ -0,0 +1,54 @@
+<template lang='pug'>
+  v-card(flat)
+    v-card(color='grey lighten-5')
+      .pa-3.pt-4
+        .headline.primary--text Search Engine
+        .subheading.grey--text Configure the search capabilities of your wiki
+      v-tabs(color='grey lighten-4', grow, slider-color='primary', show-arrows)
+        v-tab(key='settings'): v-icon settings
+        v-tab(key='db') Database
+        v-tab(key='algolia') Algolia
+        v-tab(key='elasticsearch') Elasticsearch
+        v-tab(key='solr') Solr
+
+        v-tab-item(key='settings')
+          v-card.pa-3
+            v-form
+              v-radio-group(v-model='selectedEngine')
+                v-radio(v-for='(engine, n) in engines', :key='n', :label='engine.text', :value='engine.value', color='primary')
+              v-divider
+              v-btn(color='primary')
+                v-icon(left) chevron_right
+                | Set Engine
+        v-tab-item(key='db')
+          v-card.pa-3 TODO
+        v-tab-item(key='algolia')
+          v-card.pa-3 TODO
+        v-tab-item(key='elasticsearch')
+          v-card.pa-3 TODO
+        v-tab-item(key='solr')
+          v-card.pa-3 TODO
+
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      engines: [
+        { text: 'Disabled', value: 'disabled' },
+        { text: 'Database (built-in)', value: 'db' },
+        { text: 'Algolia', value: 'algolia' },
+        { text: 'Elasticsearch', value: 'elasticsearch' },
+        { text: 'Solr', value: 'solr' }
+      ],
+      selectedEngine: 'db',
+      darkMode: false
+    }
+  }
+}
+</script>
+
+<style lang='scss'>
+
+</style>

+ 2 - 2
client/components/admin-system.vue

@@ -2,7 +2,7 @@
   v-container(fluid, fill-height, grid-list-lg)
     v-layout(row, wrap)
       v-flex(xs12)
-        .headline.blue--text.text--darken-2 System Info
+        .headline.primary--text System Info
         .subheading.grey--text Information about your system
         v-layout.mt-3(row wrap)
           v-flex(lg6 xs12)
@@ -68,7 +68,7 @@
                     v-avatar.light-green(size='40')
                       icon-node-js(fillColor='#FFFFFF')
                   v-list-tile-content
-                    v-list-tile-title v8.9.4
+                    v-list-tile-title 8.9.4
 
                 v-divider
 

+ 2 - 2
client/components/admin-theme.vue

@@ -2,7 +2,7 @@
   v-container(fluid, fill-height, grid-list-lg)
     v-layout(row wrap)
       v-flex(xs12)
-        .headline.blue--text.text--darken-2 Theme
+        .headline.primary--text Theme
         .subheading.grey--text Modify the look &amp; feel of your wiki
         v-form.pt-3
           v-layout(row wrap)
@@ -21,7 +21,7 @@
                         v-list-tile-title(v-html='data.item.text')
                         v-list-tile-sub-title(v-html='data.item.author')
                   v-divider
-                  v-switch(v-model='darkMode', label='Dark Mode', color='blue darken-2', persistent-hint, hint='Not recommended for accessibility')
+                  v-switch(v-model='darkMode', label='Dark Mode', color='primary', persistent-hint, hint='Not recommended for accessibility')
             v-flex(lg6 xs12)
               v-card
                 v-toolbar(color='blue', dark, dense, flat)

+ 73 - 13
client/components/admin-users.vue

@@ -6,8 +6,14 @@
         .subheading.grey--text Manage users
         v-card.mt-3.elevation-1
           v-card-title
-            v-btn() New User
-            v-btn() Authorize User
+            v-btn(color='primary', dark)
+              v-icon(left) add
+              | New User
+            v-btn(color='primary', dark)
+              v-icon(left) lock_outline
+              | Authorize User
+            v-btn(icon)
+              v-icon.grey--text refresh
             v-spacer
             v-text-field(append-icon='search', label='Search', single-line, hide-details, v-model='search')
           v-data-table(
@@ -16,17 +22,41 @@
             :headers='headers',
             :search='search',
             :pagination.sync='pagination',
+            :rows-per-page-items='[15]'
             select-all,
-            hide-actions
+            hide-actions,
+            disable-initial-sort
           )
+            template(slot='headers', slot-scope='props')
+              tr
+                th(width='50')
+                th.text-xs-right(
+                  width='80'
+                  :class='[`column sortable`, pagination.descending ? `desc` : `asc`, pagination.sortBy === `id` ? `active` : ``]'
+                  @click='changeSort(`id`)'
+                )
+                  v-icon(small) arrow_upward
+                  | ID
+                th.text-xs-left(
+                  v-for='header in props.headers'
+                  :key='header.text'
+                  :width='header.width'
+                  :class='[`column sortable`, pagination.descending ? `desc` : `asc`, header.value === pagination.sortBy ? `active` : ``]'
+                  @click='changeSort(header.value)'
+                )
+                  | {{ header.text }}
+                  v-icon(small) arrow_upward
             template(slot='items', slot-scope='props')
-              tr(:active='props.selected', @click='props.selected = !props.selected')
+              tr(:active='props.selected')
                 td
-                  v-checkbox(hide-details, :input-value='props.selected')
+                  v-checkbox(hide-details, :input-value='props.selected', color='blue darken-2', @click='props.selected = !props.selected')
                 td.text-xs-right {{ props.item.id }}
                 td {{ props.item.email }}
                 td {{ props.item.name }}
                 td {{ props.item.provider }}
+                td {{ props.item.createdOn }}
+                td {{ props.item.updatedOn }}
+                td: v-btn(icon): v-icon.grey--text.text--darken-1 more_horiz
             template(slot='no-data')
               v-alert(icon='warning', :value='true') No users to display!
           .text-xs-center.py-2
@@ -40,21 +70,34 @@ export default {
       selected: [],
       pagination: {},
       items: [
-        { id: 1, email: 'user@test.com', name: 'John Doe', provider: 'local' }
+        { id: 1, email: 'user@test.com', name: 'John Doe', provider: 'local' },
+        { id: 2, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 3, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 4, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 5, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 6, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 7, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 8, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 9, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 10, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 11, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 12, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 13, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 14, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 15, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 16, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 17, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 18, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 19, email: 'dude@test.com', name: 'John Doe', provider: 'local' },
+        { id: 20, email: 'dude@test.com', name: 'John Doe', provider: 'local' }
       ],
       headers: [
-        {
-          text: 'ID',
-          align: 'right',
-          value: 'id',
-          width: 80
-        },
         { text: 'Email', value: 'email' },
         { text: 'Name', value: 'name' },
         { text: 'Provider', value: 'provider' },
         { text: 'Created On', value: 'createdOn' },
         { text: 'Updated On', value: 'updatedOn' },
-        { text: 'Actions', value: 'actions', sortable: false }
+        { text: '', value: 'actions', sortable: false, width: 50 }
       ],
       search: ''
     }
@@ -67,6 +110,23 @@ export default {
 
       return Math.ceil(this.pagination.totalItems / this.pagination.rowsPerPage)
     }
+  },
+  methods: {
+    changeSort (column) {
+      if (this.pagination.sortBy === column) {
+        this.pagination.descending = !this.pagination.descending
+      } else {
+        this.pagination.sortBy = column
+        this.pagination.descending = false
+      }
+    },
+    toggleAll () {
+      if (this.selected.length) {
+        this.selected = []
+      } else {
+        this.selected = this.items.slice()
+      }
+    }
   }
 }
 </script>

+ 2 - 0
client/components/admin.vue

@@ -81,6 +81,8 @@ const router = new VueRouter({
     { path: '/locale', component: () => import(/* webpackChunkName: "admin" */ './admin-locale.vue') },
     { path: '/theme', component: () => import(/* webpackChunkName: "admin" */ './admin-theme.vue') },
     { path: '/users', component: () => import(/* webpackChunkName: "admin" */ './admin-users.vue') },
+    { path: '/auth', component: () => import(/* webpackChunkName: "admin" */ './admin-auth.vue') },
+    { path: '/search', component: () => import(/* webpackChunkName: "admin" */ './admin-search.vue') },
     { path: '/system', component: () => import(/* webpackChunkName: "admin" */ './admin-system.vue') }
   ]
 })

+ 6 - 0
client/scss/base/base.scss

@@ -41,6 +41,12 @@ html {
 	padding: 20px;
 }
 
+.datatable {
+  th, td {
+    vertical-align: middle;
+  }
+}
+
 // Visibility
 
 .is-hidden {