123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829 |
- <template lang="pug">
- 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 {{state.user.name}}
- q-space
- q-btn-group(push)
- q-btn(
- push
- color='grey-6'
- text-color='white'
- :aria-label='t(`common.actions.refresh`)'
- icon='las la-redo-alt'
- @click='fetchUser'
- :loading='state.loading > 0'
- )
- 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`)'
- icon='las la-times'
- @click='close'
- )
- q-btn(
- push
- color='positive'
- text-color='white'
- :label='t(`common.actions.save`)'
- :aria-label='t(`common.actions.save`)'
- icon='las la-check'
- @click='save()'
- :disabled='state.loading > 0'
- )
- q-drawer.bg-dark-6(:model-value='true', :width='250', dark)
- q-list(padding, v-if='state.loading < 1')
- q-item(
- v-for='sc of sections'
- :key='`section-` + sc.key'
- clickable
- :to='{ params: { section: sc.key } }'
- active-class='bg-primary text-white'
- :disabled='sc.disabled'
- )
- q-item-section(side)
- q-icon(:name='sc.icon', color='white')
- q-item-section {{sc.text}}
- q-page-container
- 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`')
- .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')}}
- 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-section
- q-input(
- outlined
- v-model='state.user.name'
- dense
- :rules=`[
- val => invalidCharsRegex.test(val) || t('admin.users.nameInvalidChars')
- ]`
- hide-bottom-space
- :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-section
- q-input(
- outlined
- v-model='state.user.email'
- dense
- :aria-label='t(`admin.users.email`)'
- )
- 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-section
- q-input(
- outlined
- v-model='state.user.meta.location'
- dense
- :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-section
- q-input(
- outlined
- v-model='state.user.meta.jobTitle'
- dense
- :aria-label='t(`admin.users.jobTitle`)'
- )
- q-card.shadow-1.q-pb-sm.q-mt-md(v-if='state.user.meta')
- q-card-section
- .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-section
- q-select(
- outlined
- 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`)'
- )
- 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-section
- q-select(
- outlined
- v-model='state.user.prefs.dateFormat'
- emit-value
- map-options
- dense
- :aria-label='t(`admin.users.dateFormat`)'
- :options=`[
- { 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' },
- { label: 'YYYY-MM-DD', value: 'YYYY-MM-DD' },
- { label: 'YYYY/MM/DD', value: 'YYYY/MM/DD' }
- ]`
- )
- q-separator.q-my-sm(inset)
- 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-section.col-auto
- q-btn-toggle(
- 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' }
- ]`
- )
- 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-section(avatar)
- q-toggle(
- v-model='state.user.prefs.darkMode'
- color='primary'
- checked-icon='las la-check'
- unchecked-icon='las la-times'
- :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')}}
- q-item
- blueprint-icon(icon='person', :hue-rotate='-45')
- q-item-section
- 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(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(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(state.user.lastLoginAt)}}
- q-card.shadow-1.q-pb-sm.q-mt-md(v-if='state.user.meta')
- q-card-section
- .text-subtitle1 {{t('admin.users.notes')}}
- q-input.q-mt-sm(
- outlined
- v-model='state.user.meta.notes'
- type='textarea'
- :aria-label='t(`admin.users.notes`)'
- input-style='min-height: 243px'
- :hint='t(`admin.users.noteHint`)'
- )
- q-page(v-else-if='route.params.section === `activity`')
- span ---
- 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')}}
- 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-section(side)
- q-btn.acrylic-btn(
- flat
- icon='las la-arrow-circle-right'
- color='primary'
- @click='changePassword'
- :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-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`)'
- )
- 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-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`)'
- )
- q-card.shadow-1.q-pb-sm.q-mt-md
- q-card-section
- .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-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`)'
- )
- 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-section(side)
- q-btn.acrylic-btn(
- flat
- icon='las la-arrow-circle-right'
- color='primary'
- @click='invalidateTFA'
- :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')}}
- 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')}}
- template(
- v-for='(prv, idx) in linkedAuthProviders'
- :key='prv._id'
- )
- q-separator.q-my-sm(inset, v-if='idx > 0')
- q-item
- blueprint-icon(icon='google', :hue-rotate='-45')
- q-item-section
- q-item-label {{prv._moduleName}}
- q-item-label(caption) {{prv.key}}
- 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')}}
- template(
- v-for='(grp, idx) of state.user.groups'
- :key='grp.id'
- )
- q-separator.q-my-sm(inset, v-if='idx > 0')
- q-item
- blueprint-icon(icon='team', :hue-rotate='-45')
- q-item-section
- q-item-label {{grp.name}}
- q-item-section(side)
- q-btn.acrylic-btn(
- flat
- icon='las la-times'
- color='accent'
- @click='unassignGroup(grp.id)'
- :aria-label='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='state.groups'
- v-model='state.groupToAdd'
- map-options
- emit-value
- option-value='id'
- option-label='name'
- options-dense
- dense
- hide-bottom-space
- :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`)'
- color='primary'
- @click='assignGroup'
- )
- 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')}}
- q-space
- q-badge(
- v-if='state.metadataInvalidJSON'
- color='negative'
- )
- q-icon.q-mr-xs(name='las la-exclamation-triangle', size='20px')
- span {{t('admin.users.invalidJSON')}}
- q-badge.q-py-xs(
- v-else
- label='JSON'
- color='positive'
- )
- q-item
- q-item-section
- q-no-ssr(:placeholder='t(`common.loading`)')
- util-code-editor.admin-theme-cm(
- v-model='metadata'
- language='json'
- :min-height='500'
- )
- 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')}}
- 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-section(side)
- q-btn.acrylic-btn(
- flat
- icon='las la-arrow-circle-right'
- color='primary'
- @click='sendWelcomeEmail'
- :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 {{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`)'
- )
- q-separator.q-my-sm(inset)
- q-item
- blueprint-icon(icon='unfriend', :hue-rotate='45')
- q-item-section
- 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`)'
- )
- 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-section(side)
- q-btn.acrylic-btn(
- flat
- icon='las la-arrow-circle-right'
- color='negative'
- @click='deleteUser'
- :label='t(`common.actions.proceed`)'
- )
- </template>
- <script setup>
- import gql from 'graphql-tag'
- import cloneDeep from 'lodash/cloneDeep'
- import some from 'lodash/some'
- import find from 'lodash/find'
- import findKey from 'lodash/findKey'
- import _get from 'lodash/get'
- import map from 'lodash/map'
- import { DateTime } from 'luxon'
- import { useI18n } from 'vue-i18n'
- import { useQuasar } from 'quasar'
- import { computed, onMounted, reactive, watch } from 'vue'
- import { useRouter, useRoute } from 'vue-router'
- import { useAdminStore } from 'src/stores/admin'
- import { useDataStore } from 'src/stores/data'
- import UserChangePwdDialog from './UserChangePwdDialog.vue'
- import UtilCodeEditor from './UtilCodeEditor.vue'
- // QUASAR
- const $q = useQuasar()
- // STORES
- const adminStore = useAdminStore()
- const dataStore = useDataStore()
- // ROUTER
- const router = useRouter()
- const route = useRoute()
- // I18N
- const { t } = useI18n()
- // DATA
- const state = reactive({
- invalidCharsRegex: /^[^<>"]+$/,
- user: {
- meta: {},
- prefs: {},
- groups: []
- },
- groups: [],
- groupToAdd: null,
- loading: 0,
- metadataInvalidJSON: false
- })
- const sections = [
- { key: 'overview', text: t('admin.users.overview'), icon: 'las la-user' },
- { key: 'activity', text: t('admin.users.activity'), icon: 'las la-chart-area' },
- { key: 'auth', text: t('admin.users.auth'), icon: 'las la-key' },
- { key: 'groups', text: t('admin.users.groups'), icon: 'las la-users' },
- { key: 'metadata', text: t('admin.users.metadata'), icon: 'las la-clipboard-list' },
- { key: 'operations', text: t('admin.users.operations'), icon: 'las la-tools' }
- ]
- // COMPUTED
- const metadata = computed({
- get () { return JSON.stringify(state.user.meta ?? {}, null, 2) },
- set (val) {
- try {
- state.user.meta = JSON.parse(val)
- state.metadataInvalidJSON = false
- } catch (err) {
- state.metadataInvalidJSON = true
- }
- }
- })
- const localAuthId = computed(() => {
- return findKey(state.user.auth, ['module', 'local'])
- })
- const localAuth = computed({
- get () {
- return localAuthId.value ? _get(state.user.auth, localAuthId.value, {}) : {}
- },
- set (val) {
- if (localAuthId.value) {
- state.user.auth[localAuthId.value] = val
- }
- }
- })
- const linkedAuthProviders = computed(() => {
- if (!state.user?.auth) { return [] }
- return map(state.user.auth, (obj, key) => {
- return {
- ...obj,
- _id: key
- }
- }).filter(prv => prv.module !== 'local')
- })
- // WATCHERS
- watch(() => route.params.section, checkRoute)
- // METHODS
- async function fetchUser () {
- state.loading++
- $q.loading.show()
- try {
- const resp = await APOLLO_CLIENT.query({
- query: gql`
- query adminFetchUser (
- $id: UUID!
- ) {
- groups {
- id
- name
- }
- userById(
- id: $id
- ) {
- id
- email
- name
- isSystem
- isVerified
- isActive
- auth
- meta
- prefs
- lastLoginAt
- createdAt
- updatedAt
- groups {
- id
- name
- }
- }
- }
- `,
- variables: {
- id: adminStore.overlayOpts.id
- },
- fetchPolicy: 'network-only'
- })
- state.groups = resp?.data?.groups?.filter(g => g.id !== '10000000-0000-4000-0000-000000000001') ?? []
- if (resp?.data?.userById) {
- state.user = cloneDeep(resp.data.userById)
- } else {
- throw new Error('An unexpected error occured while fetching user details.')
- }
- } catch (err) {
- $q.notify({
- type: 'negative',
- message: err.message
- })
- }
- $q.loading.hide()
- state.loading--
- }
- function close () {
- adminStore.$patch({ overlay: '' })
- }
- function checkRoute () {
- if (!route.params.section) {
- router.replace({ params: { section: 'overview' } })
- }
- if (route.params.section === 'metadata') {
- state.metadataInvalidJSON = false
- }
- }
- function humanizeDate (val) {
- if (!val) { return '---' }
- return DateTime.fromISO(val).toLocaleString(DateTime.DATETIME_FULL)
- }
- function assignGroup () {
- if (!state.groupToAdd) {
- $q.notify({
- type: 'negative',
- message: t('admin.users.noGroupSelected')
- })
- } else if (some(state.user.groups, gr => gr.id === state.groupToAdd)) {
- $q.notify({
- type: 'warning',
- message: t('admin.users.groupAlreadyAssigned')
- })
- } else {
- const newGroup = find(state.groups, ['id', state.groupToAdd])
- state.user.groups = [...state.user.groups, newGroup]
- }
- }
- function unassignGroup (id) {
- if (state.user.groups.length <= 1) {
- $q.notify({
- type: 'negative',
- message: t('admin.users.minimumGroupRequired')
- })
- } else {
- state.user.groups = state.user.groups.filter(gr => gr.id === id)
- }
- }
- async function save (patch, { silent, keepOpen } = { silent: false, keepOpen: false }) {
- $q.loading.show()
- if (!patch) {
- patch = {
- name: state.user.name,
- email: state.user.email,
- isVerified: state.user.isVerified,
- isActive: state.user.isActive,
- meta: state.user.meta,
- prefs: state.user.prefs,
- groups: state.user.groups.map(gr => gr.id)
- }
- }
- try {
- const resp = await APOLLO_CLIENT.mutate({
- mutation: gql`
- mutation adminSaveUser (
- $id: UUID!
- $patch: UserUpdateInput!
- ) {
- updateUser (
- id: $id
- patch: $patch
- ) {
- operation {
- succeeded
- message
- }
- }
- }
- `,
- variables: {
- id: adminStore.overlayOpts.id,
- patch
- }
- })
- if (resp?.data?.updateUser?.operation?.succeeded) {
- if (!silent) {
- $q.notify({
- type: 'positive',
- message: t('admin.users.saveSuccess')
- })
- }
- if (!keepOpen) {
- close()
- }
- } else {
- throw new Error(resp?.data?.updateUser?.operation?.message || 'An unexpected error occured.')
- }
- } catch (err) {
- $q.notify({
- type: 'negative',
- message: err.message
- })
- }
- $q.loading.hide()
- }
- function changePassword () {
- $q.dialog({
- component: UserChangePwdDialog,
- componentProps: {
- userId: adminStore.overlayOpts.id
- }
- }).onOk(({ mustChangePassword }) => {
- localAuth.value = {
- ...localAuth.value,
- mustChangePwd: mustChangePassword
- }
- })
- }
- function invalidateTFA () {
- $q.dialog({
- title: t('admin.users.tfaInvalidate'),
- message: t('admin.users.tfaInvalidateConfirm'),
- cancel: true,
- persistent: true,
- ok: {
- label: t('common.actions.confirm')
- }
- }).onOk(() => {
- localAuth.value.tfaSecret = ''
- $q.notify({
- type: 'positive',
- message: t('admin.users.tfaInvalidateSuccess')
- })
- })
- }
- async function sendWelcomeEmail () {
- }
- function toggleVerified () {
- state.user.isVerified = !state.user.isVerified
- save({
- isVerified: state.user.isVerified
- }, { silent: true, keepOpen: true })
- }
- function toggleBan () {
- state.user.isActive = !state.user.isActive
- save({
- isActive: state.user.isActive
- }, { silent: true, keepOpen: true })
- }
- async function deleteUser () {
- }
- // MOUNTED
- onMounted(() => {
- checkRoute()
- fetchUser()
- })
- </script>
- <style lang="scss" scoped>
- .metadata-codemirror {
- &:deep(.cm-editor) {
- min-height: 150px;
- border-radius: 5px;
- border: 1px solid #CCC;
- }
- }
- </style>
|