ソースを参照

feat: make user defaults global + add accessible view docs / refresh labels in admin

NGPixel 2 年 前
コミット
9ecaebba32

+ 4 - 0
server/app/data.yml

@@ -74,6 +74,10 @@ defaults:
       experimental: false
       authDebug: false
       sqlLog: false
+    userDefaults:
+      timezone: 'America/New_York'
+      dateFormat: 'YYYY-MM-DD'
+      timeFormat: '12h'
     # System defaults
     channel: NEXT
     cors:

+ 8 - 3
server/db/migrations/3.0.0.mjs

@@ -509,6 +509,14 @@ export async function up (knex) {
       value: {
         locales: true
       }
+    },
+    {
+      key: 'userDefaults',
+      value: {
+        timezone: 'America/New_York',
+        dateFormat: 'YYYY-MM-DD',
+        timeFormat: '12h'
+      }
     }
   ])
 
@@ -536,9 +544,6 @@ export async function up (knex) {
       footerExtra: '',
       pageExtensions: ['md', 'html', 'txt'],
       defaults: {
-        timezone: 'America/New_York',
-        dateFormat: 'YYYY-MM-DD',
-        timeFormat: '12h',
         tocDepth: {
           min: 1,
           max: 2

+ 19 - 0
server/graph/resolvers/user.mjs

@@ -79,6 +79,11 @@ export default {
 
     //   return usr
     // },
+
+    async userDefaults (obj, args, context) {
+      return WIKI.config.userDefaults
+    },
+
     async lastLogins (obj, args, context, info) {
       return WIKI.db.users.query()
         .select('id', 'name', 'lastLoginAt')
@@ -352,6 +357,20 @@ export default {
         WIKI.logger.warn(err)
         return generateError(err)
       }
+    },
+    /**
+     * UPDATE USER DEFAULTS
+     */
+    async updateUserDefaults (obj, args, context) {
+      WIKI.config.userDefaults = {
+        timezone: args.timezone,
+        dateFormat: args.dateFormat,
+        timeFormat: args.timeFormat
+      }
+      await WIKI.configSvc.saveToDb(['userDefaults'])
+      return {
+        operation: generateSuccess('User defaults saved successfully')
+      }
     }
   },
   User: {

+ 0 - 6
server/graph/schemas/site.graphql

@@ -89,9 +89,6 @@ type SiteFeatures {
 }
 
 type SiteDefaults {
-  timezone: String
-  dateFormat: String
-  timeFormat: String
   tocDepth: PageTocDepth
 }
 
@@ -206,9 +203,6 @@ input SiteFeaturesInput {
 }
 
 input SiteDefaultsInput {
-  timezone: String
-  dateFormat: String
-  timeFormat: String
   tocDepth: PageTocDepthInput
 }
 

+ 14 - 0
server/graph/schemas/user.graphql

@@ -16,6 +16,8 @@ extend type Query {
     id: UUID!
   ): User
 
+  userDefaults: UserDefaults
+
   lastLogins: [UserLastLogin]
 
   userPermissions: [String]
@@ -90,6 +92,12 @@ extend type Mutation {
   clearUserAvatar(
     id: UUID!
   ): DefaultResponse
+
+  updateUserDefaults(
+    timezone: String!
+    dateFormat: String!
+    timeFormat: String!
+  ): DefaultResponse
 }
 
 # -----------------------------------------------
@@ -142,6 +150,12 @@ type UserAuth {
   config: JSON
 }
 
+type UserDefaults {
+  timezone: String
+  dateFormat: String
+  timeFormat: String
+}
+
 type UserTokenResponse {
   operation: Operation
   jwt: String

+ 4 - 3
server/models/sites.mjs

@@ -58,9 +58,10 @@ export class Site extends Model {
         footerExtra: '',
         pageExtensions: ['md', 'html', 'txt'],
         defaults: {
-          timezone: 'America/New_York',
-          dateFormat: 'YYYY-MM-DD',
-          timeFormat: '12h'
+          tocDepth: {
+            min: 1,
+            max: 2
+          }
         },
         features: {
           ratings: false,

+ 3 - 3
server/models/users.mjs

@@ -588,10 +588,10 @@ export class User extends Model {
       },
       prefs: {
         cvd: 'none',
-        timezone: 'America/New_York',
+        timezone: WIKI.config.userDefaults.timezone || 'America/New_York',
         appearance: 'site',
-        dateFormat: 'YYYY-MM-DD',
-        timeFormat: '12h'
+        dateFormat: WIKI.config.userDefaults.dateFormat || 'YYYY-MM-DD',
+        timeFormat: WIKI.config.userDefaults.timeFormat || '12h'
       }
     })
 

ファイルの差分が大きいため隠しています
+ 0 - 0
ux/public/_assets/icons/fluent-choose.svg


+ 211 - 0
ux/src/components/UserDefaultsMenu.vue

@@ -0,0 +1,211 @@
+<template lang="pug">
+q-menu.translucent-menu(
+  anchor='bottom right'
+  self='top right'
+  :offset='[0, 10]'
+  ref='menuRef'
+  )
+  q-card(style='width: 850px;')
+    q-card-section.card-header
+      q-icon(name='img:/_assets/icons/fluent-choose.svg', left, size='sm')
+      span {{t(`admin.users.defaults`)}}
+    q-list(padding)
+      q-item
+        blueprint-icon(icon='timezone')
+        q-item-section
+          q-item-label {{t(`admin.general.defaultTimezone`)}}
+          q-item-label(caption) {{t(`admin.general.defaultTimezoneHint`)}}
+        q-item-section
+          q-select(
+            outlined
+            v-model='state.timezone'
+            :options='timezones'
+            option-value='value'
+            option-label='text'
+            emit-value
+            map-options
+            dense
+            options-dense
+            :virtual-scroll-slice-size='1000'
+            :aria-label='t(`admin.general.defaultTimezone`)'
+            )
+      q-separator.q-my-sm(inset)
+      q-item
+        blueprint-icon(icon='calendar')
+        q-item-section
+          q-item-label {{t(`admin.general.defaultDateFormat`)}}
+          q-item-label(caption) {{t(`admin.general.defaultDateFormatHint`)}}
+        q-item-section
+          q-select(
+            outlined
+            v-model='state.dateFormat'
+            emit-value
+            map-options
+            dense
+            :aria-label='t(`admin.general.defaultDateFormat`)'
+            :options='dateFormats'
+            )
+      q-separator.q-my-sm(inset)
+      q-item
+        blueprint-icon(icon='clock')
+        q-item-section
+          q-item-label {{t(`admin.general.defaultTimeFormat`)}}
+          q-item-label(caption) {{t(`admin.general.defaultTimeFormatHint`)}}
+        q-item-section.col-auto
+          q-btn-toggle(
+            v-model='state.timeFormat'
+            push
+            glossy
+            no-caps
+            toggle-color='primary'
+            :options='timeFormats'
+          )
+    q-card-actions.card-actions
+      q-space
+      q-btn.acrylic-btn(
+        flat
+        :label='t(`common.actions.cancel`)'
+        color='grey'
+        padding='xs md'
+        v-close-popup
+        )
+      q-btn(
+        unelevated
+        :label='t(`common.actions.save`)'
+        color='primary'
+        padding='xs md'
+        @click='save'
+        )
+    q-inner-loading(:showing='state.loading > 0')
+</template>
+
+<script setup>
+import { useI18n } from 'vue-i18n'
+import { useQuasar } from 'quasar'
+import { onMounted, reactive, ref } from 'vue'
+import gql from 'graphql-tag'
+import { cloneDeep } from 'lodash-es'
+
+import { usePageStore } from 'src/stores/page'
+import { useSiteStore } from 'src/stores/site'
+
+// QUASAR
+
+const $q = useQuasar()
+
+// STORES
+
+const pageStore = usePageStore()
+const siteStore = useSiteStore()
+
+// I18N
+
+const { t } = useI18n()
+
+// DATA
+
+const state = reactive({
+  loading: 0,
+  timezone: '',
+  dateFormat: '',
+  timeFormat: ''
+})
+
+const menuRef = ref(null)
+
+const dateFormats = [
+  { value: '', label: t('profile.localeDefault') },
+  { value: 'DD/MM/YYYY', label: 'DD/MM/YYYY' },
+  { value: 'DD.MM.YYYY', label: 'DD.MM.YYYY' },
+  { value: 'MM/DD/YYYY', label: 'MM/DD/YYYY' },
+  { value: 'YYYY-MM-DD', label: 'YYYY-MM-DD' },
+  { value: 'YYYY/MM/DD', label: 'YYYY/MM/DD' }
+]
+const timeFormats = [
+  { value: '12h', label: t('admin.general.defaultTimeFormat12h') },
+  { value: '24h', label: t('admin.general.defaultTimeFormat24h') }
+]
+const timezones = Intl.supportedValuesOf('timeZone')
+
+// METHODS
+
+async function save () {
+  state.loading++
+  try {
+    const resp = await APOLLO_CLIENT.mutate({
+      mutation: gql`
+        mutation saveSite (
+          $timezone: String!
+          $dateFormat: String!
+          $timeFormat: String!
+        ) {
+          updateUserDefaults (
+            timezone: $timezone
+            dateFormat: $dateFormat
+            timeFormat: $timeFormat
+          ) {
+            operation {
+              succeeded
+              slug
+              message
+            }
+          }
+        }
+      `,
+      variables: {
+        timezone: state.timezone,
+        dateFormat: state.dateFormat,
+        timeFormat: state.timeFormat
+      }
+    })
+    if (resp?.data?.updateUserDefaults?.operation?.succeeded) {
+      $q.notify({
+        type: 'positive',
+        message: t('admin.users.defaultsSaveSuccess')
+      })
+      menuRef.value.hide()
+    } else {
+      throw new Error(resp?.data?.updateUserDefaults?.operation?.message)
+    }
+  } catch (err) {
+    $q.notify({
+      type: 'negative',
+      message: 'Failed to save user defaults.',
+      caption: err.message
+    })
+  }
+  state.loading--
+}
+
+// MOUNTED
+
+onMounted(async () => {
+  state.loading++
+  try {
+    const resp = await APOLLO_CLIENT.query({
+      query: gql`
+        query getUserDefaults {
+          userDefaults {
+            timezone
+            dateFormat
+            timeFormat
+          }
+        }
+      `,
+      fetchPolicy: 'network-only'
+    })
+    const respData = cloneDeep(resp?.data?.userDefaults)
+    state.timezone = respData.timezone
+    state.dateFormat = respData.dateFormat
+    state.timeFormat = respData.timeFormat
+  } catch (err) {
+    $q.notify({
+      type: 'negative',
+      message: 'Failed to load user defaults',
+      caption: err.message
+    })
+  }
+  state.loading--
+})
+
+</script>

+ 3 - 0
ux/src/i18n/locales/en.json

@@ -882,6 +882,8 @@
   "admin.users.darkModeHint": "Display the user interface using dark mode.",
   "admin.users.dateFormat": "Date Format",
   "admin.users.dateFormatHint": "How dates should be formatted when displayed to the user.",
+  "admin.users.defaults": "Manage User Defaults",
+  "admin.users.defaultsSaveSuccess": "User defaults saved successfully.",
   "admin.users.delete": "Delete User",
   "admin.users.deleteConfirmForeignNotice": "Note that you cannot delete a user that already created content. You must instead either deactivate the user or delete all content that was created by that user.",
   "admin.users.deleteConfirmReplaceWarn": "Any content (pages, uploads, comments, etc.) that was created by this user will be reassigned to the user selected below. It is recommended to create a dummy target user (e.g. Deleted User) if you don't want the content to be reassigned to any current active user.",
@@ -1202,6 +1204,7 @@
   "common.actions.update": "Update",
   "common.actions.upload": "Upload",
   "common.actions.view": "View",
+  "common.actions.viewDocs": "View Documentation",
   "common.clipboard.failure": "Failed to copy to clipboard.",
   "common.clipboard.success": "Copied to clipboard successfully.",
   "common.clipboard.uuid": "Copy UUID to clipboard.",

+ 4 - 0
ux/src/pages/AdminApi.vue

@@ -19,17 +19,21 @@ q-page.admin-api
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/dev/api`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.acrylic-btn.q-mr-sm(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='refresh'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn.q-mr-sm(
         unelevated
         icon='las la-power-off'

+ 2 - 0
ux/src/pages/AdminAuth.vue

@@ -11,10 +11,12 @@ q-page.admin-mail
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/auth`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 4 - 0
ux/src/pages/AdminEditors.vue

@@ -11,17 +11,21 @@ q-page.admin-flags
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/editors`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='refresh'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 4 - 0
ux/src/pages/AdminExtensions.vue

@@ -11,17 +11,21 @@ q-page.admin-extensions
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/system/extensions`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
   q-separator(inset)
   .row.q-pa-md.q-col-gutter-md
     .col-12

+ 4 - 0
ux/src/pages/AdminFlags.vue

@@ -11,17 +11,21 @@ q-page.admin-flags
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/system/flags`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 4 - 71
ux/src/pages/AdminGeneral.vue

@@ -11,17 +11,21 @@ q-page.admin-general
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/sites#general`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'
@@ -336,57 +340,6 @@ q-page.admin-general
       q-card.q-pb-sm.q-mt-md(v-if='state.config.defaults')
         q-card-section
           .text-subtitle1 {{t('admin.general.defaults')}}
-        q-item
-          blueprint-icon(icon='timezone')
-          q-item-section
-            q-item-label {{t(`admin.general.defaultTimezone`)}}
-            q-item-label(caption) {{t(`admin.general.defaultTimezoneHint`)}}
-          q-item-section
-            q-select(
-              outlined
-              v-model='state.config.defaults.timezone'
-              :options='timezones'
-              option-value='value'
-              option-label='text'
-              emit-value
-              map-options
-              dense
-              options-dense
-              :virtual-scroll-slice-size='1000'
-              :aria-label='t(`admin.general.defaultTimezone`)'
-              )
-        q-separator.q-my-sm(inset)
-        q-item
-          blueprint-icon(icon='calendar')
-          q-item-section
-            q-item-label {{t(`admin.general.defaultDateFormat`)}}
-            q-item-label(caption) {{t(`admin.general.defaultDateFormatHint`)}}
-          q-item-section
-            q-select(
-              outlined
-              v-model='state.config.defaults.dateFormat'
-              emit-value
-              map-options
-              dense
-              :aria-label='t(`admin.general.defaultDateFormat`)'
-              :options='dateFormats'
-              )
-        q-separator.q-my-sm(inset)
-        q-item
-          blueprint-icon(icon='clock')
-          q-item-section
-            q-item-label {{t(`admin.general.defaultTimeFormat`)}}
-            q-item-label(caption) {{t(`admin.general.defaultTimeFormatHint`)}}
-          q-item-section.col-auto
-            q-btn-toggle(
-              v-model='state.config.defaults.timeFormat'
-              push
-              glossy
-              no-caps
-              toggle-color='primary'
-              :options='timeFormats'
-            )
-        q-separator.q-my-sm(inset)
         q-item
           blueprint-icon(icon='depth')
           q-item-section
@@ -589,26 +542,12 @@ const reasonForChangeModes = [
   { value: 'optional', label: t('admin.general.reasonForChangeOptional') },
   { value: 'required', label: t('admin.general.reasonForChangeRequired') }
 ]
-const dateFormats = [
-  { value: '', label: t('profile.localeDefault') },
-  { value: 'DD/MM/YYYY', label: 'DD/MM/YYYY' },
-  { value: 'DD.MM.YYYY', label: 'DD.MM.YYYY' },
-  { value: 'MM/DD/YYYY', label: 'MM/DD/YYYY' },
-  { value: 'YYYY-MM-DD', label: 'YYYY-MM-DD' },
-  { value: 'YYYY/MM/DD', label: 'YYYY/MM/DD' }
-]
-const timeFormats = [
-  { value: '12h', label: t('admin.general.defaultTimeFormat12h') },
-  { value: '24h', label: t('admin.general.defaultTimeFormat24h') }
-]
 const uploadConflictBehaviors = [
   { value: 'overwrite', label: t('admin.general.uploadConflictBehaviorOverwrite') },
   { value: 'reject', label: t('admin.general.uploadConflictBehaviorReject') },
   { value: 'new', label: t('admin.general.uploadConflictBehaviorNew') }
 ]
 
-const timezones = Intl.supportedValuesOf('timeZone')
-
 const rulesTitle = [
   val => /^[^<>"]+$/.test(val) || t('admin.general.siteTitleInvalidChars')
 ]
@@ -664,9 +603,6 @@ async function load () {
             search
           }
           defaults {
-            timezone
-            dateFormat
-            timeFormat
             tocDepth {
               min
               max
@@ -735,9 +671,6 @@ async function save () {
             search: state.config.features?.search ?? false
           },
           defaults: {
-            timezone: state.config.defaults?.timezone ?? 'America/New_York',
-            dateFormat: state.config.defaults?.dateFormat ?? 'YYYY-MM-DD',
-            timeFormat: state.config.defaults?.timeFormat ?? '12h',
             tocDepth: {
               min: state.config.defaults?.tocDepth?.min ?? 1,
               max: state.config.defaults?.tocDepth?.max ?? 2

+ 4 - 0
ux/src/pages/AdminGroups.vue

@@ -20,16 +20,20 @@ q-page.admin-groups
         flat
         color='grey'
         type='a'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/groups`'
         target='_blank'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         :loading='state.loading > 0'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='las la-plus'

+ 4 - 0
ux/src/pages/AdminIcons.vue

@@ -11,17 +11,21 @@ q-page.admin-icons
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/system/icons`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.acrylic-btn.q-mr-sm(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 5 - 1
ux/src/pages/AdminInstances.vue

@@ -11,17 +11,21 @@ q-page.admin-terminal
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/instances`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
-      )
+        )
+        q-tooltip {{ t(`common.actions.refresh`) }}
   q-separator(inset)
   .q-pa-md.q-gutter-md
     q-card

+ 4 - 0
ux/src/pages/AdminLocale.vue

@@ -20,17 +20,21 @@ q-page.admin-locale
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/localisation`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 4 - 0
ux/src/pages/AdminLogin.vue

@@ -11,17 +11,21 @@ q-page.admin-login
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/auth`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 4 - 0
ux/src/pages/AdminMail.vue

@@ -11,17 +11,21 @@ q-page.admin-mail
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/system/mail`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 4 - 0
ux/src/pages/AdminNavigation.vue

@@ -11,17 +11,21 @@ q-page.admin-navigation
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/navigation`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 1 - 0
ux/src/pages/AdminRendering.vue

@@ -22,6 +22,7 @@ q-page.admin-mail
         :loading='state.loading > 0'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 5 - 1
ux/src/pages/AdminScheduler.vue

@@ -29,17 +29,21 @@ q-page.admin-terminal
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/scheduler`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
-      )
+        )
+        q-tooltip {{ t(`common.actions.refresh`) }}
   q-separator(inset)
   .q-pa-md.q-gutter-md
     template(v-if='state.displayMode === `scheduled`')

+ 4 - 0
ux/src/pages/AdminSecurity.vue

@@ -11,17 +11,21 @@ q-page.admin-mail
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/system/security`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 4 - 0
ux/src/pages/AdminSites.vue

@@ -12,15 +12,19 @@ q-page.admin-locale
         flat
         color='grey'
         type='a'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/sites`'
         target='_blank'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
+        :aria-label='t(`common.actions.refresh`)'
         @click='refresh'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='las la-plus'

+ 2 - 0
ux/src/pages/AdminStorage.vue

@@ -30,10 +30,12 @@ q-page.admin-storage
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/storage`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 4 - 0
ux/src/pages/AdminSystem.vue

@@ -11,17 +11,21 @@ q-page.admin-system
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/system/`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn.acrylic-btn(
         ref='copySysInfoBtn'
         flat

+ 2 - 0
ux/src/pages/AdminTerminal.vue

@@ -37,10 +37,12 @@ q-page.admin-terminal
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/terminal`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
   q-separator(inset)
   .q-pa-md.q-gutter-md
     q-card

+ 4 - 0
ux/src/pages/AdminTheme.vue

@@ -12,16 +12,20 @@ q-page.admin-theme
         flat
         color='grey'
         type='a'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/theme`'
         target='_blank'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='mdi-check'

+ 14 - 0
ux/src/pages/AdminUsers.vue

@@ -20,16 +20,29 @@ q-page.admin-groups
         flat
         color='grey'
         type='a'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/groups`'
         target='_blank'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.q-mr-sm.acrylic-btn(
         icon='las la-redo-alt'
         flat
         color='secondary'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         :loading='state.loading > 0'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
+      q-btn.q-mr-sm(
+        icon='las la-user-cog'
+        unelevated
+        color='secondary'
+        :aria-label='t(`admin.users.defaults`)'
+        @click=''
+        )
+        q-tooltip {{ t(`admin.users.defaults`) }}
+        user-defaults-menu
       q-btn(
         unelevated
         icon='las la-plus'
@@ -117,6 +130,7 @@ import { useAdminStore } from 'src/stores/admin'
 import { useSiteStore } from 'src/stores/site'
 
 import UserCreateDialog from '../components/UserCreateDialog.vue'
+import UserDefaultsMenu from 'src/components/UserDefaultsMenu.vue'
 
 // QUASAR
 

+ 2 - 0
ux/src/pages/AdminUtilities.vue

@@ -11,10 +11,12 @@ q-page.admin-utilities
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/admin/utilities`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
   q-separator(inset)
   .q-pa-md.q-gutter-md
     q-card

+ 4 - 0
ux/src/pages/AdminWebhooks.vue

@@ -11,17 +11,21 @@ q-page.admin-webhooks
         icon='las la-question-circle'
         flat
         color='grey'
+        :aria-label='t(`common.actions.viewDocs`)'
         :href='siteStore.docsBase + `/system/webhooks`'
         target='_blank'
         type='a'
         )
+        q-tooltip {{ t(`common.actions.viewDocs`) }}
       q-btn.acrylic-btn.q-mr-sm(
         icon='las la-redo-alt'
         flat
         color='secondary'
         :loading='state.loading > 0'
+        :aria-label='t(`common.actions.refresh`)'
         @click='load'
         )
+        q-tooltip {{ t(`common.actions.refresh`) }}
       q-btn(
         unelevated
         icon='las la-plus'

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません