瀏覽代碼

feat: admin create user + markdown help fix

Nick 5 年之前
父節點
當前提交
2d2cf90514

+ 1 - 1
client/client-app.js

@@ -64,7 +64,7 @@ const graphQLLink = ApolloLink.from([
       )
       )
       store.commit('showNotification', {
       store.commit('showNotification', {
         style: 'red',
         style: 'red',
-        message: `An expected error occured.`,
+        message: `An unexpected error occured.`,
         icon: 'warning'
         icon: 'warning'
       })
       })
     }
     }

+ 6 - 6
client/components/admin.vue

@@ -26,8 +26,8 @@
             v-list-item(to='/pages', v-if='hasPermission([`manage:system`, `write:pages`, `manage:pages`, `delete:pages`])')
             v-list-item(to='/pages', v-if='hasPermission([`manage:system`, `write:pages`, `manage:pages`, `delete:pages`])')
               v-list-item-avatar(size='24'): v-icon mdi-file-document-outline
               v-list-item-avatar(size='24'): v-icon mdi-file-document-outline
               v-list-item-title {{ $t('admin:pages.title') }}
               v-list-item-title {{ $t('admin:pages.title') }}
-              v-list-item-action
-                v-chip(x-small, disabled, :color='darkMode ? `grey darken-3-d4` : `grey lighten-4`')
+              v-list-item-action.pr-3
+                v-chip(x-small, :color='darkMode ? `grey darken-3-d4` : `grey lighten-5`')
                   .caption.grey--text {{ info.pagesTotal }}
                   .caption.grey--text {{ info.pagesTotal }}
             v-list-item(to='/theme', v-if='hasPermission([`manage:system`, `manage:theme`])')
             v-list-item(to='/theme', v-if='hasPermission([`manage:system`, `manage:theme`])')
               v-list-item-avatar(size='24'): v-icon mdi-palette-outline
               v-list-item-avatar(size='24'): v-icon mdi-palette-outline
@@ -38,14 +38,14 @@
             v-list-item(to='/groups', v-if='hasPermission([`manage:system`, `manage:groups`, `write:groups`])')
             v-list-item(to='/groups', v-if='hasPermission([`manage:system`, `manage:groups`, `write:groups`])')
               v-list-item-avatar(size='24'): v-icon mdi-account-group
               v-list-item-avatar(size='24'): v-icon mdi-account-group
               v-list-item-title {{ $t('admin:groups.title') }}
               v-list-item-title {{ $t('admin:groups.title') }}
-              v-list-item-action
-                v-chip(x-small, disabled, :color='darkMode ? `grey darken-3-d4` : `grey lighten-4`')
+              v-list-item-action.pr-3
+                v-chip(x-small, :color='darkMode ? `grey darken-3-d4` : `grey lighten-4`')
                   .caption.grey--text {{ info.groupsTotal }}
                   .caption.grey--text {{ info.groupsTotal }}
             v-list-item(to='/users', v-if='hasPermission([`manage:system`, `manage:groups`, `write:groups`, `manage:users`, `write:users`])')
             v-list-item(to='/users', v-if='hasPermission([`manage:system`, `manage:groups`, `write:groups`, `manage:users`, `write:users`])')
               v-list-item-avatar(size='24'): v-icon mdi-account-box
               v-list-item-avatar(size='24'): v-icon mdi-account-box
               v-list-item-title {{ $t('admin:users.title') }}
               v-list-item-title {{ $t('admin:users.title') }}
-              v-list-item-action
-                v-chip(x-small, disabled, :color='darkMode ? `grey darken-3-d4` : `grey lighten-4`')
+              v-list-item-action.pr-3
+                v-chip(x-small, :color='darkMode ? `grey darken-3-d4` : `grey lighten-4`')
                   .caption.grey--text {{ info.usersTotal }}
                   .caption.grey--text {{ info.usersTotal }}
           template(v-if='hasPermission(`manage:system`)')
           template(v-if='hasPermission(`manage:system`)')
             v-divider.my-2
             v-divider.my-2

+ 8 - 9
client/components/admin/admin-groups-edit-permissions.vue

@@ -1,27 +1,26 @@
 <template lang="pug">
 <template lang="pug">
-  v-card.wiki-form(flat)
+  v-card(flat)
     v-card-text
     v-card-text
       v-text-field(
       v-text-field(
-        outline
-        background-color='grey lighten-3'
+        outlined
         v-model='group.name'
         v-model='group.name'
         label='Group Name'
         label='Group Name'
         counter='255'
         counter='255'
-        prepend-icon='people'
+        prepend-icon='mdi-account-group'
         )
         )
       v-alert.radius-7(
       v-alert.radius-7(
         v-if='group.isSystem'
         v-if='group.isSystem'
         color='orange darken-2'
         color='orange darken-2'
         :class='$vuetify.theme.dark ? "grey darken-4" : "orange lighten-5"'
         :class='$vuetify.theme.dark ? "grey darken-4" : "orange lighten-5"'
-        outline
+        outlined
         :value='true'
         :value='true'
-        icon='lock_outline'
+        icon='mdi-lock-outline'
         ) This is a system group. Some permissions cannot be modified.
         ) This is a system group. Some permissions cannot be modified.
     v-container.px-3.pb-3.pt-0(fluid, grid-list-md)
     v-container.px-3.pb-3.pt-0(fluid, grid-list-md)
       v-layout(row, wrap)
       v-layout(row, wrap)
         v-flex(xs12, md6, lg4, v-for='pmGroup in permissions', :key='pmGroup.category')
         v-flex(xs12, md6, lg4, v-for='pmGroup in permissions', :key='pmGroup.category')
-          v-card.md2(flat, :class='$vuetify.theme.dark ? "grey darken-3-d5" : "white"')
-            v-subheader {{pmGroup.category}}
+          v-card.md2(flat, :class='$vuetify.theme.dark ? "grey darken-3-d5" : "grey lighten-5"')
+            .overline.px-5.pt-5.pb-3.grey--text.text--darken-2 {{pmGroup.category}}
             v-card-text.pt-0
             v-card-text.pt-0
               template(v-for='(pm, idx) in pmGroup.items')
               template(v-for='(pm, idx) in pmGroup.items')
                 v-checkbox.pt-0(
                 v-checkbox.pt-0(
@@ -32,7 +31,7 @@
                   color='primary'
                   color='primary'
                   v-model='group.permissions'
                   v-model='group.permissions'
                   :value='pm.permission'
                   :value='pm.permission'
-                  :append-icon='pm.warning ? "warning" : null',
+                  :append-icon='pm.warning ? "mdi-alert" : null',
                   :disabled='(group.isSystem && pm.restrictedForSystem) || group.id === 1 || pm.disabled'
                   :disabled='(group.isSystem && pm.restrictedForSystem) || group.id === 1 || pm.disabled'
                 )
                 )
                 v-divider.mt-3(v-if='idx < pmGroup.items.length - 1')
                 v-divider.mt-3(v-if='idx < pmGroup.items.length - 1')

+ 53 - 57
client/components/admin/admin-groups-edit-rules.vue

@@ -1,66 +1,66 @@
 <template lang="pug">
 <template lang="pug">
-  v-card.wiki-form
+  v-card
     v-card-text(v-if='group.id === 1')
     v-card-text(v-if='group.id === 1')
       v-alert.radius-7(
       v-alert.radius-7(
         :class='$vuetify.theme.dark ? "grey darken-4" : "orange lighten-5"'
         :class='$vuetify.theme.dark ? "grey darken-4" : "orange lighten-5"'
         color='orange darken-2'
         color='orange darken-2'
-        outline
-        :value='true'
-        icon='lock_outline'
+        outlined
+        icon='mdi-lock-outline'
         ) This group has access to everything.
         ) This group has access to everything.
     template(v-else)
     template(v-else)
-      v-card-title(:class='$vuetify.theme.dark ? `grey darken-3-d5` : `grey lighten-5`')
-        v-alert.radius-7(
-          :class='$vuetify.theme.dark ? `grey darken-3-d3` : `white`'
-          :value='true'
+      v-card-title(:class='$vuetify.theme.dark ? `grey darken-3-d5` : ``')
+        v-alert.radius-7.caption(
+          :class='$vuetify.theme.dark ? `grey darken-3-d3` : `grey lighten-4`'
           color='grey'
           color='grey'
-          outline
-          icon='info'
+          outlined
+          icon='mdi-information'
           ) You must enable global content permissions (under Permissions tab) for page rules to have any effect.
           ) You must enable global content permissions (under Permissions tab) for page rules to have any effect.
         v-spacer
         v-spacer
-        v-btn(depressed, color='primary', @click='addRule')
-          v-icon(left) add
+        v-btn.mx-2(depressed, color='primary', @click='addRule')
+          v-icon(left) mdi-plus
           | Add Rule
           | Add Rule
         v-menu(
         v-menu(
           right
           right
           offset-y
           offset-y
           nudge-left='115'
           nudge-left='115'
           )
           )
