* 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';
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' }))
{!success && <BasicSeparator />}
- {(overallFailedConditionsCount > 0 ||
- qgStatuses.some(({ caycStatus }) => caycStatus !== CaycStatus.Compliant)) && (
+ {overallFailedConditionsCount > 0 && (
<div data-test="overview__quality-gate-conditions">
- {qgStatuses.map((qgStatus) => (
+ {failedQgStatuses.map((qgStatus, qgStatusIdx) => (
<QualityGatePanelSection
- component={component}
+ isApplication={isApp}
+ isLastStatus={qgStatusIdx === failedQgStatuses.length - 1}
key={qgStatus.key}
qgStatus={qgStatus}
/>
{qgStatuses.length === 1 &&
qgStatuses[0].caycStatus === CaycStatus.NonCompliant &&
- !isApplication(component.qualifier) && (
+ !isApp && (
<Card className="sw-mt-4 sw-body-sm">
<CleanAsYouCodeWarning component={component} />
</Card>
{qgStatuses.length === 1 &&
qgStatuses[0].caycStatus === CaycStatus.OverCompliant &&
- !isApplication(component.qualifier) && (
+ !isApp && (
<Card className="sw-mt-4 sw-body-sm">
<CleanAsYouCodeWarningOverCompliant component={component} />
</Card>
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<Component, 'key' | 'qualifier' | 'qualityGate'>;
+ isApplication?: boolean;
+ isLastStatus?: boolean;
qgStatus: QualityGateStatus;
}
}
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)
return (
<>
- {collapsible ? (
+ {isApplication ? (
<>
<Accordion
ariaLabel={toggleLabel}
{renderFailedConditions()}
</Accordion>
- <BasicSeparator />
+
+ {(!isLastStatus || collapsed) && <BasicSeparator />}
</>
) : (
renderFailedConditions()
--- /dev/null
+/*
+ * 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<QualityGatePanelSectionProps> = {}) {
+ return renderComponent(<QualityGatePanelSection isApplication qgStatus={qgStatus} {...props} />);
+}