Commit 92dc2846 authored by David O'Regan's avatar David O'Regan Committed by Natalia Tepluhina

Add sorting for incidents

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