-          v-btn.is-icon(slot='activator', flat, outline, color='primary')
-            v-icon more_horiz
+          template(v-slot:activator='{ on }')
+            v-btn.is-icon(v-on='on', outlined, color='primary')
+              v-icon mdi-dots-horizontal
           v-list(dense)
           v-list(dense)
             v-list-item(@click='comingSoon')
             v-list-item(@click='comingSoon')
               v-list-item-avatar
               v-list-item-avatar
-                v-icon keyboard_capslock
+                v-icon mdi-application-import
               v-list-item-title Load Preset
               v-list-item-title Load Preset
             v-divider
             v-divider
             v-list-item(@click='comingSoon')
             v-list-item(@click='comingSoon')
               v-list-item-avatar
               v-list-item-avatar
-                v-icon publish
+                v-icon mdi-application-export
               v-list-item-title Save As Preset
               v-list-item-title Save As Preset
             v-divider
             v-divider
             v-list-item(@click='comingSoon')
             v-list-item(@click='comingSoon')
               v-list-item-avatar
               v-list-item-avatar
-                v-icon cloud_upload
+                v-icon mdi-cloud-upload
               v-list-item-title Import Rules
               v-list-item-title Import Rules
             v-divider
             v-divider
             v-list-item(@click='comingSoon')
             v-list-item(@click='comingSoon')
               v-list-item-avatar
               v-list-item-avatar
-                v-icon cloud_download
+                v-icon mdi-cloud-download
               v-list-item-title Export Rules
               v-list-item-title Export Rules
       v-card-text(:class='$vuetify.theme.dark ? `grey darken-4-l5` : `white`')
       v-card-text(:class='$vuetify.theme.dark ? `grey darken-4-l5` : `white`')
         .rules
         .rules
           .caption(v-if='group.pageRules.length === 0')
           .caption(v-if='group.pageRules.length === 0')
             em(:class='$vuetify.theme.dark ? `grey--text` : `blue-grey--text`') This group has no page rules yet.
             em(:class='$vuetify.theme.dark ? `grey--text` : `blue-grey--text`') This group has no page rules yet.
           .rule(v-for='rule of group.pageRules', :key='rule.id')
           .rule(v-for='rule of group.pageRules', :key='rule.id')
-            v-btn.ma-0.rule-deny-btn(
+            v-btn.ma-0.radius-4.rule-deny-btn(
               solo
               solo
               :color='rule.deny ? "red" : "green"'
               :color='rule.deny ? "red" : "green"'
               dark
               dark
               @click='rule.deny = !rule.deny'
               @click='rule.deny = !rule.deny'
+              height='48'
               )
               )
-              v-icon(v-if='rule.deny') block
-              v-icon(v-else) check_circle
+              v-icon(v-if='rule.deny') mdi-cancel
+              v-icon(v-else) mdi-check-circle
             //- Roles
             //- Roles
             v-select.ml-1(
             v-select.ml-1(
               solo
               solo
@@ -83,7 +83,7 @@
               template(slot='item', slot-scope='props')
               template(slot='item', slot-scope='props')
                 v-list-item-action(style='min-width: 30px;')
                 v-list-item-action(style='min-width: 30px;')
                   v-checkbox(
                   v-checkbox(
-                    v-model='props.tile.props.value'
+                    v-model='props.attrs.inputValue'
                     hide-details
                     hide-details
                     color='primary'
                     color='primary'
                   )
                   )
@@ -103,7 +103,7 @@
               dense
               dense
               )
               )
               template(slot='selection', slot-scope='{ item, index }')
               template(slot='selection', slot-scope='{ item, index }')
-                .body-1 {{item.text}}
+                .body-2 {{item.text}}
               template(slot='item', slot-scope='data')
               template(slot='item', slot-scope='data')
                 v-list-item-avatar
                 v-list-item-avatar
                   v-avatar.white--text.radius-4(color='blue', size='30', tile) {{ data.item.icon }}
                   v-avatar.white--text.radius-4(color='blue', size='30', tile) {{ data.item.icon }}
@@ -133,18 +133,18 @@
                     color='primary'
                     color='primary'
                     readonly
                     readonly
                   )
                   )
-                v-icon.mr-2(:color='rule.deny ? `red` : `green`') public
+                v-icon.mr-2(:color='rule.deny ? `red` : `green`') mdi-earth
                 v-list-item-content
                 v-list-item-content
                   v-list-item-title.body-2 Any Locale
                   v-list-item-title.body-2 Any Locale
               v-divider(slot='prepend-item')
               v-divider(slot='prepend-item')
               template(slot='item', slot-scope='props')
               template(slot='item', slot-scope='props')
                 v-list-item-action(style='min-width: 30px;')
                 v-list-item-action(style='min-width: 30px;')
                   v-checkbox(
                   v-checkbox(
-                    v-model='props.tile.props.value'
+                    v-model='props.attrs.inputValue'
                     hide-details
                     hide-details
                     color='primary'
                     color='primary'
                   )
                   )
-                v-icon.mr-2(:color='rule.deny ? `red` : `green`') language
+                v-icon.mr-2(:color='rule.deny ? `red` : `green`') mdi-web
                 v-list-item-content
                 v-list-item-content
                   v-list-item-title.body-2 {{props.item.text}}
                   v-list-item-title.body-2 {{props.item.text}}
                 v-chip.mr-2.grey--text(label, small, :color='$vuetify.theme.dark ? `grey darken-4` : `grey lighten-4`').caption {{props.item.value.toUpperCase()}}
                 v-chip.mr-2.grey--text(label, small, :color='$vuetify.theme.dark ? `grey darken-4` : `grey lighten-4`').caption {{props.item.value.toUpperCase()}}
@@ -161,15 +161,15 @@
               :color='$vuetify.theme.dark ? `grey` : `blue-grey`'
               :color='$vuetify.theme.dark ? `grey` : `blue-grey`'
               )
               )
 
 
-            v-btn(icon, @click='removeRule(rule.id)')
-              v-icon(:color='$vuetify.theme.dark ? `grey` : `blue-grey`') clear
+            v-btn.ml-2.mt-1(icon, @click='removeRule(rule.id)', small)
+              v-icon(:color='$vuetify.theme.dark ? `grey` : `blue-grey`') mdi-close
 
 
         v-divider.mt-3
         v-divider.mt-3
-        v-subheader.pl-0 Rules Order
-        .body-1.pl-3 Rules are applied in order of path specificity. A more precise path will always override a less defined path.
-        .body-1.pl-4 For example, #[span.teal--text /geography/countries] will override #[span.teal--text /geography].
-        .body-1.pl-3.pt-2 When 2 rules have the same specificity, the priority is given from lowest to highest as follows:
-        .body-1.pl-3.pt-1
+        .overline.py-3 Rules Order
+        .body-2.pl-3 Rules are applied in order of path specificity. A more precise path will always override a less defined path.
+        .body-2.pl-5 For example, #[span.teal--text /geography/countries] will override #[span.teal--text /geography].
+        .body-2.pl-3.pt-2 When 2 rules have the same specificity, the priority is given from lowest to highest as follows:
+        .body-2.pl-3.pt-1
           ul
           ul
             li
             li
               strong Path Starts With...
               strong Path Starts With...
@@ -181,9 +181,9 @@
             li
             li
               strong Path Is Exactly...
               strong Path Is Exactly...
               em.caption.pl-1 (highest)
               em.caption.pl-1 (highest)
-        .body-1.pl-3.pt-2 When 2 rules have the same path specificity AND the same match type, #[strong.red--text DENY] will always override an #[strong.green--text ALLOW] rule.
+        .body-2.pl-3.pt-2 When 2 rules have the same path specificity AND the same match type, #[strong.red--text DENY] will always override an #[strong.green--text ALLOW] rule.
         v-divider.mt-3
         v-divider.mt-3
-        v-subheader.pl-0 Regular Expressions
+        .overline.py-3 Regular Expressions
         span Expressions that are deemed unsafe or could result in exponential time processing will be rejected upon saving.
         span Expressions that are deemed unsafe or could result in exponential time processing will be rejected upon saving.
 
 
 </template>
 </template>
