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
dfde2e10
Unverified
Commit
dfde2e10
authored
Apr 10, 2022
by
NGPixel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: admin sites + create site dialog to vue3 comp api
parent
70a2e3ca
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
220 additions
and
160 deletions
+220
-160
dev.code-workspace
dev.code-workspace
+2
-1
SiteCreateDialog.vue
ux/src/components/SiteCreateDialog.vue
+93
-79
app.scss
ux/src/css/app.scss
+39
-0
AdminLayout.vue
ux/src/layouts/AdminLayout.vue
+1
-2
AdminSites.vue
ux/src/pages/AdminSites.vue
+85
-78
No files found.
dev.code-workspace
View file @
dfde2e10
...
...
@@ -13,6 +13,7 @@
"i18n-ally.localesPaths": [
"src/i18n",
"src/i18n/locales"
]
],
"i18n-ally.keystyle": "nested"
}
}
ux/src/components/SiteCreateDialog.vue
View file @
dfde2e10
<
template
lang=
"pug"
>
q-dialog(ref='dialog', @hide='onDialogHide')
q-dialog(ref='dialog
Ref
', @hide='onDialogHide')
q-card(style='min-width: 450px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-plus-plus.svg', left, size='sm')
span
{{
$
t
(
`admin.sites.new`
)
}}
span
{{
t
(
`admin.sites.new`
)
}}
q-form.q-py-sm(ref='createSiteForm')
q-item
blueprint-icon(icon='home')
q-item-section
q-input(
outlined
v-model='siteName'
v-model='s
tate.s
iteName'
dense
:rules=`[
val => val.length > 0 ||
$
t('admin.sites.nameMissing'),
val => /^[^<>"]+$/.test(val) ||
$
t('admin.sites.nameInvalidChars')
val => val.length > 0 || t('admin.sites.nameMissing'),
val => /^[^<>"]+$/.test(val) || t('admin.sites.nameInvalidChars')
]`
hide-bottom-space
:label='
$
t(`common.field.name`)'
:aria-label='
$
t(`common.field.name`)'
:label='t(`common.field.name`)'
:aria-label='t(`common.field.name`)'
lazy-rules='ondemand'
autofocus
)
...
...
@@ -27,107 +27,121 @@ q-dialog(ref='dialog', @hide='onDialogHide')
q-item-section
q-input(
outlined
v-model='siteHostname'
v-model='s
tate.s
iteHostname'
dense
:rules=`[
val => val.length > 0 ||
$
t('admin.sites.hostnameMissing'),
val => /^(\\*)|([a-z0-9\-.:]+)$/.test(val) ||
$
t('admin.sites.hostnameInvalidChars')
val => val.length > 0 || t('admin.sites.hostnameMissing'),
val => /^(\\*)|([a-z0-9\-.:]+)$/.test(val) || t('admin.sites.hostnameInvalidChars')
]`
:hint='
$
t(`admin.sites.hostnameHint`)'
:hint='t(`admin.sites.hostnameHint`)'
hide-bottom-space
:label='
$
t(`admin.sites.hostname`)'
:aria-label='
$
t(`admin.sites.hostname`)'
:label='t(`admin.sites.hostname`)'
:aria-label='t(`admin.sites.hostname`)'
lazy-rules='ondemand'
)
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='
$
t(`common.actions.cancel`)'
:label='t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='
hide
'
@click='
onDialogCancel
'
)
q-btn(
unelevated
:label='
$
t(`common.actions.create`)'
:label='t(`common.actions.create`)'
color='primary'
padding='xs md'
@click='create'
:loading='isLoading'
:loading='
state.
isLoading'
)
</
template
>
<
script
>
<
script
setup
>
import
gql
from
'graphql-tag'
import
{
useI18n
}
from
'vue-i18n'
import
{
useDialogPluginComponent
,
useQuasar
}
from
'quasar'
import
{
reactive
,
ref
}
from
'vue'
export
default
{
emits
:
[
'ok'
,
'hide'
],
data
()
{
return
{
siteName
:
''
,
siteHostname
:
'wiki.example.com'
,
isLoading
:
false
import
{
useAdminStore
}
from
'../stores/admin'
defineEmits
([
...
useDialogPluginComponent
.
emits
])
// QUASAR
const
{
dialogRef
,
onDialogHide
,
onDialogOK
,
onDialogCancel
}
=
useDialogPluginComponent
()
const
$q
=
useQuasar
()
// STORES
const
adminStore
=
useAdminStore
()
// I18N
const
{
t
}
=
useI18n
()
// DATA
const
state
=
reactive
({
siteName
:
''
,
siteHostname
:
'wiki.example.com'
,
isLoading
:
false
})
// REFS
const
createSiteForm
=
ref
(
null
)
// METHODS
async
function
create
()
{
state
.
isLoading
=
true
try
{
const
isFormValid
=
await
createSiteForm
.
value
.
validate
(
true
)
if
(
!
isFormValid
)
{
throw
new
Error
(
t
(
'admin.sites.createInvalidData'
))
}
},
methods
:
{
show
()
{
this
.
$refs
.
dialog
.
show
()
},
hide
()
{
this
.
$refs
.
dialog
.
hide
()
},
onDialogHide
()
{
this
.
$emit
(
'hide'
)
},
async
create
()
{
this
.
isLoading
=
true
try
{
const
isFormValid
=
await
this
.
$refs
.
createSiteForm
.
validate
(
true
)
if
(
!
isFormValid
)
{
throw
new
Error
(
this
.
$t
(
'admin.sites.createInvalidData'
))
}
const
resp
=
await
this
.
$apollo
.
mutate
({
mutation
:
gql
`
mutation createSite (
$hostname: String!
$title: String!
) {
createSite(
hostname: $hostname
title: $title
) {
status {
succeeded
message
}
}
const
resp
=
await
APOLLO_CLIENT
.
mutate
({
mutation
:
gql
`
mutation createSite (
$hostname: String!
$title: String!
) {
createSite(
hostname: $hostname
title: $title
) {
status {
succeeded
message
}
`
,
variables
:
{
hostname
:
this
.
siteHostname
,
title
:
this
.
siteName
}
})
if
(
resp
?.
data
?.
createSite
?.
status
?.
succeeded
)
{
this
.
$q
.
notify
({
type
:
'positive'
,
message
:
this
.
$t
(
'admin.sites.createSuccess'
)
})
await
this
.
$store
.
dispatch
(
'admin/fetchSites'
)
this
.
$emit
(
'ok'
)
this
.
hide
()
}
else
{
throw
new
Error
(
resp
?.
data
?.
createSite
?.
status
?.
message
||
'An unexpected error occured.'
)
}
}
catch
(
err
)
{
this
.
$q
.
notify
({
type
:
'negative'
,
message
:
err
.
message
})
`
,
variables
:
{
hostname
:
state
.
siteHostname
,
title
:
state
.
siteName
}
this
.
isLoading
=
false
})
if
(
resp
?.
data
?.
createSite
?.
status
?.
succeeded
)
{
$q
.
notify
({
type
:
'positive'
,
message
:
t
(
'admin.sites.createSuccess'
)
})
await
adminStore
.
fetchSites
()
onDialogOK
()
}
else
{
throw
new
Error
(
resp
?.
data
?.
createSite
?.
status
?.
message
||
'An unexpected error occured.'
)
}
}
catch
(
err
)
{
$q
.
notify
({
type
:
'negative'
,
message
:
err
.
message
})
}
state
.
isLoading
=
false
}
</
script
>
ux/src/css/app.scss
View file @
dfde2e10
...
...
@@ -139,6 +139,45 @@ body.desktop .acrylic-btn {
}
// ------------------------------------------------------------------
// DIALOGS
// ------------------------------------------------------------------
.card-header
{
display
:
flex
;
align-items
:
center
;
font-weight
:
500
;
font-size
:
.9rem
;
background-color
:
$dark-3
;
background-image
:
radial-gradient
(
at
bottom
right
,
$dark-3
,
$dark-5
);
color
:
#FFF
;
@at-root
.body--light
&
{
border-bottom
:
1px
solid
$dark-3
;
box-shadow
:
0
1px
0
0
$dark-6
;
}
@at-root
.body--dark
&
{
border-bottom
:
1px
solid
#000
;
box-shadow
:
0
1px
0
0
lighten
(
$dark-3
,
2%
);
}
}
.card-actions
{
@at-root
.body--light
&
{
background-color
:
#FAFAFA
;
background-image
:
linear-gradient
(
to
bottom
,
#FCFCFC
,
#F0F0F0
);
color
:
$dark-3
;
border-top
:
1px
solid
#EEE
;
box-shadow
:
inset
0
1px
0
0
#FFF
;
}
@at-root
.body--dark
&
{
background-color
:
$dark-3
;
background-image
:
radial-gradient
(
at
top
left
,
$dark-3
,
$dark-5
);
border-top
:
1px
solid
#000
;
box-shadow
:
0
-1px
0
0
lighten
(
$dark-3
,
2%
);
}
}
// ------------------------------------------------------------------
// IMPORTS
// ------------------------------------------------------------------
...
...
ux/src/layouts/AdminLayout.vue
View file @
dfde2e10
...
...
@@ -167,8 +167,7 @@ q-layout.admin(view='hHh Lpr lff')
q-item-section
{{
t
(
'admin.dev.flags.title'
)
}}
q-page-container.admin-container
router-view(v-slot='{ Component }')
transition(name='fade')
component(:is='Component')
component(:is='Component')
q-dialog.admin-overlay(
v-model='overlayIsShown'
persistent
...
...
ux/src/pages/AdminSites.vue
View file @
dfde2e10
...
...
@@ -4,8 +4,8 @@ q-page.admin-locale
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-change-theme.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft
{{
$
t
(
'admin.sites.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
$
t
(
'admin.sites.subtitle'
)
}}
.text-h5.text-primary.animated.fadeInLeft
{{
t
(
'admin.sites.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
t
(
'admin.sites.subtitle'
)
}}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
...
...
@@ -16,7 +16,7 @@ q-page.admin-locale
target='_blank'
)
q-btn.q-mr-sm.acrylic-btn(
icon='
las la-redo-alt
'
icon='
fa-solid fa-rotate
'
flat
color='secondary'
@click='refresh'
...
...
@@ -24,7 +24,7 @@ q-page.admin-locale
q-btn(
unelevated
icon='las la-plus'
:label='
$
t(`admin.sites.new`)'
:label='t(`admin.sites.new`)'
color='primary'
@click='createSite'
)
...
...
@@ -34,7 +34,7 @@ q-page.admin-locale
q-card.shadow-1
q-list(separator)
q-item(
v-for='site of sites'
v-for='site of
adminStore.
sites'
:key='site.id'
)
q-item-section(side)
...
...
@@ -75,8 +75,8 @@ q-page.admin-locale
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:label='
$
t(`admin.sites.isActive`)'
:aria-label='
$
t(`admin.sites.isActive`)'
:label='t(`admin.sites.isActive`)'
:aria-label='t(`admin.sites.isActive`)'
@update:model-value ='(val) => { toggleSiteState(site, val) }'
)
q-separator.q-ml-md(vertical)
...
...
@@ -86,7 +86,7 @@ q-page.admin-locale
@click='editSite(site)'
icon='las la-pen'
color='indigo'
:label='
$
t(`common.actions.edit`)'
:label='t(`common.actions.edit`)'
no-caps
)
q-btn.acrylic-btn(
...
...
@@ -97,82 +97,89 @@ q-page.admin-locale
)
</
template
>
<
script
>
import
{
get
}
from
'vuex-pathify'
import
{
copyToClipboard
,
createMetaMixin
}
from
'quasar'
<
script
setup
>
import
{
useMeta
,
useQuasar
}
from
'quasar'
import
{
useI18n
}
from
'vue-i18n'
import
{
defineAsyncComponent
,
nextTick
,
onMounted
,
reactive
,
ref
,
watch
}
from
'vue'
import
{
useRouter
}
from
'vue-router'
import
{
useAdminStore
}
from
'../stores/admin'
// COMPONENTS
import
SiteActivateDialog
from
'../components/SiteActivateDialog.vue'
import
SiteCreateDialog
from
'../components/SiteCreateDialog.vue'
import
SiteDeleteDialog
from
'../components/SiteDeleteDialog.vue'
export
default
{
mixins
:
[
createMetaMixin
(
function
()
{
return
{
title
:
this
.
$t
(
'admin.sites.title'
)
}
})
],
data
()
{
return
{
loading
:
false
// QUASAR
const
$q
=
useQuasar
()
// STORES
const
adminStore
=
useAdminStore
()
// ROUTER
const
router
=
useRouter
()
// I18N
const
{
t
}
=
useI18n
()
// META
useMeta
({
title
:
t
(
'admin.sites.title'
)
})
// DATA
const
loading
=
ref
(
false
)
// METHODS
async
function
refresh
()
{
await
adminStore
.
fetchSites
()
$q
.
notify
({
type
:
'positive'
,
message
:
t
(
'admin.sites.refreshSuccess'
)
})
}
function
createSite
()
{
$q
.
dialog
({
component
:
SiteCreateDialog
})
}
function
editSite
(
st
)
{
adminStore
.
$patch
({
currentSiteId
:
st
.
id
})
nextTick
(()
=>
{
router
.
push
(
`/_admin/
${
st
.
id
}
/general`
)
})
}
function
toggleSiteState
(
st
,
newState
)
{
$q
.
dialog
({
component
:
SiteActivateDialog
,
componentProps
:
{
site
:
st
,
value
:
newState
}
},
computed
:
{
sites
:
get
(
'admin/sites'
,
false
)
},
methods
:
{
copyID
(
uid
)
{
copyToClipboard
(
uid
).
then
(()
=>
{
this
.
$q
.
notify
({
type
:
'positive'
,
message
:
this
.
$t
(
'common.clipboard.uuidSuccess'
)
})
}).
catch
(()
=>
{
this
.
$q
.
notify
({
type
:
'negative'
,
message
:
this
.
$t
(
'common.clipboard.uuidFailure'
)
})
})
},
async
refresh
()
{
await
this
.
$store
.
dispatch
(
'admin/fetchSites'
)
this
.
$q
.
notify
({
type
:
'positive'
,
message
:
this
.
$t
(
'admin.sites.refreshSuccess'
)
})
},
createSite
()
{
this
.
$q
.
dialog
({
component
:
SiteCreateDialog
})
},
editSite
(
st
)
{
this
.
$store
.
set
(
'admin/currentSiteId'
,
st
.
id
)
this
.
$nextTick
(()
=>
{
this
.
$router
.
push
(
`/_admin/
${
st
.
id
}
/general`
)
})
},
toggleSiteState
(
st
,
newState
)
{
this
.
$q
.
dialog
({
component
:
SiteActivateDialog
,
componentProps
:
{
site
:
st
,
value
:
newState
}
})
},
deleteSite
(
st
)
{
this
.
$q
.
dialog
({
component
:
SiteDeleteDialog
,
componentProps
:
{
site
:
st
}
})
})
}
function
deleteSite
(
st
)
{
$q
.
dialog
({
component
:
SiteDeleteDialog
,
componentProps
:
{
site
:
st
}
},
mounted
()
{
this
.
$store
.
dispatch
(
'admin/fetchSites'
)
}
})
}
// MOUNTED
onMounted
(
async
()
=>
{
await
adminStore
.
fetchSites
()
})
</
script
>
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