diff --git a/ee/app/assets/javascripts/analytics/dashboards/components/dora_performers_score.vue b/ee/app/assets/javascripts/analytics/dashboards/components/dora_performers_score.vue index b08a4571da6918754625b0a39fc11cbc28656495..ce42526fdce30a44e2565e2986839aaaba2cea4c 100644 --- a/ee/app/assets/javascripts/analytics/dashboards/components/dora_performers_score.vue +++ b/ee/app/assets/javascripts/analytics/dashboards/components/dora_performers_score.vue @@ -80,14 +80,11 @@ export default { return !this.fullPath || !this.shouldDisplayPanel || this.isProjectNamespace; }, update(data) { - const { - noDoraDataProjectsCount = null, - nodes: items = [], - totalProjectsCount: projectsCount = null, - } = data?.namespace?.doraPerformanceScoreCounts || {}; + const { noDoraDataProjectsCount = 0, nodes: items = [], totalProjectsCount = 0 } = + data?.namespace?.doraPerformanceScoreCounts || {}; return { - projectsCount, + totalProjectsCount, noDoraDataProjectsCount, items, }; @@ -123,16 +120,20 @@ export default { shouldDisplayDefaultPanelTitle() { return !this.namespace || this.isProjectNamespace || this.hasDoraPerformanceScoresFetchError; }, + projectsCountWithDoraData() { + const { totalProjectsCount, noDoraDataProjectsCount } = + this.groupDoraPerformanceScoreCounts || {}; + + return Math.max(0, totalProjectsCount - noDoraDataProjectsCount) || 0; // handle edge case where noDoraDataProjectsCount could be higher than totalProjectsCount + }, panelTitle() { if (this.shouldDisplayDefaultPanelTitle) { return this.$options.i18n.defaultPanelTitle; } - const projectsCount = this.groupDoraPerformanceScoreCounts?.projectsCount; - return sprintf(this.$options.i18n.panelTitleWithProjectsCount, { groupName: this.namespace?.name, - count: projectsCount, + count: this.projectsCountWithDoraData, }); }, errorMessage() { @@ -148,14 +149,9 @@ export default { return ''; }, - hasNoProjectsWithDoraData() { - const { noDoraDataProjectsCount, projectsCount } = this.groupDoraPerformanceScoreCounts || {}; - - return noDoraDataProjectsCount >= projectsCount; // handle edge case where noDoraDataProjectsCount could be higher than projectsCount - }, hasData() { return ( - !this.hasNoProjectsWithDoraData && + this.projectsCountWithDoraData && initial(this.chartData).some(({ data }) => data.some((val) => val)) // ignore the "Not included" series – we are only interested in checking if any projects have high/medium/low score counts ); }, diff --git a/ee/app/assets/javascripts/analytics/dashboards/constants.js b/ee/app/assets/javascripts/analytics/dashboards/constants.js index 2e3557183e4b02bdde6fc7d3fa7b5b6a66b07f46..ad340a1e01ae6c045014e06e89a42e01a3dc73ac 100644 --- a/ee/app/assets/javascripts/analytics/dashboards/constants.js +++ b/ee/app/assets/javascripts/analytics/dashboards/constants.js @@ -235,11 +235,11 @@ export const DORA_PERFORMERS_SCORE_METRICS = [ ]; export const DORA_PERFORMERS_SCORE_DEFAULT_PANEL_TITLE = s__( - 'DORA4Metrics|Total projects by DORA performers score', + 'DORA4Metrics|Total projects with DORA performers score', ); export const DORA_PERFORMERS_SCORE_PANEL_TITLE_WITH_PROJECTS_COUNT = s__( - 'DORA4Metrics|Total projects (%{count}) by DORA performers score for %{groupName} group', + 'DORA4Metrics|Total projects (%{count}) with DORA performers score for %{groupName} group', ); export const DORA_PERFORMERS_SCORE_TOOLTIP_PROJECTS_COUNT_TITLE = (count) => diff --git a/ee/spec/frontend/analytics/dashboards/components/dora_performers_score_spec.js b/ee/spec/frontend/analytics/dashboards/components/dora_performers_score_spec.js index 098be8ceab154d4a9762bc31e23395a878c796de..a48b7fc7c9e9830ac34c5b635079789d7bc58309 100644 --- a/ee/spec/frontend/analytics/dashboards/components/dora_performers_score_spec.js +++ b/ee/spec/frontend/analytics/dashboards/components/dora_performers_score_spec.js @@ -40,17 +40,15 @@ describe('DoraPerformersScore', () => { const doraPerformanceScoreCountsSuccess = mockGraphqlDoraPerformanceScoreCountsResponse({ totalProjectsCount: mockProjectsCount, }); - const nullDoraPerformanceScoreCounts = mockGraphqlDoraPerformanceScoreCountsResponse({ - totalProjectsCount: mockProjectsCount, - mockDataResponse: mockEmptyDoraPerformersScoreResponseData, - }); const noProjectsWithDoraData = mockGraphqlDoraPerformanceScoreCountsResponse({ totalProjectsCount: mockProjectsCount, noDoraDataProjectsCount: mockProjectsCount, + mockDataResponse: mockEmptyDoraPerformersScoreResponseData, }); const higherNoDoraDataProjectsCount = mockGraphqlDoraPerformanceScoreCountsResponse({ totalProjectsCount: mockProjectsCount, noDoraDataProjectsCount: mockProjectsCount + 1, + mockDataResponse: mockEmptyDoraPerformersScoreResponseData, }); const queryError = jest.fn().mockRejectedValueOnce(new Error('Something went wrong')); const loadingErrorMessage = `Failed to load DORA performance scores for Namespace: ${fullPath}`; @@ -64,7 +62,7 @@ describe('DoraPerformersScore', () => { ]; const defaultGlFeatures = { doraPerformersScorePanel: true }; const panelTitleWithProjectsCount = (projectsCount = mockProjectsCount) => - `Total projects (${projectsCount}) by DORA performers score for ${groupName} group`; + `Total projects (${projectsCount}) with DORA performers score for ${groupName} group`; let wrapper; let mockApollo; @@ -143,21 +141,31 @@ describe('DoraPerformersScore', () => { }); describe('when projects with no DORA data have been excluded', () => { - it.each` - noDoraDataProjectsCount | tooltipText - ${10} | ${'Excluding 10 projects with no DORA metrics'} - ${1} | ${'Excluding 1 project with no DORA metrics'} + describe.each` + totalProjectsCount | noDoraDataProjectsCount | projectsCountWithDoraData | tooltipText + ${20} | ${10} | ${10} | ${'Excluding 10 projects with no DORA metrics'} + ${5} | ${1} | ${4} | ${'Excluding 1 project with no DORA metrics'} `( 'renders tooltip in panel title with correct number of excluded projects', - async ({ noDoraDataProjectsCount, tooltipText }) => { - await createWrapper({ - doraPerformanceScoreCountsHandler: mockGraphqlDoraPerformanceScoreCountsResponse({ - totalProjectsCount: mockProjectsCount, - noDoraDataProjectsCount, - }), + ({ totalProjectsCount, noDoraDataProjectsCount, projectsCountWithDoraData, tooltipText }) => { + beforeEach(async () => { + await createWrapper({ + doraPerformanceScoreCountsHandler: mockGraphqlDoraPerformanceScoreCountsResponse({ + totalProjectsCount, + noDoraDataProjectsCount, + }), + }); }); - expect(findExcludedProjectsTooltip().value).toBe(tooltipText); + it('renders panel title with correct total projects count with DORA data', () => { + expect(findDoraPerformersScorePanelTitle().text()).toBe( + panelTitleWithProjectsCount(projectsCountWithDoraData), + ); + }); + + it('renders tooltip in panel title with correct number of excluded projects', () => { + expect(findExcludedProjectsTooltip().value).toBe(tooltipText); + }); }, ); }); @@ -178,10 +186,9 @@ describe('DoraPerformersScore', () => { }); describe.each` - emptyState | response - ${'high/medium/low score counts are null'} | ${nullDoraPerformanceScoreCounts} - ${'noDoraDataProjectsCount === projectsCount'} | ${noProjectsWithDoraData} - ${'noDoraDataProjectsCount > projectsCount'} | ${higherNoDoraDataProjectsCount} + emptyState | response + ${'noDoraDataProjectsCount === totalProjectsCount'} | ${noProjectsWithDoraData} + ${'noDoraDataProjectsCount > totalProjectsCount'} | ${higherNoDoraDataProjectsCount} `('when $emptyState', ({ response }) => { beforeEach(async () => { await createWrapper({ doraPerformanceScoreCountsHandler: response }); @@ -192,8 +199,8 @@ describe('DoraPerformersScore', () => { expect(wrapper.findByText(noDataMessage).exists()).toBe(true); }); - it('renders panel title with total project count', () => { - expect(findDoraPerformersScorePanelTitle().text()).toBe(panelTitleWithProjectsCount()); + it('renders panel title with `0` projects with DORA data', () => { + expect(findDoraPerformersScorePanelTitle().text()).toBe(panelTitleWithProjectsCount(0)); }); it('does not render panel title tooltip', () => { @@ -221,7 +228,7 @@ describe('DoraPerformersScore', () => { }); it('renders default panel title', () => { - expect(wrapper.findByText('Total projects by DORA performers score').exists()).toBe(true); + expect(wrapper.findByText('Total projects with DORA performers score').exists()).toBe(true); }); it('does not render panel title tooltip', () => { diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 1a66cb6056469579f64f43c638390343da2269bc..cf1c914f4fd8b4819ce04e5b78ef275c4d11bb2b 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -15199,10 +15199,10 @@ msgstr "" msgid "DORA4Metrics|Took more than 7 days to restore service when a service incident or a defect that impacts users occurs." msgstr "" -msgid "DORA4Metrics|Total projects (%{count}) by DORA performers score for %{groupName} group" +msgid "DORA4Metrics|Total projects (%{count}) with DORA performers score for %{groupName} group" msgstr "" -msgid "DORA4Metrics|Total projects by DORA performers score" +msgid "DORA4Metrics|Total projects with DORA performers score" msgstr "" msgid "DORA4Metrics|Value Streams Dashboard"