Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wiki-js
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
wiki-js
Commits
8fb29cfc
Unverified
Commit
8fb29cfc
authored
Jun 19, 2022
by
Nicolas Giard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(admin): migrate theme + api + utilities to vue 3 composition
parent
368493c3
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
321 additions
and
288 deletions
+321
-288
package.json
ux/package.json
+14
-13
UserCreateDialog.vue
ux/src/components/UserCreateDialog.vue
+0
-1
UserEditOverlay.vue
ux/src/components/UserEditOverlay.vue
+0
-1
UtilCodeEditor.vue
ux/src/components/UtilCodeEditor.vue
+0
-1
WebhookEditDialog.vue
ux/src/components/WebhookEditDialog.vue
+0
-1
AdminLayout.vue
ux/src/layouts/AdminLayout.vue
+0
-1
AdminApi.vue
ux/src/pages/AdminApi.vue
+101
-100
AdminTheme.vue
ux/src/pages/AdminTheme.vue
+157
-140
AdminUtilities.vue
ux/src/pages/AdminUtilities.vue
+45
-26
routes.js
ux/src/router/routes.js
+4
-4
yarn.lock
ux/yarn.lock
+0
-0
No files found.
ux/package.json
View file @
8fb29cfc
...
...
@@ -12,26 +12,26 @@
},
"dependencies"
:
{
"@apollo/client"
:
"3.6.8"
,
"@codemirror/autocomplete"
:
"
0.20.3
"
,
"@codemirror/autocomplete"
:
"
6.0.2
"
,
"@codemirror/basic-setup"
:
"0.20.0"
,
"@codemirror/closebrackets"
:
"0.19.2"
,
"@codemirror/commands"
:
"
0.2
0.0"
,
"@codemirror/commands"
:
"
6.
0.0"
,
"@codemirror/comment"
:
"0.19.1"
,
"@codemirror/fold"
:
"0.19.4"
,
"@codemirror/gutter"
:
"0.19.9"
,
"@codemirror/highlight"
:
"0.19.8"
,
"@codemirror/history"
:
"0.19.2"
,
"@codemirror/lang-css"
:
"
0.2
0.0"
,
"@codemirror/lang-html"
:
"
0.2
0.0"
,
"@codemirror/lang-javascript"
:
"
0.20.1
"
,
"@codemirror/lang-json"
:
"
0.2
0.0"
,
"@codemirror/lang-markdown"
:
"
0.20.1
"
,
"@codemirror/lang-css"
:
"
6.
0.0"
,
"@codemirror/lang-html"
:
"
6.
0.0"
,
"@codemirror/lang-javascript"
:
"
6.0.0
"
,
"@codemirror/lang-json"
:
"
6.
0.0"
,
"@codemirror/lang-markdown"
:
"
6.0.0
"
,
"@codemirror/matchbrackets"
:
"0.19.4"
,
"@codemirror/search"
:
"
0.20.1
"
,
"@codemirror/state"
:
"
0.2
0.1"
,
"@codemirror/search"
:
"
6.0.0
"
,
"@codemirror/state"
:
"
6.
0.1"
,
"@codemirror/tooltip"
:
"0.19.16"
,
"@codemirror/view"
:
"
0.20.7
"
,
"@lezer/common"
:
"
0.16.1
"
,
"@codemirror/view"
:
"
6.0.1
"
,
"@lezer/common"
:
"
1.0.0
"
,
"@quasar/extras"
:
"1.14.0"
,
"@tiptap/core"
:
"2.0.0-beta.176"
,
"@tiptap/extension-code-block"
:
"2.0.0-beta.37"
,
...
...
@@ -61,6 +61,7 @@
"apollo-upload-client"
:
"17.0.0"
,
"browser-fs-access"
:
"0.29.6"
,
"clipboard"
:
"2.0.11"
,
"codemirror"
:
"6.0.0"
,
"filesize"
:
"9.0.9"
,
"filesize-parser"
:
"1.5.0"
,
"graphql"
:
"16.5.0"
,
...
...
@@ -71,12 +72,12 @@
"luxon"
:
"2.4.0"
,
"pinia"
:
"2.0.14"
,
"pug"
:
"3.0.2"
,
"quasar"
:
"2.7.
2
"
,
"quasar"
:
"2.7.
3
"
,
"tippy.js"
:
"6.3.7"
,
"uuid"
:
"8.3.2"
,
"v-network-graph"
:
"0.5.19"
,
"vue"
:
"3.2.37"
,
"vue-codemirror"
:
"
5.1
.0"
,
"vue-codemirror"
:
"
6.0
.0"
,
"vue-i18n"
:
"9.1.10"
,
"vue-router"
:
"4.0.16"
,
"vuedraggable"
:
"4.1.0"
,
...
...
ux/src/components/UserCreateDialog.vue
View file @
8fb29cfc
...
...
@@ -178,7 +178,6 @@ defineEmits([
const
{
dialogRef
,
onDialogHide
,
onDialogOK
,
onDialogCancel
}
=
useDialogPluginComponent
()
const
$q
=
useQuasar
()
defineExpose
({
$q
})
// I18N
...
...
ux/src/components/UserEditOverlay.vue
View file @
8fb29cfc
...
...
@@ -510,7 +510,6 @@ import UtilCodeEditor from './UtilCodeEditor.vue'
// QUASAR
const
$q
=
useQuasar
()
defineExpose
({
$q
})
// STORES
...
...
ux/src/components/UtilCodeEditor.vue
View file @
8fb29cfc
...
...
@@ -12,7 +12,6 @@ import { EditorState } from '@codemirror/state'
import
{
defaultKeymap
,
history
,
historyKeymap
,
indentWithTab
}
from
'@codemirror/commands'
import
{
defaultHighlightStyle
,
syntaxHighlighting
}
from
'@codemirror/language'
import
{
ref
,
shallowRef
,
onBeforeMount
,
onMounted
,
watch
}
from
'vue'
import
{
json
}
from
'@codemirror/lang-json'
// PROPS
...
...
ux/src/components/WebhookEditDialog.vue
View file @
8fb29cfc
...
...
@@ -218,7 +218,6 @@ defineEmits([
const
{
dialogRef
,
onDialogHide
,
onDialogOK
,
onDialogCancel
}
=
useDialogPluginComponent
()
const
$q
=
useQuasar
()
defineExpose
({
$q
}
)
// I18N
...
...
ux/src/layouts/AdminLayout.vue
View file @
8fb29cfc
...
...
@@ -203,7 +203,6 @@ const overlays = {
// QUASAR
const
$q
=
useQuasar
()
defineExpose
({
$q
})
// STORES
...
...
ux/src/pages/AdminApi.vue
View file @
8fb29cfc
...
...
@@ -4,16 +4,16 @@ q-page.admin-api
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-rest-api.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft
{{
$
t
(
'admin.api.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
$
t
(
'admin.api.subtitle'
)
}}
.text-h5.text-primary.animated.fadeInLeft
{{
t
(
'admin.api.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
t
(
'admin.api.subtitle'
)
}}
.col
.flex.items-center
template(v-if='enabled')
template(v-if='
state.
enabled')
q-spinner-rings.q-mr-sm(color='green')
.text-caption.text-green
{{
$
t
(
'admin.api.enabled'
)
}}
.text-caption.text-green
{{
t
(
'admin.api.enabled'
)
}}
template(v-else)
q-spinner-rings.q-mr-sm(color='red', size='md')
.text-caption.text-red
{{
$
t
(
'admin.api.disabled'
)
}}
.text-caption.text-red
{{
t
(
'admin.api.disabled'
)
}}
.col-auto
q-btn.q-mr-sm.q-ml-md.acrylic-btn(
icon='las la-question-circle'
...
...
@@ -27,24 +27,24 @@ q-page.admin-api
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
:loading='
state.
loading > 0'
@click='load'
)
q-btn.q-mr-sm(
unelevated
icon='las la-power-off'
:label='!
enabled ? $t(`admin.api.enableButton`) : $
t(`admin.api.disableButton`)'
:color='!enabled ? `positive` : `negative`'
:label='!
state.enabled ? t(`admin.api.enableButton`) :
t(`admin.api.disableButton`)'
:color='!
state.
enabled ? `positive` : `negative`'
@click='globalSwitch'
:disabled='loading > 0'
:disabled='
state.
loading > 0'
)
q-btn(
unelevated
icon='las la-plus'
:label='
$
t(`admin.api.newKeyButton`)'
:label='t(`admin.api.newKeyButton`)'
color='primary'
@click='newKey'
:disabled='loading > 0'
:disabled='
state.
loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
...
...
@@ -114,29 +114,30 @@ q-page.admin-api
//- v-btn(color='red', dark, @click='revokeConfirm', :loading='revokeLoading')
{{
$t
(
'admin.api.revoke'
)
}}
</
template
>
<
script
>
import
_get
from
'lodash/get'
import
cloneDeep
from
'lodash/cloneDeep'
<
script
setup
>
import
gql
from
'graphql-tag'
import
{
createMetaMixin
}
from
'quasar'
// import { StatusIndicator } from 'vue-status-indicator'
import
cloneDeep
from
'lodash/cloneDeep'
import
{
useI18n
}
from
'vue-i18n'
import
{
useMeta
,
useQuasar
}
from
'quasar'
import
{
computed
,
onMounted
,
reactive
,
watch
}
from
'vue'
//
import CreateApiKey from './admin-api-create.vue'
//
QUASAR
export
default
{
components
:
{
// StatusIndicator,
// CreateApiKey
},
mixins
:
[
createMetaMixin
(
function
()
{
return
{
title
:
this
.
$t
(
'admin.api.title'
)
}
})
],
data
()
{
return
{
const
$q
=
useQuasar
()
// I18N
const
{
t
}
=
useI18n
()
// META
useMeta
({
title
:
t
(
'admin.api.title'
)
})
// DATA
const
state
=
reactive
({
enabled
:
false
,
loading
:
0
,
keys
:
[],
...
...
@@ -144,16 +145,14 @@ export default {
isRevokeConfirmDialogShown
:
false
,
revokeLoading
:
false
,
current
:
{}
}
},
mounted
()
{
this
.
load
()
},
methods
:
{
async
load
()
{
this
.
loading
++
this
.
$q
.
loading
.
show
()
const
resp
=
await
this
.
$apollo
.
query
({
})
// METHODS
async
function
load
()
{
state
.
loading
++
$q
.
loading
.
show
()
const
resp
=
await
APOLLO_CLIENT
.
query
({
query
:
gql
`
query getHooks {
apiKeys {
...
...
@@ -170,15 +169,16 @@ export default {
`
,
fetchPolicy
:
'network-only'
})
this
.
keys
=
cloneDeep
(
resp
?.
data
?.
apiKeys
)
??
[]
this
.
enabled
=
resp
?.
data
?.
apiState
===
true
this
.
$q
.
loading
.
hide
()
this
.
loading
--
},
async
globalSwitch
()
{
this
.
isToggleLoading
=
true
state
.
keys
=
cloneDeep
(
resp
?.
data
?.
apiKeys
)
??
[]
state
.
enabled
=
resp
?.
data
?.
apiState
===
true
$q
.
loading
.
hide
()
state
.
loading
--
}
async
function
globalSwitch
()
{
state
.
isToggleLoading
=
true
try
{
const
resp
=
await
this
.
$apollo
.
mutate
({
const
resp
=
await
APOLLO_CLIENT
.
mutate
({
mutation
:
gql
`
mutation ($enabled: Boolean!) {
authentication {
...
...
@@ -194,42 +194,41 @@ export default {
}
`
,
variables
:
{
enabled
:
!
this
.
enabled
},
watchLoading
(
isLoading
)
{
this
.
$store
.
commit
(
`loading
${
isLoading
?
'Start'
:
'Stop'
}
`
,
'admin-api-toggle'
)
enabled
:
!
state
.
enabled
}
})
if
(
_get
(
resp
,
'data.authentication.setApiState.responseResult.succeeded'
,
false
))
{
this
.
$store
.
commit
(
'showNotification'
,
{
style
:
'success'
,
message
:
this
.
enabled
?
this
.
$t
(
'admin.api.toggleStateDisabledSuccess'
)
:
this
.
$t
(
'admin.api.toggleStateEnabledSuccess'
),
icon
:
'check'
if
(
resp
?.
data
?.
setApiState
?.
operation
?.
succeeded
)
{
$q
.
notify
({
type
:
'positive'
,
message
:
state
.
enabled
?
t
(
'admin.api.toggleStateDisabledSuccess'
)
:
t
(
'admin.api.toggleStateEnabledSuccess'
)
})
await
this
.
load
()
await
load
()
}
else
{
this
.
$store
.
commit
(
'showNotification'
,
{
style
:
'red'
,
message
:
_get
(
resp
,
'data.authentication.setApiState.responseResult.message'
,
'An unexpected error occurred.'
),
icon
:
'alert'
})
throw
new
Error
(
resp
?.
data
?.
setApiState
?.
operation
.
message
||
'An unexpected error occurred.'
)
}
}
catch
(
err
)
{
this
.
$store
.
commit
(
'pushGraphError'
,
err
)
$q
.
notify
({
type
:
'negative'
,
message
:
'Failed to switch API state.'
,
caption
:
err
.
message
})
}
this
.
isToggleLoading
=
false
},
async
newKey
()
{
this
.
isCreateDialogShown
=
true
},
revoke
(
key
)
{
this
.
current
=
key
this
.
isRevokeConfirmDialogShown
=
true
},
async
revokeConfirm
()
{
this
.
revokeLoading
=
true
state
.
isToggleLoading
=
false
}
async
function
newKey
()
{
state
.
isCreateDialogShown
=
true
}
function
revoke
(
key
)
{
state
.
current
=
key
state
.
isRevokeConfirmDialogShown
=
true
}
async
function
revokeConfirm
()
{
state
.
revokeLoading
=
true
try
{
const
resp
=
await
this
.
$apollo
.
mutate
({
const
resp
=
await
APOLLO_CLIENT
.
mutate
({
mutation
:
gql
`
mutation ($id: Int!) {
authentication {
...
...
@@ -245,34 +244,36 @@ export default {
}
`
,
variables
:
{
id
:
this
.
current
.
id
},
watchLoading
(
isLoading
)
{
this
.
$store
.
commit
(
`loading
${
isLoading
?
'Start'
:
'Stop'
}
`
,
'admin-api-revoke'
)
id
:
state
.
current
.
id
}
})
if
(
_get
(
resp
,
'data.authentication.revokeApiKey.responseResult.succeeded'
,
false
))
{
this
.
$store
.
commit
(
'showNotification'
,
{
style
:
'success'
,
message
:
this
.
$t
(
'admin.api.revokeSuccess'
),
icon
:
'check'
})
this
.
load
()
}
else
{
this
.
$store
.
commit
(
'showNotification'
,
{
style
:
'red'
,
message
:
_get
(
resp
,
'data.authentication.revokeApiKey.responseResult.message'
,
'An unexpected error occurred.'
),
icon
:
'alert'
})
}
//
if (_get(resp, 'data.authentication.revokeApiKey.responseResult.succeeded', false)) {
//
this.$store.commit('showNotification', {
//
style: 'success',
//
message: this.$t('admin.api.revokeSuccess'),
//
icon: 'check'
//
})
//
this.load()
//
} else {
//
this.$store.commit('showNotification', {
//
style: 'red',
//
message: _get(resp, 'data.authentication.revokeApiKey.responseResult.message', 'An unexpected error occurred.'),
//
icon: 'alert'
//
})
//
}
}
catch
(
err
)
{
this
.
$store
.
commit
(
'pushGraphError'
,
err
)
}
this
.
isRevokeConfirmDialogShown
=
false
this
.
revokeLoading
=
false
}
// this.$store.commit('pushGraphError', err)
}
state
.
isRevokeConfirmDialogShown
=
false
state
.
revokeLoading
=
false
}
// MOUNTED
onMounted
(()
=>
{
load
()
})
</
script
>
<
style
lang=
'scss'
>
...
...
ux/src/pages/AdminTheme.vue
View file @
8fb29cfc
...
...
@@ -4,8 +4,8 @@ q-page.admin-theme
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-paint-roller.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft
{{
$
t
(
'admin.theme.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
$
t
(
'admin.theme.subtitle'
)
}}
.text-h5.text-primary.animated.fadeInLeft
{{
t
(
'admin.theme.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
t
(
'admin.theme.subtitle'
)
}}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
...
...
@@ -19,16 +19,16 @@ q-page.admin-theme
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
:loading='
state.
loading > 0'
@click='load'
)
q-btn(
unelevated
icon='
mdi
-check'
:label='
$
t(`common.actions.apply`)'
icon='
fa-solid fa
-check'
:label='t(`common.actions.apply`)'
color='secondary'
@click='save'
:loading='loading > 0'
:loading='
state.
loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
...
...
@@ -38,11 +38,11 @@ q-page.admin-theme
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section.flex.items-center
.text-subtitle1
{{
$
t
(
'admin.theme.options'
)
}}
.text-subtitle1
{{
t
(
'admin.theme.options'
)
}}
q-space
q-btn.acrylic-btn(
icon='las la-redo-alt'
:label='
$
t(`admin.theme.resetDefaults`)'
:label='t(`admin.theme.resetDefaults`)'
flat
size='sm'
color='pink'
...
...
@@ -51,25 +51,25 @@ q-page.admin-theme
q-item(tag='label', v-ripple)
blueprint-icon(icon='light-on')
q-item-section
q-item-label
{{
$
t
(
`admin.theme.darkMode`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.theme.darkModeHint`
)
}}
q-item-label
{{
t
(
`admin.theme.darkMode`
)
}}
q-item-label(caption)
{{
t
(
`admin.theme.darkModeHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.dark'
v-model='
state.
config.dark'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.theme.darkMode`)'
:aria-label='t(`admin.theme.darkMode`)'
)
template(v-for='(cl, idx) of colorKeys', :key='cl')
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='fill-color')
q-item-section
q-item-label
{{
$
t
(
`admin.theme.`
+
cl
+
`Color`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.theme.`
+
cl
+
`ColorHint`
)
}}
q-item-label
{{
t
(
`admin.theme.`
+
cl
+
`Color`
)
}}
q-item-label(caption)
{{
t
(
`admin.theme.`
+
cl
+
`ColorHint`
)
}}
q-item-section(side)
.text-caption.text-grey-6
{{
config
[
`color`
+
startCase
(
cl
)]
}}
.text-caption.text-grey-6
{{
state
.
config
[
`color`
+
startCase
(
cl
)]
}}
q-item-section(side)
q-btn.q-mr-sm(
:key='`btnpick-` + cl'
...
...
@@ -77,14 +77,14 @@ q-page.admin-theme
padding='xs md'
no-caps
size='sm'
:style='`background-color: ` + config[`color` + startCase(cl)] + `;`'
:style='`background-color: ` +
state.
config[`color` + startCase(cl)] + `;`'
text-color='white'
)
q-icon(name='las la-fill', size='xs', left)
span Pick...
q-menu
q-color(
v-model='config[`color` + startCase(cl)]'
v-model='
state.
config[`color` + startCase(cl)]'
)
//- -----------------------
...
...
@@ -92,69 +92,63 @@ q-page.admin-theme
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1
{{
$
t
(
'admin.theme.layout'
)
}}
.text-subtitle1
{{
t
(
'admin.theme.layout'
)
}}
q-item
blueprint-icon(icon='right-navigation-toolbar')
q-item-section
q-item-label
{{
$
t
(
`admin.theme.sidebarPosition`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.theme.sidebarPositionHint`
)
}}
q-item-label
{{
t
(
`admin.theme.sidebarPosition`
)
}}
q-item-label(caption)
{{
t
(
`admin.theme.sidebarPositionHint`
)
}}
q-item-section.col-auto
q-btn-toggle(
v-model='config.sidebarPosition'
v-model='
state.
config.sidebarPosition'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: 'Left', value: 'left' },
{ label: 'Right', value: 'right' }
]`
:options='rightLeftOptions'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='index')
q-item-section
q-item-label
{{
$
t
(
`admin.theme.tocPosition`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.theme.tocPositionHint`
)
}}
q-item-label
{{
t
(
`admin.theme.tocPosition`
)
}}
q-item-label(caption)
{{
t
(
`admin.theme.tocPositionHint`
)
}}
q-item-section.col-auto
q-btn-toggle(
v-model='config.tocPosition'
v-model='
state.
config.tocPosition'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: 'Left', value: 'left' },
{ label: 'Right', value: 'right' }
]`
:options='rightLeftOptions'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='share')
q-item-section
q-item-label
{{
$
t
(
`admin.theme.showSharingMenu`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.theme.showSharingMenuHint`
)
}}
q-item-label
{{
t
(
`admin.theme.showSharingMenu`
)
}}
q-item-label(caption)
{{
t
(
`admin.theme.showSharingMenuHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.showSharingMenu'
v-model='
state.
config.showSharingMenu'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.theme.showSharingMenu`)'
:aria-label='t(`admin.theme.showSharingMenu`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='print')
q-item-section
q-item-label
{{
$
t
(
`admin.theme.showPrintBtn`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.theme.showPrintBtnHint`
)
}}
q-item-label
{{
t
(
`admin.theme.showPrintBtn`
)
}}
q-item-label(caption)
{{
t
(
`admin.theme.showPrintBtnHint`
)
}}
q-item-section(avatar)
q-toggle(
v-model='config.showPrintBtn'
v-model='
state.
config.showPrintBtn'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='
$
t(`admin.theme.showPrintBtn`)'
:aria-label='t(`admin.theme.showPrintBtn`)'
)
.col-6
...
...
@@ -163,81 +157,86 @@ q-page.admin-theme
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1
{{
$
t
(
'admin.theme.codeInjection'
)
}}
.text-subtitle1
{{
t
(
'admin.theme.codeInjection'
)
}}
q-item
blueprint-icon(icon='css')
q-item-section
q-item-label
{{
$
t
(
`admin.theme.cssOverride`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.theme.cssOverrideHint`
)
}}
q-item-label
{{
t
(
`admin.theme.cssOverride`
)
}}
q-item-label(caption)
{{
t
(
`admin.theme.cssOverrideHint`
)
}}
q-item
q-item-section
q-no-ssr(:placeholder='
$
t(`common.loading`)')
q-no-ssr(:placeholder='t(`common.loading`)')
util-code-editor.admin-theme-cm(
ref='cmCSS'
v-model='config.injectCSS'
v-model='
state.
config.injectCSS'
language='css'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='html')
q-item-section
q-item-label
{{
$
t
(
`admin.theme.headHtmlInjection`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.theme.headHtmlInjectionHint`
)
}}
q-item-label
{{
t
(
`admin.theme.headHtmlInjection`
)
}}
q-item-label(caption)
{{
t
(
`admin.theme.headHtmlInjectionHint`
)
}}
q-item
q-item-section
q-no-ssr(:placeholder='
$
t(`common.loading`)')
q-no-ssr(:placeholder='t(`common.loading`)')
util-code-editor.admin-theme-cm(
ref='cmHead'
v-model='config.injectHead'
v-model='
state.
config.injectHead'
language='html'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='html')
q-item-section
q-item-label
{{
$
t
(
`admin.theme.bodyHtmlInjection`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.theme.bodyHtmlInjectionHint`
)
}}
q-item-label
{{
t
(
`admin.theme.bodyHtmlInjection`
)
}}
q-item-label(caption)
{{
t
(
`admin.theme.bodyHtmlInjectionHint`
)
}}
q-item
q-item-section
q-no-ssr(:placeholder='
$
t(`common.loading`)')
q-no-ssr(:placeholder='t(`common.loading`)')
util-code-editor.admin-theme-cm(
ref='cmBody'
v-model='config.injectBody'
v-model='
state.
config.injectBody'
language='html'
)
</
template
>
<
script
>
<
script
setup
>
import
gql
from
'graphql-tag'
import
{
get
}
from
'vuex-pathify'
import
_get
from
'lodash/get'
import
cloneDeep
from
'lodash/cloneDeep'
import
startCase
from
'lodash/startCase'
import
{
createMetaMixin
,
useQuasar
}
from
'quasar'
import
{
useI18n
}
from
'vue-i18n'
import
{
useMeta
,
useQuasar
}
from
'quasar'
import
{
onMounted
,
reactive
,
watch
}
from
'vue'
import
{
useAdminStore
}
from
'src/stores/admin'
import
{
useSiteStore
}
from
'src/stores/site'
import
UtilCodeEditor
from
'../components/UtilCodeEditor.vue'
export
default
{
components
:
{
UtilCodeEditor
},
mixins
:
[
createMetaMixin
(
function
()
{
return
{
title
:
this
.
$t
(
'admin.theme.title'
)
}
})
],
data
()
{
return
{
qsr
:
useQuasar
(),
// QUASAR
const
$q
=
useQuasar
()
// STORES
const
adminStore
=
useAdminStore
()
const
siteStore
=
useSiteStore
()
// I18N
const
{
t
}
=
useI18n
()
// META
useMeta
({
title
:
t
(
'admin.theme.title'
)
})
// DATA
const
state
=
reactive
({
loading
:
0
,
colorKeys
:
[
'primary'
,
'secondary'
,
'accent'
,
'header'
,
'sidebar'
],
config
:
{
dark
:
false
,
injectCSS
:
''
,
...
...
@@ -253,35 +252,43 @@ export default {
showSharingMenu
:
true
,
showPrintBtn
:
true
}
}
},
computed
:
{
currentSiteId
:
get
(
'admin/currentSiteId'
,
false
)
},
watch
:
{
currentSiteId
()
{
this
.
load
()
}
},
mounted
()
{
this
.
load
()
},
methods
:
{
startCase
,
resetColors
()
{
this
.
config
.
dark
=
false
this
.
config
.
colorPrimary
=
'#1976D2'
this
.
config
.
colorSecondary
=
'#02C39A'
this
.
config
.
colorAccent
=
'#f03a47'
this
.
config
.
colorHeader
=
'#000'
this
.
config
.
colorSidebar
=
'#1976D2'
},
async
load
()
{
if
(
!
this
.
currentSiteId
)
{
return
}
})
const
colorKeys
=
[
'primary'
,
'secondary'
,
'accent'
,
'header'
,
'sidebar'
]
const
rightLeftOptions
=
[
{
label
:
'Left'
,
value
:
'left'
},
{
label
:
'Right'
,
value
:
'right'
}
]
// WATCHERS
watch
(()
=>
adminStore
.
currentSiteId
,
(
newValue
)
=>
{
load
()
})
// METHODS
this
.
loading
++
function
resetColors
()
{
state
.
config
.
dark
=
false
state
.
config
.
colorPrimary
=
'#1976D2'
state
.
config
.
colorSecondary
=
'#02C39A'
state
.
config
.
colorAccent
=
'#f03a47'
state
.
config
.
colorHeader
=
'#000'
state
.
config
.
colorSidebar
=
'#1976D2'
}
async
function
load
()
{
state
.
loading
++
$q
.
loading
.
show
()
try
{
const
resp
=
await
this
.
$apollo
.
query
({
const
resp
=
await
APOLLO_CLIENT
.
query
({
query
:
gql
`
query fetchThemeConfig (
$id: UUID!
...
...
@@ -308,41 +315,43 @@ export default {
}
`
,
variables
:
{
id
:
this
.
currentSiteId
id
:
adminStore
.
currentSiteId
},
fetchPolicy
:
'network-only'
})
if
(
!
resp
?.
data
?.
siteById
?.
theme
)
{
throw
new
Error
(
'Failed to fetch theme config.'
)
}
this
.
config
=
cloneDeep
(
resp
.
data
.
siteById
.
theme
)
state
.
config
=
cloneDeep
(
resp
.
data
.
siteById
.
theme
)
}
catch
(
err
)
{
this
.
$q
.
notify
({
$q
.
notify
({
type
:
'negative'
,
message
:
'Failed to fetch site theme config'
})
}
this
.
loading
--
},
async
save
()
{
this
.
loading
++
$q
.
loading
.
hide
()
state
.
loading
--
}
async
function
save
()
{
state
.
loading
++
try
{
const
patchTheme
=
{
dark
:
this
.
config
.
dark
,
colorPrimary
:
this
.
config
.
colorPrimary
,
colorSecondary
:
this
.
config
.
colorSecondary
,
colorAccent
:
this
.
config
.
colorAccent
,
colorHeader
:
this
.
config
.
colorHeader
,
colorSidebar
:
this
.
config
.
colorSidebar
,
injectCSS
:
this
.
config
.
injectCSS
,
injectHead
:
this
.
config
.
injectHead
,
injectBody
:
this
.
config
.
injectBody
,
sidebarPosition
:
this
.
config
.
sidebarPosition
,
tocPosition
:
this
.
config
.
tocPosition
,
showSharingMenu
:
this
.
config
.
showSharingMenu
,
showPrintBtn
:
this
.
config
.
showPrintBtn
dark
:
state
.
config
.
dark
,
colorPrimary
:
state
.
config
.
colorPrimary
,
colorSecondary
:
state
.
config
.
colorSecondary
,
colorAccent
:
state
.
config
.
colorAccent
,
colorHeader
:
state
.
config
.
colorHeader
,
colorSidebar
:
state
.
config
.
colorSidebar
,
injectCSS
:
state
.
config
.
injectCSS
,
injectHead
:
state
.
config
.
injectHead
,
injectBody
:
state
.
config
.
injectBody
,
sidebarPosition
:
state
.
config
.
sidebarPosition
,
tocPosition
:
state
.
config
.
tocPosition
,
showSharingMenu
:
state
.
config
.
showSharingMenu
,
showPrintBtn
:
state
.
config
.
showPrintBtn
}
const
respRaw
=
await
this
.
$apollo
.
mutate
({
const
respRaw
=
await
APOLLO_CLIENT
.
mutate
({
mutation
:
gql
`
mutation saveTheme (
$id: UUID!
...
...
@@ -352,7 +361,7 @@ export default {
id: $id,
patch: $patch
) {
status
{
operation
{
succeeded
slug
message
...
...
@@ -361,36 +370,44 @@ export default {
}
`
,
variables
:
{
id
:
this
.
currentSiteId
,
id
:
adminStore
.
currentSiteId
,
patch
:
{
theme
:
patchTheme
}
}
})
const
resp
=
_get
(
respRaw
,
'data.updateSite.status'
,
{})
if
(
resp
.
succeeded
)
{
if
(
this
.
currentSiteId
===
this
.
$store
.
get
(
'site/id'
))
{
this
.
$store
.
set
(
'site/theme'
,
patchTheme
)
this
.
$q
.
dark
.
set
(
this
.
config
.
dark
)
if
(
respRaw
?.
data
?.
updateSite
?.
operation
?.
succeeded
)
{
if
(
adminStore
.
currentSiteId
===
siteStore
.
id
)
{
siteStore
.
$patch
({
theme
:
patchTheme
})
$q
.
dark
.
set
(
state
.
config
.
dark
)
}
this
.
$q
.
notify
({
$q
.
notify
({
type
:
'positive'
,
message
:
this
.
$
t
(
'admin.theme.saveSuccess'
)
message
:
t
(
'admin.theme.saveSuccess'
)
})
}
else
{
throw
new
Error
(
resp
.
message
)
throw
new
Error
(
respRaw
?.
data
?.
updateSite
?.
operation
?.
message
||
'An unexpected error occured.'
)
}
}
catch
(
err
)
{
this
.
$q
.
notify
({
$q
.
notify
({
type
:
'negative'
,
message
:
'Failed to save site theme config'
,
caption
:
err
.
message
})
}
this
.
loading
--
}
}
state
.
loading
--
}
// MOUNTED
onMounted
(()
=>
{
if
(
adminStore
.
currentSiteId
)
{
load
()
}
})
</
script
>
<
style
lang=
'scss'
>
...
...
ux/src/pages/AdminUtilities.vue
View file @
8fb29cfc
...
...
@@ -4,14 +4,14 @@ q-page.admin-utilities
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-swiss-army-knife.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft
{{
$
t
(
'admin.utilities.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
$
t
(
'admin.utilities.subtitle'
)
}}
.text-h5.text-primary.animated.fadeInLeft
{{
t
(
'admin.utilities.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
t
(
'admin.utilities.subtitle'
)
}}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.
requarks.io
/admin/utilities'
href='https://docs.
js.wiki
/admin/utilities'
target='_blank'
type='a'
)
...
...
@@ -22,38 +22,31 @@ q-page.admin-utilities
q-item
blueprint-icon(icon='matches', :hue-rotate='45')
q-item-section
q-item-label
{{
$
t
(
`admin.utilities.invalidAuthCertificates`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.utilities.invalidAuthCertificatesHint`
)
}}
q-item-label
{{
t
(
`admin.utilities.invalidAuthCertificates`
)
}}
q-item-label(caption)
{{
t
(
`admin.utilities.invalidAuthCertificatesHint`
)
}}
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='primary'
@click=''
:label='
$
t(`common.actions.proceed`)'
:label='t(`common.actions.proceed`)'
)
q-item
blueprint-icon(icon='historical', :hue-rotate='45')
q-item-section
q-item-label
{{
$
t
(
`admin.utilities.purgeHistory`
)
}}
q-item-label(caption)
{{
$
t
(
`admin.utilities.purgeHistoryHint`
)
}}
q-item-label
{{
t
(
`admin.utilities.purgeHistory`
)
}}
q-item-label(caption)
{{
t
(
`admin.utilities.purgeHistoryHint`
)
}}
q-item-section(side)
q-select(
outlined
:label='
$
t(`admin.utilities.purgeHistoryTimeframe`)'
v-model='purgeHistoryTimeframe'
:label='t(`admin.utilities.purgeHistoryTimeframe`)'
v-model='
state.
purgeHistoryTimeframe'
style='min-width: 175px;'
emit-value
map-options
dense
:options=`[
{ value: '24h', label: $t('admin.utitilies.purgeHistoryToday') },
{ value: '1m', label: $tc('admin.utitilies.purgeHistoryMonth', 1, { count: 1 }) },
{ value: '3m', label: $tc('admin.utitilies.purgeHistoryMonth', 3, { count: 3 }) },
{ value: '6m', label: $tc('admin.utitilies.purgeHistoryMonth', 6, { count: 6 }) },
{ value: '1y', label: $tc('admin.utitilies.purgeHistoryYear', 1, { count: 1 }) },
{ value: '2y', label: $tc('admin.utitilies.purgeHistoryYear', 2, { count: 2 }) }
]`
:options='purgeHistoryTimeframes'
)
q-separator.q-ml-sm(vertical)
q-item-section(side)
...
...
@@ -62,20 +55,46 @@ q-page.admin-utilities
icon='las la-arrow-circle-right'
color='primary'
@click=''
:label='
$
t(`common.actions.proceed`)'
:label='t(`common.actions.proceed`)'
)
</
template
>
<
script
>
<
script
setup
>
import
{
computed
,
reactive
}
from
'vue'
import
{
useMeta
,
useQuasar
}
from
'quasar'
import
{
useI18n
}
from
'vue-i18n'
export
default
{
data
()
{
return
{
// QUASAR
const
$q
=
useQuasar
()
// STORES / ROUTERS / i18n
const
{
t
}
=
useI18n
()
// META
useMeta
({
title
:
t
(
'admin.utilities.title'
)
})
// DATA
const
state
=
reactive
({
purgeHistoryTimeframe
:
'1y'
}
}
}
})
// COMPUTED
const
purgeHistoryTimeframes
=
computed
(()
=>
([
{
value
:
'24h'
,
label
:
t
(
'admin.utitilies.purgeHistoryToday'
)
},
{
value
:
'1m'
,
label
:
t
(
'admin.utitilies.purgeHistoryMonth'
,
1
,
{
count
:
1
})
},
{
value
:
'3m'
,
label
:
t
(
'admin.utitilies.purgeHistoryMonth'
,
3
,
{
count
:
3
})
},
{
value
:
'6m'
,
label
:
t
(
'admin.utitilies.purgeHistoryMonth'
,
6
,
{
count
:
6
})
},
{
value
:
'1y'
,
label
:
t
(
'admin.utitilies.purgeHistoryYear'
,
1
,
{
count
:
1
})
},
{
value
:
'2y'
,
label
:
t
(
'admin.utitilies.purgeHistoryYear'
,
2
,
{
count
:
2
})
}
]))
</
script
>
<
style
lang=
'scss'
>
...
...
ux/src/router/routes.js
View file @
8fb29cfc
...
...
@@ -36,20 +36,20 @@ const routes = [
{
path
:
':siteid/locale'
,
component
:
()
=>
import
(
'../pages/AdminLocale.vue'
)
},
{
path
:
':siteid/login'
,
component
:
()
=>
import
(
'../pages/AdminLogin.vue'
)
},
// { path: ':siteid/navigation', component: () => import('../pages/AdminNavigation.vue') },
{
path
:
':siteid/storage/:id?'
,
component
:
()
=>
import
(
'../pages/AdminStorage.vue'
)
},
// { path: ':siteid/rendering', component: () => import('../pages/AdminRendering.vue') },
// { path: ':siteid/theme', component: () => import('../pages/AdminTheme.vue') },
{
path
:
':siteid/storage/:id?'
,
component
:
()
=>
import
(
'../pages/AdminStorage.vue'
)
},
{
path
:
':siteid/theme'
,
component
:
()
=>
import
(
'../pages/AdminTheme.vue'
)
},
// -> Users
// { path: 'auth', component: () => import('../pages/AdminAuth.vue') },
{
path
:
'groups/:id?/:section?'
,
component
:
()
=>
import
(
'../pages/AdminGroups.vue'
)
},
{
path
:
'users/:id?/:section?'
,
component
:
()
=>
import
(
'../pages/AdminUsers.vue'
)
},
// -> System
//
{ path: 'api', component: () => import('../pages/AdminApi.vue') },
{
path
:
'api'
,
component
:
()
=>
import
(
'../pages/AdminApi.vue'
)
},
{
path
:
'extensions'
,
component
:
()
=>
import
(
'../pages/AdminExtensions.vue'
)
},
{
path
:
'mail'
,
component
:
()
=>
import
(
'../pages/AdminMail.vue'
)
},
{
path
:
'security'
,
component
:
()
=>
import
(
'../pages/AdminSecurity.vue'
)
},
{
path
:
'system'
,
component
:
()
=>
import
(
'../pages/AdminSystem.vue'
)
},
//
{ path: 'utilities', component: () => import('../pages/AdminUtilities.vue') },
{
path
:
'utilities'
,
component
:
()
=>
import
(
'../pages/AdminUtilities.vue'
)
},
{
path
:
'webhooks'
,
component
:
()
=>
import
(
'../pages/AdminWebhooks.vue'
)
},
{
path
:
'flags'
,
component
:
()
=>
import
(
'../pages/AdminFlags.vue'
)
}
]
...
...
ux/yarn.lock
View file @
8fb29cfc
This diff was suppressed by a .gitattributes entry.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment