Commit 957906d2 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '213881-alerts-list-pagination' into 'master'

Alerts list pagination

See merge request gitlab-org/gitlab!33073
parents d9f8f1d2 56d8064a
...@@ -11,6 +11,7 @@ import { ...@@ -11,6 +11,7 @@ import {
GlTabs, GlTabs,
GlTab, GlTab,
GlBadge, GlBadge,
GlPagination,
} from '@gitlab/ui'; } from '@gitlab/ui';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
...@@ -22,6 +23,7 @@ import getAlertsCountByStatus from '../graphql/queries/get_count_by_status.query ...@@ -22,6 +23,7 @@ import getAlertsCountByStatus from '../graphql/queries/get_count_by_status.query
import { import {
ALERTS_STATUS_TABS, ALERTS_STATUS_TABS,
ALERTS_SEVERITY_LABELS, ALERTS_SEVERITY_LABELS,
DEFAULT_PAGE_SIZE,
trackAlertListViewsOptions, trackAlertListViewsOptions,
trackAlertStatusUpdateOptions, trackAlertStatusUpdateOptions,
} from '../constants'; } from '../constants';
...@@ -34,6 +36,14 @@ const bodyTrClass = ...@@ -34,6 +36,14 @@ const bodyTrClass =
'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-bg-blue-50 gl-hover-cursor-pointer gl-hover-border-b-solid gl-hover-border-blue-200'; 'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-bg-blue-50 gl-hover-cursor-pointer gl-hover-border-b-solid gl-hover-border-blue-200';
const findDefaultSortColumn = () => document.querySelector('.js-started-at'); const findDefaultSortColumn = () => document.querySelector('.js-started-at');
const initialPaginationState = {
currentPage: 1,
prevPageCursor: '',
nextPageCursor: '',
firstPageSize: DEFAULT_PAGE_SIZE,
lastPageSize: null,
};
export default { export default {
i18n: { i18n: {
noAlertsMsg: s__( noAlertsMsg: s__(
...@@ -110,6 +120,7 @@ export default { ...@@ -110,6 +120,7 @@ export default {
GlTabs, GlTabs,
GlTab, GlTab,
GlBadge, GlBadge,
GlPagination,
}, },
props: { props: {
projectPath: { projectPath: {
...@@ -142,10 +153,20 @@ export default { ...@@ -142,10 +153,20 @@ export default {
projectPath: this.projectPath, projectPath: this.projectPath,
statuses: this.statusFilter, statuses: this.statusFilter,
sort: this.sort, sort: this.sort,
firstPageSize: this.pagination.firstPageSize,
lastPageSize: this.pagination.lastPageSize,
prevPageCursor: this.pagination.prevPageCursor,
nextPageCursor: this.pagination.nextPageCursor,
}; };
}, },
update(data) { update(data) {
return data.project?.alertManagementAlerts?.nodes; const { alertManagementAlerts: { nodes: list = [], pageInfo = {} } = {} } =
data.project || {};
return {
list,
pageInfo,
};
}, },
error() { error() {
this.errored = true; this.errored = true;
...@@ -169,7 +190,9 @@ export default { ...@@ -169,7 +190,9 @@ export default {
isAlertDismissed: false, isAlertDismissed: false,
isErrorAlertDismissed: false, isErrorAlertDismissed: false,
sort: 'STARTED_AT_ASC', sort: 'STARTED_AT_ASC',
statusFilter: this.$options.statusTabs[4].filters, statusFilter: [],
filteredByStatus: '',
pagination: initialPaginationState,
}; };
}, },
computed: { computed: {
...@@ -185,19 +208,34 @@ export default { ...@@ -185,19 +208,34 @@ export default {
return this.$apollo.queries.alerts.loading; return this.$apollo.queries.alerts.loading;
}, },
hasAlerts() { hasAlerts() {
return this.alerts?.length; return this.alerts?.list?.length;
}, },
tbodyTrClass() { tbodyTrClass() {
return !this.loading && this.hasAlerts ? bodyTrClass : ''; return !this.loading && this.hasAlerts ? bodyTrClass : '';
}, },
showPaginationControls() {
return Boolean(this.prevPage || this.nextPage);
},
alertsForCurrentTab() {
return this.alertsCount ? this.alertsCount[this.filteredByStatus.toLowerCase()] : 0;
},
prevPage() {
return Math.max(this.pagination.currentPage - 1, 0);
},
nextPage() {
const nextPage = this.pagination.currentPage + 1;
return nextPage > Math.ceil(this.alertsForCurrentTab / DEFAULT_PAGE_SIZE) ? null : nextPage;
},
}, },
mounted() { mounted() {
findDefaultSortColumn().ariaSort = 'ascending';
this.trackPageViews(); this.trackPageViews();
}, },
methods: { methods: {
filterAlertsByStatus(tabIndex) { filterAlertsByStatus(tabIndex) {
this.statusFilter = this.$options.statusTabs[tabIndex].filters; this.resetPagination();
const { filters, status } = this.$options.statusTabs[tabIndex];
this.statusFilter = filters;
this.filteredByStatus = status;
}, },
fetchSortedData({ sortBy, sortDesc }) { fetchSortedData({ sortBy, sortDesc }) {
const sortDirection = sortDesc ? 'DESC' : 'ASC'; const sortDirection = sortDesc ? 'DESC' : 'ASC';
...@@ -206,6 +244,7 @@ export default { ...@@ -206,6 +244,7 @@ export default {
if (sortBy !== 'startedAt') { if (sortBy !== 'startedAt') {
findDefaultSortColumn().ariaSort = 'none'; findDefaultSortColumn().ariaSort = 'none';
} }
this.resetPagination();
this.sort = `${sortColumn}_${sortDirection}`; this.sort = `${sortColumn}_${sortDirection}`;
}, },
updateAlertStatus(status, iid) { updateAlertStatus(status, iid) {
...@@ -222,6 +261,7 @@ export default { ...@@ -222,6 +261,7 @@ export default {
this.trackStatusUpdate(status); this.trackStatusUpdate(status);
this.$apollo.queries.alerts.refetch(); this.$apollo.queries.alerts.refetch();
this.$apollo.queries.alertsCount.refetch(); this.$apollo.queries.alertsCount.refetch();
this.resetPagination();
}) })
.catch(() => { .catch(() => {
createFlash( createFlash(
...@@ -246,6 +286,28 @@ export default { ...@@ -246,6 +286,28 @@ export default {
// TODO: Update to show list of assignee(s) after https://gitlab.com/gitlab-org/gitlab/-/issues/218405 // TODO: Update to show list of assignee(s) after https://gitlab.com/gitlab-org/gitlab/-/issues/218405
return assignees?.length > 0 ? assignees[0]?.username : s__('AlertManagement|Unassigned'); return assignees?.length > 0 ? assignees[0]?.username : s__('AlertManagement|Unassigned');
}, },
handlePageChange(page) {
const { startCursor, endCursor } = this.alerts.pageInfo;
if (page > this.pagination.currentPage) {
this.pagination = {
...initialPaginationState,
nextPageCursor: endCursor,
currentPage: page,
};
} else {
this.pagination = {
lastPageSize: DEFAULT_PAGE_SIZE,
firstPageSize: null,
prevPageCursor: startCursor,
nextPageCursor: '',
currentPage: page,
};
}
},
resetPagination() {
this.pagination = initialPaginationState;
},
}, },
}; };
</script> </script>
...@@ -275,7 +337,7 @@ export default { ...@@ -275,7 +337,7 @@ export default {
</h4> </h4>
<gl-table <gl-table
class="alert-management-table mt-3" class="alert-management-table mt-3"
:items="alerts" :items="alerts ? alerts.list : []"
:fields="$options.fields" :fields="$options.fields"
:show-empty="true" :show-empty="true"
:busy="loading" :busy="loading"
...@@ -283,6 +345,7 @@ export default { ...@@ -283,6 +345,7 @@ export default {
:tbody-tr-class="tbodyTrClass" :tbody-tr-class="tbodyTrClass"
:no-local-sorting="true" :no-local-sorting="true"
sort-icon-left sort-icon-left
sort-by="startedAt"
@row-clicked="navigateToAlertDetails" @row-clicked="navigateToAlertDetails"
@sort-changed="fetchSortedData" @sort-changed="fetchSortedData"
> >
...@@ -350,6 +413,16 @@ export default { ...@@ -350,6 +413,16 @@ export default {
<gl-loading-icon size="lg" color="dark" class="mt-3" /> <gl-loading-icon size="lg" color="dark" class="mt-3" />
</template> </template>
</gl-table> </gl-table>
<gl-pagination
v-if="showPaginationControls"
:value="pagination.currentPage"
:prev-page="prevPage"
:next-page="nextPage"
align="center"
class="gl-pagination prepend-top-default"
@input="handlePageChange"
/>
</div> </div>
<gl-empty-state <gl-empty-state
v-else v-else
......
...@@ -63,3 +63,5 @@ export const trackAlertStatusUpdateOptions = { ...@@ -63,3 +63,5 @@ export const trackAlertStatusUpdateOptions = {
action: 'update_alert_status', action: 'update_alert_status',
label: 'Status', label: 'Status',
}; };
export const DEFAULT_PAGE_SIZE = 10;
#import "../fragments/list_item.fragment.graphql" #import "../fragments/list_item.fragment.graphql"
query getAlerts($projectPath: ID!, $statuses: [AlertManagementStatus!], $sort: AlertManagementAlertSort ) { query getAlerts(
project(fullPath: $projectPath) { $projectPath: ID!,
alertManagementAlerts(statuses: $statuses, sort: $sort) { $statuses: [AlertManagementStatus!],
nodes { $sort: AlertManagementAlertSort,
...AlertListItem $firstPageSize: Int,
} $lastPageSize: Int,
$prevPageCursor: String = ""
$nextPageCursor: String = ""
) {
project(fullPath: $projectPath, ) {
alertManagementAlerts(
statuses: $statuses,
sort: $sort,
first: $firstPageSize
last: $lastPageSize,
after: $nextPageCursor,
before: $prevPageCursor
) {
nodes {
...AlertListItem
},
pageInfo {
hasNextPage
endCursor
hasPreviousPage
startCursor
}
}
} }
}
} }
---
title: Alerts list pagination
merge_request: 33073
author:
type: added
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