From 59a882d782c56f7aa8d79033e91efeab512d5d20 Mon Sep 17 00:00:00 2001 From: nscuro Date: Sat, 6 Jul 2024 14:26:42 +0200 Subject: [PATCH] Add autocomplete support for tag inputs Signed-off-by: nscuro --- .../projects/ProjectCreateProjectModal.vue | 21 +++++++++++++++++++ .../projects/ProjectDetailsModal.vue | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/views/portfolio/projects/ProjectCreateProjectModal.vue b/src/views/portfolio/projects/ProjectCreateProjectModal.vue index bc9062ac3..23951c4d5 100644 --- a/src/views/portfolio/projects/ProjectCreateProjectModal.vue +++ b/src/views/portfolio/projects/ProjectCreateProjectModal.vue @@ -88,6 +88,7 @@ :tags="tags" :add-on-key="addOnKeys" :placeholder="$t('message.add_tag')" + :autocomplete-items="tagsAutoCompleteItems" @tags-changed="(newTags) => (this.tags = newTags)" class="mw-100 bg-transparent text-lowercase" /> @@ -244,6 +245,8 @@ export default { project: {}, tag: '', // The contents of a tag as its being typed into the vue-tag-input tags: [], // An array of tags bound to the vue-tag-input + tagsAutoCompleteItems: [], + tagsAutoCompleteDebounce: null, addOnKeys: [9, 13, 32, ':', ';', ','], // Separators used when typing tags into the vue-tag-input labelIcon: { dataOn: '\u2713', @@ -274,6 +277,9 @@ export default { return this.availableClassifiers; }, }, + watch: { + tag: 'searchTags', + }, methods: { syncReadOnlyNameField: function (value) { this.readOnlyProjectName = value; @@ -374,6 +380,21 @@ export default { }); } }, + searchTags: function () { + if (!this.tag) { + return; + } + + clearTimeout(this.tagsAutoCompleteDebounce); + this.tagsAutoCompleteDebounce = setTimeout(() => { + const url = `${this.$api.BASE_URL}/${this.$api.URL_TAG}?searchText=${encodeURIComponent(this.tag)}&pageNumber=1&pageSize=6`; + this.axios.get(url).then((response) => { + this.tagsAutoCompleteItems = response.data.map((tag) => { + return { text: tag.name }; + }); + }); + }, 250); + }, }, }; diff --git a/src/views/portfolio/projects/ProjectDetailsModal.vue b/src/views/portfolio/projects/ProjectDetailsModal.vue index 385cf7917..967c7d8c1 100644 --- a/src/views/portfolio/projects/ProjectDetailsModal.vue +++ b/src/views/portfolio/projects/ProjectDetailsModal.vue @@ -95,6 +95,7 @@ :tags="tags" :add-on-key="addOnKeys" :placeholder="$t('message.add_tag')" + :autocomplete-items="tagsAutoCompleteItems" @tags-changed="(newTags) => (this.tags = newTags)" class="mw-100 bg-transparent text-lowercase" :readonly="this.isNotPermitted(PERMISSIONS.PORTFOLIO_MANAGEMENT)" @@ -500,6 +501,8 @@ export default { availableParents: [], tag: '', // The contents of a tag as its being typed into the vue-tag-input tags: [], // An array of tags bound to the vue-tag-input + tagsAutoCompleteItems: [], + tagsAutoCompleteDebounce: null, addOnKeys: [9, 13, 32, ':', ';', ','], // Separators used when typing tags into the vue-tag-input labelIcon: { dataOn: '\u2713', @@ -648,6 +651,9 @@ export default { this.$root.$emit('bv::show::modal', 'projectDetailsModal'); }); }, + watch: { + tag: 'searchTags', + }, methods: { initializeTags: function () { this.tags = (this.project.tags || []).map((tag) => ({ text: tag.name })); @@ -750,6 +756,21 @@ export default { }); } }, + searchTags: function () { + if (!this.tag) { + return; + } + + clearTimeout(this.tagsAutoCompleteDebounce); + this.tagsAutoCompleteDebounce = setTimeout(() => { + const url = `${this.$api.BASE_URL}/${this.$api.URL_TAG}?searchText=${encodeURIComponent(this.tag)}&pageNumber=1&pageSize=6`; + this.axios.get(url).then((response) => { + this.tagsAutoCompleteItems = response.data.map((tag) => { + return { text: tag.name }; + }); + }); + }, 250); + }, resetValues: function () { this.selectedParent = this.parent; this.availableParents = [{ name: '', version: '', uuid: null }];