diff options
Diffstat (limited to 'app/assets/javascripts/search/sort')
-rw-r--r-- | app/assets/javascripts/search/sort/components/app.vue | 103 | ||||
-rw-r--r-- | app/assets/javascripts/search/sort/constants.js | 19 | ||||
-rw-r--r-- | app/assets/javascripts/search/sort/index.js | 27 |
3 files changed, 149 insertions, 0 deletions
diff --git a/app/assets/javascripts/search/sort/components/app.vue b/app/assets/javascripts/search/sort/components/app.vue new file mode 100644 index 00000000000..e4eba655e39 --- /dev/null +++ b/app/assets/javascripts/search/sort/components/app.vue @@ -0,0 +1,103 @@ +<script> +import { + GlButtonGroup, + GlButton, + GlDropdown, + GlDropdownItem, + GlTooltipDirective, +} from '@gitlab/ui'; +import { mapState, mapActions } from 'vuex'; +import { SORT_DIRECTION_UI } from '../constants'; + +export default { + name: 'GlobalSearchSort', + components: { + GlButtonGroup, + GlButton, + GlDropdown, + GlDropdownItem, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + searchSortOptions: { + type: Array, + required: true, + }, + }, + computed: { + ...mapState(['query']), + selectedSortOption: { + get() { + const { sort } = this.query; + + if (!sort) { + return this.searchSortOptions[0]; + } + + const sortOption = this.searchSortOptions.find((option) => { + if (!option.sortable) { + return option.sortParam === sort; + } + + return Object.values(option.sortParam).indexOf(sort) !== -1; + }); + + // Handle invalid sort param + return sortOption || this.searchSortOptions[0]; + }, + set(value) { + this.setQuery({ key: 'sort', value }); + this.applyQuery(); + }, + }, + sortDirectionData() { + if (!this.selectedSortOption.sortable) { + return SORT_DIRECTION_UI.disabled; + } + + return this.query?.sort?.includes('asc') ? SORT_DIRECTION_UI.asc : SORT_DIRECTION_UI.desc; + }, + }, + methods: { + ...mapActions(['applyQuery', 'setQuery']), + handleSortChange(option) { + if (!option.sortable) { + this.selectedSortOption = option.sortParam; + } else { + // Default new sort options to desc + this.selectedSortOption = option.sortParam.desc; + } + }, + handleSortDirectionChange() { + this.selectedSortOption = + this.sortDirectionData.direction === 'desc' + ? this.selectedSortOption.sortParam.asc + : this.selectedSortOption.sortParam.desc; + }, + }, +}; +</script> + +<template> + <gl-button-group> + <gl-dropdown :text="selectedSortOption.title" :right="true" class="w-100"> + <gl-dropdown-item + v-for="sortOption in searchSortOptions" + :key="sortOption.title" + is-check-item + :is-checked="sortOption.title === selectedSortOption.title" + @click="handleSortChange(sortOption)" + >{{ sortOption.title }}</gl-dropdown-item + > + </gl-dropdown> + <gl-button + v-gl-tooltip + :disabled="!selectedSortOption.sortable" + :title="sortDirectionData.tooltip" + :icon="sortDirectionData.icon" + @click="handleSortDirectionChange" + /> + </gl-button-group> +</template> diff --git a/app/assets/javascripts/search/sort/constants.js b/app/assets/javascripts/search/sort/constants.js new file mode 100644 index 00000000000..575fba5873b --- /dev/null +++ b/app/assets/javascripts/search/sort/constants.js @@ -0,0 +1,19 @@ +import { __ } from '~/locale'; + +export const SORT_DIRECTION_UI = { + disabled: { + direction: null, + tooltip: '', + icon: 'sort-highest', + }, + desc: { + direction: 'desc', + tooltip: __('Sort direction: Descending'), + icon: 'sort-highest', + }, + asc: { + direction: 'asc', + tooltip: __('Sort direction: Ascending'), + icon: 'sort-lowest', + }, +}; diff --git a/app/assets/javascripts/search/sort/index.js b/app/assets/javascripts/search/sort/index.js new file mode 100644 index 00000000000..84bb5175b1d --- /dev/null +++ b/app/assets/javascripts/search/sort/index.js @@ -0,0 +1,27 @@ +import Vue from 'vue'; +import Translate from '~/vue_shared/translate'; +import GlobalSearchSort from './components/app.vue'; + +Vue.use(Translate); + +export const initSearchSort = (store) => { + const el = document.getElementById('js-search-sort'); + + if (!el) return false; + + let { searchSortOptions } = el.dataset; + + searchSortOptions = JSON.parse(searchSortOptions); + + return new Vue({ + el, + store, + render(createElement) { + return createElement(GlobalSearchSort, { + props: { + searchSortOptions, + }, + }); + }, + }); +}; |