Skip to content
Snippets Groups Projects

Resolve "Add issue state counts to GraphQL"

Merged David O'Regan requested to merge 232580-state-count into master
All threads resolved!
11 files
+ 188
20
Compare changes
  • Side-by-side
  • Inline
Files
11
@@ -11,13 +11,17 @@ import {
GlSearchBoxByType,
GlIcon,
GlPagination,
GlTabs,
GlTab,
GlBadge,
} from '@gitlab/ui';
import { debounce } from 'lodash';
import { debounce, trim } from 'lodash';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
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 } from '../constants';
import getIncidentsCountByStatus from '../graphql/queries/get_count_by_state.query.graphql';
import { I18N, DEFAULT_PAGE_SIZE, INCIDENT_SEARCH_DELAY, INCIDENT_STATE_TABS } from '../constants';
const tdClass =
'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap';
@@ -35,6 +39,7 @@ const initialPaginationState = {
export default {
i18n: I18N,
stateTabs: INCIDENT_STATE_TABS,
fields: [
{
key: 'title',
@@ -67,6 +72,9 @@ export default {
GlSearchBoxByType,
GlIcon,
GlPagination,
GlTabs,
GlTab,
GlBadge,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -78,6 +86,7 @@ export default {
variables() {
return {
searchTerm: this.searchTerm,
state: this.stateFilter,
projectPath: this.projectPath,
labelNames: ['incident'],
firstPageSize: this.pagination.firstPageSize,
@@ -96,6 +105,18 @@ export default {
this.errored = true;
},
},
incidentsCount: {
query: getIncidentsCountByStatus,
variables() {
return {
searchTerm: this.searchTerm,
projectPath: this.projectPath,
};
},
update(data) {
return data.project?.issueStatusCounts;
},
},
},
data() {
return {
@@ -105,11 +126,13 @@ export default {
searchTerm: '',
pagination: initialPaginationState,
incidents: {},
stateFilter: '',
filteredByState: '',
};
},
computed: {
showErrorMsg() {
return this.errored && !this.isErrorAlertDismissed && !this.searchTerm;
return this.errored && !this.isErrorAlertDismissed && this.incidentsCount?.all === 0;
},
loading() {
return this.$apollo.queries.incidents.loading;
@@ -117,6 +140,9 @@ export default {
hasIncidents() {
return this.incidents?.list?.length;
},
incidentsForCurrentTab() {
return this.incidentsCount ? this.incidentsCount[this.filteredByState.toLowerCase()] : 0;
},
showPaginationControls() {
return Boolean(
this.incidents?.pageInfo?.hasNextPage || this.incidents?.pageInfo?.hasPreviousPage,
@@ -127,7 +153,9 @@ export default {
},
nextPage() {
const nextPage = this.pagination.currentPage + 1;
return this.incidents?.list?.length < DEFAULT_PAGE_SIZE ? null : nextPage;
return nextPage > Math.ceil(this.incidentsForCurrentTab / DEFAULT_PAGE_SIZE)
? null
: nextPage;
},
tbodyTrClass() {
return {
@@ -138,14 +166,18 @@ export default {
return mergeUrlParams({ issuable_template: this.incidentTemplateName }, this.newIssuePath);
},
},
watch: {
searchTerm: debounce(function debounceSearch(input) {
if (input !== this.searchTerm) {
this.searchTerm = input;
methods: {
onInputChange: debounce(function debounceSearch(input) {
const trimmedInput = trim(input);
if (trimmedInput !== this.searchTerm) {
this.searchTerm = trimmedInput;
}
}, INCIDENT_SEARCH_DELAY),
},
methods: {
filterIncidentsByState(tabIndex) {
const { filters, state } = this.$options.stateTabs[tabIndex];
this.stateFilter = filters;
this.filteredByState = state;
},
hasAssignees(assignees) {
return Boolean(assignees.nodes?.length);
},
@@ -176,7+208,7 @@
},
},
};
</script>
<template>
<div class="incident-management-list">
<gl-alert v-if="showErrorMsg" variant="danger" @dismiss="isErrorAlertDismissed = true">
{{ $options.i18n.errorMsg }}
</gl-alert>
<div class="gl-display-flex gl-justify-content-end">
<div class="incident-management-list-header gl-display-flex gl-justify-content-space-between">
<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 slot="title">
<span>{{ tab.title }}</span>
<gl-badge v-if="incidentsCount" pill size="sm" class="gl-tab-counter-badge">
{{ incidentsCount[tab.state.toLowerCase()] }}
</gl-badge>
</template>
</gl-tab>
</gl-tabs>
<gl-button
class="gl-mt-3 gl-mb-3 create-incident-button"
class="gl-my-3 create-incident-button"
data-testid="createIncidentBtn"
:loading="redirecting"
:disabled="redirecting"
@@ -200,0+243,0 @@
<div class="gl-bg-gray-10 gl-p-5 gl-border-b-solid gl-border-b-1 gl-border-gray-100">
<gl-search-box-by-type
v-model.trim="searchTerm"
class="gl-bg-white"
:placeholder="$options.i18n.searchPlaceholder"
@input="onInputChange"
/>
</div>
@@ -221,7 +264,7 @@ export default {
@row-clicked="navigateToIncidentDetails"
>
<template #cell(title)="{ item }">
<div class="gl-display-flex gl-justify-content-center">
<div class="gl-display-sm-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'"
Loading