Commit c0d09dd9 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '229534-column-sort' into 'master'

Add sorting for incidents

See merge request gitlab-org/gitlab!38178
parents 688830b8 92dc2846
......@@ -332,7 +332,10 @@ export default {
<p v-html="errorMessage || $options.i18n.errorMsg"></p>
</gl-alert>
<gl-tabs content-class="gl-p-0" @input="filterAlertsByStatus">
<gl-tabs
content-class="gl-p-0 gl-border-b-solid gl-border-b-1 gl-border-gray-100"
@input="filterAlertsByStatus"
>
<gl-tab v-for="tab in $options.statusTabs" :key="tab.status">
<template slot="title">
<span>{{ tab.title }}</span>
......
......@@ -14,13 +14,15 @@ import {
GlTabs,
GlTab,
} from '@gitlab/ui';
import { debounce, trim } from 'lodash';
import { debounce } from 'lodash';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { convertToSnakeCase } from '~/lib/utils/text_utility';
import { s__ } from '~/locale';
import { mergeUrlParams, joinPaths, visitUrl } from '~/lib/utils/url_utility';
import getIncidents from '../graphql/queries/get_incidents.query.graphql';
import { I18N, DEFAULT_PAGE_SIZE, INCIDENT_SEARCH_DELAY, INCIDENT_STATE_TABS } from '../constants';
const TH_TEST_ID = { 'data-testid': 'incident-management-created-at-sort' };
const tdClass =
'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap';
const thClass = 'gl-hover-bg-blue-50';
......@@ -48,8 +50,10 @@ export default {
{
key: 'createdAt',
label: s__('IncidentManagement|Date created'),
thClass: `${thClass} gl-pointer-events-none`,
tdClass,
thClass,
tdClass: `${tdClass} sortable-cell`,
sortable: true,
thAttr: TH_TEST_ID,
},
{
key: 'assignees',
......@@ -93,6 +97,7 @@ export default {
state: this.stateFilter,
projectPath: this.projectPath,
issueTypes: ['INCIDENT'],
sort: this.sort,
firstPageSize: this.pagination.firstPageSize,
lastPageSize: this.pagination.lastPageSize,
prevPageCursor: this.pagination.prevPageCursor,
......@@ -119,6 +124,9 @@ export default {
pagination: initialPaginationState,
incidents: {},
stateFilter: '',
sort: 'created_desc',
sortBy: 'createdAt',
sortDesc: true,
};
},
computed: {
......@@ -168,7 +176,7 @@ export default {
},
methods: {
onInputChange: debounce(function debounceSearch(input) {
const trimmedInput = trim(input);
const trimmedInput = input.trim();
if (trimmedInput !== this.searchTerm) {
this.searchTerm = trimmedInput;
}
......@@ -205,6 +213,12 @@ export default {
resetPagination() {
this.pagination = initialPaginationState;
},
fetchSortedData({ sortBy, sortDesc }) {
const sortingDirection = sortDesc ? 'desc' : 'asc';
const sortingColumn = convertToSnakeCase(sortBy).replace(/_.*/, '');
this.sort = `${sortingColumn}_${sortingDirection}`;
},
},
};
</script>
......@@ -214,7 +228,9 @@ export default {
{{ $options.i18n.errorMsg }}
</gl-alert>
<div class="incident-management-list-header gl-display-flex gl-justify-content-space-between">
<div
class="incident-management-list-header gl-display-flex gl-justify-content-space-between gl-border-b-solid gl-border-b-1 gl-border-gray-100"
>
<gl-tabs content-class="gl-p-0" @input="filterIncidentsByState">
<gl-tab v-for="tab in $options.stateTabs" :key="tab.state" :data-testid="tab.state">
<template #title>
......@@ -224,7 +240,7 @@ export default {
</gl-tabs>
<gl-button
class="gl-my-3 create-incident-button"
class="gl-my-3 gl-mr-5 create-incident-button"
data-testid="createIncidentBtn"
:loading="redirecting"
:disabled="redirecting"
......@@ -257,16 +273,22 @@ export default {
stacked="md"
:tbody-tr-class="tbodyTrClass"
:no-local-sorting="true"
:sort-direction="'desc'"
:sort-desc.sync="sortDesc"
:sort-by.sync="sortBy"
sort-icon-left
fixed
@row-clicked="navigateToIncidentDetails"
@sort-changed="fetchSortedData"
>
<template #cell(title)="{ item }">
<div class="gl-display-sm-flex gl-align-items-center">
<div class="incident-management-list-title gl-display-flex gl-align-items-center">
<div class="gl-max-w-full text-truncate" :title="item.title">{{ item.title }}</div>
<gl-icon
v-if="item.state === 'closed'"
name="issue-close"
class="gl-ml-1 gl-fill-blue-500"
class="gl-mx-1 gl-fill-blue-500"
:size="16"
data-testid="incident-closed"
/>
</div>
......
......@@ -6,7 +6,7 @@ export const I18N = {
unassigned: s__('IncidentManagement|Unassigned'),
createIncidentBtnLabel: s__('IncidentManagement|Create incident'),
unPublished: s__('IncidentManagement|Unpublished'),
searchPlaceholder: __('Search results...'),
searchPlaceholder: __('Search results'),
};
export const INCIDENT_STATE_TABS = [
......@@ -21,7 +21,7 @@ export const INCIDENT_STATE_TABS = [
filters: 'closed',
},
{
title: s__('IncidentManagement|All incidents'),
title: s__('IncidentManagement|All'),
state: 'ALL',
filters: 'all',
},
......
query getIncidents(
$projectPath: ID!
$issueTypes: [IssueType!]
$sort: IssueSort
$state: IssuableState
$firstPageSize: Int
$lastPageSize: Int
......@@ -13,6 +14,7 @@ query getIncidents(
search: $searchTerm
state: $state
types: $issueTypes
sort: $sort
first: $firstPageSize
last: $lastPageSize
after: $nextPageCursor
......
......@@ -76,23 +76,31 @@
}
}
}
.incident-management-list-title {
@include gl-flex-direction-row-reverse;
}
}
}
.gl-tab-nav-item {
color: $gl-gray-600;
.gl-tabs-nav {
border-bottom-width: 0;
.gl-tab-nav-item {
color: $gl-gray-600;
> .gl-tab-counter-badge {
color: inherit;
@include gl-font-sm;
background-color: $white-normal;
> .gl-tab-counter-badge {
color: inherit;
@include gl-font-sm;
background-color: $gray-50;
}
}
}
@include media-breakpoint-down(xs) {
.incident-management-list-header {
flex-direction: column-reverse;
};
}
.create-incident-button {
@include gl-w-full;
......
---
title: Add sorting by date for incident list
merge_request: 38178
author:
type: changed
......@@ -12811,7 +12811,7 @@ msgstr ""
msgid "Incident Management Limits"
msgstr ""
msgid "IncidentManagement|All incidents"
msgid "IncidentManagement|All"
msgstr ""
msgid "IncidentManagement|Assignees"
......@@ -21108,7 +21108,7 @@ msgstr ""
msgid "Search requirements"
msgstr ""
msgid "Search results..."
msgid "Search results"
msgstr ""
msgid "Search users"
......
......@@ -30,9 +30,11 @@ describe('Incidents List', () => {
const findAlert = () => wrapper.find(GlAlert);
const findLoader = () => wrapper.find(GlLoadingIcon);
const findTimeAgo = () => wrapper.findAll(TimeAgoTooltip);
const findDateColumnHeader = () =>
wrapper.find('[data-testid="incident-management-created-at-sort"]');
const findSearch = () => wrapper.find(GlSearchBoxByType);
const findAssingees = () => wrapper.findAll('[data-testid="incident-assignees"]');
const findCreateIncidentBtn = () => wrapper.find('[data-testid="createIncidentBtn"]');
const findSearch = () => wrapper.find(GlSearchBoxByType);
const findClosedIcon = () => wrapper.findAll("[data-testid='incident-closed']");
const findPagination = () => wrapper.find(GlPagination);
const findStatusFilterTabs = () => wrapper.findAll(GlTab);
......@@ -304,4 +306,22 @@ describe('Incidents List', () => {
});
});
});
describe('sorting the incident list by column', () => {
beforeEach(() => {
mountComponent({
data: { incidents: mockIncidents },
loading: false,
});
});
it('updates sort with new direction and column key', () => {
expect(findDateColumnHeader().attributes('aria-sort')).toBe('descending');
findDateColumnHeader().trigger('click');
return wrapper.vm.$nextTick(() => {
expect(findDateColumnHeader().attributes('aria-sort')).toBe('ascending');
});
});
});
});
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