@@ -202,18 +202,18 @@ export default {
   data() {
   data() {
     return {
     return {
       roles: [
       roles: [
-        { text: 'Read Pages', value: 'read:pages', icon: 'insert_drive_file' },
-        { text: 'Create Pages', value: 'write:pages', icon: 'insert_drive_file' },
-        { text: 'Edit + Move Pages', value: 'manage:pages', icon: 'insert_drive_file' },
-        { text: 'Delete Pages', value: 'delete:pages', icon: 'insert_drive_file' },
-        { text: 'View Pages Source', value: 'read:source', icon: 'code' },
-        { text: 'View Pages History', value: 'read:history', icon: 'restore' },
-        { text: 'Read / Use Assets', value: 'read:assets', icon: 'camera' },
-        { text: 'Upload Assets', value: 'write:assets', icon: 'camera' },
-        { text: 'Edit + Delete Assets', value: 'manage:assets', icon: 'camera' },
-        { text: 'Read Comments', value: 'read:comments', icon: 'insert_comment' },
-        { text: 'Create Comments', value: 'write:comments', icon: 'insert_comment' },
-        { text: 'Edit + Delete Comments', value: 'manage:comments', icon: 'insert_comment' }
+        { text: 'Read Pages', value: 'read:pages', icon: 'mdi-file-document-box-search-outline' },
+        { text: 'Create Pages', value: 'write:pages', icon: 'mdi-file-document-box-plus-outline' },
+        { text: 'Edit + Move Pages', value: 'manage:pages', icon: 'mdi-file-document-edit-outline' },
+        { text: 'Delete Pages', value: 'delete:pages', icon: 'mdi-file-document-box-remove-outline' },
+        { text: 'View Pages Source', value: 'read:source', icon: 'mdi-code-tags' },
+        { text: 'View Pages History', value: 'read:history', icon: 'mdi-history' },
+        { text: 'Read / Use Assets', value: 'read:assets', icon: 'mdi-image-search-outline' },
+        { text: 'Upload Assets', value: 'write:assets', icon: 'mdi-image-plus' },
+        { text: 'Edit + Delete Assets', value: 'manage:assets', icon: 'mdi-image-size-select-large' },
+        { text: 'Read Comments', value: 'read:comments', icon: 'mdi-comment-search-outline' },
+        { text: 'Create Comments', value: 'write:comments', icon: 'mdi-comment-plus-outline' },
+        { text: 'Edit + Delete Comments', value: 'manage:comments', icon: 'mdi-comment-remove-outline' }
       ],
       ],
       matches: [
       matches: [
         { text: 'Path Starts With...', value: 'START', icon: '/...' },
         { text: 'Path Starts With...', value: 'START', icon: '/...' },
@@ -252,6 +252,9 @@ export default {
         message: `Coming soon...`,
         message: `Coming soon...`,
         icon: 'directions_boat'
         icon: 'directions_boat'
       })
       })
+    },
+    dude (stuff) {
+      console.info(stuff)
     }
     }
   }
   }
 }
 }
@@ -264,7 +267,7 @@ export default {
   padding: 1rem;
   padding: 1rem;
   position: relative;
   position: relative;
 
 
-  @at-root .theme--dark & {
+  @at-root .v-application.theme--dark & {
     background-color: mc('grey', '800');
     background-color: mc('grey', '800');
   }
   }
 }
 }
@@ -282,7 +285,7 @@ export default {
     opacity: 0;
     opacity: 0;
   }
   }
 
 
-  @at-root .theme--dark & {
+  @at-root .v-application.theme--dark & {
     background-color: mc('grey', '700');
     background-color: mc('grey', '700');
   }
   }
 
 
@@ -306,7 +309,7 @@ export default {
       left: -2rem;
       left: -2rem;
       top: -1.3rem;
       top: -1.3rem;
 
 
-      @at-root .theme--dark & {
+      @at-root .v-application.theme--dark & {
         background-color: mc('grey', '800');
         background-color: mc('grey', '800');
         color: mc('grey', '600');
         color: mc('grey', '600');
       }
       }
@@ -316,12 +319,5 @@ export default {
   .input-group + * {
   .input-group + * {
     margin-left: .5rem;
     margin-left: .5rem;
   }
   }
-
-  &-deny-btn {
-    height: 48px;
-    border-radius: 2px 0 0 2px;
-    min-width: 0;
-  }
-
 }
 }
 </style>
 </style>

+ 22 - 18
client/components/admin/admin-groups-edit-users.vue

@@ -1,49 +1,52 @@
 <template lang="pug">
 <template lang="pug">
-  v-card.wiki-form
-    v-card-title(:class='$vuetify.theme.dark ? `grey darken-3-d3` : `grey lighten-5`')
+  v-card
+    v-card-title.pb-4(:class='$vuetify.theme.dark ? `grey darken-3-d3` : `grey lighten-5`')
       v-text-field(
       v-text-field(
-        outline
+        outlined
         flat
         flat
-        prepend-inner-icon='search'
+        prepend-inner-icon='mdi-magnify'
         v-model='search'
         v-model='search'
         label='Search Group Users...'
         label='Search Group Users...'
         hide-details
         hide-details
       )
       )
       v-spacer
       v-spacer
       v-btn(color='primary', depressed, @click='searchUserDialog = true', :disabled='group.id === 2')
       v-btn(color='primary', depressed, @click='searchUserDialog = true', :disabled='group.id === 2')
-        v-icon(left) assignment_ind
+        v-icon(left) mdi-clipboard-account
         | Assign User
         | Assign User
     v-data-table(
     v-data-table(
       :items='group.users',
       :items='group.users',
       :headers='headers',
       :headers='headers',
       :search='search'
       :search='search'
-      :pagination.sync='pagination',
-      :rows-per-page-items='[15]'
-      hide-actions
+      :page.sync='pagination'
+      :items-per-page='15'
+      @page-count='pageCount = $event'
+      must-sort,
+      hide-default-footer
     )
     )
-      template(slot='items', slot-scope='props')
+      template(slot='item', slot-scope='props')
         tr(:active='props.selected')
         tr(:active='props.selected')
           td.text-xs-right {{ props.item.id }}
           td.text-xs-right {{ props.item.id }}
           td {{ props.item.name }}
           td {{ props.item.name }}
           td {{ props.item.email }}
           td {{ props.item.email }}
           td
           td
             v-menu(bottom, right, min-width='200')
             v-menu(bottom, right, min-width='200')
-              v-btn(icon, slot='activator'): v-icon.grey--text.text--darken-1 more_horiz
-              v-list
+              template(v-slot:activator='{ on }')
+                v-btn(icon, v-on='on', small)
+                  v-icon.grey--text.text--darken-1 mdi-dots-horizontal
+              v-list(dense, nav)
                 v-list-item(:to='`/users/` + props.item.id')
                 v-list-item(:to='`/users/` + props.item.id')
-                  v-list-item-action: v-icon(color='primary') person
+                  v-list-item-action: v-icon(color='primary') mdi-account-outline
                   v-list-item-content
                   v-list-item-content
                     v-list-item-title View User Profile
                     v-list-item-title View User Profile
                 template(v-if='props.item.id !== 2')
                 template(v-if='props.item.id !== 2')
-                  v-divider
                   v-list-item(@click='unassignUser(props.item.id)')
                   v-list-item(@click='unassignUser(props.item.id)')
-                    v-list-item-action: v-icon(color='orange') highlight_off
+                    v-list-item-action: v-icon(color='orange') mdi-account-remove-outline
                     v-list-item-content
                     v-list-item-content
                       v-list-item-title Unassign
                       v-list-item-title Unassign
       template(slot='no-data')
       template(slot='no-data')
-        v-alert.ma-3(icon='warning', :value='true', outline) No users to display.
-    .text-xs-center.py-2(v-if='group.users.length > 15')
-      v-pagination(v-model='pagination.page', :length='pages')
+        v-alert.ma-3(icon='warning', outlined) No users to display.
+    .text-center.py-2(v-if='group.users.length > 15')
+      v-pagination(v-model='pagination', :length='pageCount')
 
 
     user-search(v-model='searchUserDialog', @select='assignUser')
     user-search(v-model='searchUserDialog', @select='assignUser')
 </template>
 </template>
@@ -73,7 +76,8 @@ export default {
         { text: '', value: 'actions', sortable: false, width: 50 }
         { text: '', value: 'actions', sortable: false, width: 50 }
       ],
       ],
       searchUserDialog: false,
       searchUserDialog: false,
-      pagination: {},
+      pagination: 1,
+      pageCount: 0,
       search: ''
       search: ''
     }
     }
   },
   },

+ 9 - 8
client/components/admin/admin-groups-edit.vue

@@ -10,11 +10,12 @@
           v-spacer
           v-spacer
           .caption.grey--text ID #[strong {{group.id}}]
           .caption.grey--text ID #[strong {{group.id}}]
           v-divider.mx-3(vertical)
           v-divider.mx-3(vertical)
-          v-btn(color='grey', large, outline, to='/groups')
-            v-icon arrow_back
+          v-btn(color='grey', large, outlined, to='/groups')
+            v-icon mdi-arrow-left
           v-dialog(v-model='deleteGroupDialog', max-width='500', v-if='!group.isSystem')
           v-dialog(v-model='deleteGroupDialog', max-width='500', v-if='!group.isSystem')
-            v-btn(color='red', large, outline, slot='activator')
-              v-icon(color='red') delete
+            template(v-slot:activator='{ on }')
+              v-btn(color='red', large, outlined, v-on='{ on }')
+                v-icon(color='red') mdi-trash-can-outline
             v-card
             v-card
               .dialog-header.is-red Delete Group?
               .dialog-header.is-red Delete Group?
               v-card-text Are you sure you want to delete group #[strong {{ group.name }}]? All users will be unassigned from this group.
               v-card-text Are you sure you want to delete group #[strong {{ group.name }}]? All users will be unassigned from this group.
@@ -22,11 +23,11 @@
                 v-spacer
                 v-spacer
                 v-btn(flat, @click='deleteGroupDialog = false') Cancel
                 v-btn(flat, @click='deleteGroupDialog = false') Cancel
                 v-btn(color='red', dark, @click='deleteGroup') Delete
                 v-btn(color='red', dark, @click='deleteGroup') Delete
