From 382f8ff2a116b1a1c5adaccb2b07be7047b7b8c1 Mon Sep 17 00:00:00 2001 From: stanislavh Date: Fri, 13 Oct 2023 13:47:03 +0200 Subject: [PATCH] SONAR-20742 Implement Overview header --- .../apps/overview/components/MetaTopBar.tsx | 59 ++++++++++++++++++- .../pullRequests/PullRequestOverview.tsx | 19 +++--- .../__tests__/PullRequestOverview-it.tsx | 34 +++++------ .../src/main/js/apps/overview/utils.ts | 5 ++ .../resources/org/sonar/l10n/core.properties | 1 + 5 files changed, 90 insertions(+), 28 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/overview/components/MetaTopBar.tsx b/server/sonar-web/src/main/js/apps/overview/components/MetaTopBar.tsx index 25a1d43e52f..a7ea045a677 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/MetaTopBar.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/MetaTopBar.tsx @@ -18,7 +18,62 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import React from 'react'; +import { useIntl } from 'react-intl'; +import DateFromNow from '../../../components/intl/DateFromNow'; +import { getLeakValue } from '../../../components/measure/utils'; +import { isPullRequest } from '../../../helpers/branch-like'; +import { findMeasure, formatMeasure } from '../../../helpers/measures'; +import { BranchLike } from '../../../types/branch-like'; +import { MetricKey, MetricType } from '../../../types/metrics'; +import { MeasureEnhanced } from '../../../types/types'; -export default function MetaTopBar() { - return
Meta top bar
; +interface Props { + branchLike: BranchLike; + measures: MeasureEnhanced[]; +} + +export default function MetaTopBar({ branchLike, measures }: Readonly) { + const intl = useIntl(); + const isPR = isPullRequest(branchLike); + + const leftSection = ( +
+ {isPR ? ( + <> + + {formatMeasure( + getLeakValue(findMeasure(measures, MetricKey.new_lines)), + MetricType.ShortInteger, + ) ?? '0'} + + {intl.formatMessage({ id: 'metric.new_lines.name' })} + + ) : null} +
+ ); + const rightSection = ( +
+ {branchLike.analysisDate + ? intl.formatMessage( + { + id: 'overview.last_analysis_x', + }, + { + date: ( + + + + ), + }, + ) + : null} +
+ ); + + return ( +
+ {leftSection} + {rightSection} +
+ ); } diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx index c02df843b49..ae2114dac0f 100644 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx +++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx @@ -53,7 +53,7 @@ import QualityGateStatusHeader from '../components/QualityGateStatusHeader'; import QualityGateStatusPassedView from '../components/QualityGateStatusPassedView'; import SonarLintPromotion from '../components/SonarLintPromotion'; import '../styles.css'; -import { MeasurementType, PR_METRICS } from '../utils'; +import { MeasurementType, PR_METRICS, Status } from '../utils'; interface Props { branchLike: PullRequest; @@ -74,7 +74,10 @@ export default function PullRequestOverview(props: Props) { const metricKeys = conditions !== undefined ? // Also load metrics that apply to failing QG conditions. - uniq([...PR_METRICS, ...conditions.filter((c) => c.level !== 'OK').map((c) => c.metric)]) + uniq([ + ...PR_METRICS, + ...conditions.filter((c) => c.level !== Status.OK).map((c) => c.metric), + ]) : PR_METRICS; getMeasuresWithMetrics(component.key, metricKeys, getBranchLikeQuery(branchLike)).then( @@ -117,9 +120,11 @@ export default function PullRequestOverview(props: Props) { return (
- + + {ignoredConditions && } +
{status && ( @@ -147,11 +152,11 @@ export default function PullRequestOverview(props: Props) {
- {ignoredConditions && } - - {status === 'OK' && failedConditions.length === 0 && } + {status === Status.OK && failedConditions.length === 0 && ( + + )} - {status !== 'OK' && } + {status !== Status.OK && } {failedConditions.length > 0 && (
diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx index a7260b8320b..26af400499a 100644 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx +++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx @@ -23,15 +23,12 @@ import { getQualityGateProjectStatus } from '../../../../api/quality-gates'; import CurrentUserContextProvider from '../../../../app/components/current-user/CurrentUserContextProvider'; import { mockPullRequest } from '../../../../helpers/mocks/branch-like'; import { mockComponent } from '../../../../helpers/mocks/component'; -import { - mockQualityGateProjectCondition, - mockQualityGateStatusCondition, -} from '../../../../helpers/mocks/quality-gates'; -import { mockLoggedInUser, mockMetric, mockPeriod } from '../../../../helpers/testMocks'; +import { mockQualityGateProjectCondition } from '../../../../helpers/mocks/quality-gates'; +import { mockLoggedInUser, mockMeasure, mockMetric } from '../../../../helpers/testMocks'; import { renderComponent } from '../../../../helpers/testReactTestingUtils'; import { ComponentPropsType } from '../../../../helpers/testUtils'; import { ComponentQualifier } from '../../../../types/component'; -import { MetricKey } from '../../../../types/metrics'; +import { MetricKey, MetricType } from '../../../../types/metrics'; import { CaycStatus } from '../../../../types/types'; import PullRequestOverview from '../PullRequestOverview'; @@ -44,20 +41,17 @@ jest.mock('../../../../api/measures', () => { name: '', qualifier: ComponentQualifier.Project, measures: [ - mockQualityGateStatusCondition({ - error: '1.0', + mockMeasure({ metric: MetricKey.new_coverage, - period: 1, }), - mockQualityGateStatusCondition({ - error: '1.0', + mockMeasure({ metric: MetricKey.duplicated_lines, - period: 1, }), - mockQualityGateStatusCondition({ - error: '3', + mockMeasure({ metric: MetricKey.new_bugs, - period: 1, + }), + mockMeasure({ + metric: MetricKey.new_lines, }), ], }, @@ -66,12 +60,12 @@ jest.mock('../../../../api/measures', () => { mockMetric({ key: MetricKey.duplicated_lines, }), + mockMetric({ key: MetricKey.new_lines, type: MetricType.ShortInteger }), mockMetric({ key: MetricKey.new_bugs, - type: 'INT', + type: MetricType.Integer, }), ], - period: mockPeriod(), }), }; }); @@ -127,6 +121,8 @@ it('should render correctly for a passed QG', async () => { renderPullRequestOverview(); await waitFor(async () => expect(await screen.findByText('metric.level.OK')).toBeInTheDocument()); + expect(screen.getByText('metric.new_lines.name')).toBeInTheDocument(); + expect(screen.getByText(/overview.last_analysis_x/)).toBeInTheDocument(); }); it('should render correctly if conditions are ignored', async () => { @@ -172,11 +168,11 @@ it('should render correctly for a failed QG', async () => { expect(await screen.findByText('metric.level.ERROR')).toBeInTheDocument(), ); - expect(await screen.findByText('metric.new_coverage.name')).toBeInTheDocument(); + expect(await screen.findByText('1.0% metric.new_coverage.name')).toBeInTheDocument(); expect(await screen.findByText('quality_gates.operator.GT 2.0%')).toBeInTheDocument(); expect( - await screen.findByText('metric.duplicated_lines.name quality_gates.conditions.new_code'), + await screen.findByText('1.0% metric.duplicated_lines.name quality_gates.conditions.new_code'), ).toBeInTheDocument(); expect(await screen.findByText('quality_gates.operator.GT 1.0%')).toBeInTheDocument(); diff --git a/server/sonar-web/src/main/js/apps/overview/utils.ts b/server/sonar-web/src/main/js/apps/overview/utils.ts index d67c362653c..abca784fab8 100644 --- a/server/sonar-web/src/main/js/apps/overview/utils.ts +++ b/server/sonar-web/src/main/js/apps/overview/utils.ts @@ -122,6 +122,11 @@ export enum MeasurementType { Duplication = 'DUPLICATION', } +export enum Status { + OK = 'OK', + ERROR = 'ERROR', +} + const MEASUREMENTS_MAP = { [MeasurementType.Coverage]: { metric: MetricKey.coverage, diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 4751ffc5ec9..fc35a833d05 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -3766,6 +3766,7 @@ overview.max_new_code_period_from_x=Max New Code from: {0} overview.started_x=Started {0} overview.new_code=New Code overview.overall_code=Overall Code +overview.last_analysis_x=Last analysis {date} overview.previous_analysis_x=Previous analysis was {0} overview.started_on_x=Started on {0} overview.previous_analysis_on_x=Previous analysis on {0} -- 2.39.5