diff options
Diffstat (limited to 'app/assets/javascripts/notes/components/discussion_filter.vue')
-rw-r--r-- | app/assets/javascripts/notes/components/discussion_filter.vue | 109 |
1 files changed, 89 insertions, 20 deletions
diff --git a/app/assets/javascripts/notes/components/discussion_filter.vue b/app/assets/javascripts/notes/components/discussion_filter.vue index 15887c2738d..8a42fb6bd85 100644 --- a/app/assets/javascripts/notes/components/discussion_filter.vue +++ b/app/assets/javascripts/notes/components/discussion_filter.vue @@ -2,6 +2,9 @@ import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui'; import { mapGetters, mapActions } from 'vuex'; import { getLocationHash, doesHashExistInUrl } from '~/lib/utils/url_utility'; +import { __ } from '~/locale'; +import Tracking from '~/tracking'; +import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; import { DISCUSSION_FILTERS_DEFAULT_VALUE, HISTORY_ONLY_FILTER_VALUE, @@ -9,15 +12,25 @@ import { DISCUSSION_TAB_LABEL, DISCUSSION_FILTER_TYPES, NOTE_UNDERSCORE, + ASC, + DESC, } from '../constants'; import notesEventHub from '../event_hub'; +const SORT_OPTIONS = [ + { key: DESC, text: __('Newest first'), cls: 'js-newest-first' }, + { key: ASC, text: __('Oldest first'), cls: 'js-oldest-first' }, +]; + export default { + SORT_OPTIONS, components: { GlDropdown, GlDropdownItem, GlDropdownDivider, + LocalStorageSync, }, + mixins: [Tracking.mixin()], props: { filters: { type: Array, @@ -39,11 +52,24 @@ export default { }; }, computed: { - ...mapGetters(['getNotesDataByProp', 'timelineEnabled', 'isLoading']), + ...mapGetters([ + 'getNotesDataByProp', + 'timelineEnabled', + 'isLoading', + 'sortDirection', + 'persistSortOrder', + 'noteableType', + ]), currentFilter() { if (!this.currentValue) return this.filters[0]; return this.filters.find((filter) => filter.value === this.currentValue); }, + selectedSortOption() { + return SORT_OPTIONS.find(({ key }) => this.sortDirection === key); + }, + sortStorageKey() { + return `sort_direction_${this.noteableType.toLowerCase()}`; + }, }, created() { if (window.mrTabs) { @@ -69,6 +95,7 @@ export default { 'setCommentsDisabled', 'setTargetNoteHash', 'setTimelineView', + 'setDiscussionSortDirection', ]), selectFilter(value, persistFilter = true) { const filter = parseInt(value, 10); @@ -108,31 +135,73 @@ export default { } return DISCUSSION_FILTER_TYPES.HISTORY; }, + fetchSortedDiscussions(direction) { + if (this.isSortDropdownItemActive(direction)) { + return; + } + + this.setDiscussionSortDirection({ direction }); + this.track('change_discussion_sort_direction', { property: direction }); + }, + isSortDropdownItemActive(sortDir) { + return sortDir === this.sortDirection; + }, }, }; </script> <template> - <gl-dropdown + <div v-if="displayFilters" - id="discussion-filter-dropdown" - class="full-width-mobile discussion-filter-container js-discussion-filter-container" - data-qa-selector="discussion_filter_dropdown" - :text="currentFilter.title" - :disabled="isLoading" + id="discussion-preferences" + data-testid="discussion-preferences" + class="gl-display-inline-block gl-vertical-align-bottom full-width-mobile" > - <div v-for="filter in filters" :key="filter.value" class="dropdown-item-wrapper"> - <gl-dropdown-item - :is-check-item="true" - :is-checked="filter.value === currentValue" - :class="{ 'is-active': filter.value === currentValue }" - :data-filter-type="filterType(filter.value)" - data-qa-selector="filter_menu_item" - @click.prevent="selectFilter(filter.value)" + <local-storage-sync + :value="sortDirection" + :storage-key="sortStorageKey" + :persist="persistSortOrder" + as-string + @input="setDiscussionSortDirection({ direction: $event })" + /> + <gl-dropdown + id="discussion-preferences-dropdown" + class="full-width-mobile" + data-qa-selector="discussion_preferences_dropdown" + text="Sort or filter" + :disabled="isLoading" + right + > + <div id="discussion-sort"> + <gl-dropdown-item + v-for="{ text, key, cls } in $options.SORT_OPTIONS" + :key="text" + :class="cls" + is-check-item + :is-checked="isSortDropdownItemActive(key)" + @click="fetchSortedDiscussions(key)" + > + {{ text }} + </gl-dropdown-item> + </div> + <gl-dropdown-divider /> + <div + id="discussion-filter" + class="discussion-filter-container js-discussion-filter-container" > - {{ filter.title }} - </gl-dropdown-item> - <gl-dropdown-divider v-if="filter.value === defaultValue" /> - </div> - </gl-dropdown> + <gl-dropdown-item + v-for="filter in filters" + :key="filter.value" + is-check-item + :is-checked="filter.value === currentValue" + :class="{ 'is-active': filter.value === currentValue }" + :data-filter-type="filterType(filter.value)" + data-qa-selector="filter_menu_item" + @click.prevent="selectFilter(filter.value)" + > + {{ filter.title }} + </gl-dropdown-item> + </div> + </gl-dropdown> + </div> </template> |