diff --git a/client/components/admin.vue b/client/components/admin.vue index eed8483c..b31f935f 100644 --- a/client/components/admin.vue +++ b/client/components/admin.vue @@ -29,9 +29,12 @@ v-list-item-action(style='min-width:auto;') v-chip(x-small, :color='darkMode ? `grey darken-3-d4` : `grey lighten-5`') .caption.grey--text {{ info.pagesTotal }} - v-list-item(to='/tags', v-if='hasPermission([`manage:system`])', disabled) - v-list-item-avatar(size='24'): v-icon(color='grey lighten-2') mdi-tag-multiple + v-list-item(to='/tags', v-if='hasPermission([`manage:system`])') + v-list-item-avatar(size='24'): v-icon mdi-tag-multiple v-list-item-title {{ $t('admin:tags.title') }} + v-list-item-action(style='min-width:auto;') + v-chip(x-small, :color='darkMode ? `grey darken-3-d4` : `grey lighten-5`') + .caption.grey--text {{ info.tagsTotal }} v-list-item(to='/theme', color='primary', v-if='hasPermission([`manage:system`, `manage:theme`])') v-list-item-avatar(size='24'): v-icon mdi-palette-outline v-list-item-title {{ $t('admin:theme.title') }} @@ -154,6 +157,7 @@ const router = new VueRouter({ { path: '/pages', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-pages.vue') }, { path: '/pages/:id(\\d+)', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-pages-edit.vue') }, { path: '/pages/visualize', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-pages-visualize.vue') }, + { path: '/tags', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-tags.vue') }, { path: '/theme', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-theme.vue') }, { path: '/groups', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-groups.vue') }, { path: '/groups/:id(\\d+)', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-groups-edit.vue') }, diff --git a/client/components/admin/admin-tags.vue b/client/components/admin/admin-tags.vue new file mode 100644 index 00000000..77466ada --- /dev/null +++ b/client/components/admin/admin-tags.vue @@ -0,0 +1,247 @@ + + + + + diff --git a/client/graph/admin/dashboard/dashboard-query-stats.gql b/client/graph/admin/dashboard/dashboard-query-stats.gql index 48be7ce8..75bf2096 100644 --- a/client/graph/admin/dashboard/dashboard-query-stats.gql +++ b/client/graph/admin/dashboard/dashboard-query-stats.gql @@ -6,6 +6,7 @@ query { groupsTotal pagesTotal usersTotal + tagsTotal } } } diff --git a/client/static/svg/icon-color-palette.svg b/client/static/svg/icon-color-palette.svg new file mode 100644 index 00000000..5b8fb451 --- /dev/null +++ b/client/static/svg/icon-color-palette.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/static/svg/icon-tags.svg b/client/static/svg/icon-tags.svg new file mode 100644 index 00000000..c003235a --- /dev/null +++ b/client/static/svg/icon-tags.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/server/graph/resolvers/page.js b/server/graph/resolvers/page.js index 0a831fe6..851d4ec4 100644 --- a/server/graph/resolvers/page.js +++ b/server/graph/resolvers/page.js @@ -289,6 +289,46 @@ module.exports = { return graphHelper.generateError(err) } }, + /** + * DELETE TAG + */ + async deleteTag (obj, args, context) { + try { + const tagToDel = await WIKI.models.tags.query().findById(args.id) + if (tagToDel) { + await tagToDel.$relatedQuery('pages').unrelate() + await WIKI.models.tags.query().deleteById(args.id) + } else { + throw new Error('This tag does not exist.') + } + return { + responseResult: graphHelper.generateSuccess('Tag has been deleted.') + } + } catch (err) { + return graphHelper.generateError(err) + } + }, + /** + * UPDATE TAG + */ + async updateTag (obj, args, context) { + try { + const affectedRows = await WIKI.models.tags.query() + .findById(args.id) + .patch({ + tag: args.tag, + title: args.title + }) + if (affectedRows < 1) { + throw new Error('This tag does not exist.') + } + return { + responseResult: graphHelper.generateSuccess('Tag has been updated successfully.') + } + } catch (err) { + return graphHelper.generateError(err) + } + }, /** * FLUSH PAGE CACHE */ diff --git a/server/graph/resolvers/system.js b/server/graph/resolvers/system.js index cafff776..50298363 100644 --- a/server/graph/resolvers/system.js +++ b/server/graph/resolvers/system.js @@ -372,6 +372,10 @@ module.exports = { async usersTotal () { const total = await WIKI.models.users.query().count('* as total').first() return _.toSafeInteger(total.total) + }, + async tagsTotal () { + const total = await WIKI.models.tags.query().count('* as total').first() + return _.toSafeInteger(total.total) } } } diff --git a/server/graph/schemas/page.graphql b/server/graph/schemas/page.graphql index 57a2df87..3be9881e 100644 --- a/server/graph/schemas/page.graphql +++ b/server/graph/schemas/page.graphql @@ -102,6 +102,16 @@ type PageMutation { id: Int! ): DefaultResponse @auth(requires: ["delete:pages", "manage:system"]) + deleteTag( + id: Int! + ): DefaultResponse @auth(requires: ["manage:system"]) + + updateTag( + id: Int! + tag: String! + title: String! + ): DefaultResponse @auth(requires: ["manage:system"]) + flushCache: DefaultResponse @auth(requires: ["manage:system"]) migrateToLocale( diff --git a/server/graph/schemas/system.graphql b/server/graph/schemas/system.graphql index 5b418340..9af61074 100644 --- a/server/graph/schemas/system.graphql +++ b/server/graph/schemas/system.graphql @@ -86,6 +86,7 @@ type SystemInfo { sslProvider: String @auth(requires: ["manage:system"]) sslStatus: String @auth(requires: ["manage:system"]) sslSubscriberEmail: String @auth(requires: ["manage:system"]) + tagsTotal: Int @auth(requires: ["manage:system", "manage:navigation", "manage:pages", "delete:pages"]) telemetry: Boolean @auth(requires: ["manage:system"]) telemetryClientId: String @auth(requires: ["manage:system"]) upgradeCapable: Boolean @auth(requires: ["manage:system"])