-          v-btn(color='success', large, depressed, @click='updateGroup')
-            v-icon(left) check
+          v-btn.ml-2(color='success', large, depressed, @click='updateGroup')
+            v-icon(left) mdi-check
             span Update Group
             span Update Group
         v-card.mt-3
         v-card.mt-3
-          v-tabs(v-model='tab', :color='$vuetify.theme.dark ? "primary" : "grey darken-2"', fixed-tabs, slider-color='white', show-arrows, dark)
+          v-tabs(v-model='tab', :background-color='$vuetify.theme.dark ? "primary" : "grey darken-2"', fixed-tabs, slider-color='white', show-arrows, dark)
             v-tab(key='permissions') Permissions
             v-tab(key='permissions') Permissions
             v-tab(key='rules') Page Rules
             v-tab(key='rules') Page Rules
             v-tab(key='users') Users
             v-tab(key='users') Users
@@ -69,7 +70,7 @@ export default {
         users: []
         users: []
       },
       },
       deleteGroupDialog: false,
       deleteGroupDialog: false,
-      tab: '1'
+      tab: null
     }
     }
   },
   },
   methods: {
   methods: {

+ 17 - 19
client/components/admin/admin-groups.vue

@@ -37,25 +37,29 @@
             :items='groups'
             :items='groups'
             :headers='headers'
             :headers='headers'
             :search='search'
             :search='search'
-            :pagination.sync='pagination'
-            :rows-per-page-items='[15]'
-            hide-actions
+            :page.sync='pagination'
+            :items-per-page='15'
+            :loading='loading'
+            @page-count='pageCount = $event'
+            must-sort,
+            hide-default-footer
           )
           )
-            template(slot='items', slot-scope='props')
+            template(slot='item', slot-scope='props')
               tr.is-clickable(:active='props.selected', @click='$router.push("/groups/" + props.item.id)')
               tr.is-clickable(:active='props.selected', @click='$router.push("/groups/" + props.item.id)')
-                td.text-xs-right {{ props.item.id }}
+                td {{ props.item.id }}
                 td: strong {{ props.item.name }}
                 td: strong {{ props.item.name }}
                 td {{ props.item.userCount }}
                 td {{ props.item.userCount }}
                 td {{ props.item.createdAt | moment('calendar') }}
                 td {{ props.item.createdAt | moment('calendar') }}
                 td {{ props.item.updatedAt | moment('calendar') }}
                 td {{ props.item.updatedAt | moment('calendar') }}
                 td
                 td
                   v-tooltip(left, v-if='props.item.isSystem')
                   v-tooltip(left, v-if='props.item.isSystem')
-                    v-icon(slot='activator') lock_outline
+                    template(v-slot:activator='{ on }')
+                      v-icon(v-on='on') mdi-lock-outline
                     span System Group
                     span System Group
             template(slot='no-data')
             template(slot='no-data')
               v-alert.ma-3(icon='warning', :value='true', outline) No groups to display.
               v-alert.ma-3(icon='warning', :value='true', outline) No groups to display.
-          .text-xs-center.py-2(v-if='this.pages > 0')
-            v-pagination(v-model='pagination.page', :length='pages')
+          .text-xs-center.py-2(v-if='pageCount > 1')
+            v-pagination(v-model='pagination', :length='pageCount')
 </template>
 </template>
 
 
 <script>
 <script>
@@ -70,7 +74,8 @@ export default {
       newGroupDialog: false,
       newGroupDialog: false,
       newGroupName: '',
       newGroupName: '',
       selectedGroup: {},
       selectedGroup: {},
-      pagination: {},
+      pagination: 1,
+      pageCount: 0,
       groups: [],
       groups: [],
       headers: [
       headers: [
         { text: 'ID', value: 'id', width: 50, align: 'right' },
         { text: 'ID', value: 'id', width: 50, align: 'right' },
@@ -80,16 +85,8 @@ export default {
         { text: 'Last Updated', value: 'updatedAt', width: 250 },
         { text: 'Last Updated', value: 'updatedAt', width: 250 },
         { text: '', value: 'isSystem', width: 20, sortable: false }
         { text: '', value: 'isSystem', width: 20, sortable: false }
       ],
       ],
-      search: ''
-    }
-  },
-  computed: {
-    pages () {
-      if (this.pagination.rowsPerPage == null || this.pagination.totalItems == null) {
-        return 0
-      }
-
-      return Math.ceil(this.pagination.totalItems / this.pagination.rowsPerPage)
+      search: '',
+      loading: false
     }
     }
   },
   },
   watch: {
   watch: {
@@ -158,6 +155,7 @@ export default {
       fetchPolicy: 'network-only',
       fetchPolicy: 'network-only',
       update: (data) => data.groups.list,
       update: (data) => data.groups.list,
       watchLoading (isLoading) {
       watchLoading (isLoading) {
+        this.loading = isLoading
         this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-groups-refresh')
         this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-groups-refresh')
       }
       }
     }
     }

+ 4 - 4
client/components/admin/admin-storage.vue

@@ -46,7 +46,7 @@
               v-list-item(:key='tgt.key')
               v-list-item(:key='tgt.key')
                 template(v-if='tgt.status === `pending`')
                 template(v-if='tgt.status === `pending`')
                   v-list-item-avatar(color='purple')
                   v-list-item-avatar(color='purple')
-                    v-icon(color='white') schedule
+                    v-icon(color='white') mdi-clock-outline
                   v-list-item-content
                   v-list-item-content
                     v-list-item-title.body-2 {{tgt.title}}
                     v-list-item-title.body-2 {{tgt.title}}
                     v-list-item-sub-title.purple--text.caption {{tgt.status}}
                     v-list-item-sub-title.purple--text.caption {{tgt.status}}
@@ -54,20 +54,20 @@
                     v-progress-circular(indeterminate, :size='20', :width='2', color='purple')
                     v-progress-circular(indeterminate, :size='20', :width='2', color='purple')
                 template(v-else-if='tgt.status === `operational`')
                 template(v-else-if='tgt.status === `operational`')
                   v-list-item-avatar(color='green')
                   v-list-item-avatar(color='green')
-                    v-icon(color='white') check_circle
+                    v-icon(color='white') mdi-check-circle
                   v-list-item-content
                   v-list-item-content
                     v-list-item-title.body-2 {{tgt.title}}
                     v-list-item-title.body-2 {{tgt.title}}
                     v-list-item-sub-title.green--text.caption {{$t('admin:storage.lastSync', { time: $options.filters.moment(tgt.lastAttempt, 'from') })}}
                     v-list-item-sub-title.green--text.caption {{$t('admin:storage.lastSync', { time: $options.filters.moment(tgt.lastAttempt, 'from') })}}
                 template(v-else)
                 template(v-else)
                   v-list-item-avatar(color='red')
                   v-list-item-avatar(color='red')
-                    v-icon(color='white') highlight_off
+                    v-icon(color='white') mdi-close-circle-outline
                   v-list-item-content
                   v-list-item-content
                     v-list-item-title.body-2 {{tgt.title}}
                     v-list-item-title.body-2 {{tgt.title}}
                     v-list-item-sub-title.red--text.caption {{$t('admin:storage.lastSyncAttempt', { time: $options.filters.moment(tgt.lastAttempt, 'from') })}}
                     v-list-item-sub-title.red--text.caption {{$t('admin:storage.lastSyncAttempt', { time: $options.filters.moment(tgt.lastAttempt, 'from') })}}
                   v-list-item-action
                   v-list-item-action
                     v-menu
                     v-menu
                       v-btn(slot='activator', icon)
                       v-btn(slot='activator', icon)
-                        v-icon(color='red') info
+                        v-icon(color='red') mdi-information
                       v-card(width='450')
                       v-card(width='450')
                         v-toolbar(flat, color='red', dark, dense) {{$t('admin:storage.errorMsg')}}
                         v-toolbar(flat, color='red', dark, dense) {{$t('admin:storage.errorMsg')}}
                         v-card-text {{tgt.message}}
                         v-card-text {{tgt.message}}

+ 13 - 7
client/components/admin/admin-users-create.vue

@@ -1,6 +1,6 @@
 <template lang="pug">
 <template lang="pug">
   v-dialog(v-model='isShown', max-width='650', persistent)
   v-dialog(v-model='isShown', max-width='650', persistent)
-    v-card.wiki-form
+    v-card
       .dialog-header.is-short
       .dialog-header.is-short
         v-icon.mr-3(color='white') mdi-plus
         v-icon.mr-3(color='white') mdi-plus
         span New User
         span New User
@@ -59,13 +59,14 @@
           data-vv-as='Name',
           data-vv-as='Name',
           data-vv-scope='newUser',
           data-vv-scope='newUser',
           :error-messages='errors.collect(`newUser.name`)'
           :error-messages='errors.collect(`newUser.name`)'
+          :hint='provider === `local` ? `Can be changed by the user.` : `May be overwritten by the provider during login.`'
           key='newUserName'
           key='newUserName'
           persistent-hint
           persistent-hint
           )
           )
