Limit on-demand scans tabs counts

Changelog: changed
EE: true
parent 5dbff37a
...@@ -21,7 +21,12 @@ import { ...@@ -21,7 +21,12 @@ import {
import handlesErrors from '../../mixins/handles_errors'; import handlesErrors from '../../mixins/handles_errors';
import Actions from '../actions.vue'; import Actions from '../actions.vue';
import EmptyState from '../empty_state.vue'; import EmptyState from '../empty_state.vue';
import { PIPELINES_PER_PAGE, PIPELINES_POLL_INTERVAL, ACTION_COLUMN } from '../../constants'; import {
PIPELINES_PER_PAGE,
MAX_PIPELINES_COUNT,
PIPELINES_POLL_INTERVAL,
ACTION_COLUMN,
} from '../../constants';
const defaultCursor = { const defaultCursor = {
first: PIPELINES_PER_PAGE, first: PIPELINES_PER_PAGE,
...@@ -72,6 +77,11 @@ export default { ...@@ -72,6 +77,11 @@ export default {
type: Number, type: Number,
required: true, required: true,
}, },
maxItemsCount: {
type: Number,
required: false,
default: MAX_PIPELINES_COUNT,
},
emptyStateTitle: { emptyStateTitle: {
type: String, type: String,
required: false, required: false,
...@@ -137,6 +147,10 @@ export default { ...@@ -137,6 +147,10 @@ export default {
}; };
}, },
computed: { computed: {
formattedCount() {
const { itemsCount, maxItemsCount } = this;
return itemsCount === maxItemsCount ? `${itemsCount}+` : itemsCount;
},
pipelineNodes() { pipelineNodes() {
return this.pipelines?.nodes ?? []; return this.pipelines?.nodes ?? [];
}, },
...@@ -214,7 +228,7 @@ export default { ...@@ -214,7 +228,7 @@ export default {
<template #title> <template #title>
<span class="gl-white-space-nowrap"> <span class="gl-white-space-nowrap">
{{ title }} {{ title }}
<gl-badge size="sm" class="gl-tab-counter-badge">{{ itemsCount }}</gl-badge> <gl-badge size="sm" class="gl-tab-counter-badge">{{ formattedCount }}</gl-badge>
</span> </span>
</template> </template>
<template v-if="$apollo.queries.pipelines.loading || hasPipelines"> <template v-if="$apollo.queries.pipelines.loading || hasPipelines">
......
...@@ -15,7 +15,7 @@ import dastProfileDelete from '../../graphql/dast_profile_delete.mutation.graphq ...@@ -15,7 +15,7 @@ import dastProfileDelete from '../../graphql/dast_profile_delete.mutation.graphq
import handlesErrors from '../../mixins/handles_errors'; import handlesErrors from '../../mixins/handles_errors';
import { removeProfile } from '../../graphql/cache_utils'; import { removeProfile } from '../../graphql/cache_utils';
import dastProfilesQuery from '../../graphql/dast_profiles.query.graphql'; import dastProfilesQuery from '../../graphql/dast_profiles.query.graphql';
import { SAVED_TAB_TABLE_FIELDS, LEARN_MORE_TEXT } from '../../constants'; import { SAVED_TAB_TABLE_FIELDS, LEARN_MORE_TEXT, MAX_DAST_PROFILES_COUNT } from '../../constants';
import BaseTab from './base_tab.vue'; import BaseTab from './base_tab.vue';
export default { export default {
...@@ -34,6 +34,7 @@ export default { ...@@ -34,6 +34,7 @@ export default {
}, },
mixins: [handlesErrors], mixins: [handlesErrors],
inject: ['projectPath'], inject: ['projectPath'],
maxItemsCount: MAX_DAST_PROFILES_COUNT,
tableFields: SAVED_TAB_TABLE_FIELDS, tableFields: SAVED_TAB_TABLE_FIELDS,
deleteScanModalId: `delete-scan-modal`, deleteScanModalId: `delete-scan-modal`,
i18n: { i18n: {
...@@ -145,6 +146,7 @@ export default { ...@@ -145,6 +146,7 @@ export default {
<template> <template>
<base-tab <base-tab
:max-items-count="$options.maxItemsCount"
:query="$options.query" :query="$options.query"
:query-variables="$options.queryVariables" :query-variables="$options.queryVariables"
:title="$options.i18n.title" :title="$options.i18n.title"
......
...@@ -3,7 +3,11 @@ import { GlIcon } from '@gitlab/ui'; ...@@ -3,7 +3,11 @@ import { GlIcon } from '@gitlab/ui';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import DastScanSchedule from 'ee/security_configuration/dast_profiles/components/dast_scan_schedule.vue'; import DastScanSchedule from 'ee/security_configuration/dast_profiles/components/dast_scan_schedule.vue';
import scheduledDastProfilesQuery from '../../graphql/scheduled_dast_profiles.query.graphql'; import scheduledDastProfilesQuery from '../../graphql/scheduled_dast_profiles.query.graphql';
import { SCHEDULED_TAB_TABLE_FIELDS, LEARN_MORE_TEXT } from '../../constants'; import {
SCHEDULED_TAB_TABLE_FIELDS,
LEARN_MORE_TEXT,
MAX_DAST_PROFILES_COUNT,
} from '../../constants';
import BaseTab from './base_tab.vue'; import BaseTab from './base_tab.vue';
export default { export default {
...@@ -14,6 +18,7 @@ export default { ...@@ -14,6 +18,7 @@ export default {
DastScanSchedule, DastScanSchedule,
}, },
inject: ['timezones'], inject: ['timezones'],
maxItemsCount: MAX_DAST_PROFILES_COUNT,
tableFields: SCHEDULED_TAB_TABLE_FIELDS, tableFields: SCHEDULED_TAB_TABLE_FIELDS,
i18n: { i18n: {
title: __('Scheduled'), title: __('Scheduled'),
...@@ -30,6 +35,7 @@ export default { ...@@ -30,6 +35,7 @@ export default {
<template> <template>
<base-tab <base-tab
:max-items-count="$options.maxItemsCount"
:query="$options.query" :query="$options.query"
:title="$options.i18n.title" :title="$options.i18n.title"
:fields="$options.tableFields" :fields="$options.tableFields"
......
...@@ -13,6 +13,8 @@ export const PIPELINE_TABS_KEYS = ['all', 'running', 'finished', 'scheduled', 's ...@@ -13,6 +13,8 @@ export const PIPELINE_TABS_KEYS = ['all', 'running', 'finished', 'scheduled', 's
export const PIPELINES_PER_PAGE = 20; export const PIPELINES_PER_PAGE = 20;
export const PIPELINES_POLL_INTERVAL = 3000; export const PIPELINES_POLL_INTERVAL = 3000;
export const PIPELINES_COUNT_POLL_INTERVAL = 3000; export const PIPELINES_COUNT_POLL_INTERVAL = 3000;
export const MAX_PIPELINES_COUNT = 1000;
export const MAX_DAST_PROFILES_COUNT = 100;
// Pipeline scopes // Pipeline scopes
export const PIPELINES_SCOPE_RUNNING = 'RUNNING'; export const PIPELINES_SCOPE_RUNNING = 'RUNNING';
......
...@@ -122,6 +122,18 @@ describe('BaseTab', () => { ...@@ -122,6 +122,18 @@ describe('BaseTab', () => {
}); });
describe('when the app loads', () => { describe('when the app loads', () => {
it('formats the items count if it hit its max value', () => {
const itemsCount = 10;
createComponent({
propsData: {
itemsCount,
maxItemsCount: itemsCount,
},
});
expect(findTitle().text()).toMatchInterpolatedText(`All ${itemsCount}+`);
});
it('controls the pipelines query with a visibility check', () => { it('controls the pipelines query with a visibility check', () => {
jest.spyOn(graphQlUtils, 'toggleQueryPollingByVisibility'); jest.spyOn(graphQlUtils, 'toggleQueryPollingByVisibility');
createComponent(); createComponent();
......
import Vue, { nextTick } from 'vue'; import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import { merge } from 'lodash'; import { merge, cloneDeep } from 'lodash';
import dastProfilesMock from 'test_fixtures/graphql/on_demand_scans/graphql/dast_profiles.query.graphql.json'; import dastProfilesMock from 'test_fixtures/graphql/on_demand_scans/graphql/dast_profiles.query.graphql.json';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import SavedTab from 'ee/on_demand_scans/components/tabs/saved.vue'; import SavedTab from 'ee/on_demand_scans/components/tabs/saved.vue';
...@@ -11,7 +11,11 @@ import dastProfilesQuery from 'ee/on_demand_scans/graphql/dast_profiles.query.gr ...@@ -11,7 +11,11 @@ import dastProfilesQuery from 'ee/on_demand_scans/graphql/dast_profiles.query.gr
import dastProfileRunMutation from 'ee/on_demand_scans/graphql/dast_profile_run.mutation.graphql'; import dastProfileRunMutation from 'ee/on_demand_scans/graphql/dast_profile_run.mutation.graphql';
import dastProfileDeleteMutation from 'ee/on_demand_scans/graphql/dast_profile_delete.mutation.graphql'; import dastProfileDeleteMutation from 'ee/on_demand_scans/graphql/dast_profile_delete.mutation.graphql';
import { createRouter } from 'ee/on_demand_scans/router'; import { createRouter } from 'ee/on_demand_scans/router';
import { SAVED_TAB_TABLE_FIELDS, LEARN_MORE_TEXT } from 'ee/on_demand_scans/constants'; import {
SAVED_TAB_TABLE_FIELDS,
LEARN_MORE_TEXT,
MAX_DAST_PROFILES_COUNT,
} from 'ee/on_demand_scans/constants';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import ScanTypeBadge from 'ee/security_configuration/dast_profiles/components/dast_scan_type_badge.vue'; import ScanTypeBadge from 'ee/security_configuration/dast_profiles/components/dast_scan_type_badge.vue';
import flushPromises from 'helpers/flush_promises'; import flushPromises from 'helpers/flush_promises';
...@@ -119,14 +123,17 @@ describe('Saved tab', () => { ...@@ -119,14 +123,17 @@ describe('Saved tab', () => {
it('renders the base tab with the correct props', () => { it('renders the base tab with the correct props', () => {
createComponent(); createComponent();
expect(findBaseTab().props('title')).toBe(s__('OnDemandScans|Scan library')); expect(cloneDeep(findBaseTab().props())).toEqual({
expect(findBaseTab().props('itemsCount')).toBe(itemsCount); isActive: true,
expect(findBaseTab().props('query')).toBe(dastProfilesQuery); title: s__('OnDemandScans|Scan library'),
expect(findBaseTab().props('emptyStateTitle')).toBe( itemsCount,
s__('OnDemandScans|There are no saved scans.'), maxItemsCount: MAX_DAST_PROFILES_COUNT,
); query: dastProfilesQuery,
expect(findBaseTab().props('emptyStateText')).toBe(LEARN_MORE_TEXT); queryVariables: {},
expect(findBaseTab().props('fields')).toBe(SAVED_TAB_TABLE_FIELDS); emptyStateTitle: s__('OnDemandScans|There are no saved scans.'),
emptyStateText: LEARN_MORE_TEXT,
fields: SAVED_TAB_TABLE_FIELDS,
});
}); });
it('fetches the profiles', () => { it('fetches the profiles', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import { merge } from 'lodash'; import { merge, cloneDeep } from 'lodash';
import scheduledDastProfilesMock from 'test_fixtures/graphql/on_demand_scans/graphql/scheduled_dast_profiles.query.graphql.json'; import scheduledDastProfilesMock from 'test_fixtures/graphql/on_demand_scans/graphql/scheduled_dast_profiles.query.graphql.json';
import mockTimezones from 'test_fixtures/timezones/abbr.json'; import mockTimezones from 'test_fixtures/timezones/abbr.json';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
...@@ -10,7 +10,11 @@ import createMockApollo from 'helpers/mock_apollo_helper'; ...@@ -10,7 +10,11 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import scheduledDastProfilesQuery from 'ee/on_demand_scans/graphql/scheduled_dast_profiles.query.graphql'; import scheduledDastProfilesQuery from 'ee/on_demand_scans/graphql/scheduled_dast_profiles.query.graphql';
import { createRouter } from 'ee/on_demand_scans/router'; import { createRouter } from 'ee/on_demand_scans/router';
import { SCHEDULED_TAB_TABLE_FIELDS, LEARN_MORE_TEXT } from 'ee/on_demand_scans/constants'; import {
SCHEDULED_TAB_TABLE_FIELDS,
LEARN_MORE_TEXT,
MAX_DAST_PROFILES_COUNT,
} from 'ee/on_demand_scans/constants';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import { stripTimezoneFromISODate } from '~/lib/utils/datetime/date_format_utility'; import { stripTimezoneFromISODate } from '~/lib/utils/datetime/date_format_utility';
import DastScanSchedule from 'ee/security_configuration/dast_profiles/components/dast_scan_schedule.vue'; import DastScanSchedule from 'ee/security_configuration/dast_profiles/components/dast_scan_schedule.vue';
...@@ -81,14 +85,17 @@ describe('Scheduled tab', () => { ...@@ -81,14 +85,17 @@ describe('Scheduled tab', () => {
it('renders the base tab with the correct props', () => { it('renders the base tab with the correct props', () => {
createComponent(); createComponent();
expect(findBaseTab().props('title')).toBe(__('Scheduled')); expect(cloneDeep(findBaseTab().props())).toEqual({
expect(findBaseTab().props('itemsCount')).toBe(itemsCount); isActive: true,
expect(findBaseTab().props('query')).toBe(scheduledDastProfilesQuery); title: __('Scheduled'),
expect(findBaseTab().props('emptyStateTitle')).toBe( itemsCount,
s__('OnDemandScans|There are no scheduled scans.'), maxItemsCount: MAX_DAST_PROFILES_COUNT,
); query: scheduledDastProfilesQuery,
expect(findBaseTab().props('emptyStateText')).toBe(LEARN_MORE_TEXT); queryVariables: {},
expect(findBaseTab().props('fields')).toBe(SCHEDULED_TAB_TABLE_FIELDS); emptyStateTitle: s__('OnDemandScans|There are no scheduled scans.'),
emptyStateText: LEARN_MORE_TEXT,
fields: SCHEDULED_TAB_TABLE_FIELDS,
});
}); });
it('fetches the profiles', () => { it('fetches the profiles', () => {
......
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