diff options
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue')
-rw-r--r-- | app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue | 65 |
1 files changed, 41 insertions, 24 deletions
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue index a858ffdbed5..04090213218 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue @@ -83,6 +83,7 @@ export default { return { initialRender: true, recentSearchesPromise: null, + recentSearches: [], filterValue: this.initialFilterValue, selectedSortOption, selectedSortDirection, @@ -98,6 +99,15 @@ export default { {}, ); }, + tokenTitles() { + return this.tokens.reduce( + (tokenSymbols, token) => ({ + ...tokenSymbols, + [token.type]: token.title, + }), + {}, + ); + }, sortDirectionIcon() { return this.selectedSortDirection === SortDirection.ascending ? 'sort-lowest' @@ -112,11 +122,10 @@ export default { watch: { /** * GlFilteredSearch currently doesn't emit any event when - * search field is cleared, but we still want our parent - * component to know that filters were cleared and do - * necessary data refetch, so this watcher is basically - * a dirty hack/workaround to identify if filter input - * was cleared. :( + * tokens are manually removed from search field so we'd + * never know when user actually clears all the tokens. + * This watcher listens for updates to `filterValue` on + * such instances. :( */ filterValue(value) { const [firstVal] = value; @@ -172,11 +181,9 @@ export default { this.recentSearchesStore.state.recentSearches.concat(searches), ); this.recentSearchesService.save(resultantSearches); + this.recentSearches = resultantSearches; }); }, - getRecentSearches() { - return this.recentSearchesStore?.state.recentSearches; - }, handleSortOptionClick(sortBy) { this.selectedSortOption = sortBy; this.$emit('onSort', sortBy.sortDirection[this.selectedSortDirection]); @@ -188,26 +195,22 @@ export default { : SortDirection.ascending; this.$emit('onSort', this.selectedSortOption.sortDirection[this.selectedSortDirection]); }, + handleHistoryItemSelected(filters) { + this.$emit('onFilter', filters); + }, + handleClearHistory() { + const resultantSearches = this.recentSearchesStore.setRecentSearches([]); + this.recentSearchesService.save(resultantSearches); + this.recentSearches = []; + }, handleFilterSubmit(filters) { if (this.recentSearchesStorageKey) { this.recentSearchesPromise .then(() => { if (filters.length) { - const searchTokens = filters.map(filter => { - // check filter was plain text search - if (typeof filter === 'string') { - return filter; - } - // filter was a token. - return `${filter.type}:${filter.value.operator}${this.tokenSymbols[filter.type]}${ - filter.value.data - }`; - }); - - const resultantSearches = this.recentSearchesStore.addRecentSearch( - searchTokens.join(' '), - ); + const resultantSearches = this.recentSearchesStore.addRecentSearch(filters); this.recentSearchesService.save(resultantSearches); + this.recentSearches = resultantSearches; } }) .catch(() => { @@ -226,10 +229,24 @@ export default { v-model="filterValue" :placeholder="searchInputPlaceholder" :available-tokens="tokens" - :history-items="getRecentSearches()" + :history-items="recentSearches" class="flex-grow-1" + @history-item-selected="handleHistoryItemSelected" + @clear-history="handleClearHistory" @submit="handleFilterSubmit" - /> + > + <template #history-item="{ historyItem }"> + <template v-for="(token, index) in historyItem"> + <span v-if="typeof token === 'string'" :key="index" class="gl-px-1">"{{ token }}"</span> + <span v-else :key="`${token.type}-${token.value.data}`" class="gl-px-1"> + <span v-if="tokenTitles[token.type]" + >{{ tokenTitles[token.type] }} :{{ token.value.operator }}</span + > + <strong>{{ tokenSymbols[token.type] }}{{ token.value.data }}</strong> + </span> + </template> + </template> + </gl-filtered-search> <gl-button-group class="sort-dropdown-container d-flex"> <gl-dropdown :text="selectedSortOption.title" :right="true" class="w-100"> <gl-dropdown-item |