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
7e344fc6
Unverified
Commit
7e344fc6
authored
May 24, 2022
by
Nicolas Giard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(admin): migrate groups page to vue 3 composable
parent
1eefdb06
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
214 additions
and
155 deletions
+214
-155
3.0.0.js
server/db/migrations/3.0.0.js
+1
-1
group.graphql
server/graph/schemas/group.graphql
+43
-26
AdminGroups.vue
ux/src/pages/AdminGroups.vue
+169
-127
routes.js
ux/src/router/routes.js
+1
-1
No files found.
server/db/migrations/3.0.0.js
View file @
7e344fc6
...
...
@@ -341,7 +341,7 @@ exports.up = async knex => {
// -> GENERATE IDS
const
groupAdminId
=
uuid
()
const
groupGuestId
=
'10000000-0000-4000-
0
000-000000000001'
const
groupGuestId
=
'10000000-0000-4000-
8
000-000000000001'
const
siteId
=
uuid
()
const
authModuleId
=
uuid
()
const
userAdminId
=
uuid
()
...
...
server/graph/schemas/group.graphql
View file @
7e344fc6
...
...
@@ -9,7 +9,7 @@ extend type Query {
):
[
Group
]
groupById
(
id
:
Int
!
id
:
UUID
!
):
Group
}
...
...
@@ -19,22 +19,25 @@ extend type Mutation {
):
GroupResponse
updateGroup
(
id
:
Int
!
patch
:
GroupUpdateInput
!
id
:
UUID
!
name
:
String
!
redirectOnLogin
:
String
!
permissions
:
[
String
]!
rules
:
[
GroupRuleInput
]!
):
DefaultResponse
deleteGroup
(
id
:
Int
!
id
:
UUID
!
):
DefaultResponse
assignUserToGroup
(
groupId
:
Int
!
userId
:
Int
!
groupId
:
UUID
!
userId
:
UUID
!
):
DefaultResponse
unassignUserFromGroup
(
groupId
:
Int
!
userId
:
Int
!
groupId
:
UUID
!
userId
:
UUID
!
):
DefaultResponse
}
...
...
@@ -48,46 +51,60 @@ type GroupResponse {
}
type
Group
{
id
:
Int
id
:
UUID
name
:
String
isSystem
:
Boolean
redirectOnLogin
:
String
redirectOnFirstLogin
:
String
redirectOnLogout
:
String
permissions
:
[
String
]
pageRules
:
[
PageRule
]
users
:
[
UserMinimal
]
rules
:
[
GroupRule
]
users
(
page
:
Int
pageSize
:
Int
orderBy
:
UserOrderBy
orderByDirection
:
OrderByDirection
# Filter by name / email
filter
:
String
):
[
UserMinimal
]
userCount
:
Int
createdAt
:
Date
updatedAt
:
Date
}
type
PageRule
{
id
:
String
deny
:
Boolean
match
:
PageRuleMatch
type
GroupRule
{
id
:
UUID
name
:
String
mode
:
GroupRuleMode
match
:
GroupRuleMatch
roles
:
[
String
]
path
:
String
locales
:
[
String
]
sites
:
[
UUID
]
}
input
GroupUpdateInput
{
input
GroupRuleInput
{
id
:
UUID
!
name
:
String
!
redirectOnLogin
:
String
!
permissions
:
[
String
]!
pageRules
:
[
PageRuleInput
]!
}
input
PageRuleInput
{
id
:
String
!
deny
:
Boolean
!
match
:
PageRuleMatch
!
mode
:
GroupRuleMode
!
match
:
GroupRuleMatch
!
roles
:
[
String
]!
path
:
String
!
locales
:
[
String
]!
sites
:
[
UUID
]
}
enum
GroupRuleMode
{
ALLOW
DENY
FORCEALLOW
}
enum
Page
RuleMatch
{
enum
Group
RuleMatch
{
START
EXACT
END
REGEX
TAG
TAGALL
}
ux/src/pages/AdminGroups.vue
View file @
7e344fc6
...
...
@@ -4,12 +4,12 @@ q-page.admin-groups
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-people.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft
{{
$
t
(
'admin.groups.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
$
t
(
'admin.groups.subtitle'
)
}}
.text-h5.text-primary.animated.fadeInLeft
{{
t
(
'admin.groups.title'
)
}}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s
{{
t
(
'admin.groups.subtitle'
)
}}
.col-auto.flex.items-center
q-input.denser.q-mr-sm(
outlined
v-model='search'
v-model='s
tate.s
earch'
dense
:class='$q.dark.isActive ? `bg-dark` : `bg-white`'
)
...
...
@@ -28,12 +28,12 @@ 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.groups.create`)'
:label='t(`admin.groups.create`)'
color='primary'
@click='createGroup'
)
...
...
@@ -42,15 +42,15 @@ q-page.admin-groups
.col-12
q-card.shadow-1
q-table(
:rows='groups'
:rows='
state.
groups'
:columns='headers'
row-key='id'
flat
hide-header
hide-bottom
:rows-per-page-options='[0]'
:loading='loading > 0'
:filter='search'
:loading='
state.
loading > 0'
:filter='s
tate.s
earch'
)
template(v-slot:body-cell-id='props')
q-td(:props='props')
...
...
@@ -71,7 +71,7 @@ q-page.admin-groups
:color='$q.dark.isActive ? `dark-6` : `grey-2`'
:text-color='$q.dark.isActive ? `white` : `grey-8`'
dense
)
{{
$
t
(
'admin.groups.usersCount'
,
{
count
:
props
.
value
}
)
}}
)
{{
t
(
'admin.groups.usersCount'
,
{
count
:
props
.
value
}
)
}}
template
(
v
-
slot
:
body
-
cell
-
edit
=
'props'
)
q
-
td
(:
props
=
'props'
)
q
-
btn
.
acrylic
-
btn
.
q
-
mr
-
sm
(
...
...
@@ -79,7 +79,7 @@ q-page.admin-groups
:
to
=
'`/_admin/groups/` + 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
(
...
...
@@ -91,136 +91,178 @@ q-page.admin-groups
)
<
/template
>
<
script
>
<
script
setup
>
import
gql
from
'graphql-tag'
import
cloneDeep
from
'lodash/cloneDeep'
import
{
createMetaMixin
}
from
'quasar'
import
{
sync
}
from
'vuex-pathify'
import
{
useI18n
}
from
'vue-i18n'
import
{
useMeta
,
useQuasar
}
from
'quasar'
import
{
computed
,
onBeforeUnmount
,
onMounted
,
reactive
,
watch
}
from
'vue'
import
{
useRouter
,
useRoute
}
from
'vue-router'
import
{
useAdminStore
}
from
'src/stores/admin'
import
GroupCreateDialog
from
'../components/GroupCreateDialog.vue'
import
GroupDeleteDialog
from
'../components/GroupDeleteDialog.vue'
export
default
{
mixins
:
[
createMetaMixin
(
function
()
{
return
{
title
:
this
.
$t
(
'admin.groups.title'
)
}
}
)
],
data
()
{
return
{
groups
:
[],
loading
:
0
,
search
:
''
}
}
,
computed
:
{
overlay
:
sync
(
'admin/overlay'
,
false
),
headers
()
{
return
[
{
align
:
'center'
,
field
:
'id'
,
name
:
'id'
,
sortable
:
false
,
style
:
'width: 20px'
}
,
{
label
:
this
.
$t
(
'common.field.name'
),
align
:
'left'
,
field
:
'name'
,
name
:
'name'
,
sortable
:
true
}
,
{
label
:
this
.
$t
(
'admin.groups.userCount'
),
align
:
'center'
,
field
:
'userCount'
,
name
:
'usercount'
,
sortable
:
false
,
style
:
'width: 150px'
}
,
{
label
:
''
,
align
:
'right'
,
field
:
'edit'
,
name
:
'edit'
,
sortable
:
false
,
style
:
'width: 250px'
}
]
}
}
,
watch
:
{
overlay
(
newValue
,
oldValue
)
{
if
(
newValue
===
''
&&
oldValue
===
'GroupEditOverlay'
)
{
this
.
$router
.
push
(
'/_admin/groups'
)
this
.
load
()
}
}
,
$route
:
'checkOverlay'
// QUASAR
const
$q
=
useQuasar
()
// STORES
const
adminStore
=
useAdminStore
()
// ROUTER
const
router
=
useRouter
()
const
route
=
useRoute
()
// I18N
const
{
t
}
=
useI18n
()
// META
useMeta
({
title
:
t
(
'admin.groups.title'
)
}
)
// DATA
const
state
=
reactive
({
groups
:
[],
loading
:
0
,
search
:
''
}
)
const
headers
=
[
{
align
:
'center'
,
field
:
'id'
,
name
:
'id'
,
sortable
:
false
,
style
:
'width: 20px'
}
,
mounted
()
{
this
.
checkOverlay
()
this
.
load
()
{
label
:
t
(
'common.field.name'
),
align
:
'left'
,
field
:
'name'
,
name
:
'name'
,
sortable
:
true
}
,
beforeUnmount
()
{
this
.
overlay
=
''
{
label
:
t
(
'admin.groups.userCount'
),
align
:
'center'
,
field
:
'userCount'
,
name
:
'usercount'
,
sortable
:
false
,
style
:
'width: 150px'
}
,
methods
:
{
async
load
()
{
this
.
loading
++
this
.
$q
.
loading
.
show
()
const
resp
=
await
this
.
$apollo
.
query
({
query
:
gql
`
query getGroups {
groups {
id
name
isSystem
userCount
createdAt
updatedAt
}
{
label
:
''
,
align
:
'right'
,
field
:
'edit'
,
name
:
'edit'
,
sortable
:
false
,
style
:
'width: 250px'
}
]
watch
(()
=>
adminStore
.
overlay
,
(
newValue
,
oldValue
)
=>
{
if
(
newValue
===
''
&&
oldValue
===
'GroupEditOverlay'
)
{
router
.
push
(
'/_admin/groups'
)
load
()
}
}
)
watch
(()
=>
route
,
()
=>
{
checkOverlay
()
}
)
// METHODS
async
function
load
()
{
state
.
loading
++
$q
.
loading
.
show
()
try
{
const
resp
=
await
APOLLO_CLIENT
.
query
({
query
:
gql
`
query getGroups {
groups {
id
name
isSystem
userCount
createdAt
updatedAt
}
`
,
fetchPolicy
:
'network-only'
}
)
this
.
groups
=
cloneDeep
(
resp
?.
data
?.
groups
)
this
.
$q
.
loading
.
hide
()
this
.
loading
--
}
,
checkOverlay
()
{
if
(
this
.
$route
.
params
&&
this
.
$route
.
params
.
id
)
{
this
.
$store
.
set
(
'admin/overlayOpts'
,
{
id
:
this
.
$route
.
params
.
id
}
)
this
.
$store
.
set
(
'admin/overlay'
,
'GroupEditOverlay'
)
}
else
{
this
.
$store
.
set
(
'admin/overlay'
,
''
)
}
}
,
createGroup
()
{
this
.
$q
.
dialog
({
component
:
GroupCreateDialog
}
).
onOk
(()
=>
{
this
.
load
()
}
)
}
,
editGroup
(
gr
)
{
this
.
$router
.
push
(
`/_admin/groups/${gr.id
}
`
)
}
,
deleteGroup
(
gr
)
{
this
.
$q
.
dialog
({
component
:
GroupDeleteDialog
,
componentProps
:
{
group
:
gr
}
}
).
onOk
(()
=>
{
this
.
load
()
}
)
}
`
,
fetchPolicy
:
'network-only'
}
)
state
.
groups
=
cloneDeep
(
resp
?.
data
?.
groups
)
}
catch
(
err
)
{
$q
.
notify
({
type
:
'negative'
,
message
:
'Failed to load groups.'
,
caption
:
err
.
message
}
)
}
$q
.
loading
.
hide
()
state
.
loading
--
}
function
checkOverlay
()
{
if
(
route
.
params
&&
route
.
params
.
id
)
{
adminStore
.
$patch
({
overlayOpts
:
{
id
:
route
.
params
.
id
}
,
overlay
:
'GroupEditOverlay'
}
)
}
else
{
adminStore
.
$patch
({
overlay
:
''
}
)
}
}
function
createGroup
()
{
$q
.
dialog
({
component
:
GroupCreateDialog
}
).
onOk
(()
=>
{
load
()
}
)
}
function
editGroup
(
gr
)
{
router
.
push
(
`/_admin/groups/${gr.id
}
`
)
}
function
deleteGroup
(
gr
)
{
$q
.
dialog
({
component
:
GroupDeleteDialog
,
componentProps
:
{
group
:
gr
}
}
).
onOk
(()
=>
{
load
()
}
)
}
// MOUNTED
onMounted
(()
=>
{
checkOverlay
()
load
()
}
)
// BEFORE UNMOUNT
onBeforeUnmount
(()
=>
{
adminStore
.
$patch
({
overlay
:
''
}
)
}
)
<
/script
>
<
style
lang
=
'scss'
>
...
...
ux/src/router/routes.js
View file @
7e344fc6
...
...
@@ -41,7 +41,7 @@ const routes = [
// { 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
:
'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') },
...
...
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