From f4e3fd0954d9a8840942eb10c322e3333eb2a2a3 Mon Sep 17 00:00:00 2001 From: NGPixel Date: Sun, 2 Feb 2020 16:24:27 -0500 Subject: [PATCH] feat: tags autocomplete in page properties --- .../editor/editor-modal-properties.vue | 60 +++++++++++++++++-- server/graph/resolvers/page.js | 18 ++++++ server/graph/schemas/page.graphql | 4 ++ server/models/tags.js | 4 ++ server/modules/search/db/engine.js | 1 - 5 files changed, 80 insertions(+), 7 deletions(-) diff --git a/client/components/editor/editor-modal-properties.vue b/client/components/editor/editor-modal-properties.vue index 53a2b259..792f60a9 100644 --- a/client/components/editor/editor-modal-properties.vue +++ b/client/components/editor/editor-modal-properties.vue @@ -67,18 +67,32 @@ v-divider v-card-text.grey.pt-5(:class='darkMode ? `darken-3-d5` : `lighten-4`') .overline.pb-5 {{$t('editor:props.categorization')}} + v-chip-group.radius-5.mb-5(column, v-if='tags && tags.length > 0') + v-chip( + v-for='tag of tags' + :key='`tag-` + tag' + close + label + color='teal' + text-color='teal lighten-5' + @click:close='removeTag(tag)' + ) {{tag}} v-combobox( - chips - deletable-chips :label='$t(`editor:props.tags`)' outlined - multiple v-model='tags' :hint='$t(`editor:props.tagsHint`)' + :items='newTagSuggestions' + :loading='$apollo.queries.newTagSuggestions.loading' persistent-hint - clearable - height='130' + deletable-chips + hide-no-data + hide-selected + :search-input.sync='newTagSearch' + multiple ) + template(v-slot:selection='{ attrs, item, parent, selected }') + span v-tab-item v-card-text .overline.pb-5 {{$t('editor:props.publishState')}} #[v-chip.ml-3(label, color='grey', small, outlined).white--text coming soon] @@ -243,6 +257,7 @@ diff --git a/server/graph/resolvers/page.js b/server/graph/resolvers/page.js index 86ef68cd..0a831fe6 100644 --- a/server/graph/resolvers/page.js +++ b/server/graph/resolvers/page.js @@ -129,6 +129,24 @@ module.exports = { async tags (obj, args, context, info) { return WIKI.models.tags.query().orderBy('tag', 'asc') }, + /** + * SEARCH TAGS + */ + async searchTags (obj, args, context, info) { + const results = await WIKI.models.tags.query() + .column('tag') + .where(builder => { + builder.andWhere(builderSub => { + if (WIKI.config.db.type === 'postgres') { + builderSub.where('tag', 'ILIKE', `%${args.query}%`) + } else { + builderSub.where('tag', 'LIKE', `%${args.query}%`) + } + }) + }) + .limit(5) + return results.map(r => r.tag) + }, /** * FETCH PAGE TREE */ diff --git a/server/graph/schemas/page.graphql b/server/graph/schemas/page.graphql index 0d0ce215..57a2df87 100644 --- a/server/graph/schemas/page.graphql +++ b/server/graph/schemas/page.graphql @@ -41,6 +41,10 @@ type PageQuery { tags: [PageTag]! @auth(requires: ["manage:system", "read:pages"]) + searchTags( + query: String! + ): [String]! @auth(requires: ["manage:system", "read:pages"]) + tree( path: String parent: Int diff --git a/server/models/tags.js b/server/models/tags.js index b2424a4a..18260810 100644 --- a/server/models/tags.js +++ b/server/models/tags.js @@ -53,6 +53,10 @@ module.exports = class Tag extends Model { static async associateTags ({ tags, page }) { let existingTags = await WIKI.models.tags.query().column('id', 'tag') + // Format tags + + tags = _.uniq(tags.map(t => t.toLowerCase())) + // Create missing tags const newTags = _.filter(tags, t => !_.some(existingTags, ['tag', t])).map(t => ({ diff --git a/server/modules/search/db/engine.js b/server/modules/search/db/engine.js index ddbb8891..bb7f931c 100644 --- a/server/modules/search/db/engine.js +++ b/server/modules/search/db/engine.js @@ -30,7 +30,6 @@ module.exports = { if (opts.path) { builder.andWhere('path', 'like', `${opts.path}%`) } - // TODO: Add user permissions filtering builder.andWhere(builderSub => { if (WIKI.config.db.type === 'postgres') { builderSub.where('title', 'ILIKE', `%${q}%`)