-        v-select(
+        v-select.mt-2(
           :items='groups'
           :items='groups'
           item-text='name'
           item-text='name'
-          item-value='key'
+          item-value='id'
           outlined
           outlined
           prepend-icon='mdi-account-group'
           prepend-icon='mdi-account-group'
           v-model='group'
           v-model='group'
@@ -90,8 +91,12 @@
       v-card-chin
       v-card-chin
         v-spacer
         v-spacer
         v-btn(text, @click='isShown = false') Cancel
         v-btn(text, @click='isShown = false') Cancel
-        v-btn(depressed, color='primary', @click='newUser(false)', :disabled='errors.any(`newUser`)') Create
-        v-btn(depressed, color='primary', @click='newUser(true)', :disabled='errors.any(`newUser`)') Create and Close
+        v-btn.px-3(depressed, color='primary', @click='newUser(false)', :disabled='errors.any(`newUser`)')
+          v-icon(left) mdi-chevron-right
+          span Create
+        v-btn.px-3(depressed, color='primary', @click='newUser(true)', :disabled='errors.any(`newUser`)')
+          v-icon(left) mdi-chevron-double-right
+          span Create and Close
 </template>
 </template>
 
 
 <script>
 <script>
@@ -116,7 +121,7 @@ export default {
       password: '',
       password: '',
       name: '',
       name: '',
       groups: [],
       groups: [],
-      group: '',
+      group: [],
       mustChangePwd: false,
       mustChangePwd: false,
       sendWelcomeEmail: false
       sendWelcomeEmail: false
     }
     }
@@ -155,7 +160,7 @@ export default {
             email: this.email,
             email: this.email,
             passwordRaw: this.password,
             passwordRaw: this.password,
             name: this.name,
             name: this.name,
-            groups: this.groups,
+            groups: this.group,
             mustChangePassword: this.mustChangePwd,
             mustChangePassword: this.mustChangePwd,
             sendWelcomeEmail: this.sendWelcomeEmail
             sendWelcomeEmail: this.sendWelcomeEmail
           },
           },
