From 47ed7b371c10e3a47488a93fc3980a8ac12f9fe2 Mon Sep 17 00:00:00 2001 From: Nicolas Giard Date: Sun, 29 May 2022 02:30:47 +0000 Subject: [PATCH] feat(admin): migrate users to vue 3 composable --- server/graph/resolvers/user.js | 18 +- ux/package.json | 1 + ux/src/components/GroupEditOverlay.vue | 2 +- ux/src/components/UserChangePwdDialog.vue | 282 +++---- ux/src/components/UserCreateDialog.vue | 426 ++++++----- ux/src/components/UserEditOverlay.vue | 852 ++++++++++++---------- ux/src/pages/AdminGroups.vue | 6 +- ux/src/pages/AdminUsers.vue | 304 ++++---- ux/src/router/routes.js | 2 +- ux/yarn.lock | 19 +- 10 files changed, 1032 insertions(+), 880 deletions(-) diff --git a/server/graph/resolvers/user.js b/server/graph/resolvers/user.js index f00f2d12..f6103595 100644 --- a/server/graph/resolvers/user.js +++ b/server/graph/resolvers/user.js @@ -89,7 +89,7 @@ module.exports = { await WIKI.models.users.createNewUser({ ...args, passwordRaw: args.password, isVerified: true }) return { - status: graphHelper.generateSuccess('User created successfully') + operation: graphHelper.generateSuccess('User created successfully') } } catch (err) { return graphHelper.generateError(err) @@ -106,7 +106,7 @@ module.exports = { WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'u' }) return { - status: graphHelper.generateSuccess('User deleted successfully') + operation: graphHelper.generateSuccess('User deleted successfully') } } catch (err) { if (err.message.indexOf('foreign') >= 0) { @@ -121,7 +121,7 @@ module.exports = { await WIKI.models.users.updateUser(args.id, args.patch) return { - status: graphHelper.generateSuccess('User updated successfully') + operation: graphHelper.generateSuccess('User updated successfully') } } catch (err) { return graphHelper.generateError(err) @@ -132,7 +132,7 @@ module.exports = { await WIKI.models.users.query().patch({ isVerified: true }).findById(args.id) return { - status: graphHelper.generateSuccess('User verified successfully') + operation: graphHelper.generateSuccess('User verified successfully') } } catch (err) { return graphHelper.generateError(err) @@ -143,7 +143,7 @@ module.exports = { await WIKI.models.users.query().patch({ isActive: true }).findById(args.id) return { - status: graphHelper.generateSuccess('User activated successfully') + operation: graphHelper.generateSuccess('User activated successfully') } } catch (err) { return graphHelper.generateError(err) @@ -160,7 +160,7 @@ module.exports = { WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'u' }) return { - status: graphHelper.generateSuccess('User deactivated successfully') + operation: graphHelper.generateSuccess('User deactivated successfully') } } catch (err) { return graphHelper.generateError(err) @@ -171,7 +171,7 @@ module.exports = { await WIKI.models.users.query().patch({ tfaIsActive: true, tfaSecret: null }).findById(args.id) return { - status: graphHelper.generateSuccess('User 2FA enabled successfully') + operation: graphHelper.generateSuccess('User 2FA enabled successfully') } } catch (err) { return graphHelper.generateError(err) @@ -182,7 +182,7 @@ module.exports = { await WIKI.models.users.query().patch({ tfaIsActive: false, tfaSecret: null }).findById(args.id) return { - status: graphHelper.generateSuccess('User 2FA disabled successfully') + operation: graphHelper.generateSuccess('User 2FA disabled successfully') } } catch (err) { return graphHelper.generateError(err) @@ -225,7 +225,7 @@ module.exports = { const newToken = await WIKI.models.users.refreshToken(usr.id) return { - status: graphHelper.generateSuccess('User profile updated successfully'), + operation: graphHelper.generateSuccess('User profile updated successfully'), jwt: newToken.token } } catch (err) { diff --git a/ux/package.json b/ux/package.json index cf78b6d5..ab219231 100644 --- a/ux/package.json +++ b/ux/package.json @@ -76,6 +76,7 @@ "uuid": "8.3.2", "v-network-graph": "0.5.16", "vue": "3.2.31", + "vue-codemirror": "5.0.1", "vue-i18n": "9.1.10", "vue-router": "4.0.15", "vuedraggable": "4.1.0", diff --git a/ux/src/components/GroupEditOverlay.vue b/ux/src/components/GroupEditOverlay.vue index 6ac2a3c5..c0b02125 100644 --- a/ux/src/components/GroupEditOverlay.vue +++ b/ux/src/components/GroupEditOverlay.vue @@ -501,7 +501,7 @@ import { fileOpen } from 'browser-fs-access' import { useI18n } from 'vue-i18n' import { exportFile, useQuasar } from 'quasar' -import { computed, onBeforeUnmount, onMounted, reactive, watch } from 'vue' +import { computed, onMounted, reactive, watch } from 'vue' import { useRouter, useRoute } from 'vue-router' import { useAdminStore } from 'src/stores/admin' diff --git a/ux/src/components/UserChangePwdDialog.vue b/ux/src/components/UserChangePwdDialog.vue index c727b575..3fbf71fc 100644 --- a/ux/src/components/UserChangePwdDialog.vue +++ b/ux/src/components/UserChangePwdDialog.vue @@ -1,24 +1,21 @@ - diff --git a/ux/src/components/UserCreateDialog.vue b/ux/src/components/UserCreateDialog.vue index ebd65983..a6d47616 100644 --- a/ux/src/components/UserCreateDialog.vue +++ b/ux/src/components/UserCreateDialog.vue @@ -1,24 +1,21 @@ - diff --git a/ux/src/components/UserEditOverlay.vue b/ux/src/components/UserEditOverlay.vue index 6dfd0248..9791f576 100644 --- a/ux/src/components/UserEditOverlay.vue +++ b/ux/src/components/UserEditOverlay.vue @@ -3,26 +3,26 @@ q-layout(view='hHh lpR fFf', container) q-header.card-header.q-px-md.q-py-sm q-icon(name='img:/_assets/icons/fluent-account.svg', left, size='md') div - span {{$t(`admin.users.edit`)}} - .text-caption {{user.name}} + span {{t(`admin.users.edit`)}} + .text-caption {{state.user.name}} q-space q-btn-group(push) q-btn( push color='grey-6' text-color='white' - :aria-label='$t(`common.actions.refresh`)' + :aria-label='t(`common.actions.refresh`)' icon='las la-redo-alt' - @click='load' - :loading='loading > 0' + @click='fetchUser' + :loading='state.loading > 0' ) - q-tooltip(anchor='center left', self='center right') {{$t(`common.actions.refresh`)}} + q-tooltip(anchor='center left', self='center right') {{t(`common.actions.refresh`)}} q-btn( push color='white' text-color='grey-7' - :label='$t(`common.actions.close`)' - :aria-label='$t(`common.actions.close`)' + :label='t(`common.actions.close`)' + :aria-label='t(`common.actions.close`)' icon='las la-times' @click='close' ) @@ -30,14 +30,14 @@ q-layout(view='hHh lpR fFf', container) push color='positive' text-color='white' - :label='$t(`common.actions.save`)' - :aria-label='$t(`common.actions.save`)' + :label='t(`common.actions.save`)' + :aria-label='t(`common.actions.save`)' icon='las la-check' @click='save()' - :disabled='loading > 0' + :disabled='state.loading > 0' ) q-drawer.bg-dark-6(:model-value='true', :width='250', dark) - q-list(padding, v-if='loading < 1') + q-list(padding, v-if='state.loading < 1') q-item( v-for='sc of sections' :key='`section-` + sc.key' @@ -50,111 +50,111 @@ q-layout(view='hHh lpR fFf', container) q-icon(:name='sc.icon', color='white') q-item-section {{sc.text}} q-page-container - q-page(v-if='loading > 0') + q-page(v-if='state.loading > 0') .flex.q-pa-lg.items-center q-spinner-tail(color='primary', size='32px', :thickness='2') - .text-caption.text-primary.q-pl-md: strong {{$t('admin.users.loading')}} - q-page(v-else-if='$route.params.section === `overview`') + .text-caption.text-primary.q-pl-md: strong {{t('admin.users.loading')}} + q-page(v-else-if='route.params.section === `overview`') .q-pa-md .row.q-col-gutter-md .col-12.col-lg-8 q-card.shadow-1.q-pb-sm q-card-section - .text-subtitle1 {{$t('admin.users.profile')}} + .text-subtitle1 {{t('admin.users.profile')}} q-item blueprint-icon(icon='contact') q-item-section - q-item-label {{$t(`admin.users.name`)}} - q-item-label(caption) {{$t(`admin.users.nameHint`)}} + q-item-label {{t(`admin.users.name`)}} + q-item-label(caption) {{t(`admin.users.nameHint`)}} q-item-section q-input( outlined - v-model='user.name' + v-model='state.user.name' dense :rules=`[ - val => invalidCharsRegex.test(val) || $t('admin.users.nameInvalidChars') + val => invalidCharsRegex.test(val) || t('admin.users.nameInvalidChars') ]` hide-bottom-space - :aria-label='$t(`admin.users.name`)' + :aria-label='t(`admin.users.name`)' ) q-separator.q-my-sm(inset) q-item blueprint-icon(icon='envelope') q-item-section - q-item-label {{$t(`admin.users.email`)}} - q-item-label(caption) {{$t(`admin.users.emailHint`)}} + q-item-label {{t(`admin.users.email`)}} + q-item-label(caption) {{t(`admin.users.emailHint`)}} q-item-section q-input( outlined - v-model='user.email' + v-model='state.user.email' dense - :aria-label='$t(`admin.users.email`)' + :aria-label='t(`admin.users.email`)' ) - template(v-if='user.meta') + template(v-if='state.user.meta') q-separator.q-my-sm(inset) q-item blueprint-icon(icon='address') q-item-section - q-item-label {{$t(`admin.users.location`)}} - q-item-label(caption) {{$t(`admin.users.locationHint`)}} + q-item-label {{t(`admin.users.location`)}} + q-item-label(caption) {{t(`admin.users.locationHint`)}} q-item-section q-input( outlined - v-model='user.meta.location' + v-model='state.user.meta.location' dense - :aria-label='$t(`admin.users.location`)' + :aria-label='t(`admin.users.location`)' ) q-separator.q-my-sm(inset) q-item blueprint-icon(icon='new-job') q-item-section - q-item-label {{$t(`admin.users.jobTitle`)}} - q-item-label(caption) {{$t(`admin.users.jobTitleHint`)}} + q-item-label {{t(`admin.users.jobTitle`)}} + q-item-label(caption) {{t(`admin.users.jobTitleHint`)}} q-item-section q-input( outlined - v-model='user.meta.jobTitle' + v-model='state.user.meta.jobTitle' dense - :aria-label='$t(`admin.users.jobTitle`)' + :aria-label='t(`admin.users.jobTitle`)' ) - q-card.shadow-1.q-pb-sm.q-mt-md(v-if='user.meta') + q-card.shadow-1.q-pb-sm.q-mt-md(v-if='state.user.meta') q-card-section - .text-subtitle1 {{$t('admin.users.preferences')}} + .text-subtitle1 {{t('admin.users.preferences')}} q-item blueprint-icon(icon='timezone') q-item-section - q-item-label {{$t(`admin.users.timezone`)}} - q-item-label(caption) {{$t(`admin.users.timezoneHint`)}} + q-item-label {{t(`admin.users.timezone`)}} + q-item-label(caption) {{t(`admin.users.timezoneHint`)}} q-item-section q-select( outlined - v-model='user.prefs.timezone' - :options='timezones' + v-model='state.user.prefs.timezone' + :options='dataStore.timezones' option-value='value' option-label='text' emit-value map-options dense options-dense - :aria-label='$t(`admin.users.timezone`)' + :aria-label='t(`admin.users.timezone`)' ) q-separator.q-my-sm(inset) q-item blueprint-icon(icon='calendar') q-item-section - q-item-label {{$t(`admin.users.dateFormat`)}} - q-item-label(caption) {{$t(`admin.users.dateFormatHint`)}} + q-item-label {{t(`admin.users.dateFormat`)}} + q-item-label(caption) {{t(`admin.users.dateFormatHint`)}} q-item-section q-select( outlined - v-model='user.prefs.dateFormat' + v-model='state.user.prefs.dateFormat' emit-value map-options dense - :aria-label='$t(`admin.users.dateFormat`)' + :aria-label='t(`admin.users.dateFormat`)' :options=`[ - { label: $t('profile.localeDefault'), value: '' }, + { label: t('profile.localeDefault'), value: '' }, { label: 'DD/MM/YYYY', value: 'DD/MM/YYYY' }, { label: 'DD.MM.YYYY', value: 'DD.MM.YYYY' }, { label: 'MM/DD/YYYY', value: 'MM/DD/YYYY' }, @@ -166,168 +166,168 @@ q-layout(view='hHh lpR fFf', container) q-item blueprint-icon(icon='clock') q-item-section - q-item-label {{$t(`admin.users.timeFormat`)}} - q-item-label(caption) {{$t(`admin.users.timeFormatHint`)}} + q-item-label {{t(`admin.users.timeFormat`)}} + q-item-label(caption) {{t(`admin.users.timeFormatHint`)}} q-item-section.col-auto q-btn-toggle( - v-model='user.prefs.timeFormat' + v-model='state.user.prefs.timeFormat' push glossy no-caps toggle-color='primary' :options=`[ - { label: $t('profile.timeFormat12h'), value: '12h' }, - { label: $t('profile.timeFormat24h'), value: '24h' } + { label: t('profile.timeFormat12h'), value: '12h' }, + { label: t('profile.timeFormat24h'), value: '24h' } ]` ) q-separator.q-my-sm(inset) q-item(tag='label', v-ripple) blueprint-icon(icon='light-on') q-item-section - q-item-label {{$t(`admin.users.darkMode`)}} - q-item-label(caption) {{$t(`admin.users.darkModeHint`)}} + q-item-label {{t(`admin.users.darkMode`)}} + q-item-label(caption) {{t(`admin.users.darkModeHint`)}} q-item-section(avatar) q-toggle( - v-model='user.prefs.darkMode' + v-model='state.user.prefs.darkMode' color='primary' checked-icon='las la-check' unchecked-icon='las la-times' - :aria-label='$t(`admin.users.darkMode`)' + :aria-label='t(`admin.users.darkMode`)' ) .col-12.col-lg-4 q-card.shadow-1.q-pb-sm q-card-section - .text-subtitle1 {{$t('admin.users.info')}} + .text-subtitle1 {{t('admin.users.info')}} q-item blueprint-icon(icon='person', :hue-rotate='-45') q-item-section - q-item-label {{$t(`common.field.id`)}} - q-item-label: strong {{userId}} + q-item-label {{t(`common.field.id`)}} + q-item-label: strong {{state.user.id}} q-separator.q-my-sm(inset) q-item blueprint-icon(icon='calendar-plus', :hue-rotate='-45') q-item-section - q-item-label {{$t(`common.field.createdOn`)}} - q-item-label: strong {{humanizeDate(user.createdAt)}} + q-item-label {{t(`common.field.createdOn`)}} + q-item-label: strong {{humanizeDate(state.user.createdAt)}} q-separator.q-my-sm(inset) q-item blueprint-icon(icon='summertime', :hue-rotate='-45') q-item-section - q-item-label {{$t(`common.field.lastUpdated`)}} - q-item-label: strong {{humanizeDate(user.updatedAt)}} + q-item-label {{t(`common.field.lastUpdated`)}} + q-item-label: strong {{humanizeDate(state.user.updatedAt)}} q-separator.q-my-sm(inset) q-item blueprint-icon(icon='enter', :hue-rotate='-45') q-item-section - q-item-label {{$t(`admin.users.lastLoginAt`)}} - q-item-label: strong {{humanizeDate(user.lastLoginAt)}} + q-item-label {{t(`admin.users.lastLoginAt`)}} + q-item-label: strong {{humanizeDate(state.user.lastLoginAt)}} - q-card.shadow-1.q-pb-sm.q-mt-md(v-if='user.meta') + q-card.shadow-1.q-pb-sm.q-mt-md(v-if='state.user.meta') q-card-section - .text-subtitle1 {{$t('admin.users.notes')}} + .text-subtitle1 {{t('admin.users.notes')}} q-input.q-mt-sm( outlined - v-model='user.meta.notes' + v-model='state.user.meta.notes' type='textarea' - :aria-label='$t(`admin.users.notes`)' + :aria-label='t(`admin.users.notes`)' input-style='min-height: 243px' - :hint='$t(`admin.users.noteHint`)' + :hint='t(`admin.users.noteHint`)' ) - q-page(v-else-if='$route.params.section === `activity`') + q-page(v-else-if='route.params.section === `activity`') span --- - q-page(v-else-if='$route.params.section === `auth`') + q-page(v-else-if='route.params.section === `auth`') .q-pa-md .row.q-col-gutter-md .col-12.col-lg-7 q-card.shadow-1.q-pb-sm q-card-section - .text-subtitle1 {{$t('admin.users.passAuth')}} + .text-subtitle1 {{t('admin.users.passAuth')}} q-item blueprint-icon(icon='password', :hue-rotate='45') q-item-section - q-item-label {{$t(`admin.users.changePassword`)}} - q-item-label(caption) {{$t(`admin.users.changePasswordHint`)}} - q-item-label(caption): strong(:class='localAuth.password ? `text-positive` : `text-negative`') {{localAuth.password ? $t(`admin.users.pwdSet`) : $t(`admin.users.pwdNotSet`)}} + q-item-label {{t(`admin.users.changePassword`)}} + q-item-label(caption) {{t(`admin.users.changePasswordHint`)}} + q-item-label(caption): strong(:class='localAuth.password ? `text-positive` : `text-negative`') {{localAuth.password ? t(`admin.users.pwdSet`) : t(`admin.users.pwdNotSet`)}} q-item-section(side) q-btn.acrylic-btn( flat icon='las la-arrow-circle-right' color='primary' @click='changePassword' - :label='$t(`common.actions.proceed`)' + :label='t(`common.actions.proceed`)' ) q-separator.q-my-sm(inset) q-item(tag='label', v-ripple) blueprint-icon(icon='password-reset') q-item-section - q-item-label {{$t(`admin.users.mustChangePwd`)}} - q-item-label(caption) {{$t(`admin.users.mustChangePwdHint`)}} + q-item-label {{t(`admin.users.mustChangePwd`)}} + q-item-label(caption) {{t(`admin.users.mustChangePwdHint`)}} q-item-section(avatar) q-toggle( v-model='localAuth.mustChangePwd' color='primary' checked-icon='las la-check' unchecked-icon='las la-times' - :aria-label='$t(`admin.users.mustChangePwd`)' + :aria-label='t(`admin.users.mustChangePwd`)' ) q-separator.q-my-sm(inset) q-item(tag='label', v-ripple) blueprint-icon(icon='key') q-item-section - q-item-label {{$t(`admin.users.pwdAuthRestrict`)}} - q-item-label(caption) {{$t(`admin.users.pwdAuthRestrictHint`)}} + q-item-label {{t(`admin.users.pwdAuthRestrict`)}} + q-item-label(caption) {{t(`admin.users.pwdAuthRestrictHint`)}} q-item-section(avatar) q-toggle( v-model='localAuth.restrictLogin' color='primary' checked-icon='las la-check' unchecked-icon='las la-times' - :aria-label='$t(`admin.users.pwdAuthRestrict`)' + :aria-label='t(`admin.users.pwdAuthRestrict`)' ) q-card.shadow-1.q-pb-sm.q-mt-md q-card-section - .text-subtitle1 {{$t('admin.users.tfa')}} + .text-subtitle1 {{t('admin.users.tfa')}} q-item(tag='label', v-ripple) blueprint-icon(icon='key') q-item-section - q-item-label {{$t(`admin.users.tfaRequired`)}} - q-item-label(caption) {{$t(`admin.users.tfaRequiredHint`)}} + q-item-label {{t(`admin.users.tfaRequired`)}} + q-item-label(caption) {{t(`admin.users.tfaRequiredHint`)}} q-item-section(avatar) q-toggle( v-model='localAuth.tfaRequired' color='primary' checked-icon='las la-check' unchecked-icon='las la-times' - :aria-label='$t(`admin.users.tfaRequired`)' + :aria-label='t(`admin.users.tfaRequired`)' ) q-separator.q-my-sm(inset) q-item blueprint-icon(icon='password', :hue-rotate='45') q-item-section - q-item-label {{$t(`admin.users.tfaInvalidate`)}} - q-item-label(caption) {{$t(`admin.users.tfaInvalidateHint`)}} - q-item-label(caption): strong(:class='localAuth.tfaSecret ? `text-positive` : `text-negative`') {{localAuth.tfaSecret ? $t(`admin.users.tfaSet`) : $t(`admin.users.tfaNotSet`)}} + q-item-label {{t(`admin.users.tfaInvalidate`)}} + q-item-label(caption) {{t(`admin.users.tfaInvalidateHint`)}} + q-item-label(caption): strong(:class='localAuth.tfaSecret ? `text-positive` : `text-negative`') {{localAuth.tfaSecret ? t(`admin.users.tfaSet`) : t(`admin.users.tfaNotSet`)}} q-item-section(side) q-btn.acrylic-btn( flat icon='las la-arrow-circle-right' color='primary' @click='invalidateTFA' - :label='$t(`common.actions.proceed`)' + :label='t(`common.actions.proceed`)' ) .col-12.col-lg-5 q-card.shadow-1.q-pb-sm q-card-section - .text-subtitle1 {{$t('admin.users.linkedProviders')}} + .text-subtitle1 {{t('admin.users.linkedProviders')}} q-banner.q-mt-md( v-if='linkedAuthProviders.length < 1' rounded :class='$q.dark.isActive ? `bg-negative text-white` : `bg-grey-2 text-grey-7`' - ) {{$t('admin.users.noLinkedProviders')}} + ) {{t('admin.users.noLinkedProviders')}} template( v-for='(prv, idx) in linkedAuthProviders' :key='prv._id' @@ -339,15 +339,15 @@ q-layout(view='hHh lpR fFf', container) q-item-label {{prv._moduleName}} q-item-label(caption) {{prv.key}} - q-page(v-else-if='$route.params.section === `groups`') + q-page(v-else-if='route.params.section === `groups`') .q-pa-md .row.q-col-gutter-md .col-12.col-lg-8 q-card.shadow-1.q-pb-sm q-card-section - .text-subtitle1 {{$t('admin.users.groups')}} + .text-subtitle1 {{t('admin.users.groups')}} template( - v-for='(grp, idx) of user.groups' + v-for='(grp, idx) of state.user.groups' :key='grp.id' ) q-separator.q-my-sm(inset, v-if='idx > 0') @@ -361,17 +361,17 @@ q-layout(view='hHh lpR fFf', container) icon='las la-times' color='accent' @click='unassignGroup(grp.id)' - :aria-label='$t(`admin.users.unassignGroup`)' + :aria-label='t(`admin.users.unassignGroup`)' ) - q-tooltip(anchor='center left' self='center right') {{$t('admin.users.unassignGroup')}} + q-tooltip(anchor='center left' self='center right') {{t('admin.users.unassignGroup')}} q-card.shadow-1.q-py-sm.q-mt-md q-item blueprint-icon(icon='join') q-item-section q-select( outlined - :options='groups' - v-model='groupToAdd' + :options='state.groups' + v-model='state.groupToAdd' map-options emit-value option-value='id' @@ -379,33 +379,33 @@ q-layout(view='hHh lpR fFf', container) options-dense dense hide-bottom-space - :label='$t(`admin.users.groups`)' - :aria-label='$t(`admin.users.groups`)' - :loading='loading > 0' + :label='t(`admin.users.groups`)' + :aria-label='t(`admin.users.groups`)' + :loading='state.loading > 0' ) q-item-section(side) q-btn( unelevated icon='las la-plus' - :label='$t(`admin.users.assignGroup`)' + :label='t(`admin.users.assignGroup`)' color='primary' @click='assignGroup' ) - q-page(v-else-if='$route.params.section === `metadata`') + q-page(v-else-if='route.params.section === `metadata`') .q-pa-md .row.q-col-gutter-md .col-12.col-lg-8 q-card.shadow-1.q-pb-sm q-card-section.flex.items-center - .text-subtitle1 {{$t('admin.users.metadata')}} + .text-subtitle1 {{t('admin.users.metadata')}} q-space q-badge( - v-if='metadataInvalidJSON' + v-if='state.metadataInvalidJSON' color='negative' ) q-icon.q-mr-xs(name='las la-exclamation-triangle', size='20px') - span {{$t('admin.users.invalidJSON')}} + span {{t('admin.users.invalidJSON')}} q-badge.q-py-xs( v-else label='JSON' @@ -413,80 +413,79 @@ q-layout(view='hHh lpR fFf', container) ) q-item q-item-section - q-no-ssr(:placeholder='$t(`common.loading`)') - util-code-editor.admin-theme-cm( + q-no-ssr(:placeholder='t(`common.loading`)') + codemirror.metadata-codemirror( v-model='metadata' - language='json' - :min-height='500' + :extensions='[json()]' ) - q-page(v-else-if='$route.params.section === `operations`') + q-page(v-else-if='route.params.section === `operations`') .q-pa-md .row.q-col-gutter-md .col-12.col-lg-8 q-card.shadow-1.q-pb-sm q-card-section - .text-subtitle1 {{$t('admin.users.operations')}} + .text-subtitle1 {{t('admin.users.operations')}} q-item blueprint-icon(icon='email-open', :hue-rotate='45') q-item-section - q-item-label {{$t(`admin.users.sendWelcomeEmail`)}} - q-item-label(caption) {{$t(`admin.users.sendWelcomeEmailAltHint`)}} + q-item-label {{t(`admin.users.sendWelcomeEmail`)}} + q-item-label(caption) {{t(`admin.users.sendWelcomeEmailAltHint`)}} q-item-section(side) q-btn.acrylic-btn( flat icon='las la-arrow-circle-right' color='primary' @click='sendWelcomeEmail' - :label='$t(`common.actions.proceed`)' + :label='t(`common.actions.proceed`)' ) q-separator.q-my-sm(inset) q-item blueprint-icon(icon='apply', :hue-rotate='45') q-item-section - q-item-label {{user.isVerified ? $t(`admin.users.unverify`) : $t(`admin.users.verify`)}} - q-item-label(caption) {{user.isVerified ? $t(`admin.users.unverifyHint`) : $t(`admin.users.verifyHint`)}} - q-item-label(caption): strong(:class='user.isVerified ? `text-positive` : `text-negative`') {{user.isVerified ? $t(`admin.users.verified`) : $t(`admin.users.unverified`)}} + q-item-label {{state.user.isVerified ? t(`admin.users.unverify`) : t(`admin.users.verify`)}} + q-item-label(caption) {{state.user.isVerified ? t(`admin.users.unverifyHint`) : t(`admin.users.verifyHint`)}} + q-item-label(caption): strong(:class='state.user.isVerified ? `text-positive` : `text-negative`') {{state.user.isVerified ? t(`admin.users.verified`) : t(`admin.users.unverified`)}} q-item-section(side) q-btn.acrylic-btn( flat icon='las la-arrow-circle-right' color='primary' @click='toggleVerified' - :label='$t(`common.actions.proceed`)' + :label='t(`common.actions.proceed`)' ) q-separator.q-my-sm(inset) q-item blueprint-icon(icon='unfriend', :hue-rotate='45') q-item-section - q-item-label {{user.isActive ? $t(`admin.users.ban`) : $t(`admin.users.unban`)}} - q-item-label(caption) {{user.isActive ? $t(`admin.users.banHint`) : $t(`admin.users.unbanHint`)}} - q-item-label(caption): strong(:class='user.isActive ? `text-positive` : `text-negative`') {{user.isActive ? $t(`admin.users.active`) : $t(`admin.users.banned`)}} + q-item-label {{state.user.isActive ? t(`admin.users.ban`) : t(`admin.users.unban`)}} + q-item-label(caption) {{state.user.isActive ? t(`admin.users.banHint`) : t(`admin.users.unbanHint`)}} + q-item-label(caption): strong(:class='state.user.isActive ? `text-positive` : `text-negative`') {{state.user.isActive ? t(`admin.users.active`) : t(`admin.users.banned`)}} q-item-section(side) q-btn.acrylic-btn( flat icon='las la-arrow-circle-right' color='primary' @click='toggleBan' - :label='$t(`common.actions.proceed`)' + :label='t(`common.actions.proceed`)' ) q-card.shadow-1.q-py-sm.q-mt-md q-item blueprint-icon(icon='denied', :hue-rotate='140') q-item-section - q-item-label {{$t(`admin.users.delete`)}} - q-item-label(caption) {{$t(`admin.users.deleteHint`)}} + q-item-label {{t(`admin.users.delete`)}} + q-item-label(caption) {{t(`admin.users.deleteHint`)}} q-item-section(side) q-btn.acrylic-btn( flat icon='las la-arrow-circle-right' color='negative' @click='deleteUser' - :label='$t(`common.actions.proceed`)' + :label='t(`common.actions.proceed`)' ) - + + diff --git a/ux/src/pages/AdminGroups.vue b/ux/src/pages/AdminGroups.vue index 69b0c8ed..aa1c3eb3 100644 --- a/ux/src/pages/AdminGroups.vue +++ b/ux/src/pages/AdminGroups.vue @@ -168,6 +168,8 @@ const headers = [ } ] +// WATCHERS + watch(() => adminStore.overlay, (newValue, oldValue) => { if (newValue === '' && oldValue === 'GroupEditOverlay') { router.push('/_admin/groups') @@ -175,9 +177,7 @@ watch(() => adminStore.overlay, (newValue, oldValue) => { } }) -watch(() => route.params.id, () => { - checkOverlay() -}) +watch(() => route.params.id, checkOverlay) // METHODS diff --git a/ux/src/pages/AdminUsers.vue b/ux/src/pages/AdminUsers.vue index f2c7e569..8f8d83be 100644 --- a/ux/src/pages/AdminUsers.vue +++ b/ux/src/pages/AdminUsers.vue @@ -4,12 +4,12 @@ q-page.admin-groups .col-auto img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-account.svg') .col.q-pl-md - .text-h5.text-primary.animated.fadeInLeft {{ $t('admin.users.title') }} - .text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.users.subtitle') }} + .text-h5.text-primary.animated.fadeInLeft {{ t('admin.users.title') }} + .text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ t('admin.users.subtitle') }} .col-auto.flex.items-center q-input.denser.q-mr-sm( outlined - v-model='search' + v-model='state.search' dense :class='$q.dark.isActive ? `bg-dark` : `bg-white`' ) @@ -28,29 +28,29 @@ q-page.admin-groups flat color='secondary' @click='load' - :loading='loading > 0' + :loading='state.loading > 0' ) q-btn( unelevated icon='las la-plus' - :label='$t(`admin.users.create`)' + :label='t(`admin.users.create`)' color='primary' @click='createUser' - :disabled='loading > 0' + :disabled='state.loading > 0' ) q-separator(inset) .row.q-pa-md.q-col-gutter-md .col-12 q-card.shadow-1 q-table( - :rows='users' + :rows='state.users' :columns='headers' row-key='id' flat hide-header hide-bottom :rows-per-page-options='[0]' - :loading='loading > 0' + :loading='state.loading > 0' ) template(v-slot:body-cell-id='props') q-td(:props='props') @@ -92,7 +92,7 @@ q-page.admin-groups :to='`/_admin/users/` + props.row.id' icon='las la-pen' color='indigo' - :label='$t(`common.actions.edit`)' + :label='t(`common.actions.edit`)' no-caps ) q-btn.acrylic-btn( @@ -100,146 +100,178 @@ q-page.admin-groups flat icon='las la-trash' color='accent' - @click='deleteGroup(props.row)' + @click='deleteUser(props.row)' ) -