* 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 <div>Meta top bar</div>;
+interface Props {
+ branchLike: BranchLike;
+ measures: MeasureEnhanced[];
+}
+
+export default function MetaTopBar({ branchLike, measures }: Readonly<Props>) {
+ const intl = useIntl();
+ const isPR = isPullRequest(branchLike);
+
+ const leftSection = (
+ <div>
+ {isPR ? (
+ <>
+ <strong className="sw-body-sm-highlight sw-mr-1">
+ {formatMeasure(
+ getLeakValue(findMeasure(measures, MetricKey.new_lines)),
+ MetricType.ShortInteger,
+ ) ?? '0'}
+ </strong>
+ {intl.formatMessage({ id: 'metric.new_lines.name' })}
+ </>
+ ) : null}
+ </div>
+ );
+ const rightSection = (
+ <div>
+ {branchLike.analysisDate
+ ? intl.formatMessage(
+ {
+ id: 'overview.last_analysis_x',
+ },
+ {
+ date: (
+ <strong className="sw-body-sm-highlight">
+ <DateFromNow date={branchLike.analysisDate} />
+ </strong>
+ ),
+ },
+ )
+ : null}
+ </div>
+ );
+
+ return (
+ <div className="sw-flex sw-justify-between sw-whitespace-nowrap sw-body-sm">
+ {leftSection}
+ {rightSection}
+ </div>
+ );
}
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;
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(
return (
<CenteredLayout>
<div className="it__pr-overview sw-mt-12">
- <MetaTopBar />
+ <MetaTopBar branchLike={branchLike} measures={measures} />
<BasicSeparator className="sw-my-4" />
+ {ignoredConditions && <IgnoredConditionWarning />}
+
<div className="sw-flex sw-flex-col sw-mr-12 width-30">
<Card>
{status && (
</HelpTooltip>
</div>
- {ignoredConditions && <IgnoredConditionWarning />}
-
- {status === 'OK' && failedConditions.length === 0 && <QualityGateStatusPassedView />}
+ {status === Status.OK && failedConditions.length === 0 && (
+ <QualityGateStatusPassedView />
+ )}
- {status !== 'OK' && <BasicSeparator />}
+ {status !== Status.OK && <BasicSeparator />}
{failedConditions.length > 0 && (
<div>
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';
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,
}),
],
},
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(),
}),
};
});
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 () => {
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();
Duplication = 'DUPLICATION',
}
+export enum Status {
+ OK = 'OK',
+ ERROR = 'ERROR',
+}
+
const MEASUREMENTS_MAP = {
[MeasurementType.Coverage]: {
metric: MetricKey.coverage,
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}