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>
import { GlButton, GlDropdown, GlDropdownItem, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { GlButton, GlSorting, GlSortingItem, GlTooltipDirective } from '@gitlab/ui';
import { mapActions, mapState } from 'vuex';
import { __ } from '~/locale';
import { DEPENDENCY_LIST_TYPES } from '../store/constants';
......@@ -13,9 +13,8 @@ export default {
name: 'DependenciesActions',
components: {
GlButton,
GlDropdown,
GlDropdownItem,
GlIcon,
GlSorting,
GlSortingItem,
},
directives: {
GlTooltip: GlTooltipDirective,
......@@ -29,6 +28,9 @@ export default {
},
},
computed: {
isSortAscending() {
return this.sortOrder === SORT_ASCENDING;
},
...mapState({
sortField(state) {
return state[this.namespace].sortField;
......@@ -43,9 +45,6 @@ export default {
sortFieldName() {
return this.$options.i18n.sortFields[this.sortField];
},
sortOrderIcon() {
return this.sortOrder === SORT_ASCENDING ? 'sort-lowest' : 'sort-highest';
},
},
methods: {
...mapActions({
......@@ -56,49 +55,41 @@ export default {
dispatch(`${this.namespace}/toggleSortOrder`);
},
}),
isCurrentSortField(id) {
return id === this.sortField;
isCurrentSortField(field) {
return field === this.sortField;
},
},
};
</script>
<template>
<div class="btn-toolbar">
<div class="btn-group flex-grow-1 mr-2">
<gl-dropdown :text="sortFieldName" class="flex-grow-1 text-center" right>
<gl-dropdown-item
v-for="(name, id) in $options.i18n.sortFields"
:key="id"
@click="setSortField(id)"
<div class="gl-display-flex">
<gl-sorting
:text="sortFieldName"
:is-ascending="isSortAscending"
:sort-direction-tool-tip="$options.i18n.sortDirectionLabel"
class="gl-flex-grow-1"
dropdown-class="gl-flex-grow-1"
sort-direction-toggle-class="gl-flex-grow-0!"
@sortDirectionChange="toggleSortOrder"
>
<span class="d-flex">
<gl-icon
class="flex-shrink-0 gl-mr-2"
:class="{ invisible: !isCurrentSortField(id) }"
name="mobile-issue-close"
/>
{{ name }}
</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-sorting-item
v-for="(name, field) in $options.i18n.sortFields"
:key="field"
:active="isCurrentSortField(field)"
@click="setSortField(field)"
>
<gl-icon :name="sortOrderIcon" />
</gl-button>
</div>
{{ name }}
</gl-sorting-item>
</gl-sorting>
<gl-button
v-gl-tooltip
:href="downloadEndpoint"
download="dependencies.json"
:title="s__('Dependencies|Export as JSON')"
class="js-download"
class="gl-ml-3"
icon="export"
data-testid="export"
>
{{ __('Export') }}
</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 { shallowMount } from '@vue/test-utils';
import { GlSorting, GlSortingItem } from '@gitlab/ui';
import DependenciesActions from 'ee/dependencies/components/dependencies_actions.vue';
import createStore from 'ee/dependencies/store';
import { DEPENDENCY_LIST_TYPES } from 'ee/dependencies/store/constants';
import { SORT_FIELDS } from 'ee/dependencies/store/modules/list/constants';
import { TEST_HOST } from 'helpers/test_constants';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
describe('DependenciesActions component', () => {
let store;
......@@ -15,13 +15,19 @@ describe('DependenciesActions component', () => {
store = createStore();
jest.spyOn(store, 'dispatch').mockImplementation();
wrapper = shallowMount(DependenciesActions, {
wrapper = shallowMountExtended(DependenciesActions, {
...options,
store,
propsData: { ...propsData },
stubs: {
GlSortingItem,
},
});
};
const findExportButton = () => wrapper.findByTestId('export');
const findSorting = () => wrapper.findComponent(GlSorting);
beforeEach(() => {
factory({
propsData: { namespace },
......@@ -34,14 +40,10 @@ describe('DependenciesActions component', () => {
wrapper.destroy();
});
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
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
// https://github.com/vuejs/vue-test-utils/issues/919
item.vm.$emit('click');
......@@ -55,14 +57,12 @@ describe('DependenciesActions component', () => {
});
it('dispatches the toggleSortOrder action on clicking the sort order button', () => {
const sortButton = wrapper.find('.js-sort-order');
sortButton.vm.$emit('click');
findSorting().vm.$emit('sortDirectionChange');
expect(store.dispatch).toHaveBeenCalledWith(`${namespace}/toggleSortOrder`);
});
it('has a button to export the dependency list', () => {
const download = wrapper.find('.js-download');
expect(download.attributes()).toEqual(
expect(findExportButton().attributes()).toEqual(
expect.objectContaining({
href: store.getters[`${namespace}/downloadEndpoint`],
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