import { translate, translateWithParameters } from '../../../helpers/l10n';
import { localizeMetric } from '../../../helpers/measures';
import { BranchLike } from '../../../types/branch-like';
+import { MetricKey } from '../../../types/metrics';
import {
Analysis as AnalysisType,
GraphType,
[measuresHistory, analyses.length],
);
+ const qualityGateStatuses = React.useMemo(
+ () =>
+ measuresHistory
+ .find(({ metric }) => metric === MetricKey.alert_status)
+ ?.history.slice(-MAX_ANALYSES_NB)
+ .reverse(),
+ [measuresHistory],
+ );
+
return (
<div className="sw-mt-8">
<PageTitle as="h2" text={translate('overview.activity')} />
analysis={analysis}
isFirstAnalysis={index === analyses.length - 1}
qualifier={component.qualifier}
+ qualityGateStatus={qualityGateStatuses?.[index]?.value}
variations={analysisVariations[index]}
/>
{index !== displayedAnalyses.length - 1 && <BasicSeparator className="sw-my-3" />}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { QualityGateIndicator } from 'design-system';
import { sortBy } from 'lodash';
import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import { translate } from '../../../helpers/l10n';
import { ComponentQualifier } from '../../../types/component';
ProjectAnalysisEventCategory,
Analysis as TypeAnalysis,
} from '../../../types/project-activity';
+import { Status } from '../../../types/types';
import { AnalysisVariations } from './AnalysisVariations';
import Event from './Event';
analysis: TypeAnalysis;
isFirstAnalysis?: boolean;
qualifier: string;
+ qualityGateStatus?: string;
variations?: AnalysisMeasuresVariations;
}
export function Analysis(props: Readonly<AnalysisProps>) {
- const { analysis, isFirstAnalysis, qualifier, variations } = props;
+ const { analysis, isFirstAnalysis, qualifier, qualityGateStatus, variations } = props;
const sortedEvents = sortBy(
- analysis.events,
+ analysis.events.filter((event) => event.category !== ProjectAnalysisEventCategory.QualityGate),
(event) => {
switch (event.category) {
case ProjectAnalysisEventCategory.Version:
return (
<div className="sw-body-sm">
- <div className="sw-body-sm-highlight sw-mb-1">
- <DateTimeFormatter date={analysis.date} />
+ <div className="sw-flex sw-justify-between sw-mb-1">
+ <div className="sw-body-sm-highlight">
+ <DateTimeFormatter date={analysis.date} />
+ </div>
+ {qualityGateStatus !== undefined && (
+ <div className="sw-flex sw-items-center">
+ <FormattedMessage
+ id="overview.quality_gate_x"
+ values={{
+ 0: (
+ <QualityGateIndicator
+ className="sw-mx-2"
+ size="sm"
+ status={qualityGateStatus as Status}
+ />
+ ),
+ }}
+ />
+ <span className="sw-body-sm-highlight">
+ <FormattedMessage id={`metric.level.${qualityGateStatus}`} />
+ </span>
+ </div>
+ )}
</div>
{sortedEvents.length > 0
it('should render correctly', async () => {
renderActivityPanel();
- expect(await screen.findByText('event.quality_gate.ERROR')).toBeInTheDocument();
+ expect(await screen.findAllByText('metric.level.ERROR')).toHaveLength(2);
+ expect(screen.getAllByText('metric.level.OK')).toHaveLength(2);
expect(screen.getByRole('status', { name: 'v1.0' })).toBeInTheDocument();
expect(screen.getByText(/event.category.OTHER/)).toBeInTheDocument();
expect(screen.getByText(/event.category.DEFINITION_CHANGE/)).toBeInTheDocument();
mockHistoryItem({ date: parseDate('2020-10-27T18:33:50+0200'), value: '14.2' }),
],
}),
+ mockMeasureHistory({
+ metric: MetricKey.alert_status,
+ history: [
+ mockHistoryItem({ date: parseDate('2018-10-27T10:21:15+0200'), value: 'OK' }),
+ mockHistoryItem({ date: parseDate('2018-10-27T12:21:15+0200'), value: 'ERROR' }),
+ mockHistoryItem({ date: parseDate('2020-10-27T16:33:50+0200'), value: 'ERROR' }),
+ mockHistoryItem({ date: parseDate('2020-10-27T18:33:50+0200'), value: 'OK' }),
+ ],
+ }),
];
const mockedMetrics = [mockMetric()];
const mockedAnalysis = [