@@ -176,6 +181,7 @@ export default {
 
 
           if (close) {
           if (close) {
             this.isShown = false
             this.isShown = false
+            this.$emit('refresh')
           } else {
           } else {
             this.$refs.emailInput.focus()
             this.$refs.emailInput.focus()
           }
           }

+ 78 - 66
client/components/admin/admin-users-edit.vue

@@ -9,150 +9,162 @@
             .subtitle-1.grey--text.animated.fadeInLeft.wait-p2s {{user.name}}
             .subtitle-1.grey--text.animated.fadeInLeft.wait-p2s {{user.name}}
           v-spacer
           v-spacer
           .caption.grey--text.animated.fadeInRight.wait-p5s ID #[strong {{user.id}}]
           .caption.grey--text.animated.fadeInRight.wait-p5s ID #[strong {{user.id}}]
-          v-divider.animated.fadeInRight.wait-p3s.mx-3(vertical)
-          v-btn.animated.fadeInDown.wait-p2s(color='grey', large, outline, to='/users')
-            v-icon arrow_back
+          v-divider.animated.fadeInRight.wait-p3s.ml-3(vertical)
+          v-btn.ml-3.animated.fadeInDown.wait-p2s(color='grey', large, outlined, to='/users')
+            v-icon mdi-arrow-left
           v-dialog(v-model='deleteUserDialog', max-width='500', v-if='user.id !== currentUserId && !user.isSystem')
           v-dialog(v-model='deleteUserDialog', max-width='500', v-if='user.id !== currentUserId && !user.isSystem')
-            v-btn.animated.fadeInDown.wait-p1s(color='red', large, outline, slot='activator')
-              v-icon(color='red') delete
+            template(v-slot:activator='{ on }')
+              v-btn.ml-3.animated.fadeInDown.wait-p1s(color='red', large, outlined, v-on='on')
+                v-icon(color='red') mdi-trash-can-outline
             v-card
             v-card
               .dialog-header.is-red Delete User?
               .dialog-header.is-red Delete User?
               v-card-text Are you sure you want to delete user #[strong {{ user.name }}]?
               v-card-text Are you sure you want to delete user #[strong {{ user.name }}]?
               v-card-actions
               v-card-actions
                 v-spacer
                 v-spacer
-                v-btn(flat, @click='deleteUserDialog = false') Cancel
+                v-btn(text, @click='deleteUserDialog = false') Cancel
                 v-btn(color='red', dark, @click='deleteUser') Delete
                 v-btn(color='red', dark, @click='deleteUser') Delete
-          v-btn.animated.fadeInDown(color='primary', large, depressed, @click='updateUser')
-            v-icon(left) check
+          v-btn.ml-3.animated.fadeInDown(color='primary', large, depressed, @click='updateUser')
+            v-icon(left) mdi-check
             span Update User
             span Update User
       v-flex(xs5)
       v-flex(xs5)
         v-card.animated.fadeInUp
         v-card.animated.fadeInUp
           v-toolbar(color='primary', dense, dark, flat)
           v-toolbar(color='primary', dense, dark, flat)
-            v-icon.mr-2 directions_run
+            v-icon.mr-2 mdi-information-variant
             span Basic Info
             span Basic Info
           v-list.py-0(two-line, dense)
           v-list.py-0(two-line, dense)
             v-list-item
             v-list-item
-              v-list-item-avatar
-                v-icon alternate_email
+              v-list-item-avatar(size='32')
+                v-icon mdi-email-variant
               v-list-item-content
               v-list-item-content
                 v-list-item-title Email
                 v-list-item-title Email
-                v-list-item-sub-title {{ user.email }}
+                v-list-item-subtitle {{ user.email }}
               v-list-item-action(v-if='!user.isSystem')
               v-list-item-action(v-if='!user.isSystem')
-                  v-btn(icon, color='grey', flat)
-                    v-icon edit
+                  v-btn(icon, color='grey', flat, x-small)
+                    v-icon mdi-pencil
             v-divider
             v-divider
             v-list-item
             v-list-item
-              v-list-item-avatar
-                v-icon person
+              v-list-item-avatar(size='32')
+                v-icon mdi-account
               v-list-item-content
               v-list-item-content
                 v-list-item-title Display Name
                 v-list-item-title Display Name
-                v-list-item-sub-title {{ user.name }}
+                v-list-item-subtitle {{ user.name }}
               v-list-item-action
               v-list-item-action
-                  v-btn(icon, color='grey', flat)
-                    v-icon edit
+                  v-btn(icon, color='grey', flat, x-small)
+                    v-icon mdi-pencil
         v-card.mt-3.animated.fadeInUp.wait-p2s(v-if='!user.isSystem')
         v-card.mt-3.animated.fadeInUp.wait-p2s(v-if='!user.isSystem')
           v-toolbar(color='primary', dense, dark, flat)
           v-toolbar(color='primary', dense, dark, flat)
-            v-icon.mr-2 lock_outline
+            v-icon.mr-2 mdi-lock-outline
             span Authentication
             span Authentication
           v-list.py-0(two-line, dense)
           v-list.py-0(two-line, dense)
             v-list-item
             v-list-item
-              v-list-item-avatar
-                v-icon business
+              v-list-item-avatar(size='32')
+                v-icon mdi-domain
               v-list-item-content
               v-list-item-content
                 v-list-item-title Provider
                 v-list-item-title Provider
-                v-list-item-sub-title {{ user.providerKey }}
-              v-list-item-action
-                v-img(src='https://static.requarks.io/logo/wikijs.svg', alt='')
+                v-list-item-subtitle {{ user.providerKey }}
+              //- v-list-item-action
+              //-   v-img(src='https://static.requarks.io/logo/wikijs.svg', alt='', contain, max-height='32', position='center right')
             template(v-if='user.providerKey === `local`')
             template(v-if='user.providerKey === `local`')
               v-divider
               v-divider
               v-list-item
               v-list-item
-                v-list-item-avatar
-                  v-icon security
+                v-list-item-avatar(size='32')
+                  v-icon mdi-textbox-password
                 v-list-item-content
                 v-list-item-content
                   v-list-item-title Password
                   v-list-item-title Password
-                  v-list-item-sub-title ********
+                  v-list-item-subtitle &bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;
                 v-list-item-action
                 v-list-item-action
-                    v-btn(icon, color='grey', flat)
-                      v-icon cached
+                  v-tooltip(top)
+                    template(v-slot:activator='{ on }')
+                      v-btn(icon, color='grey', flat, x-small, v-on='on')
+                        v-icon mdi-cached
+                    span Change Password
                 v-list-item-action
                 v-list-item-action
-                    v-btn(icon, color='grey', flat)
-                      v-icon email
+                  v-tooltip(top)
+                    template(v-slot:activator='{ on }')
+                      v-btn(icon, color='grey', flat, x-small, v-on='on')
+                        v-icon mdi-email
+                    span Send Password Reset Email
               v-divider
               v-divider
               v-list-item
               v-list-item
-                v-list-item-avatar
-                  v-icon screen_lock_portrait
+                v-list-item-avatar(size='32')
+                  v-icon mdi-two-factor-authentication
                 v-list-item-content
                 v-list-item-content
                   v-list-item-title Two Factor Authentication (2FA)
                   v-list-item-title Two Factor Authentication (2FA)
-                  v-list-item-sub-title.red--text Inactive
+                  v-list-item-subtitle.red--text Inactive
                 v-list-item-action
                 v-list-item-action
-                    v-btn(icon, color='grey', flat)
-                      v-icon power_settings_new
+                  v-tooltip(top)
+                    template(v-slot:activator='{ on }')
+                      v-btn(icon, color='grey', flat, x-small, v-on='on')
+                        v-icon mdi-power
+                    span Toggle 2FA
               template(v-if='user.providerId')
               template(v-if='user.providerId')
                 v-divider
                 v-divider
                 v-list-item
                 v-list-item
-                  v-list-item-avatar
-                    v-icon person
+                  v-list-item-avatar(size='32')
+                    v-icon mdi-account
                   v-list-item-content
                   v-list-item-content
                     v-list-item-title Provider Id
                     v-list-item-title Provider Id
-                    v-list-item-sub-title {{ user.providerId }}
+                    v-list-item-subtitle {{ user.providerId }}
         v-card.mt-3.animated.fadeInUp.wait-p4s
         v-card.mt-3.animated.fadeInUp.wait-p4s
           v-toolbar(color='primary', dense, dark, flat)
           v-toolbar(color='primary', dense, dark, flat)
-            v-icon.mr-2 people
+            v-icon.mr-2 mdi-account-group
             span User Groups
             span User Groups
           v-list(dense)
           v-list(dense)
             template(v-for='(group, idx) in user.groups')
             template(v-for='(group, idx) in user.groups')
               v-list-item
               v-list-item
-                v-list-item-avatar
-                  v-icon people_outline
+                v-list-item-avatar(size='32')
+                  v-icon mdi-account-group-outline
                 v-list-item-content
                 v-list-item-content
                   v-list-item-title {{group.name}}
                   v-list-item-title {{group.name}}
-                v-list-item-action
-                  v-btn(icon, color='red', flat)
-                    v-icon clear
+                v-list-item-action(v-if='!user.isSystem')
+                  v-btn(icon, color='red', x-small)
+                    v-icon mdi-close
               v-divider(v-if='idx < user.groups.length - 1')
               v-divider(v-if='idx < user.groups.length - 1')
-          v-card-chin
+          v-alert.mx-3(v-if='user.groups.length < 1', outlined, color='grey darken-1', icon='mdi-alert')
+            .caption This user is not assigned to any group yet. You must assign at least 1 group to a user.
+          v-card-chin(v-if='!user.isSystem')
             v-spacer
             v-spacer
-            v-btn(small, color='primary', flat)
-              v-icon(left) how_to_reg
+            v-btn(color='primary', text)
+              v-icon(left) mdi-clipboard-account
               span Assign to group
               span Assign to group
       v-flex(xs7)
       v-flex(xs7)
         v-card.animated.fadeInUp.wait-p2s
         v-card.animated.fadeInUp.wait-p2s
           v-toolbar(color='primary', dense, dark, flat)
           v-toolbar(color='primary', dense, dark, flat)
-            v-icon.mr-2 directions_walk
+            v-icon.mr-2 mdi-account-badge-outline
             span Extended Metadata
             span Extended Metadata
           v-list.py-0(two-line, dense)
           v-list.py-0(two-line, dense)
             v-list-item
             v-list-item
-              v-list-item-avatar
-                v-icon public
+              v-list-item-avatar(size='32')
+                v-icon mdi-map-marker
               v-list-item-content
               v-list-item-content
                 v-list-item-title Location
                 v-list-item-title Location
-                v-list-item-sub-title {{ user.location }}
+                v-list-item-subtitle {{ user.location }}
               v-list-item-action
               v-list-item-action
-                  v-btn(icon, color='grey', flat)
-                    v-icon edit
+                  v-btn(icon, color='grey', flat, x-small)
+                    v-icon mdi-pencil
             v-divider
             v-divider
             v-list-item
             v-list-item
-              v-list-item-avatar
-                v-icon local_library
+              v-list-item-avatar(size='32')
+                v-icon mdi-account-badge-horizontal-outline
               v-list-item-content
               v-list-item-content
                 v-list-item-title Job Title
                 v-list-item-title Job Title
-                v-list-item-sub-title {{ user.jobTitle }}
+                v-list-item-subtitle {{ user.jobTitle }}
               v-list-item-action
               v-list-item-action
-                  v-btn(icon, color='grey', flat)
-                    v-icon edit
+                  v-btn(icon, color='grey', flat, x-small)
+                    v-icon mdi-pencil
             v-divider
             v-divider
             v-list-item
             v-list-item
-              v-list-item-avatar
-                v-icon map
+              v-list-item-avatar(size='32')
+                v-icon mdi-map-clock-outline
               v-list-item-content
               v-list-item-content
                 v-list-item-title Timezone
                 v-list-item-title Timezone
-                v-list-item-sub-title {{ user.timezone }}
+                v-list-item-subtitle {{ user.timezone }}
               v-list-item-action
               v-list-item-action
-                  v-btn(icon, color='grey', flat)
-                    v-icon edit
+                  v-btn(icon, color='grey', flat, x-small)
+                    v-icon mdi-pencil
         v-card.mt-3.animated.fadeInUp.wait-p4s
         v-card.mt-3.animated.fadeInUp.wait-p4s
           v-toolbar(color='primary', dense, dark, flat)
           v-toolbar(color='primary', dense, dark, flat)
-            v-icon.mr-2 insert_drive_file
+            v-icon.mr-2 mdi-file-document-box-multiple-outline
             span Content
             span Content
           v-card-text
           v-card-text
             em.caption.grey--text Coming soon
             em.caption.grey--text Coming soon

+ 23 - 51
client/components/admin/admin-users.vue

@@ -39,45 +39,36 @@
             :items='usersFiltered',
             :items='usersFiltered',
             :headers='headers',
             :headers='headers',
             :search='search',
             :search='search',
-            :pagination.sync='pagination',
-            :rows-per-page-items='[15]'
+            :page.sync='pagination'
+            :items-per-page='15'
             :loading='loading'
             :loading='loading'
-            hide-actions,
-            disable-initial-sort
-          )
-            template(slot='headers', slot-scope='props')
-              tr
-                th.text-xs-left(
-                  v-for='header in props.headers'
-                  :key='header.text'
-                  :width='header.width'
-                  :class='[`column`, header.sortable ? `sortable` : ``, pagination.descending ? `desc` : `asc`, header.value === pagination.sortBy ? `active` : ``]'
-                  @click='changeSort(header.value)'
-                )
-                  | {{ header.text }}
-                  v-icon(small, v-if='header.sortable') arrow_upward
-            template(slot='items', slot-scope='props')
+            @page-count='pageCount = $event'
+            hide-default-footer
+            )
+            template(slot='item', slot-scope='props')
               tr.is-clickable(:active='props.selected', @click='$router.push("/users/" + props.item.id)')
               tr.is-clickable(:active='props.selected', @click='$router.push("/users/" + props.item.id)')
                 //- td
                 //- td
                   v-checkbox(hide-details, :input-value='props.selected', color='blue darken-2', @click='props.selected = !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.id }}
                 td: strong {{ props.item.name }}
                 td: strong {{ props.item.name }}
                 td {{ props.item.email }}
                 td {{ props.item.email }}
                 td {{ props.item.providerKey }}
                 td {{ props.item.providerKey }}
                 td {{ props.item.createdAt | moment('from') }}
                 td {{ props.item.createdAt | moment('from') }}
                 td
                 td
                   v-tooltip(left, v-if='props.item.isSystem')
                   v-tooltip(left, v-if='props.item.isSystem')
-                    v-icon(slot='activator') lock_outline
+                    template(v-slot:activator='{ on }')
+                      v-icon(v-on='{ on }') mdi-lock-outline
                     span System User
                     span System User
             template(slot='no-data')
             template(slot='no-data')
               .pa-3
               .pa-3
-                v-alert(icon='warning', :value='true', outline) No users to display!
-          v-card-chin(v-if='this.pages > 1')
+                v-alert.text-left(icon='mdi-alert', outlined, color='grey')
+                  em.body-2 No users to display!
+          v-card-chin(v-if='pageCount > 1')
             v-spacer
             v-spacer
-            v-pagination(v-model='pagination.page', :length='pages')
+            v-pagination(v-model='pagination', :length='pageCount')
             v-spacer
             v-spacer
 
 
-    user-create(v-model='isCreateDialogShown')
+    user-create(v-model='isCreateDialogShown', @refresh='refresh(false)')
 </template>
 </template>
 
 
 <script>
 <script>
@@ -95,7 +86,8 @@ export default {
   data() {
   data() {
     return {
     return {
       selected: [],
       selected: [],
-      pagination: {},
+      pagination: 1,
+      pageCount: 0,
       users: [],
       users: [],
       headers: [
       headers: [
         { text: 'ID', value: 'id', width: 80, sortable: true },
         { text: 'ID', value: 'id', width: 80, sortable: true },
@@ -116,40 +108,20 @@ export default {
     usersFiltered () {
     usersFiltered () {
       const all = this.filterStrategy === 'all' || this.filterStrategy === ''
       const all = this.filterStrategy === 'all' || this.filterStrategy === ''
       return _.filter(this.users, u => all || u.providerKey === this.filterStrategy)
       return _.filter(this.users, u => all || u.providerKey === this.filterStrategy)
-    },
-    pages () {
-      if (this.pagination.rowsPerPage == null || this.usersFiltered.length < 1) {
-        return 0
-      }
-
-      return Math.ceil(this.usersFiltered.length / this.pagination.rowsPerPage)
     }
     }
   },
   },
   methods: {
   methods: {
     createUser() {
     createUser() {
       this.isCreateDialogShown = true
       this.isCreateDialogShown = true
     },
     },
-    async refresh() {
+    async refresh(notify = true) {
       await this.$apollo.queries.users.refetch()
       await this.$apollo.queries.users.refetch()
-      this.$store.commit('showNotification', {
-        message: 'Users list has been refreshed.',
-        style: 'success',
-        icon: 'cached'
-      })
-    },
-    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()
+      if (notify) {
+        this.$store.commit('showNotification', {
+          message: 'Users list has been refreshed.',
+          style: 'success',
+          icon: 'cached'
+        })
       }
       }
     }
     }
   },
   },

+ 5 - 5
client/components/common/user-search.vue

@@ -16,10 +16,10 @@
           )
           )
       v-card-text
       v-card-text
         v-text-field(
         v-text-field(
-          outline
+          outlined
           :label='$t(`common:user.searchPlaceholder`)'
           :label='$t(`common:user.searchPlaceholder`)'
           v-model='search'
           v-model='search'
-          prepend-inner-icon='search'
+          prepend-inner-icon='mdi-account-search-outline'
           color='primary'
           color='primary'
           ref='searchIpt'
           ref='searchIpt'
           hide-details
           hide-details
@@ -35,14 +35,14 @@
                 span.body-1.white--text {{usr.name | initials}}
                 span.body-1.white--text {{usr.name | initials}}
               v-list-item-content
               v-list-item-content
                 v-list-item-title.body-2 {{usr.name}}
                 v-list-item-title.body-2 {{usr.name}}
-                v-list-item-sub-title {{usr.email}}
+                v-list-item-subtitle {{usr.email}}
               v-list-item-action
               v-list-item-action
-                v-icon(color='primary') arrow_forward
+                v-icon(color='primary') mdi-arrow-right
             v-divider.my-0(v-if='idx < items.length - 1')
             v-divider.my-0(v-if='idx < items.length - 1')
       v-card-chin
       v-card-chin
         v-spacer
         v-spacer
         v-btn(
         v-btn(
-          flat
+          text
           @click='close'
           @click='close'
           :disabled='loading'
           :disabled='loading'
           ) {{$t('common:actions.cancel')}}
           ) {{$t('common:actions.cancel')}}

+ 38 - 41
client/components/editor/markdown/help.vue

@@ -7,7 +7,7 @@
             v-card-text
             v-card-text
               .d-flex
               .d-flex
                 v-toolbar.radius-7(color='teal lighten-5', dense, flat, height='44')
                 v-toolbar.radius-7(color='teal lighten-5', dense, flat, height='44')
-                  v-icon.mr-3(color='teal') info
+                  v-icon.mr-3(color='teal') mdi-information-variant
                   .body-2.teal--text Markdown Reference
                   .body-2.teal--text Markdown Reference
               .body-2.mt-3 Bold
               .body-2.mt-3 Bold
               v-layout(row)
               v-layout(row)
@@ -15,8 +15,8 @@
                   v-card.editor-markdown-help-source(flat)
                   v-card.editor-markdown-help-source(flat)
                     v-card-text
                     v-card-text
                       div **Lorem ipsum**
                       div **Lorem ipsum**
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       .caption: strong Lorem ipsum
                       .caption: strong Lorem ipsum
@@ -26,8 +26,8 @@
                   v-card.editor-markdown-help-source(flat)
                   v-card.editor-markdown-help-source(flat)
                     v-card-text
                     v-card-text
                       div *Lorem ipsum*
                       div *Lorem ipsum*
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       .caption: em Lorem ipsum
                       .caption: em Lorem ipsum
@@ -37,8 +37,8 @@
                   v-card.editor-markdown-help-source(flat)
                   v-card.editor-markdown-help-source(flat)
                     v-card-text
                     v-card-text
                       div ~~Lorem ipsum~~
                       div ~~Lorem ipsum~~
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       .caption(style='text-decoration: line-through;') Lorem ipsum
                       .caption(style='text-decoration: line-through;') Lorem ipsum
@@ -53,8 +53,8 @@
                       div #### Header 4
                       div #### Header 4
                       div ##### Header 5
                       div ##### Header 5
                       div ###### Header 6
                       div ###### Header 6
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       div(style='font-weight: 700; font-size: 24px;') Header 1
                       div(style='font-weight: 700; font-size: 24px;') Header 1
@@ -72,8 +72,8 @@
                       div - Unordered List Item 1
                       div - Unordered List Item 1
                       div - Unordered List Item 2
                       div - Unordered List Item 2
                       div - Unordered List Item 3
                       div - Unordered List Item 3
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       ul
                       ul
@@ -89,8 +89,8 @@
                       div 1. Ordered List Item 1
                       div 1. Ordered List Item 1
                       div 1. Ordered List Item 2
                       div 1. Ordered List Item 2
                       div 1. Ordered List Item 3
                       div 1. Ordered List Item 3
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       ol
                       ol
@@ -103,8 +103,8 @@
                   v-card.editor-markdown-help-source(flat)
                   v-card.editor-markdown-help-source(flat)
                     v-card-text
                     v-card-text
                       div ![Caption Text](/path/to/image.jpg)
                       div ![Caption Text](/path/to/image.jpg)
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       img(src='https://via.placeholder.com/150x50.png')
                       img(src='https://via.placeholder.com/150x50.png')
@@ -113,7 +113,7 @@
             v-card-text
             v-card-text
               .d-flex
               .d-flex
                 v-toolbar.radius-7(color='teal lighten-5', dense, flat, height='44')
                 v-toolbar.radius-7(color='teal lighten-5', dense, flat, height='44')
-                  v-icon.mr-3(color='teal') info
+                  v-icon.mr-3(color='teal') mdi-information-variant
                   .body-2.teal--text Markdown Reference (continued)
                   .body-2.teal--text Markdown Reference (continued)
               .body-2.mt-3 Links
               .body-2.mt-3 Links
               v-layout(row)
               v-layout(row)
@@ -121,8 +121,8 @@
                   v-card.editor-markdown-help-source(flat)
                   v-card.editor-markdown-help-source(flat)
                     v-card-text
                     v-card-text
                       div [Link Text](https://wiki.js.org)
                       div [Link Text](https://wiki.js.org)
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       .caption: a(href='https://wiki.js.org', target='_blank') Link Text
                       .caption: a(href='https://wiki.js.org', target='_blank') Link Text
@@ -132,8 +132,8 @@
                   v-card.editor-markdown-help-source(flat)
                   v-card.editor-markdown-help-source(flat)
                     v-card-text
                     v-card-text
                       div Lorem ^ipsum^
                       div Lorem ^ipsum^
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       .caption Lorem #[sup ipsum]
                       .caption Lorem #[sup ipsum]
@@ -143,8 +143,8 @@
                   v-card.editor-markdown-help-source(flat)
                   v-card.editor-markdown-help-source(flat)
                     v-card-text
                     v-card-text
                       div Lorem ~ipsum~
                       div Lorem ~ipsum~
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       .caption: em Lorem #[sub ipsum]
                       .caption: em Lorem #[sub ipsum]
@@ -156,8 +156,8 @@
                       div Lorem ipsum
                       div Lorem ipsum
                       div ---
                       div ---
                       div Dolor sit amet
                       div Dolor sit amet
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       .caption Lorem ipsum
                       .caption Lorem ipsum
@@ -169,8 +169,8 @@
                   v-card.editor-markdown-help-source(flat)
                   v-card.editor-markdown-help-source(flat)
                     v-card-text
                     v-card-text
                       div Lorem `ipsum dolor sit` amet
                       div Lorem `ipsum dolor sit` amet
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       .caption Lorem #[code ipsum dolor sit] amet
                       .caption Lorem #[code ipsum dolor sit] amet
@@ -185,8 +185,8 @@
                       div.pl-3 echo 'Lorem ipsum'
                       div.pl-3 echo 'Lorem ipsum'
                       div }
                       div }
                       div ```
                       div ```
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text.contents
                     v-card-text.contents
                       pre.prismjs.line-numbers.language-js
                       pre.prismjs.line-numbers.language-js
@@ -211,8 +211,8 @@
                       div &gt; Lorem ipsum
                       div &gt; Lorem ipsum
                       div &gt; dolor sit amet
                       div &gt; dolor sit amet
                       div &gt; consectetur adipiscing elit
                       div &gt; consectetur adipiscing elit
-                v-icon chevron_right
-                v-flex(xs6)
+                v-icon mdi-chevron-right
+                v-flex
                   v-card.editor-markdown-help-result(flat)
                   v-card.editor-markdown-help-result(flat)
                     v-card-text
                     v-card-text
                       blockquote(style='border: 1px solid #263238; border-radius: .5rem; padding: 1rem 24px;') Lorem ipsum#[br]dolor sit amet#[br]consectetur adipiscing elit
                       blockquote(style='border: 1px solid #263238; border-radius: .5rem; padding: 1rem 24px;') Lorem ipsum#[br]dolor sit amet#[br]consectetur adipiscing elit
@@ -221,7 +221,7 @@
           v-card.radius-7.animated.fadeInUp.wait-p2s(light)
           v-card.radius-7.animated.fadeInUp.wait-p2s(light)
             v-card-text
             v-card-text
               v-toolbar.radius-7(color='teal lighten-5', dense, flat)
               v-toolbar.radius-7(color='teal lighten-5', dense, flat)
-                v-icon.mr-3(color='teal') keyboard
+                v-icon.mr-3(color='teal') mdi-keyboard
                 .body-2.teal--text Keyboard Shortcuts
                 .body-2.teal--text Keyboard Shortcuts
               v-list.editor-markdown-help-kbd(two-line, dense)
               v-list.editor-markdown-help-kbd(two-line, dense)
                 v-list-item
                 v-list-item
@@ -255,13 +255,13 @@
                 v-list-item
                 v-list-item
                   v-list-item-content
                   v-list-item-content
                     v-list-item-title.body-2 Distraction Free Mode
                     v-list-item-title.body-2 Distraction Free Mode
-                    v-list-item-sub-title Press <kbd>Esc</kbd> to exit.
+                    v-list-item-subtitle Press <kbd>Esc</kbd> to exit.
                   v-list-item-action #[kbd F11]
                   v-list-item-action #[kbd F11]
 
 
           v-card.radius-7.animated.fadeInUp.wait-p3s.mt-3(light)
           v-card.radius-7.animated.fadeInUp.wait-p3s.mt-3(light)
             v-card-text
             v-card-text
               v-toolbar.radius-7(color='teal lighten-5', dense, flat)
               v-toolbar.radius-7(color='teal lighten-5', dense, flat)
-                v-icon.mr-3(color='teal') mouse
+                v-icon.mr-3(color='teal') mdi-mouse
                 .body-2.teal--text Multi-Selection
                 .body-2.teal--text Multi-Selection
               v-list.editor-markdown-help-kbd(two-line, dense)
               v-list.editor-markdown-help-kbd(two-line, dense)
                 v-list-item
                 v-list-item
@@ -303,6 +303,10 @@ export default {
     font-family: 'Roboto Mono', monospace;
     font-family: 'Roboto Mono', monospace;
     font-size: 14px;
     font-size: 14px;
     color: #FFF !important;
     color: #FFF !important;
+
+    .v-card__text {
+      color: #FFF !important;
+    }
   }
   }
 
 
   &-result {
   &-result {
@@ -327,7 +331,7 @@ export default {
   }
   }
 
 
   &-kbd {
   &-kbd {
-    .v-list__tile__action {
+    .v-list-item__action {
       flex-direction: row;
       flex-direction: row;
       align-items: center;
       align-items: center;
 
 
@@ -345,12 +349,5 @@ export default {
       }
       }
     }
     }
   }
   }
-
-  &-ref {
-    .v-list__tile__action {
-      flex-direction: row;
-      align-items: center;
-    }
-  }
 }
 }
 </style>
 </style>

+ 1 - 1
client/components/login.vue

@@ -109,7 +109,7 @@
                   v-spacer
                   v-spacer
                 template(v-if='screen === "login" && isSocialShown')
                 template(v-if='screen === "login" && isSocialShown')
                   v-divider
                   v-divider
-                  v-card-text.grey.lighten-4.text-xs-center
+                  v-card-text.grey.lighten-4.text-center
                     .pb-2.body-2.text-xs-center.grey--text.text--darken-2 {{ $t('auth:orLoginUsingStrategy') }}
                     .pb-2.body-2.text-xs-center.grey--text.text--darken-2 {{ $t('auth:orLoginUsingStrategy') }}
                     v-tooltip(top, v-for='strategy in strategies', :key='strategy.key')
                     v-tooltip(top, v-for='strategy in strategies', :key='strategy.key')
                       .social-login-btn.mr-2(
                       .social-login-btn.mr-2(

+ 1 - 1
client/scss/components/v-data-table.scss

@@ -1,4 +1,4 @@
-.v-datatable {
+.v-data-table {
   .is-clickable {
   .is-clickable {
     cursor: pointer;
     cursor: pointer;
   }
   }

+ 11 - 2
server/graph/resolvers/user.js

@@ -1,3 +1,4 @@
+const graphHelper = require('../../helpers/graph')
 
 
 /* global WIKI */
 /* global WIKI */
 
 
@@ -28,8 +29,16 @@ module.exports = {
     }
     }
   },
   },
   UserMutation: {
   UserMutation: {
-    create(obj, args) {
-      return WIKI.models.users.createNewUser(args)
+    async create(obj, args) {
+      try {
+        await WIKI.models.users.createNewUser(args)
+
+        return {
+          responseResult: graphHelper.generateSuccess('User created successfully')
+        }
+      } catch (err) {
+        return graphHelper.generateError(err)
+      }
     },
     },
     delete(obj, args) {
     delete(obj, args) {
       return WIKI.models.users.query().deleteById(args.id)
       return WIKI.models.users.query().deleteById(args.id)

+ 75 - 30
server/models/users.js

@@ -180,6 +180,20 @@ module.exports = class User extends Model {
     }
     }
     primaryEmail = _.toLower(primaryEmail)
     primaryEmail = _.toLower(primaryEmail)
 
 
+    // Find pending social user
+    if (!user) {
+      user = await WIKI.models.users.query().findOne({
+        email: primaryEmail,
+        providerId: null,
+        providerKey
+      })
+      if (user) {
+        user = await user.$query().patchAndFetch({
+          providerId: _.toString(profile.id)
+        })
+      }
+    }
+
     // Parse display name
     // Parse display name
     let displayName = ''
     let displayName = ''
     if (_.isString(profile.displayName) && profile.displayName.length > 0) {
     if (_.isString(profile.displayName) && profile.displayName.length > 0) {
@@ -365,35 +379,60 @@ module.exports = class User extends Model {
     email = _.toLower(email)
     email = _.toLower(email)
 
 
     // Input validation
     // Input validation
-    const validation = validate({
-      email,
-      passwordRaw,
-      name
-    }, {
-      email: {
-        email: true,
-        length: {
-          maximum: 255
-        }
-      },
-      passwordRaw: {
-        presence: {
-          allowEmpty: false
+    let validation = null
+    if (providerKey === 'local') {
+      validation = validate({
+        email,
+        passwordRaw,
+        name
+      }, {
+        email: {
+          email: true,
+          length: {
+            maximum: 255
+          }
         },
         },
-        length: {
-          minimum: 6
+        passwordRaw: {
+          presence: {
+            allowEmpty: false
+          },
+          length: {
+            minimum: 6
+          }
+        },
+        name: {
+          presence: {
+            allowEmpty: false
+          },
+          length: {
+            minimum: 2,
+            maximum: 255
+          }
         }
         }
-      },
-      name: {
-        presence: {
-          allowEmpty: false
+      }, { format: 'flat' })
+    } else {
+      validation = validate({
+        email,
+        name
+      }, {
+        email: {
+          email: true,
+          length: {
+            maximum: 255
+          }
         },
         },
-        length: {
-          minimum: 2,
-          maximum: 255
+        name: {
+          presence: {
+            allowEmpty: false
+          },
+          length: {
+            minimum: 2,
+            maximum: 255
+          }
         }
         }
-      }
-    }, { format: 'flat' })
+      }, { format: 'flat' })
+    }
+
     if (validation && validation.length > 0) {
     if (validation && validation.length > 0) {
       throw new WIKI.Error.InputInvalid(validation[0])
       throw new WIKI.Error.InputInvalid(validation[0])
     }
     }
@@ -402,19 +441,25 @@ module.exports = class User extends Model {
     const usr = await WIKI.models.users.query().findOne({ email, providerKey })
     const usr = await WIKI.models.users.query().findOne({ email, providerKey })
     if (!usr) {
     if (!usr) {
       // Create the account
       // Create the account
-      const newUsr = await WIKI.models.users.query().insert({
-        provider: providerKey,
+      let newUsrData = {
+        providerKey,
         email,
         email,
         name,
         name,
-        password: passwordRaw,
         locale: 'en',
         locale: 'en',
         defaultEditor: 'markdown',
         defaultEditor: 'markdown',
         tfaIsActive: false,
         tfaIsActive: false,
         isSystem: false,
         isSystem: false,
         isActive: true,
         isActive: true,
         isVerified: true,
         isVerified: true,
-        mustChangePwd: (mustChangePassword === true)
-      })
+        mustChangePwd: false
+      }
+
+      if (providerKey === `local`) {
+        newUsrData.password = passwordRaw
+        newUsrData.mustChangePwd = (mustChangePassword === true)
+      }
+
+      const newUsr = await WIKI.models.users.query().insert(newUsrData)
 
 
       // Assign to group(s)
       // Assign to group(s)
       if (groups.length > 0) {
       if (groups.length > 0) {