diff --git a/ee/app/assets/javascripts/ci/runner/admin_runners_dashboard/admin_runners_wait_times.vue b/ee/app/assets/javascripts/ci/runner/admin_runners_dashboard/admin_runners_wait_times.vue index f645eb878346c64b873e8b8ec4f9c418e3100e82..78fa384c4c7d2363fe0e23e986f4929dcee045ee 100644 --- a/ee/app/assets/javascripts/ci/runner/admin_runners_dashboard/admin_runners_wait_times.vue +++ b/ee/app/assets/javascripts/ci/runner/admin_runners_dashboard/admin_runners_wait_times.vue @@ -65,8 +65,16 @@ export default { </script> <template> <runner-wait-times + :wait-times-popover-description=" + s__( + 'Runners|The time it takes for an instance runner to pick up a job. Jobs waiting for runners are in the pending state.', + ) + " :wait-times="waitTimes" :wait-times-loading="waitTimesLoading" + :wait-time-history-empty-state-description=" + s__('Runners|No jobs have been run by instance runners in the past 3 hours.') + " :wait-time-history-enabled="isHistoryFeatureEnabled" :wait-time-history="waitTimeHistory" :wait-time-history-loading="waitTimeHistoryLoading" diff --git a/ee/app/assets/javascripts/ci/runner/components/runner_wait_times.vue b/ee/app/assets/javascripts/ci/runner/components/runner_wait_times.vue index 7147c52c64dced8af0135cbc0786f7dbaaea551a..900602a0373ba4adc2e5ea7708299ed6f2c37e10 100644 --- a/ee/app/assets/javascripts/ci/runner/components/runner_wait_times.vue +++ b/ee/app/assets/javascripts/ci/runner/components/runner_wait_times.vue @@ -1,5 +1,5 @@ <script> -import { GlEmptyState, GlLink, GlLoadingIcon, GlSkeletonLoader, GlSprintf } from '@gitlab/ui'; +import { GlEmptyState, GlLink, GlLoadingIcon, GlSkeletonLoader } from '@gitlab/ui'; import { GlSingleStat, GlLineChart } from '@gitlab/ui/dist/charts'; import CHART_EMPTY_STATE_SVG_URL from '@gitlab/svgs/dist/illustrations/empty-state/empty-pipeline-md.svg?url'; import HelpPopover from '~/vue_shared/components/help_popover.vue'; @@ -22,11 +22,14 @@ export default { GlLink, GlLoadingIcon, GlSkeletonLoader, - GlSprintf, GlSingleStat, GlLineChart, }, props: { + waitTimesPopoverDescription: { + type: String, + required: true, + }, waitTimes: { type: Object, required: false, @@ -38,6 +41,10 @@ export default { default: false, }, + waitTimeHistoryEmptyStateDescription: { + type: String, + required: true, + }, waitTimeHistoryEnabled: { type: Boolean, required: false, @@ -91,17 +98,10 @@ export default { <h2 class="gl-font-lg gl-mt-0"> {{ s__('Runners|Wait time to pick a job') }} <help-popover trigger-class="gl-align-baseline"> - <gl-sprintf - :message=" - s__( - 'Runners|The time it takes for an instance runner to pick up a job. Jobs waiting for runners are in the pending state. %{linkStart}How is this calculated?%{linkEnd}', - ) - " - > - <template #link="{ content }"> - <gl-link :href="$options.jobDurationHelpPagePath">{{ content }}</gl-link> - </template> - </gl-sprintf> + {{ waitTimesPopoverDescription }} + <gl-link :href="$options.jobDurationHelpPagePath">{{ + s__('Runners|How is this calculated?') + }}</gl-link> </help-popover> </h2> <gl-loading-icon v-if="waitTimesLoading || waitTimeHistoryLoading" class="gl-ml-auto" /> @@ -126,7 +126,7 @@ export default { <gl-empty-state v-else-if="!waitTimeHistoryChartData.length" :svg-path="$options.CHART_EMPTY_STATE_SVG_URL" - :description="s__('Runners|No jobs have been run by instance runners in the past 3 hours.')" + :description="waitTimeHistoryEmptyStateDescription" /> <gl-line-chart v-else diff --git a/ee/app/assets/javascripts/ci/runner/graphql/performance/group_runner_wait_time_history.query.graphql b/ee/app/assets/javascripts/ci/runner/graphql/performance/group_runner_wait_time_history.query.graphql new file mode 100644 index 0000000000000000000000000000000000000000..c8a8cff209f5456ea8dd938eaca114c34c4ac517 --- /dev/null +++ b/ee/app/assets/javascripts/ci/runner/graphql/performance/group_runner_wait_time_history.query.graphql @@ -0,0 +1,14 @@ +query groupRunnerWaitTimeHistory($fullPath: ID!, $fromTime: Time, $toTime: Time) { + group(fullPath: $fullPath) { + id + ciQueueingHistory(fromTime: $fromTime, toTime: $toTime) { + timeSeries { + time + p99 + p90 + p75 + p50 + } + } + } +} diff --git a/ee/app/assets/javascripts/ci/runner/graphql/performance/group_runner_wait_times.query.graphql b/ee/app/assets/javascripts/ci/runner/graphql/performance/group_runner_wait_times.query.graphql new file mode 100644 index 0000000000000000000000000000000000000000..e360bd0ae2cadab962f688e6b7da6b8f4e24ce0e --- /dev/null +++ b/ee/app/assets/javascripts/ci/runner/graphql/performance/group_runner_wait_times.query.graphql @@ -0,0 +1,15 @@ +query groupRunnersWaitTimesEE($fullPath: ID!) { + group(fullPath: $fullPath) { + id + runners { + jobsStatistics { + queuedDuration { + p99 + p90 + p75 + p50 + } + } + } + } +} diff --git a/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_dashboard_app.vue b/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_dashboard_app.vue index 4f9e91ecedd71235e9ff5a31eeac6408025150eb..b8ad86739f299cb2ec1e0b3198c6c2d447007a7e 100644 --- a/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_dashboard_app.vue +++ b/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_dashboard_app.vue @@ -2,12 +2,14 @@ import { GlButton } from '@gitlab/ui'; import RunnerListHeader from '~/ci/runner/components/runner_list_header.vue'; -import GroupRunnerActiveList from './group_runners_active_list.vue'; +import GroupRunnersActiveList from './group_runners_active_list.vue'; +import GroupRunnersWaitTimes from './group_runners_wait_times.vue'; export default { components: { GlButton, - GroupRunnerActiveList, + GroupRunnersActiveList, + GroupRunnersWaitTimes, RunnerListHeader, }, inject: { @@ -49,6 +51,7 @@ export default { {{ s__('Runners|Use the dashboard to view performance statistics of your runner fleet.') }} </p> - <group-runner-active-list :group-full-path="groupFullPath" /> + <group-runners-active-list :group-full-path="groupFullPath" class="gl-mb-4" /> + <group-runners-wait-times :group-full-path="groupFullPath" /> </div> </template> diff --git a/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_wait_times.vue b/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_wait_times.vue new file mode 100644 index 0000000000000000000000000000000000000000..3b4ece9d93cd51217492d3e3f8f3b567d70ccbec --- /dev/null +++ b/ee/app/assets/javascripts/ci/runner/group_runners_dashboard/group_runners_wait_times.vue @@ -0,0 +1,98 @@ +<script> +import { captureException } from '~/ci/runner/sentry_utils'; +import { createAlert } from '~/alert'; + +import { runnerWaitTimeHistoryRange } from 'ee/ci/runner/runner_performance_utils'; +import groupRunnerWaitTimesQuery from 'ee/ci/runner/graphql/performance/group_runner_wait_times.query.graphql'; +import groupRunnerWaitTimeHistoryQuery from 'ee/ci/runner/graphql/performance/group_runner_wait_time_history.query.graphql'; + +import RunnerWaitTimes from '../components/runner_wait_times.vue'; + +export default { + name: 'AdminRunnerWaitTimes', + components: { + RunnerWaitTimes, + }, + inject: { + clickhouseCiAnalyticsAvailable: { + default: false, + }, + }, + props: { + groupFullPath: { + type: String, + required: true, + }, + }, + apollo: { + waitTimes: { + query: groupRunnerWaitTimesQuery, + update({ group }) { + return group?.runners?.jobsStatistics?.queuedDuration; + }, + variables() { + return { + fullPath: this.groupFullPath, + }; + }, + error(error) { + this.handlerError(error); + }, + }, + waitTimeHistory: { + query: groupRunnerWaitTimeHistoryQuery, + skip() { + return !this.isHistoryFeatureEnabled; + }, + variables() { + return { + fullPath: this.groupFullPath, + ...runnerWaitTimeHistoryRange(), + }; + }, + update({ group }) { + return group?.ciQueueingHistory?.timeSeries; + }, + error(error) { + this.handlerError(error); + }, + }, + }, + computed: { + isHistoryFeatureEnabled() { + return this.clickhouseCiAnalyticsAvailable; + }, + waitTimesLoading() { + return this.$apollo.queries.waitTimes.loading; + }, + waitTimeHistoryLoading() { + return this.$apollo.queries.waitTimeHistory.loading; + }, + }, + methods: { + handlerError(error) { + createAlert({ message: error.message }); + captureException({ error, component: this.$options.name }); + }, + }, +}; +</script> +<template> + <runner-wait-times + :wait-times-popover-description=" + s__( + 'Runners|The time it takes for a group runner assigned to this group to pick up a job. Jobs waiting for runners are in the pending state.', + ) + " + :wait-times="waitTimes" + :wait-times-loading="waitTimesLoading" + :wait-time-history-empty-state-description=" + s__( + 'Runners|No jobs have been run by group runners assigned to this group in the past 3 hours.', + ) + " + :wait-time-history-enabled="isHistoryFeatureEnabled" + :wait-time-history="waitTimeHistory" + :wait-time-history-loading="waitTimeHistoryLoading" + /> +</template> diff --git a/ee/spec/frontend/ci/runner/admin_runners_dashboard/admin_runners_wait_times_spec.js b/ee/spec/frontend/ci/runner/admin_runners_dashboard/admin_runners_wait_times_spec.js index 67ac85c2b9eef6bc0d6fb513bdef21866b8f50ec..34889bf11630e1a9c934feab90d20d91f90156c7 100644 --- a/ee/spec/frontend/ci/runner/admin_runners_dashboard/admin_runners_wait_times_spec.js +++ b/ee/spec/frontend/ci/runner/admin_runners_dashboard/admin_runners_wait_times_spec.js @@ -11,13 +11,33 @@ import runnerWaitTimeHistoryQuery from 'ee/ci/runner/graphql/performance/runner_ import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import { runnersWaitTimes, runnerWaitTimeHistory } from '../mock_data'; +import { queuedDuration, timeSeries } from '../mock_data'; jest.mock('~/alert'); jest.mock('~/ci/runner/sentry_utils'); Vue.use(VueApollo); +const runnersWaitTimes = { + data: { + runners: { + jobsStatistics: { + queuedDuration, + __typename: 'CiJobsStatistics', + }, + __typename: 'CiRunnerConnection', + }, + }, +}; + +const runnerWaitTimeHistory = { + data: { + ciQueueingHistory: { + timeSeries, + }, + }, +}; + describe('RunnerActiveList', () => { let wrapper; let runnerWaitTimesHandler; @@ -48,9 +68,11 @@ describe('RunnerActiveList', () => { it('shows loading state', () => { expect(findRunnerWaitTimes().props()).toEqual({ + waitTimesPopoverDescription: expect.any(String), waitTimes: null, waitTimesLoading: true, + waitTimeHistoryEmptyStateDescription: expect.any(String), waitTimeHistory: [], waitTimeHistoryEnabled: true, waitTimeHistoryLoading: true, @@ -81,10 +103,12 @@ describe('RunnerActiveList', () => { it('shows data', () => { expect(findRunnerWaitTimes().props()).toEqual({ - waitTimes: runnersWaitTimes.data.runners.jobsStatistics.queuedDuration, + waitTimesPopoverDescription: expect.any(String), + waitTimes: queuedDuration, waitTimesLoading: false, - waitTimeHistory: runnerWaitTimeHistory.data.ciQueueingHistory.timeSeries, + waitTimeHistoryEmptyStateDescription: expect.any(String), + waitTimeHistory: timeSeries, waitTimeHistoryEnabled: true, waitTimeHistoryLoading: false, }); diff --git a/ee/spec/frontend/ci/runner/components/runner_wait_times_spec.js b/ee/spec/frontend/ci/runner/components/runner_wait_times_spec.js index c016bf0139c1f0d2ea8d329cd499686f9da6b27b..44f0ad18695d81a7a716bf1651ea17177cac6ae5 100644 --- a/ee/spec/frontend/ci/runner/components/runner_wait_times_spec.js +++ b/ee/spec/frontend/ci/runner/components/runner_wait_times_spec.js @@ -1,4 +1,4 @@ -import { GlSprintf, GlLink, GlLoadingIcon, GlSkeletonLoader } from '@gitlab/ui'; +import { GlLink, GlLoadingIcon, GlSkeletonLoader, GlEmptyState } from '@gitlab/ui'; import { GlSingleStat, GlLineChart } from '@gitlab/ui/dist/charts'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { useFakeDate } from 'helpers/fake_date'; @@ -9,14 +9,14 @@ import { I18N_MEDIAN, I18N_P75, I18N_P90, I18N_P99 } from 'ee/ci/runner/constant import HelpPopover from '~/vue_shared/components/help_popover.vue'; -import { runnersWaitTimes, runnerWaitTimeHistory } from '../mock_data'; - -const waitTimes = runnersWaitTimes.data.runners.jobsStatistics.queuedDuration; -const waitTimeHistory = runnerWaitTimeHistory.data.ciQueueingHistory.timeSeries; +import { queuedDuration as waitTimes, timeSeries as waitTimeHistory } from '../mock_data'; jest.mock('~/alert'); jest.mock('~/ci/runner/sentry_utils'); +const waitTimesPopoverDescription = 'Popover description'; +const waitTimeHistoryEmptyStateDescription = 'Empty state description'; + describe('RunnerActiveList', () => { let wrapper; @@ -24,6 +24,7 @@ describe('RunnerActiveList', () => { const findHelpPopover = () => wrapper.findComponent(HelpPopover); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader); + const findGlEmptyState = () => wrapper.findComponent(GlEmptyState); const findChart = () => wrapper.findComponent(GlLineChart); const getStatData = () => @@ -32,10 +33,11 @@ describe('RunnerActiveList', () => { const createComponent = ({ props, ...options } = {}) => { wrapper = shallowMountExtended(RunnerWaitTimes, { propsData: { + waitTimesPopoverDescription, + waitTimeHistoryEmptyStateDescription, waitTimeHistoryEnabled: true, ...props, }, - stubs: { GlSprintf }, ...options, }); }; @@ -61,6 +63,7 @@ describe('RunnerActiveList', () => { }); it('shows help popover with link', () => { + expect(findHelpPopover().text()).toContain(waitTimesPopoverDescription); expect(findHelpPopover().findComponent(GlLink).exists()).toBe(true); }); @@ -132,6 +135,20 @@ describe('RunnerActiveList', () => { }); }); + describe('When wait times are empty', () => { + beforeEach(() => { + createComponent({ + props: { waitTimeHistory: [] }, + }); + }); + + it('shows an empty state', () => { + expect(findGlEmptyState().props('description')).toContain( + waitTimeHistoryEmptyStateDescription, + ); + }); + }); + describe('When ClickHouse is not configured', () => { beforeEach(() => { createComponent({ diff --git a/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_dashboard_app_spec.js b/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_dashboard_app_spec.js index 7fb16cddea018b8361363477465072dd42ef1a02..9ceb8e6e1a47a93211336c5d034d08d4f92afd0b 100644 --- a/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_dashboard_app_spec.js +++ b/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_dashboard_app_spec.js @@ -5,6 +5,7 @@ import GroupRunnersDashboardApp from 'ee/ci/runner/group_runners_dashboard/group import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import GroupRunnersActiveList from 'ee/ci/runner/group_runners_dashboard/group_runners_active_list.vue'; +import GroupRunnersWaitTimes from 'ee/ci/runner/group_runners_dashboard/group_runners_wait_times.vue'; const mockGroupPath = 'group'; const mockGroupRunnersPath = '/group/-/runners'; @@ -13,6 +14,9 @@ const mockNewRunnerPath = '/runners/new'; describe('GroupRunnersDashboardApp', () => { let wrapper; + const findGroupRunnersActiveList = () => wrapper.findComponent(GroupRunnersActiveList); + const findGroupRunnersWaitTimes = () => wrapper.findComponent(GroupRunnersWaitTimes); + const createComponent = (options) => { wrapper = shallowMountExtended(GroupRunnersDashboardApp, { propsData: { @@ -39,7 +43,10 @@ describe('GroupRunnersDashboardApp', () => { }); it('shows dashboard panels', () => { - expect(wrapper.findComponent(GroupRunnersActiveList).props()).toEqual({ + expect(findGroupRunnersActiveList().props()).toEqual({ + groupFullPath: mockGroupPath, + }); + expect(findGroupRunnersWaitTimes().props()).toEqual({ groupFullPath: mockGroupPath, }); }); diff --git a/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_wait_times_spec.js b/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_wait_times_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..dbd8b5f2e13c1eb5e37d6d09cd0e77456a81d3e8 --- /dev/null +++ b/ee/spec/frontend/ci/runner/group_runners_dashboard/group_runners_wait_times_spec.js @@ -0,0 +1,155 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; + +import GroupRunnersWaitTimes from 'ee/ci/runner/group_runners_dashboard/group_runners_wait_times.vue'; + +import RunnerWaitTimes from 'ee/ci/runner/components/runner_wait_times.vue'; +import groupRunnerWaitTimesQuery from 'ee/ci/runner/graphql/performance/group_runner_wait_times.query.graphql'; +import groupRunnerWaitTimeHistoryQuery from 'ee/ci/runner/graphql/performance/group_runner_wait_time_history.query.graphql'; + +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; + +import { queuedDuration, timeSeries } from '../mock_data'; + +jest.mock('~/alert'); +jest.mock('~/ci/runner/sentry_utils'); + +Vue.use(VueApollo); + +const mockGroupPath = '/group/-/runners'; + +const groupRunnersWaitTimes = { + data: { + group: { + id: 'group1', + runners: { + jobsStatistics: { + queuedDuration, + __typename: 'CiJobsStatistics', + }, + __typename: 'CiRunnerConnection', + }, + __typename: 'Group', + }, + }, +}; + +const groupRunnersWaitTimeHistory = { + data: { + group: { + id: 'group1', + ciQueueingHistory: { + timeSeries, + }, + __typename: 'Group', + }, + }, +}; + +describe('RunnerActiveList', () => { + let wrapper; + let groupRunnerWaitTimesHandler; + let groupRunnerWaitTimeHistoryHandler; + + const findRunnerWaitTimes = () => wrapper.findComponent(RunnerWaitTimes); + + const createComponent = (options = {}) => { + wrapper = shallowMountExtended(GroupRunnersWaitTimes, { + apolloProvider: createMockApollo([ + [groupRunnerWaitTimesQuery, groupRunnerWaitTimesHandler], + [groupRunnerWaitTimeHistoryQuery, groupRunnerWaitTimeHistoryHandler], + ]), + props: { + groupFullPath: mockGroupPath, + }, + provide: { clickhouseCiAnalyticsAvailable: true }, + ...options, + }); + }; + + beforeEach(() => { + groupRunnerWaitTimesHandler = jest.fn().mockResolvedValue(new Promise(() => {})); + groupRunnerWaitTimeHistoryHandler = jest.fn().mockResolvedValue(new Promise(() => {})); + }); + + describe('When loading data', () => { + beforeEach(() => { + createComponent(); + }); + + it('shows loading state', () => { + expect(findRunnerWaitTimes().props()).toEqual({ + waitTimesPopoverDescription: expect.any(String), + waitTimes: null, + waitTimesLoading: true, + + waitTimeHistoryEmptyStateDescription: expect.any(String), + waitTimeHistory: [], + waitTimeHistoryEnabled: true, + waitTimeHistoryLoading: true, + }); + }); + + it('requests wait times', () => { + expect(groupRunnerWaitTimesHandler).toHaveBeenCalledTimes(1); + }); + + it('requests wait time history', () => { + expect(groupRunnerWaitTimeHistoryHandler).toHaveBeenCalledTimes(1); + expect(groupRunnerWaitTimeHistoryHandler).toHaveBeenCalledWith({ + fromTime: expect.any(String), + toTime: expect.any(String), + }); + }); + }); + + describe('When wait times are loaded', () => { + beforeEach(async () => { + groupRunnerWaitTimesHandler.mockResolvedValue(groupRunnersWaitTimes); + groupRunnerWaitTimeHistoryHandler.mockResolvedValue(groupRunnersWaitTimeHistory); + + createComponent(); + await waitForPromises(); + }); + + it('shows data', () => { + expect(findRunnerWaitTimes().props()).toEqual({ + waitTimesPopoverDescription: expect.any(String), + waitTimes: queuedDuration, + waitTimesLoading: false, + + waitTimeHistoryEmptyStateDescription: expect.any(String), + waitTimeHistory: timeSeries, + waitTimeHistoryEnabled: true, + waitTimeHistoryLoading: false, + }); + }); + }); + + describe('When ClickHouse is not configured', () => { + beforeEach(async () => { + groupRunnerWaitTimesHandler.mockResolvedValue(groupRunnersWaitTimes); + + createComponent({ provide: { clickhouseCiAnalyticsAvailable: false } }); + await waitForPromises(); + }); + + it('request wait times', () => { + expect(groupRunnerWaitTimesHandler).toHaveBeenCalledTimes(1); + }); + + it('does not request wait time history', () => { + expect(groupRunnerWaitTimeHistoryHandler).toHaveBeenCalledTimes(0); + }); + + it('shows wait time data without history', () => { + expect(findRunnerWaitTimes().props()).toMatchObject({ + waitTimeHistory: [], + waitTimeHistoryEnabled: false, + waitTimeHistoryLoading: false, + }); + }); + }); +}); diff --git a/ee/spec/frontend/ci/runner/mock_data.js b/ee/spec/frontend/ci/runner/mock_data.js index 3a455d6a3a3a91769a88d6c45224f07da87ac82d..d6e7d80fbbb104198559e9ba135203d61a1d8404 100644 --- a/ee/spec/frontend/ci/runner/mock_data.js +++ b/ee/spec/frontend/ci/runner/mock_data.js @@ -8,48 +8,32 @@ import mostActiveRunnersData from 'test_fixtures/graphql/ci/runner/performance/m import groupMostActiveRunnersData from 'test_fixtures/graphql/ci/runner/performance/group_most_active_runners.query.graphql.json'; import runnerFailedJobsData from 'test_fixtures/graphql/ci/runner/performance/runner_failed_jobs.graphql.json'; -export const runnersWaitTimes = { - data: { - runners: { - jobsStatistics: { - queuedDuration: { - p99: 99, - p90: 90, - p75: 75, - p50: 50, - __typename: 'CiJobsDurationStatistics', - }, - __typename: 'CiJobsStatistics', - }, - __typename: 'CiRunnerConnection', - }, - }, +export const queuedDuration = { + p99: 99, + p90: 90, + p75: 75, + p50: 50, + __typename: 'CiJobsDurationStatistics', }; -export const runnerWaitTimeHistory = { - data: { - ciQueueingHistory: { - timeSeries: [ - { - time: '2023-09-14T10:00:00Z', - p99: 99, - p90: 90, - p75: 75, - p50: 50, - __typename: 'QueueingHistoryTimeSeries', - }, - { - time: '2023-09-14T11:00:00Z', - p99: 98, - p90: 89, - p75: 74, - p50: 49, - __typename: 'QueueingHistoryTimeSeries', - }, - ], - }, +export const timeSeries = [ + { + time: '2023-09-14T10:00:00Z', + p99: 99, + p90: 90, + p75: 75, + p50: 50, + __typename: 'QueueingHistoryTimeSeries', }, -}; + { + time: '2023-09-14T11:00:00Z', + p99: 98, + p90: 89, + p75: 74, + p50: 49, + __typename: 'QueueingHistoryTimeSeries', + }, +]; export const runnerDashboardPath = '/admin/runners/dashboard'; diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 4c0e0dc218098a762d44135142f1e2d3a980fe61..e6276fbc7519b24063fe2c9a6e491cd1c871f222 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -44822,6 +44822,9 @@ msgstr "" msgid "Runners|How do runners pick up jobs?" msgstr "" +msgid "Runners|How is this calculated?" +msgstr "" + msgid "Runners|IP Address" msgstr "" @@ -44966,6 +44969,9 @@ msgstr "" msgid "Runners|No description" msgstr "" +msgid "Runners|No jobs have been run by group runners assigned to this group in the past 3 hours." +msgstr "" + msgid "Runners|No jobs have been run by instance runners in the past 3 hours." msgstr "" @@ -45308,7 +45314,10 @@ msgid_plural "Runners|%d runners will be permanently deleted and no longer avail msgstr[0] "" msgstr[1] "" -msgid "Runners|The time it takes for an instance runner to pick up a job. Jobs waiting for runners are in the pending state. %{linkStart}How is this calculated?%{linkEnd}" +msgid "Runners|The time it takes for a group runner assigned to this group to pick up a job. Jobs waiting for runners are in the pending state." +msgstr "" + +msgid "Runners|The time it takes for an instance runner to pick up a job. Jobs waiting for runners are in the pending state." msgstr "" msgid "Runners|The unique ID for each runner that uses this configuration."