Commit 721267a5 authored by Mark Florian's avatar Mark Florian

Replace custom sorting with GlSorting component

A snapshot test was removed, since it provided almost no value.

Using GlSorting has changed the styling slightly, although not in
a harmful way: the width of the dropdown is fixed, instead of scaling
with the amount of text in the selected item.

The GlSorting component may not be fully Pajamas-compliant, and fixing
that may bring this UI back to nearly how it looked previously.

Addresses part of https://gitlab.com/gitlab-org/gitlab/-/issues/335066.
parent 2bc06dec
<script> <script>
import { GlButton, GlDropdown, GlDropdownItem, GlIcon, GlTooltipDirective } from '@gitlab/ui'; import { GlButton, GlSorting, GlSortingItem, GlTooltipDirective } from '@gitlab/ui';
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { DEPENDENCY_LIST_TYPES } from '../store/constants'; import { DEPENDENCY_LIST_TYPES } from '../store/constants';
...@@ -13,9 +13,8 @@ export default { ...@@ -13,9 +13,8 @@ export default {
name: 'DependenciesActions', name: 'DependenciesActions',
components: { components: {
GlButton, GlButton,
GlDropdown, GlSorting,
GlDropdownItem, GlSortingItem,
GlIcon,
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
...@@ -29,6 +28,9 @@ export default { ...@@ -29,6 +28,9 @@ export default {
}, },
}, },
computed: { computed: {
isSortAscending() {
return this.sortOrder === SORT_ASCENDING;
},
...mapState({ ...mapState({
sortField(state) { sortField(state) {
return state[this.namespace].sortField; return state[this.namespace].sortField;
...@@ -43,9 +45,6 @@ export default { ...@@ -43,9 +45,6 @@ export default {
sortFieldName() { sortFieldName() {
return this.$options.i18n.sortFields[this.sortField]; return this.$options.i18n.sortFields[this.sortField];
}, },
sortOrderIcon() {
return this.sortOrder === SORT_ASCENDING ? 'sort-lowest' : 'sort-highest';
},
}, },
methods: { methods: {
...mapActions({ ...mapActions({
...@@ -56,49 +55,41 @@ export default { ...@@ -56,49 +55,41 @@ export default {
dispatch(`${this.namespace}/toggleSortOrder`); dispatch(`${this.namespace}/toggleSortOrder`);
}, },
}), }),
isCurrentSortField(id) { isCurrentSortField(field) {
return id === this.sortField; return field === this.sortField;
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="btn-toolbar"> <div class="gl-display-flex">
<div class="btn-group flex-grow-1 mr-2"> <gl-sorting
<gl-dropdown :text="sortFieldName" class="flex-grow-1 text-center" right> :text="sortFieldName"
<gl-dropdown-item :is-ascending="isSortAscending"
v-for="(name, id) in $options.i18n.sortFields" :sort-direction-tool-tip="$options.i18n.sortDirectionLabel"
:key="id" class="gl-flex-grow-1"
@click="setSortField(id)" dropdown-class="gl-flex-grow-1"
> sort-direction-toggle-class="gl-flex-grow-0!"
<span class="d-flex"> @sortDirectionChange="toggleSortOrder"
<gl-icon >
class="flex-shrink-0 gl-mr-2" <gl-sorting-item
:class="{ invisible: !isCurrentSortField(id) }" v-for="(name, field) in $options.i18n.sortFields"
name="mobile-issue-close" :key="field"
/> :active="isCurrentSortField(field)"
{{ name }} @click="setSortField(field)"
</span>
</gl-dropdown-item>
</gl-dropdown>
<gl-button
v-gl-tooltip
:title="$options.i18n.sortDirectionLabel"
:aria-label="$options.i18n.sortDirectionLabel"
class="flex-grow-0 js-sort-order"
@click="toggleSortOrder"
> >
<gl-icon :name="sortOrderIcon" /> {{ name }}
</gl-button> </gl-sorting-item>
</div> </gl-sorting>
<gl-button <gl-button
v-gl-tooltip v-gl-tooltip
:href="downloadEndpoint" :href="downloadEndpoint"
download="dependencies.json" download="dependencies.json"
:title="s__('Dependencies|Export as JSON')" :title="s__('Dependencies|Export as JSON')"
class="js-download" class="gl-ml-3"
icon="export" icon="export"
data-testid="export"
> >
{{ __('Export') }} {{ __('Export') }}
</gl-button> </gl-button>
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`DependenciesActions component matches the snapshot 1`] = `
<div
class="btn-toolbar"
>
<div
class="btn-group flex-grow-1 mr-2"
>
<gl-dropdown-stub
category="primary"
class="flex-grow-1 text-center"
headertext=""
hideheaderborder="true"
right="true"
size="medium"
text="Severity"
variant="default"
>
<gl-dropdown-item-stub
avatarurl=""
iconcolor=""
iconname=""
iconrightarialabel=""
iconrightname=""
secondarytext=""
>
<span
class="d-flex"
>
<gl-icon-stub
class="flex-shrink-0 gl-mr-2 invisible"
name="mobile-issue-close"
size="16"
/>
Component name
</span>
</gl-dropdown-item-stub>
<gl-dropdown-item-stub
avatarurl=""
iconcolor=""
iconname=""
iconrightarialabel=""
iconrightname=""
secondarytext=""
>
<span
class="d-flex"
>
<gl-icon-stub
class="flex-shrink-0 gl-mr-2 invisible"
name="mobile-issue-close"
size="16"
/>
Packager
</span>
</gl-dropdown-item-stub>
<gl-dropdown-item-stub
avatarurl=""
iconcolor=""
iconname=""
iconrightarialabel=""
iconrightname=""
secondarytext=""
>
<span
class="d-flex"
>
<gl-icon-stub
class="flex-shrink-0 gl-mr-2"
name="mobile-issue-close"
size="16"
/>
Severity
</span>
</gl-dropdown-item-stub>
</gl-dropdown-stub>
<gl-button-stub
aria-label="Sort direction"
buttontextclasses=""
category="primary"
class="flex-grow-0 js-sort-order"
icon=""
size="medium"
title="Sort direction"
variant="default"
>
<gl-icon-stub
name="sort-highest"
size="16"
/>
</gl-button-stub>
</div>
<gl-button-stub
buttontextclasses=""
category="primary"
class="js-download"
download="dependencies.json"
href="http://test.host/dependencies.json"
icon="export"
size="medium"
title="Export as JSON"
variant="default"
>
Export
</gl-button-stub>
</div>
`;
import { GlDropdownItem } from '@gitlab/ui'; import { GlSorting, GlSortingItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import DependenciesActions from 'ee/dependencies/components/dependencies_actions.vue'; import DependenciesActions from 'ee/dependencies/components/dependencies_actions.vue';
import createStore from 'ee/dependencies/store'; import createStore from 'ee/dependencies/store';
import { DEPENDENCY_LIST_TYPES } from 'ee/dependencies/store/constants'; import { DEPENDENCY_LIST_TYPES } from 'ee/dependencies/store/constants';
import { SORT_FIELDS } from 'ee/dependencies/store/modules/list/constants'; import { SORT_FIELDS } from 'ee/dependencies/store/modules/list/constants';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
describe('DependenciesActions component', () => { describe('DependenciesActions component', () => {
let store; let store;
...@@ -15,13 +15,19 @@ describe('DependenciesActions component', () => { ...@@ -15,13 +15,19 @@ describe('DependenciesActions component', () => {
store = createStore(); store = createStore();
jest.spyOn(store, 'dispatch').mockImplementation(); jest.spyOn(store, 'dispatch').mockImplementation();
wrapper = shallowMount(DependenciesActions, { wrapper = shallowMountExtended(DependenciesActions, {
...options, ...options,
store, store,
propsData: { ...propsData }, propsData: { ...propsData },
stubs: {
GlSortingItem,
},
}); });
}; };
const findExportButton = () => wrapper.findByTestId('export');
const findSorting = () => wrapper.findComponent(GlSorting);
beforeEach(() => { beforeEach(() => {
factory({ factory({
propsData: { namespace }, propsData: { namespace },
...@@ -34,14 +40,10 @@ describe('DependenciesActions component', () => { ...@@ -34,14 +40,10 @@ describe('DependenciesActions component', () => {
wrapper.destroy(); wrapper.destroy();
}); });
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('dispatches the right setSortField action on clicking each item in the dropdown', () => { it('dispatches the right setSortField action on clicking each item in the dropdown', () => {
const dropdownItems = wrapper.findAll(GlDropdownItem).wrappers; const sortingItems = wrapper.findAllComponents(GlSortingItem).wrappers;
dropdownItems.forEach((item) => { sortingItems.forEach((item) => {
// trigger() does not work on stubbed/shallow mounted components // trigger() does not work on stubbed/shallow mounted components
// https://github.com/vuejs/vue-test-utils/issues/919 // https://github.com/vuejs/vue-test-utils/issues/919
item.vm.$emit('click'); item.vm.$emit('click');
...@@ -55,14 +57,12 @@ describe('DependenciesActions component', () => { ...@@ -55,14 +57,12 @@ describe('DependenciesActions component', () => {
}); });
it('dispatches the toggleSortOrder action on clicking the sort order button', () => { it('dispatches the toggleSortOrder action on clicking the sort order button', () => {
const sortButton = wrapper.find('.js-sort-order'); findSorting().vm.$emit('sortDirectionChange');
sortButton.vm.$emit('click');
expect(store.dispatch).toHaveBeenCalledWith(`${namespace}/toggleSortOrder`); expect(store.dispatch).toHaveBeenCalledWith(`${namespace}/toggleSortOrder`);
}); });
it('has a button to export the dependency list', () => { it('has a button to export the dependency list', () => {
const download = wrapper.find('.js-download'); expect(findExportButton().attributes()).toEqual(
expect(download.attributes()).toEqual(
expect.objectContaining({ expect.objectContaining({
href: store.getters[`${namespace}/downloadEndpoint`], href: store.getters[`${namespace}/downloadEndpoint`],
download: expect.any(String), download: expect.any(String),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment