From 8fc054c0eeae08726c5e1fcd67c399afedc0e31a Mon Sep 17 00:00:00 2001 From: David Cho-Lerat Date: Wed, 26 Jul 2023 16:15:33 +0200 Subject: [PATCH] SONAR-19157 Remove extra bottom separator for Application failed conditions --- .../overview/branches/QualityGatePanel.tsx | 21 +++-- .../branches/QualityGatePanelSection.tsx | 32 ++----- .../QualityGatePanelSection-test.tsx | 84 +++++++++++++++++++ 3 files changed, 104 insertions(+), 33 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx diff --git a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx index bdea28e3c36..c31b5cc7f42 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx @@ -17,6 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + import { BasicSeparator, Card, DeferredSpinner } from 'design-system'; import { flatMap } from 'lodash'; import * as React from 'react'; @@ -49,18 +50,22 @@ export function QualityGatePanel(props: QualityGatePanelProps) { const overallLevel = qgStatuses.map((s) => s.status).includes('ERROR') ? 'ERROR' : 'OK'; const success = overallLevel === 'OK'; + const failedQgStatuses = qgStatuses.filter((qgStatus) => qgStatus.failedConditions.length > 0); + const overallFailedConditionsCount = qgStatuses.reduce( (acc, qgStatus) => acc + qgStatus.failedConditions.length, 0 ); - const nonCaycProjectsInApp = isApplication(component.qualifier) + const isApp = isApplication(component.qualifier); + + const nonCaycProjectsInApp = isApp ? qgStatuses .filter(({ caycStatus }) => caycStatus === CaycStatus.NonCompliant) .sort(({ name: a }, { name: b }) => a.localeCompare(b, undefined, { sensitivity: 'base' })) : []; - const overCompliantCaycProjectsInApp = isApplication(component.qualifier) + const overCompliantCaycProjectsInApp = isApp ? qgStatuses .filter(({ caycStatus }) => caycStatus === CaycStatus.OverCompliant) .sort(({ name: a }, { name: b }) => a.localeCompare(b, undefined, { sensitivity: 'base' })) @@ -91,12 +96,12 @@ export function QualityGatePanel(props: QualityGatePanelProps) { {!success && } - {(overallFailedConditionsCount > 0 || - qgStatuses.some(({ caycStatus }) => caycStatus !== CaycStatus.Compliant)) && ( + {overallFailedConditionsCount > 0 && (
- {qgStatuses.map((qgStatus) => ( + {failedQgStatuses.map((qgStatus, qgStatusIdx) => ( @@ -124,7 +129,7 @@ export function QualityGatePanel(props: QualityGatePanelProps) { {qgStatuses.length === 1 && qgStatuses[0].caycStatus === CaycStatus.NonCompliant && - !isApplication(component.qualifier) && ( + !isApp && ( @@ -132,7 +137,7 @@ export function QualityGatePanel(props: QualityGatePanelProps) { {qgStatuses.length === 1 && qgStatuses[0].caycStatus === CaycStatus.OverCompliant && - !isApplication(component.qualifier) && ( + !isApp && ( diff --git a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx index daed4ad5e35..6a3379d9de9 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx @@ -23,17 +23,16 @@ import * as React from 'react'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { isDiffMetric } from '../../../helpers/measures'; import { BranchLike } from '../../../types/branch-like'; -import { isApplication } from '../../../types/component'; import { QualityGateStatus, QualityGateStatusConditionEnhanced, } from '../../../types/quality-gates'; -import { CaycStatus, Component } from '../../../types/types'; import QualityGateConditions from '../components/QualityGateConditions'; export interface QualityGatePanelSectionProps { branchLike?: BranchLike; - component: Pick; + isApplication?: boolean; + isLastStatus?: boolean; qgStatus: QualityGateStatus; } @@ -55,37 +54,19 @@ function splitConditions( } export function QualityGatePanelSection(props: QualityGatePanelSectionProps) { - const { component, qgStatus } = props; + const { isApplication, isLastStatus, qgStatus } = props; const [collapsed, setCollapsed] = React.useState(false); const toggle = React.useCallback(() => { setCollapsed(!collapsed); }, [collapsed]); - /* - * Show if project has failed conditions or that - * it is a single non-cayc project - * In the context of an App, only show projects with failed conditions - */ - if ( - !( - qgStatus.failedConditions.length > 0 || - (qgStatus.caycStatus !== CaycStatus.Compliant && !isApplication(component.qualifier)) - ) - ) { - return null; - } - const [newCodeFailedConditions, overallFailedConditions] = splitConditions( qgStatus.failedConditions ); - const collapsible = isApplication(component.qualifier); - const showSectionTitles = - isApplication(component.qualifier) || - qgStatus.caycStatus !== CaycStatus.Compliant || - (overallFailedConditions.length > 0 && newCodeFailedConditions.length > 0); + isApplication || (overallFailedConditions.length > 0 && newCodeFailedConditions.length > 0); const toggleLabel = collapsed ? translateWithParameters('overview.quality_gate.show_project_conditions_x', qgStatus.name) @@ -151,7 +132,7 @@ export function QualityGatePanelSection(props: QualityGatePanelSectionProps) { return ( <> - {collapsible ? ( + {isApplication ? ( <> - + + {(!isLastStatus || collapsed) && } ) : ( renderFailedConditions() diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx new file mode 100644 index 00000000000..05d84f0e223 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx @@ -0,0 +1,84 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { screen } from '@testing-library/react'; +import * as React from 'react'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; +import { MetricKey } from '../../../../types/metrics'; +import { CaycStatus, Status } from '../../../../types/types'; +import QualityGatePanelSection, { QualityGatePanelSectionProps } from '../QualityGatePanelSection'; + +const failedConditions = [ + { + level: 'ERROR' as Status, + measure: { + metric: { + id: 'metricId1', + key: 'metricKey1', + name: 'metricName1', + type: 'metricType1', + }, + }, + metric: MetricKey.new_coverage, + op: 'op1', + }, + { + level: 'ERROR' as Status, + measure: { + metric: { + id: 'metricId2', + key: 'metricKey2', + name: 'metricName2', + type: 'metricType2', + }, + }, + metric: MetricKey.security_hotspots, + op: 'op2', + }, +]; + +const qgStatus = { + caycStatus: CaycStatus.Compliant, + failedConditions, + key: 'qgStatusKey', + name: 'qgStatusName', + status: 'ERROR' as Status, +}; + +it('should render correctly for an application with 1 new code condition and 1 overall code condition', async () => { + renderQualityGatePanelSection(); + + expect(await screen.findByText('quality_gates.conditions.new_code_1')).toBeInTheDocument(); + expect(await screen.findByText('quality_gates.conditions.overall_code_1')).toBeInTheDocument(); +}); + +it('should render correctly for a project with 1 new code condition', () => { + renderQualityGatePanelSection({ + isApplication: false, + qgStatus: { ...qgStatus, failedConditions: [failedConditions[0]] }, + }); + + expect(screen.queryByText('quality_gates.conditions.new_code_1')).not.toBeInTheDocument(); + expect(screen.queryByText('quality_gates.conditions.overall_code_1')).not.toBeInTheDocument(); +}); + +function renderQualityGatePanelSection(props: Partial = {}) { + return renderComponent(); +} -- 2.39.5