aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src
diff options
context:
space:
mode:
authorWouter Admiraal <wouter.admiraal@sonarsource.com>2019-12-19 10:58:37 +0100
committerSonarTech <sonartech@sonarsource.com>2020-02-10 20:46:15 +0100
commit822405efd0ddde6b1e123c40cc1255e9b57c05f8 (patch)
tree5896c4f40e0240c563f48370b90b2450a0a061a8 /server/sonar-web/src
parent914f3a4e69b2d5896bf71e71ee63f45d45303efe (diff)
downloadsonarqube-822405efd0ddde6b1e123c40cc1255e9b57c05f8.tar.gz
sonarqube-822405efd0ddde6b1e123c40cc1255e9b57c05f8.zip
SONAR-12632 SONAR-12678 Implement new Overview layout
Diffstat (limited to 'server/sonar-web/src')
-rw-r--r--server/sonar-web/src/main/js/app/styles/init/tables.css2
-rw-r--r--server/sonar-web/src/main/js/app/theme.js4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/ActivityPanel.tsx141
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/Analysis.tsx (renamed from server/sonar-web/src/main/js/apps/overview/events/Analysis.tsx)6
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/ApplicationLeakPeriodInfo.tsx21
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/BranchOverview.tsx410
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx115
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/DebtValue.tsx66
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/DrilldownMeasureValue.tsx64
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/Event.tsx (renamed from server/sonar-web/src/main/js/apps/overview/events/Event.tsx)4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanel.tsx265
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/NoCodeWarning.tsx90
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx125
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx79
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-test.tsx83
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/Analysis-test.tsx (renamed from server/sonar-web/src/main/js/apps/overview/events/__tests__/AnalysesList-test.tsx)36
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx349
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverviewRenderer-test.tsx46
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/DebtValue-test.tsx (renamed from server/sonar-web/src/main/js/apps/overview/main/__tests__/Coverage-test.tsx)42
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/DrilldownMeasureValue-test.tsx42
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/Event-test.tsx (renamed from server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx)16
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanel-test.tsx82
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/NoCodeWarning-test.tsx68
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanel-test.tsx83
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ActivityPanel-test.tsx.snap349
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Analysis-test.tsx.snap81
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ApplicationLeakPeriodInfo-test.tsx.snap19
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverview-test.tsx.snap1702
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverviewRenderer-test.tsx.snap386
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DebtValue-test.tsx.snap65
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DrilldownMeasureValue-test.tsx.snap47
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Event-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap25
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap5943
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ProjectLeakPeriodInfo-test.tsx.snap115
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap625
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap436
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/App.tsx29
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx122
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx341
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx69
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx85
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx179
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.tsx72
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap337
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap790
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.tsx.snap110
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/AnalysesList.tsx146
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/AnalysesList-test.tsx.snap18
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.tsx.snap41
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/Bugs.tsx135
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx136
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx193
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx194
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/VulnerabilitiesAndHotspots.tsx128
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/__tests__/Bugs-test.tsx80
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/__tests__/CodeSmells-test.tsx109
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/__tests__/Duplications-test.tsx88
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/__tests__/VulnerabilitiesAndHotspots-test.tsx115
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Bugs-test.tsx.snap229
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/CodeSmells-test.tsx.snap295
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Coverage-test.tsx.snap251
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Duplications-test.tsx.snap227
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/VulnerabilitiesAndHotspots-test.tsx.snap307
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/enhance.tsx227
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx17
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaContainer-test.tsx.snap81
-rw-r--r--server/sonar-web/src/main/js/apps/overview/styles.css529
-rw-r--r--server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx (renamed from server/sonar-web/src/main/js/apps/overview/events/__tests__/Analysis-test.tsx)21
72 files changed, 12344 insertions, 5462 deletions
diff --git a/server/sonar-web/src/main/js/app/styles/init/tables.css b/server/sonar-web/src/main/js/app/styles/init/tables.css
index dd34a6cc3a8..75431350415 100644
--- a/server/sonar-web/src/main/js/app/styles/init/tables.css
+++ b/server/sonar-web/src/main/js/app/styles/init/tables.css
@@ -269,7 +269,7 @@ table.data.boxed-padding > thead + tbody > tr:first-child > td {
}
table.data.zebra-hover > tbody > tr:hover {
- background-color: #ecf6fe !important;
+ background-color: var(--rowHoverHighlight) !important;
}
table.data.zebra > tbody > tr.selected {
diff --git a/server/sonar-web/src/main/js/app/theme.js b/server/sonar-web/src/main/js/app/theme.js
index 48b05a12810..7f302abda3b 100644
--- a/server/sonar-web/src/main/js/app/theme.js
+++ b/server/sonar-web/src/main/js/app/theme.js
@@ -55,6 +55,9 @@ module.exports = {
globalNavBarBg: '#262626',
+ // table
+ rowHoverHighlight: '#ecf6fe',
+
// fonts
baseFontColor: '#444',
secondFontColor: '#777',
@@ -145,6 +148,7 @@ module.exports = {
mediumFontSize: '14px',
bigFontSize: '16px',
hugeFontSize: '24px',
+ giganticFontSize: '36px',
hugeControlHeight: `${5 * grid}px`,
largeControlHeight: `${4 * grid}px`,
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/ActivityPanel.tsx b/server/sonar-web/src/main/js/apps/overview/branches/ActivityPanel.tsx
new file mode 100644
index 00000000000..6118f97707d
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/ActivityPanel.tsx
@@ -0,0 +1,141 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 * as React from 'react';
+import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
+import { parseDate } from 'sonar-ui-common/helpers/dates';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import GraphsHeader from '../../../components/activity-graph/GraphsHeader';
+import GraphsHistory from '../../../components/activity-graph/GraphsHistory';
+import {
+ DEFAULT_GRAPH,
+ generateSeries,
+ getDisplayedHistoryMetrics,
+ splitSeriesInGraphs
+} from '../../../components/activity-graph/utils';
+import ActivityLink from '../../../components/common/ActivityLink';
+import { BranchLike } from '../../../types/branch-like';
+import { GraphType, MeasureHistory } from '../../../types/project-activity';
+import Analysis from './Analysis';
+
+export interface ActivityPanelProps {
+ analyses?: T.Analysis[];
+ branchLike?: BranchLike;
+ component: Pick<T.Component, 'key' | 'qualifier'>;
+ graph?: GraphType;
+ leakPeriodDate?: Date;
+ loading?: boolean;
+ measuresHistory: MeasureHistory[];
+ metrics: T.Metric[];
+ onGraphChange: (graph: GraphType) => void;
+}
+
+const MAX_ANALYSES_NB = 5;
+const MAX_GRAPH_NB = 2;
+const MAX_SERIES_PER_GRAPH = 3;
+
+export function ActivityPanel(props: ActivityPanelProps) {
+ const {
+ analyses = [],
+ branchLike,
+ component,
+ graph = DEFAULT_GRAPH,
+ leakPeriodDate,
+ loading,
+ measuresHistory,
+ metrics
+ } = props;
+
+ const series = generateSeries(
+ measuresHistory,
+ graph,
+ metrics,
+ getDisplayedHistoryMetrics(graph, [])
+ );
+ const graphs = splitSeriesInGraphs(series, MAX_GRAPH_NB, MAX_SERIES_PER_GRAPH);
+ const parsedAnalyses = analyses.map(a => ({ ...a, date: parseDate(a.date) }));
+ let shownLeakPeriodDate;
+ if (leakPeriodDate !== undefined) {
+ const startDate = measuresHistory.reduce((oldest: Date, { history }) => {
+ if (history.length > 0) {
+ const date = parseDate(history[0].date);
+ return oldest.getTime() > date.getTime() ? date : oldest;
+ } else {
+ return oldest;
+ }
+ }, new Date());
+ shownLeakPeriodDate =
+ startDate.getTime() > leakPeriodDate.getTime() ? startDate : leakPeriodDate;
+ }
+
+ const filteredAnalyses = analyses.filter(a => a.events.length > 0).slice(0, MAX_ANALYSES_NB);
+
+ return (
+ <div className="overview-panel big-spacer-top" data-test="overview__activity-panel">
+ <h2 className="overview-panel-title">{translate('overview.activity')}</h2>
+
+ <div className="overview-panel-content">
+ <div className="display-flex-row">
+ <div className="display-flex-column flex-1">
+ <div aria-hidden={true} className="overview-panel-padded display-flex-column flex-1">
+ <GraphsHeader graph={graph} metrics={metrics} updateGraph={props.onGraphChange} />
+ <GraphsHistory
+ analyses={parsedAnalyses}
+ graph={graph}
+ graphs={graphs}
+ leakPeriodDate={shownLeakPeriodDate}
+ loading={Boolean(loading)}
+ measuresHistory={measuresHistory}
+ series={series}
+ />
+ </div>
+
+ <div className="overview-panel-padded bordered-top text-right">
+ <ActivityLink branchLike={branchLike} component={component.key} graph={graph} />
+ </div>
+ </div>
+
+ <div className="overview-panel-padded bordered-left width-30">
+ <div data-test="overview__activity-analyses">
+ <DeferredSpinner
+ className="spacer-top spacer-left"
+ loading={analyses.length === 0 && loading}>
+ {analyses.length === 0 ? (
+ <p className="spacer-top spacer-left note">{translate('no_results')}</p>
+ ) : (
+ <ul className="spacer-top spacer-left">
+ {filteredAnalyses.map(analysis => (
+ <Analysis
+ analysis={analysis}
+ key={analysis.key}
+ qualifier={component.qualifier}
+ />
+ ))}
+ </ul>
+ )}
+ </DeferredSpinner>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+}
+
+export default React.memo(ActivityPanel);
diff --git a/server/sonar-web/src/main/js/apps/overview/events/Analysis.tsx b/server/sonar-web/src/main/js/apps/overview/branches/Analysis.tsx
index 78534752de0..0860bfa80c4 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/Analysis.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/Analysis.tsx
@@ -23,12 +23,12 @@ import { translate } from 'sonar-ui-common/helpers/l10n';
import DateTooltipFormatter from '../../../components/intl/DateTooltipFormatter';
import Event from './Event';
-interface Props {
+export interface AnalysisProps {
analysis: T.Analysis;
qualifier: string;
}
-export default function Analysis({ analysis, ...props }: Props) {
+export function Analysis({ analysis, ...props }: AnalysisProps) {
const sortedEvents = sortBy(
analysis.events,
// versions first
@@ -60,3 +60,5 @@ export default function Analysis({ analysis, ...props }: Props) {
</li>
);
}
+
+export default React.memo(Analysis);
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/ApplicationLeakPeriodInfo.tsx b/server/sonar-web/src/main/js/apps/overview/branches/ApplicationLeakPeriodInfo.tsx
index 1d27c582616..3505f3d96a8 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/ApplicationLeakPeriodInfo.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/ApplicationLeakPeriodInfo.tsx
@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import { translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import DateFromNow from '../../../components/intl/DateFromNow';
import { ApplicationPeriod } from '../../../types/application';
@@ -28,18 +29,18 @@ export interface ApplicationLeakPeriodInfoProps {
export function ApplicationLeakPeriodInfo({ leakPeriod }: ApplicationLeakPeriodInfoProps) {
return (
- <>
- <div className="note spacer-top">
- {translateWithParameters('overview.max_new_code_period_from_x', leakPeriod.projectName)}
- </div>
+ <div className="note spacer-top display-inline-flex-center">
<DateFromNow date={leakPeriod.date}>
- {fromNow => (
- <div className="note little-spacer-top">
- {translateWithParameters('overview.started_x', fromNow)}
- </div>
- )}
+ {fromNow => translateWithParameters('overview.started_x', fromNow)}
</DateFromNow>
- </>
+ <HelpTooltip
+ className="little-spacer-left"
+ overlay={translateWithParameters(
+ 'overview.max_new_code_period_from_x',
+ leakPeriod.projectName
+ )}
+ />
+ </div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/BranchOverview.tsx b/server/sonar-web/src/main/js/apps/overview/branches/BranchOverview.tsx
new file mode 100644
index 00000000000..6ad66b9295d
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/BranchOverview.tsx
@@ -0,0 +1,410 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { sortBy, uniq } from 'lodash';
+import * as React from 'react';
+import { parseDate, toNotSoISOString } from 'sonar-ui-common/helpers/dates';
+import { isDefined } from 'sonar-ui-common/helpers/types';
+import { getApplicationLeak } from '../../../api/application';
+import { getMeasuresAndMeta } from '../../../api/measures';
+import { getProjectActivity } from '../../../api/projectActivity';
+import { getApplicationQualityGate, getQualityGateProjectStatus } from '../../../api/quality-gates';
+import { getTimeMachineData } from '../../../api/time-machine';
+import {
+ getActivityGraph,
+ getHistoryMetrics,
+ saveActivityGraph
+} from '../../../components/activity-graph/utils';
+import {
+ getBranchLikeDisplayName,
+ getBranchLikeQuery,
+ isSameBranchLike
+} from '../../../helpers/branch-like';
+import { enhanceConditionWithMeasure, enhanceMeasuresWithMetrics } from '../../../helpers/measures';
+import { getLeakPeriod } from '../../../helpers/periods';
+import {
+ extractStatusConditionsFromApplicationStatusChildProject,
+ extractStatusConditionsFromProjectStatus
+} from '../../../helpers/qualityGates';
+import { ApplicationPeriod } from '../../../types/application';
+import { BranchLike } from '../../../types/branch-like';
+import { MetricKey } from '../../../types/metrics';
+import { GraphType, MeasureHistory } from '../../../types/project-activity';
+import { QualityGateStatus, QualityGateStatusCondition } from '../../../types/quality-gates';
+import '../styles.css';
+import { HISTORY_METRICS_LIST, METRICS } from '../utils';
+import BranchOverviewRenderer from './BranchOverviewRenderer';
+
+interface Props {
+ branchLike?: BranchLike;
+ component: T.Component;
+}
+
+interface State {
+ analyses?: T.Analysis[];
+ appLeak?: ApplicationPeriod;
+ graph: GraphType;
+ loadingHistory?: boolean;
+ loadingStatus?: boolean;
+ measures?: T.MeasureEnhanced[];
+ measuresHistory?: MeasureHistory[];
+ metrics?: T.Metric[];
+ periods?: T.Period[];
+ qgStatuses?: QualityGateStatus[];
+}
+
+export const BRANCH_OVERVIEW_ACTIVITY_GRAPH = 'sonar_branch_overview.graph';
+
+// Get all history data over the past year.
+const FROM_DATE = toNotSoISOString(new Date().setFullYear(new Date().getFullYear() - 1));
+
+export default class BranchOverview extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State;
+
+ constructor(props: Props) {
+ super(props);
+
+ const { graph } = getActivityGraph(BRANCH_OVERVIEW_ACTIVITY_GRAPH, props.component.key);
+ this.state = { graph };
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ this.loadStatus();
+ this.loadHistory();
+ }
+
+ componentDidUpdate(prevProps: Props) {
+ if (
+ this.props.component.key !== prevProps.component.key ||
+ !isSameBranchLike(this.props.branchLike, prevProps.branchLike)
+ ) {
+ this.loadStatus();
+ this.loadHistory();
+ }
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ loadStatus = () => {
+ if (this.props.component.qualifier === 'APP') {
+ this.loadApplicationStatus();
+ } else {
+ this.loadProjectStatus();
+ }
+ };
+
+ loadApplicationStatus = async () => {
+ const { branchLike, component } = this.props;
+ this.setState({ loadingStatus: true });
+
+ // Start by loading the application quality gate info, as well as the meta
+ // data for the application as a whole.
+ const appStatus = await getApplicationQualityGate({
+ application: component.key,
+ ...getBranchLikeQuery(branchLike)
+ });
+ const { measures: appMeasures, metrics, periods } = await this.loadMeasuresAndMeta(
+ component.key
+ );
+
+ // We also need to load the application leak periods separately.
+ getApplicationLeak(component.key, branchLike && getBranchLikeDisplayName(branchLike)).then(
+ leaks => {
+ if (this.mounted && leaks && leaks.length) {
+ const sortedLeaks = sortBy(leaks, leak => {
+ return new Date(leak.date);
+ });
+ this.setState({
+ appLeak: sortedLeaks[0]
+ });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ appLeak: undefined });
+ }
+ }
+ );
+
+ // We need to load the measures for each project in an application
+ // individually, in order to display all QG conditions correctly. Loading
+ // them at the parent application level will not get all the necessary
+ // information, unfortunately, as they are aggregated.
+ Promise.all(
+ appStatus.projects.map(project => {
+ return this.loadMeasuresAndMeta(
+ project.key,
+ // Only load metrics that apply to failing QG conditions; we don't
+ // need the others anyway.
+ project.conditions.filter(c => c.status !== 'OK').map(c => c.metric)
+ ).then(({ measures }) => ({
+ measures,
+ project
+ }));
+ })
+ ).then(
+ results => {
+ if (this.mounted) {
+ const qgStatuses = results.map(({ measures = [], project }) => {
+ const { key, name, status } = project;
+ const conditions = extractStatusConditionsFromApplicationStatusChildProject(project);
+ const failedConditions = this.getFailedConditions(conditions, measures);
+
+ return {
+ failedConditions,
+ key,
+ name,
+ status
+ };
+ });
+
+ this.setState({
+ loadingStatus: false,
+ measures: appMeasures,
+ metrics,
+ periods,
+ qgStatuses
+ });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loadingStatus: false, qgStatuses: undefined });
+ }
+ }
+ );
+ };
+
+ loadProjectStatus = async () => {
+ const {
+ branchLike,
+ component: { key, name }
+ } = this.props;
+ this.setState({ loadingStatus: true });
+
+ const projectStatus = await getQualityGateProjectStatus({
+ projectKey: key,
+ ...getBranchLikeQuery(branchLike)
+ });
+
+ // Get failing condition metric keys. We need measures for them as well to
+ // render them.
+ const metricKeys =
+ projectStatus.conditions !== undefined
+ ? uniq([...METRICS, ...projectStatus.conditions.map(c => c.metricKey)])
+ : METRICS;
+
+ this.loadMeasuresAndMeta(key, metricKeys).then(
+ ({ measures, metrics, periods }) => {
+ if (this.mounted && measures) {
+ const { ignoredConditions, status } = projectStatus;
+ const conditions = extractStatusConditionsFromProjectStatus(projectStatus);
+ const failedConditions = this.getFailedConditions(conditions, measures);
+
+ const qgStatus = {
+ ignoredConditions,
+ failedConditions,
+ key,
+ name,
+ status
+ };
+
+ this.setState({
+ loadingStatus: false,
+ measures,
+ metrics,
+ periods,
+ qgStatuses: [qgStatus]
+ });
+ } else if (this.mounted) {
+ this.setState({ loadingStatus: false, qgStatuses: undefined });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loadingStatus: false, qgStatuses: undefined });
+ }
+ }
+ );
+ };
+
+ loadMeasuresAndMeta = (componentKey: string, metricKeys: string[] = []) => {
+ const { branchLike } = this.props;
+
+ return getMeasuresAndMeta(componentKey, metricKeys.length > 0 ? metricKeys : METRICS, {
+ additionalFields: 'metrics,periods',
+ ...getBranchLikeQuery(branchLike)
+ }).then(({ component: { measures }, metrics, periods }) => {
+ return {
+ measures: enhanceMeasuresWithMetrics(measures || [], metrics || []),
+ metrics,
+ periods
+ };
+ });
+ };
+
+ loadHistory = () => {
+ this.setState({ loadingHistory: true });
+
+ return Promise.all([this.loadHistoryMeasures(), this.loadAnalyses()]).then(
+ this.doneLoadingHistory,
+ this.doneLoadingHistory
+ );
+ };
+
+ loadHistoryMeasures = () => {
+ const { branchLike, component } = this.props;
+ const { graph } = this.state;
+
+ const graphMetrics = getHistoryMetrics(graph, []);
+ const metrics = uniq([...HISTORY_METRICS_LIST, ...graphMetrics]);
+
+ return getTimeMachineData({
+ ...getBranchLikeQuery(branchLike),
+ from: FROM_DATE,
+ component: component.key,
+ metrics: metrics.join()
+ }).then(
+ ({ measures }) => {
+ if (this.mounted) {
+ this.setState({
+ measuresHistory: measures.map(measure => ({
+ metric: measure.metric,
+ history: measure.history.map(analysis => ({
+ date: parseDate(analysis.date),
+ value: analysis.value
+ }))
+ }))
+ });
+ }
+ },
+ () => {}
+ );
+ };
+
+ loadAnalyses = () => {
+ const { branchLike } = this.props;
+
+ return getProjectActivity({
+ ...getBranchLikeQuery(branchLike),
+ project: this.getTopLevelComponent(),
+ from: FROM_DATE
+ }).then(
+ ({ analyses }) => {
+ if (this.mounted) {
+ this.setState({
+ analyses
+ });
+ }
+ },
+ () => {}
+ );
+ };
+
+ getFailedConditions = (
+ conditions: QualityGateStatusCondition[],
+ measures: T.MeasureEnhanced[]
+ ) => {
+ return (
+ conditions
+ .filter(c => c.level !== 'OK')
+ // Enhance them with Metric information, which will be needed
+ // to render the conditions properly.
+ .map(c => enhanceConditionWithMeasure(c, measures))
+ // The enhancement will return undefined if it cannot find the
+ // appropriate measure. Make sure we filter them out.
+ .filter(isDefined)
+ );
+ };
+
+ getTopLevelComponent = () => {
+ const { component } = this.props;
+ let current = component.breadcrumbs.length - 1;
+ while (
+ current > 0 &&
+ !['TRK', 'VW', 'APP'].includes(component.breadcrumbs[current].qualifier)
+ ) {
+ current--;
+ }
+ return component.breadcrumbs[current].key;
+ };
+
+ doneLoadingHistory = () => {
+ if (this.mounted) {
+ this.setState({
+ loadingHistory: false
+ });
+ }
+ };
+
+ handleGraphChange = (graph: GraphType) => {
+ const { component } = this.props;
+ saveActivityGraph(BRANCH_OVERVIEW_ACTIVITY_GRAPH, component.key, graph);
+ this.setState({ graph, loadingHistory: true }, () => {
+ this.loadHistoryMeasures().then(this.doneLoadingHistory, this.doneLoadingHistory);
+ });
+ };
+
+ render() {
+ const { branchLike, component } = this.props;
+ const {
+ analyses,
+ appLeak,
+ graph,
+ loadingStatus,
+ loadingHistory,
+ measures,
+ measuresHistory,
+ metrics,
+ periods,
+ qgStatuses
+ } = this.state;
+
+ const leakPeriod = component.qualifier === 'APP' ? appLeak : getLeakPeriod(periods);
+
+ const projectIsEmpty =
+ loadingStatus === false &&
+ (measures === undefined ||
+ measures.find(measure =>
+ ([MetricKey.lines, MetricKey.new_lines] as string[]).includes(measure.metric.key)
+ ) === undefined);
+
+ return (
+ <BranchOverviewRenderer
+ analyses={analyses}
+ branchLike={branchLike}
+ component={component}
+ graph={graph}
+ leakPeriod={leakPeriod}
+ loadingHistory={loadingHistory}
+ loadingStatus={loadingStatus}
+ measures={measures}
+ measuresHistory={measuresHistory}
+ metrics={metrics}
+ onGraphChange={this.handleGraphChange}
+ projectIsEmpty={projectIsEmpty}
+ qgStatuses={qgStatuses}
+ />
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx b/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx
new file mode 100644
index 00000000000..7db0fe4158e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx
@@ -0,0 +1,115 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 * as React from 'react';
+import { parseDate } from 'sonar-ui-common/helpers/dates';
+import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget';
+import { ApplicationPeriod } from '../../../types/application';
+import { BranchLike } from '../../../types/branch-like';
+import { GraphType, MeasureHistory } from '../../../types/project-activity';
+import { QualityGateStatus } from '../../../types/quality-gates';
+import ActivityPanel from './ActivityPanel';
+import { MeasuresPanel } from './MeasuresPanel';
+import NoCodeWarning from './NoCodeWarning';
+import QualityGatePanel from './QualityGatePanel';
+
+export interface BranchOverviewRendererProps {
+ analyses?: T.Analysis[];
+ branchLike?: BranchLike;
+ component: T.Component;
+ graph?: GraphType;
+ leakPeriod?: T.Period | ApplicationPeriod;
+ loadingHistory?: boolean;
+ loadingStatus?: boolean;
+ measures?: T.MeasureEnhanced[];
+ measuresHistory?: MeasureHistory[];
+ metrics?: T.Metric[];
+ onGraphChange: (graph: GraphType) => void;
+ projectIsEmpty?: boolean;
+ qgStatuses?: QualityGateStatus[];
+}
+
+export function BranchOverviewRenderer(props: BranchOverviewRendererProps) {
+ const {
+ analyses,
+ branchLike,
+ component,
+ graph,
+ leakPeriod,
+ loadingHistory,
+ loadingStatus,
+ measures,
+ measuresHistory = [],
+ metrics = [],
+ onGraphChange,
+ projectIsEmpty,
+ qgStatuses
+ } = props;
+
+ return (
+ <div className="page page-limited">
+ <div className="overview">
+ <A11ySkipTarget anchor="overview_main" />
+
+ {projectIsEmpty ? (
+ <NoCodeWarning branchLike={branchLike} component={component} measures={measures} />
+ ) : (
+ <>
+ <div className="display-flex-row">
+ <div className="width-25 big-spacer-right">
+ <QualityGatePanel
+ branchLike={branchLike}
+ component={component}
+ loading={loadingStatus}
+ qgStatuses={qgStatuses}
+ />
+ </div>
+
+ <div className="flex-1">
+ <div className="display-flex-column">
+ <MeasuresPanel
+ branchLike={branchLike}
+ component={component}
+ leakPeriod={leakPeriod}
+ loading={loadingStatus}
+ measures={measures}
+ />
+
+ <ActivityPanel
+ analyses={analyses}
+ branchLike={branchLike}
+ component={component}
+ graph={graph}
+ leakPeriodDate={leakPeriod && parseDate(leakPeriod.date)}
+ loading={loadingHistory}
+ measuresHistory={measuresHistory}
+ metrics={metrics}
+ onGraphChange={onGraphChange}
+ />
+ </div>
+ </div>
+ </div>
+ </>
+ )}
+ </div>
+ </div>
+ );
+}
+
+export default React.memo(BranchOverviewRenderer);
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/DebtValue.tsx b/server/sonar-web/src/main/js/apps/overview/branches/DebtValue.tsx
new file mode 100644
index 00000000000..00c01a5057f
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/DebtValue.tsx
@@ -0,0 +1,66 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 * as React from 'react';
+import { getLocalizedMetricName, translate } from 'sonar-ui-common/helpers/l10n';
+import { formatMeasure } from 'sonar-ui-common/helpers/measures';
+import { getLeakValue } from '../../../components/measure/utils';
+import DrilldownLink from '../../../components/shared/DrilldownLink';
+import { findMeasure, localizeMetric } from '../../../helpers/measures';
+import { BranchLike } from '../../../types/branch-like';
+import { MetricKey } from '../../../types/metrics';
+
+export interface DebtValueProps {
+ branchLike?: BranchLike;
+ component: T.Component;
+ measures: T.MeasureEnhanced[];
+ useDiffMetric?: boolean;
+}
+
+export function DebtValue(props: DebtValueProps) {
+ const { branchLike, component, measures, useDiffMetric = false } = props;
+ const metric = useDiffMetric ? MetricKey.new_technical_debt : MetricKey.sqale_index;
+ const measure = findMeasure(measures, metric);
+
+ let value;
+ if (measure) {
+ value = useDiffMetric ? getLeakValue(measure) : measure.value;
+ }
+
+ return (
+ <>
+ {value === undefined ? (
+ <span aria-label={translate('no_data')} className="overview-measures-empty-value" />
+ ) : (
+ <DrilldownLink
+ branchLike={branchLike}
+ className="overview-measures-value text-light"
+ component={component.key}
+ metric={metric}>
+ {formatMeasure(value, 'WORK_DUR')}
+ </DrilldownLink>
+ )}
+ <span className="big-spacer-left">
+ {measure ? getLocalizedMetricName(measure.metric, true) : localizeMetric(metric)}
+ </span>
+ </>
+ );
+}
+
+export default React.memo(DebtValue);
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/DrilldownMeasureValue.tsx b/server/sonar-web/src/main/js/apps/overview/branches/DrilldownMeasureValue.tsx
new file mode 100644
index 00000000000..4db04aef6c0
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/DrilldownMeasureValue.tsx
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 * as React from 'react';
+import { getLocalizedMetricName } from 'sonar-ui-common/helpers/l10n';
+import { formatMeasure } from 'sonar-ui-common/helpers/measures';
+import DrilldownLink from '../../../components/shared/DrilldownLink';
+import { findMeasure } from '../../../helpers/measures';
+import { BranchLike } from '../../../types/branch-like';
+import { MetricKey } from '../../../types/metrics';
+
+export interface DrilldownMeasureValueProps {
+ branchLike?: BranchLike;
+ component: T.Component;
+ measures: T.MeasureEnhanced[];
+ metric: MetricKey;
+}
+
+export function DrilldownMeasureValue(props: DrilldownMeasureValueProps) {
+ const { branchLike, component, measures, metric } = props;
+ const measure = findMeasure(measures, metric);
+
+ let content;
+ if (!measure) {
+ content = <span className="overview-measures-value text-light">-</span>;
+ } else {
+ content = (
+ <span>
+ <DrilldownLink
+ branchLike={branchLike}
+ className="overview-measures-value text-light"
+ component={component.key}
+ metric={metric}>
+ {formatMeasure(measure.value, 'SHORT_INT')}
+ </DrilldownLink>
+ </span>
+ );
+ }
+
+ return (
+ <div className="display-flex-column display-flex-center">
+ {content}
+ <span className="spacer-top">{getLocalizedMetricName({ key: metric })}</span>
+ </div>
+ );
+}
+
+export default React.memo(DrilldownMeasureValue);
diff --git a/server/sonar-web/src/main/js/apps/overview/events/Event.tsx b/server/sonar-web/src/main/js/apps/overview/branches/Event.tsx
index bdd90941df2..375380d086b 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/Event.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/Event.tsx
@@ -28,7 +28,7 @@ interface Props {
event: T.AnalysisEvent;
}
-export default function Event({ event }: Props) {
+export function Event({ event }: Props) {
if (event.category === 'VERSION') {
return (
<span
@@ -76,3 +76,5 @@ export default function Event({ event }: Props) {
</div>
);
}
+
+export default React.memo(Event);
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanel.tsx b/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanel.tsx
new file mode 100644
index 00000000000..dfd6f067690
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanel.tsx
@@ -0,0 +1,265 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { Link } from 'react-router';
+import BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs';
+import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import { isDiffMetric } from 'sonar-ui-common/helpers/measures';
+import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
+import { rawSizes } from '../../../app/theme';
+import { findMeasure } from '../../../helpers/measures';
+import { ApplicationPeriod } from '../../../types/application';
+import { BranchLike } from '../../../types/branch-like';
+import { ComponentQualifier } from '../../../types/component';
+import { MetricKey } from '../../../types/metrics';
+import IssueLabel from '../components/IssueLabel';
+import IssueRating from '../components/IssueRating';
+import MeasurementLabel from '../components/MeasurementLabel';
+import { IssueType, MeasurementType } from '../utils';
+import DebtValue from './DebtValue';
+import { DrilldownMeasureValue } from './DrilldownMeasureValue';
+import { LeakPeriodInfo } from './LeakPeriodInfo';
+
+export interface MeasuresPanelProps {
+ branchLike?: BranchLike;
+ component: T.Component;
+ leakPeriod?: T.Period | ApplicationPeriod;
+ loading?: boolean;
+ measures?: T.MeasureEnhanced[];
+}
+
+export enum MeasuresPanelTabs {
+ New,
+ Overall
+}
+
+export function MeasuresPanel(props: MeasuresPanelProps) {
+ const { branchLike, component, loading, leakPeriod, measures = [] } = props;
+
+ const hasDiffMeasures = measures.some(m => isDiffMetric(m.metric.key));
+ const isApp = component.qualifier === ComponentQualifier.Application;
+
+ const [tab, selectTab] = React.useState(MeasuresPanelTabs.New);
+
+ React.useEffect(() => {
+ // Open Overall tab by default if there are no new measures.
+ if (loading === false && !hasDiffMeasures && tab === MeasuresPanelTabs.New) {
+ selectTab(MeasuresPanelTabs.Overall);
+ }
+ // In this case, we explicitly do NOT want to mark tab as a dependency, as
+ // it would prevent the user from selecting it, even if it's empty.
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
+ }, [loading, hasDiffMeasures]);
+
+ const tabs = [
+ {
+ key: MeasuresPanelTabs.New,
+ label: (
+ <div className="text-left overview-measures-tab">
+ <span className="text-bold">{translate('overview.new_code')}</span>
+ {leakPeriod && <LeakPeriodInfo leakPeriod={leakPeriod} />}
+ </div>
+ )
+ },
+ {
+ key: MeasuresPanelTabs.Overall,
+ label: (
+ <div className="text-left overview-measures-tab">
+ <span className="text-bold" style={{ position: 'absolute', top: 2 * rawSizes.grid }}>
+ {translate('overview.overall_code')}
+ </span>
+ </div>
+ )
+ }
+ ];
+
+ return (
+ <div className="overview-panel" data-test="overview__measures-panel">
+ <h2 className="overview-panel-title">{translate('overview.measures')}</h2>
+
+ {loading ? (
+ <div className="overview-panel-content overview-panel-big-padded">
+ <DeferredSpinner loading={loading} />
+ </div>
+ ) : (
+ <>
+ <BoxedTabs onSelect={selectTab} selected={tab} tabs={tabs} />
+
+ <div className="overview-panel-content flex-1 bordered">
+ {!hasDiffMeasures && tab === MeasuresPanelTabs.New ? (
+ <div
+ className="display-flex-center display-flex-justify-center"
+ style={{ height: 500 }}>
+ <img
+ alt="" /* Make screen readers ignore this image; it's purely eye candy. */
+ className="spacer-right"
+ height={52}
+ src={`${getBaseUrl()}/images/source-code.svg`}
+ />
+ <div className="big-spacer-left text-muted" style={{ maxWidth: 500 }}>
+ <p className="spacer-bottom big-spacer-top big">
+ {translate('overview.measures.empty_explanation')}
+ </p>
+ <p>
+ <FormattedMessage
+ defaultMessage={translate('overview.measures.empty_link')}
+ id="overview.measures.empty_link"
+ values={{
+ learn_more_link: (
+ <Link to="/documentation/user-guide/clean-as-you-code/">
+ {translate('learn_more')}
+ </Link>
+ )
+ }}
+ />
+ </p>
+ </div>
+ </div>
+ ) : (
+ <>
+ {[IssueType.Bug, IssueType.Vulnerability, IssueType.CodeSmell].map(
+ (type: IssueType) => (
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test={`overview__measures-${type.toString().toLowerCase()}`}
+ key={type}>
+ {type === IssueType.CodeSmell ? (
+ <>
+ <div className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left">
+ <DebtValue
+ branchLike={branchLike}
+ component={component}
+ measures={measures}
+ useDiffMetric={tab === MeasuresPanelTabs.New}
+ />
+ </div>
+ <div className="flex-1 small display-flex-center">
+ <IssueLabel
+ branchLike={branchLike}
+ component={component}
+ measures={measures}
+ type={type}
+ useDiffMetric={tab === MeasuresPanelTabs.New}
+ />
+ </div>
+ </>
+ ) : (
+ <>
+ <div className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left">
+ <IssueLabel
+ branchLike={branchLike}
+ component={component}
+ measures={measures}
+ type={type}
+ useDiffMetric={tab === MeasuresPanelTabs.New}
+ />
+ </div>
+ {type === 'VULNERABILITY' && (
+ <div className="flex-1 small display-flex-center">
+ <IssueLabel
+ branchLike={branchLike}
+ component={component}
+ docTooltip={import(
+ /* webpackMode: "eager" */ 'Docs/tooltips/metrics/security-hotspots.md'
+ )}
+ measures={measures}
+ type={IssueType.SecurityHotspot}
+ useDiffMetric={tab === MeasuresPanelTabs.New}
+ />
+ </div>
+ )}
+ </>
+ )}
+ {(!isApp || tab === MeasuresPanelTabs.Overall) && (
+ <div className="overview-panel-big-padded overview-measures-aside display-flex-center">
+ <IssueRating
+ branchLike={branchLike}
+ component={component}
+ measures={measures}
+ type={type}
+ useDiffMetric={tab === MeasuresPanelTabs.New}
+ />
+ </div>
+ )}
+ </div>
+ )
+ )}
+
+ <div className="display-flex-row overview-measures-row">
+ {(findMeasure(measures, MetricKey.coverage) ||
+ findMeasure(measures, MetricKey.new_coverage)) && (
+ <div
+ className="overview-panel-huge-padded flex-1 bordered-right display-flex-center"
+ data-test="overview__measures-coverage">
+ <MeasurementLabel
+ branchLike={branchLike}
+ centered={tab === MeasuresPanelTabs.New}
+ component={component}
+ measures={measures}
+ type={MeasurementType.Coverage}
+ useDiffMetric={tab === MeasuresPanelTabs.New}
+ />
+
+ {tab === MeasuresPanelTabs.Overall && (
+ <div className="huge-spacer-left">
+ <DrilldownMeasureValue
+ branchLike={branchLike}
+ component={component}
+ measures={measures}
+ metric={MetricKey.tests}
+ />
+ </div>
+ )}
+ </div>
+ )}
+ <div className="overview-panel-huge-padded flex-1 display-flex-center">
+ <MeasurementLabel
+ branchLike={branchLike}
+ centered={tab === MeasuresPanelTabs.New}
+ component={component}
+ measures={measures}
+ type={MeasurementType.Duplication}
+ useDiffMetric={tab === MeasuresPanelTabs.New}
+ />
+
+ {tab === MeasuresPanelTabs.Overall && (
+ <div className="huge-spacer-left">
+ <DrilldownMeasureValue
+ branchLike={branchLike}
+ component={component}
+ measures={measures}
+ metric={MetricKey.duplicated_blocks}
+ />
+ </div>
+ )}
+ </div>
+ </div>
+ </>
+ )}
+ </div>
+ </>
+ )}
+ </div>
+ );
+}
+
+export default React.memo(MeasuresPanel);
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/NoCodeWarning.tsx b/server/sonar-web/src/main/js/apps/overview/branches/NoCodeWarning.tsx
new file mode 100644
index 00000000000..1a81132e2a1
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/NoCodeWarning.tsx
@@ -0,0 +1,90 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 * as React from 'react';
+import { Alert } from 'sonar-ui-common/components/ui/Alert';
+import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
+import { getBranchLikeDisplayName, isMainBranch } from '../../../helpers/branch-like';
+import { BranchLike } from '../../../types/branch-like';
+
+interface Props {
+ branchLike?: BranchLike;
+ component: T.Component;
+ measures?: T.MeasureEnhanced[];
+}
+
+export function NoCodeWarning({ branchLike, component, measures }: Props) {
+ const isApp = component.qualifier === 'APP';
+
+ /* eslint-disable no-lonely-if */
+ // - Is App
+ // - No measures, OR measures, but no projects => empty
+ // - Else => no lines of code
+ // - Else
+ // - No measures => empty
+ // - Main branch?
+ // - LLB?
+ // - No branch info?
+ // - Measures, but no ncloc (checked in isEmpty()) => no lines of code
+ // - Main branch?
+ // - LLB?
+ // - No branch info?
+ let title = translate('overview.project.no_lines_of_code');
+ if (isApp) {
+ if (
+ measures === undefined ||
+ measures.find(measure => measure.metric.key === 'projects') === undefined
+ ) {
+ title = translate('portfolio.app.empty');
+ } else {
+ title = translate('portfolio.app.no_lines_of_code');
+ }
+ } else {
+ if (measures === undefined || measures.length === 0) {
+ if (isMainBranch(branchLike)) {
+ title = translate('overview.project.main_branch_empty');
+ } else if (branchLike !== undefined) {
+ title = translateWithParameters(
+ 'overview.project.branch_X_empty',
+ getBranchLikeDisplayName(branchLike)
+ );
+ } else {
+ title = translate('overview.project.empty');
+ }
+ } else {
+ if (isMainBranch(branchLike)) {
+ title = translate('overview.project.main_branch_no_lines_of_code');
+ } else if (branchLike !== undefined) {
+ title = translateWithParameters(
+ 'overview.project.branch_X_no_lines_of_code',
+ getBranchLikeDisplayName(branchLike)
+ );
+ }
+ }
+ }
+ /* eslint-enable no-lonely-if */
+
+ return (
+ <Alert display="banner" variant="warning">
+ {title}
+ </Alert>
+ );
+}
+
+export default React.memo(NoCodeWarning);
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
new file mode 100644
index 00000000000..fbea9c5716d
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx
@@ -0,0 +1,125 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 * as classNames from 'classnames';
+import * as React from 'react';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
+import { Alert } from 'sonar-ui-common/components/ui/Alert';
+import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
+import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
+import DocTooltip from '../../../components/docs/DocTooltip';
+import { BranchLike } from '../../../types/branch-like';
+import { QualityGateStatus } from '../../../types/quality-gates';
+import QualityGatePanelSection from './QualityGatePanelSection';
+
+export interface QualityGatePanelProps {
+ branchLike?: BranchLike;
+ component: Pick<T.Component, 'key' | 'qualifier'>;
+ loading?: boolean;
+ qgStatuses?: QualityGateStatus[];
+}
+
+export function QualityGatePanel(props: QualityGatePanelProps) {
+ const { branchLike, component, loading, qgStatuses = [] } = props;
+
+ if (qgStatuses === undefined) {
+ return null;
+ }
+
+ const overallLevel = qgStatuses.map(s => s.status).includes('ERROR') ? 'ERROR' : 'OK';
+ const success = overallLevel === 'OK';
+
+ const overallFailedConditionsCount = qgStatuses.reduce(
+ (acc, qgStatus) => acc + qgStatus.failedConditions.length,
+ 0
+ );
+
+ const showIgnoredConditionWarning =
+ component.qualifier === 'TRK' &&
+ qgStatuses !== undefined &&
+ qgStatuses.some(p => Boolean(p.ignoredConditions));
+
+ return (
+ <div className="overview-panel" data-test="overview__quality-gate-panel">
+ <h2 className="overview-panel-title display-inline-flex-center">
+ {translate('overview.quality_gate')}{' '}
+ <DocTooltip
+ className="little-spacer-left"
+ doc={import(
+ /* webpackMode: "eager" */ 'Docs/tooltips/quality-gates/project-homepage-quality-gate.md'
+ )}
+ />
+ </h2>
+
+ {showIgnoredConditionWarning && (
+ <Alert className="big-spacer-bottom" display="inline" variant="info">
+ <span className="text-middle">
+ {translate('overview.quality_gate.ignored_conditions')}
+ </span>
+ <HelpTooltip
+ className="spacer-left"
+ overlay={translate('overview.quality_gate.ignored_conditions.tooltip')}
+ />
+ </Alert>
+ )}
+
+ <div className="overview-panel-content">
+ {loading ? (
+ <div className="overview-panel-big-padded">
+ <DeferredSpinner loading={loading} />
+ </div>
+ ) : (
+ <>
+ <div
+ className={classNames('overview-quality-gate-badge-large', {
+ failed: !success,
+ success
+ })}>
+ <h3 className="big-spacer-bottom huge">{translate('metric.level', overallLevel)}</h3>
+
+ <span className="small">
+ {overallFailedConditionsCount > 0
+ ? translateWithParameters(
+ 'overview.X_conditions_failed',
+ overallFailedConditionsCount
+ )
+ : translate('overview.quality_gate_all_conditions_passed')}
+ </span>
+ </div>
+
+ {overallFailedConditionsCount > 0 && (
+ <div data-test="overview__quality-gate-conditions">
+ {qgStatuses.map(qgStatus => (
+ <QualityGatePanelSection
+ branchLike={branchLike}
+ component={component}
+ key={qgStatus.key}
+ qgStatus={qgStatus}
+ />
+ ))}
+ </div>
+ )}
+ </>
+ )}
+ </div>
+ </div>
+ );
+}
+
+export default React.memo(QualityGatePanel);
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
new file mode 100644
index 00000000000..a304c5dccd9
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx
@@ -0,0 +1,79 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 * as React from 'react';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import { isDiffMetric } from '../../../helpers/measures';
+import { BranchLike } from '../../../types/branch-like';
+import { QualityGateStatus } from '../../../types/quality-gates';
+import { QualityGateConditions } from '../components/QualityGateConditions';
+
+export interface QualityGatePanelSectionProps {
+ branchLike?: BranchLike;
+ component: Pick<T.Component, 'key' | 'qualifier'>;
+ qgStatus: QualityGateStatus;
+}
+
+export function QualityGatePanelSection(props: QualityGatePanelSectionProps) {
+ const { branchLike, component, qgStatus } = props;
+ const newCodeFailedConditions = qgStatus.failedConditions.filter(c => isDiffMetric(c.metric));
+ const overallFailedConditions = qgStatus.failedConditions.filter(c => !isDiffMetric(c.metric));
+
+ if (newCodeFailedConditions.length === 0 && overallFailedConditions.length === 0) {
+ return null;
+ }
+
+ const showName = component.qualifier === 'APP';
+
+ return (
+ <div className="overview-quality-gate-conditions">
+ {showName && (
+ <h3 className="overview-quality-gate-conditions-project-name">{qgStatus.name}</h3>
+ )}
+
+ {newCodeFailedConditions.length > 0 && (
+ <>
+ <h4 className="overview-quality-gate-conditions-section-title">
+ {translate('quality_gates.conditions.new_code')}
+ </h4>
+ <QualityGateConditions
+ branchLike={branchLike}
+ component={qgStatus}
+ failedConditions={newCodeFailedConditions}
+ />
+ </>
+ )}
+
+ {overallFailedConditions.length > 0 && (
+ <>
+ <h4 className="overview-quality-gate-conditions-section-title">
+ {translate('quality_gates.conditions.overall_code')}
+ </h4>
+ <QualityGateConditions
+ branchLike={branchLike}
+ component={qgStatus}
+ failedConditions={overallFailedConditions}
+ />
+ </>
+ )}
+ </div>
+ );
+}
+
+export default React.memo(QualityGatePanelSection);
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-test.tsx
new file mode 100644
index 00000000000..21856507dd6
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-test.tsx
@@ -0,0 +1,83 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { parseDate } from 'sonar-ui-common/helpers/dates';
+import GraphsHistory from '../../../../components/activity-graph/GraphsHistory';
+import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
+import {
+ mockAnalysis,
+ mockAnalysisEvent,
+ mockComponent,
+ mockMeasure,
+ mockMetric
+} from '../../../../helpers/testMocks';
+import { GraphType } from '../../../../types/project-activity';
+import { ActivityPanel, ActivityPanelProps } from '../ActivityPanel';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ loading: true, analyses: undefined })).toMatchSnapshot();
+});
+
+it('should correctly pass the leak period start date', () => {
+ // Leak period start is more recent than the oldest historic measure.
+ let { leakPeriodDate } = shallowRender({
+ leakPeriodDate: parseDate('2017-08-27T16:33:50+0200')
+ })
+ .find(GraphsHistory)
+ .props();
+
+ if (leakPeriodDate) {
+ expect(leakPeriodDate.getTime()).toBe(1503844430000); /* 2017-08-27T16:33:50+0200 */
+ } else {
+ fail('leakPeriodDate should have been set');
+ }
+
+ // Leak period start is older than the oldest historic measure.
+ ({ leakPeriodDate } = shallowRender({ leakPeriodDate: parseDate('2015-08-27T16:33:50+0200') })
+ .find(GraphsHistory)
+ .props());
+
+ if (leakPeriodDate) {
+ expect(leakPeriodDate.getTime()).toBe(1477578830000); /* 2016-10-27T16:33:50+0200 */
+ } else {
+ fail('leakPeriodDate should have been set');
+ }
+});
+
+function shallowRender(props: Partial<ActivityPanelProps> = {}) {
+ return shallow(
+ <ActivityPanel
+ analyses={[mockAnalysis({ events: [mockAnalysisEvent()] }), mockAnalysis()]}
+ branchLike={mockMainBranch()}
+ component={mockComponent()}
+ graph={GraphType.issues}
+ loading={false}
+ measuresHistory={[mockMeasure()].map(m => ({
+ ...m,
+ history: [{ date: parseDate('2016-10-27T16:33:50+0200'), value: '20' }]
+ }))}
+ metrics={[mockMetric({ key: 'bugs' })]}
+ onGraphChange={jest.fn()}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/AnalysesList-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/Analysis-test.tsx
index 52ce01f3aa4..d530f2fff8d 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/AnalysesList-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/Analysis-test.tsx
@@ -19,21 +19,25 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
-import AnalysesList from '../AnalysesList';
+import { mockAnalysis } from '../../../../helpers/testMocks';
+import { Analysis, AnalysisProps } from '../Analysis';
-it('should render show more link', () => {
- const branchLike = mockMainBranch();
- const component = {
- breadcrumbs: [{ key: 'foo', name: 'foo', qualifier: 'TRK' }],
- key: 'foo',
- name: 'foo',
- organization: 'org',
- qualifier: 'TRK'
- };
- const wrapper = shallow(
- <AnalysesList branchLike={branchLike} component={component} metrics={{}} qualifier="TRK" />
- );
- wrapper.setState({ loading: false });
- expect(wrapper.find('Link')).toMatchSnapshot();
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ qualifier: 'APP' })).toMatchSnapshot();
});
+
+function shallowRender(props: Partial<AnalysisProps> = {}) {
+ return shallow(
+ <Analysis
+ analysis={mockAnalysis({
+ events: [
+ { key: '1', category: 'OTHER', name: 'test' },
+ { key: '2', category: 'VERSION', name: '6.5-SNAPSHOT' }
+ ]
+ })}
+ qualifier="TRK"
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx
new file mode 100644
index 00000000000..99244d2f41c
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx
@@ -0,0 +1,349 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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.
+ */
+/* eslint-disable sonarjs/no-duplicate-string */
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import { isDiffMetric } from 'sonar-ui-common/helpers/measures';
+import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
+import { getApplicationLeak } from '../../../../api/application';
+import { getMeasuresAndMeta } from '../../../../api/measures';
+import { getProjectActivity } from '../../../../api/projectActivity';
+import {
+ getApplicationQualityGate,
+ getQualityGateProjectStatus
+} from '../../../../api/quality-gates';
+import { getTimeMachineData } from '../../../../api/time-machine';
+import { getActivityGraph, saveActivityGraph } from '../../../../components/activity-graph/utils';
+import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
+import { mockComponent } from '../../../../helpers/testMocks';
+import { MetricKey } from '../../../../types/metrics';
+import { GraphType } from '../../../../types/project-activity';
+import BranchOverview, { BRANCH_OVERVIEW_ACTIVITY_GRAPH } from '../BranchOverview';
+import BranchOverviewRenderer from '../BranchOverviewRenderer';
+
+jest.mock('sonar-ui-common/helpers/dates', () => ({
+ parseDate: jest.fn(date => `PARSED:${date}`),
+ toNotSoISOString: jest.fn(date => date)
+}));
+
+jest.mock('../../../../api/measures', () => {
+ const { mockMeasure, mockMetric } = require.requireActual('../../../../helpers/testMocks');
+ return {
+ getMeasuresAndMeta: jest.fn((_, metricKeys: string[]) => {
+ const metrics: T.Metric[] = [];
+ const measures: T.Measure[] = [];
+ metricKeys.forEach(key => {
+ if (key === 'unknown_metric') {
+ return;
+ }
+
+ let type;
+ if (/(coverage|duplication)$/.test(key)) {
+ type = 'PERCENT';
+ } else if (/_rating$/.test(key)) {
+ type = 'RATING';
+ } else {
+ type = 'INT';
+ }
+ metrics.push(mockMetric({ key, id: key, name: key, type }));
+ measures.push(
+ mockMeasure({
+ metric: key,
+ ...(isDiffMetric(key) ? { leak: '1' } : { periods: undefined })
+ })
+ );
+ });
+ return Promise.resolve({
+ component: {
+ measures,
+ name: 'foo'
+ },
+ metrics
+ });
+ })
+ };
+});
+
+jest.mock('../../../../api/quality-gates', () => {
+ const { mockQualityGateProjectStatus, mockQualityGateApplicationStatus } = require.requireActual(
+ '../../../../helpers/mocks/quality-gates'
+ );
+ const { MetricKey } = require.requireActual('../../../../types/metrics');
+ return {
+ getQualityGateProjectStatus: jest.fn().mockResolvedValue(
+ mockQualityGateProjectStatus({
+ status: 'ERROR',
+ conditions: [
+ {
+ actualValue: '2',
+ comparator: 'GT',
+ errorThreshold: '1.0',
+ metricKey: MetricKey.new_bugs,
+ periodIndex: 1,
+ status: 'ERROR'
+ },
+ {
+ actualValue: '5',
+ comparator: 'GT',
+ errorThreshold: '2.0',
+ metricKey: MetricKey.bugs,
+ periodIndex: 0,
+ status: 'ERROR'
+ },
+ {
+ actualValue: '2',
+ comparator: 'GT',
+ errorThreshold: '1.0',
+ metricKey: 'unknown_metric',
+ periodIndex: 0,
+ status: 'ERROR'
+ }
+ ]
+ })
+ ),
+ getApplicationQualityGate: jest.fn().mockResolvedValue(mockQualityGateApplicationStatus())
+ };
+});
+
+jest.mock('../../../../api/time-machine', () => {
+ const { MetricKey } = require.requireActual('../../../../types/metrics');
+ return {
+ getTimeMachineData: jest.fn().mockResolvedValue({
+ measures: [
+ { metric: MetricKey.bugs, history: [{ date: '2019-01-05', value: '2.0' }] },
+ { metric: MetricKey.vulnerabilities, history: [{ date: '2019-01-05', value: '0' }] },
+ { metric: MetricKey.sqale_index, history: [{ date: '2019-01-01', value: '1.0' }] },
+ {
+ metric: MetricKey.duplicated_lines_density,
+ history: [{ date: '2019-01-02', value: '1.0' }]
+ },
+ { metric: MetricKey.ncloc, history: [{ date: '2019-01-03', value: '10000' }] },
+ { metric: MetricKey.coverage, history: [{ date: '2019-01-04', value: '95.5' }] }
+ ]
+ })
+ };
+});
+
+jest.mock('../../../../api/projectActivity', () => {
+ const { mockAnalysis } = require.requireActual('../../../../helpers/testMocks');
+ return {
+ getProjectActivity: jest.fn().mockResolvedValue({
+ analyses: [mockAnalysis(), mockAnalysis(), mockAnalysis(), mockAnalysis(), mockAnalysis()]
+ })
+ };
+});
+
+jest.mock('../../../../api/application', () => ({
+ getApplicationLeak: jest.fn().mockResolvedValue([
+ {
+ date: '2017-01-05',
+ project: 'foo',
+ projectName: 'Foo'
+ }
+ ])
+}));
+
+jest.mock('../../../../components/activity-graph/utils', () => {
+ const { MetricKey } = require.requireActual('../../../../types/metrics');
+ const { GraphType } = require.requireActual('../../../../types/project-activity');
+ return {
+ getActivityGraph: jest.fn(() => ({ graph: GraphType.coverage })),
+ saveActivityGraph: jest.fn(),
+ getHistoryMetrics: jest.fn(() => [MetricKey.lines_to_cover, MetricKey.uncovered_lines])
+ };
+});
+
+beforeEach(jest.clearAllMocks);
+
+describe('project overview', () => {
+ it('should render correctly', async () => {
+ const wrapper = shallowRender();
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it("should correctly load a project's status", async () => {
+ const wrapper = shallowRender();
+ await waitAndUpdate(wrapper);
+ expect(getQualityGateProjectStatus).toBeCalled();
+ expect(getMeasuresAndMeta).toBeCalled();
+
+ // Check the conditions got correctly enhanced with measure meta data.
+ const { qgStatuses } = wrapper.state();
+ expect(qgStatuses).toHaveLength(1);
+ const [qgStatus] = qgStatuses!;
+
+ expect(qgStatus).toEqual(
+ expect.objectContaining({
+ name: 'Foo',
+ key: 'foo',
+ status: 'ERROR'
+ })
+ );
+
+ const { failedConditions } = qgStatus;
+ expect(failedConditions).toHaveLength(2);
+ expect(failedConditions[0]).toMatchObject({
+ actual: '2',
+ level: 'ERROR',
+ metric: MetricKey.new_bugs,
+ measure: expect.objectContaining({
+ metric: expect.objectContaining({ key: MetricKey.new_bugs })
+ })
+ });
+ expect(failedConditions[1]).toMatchObject({
+ actual: '5',
+ level: 'ERROR',
+ metric: MetricKey.bugs,
+ measure: expect.objectContaining({
+ metric: expect.objectContaining({ key: MetricKey.bugs })
+ })
+ });
+ });
+
+ it('should correctly flag a project as empty', async () => {
+ (getMeasuresAndMeta as jest.Mock).mockResolvedValueOnce({ component: {} });
+
+ const wrapper = shallowRender();
+ await waitAndUpdate(wrapper);
+ expect(wrapper.find(BranchOverviewRenderer).props().projectIsEmpty).toBe(true);
+ });
+});
+
+describe('application overview', () => {
+ const component = mockComponent({
+ breadcrumbs: [mockComponent({ key: 'foo', qualifier: 'APP' })],
+ qualifier: 'APP'
+ });
+
+ it('should render correctly', async () => {
+ const wrapper = shallowRender({ component });
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it("should correctly load an application's status", async () => {
+ const wrapper = shallowRender({ component });
+ await waitAndUpdate(wrapper);
+ expect(getApplicationQualityGate).toBeCalled();
+ expect(getApplicationLeak).toBeCalled();
+ expect(getMeasuresAndMeta).toBeCalled();
+
+ // Check the conditions got correctly enhanced with measure meta data.
+ const { qgStatuses } = wrapper.state();
+ expect(qgStatuses).toHaveLength(2);
+ const [qgStatus1, qgStatus2] = qgStatuses!;
+
+ expect(qgStatus1).toEqual(
+ expect.objectContaining({
+ name: 'Foo',
+ key: 'foo',
+ status: 'ERROR'
+ })
+ );
+
+ const { failedConditions: failedConditions1 } = qgStatus1;
+ expect(failedConditions1).toHaveLength(2);
+ expect(failedConditions1[0]).toMatchObject({
+ actual: '10',
+ level: 'ERROR',
+ metric: MetricKey.coverage,
+ measure: expect.objectContaining({
+ metric: expect.objectContaining({ key: MetricKey.coverage })
+ })
+ });
+ expect(failedConditions1[1]).toMatchObject({
+ actual: '5',
+ level: 'ERROR',
+ metric: MetricKey.new_bugs,
+ measure: expect.objectContaining({
+ metric: expect.objectContaining({ key: MetricKey.new_bugs })
+ })
+ });
+
+ expect(qgStatus1).toEqual(
+ expect.objectContaining({
+ name: 'Foo',
+ key: 'foo',
+ status: 'ERROR'
+ })
+ );
+
+ const { failedConditions: failedConditions2 } = qgStatus2;
+ expect(failedConditions2).toHaveLength(1);
+ expect(failedConditions2[0]).toMatchObject({
+ actual: '15',
+ level: 'ERROR',
+ metric: MetricKey.new_bugs,
+ measure: expect.objectContaining({
+ metric: expect.objectContaining({ key: MetricKey.new_bugs })
+ })
+ });
+ });
+
+ it('should correctly flag an application as empty', async () => {
+ (getMeasuresAndMeta as jest.Mock).mockResolvedValueOnce({ component: {} });
+
+ const wrapper = shallowRender({ component });
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper.find(BranchOverviewRenderer).props().projectIsEmpty).toBe(true);
+ });
+});
+
+it("should correctly load a component's history", async () => {
+ const wrapper = shallowRender();
+ await waitAndUpdate(wrapper);
+ expect(getProjectActivity).toBeCalled();
+ expect(getTimeMachineData).toBeCalled();
+
+ const { measuresHistory } = wrapper.state();
+ expect(measuresHistory).toHaveLength(6);
+ expect(measuresHistory![0]).toEqual(
+ expect.objectContaining({
+ metric: MetricKey.bugs,
+ history: [{ date: 'PARSED:2019-01-05', value: '2.0' }]
+ })
+ );
+});
+
+it('should correctly handle graph type storage', () => {
+ const wrapper = shallowRender();
+ expect(getActivityGraph).toBeCalledWith(BRANCH_OVERVIEW_ACTIVITY_GRAPH, 'foo');
+ expect(wrapper.state().graph).toBe(GraphType.coverage);
+
+ wrapper.instance().handleGraphChange(GraphType.issues);
+ expect(saveActivityGraph).toBeCalledWith(BRANCH_OVERVIEW_ACTIVITY_GRAPH, 'foo', GraphType.issues);
+ expect(wrapper.state().graph).toBe(GraphType.issues);
+});
+
+function shallowRender(props: Partial<BranchOverview['props']> = {}) {
+ return shallow<BranchOverview>(
+ <BranchOverview
+ branchLike={mockMainBranch()}
+ component={mockComponent({
+ breadcrumbs: [mockComponent({ key: 'foo' })],
+ key: 'foo',
+ name: 'Foo'
+ })}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverviewRenderer-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverviewRenderer-test.tsx
new file mode 100644
index 00000000000..024b32cf1a6
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverviewRenderer-test.tsx
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
+import { mockComponent, mockMeasureEnhanced } from '../../../../helpers/testMocks';
+import { GraphType } from '../../../../types/project-activity';
+import { BranchOverviewRenderer, BranchOverviewRendererProps } from '../BranchOverviewRenderer';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ projectIsEmpty: true })).toMatchSnapshot();
+ expect(shallowRender({ loadingHistory: true, loadingStatus: true })).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<BranchOverviewRendererProps> = {}) {
+ return shallow(
+ <BranchOverviewRenderer
+ branchLike={mockMainBranch()}
+ component={mockComponent()}
+ graph={GraphType.issues}
+ loadingHistory={false}
+ loadingStatus={false}
+ measures={[mockMeasureEnhanced()]}
+ onGraphChange={jest.fn()}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/Coverage-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/DebtValue-test.tsx
index 13534354d84..49f1d272fd1 100644
--- a/server/sonar-web/src/main/js/apps/overview/main/__tests__/Coverage-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/DebtValue-test.tsx
@@ -21,49 +21,25 @@ import { shallow } from 'enzyme';
import * as React from 'react';
import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
import { mockComponent, mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks';
-import Coverage from '../Coverage';
-import { ComposedProps } from '../enhance';
+import { MetricKey } from '../../../../types/metrics';
+import { DebtValue, DebtValueProps } from '../DebtValue';
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ useDiffMetric: true })).toMatchSnapshot();
+ expect(shallowRender({ measures: [] })).toMatchSnapshot();
});
-function shallowRender(props: Partial<ComposedProps> = {}) {
+function shallowRender(props: Partial<DebtValueProps> = {}) {
return shallow(
- <Coverage
+ <DebtValue
branchLike={mockMainBranch()}
component={mockComponent()}
- leakPeriod={{ index: 1 } as T.Period}
measures={[
- mockMeasureEnhanced(),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_lines_to_cover',
- key: 'new_lines_to_cover',
- name: 'New Lines to Cover',
- type: 'INT'
- }),
- value: '52'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_coverage',
- key: 'new_coverage',
- name: 'New Coverage'
- }),
- value: '85.0'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'tests',
- key: 'tests',
- name: 'Unit Tests',
- type: 'INT'
- }),
- value: '15'
- })
+ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.sqale_index }) }),
+ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_technical_debt }) })
]}
{...props}
/>
- ).dive();
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/DrilldownMeasureValue-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/DrilldownMeasureValue-test.tsx
new file mode 100644
index 00000000000..73ab71e8bef
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/DrilldownMeasureValue-test.tsx
@@ -0,0 +1,42 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
+import { mockComponent, mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks';
+import { MetricKey } from '../../../../types/metrics';
+import { DrilldownMeasureValue, DrilldownMeasureValueProps } from '../DrilldownMeasureValue';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(shallowRender({ metric: MetricKey.bugs })).toMatchSnapshot('measure not found');
+});
+
+function shallowRender(props: Partial<DrilldownMeasureValueProps> = {}) {
+ return shallow(
+ <DrilldownMeasureValue
+ branchLike={mockMainBranch()}
+ component={mockComponent()}
+ measures={[mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.tests }) })]}
+ metric={MetricKey.tests}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/Event-test.tsx
index 70179114ae4..036705ea099 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/Event-test.tsx
@@ -19,22 +19,22 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { RichQualityGateEvent } from '../../../projectActivity/components/RichQualityGateEventInner';
-import Event from '../Event';
-
-const EVENT = { key: '1', category: 'OTHER', name: 'test' };
-const VERSION = { key: '2', category: 'VERSION', name: '6.5-SNAPSHOT' };
+import { Event } from '../Event';
it('should render an event correctly', () => {
- expect(shallow(<Event event={EVENT} />)).toMatchSnapshot();
+ expect(
+ shallow(<Event event={{ key: '1', category: 'OTHER', name: 'test' }} />)
+ ).toMatchSnapshot();
});
it('should render a version correctly', () => {
- expect(shallow(<Event event={VERSION} />)).toMatchSnapshot();
+ expect(
+ shallow(<Event event={{ key: '2', category: 'VERSION', name: '6.5-SNAPSHOT' }} />)
+ ).toMatchSnapshot();
});
it('should render rich quality gate event', () => {
- const event: RichQualityGateEvent = {
+ const event: T.AnalysisEvent = {
category: 'QUALITY_GATE',
key: 'foo1234',
name: '',
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanel-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanel-test.tsx
new file mode 100644
index 00000000000..4f0094bc1b4
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanel-test.tsx
@@ -0,0 +1,82 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs';
+import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
+import { mockComponent, mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks';
+import { MetricKey } from '../../../../types/metrics';
+import { MeasuresPanel, MeasuresPanelProps, MeasuresPanelTabs } from '../MeasuresPanel';
+
+it('should render correctly for projects', () => {
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot();
+ wrapper.find(BoxedTabs).prop<Function>('onSelect')(MeasuresPanelTabs.Overall);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render correctly for applications', () => {
+ const wrapper = shallowRender({ component: mockComponent({ qualifier: 'APP' }) });
+ expect(wrapper).toMatchSnapshot();
+ wrapper.find(BoxedTabs).prop<Function>('onSelect')(MeasuresPanelTabs.Overall);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render correctly if there is no new code measures', () => {
+ const wrapper = shallowRender({
+ measures: [
+ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.coverage }) }),
+ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.bugs }) })
+ ]
+ });
+ wrapper.find(BoxedTabs).prop<Function>('onSelect')(MeasuresPanelTabs.New);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render correctly if there is no coverage', () => {
+ expect(
+ shallowRender({
+ measures: [
+ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.bugs }) }),
+ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_bugs }) })
+ ]
+ })
+ ).toMatchSnapshot();
+});
+
+it('should render correctly if the data is still loading', () => {
+ expect(shallowRender({ loading: true })).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<MeasuresPanelProps> = {}) {
+ return shallow(
+ <MeasuresPanel
+ branchLike={mockMainBranch()}
+ component={mockComponent()}
+ measures={[
+ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.coverage }) }),
+ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_coverage }) }),
+ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.bugs }) }),
+ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_bugs }) })
+ ]}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/NoCodeWarning-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/NoCodeWarning-test.tsx
new file mode 100644
index 00000000000..cfec0025b07
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/NoCodeWarning-test.tsx
@@ -0,0 +1,68 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like';
+import { mockComponent, mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks';
+import { NoCodeWarning } from '../NoCodeWarning';
+
+it.only('should render correctly if the project has no lines of code', () => {
+ const wrapper = shallowRender();
+ expect(wrapper.children().text()).toBe('overview.project.main_branch_no_lines_of_code');
+
+ wrapper.setProps({ branchLike: mockBranch({ name: 'branch-foo' }) });
+ expect(wrapper.children().text()).toBe('overview.project.branch_X_no_lines_of_code.branch-foo');
+
+ wrapper.setProps({ branchLike: undefined });
+ expect(wrapper.children().text()).toBe('overview.project.no_lines_of_code');
+});
+
+it('should correctly if the project is empty', () => {
+ const wrapper = shallowRender({ measures: [] });
+ expect(wrapper.children().text()).toBe('overview.project.main_branch_empty');
+
+ wrapper.setProps({ branchLike: mockBranch({ name: 'branch-foo' }) });
+ expect(wrapper.children().text()).toBe('overview.project.branch_X_empty.branch-foo');
+
+ wrapper.setProps({ branchLike: undefined });
+ expect(wrapper.children().text()).toBe('overview.project.empty');
+});
+
+it('should render correctly if the application is empty or has no lines of code', () => {
+ const wrapper = shallowRender({
+ component: mockComponent({ qualifier: 'APP' }),
+ measures: [mockMeasureEnhanced({ metric: mockMetric({ key: 'projects' }) })]
+ });
+ expect(wrapper.children().text()).toBe('portfolio.app.no_lines_of_code');
+
+ wrapper.setProps({ measures: [] });
+ expect(wrapper.children().text()).toBe('portfolio.app.empty');
+});
+
+function shallowRender(props = {}) {
+ return shallow(
+ <NoCodeWarning
+ branchLike={mockMainBranch()}
+ component={mockComponent()}
+ measures={[mockMeasureEnhanced({ metric: mockMetric({ key: 'bugs' }) })]}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanel-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanel-test.tsx
new file mode 100644
index 00000000000..8769973e216
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanel-test.tsx
@@ -0,0 +1,83 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
+import {
+ mockQualityGateStatus,
+ mockQualityGateStatusConditionEnhanced
+} from '../../../../helpers/mocks/quality-gates';
+import { mockComponent, mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks';
+import { QualityGatePanel, QualityGatePanelProps } from '../QualityGatePanel';
+
+it('should render correctly for projects', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(
+ shallowRender({ qgStatuses: [mockQualityGateStatus({ status: 'OK', failedConditions: [] })] })
+ ).toMatchSnapshot();
+
+ const wrapper = shallowRender({
+ qgStatuses: [mockQualityGateStatus({ ignoredConditions: true })]
+ });
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render correctly for applications', () => {
+ expect(
+ shallowRender({
+ component: mockComponent({ qualifier: 'APP' }),
+ qgStatuses: [
+ mockQualityGateStatus(),
+ mockQualityGateStatus({
+ failedConditions: [
+ mockQualityGateStatusConditionEnhanced(),
+ mockQualityGateStatusConditionEnhanced({
+ measure: mockMeasureEnhanced({ metric: mockMetric({ key: 'new_code_smells' }) }),
+ metric: 'new_code_smells'
+ })
+ ]
+ })
+ ]
+ })
+ ).toMatchSnapshot();
+
+ const wrapper = shallowRender({
+ component: mockComponent({ qualifier: 'APP' }),
+ qgStatuses: [
+ mockQualityGateStatus(),
+ mockQualityGateStatus({
+ status: 'OK',
+ failedConditions: []
+ })
+ ]
+ });
+ expect(wrapper).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<QualityGatePanelProps> = {}) {
+ return shallow(
+ <QualityGatePanel
+ branchLike={mockMainBranch()}
+ component={mockComponent()}
+ qgStatuses={[mockQualityGateStatus()]}
+ {...props}
+ />
+ );
+}
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..50169bf8223
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
+import {
+ mockQualityGateStatus,
+ mockQualityGateStatusConditionEnhanced
+} from '../../../../helpers/mocks/quality-gates';
+import { mockComponent } from '../../../../helpers/testMocks';
+import { QualityGatePanelSection, QualityGatePanelSectionProps } from '../QualityGatePanelSection';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(
+ shallowRender({
+ qgStatus: mockQualityGateStatus({
+ failedConditions: [],
+ status: 'OK'
+ })
+ }).type()
+ ).toBeNull();
+ expect(shallowRender({ component: mockComponent({ qualifier: 'APP' }) })).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<QualityGatePanelSectionProps> = {}) {
+ return shallow(
+ <QualityGatePanelSection
+ branchLike={mockMainBranch()}
+ component={mockComponent()}
+ qgStatus={mockQualityGateStatus({
+ failedConditions: [
+ mockQualityGateStatusConditionEnhanced({ metric: 'bugs' }),
+ mockQualityGateStatusConditionEnhanced({ metric: 'new_bugs' })
+ ],
+ status: 'ERROR'
+ })}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ActivityPanel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ActivityPanel-test.tsx.snap
new file mode 100644
index 00000000000..90b14ae0e81
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ActivityPanel-test.tsx.snap
@@ -0,0 +1,349 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="overview-panel big-spacer-top"
+ data-test="overview__activity-panel"
+>
+ <h2
+ className="overview-panel-title"
+ >
+ overview.activity
+ </h2>
+ <div
+ className="overview-panel-content"
+ >
+ <div
+ className="display-flex-row"
+ >
+ <div
+ className="display-flex-column flex-1"
+ >
+ <div
+ aria-hidden={true}
+ className="overview-panel-padded display-flex-column flex-1"
+ >
+ <GraphsHeader
+ graph="issues"
+ metrics={
+ Array [
+ Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ ]
+ }
+ updateGraph={[MockFunction]}
+ />
+ <GraphsHistory
+ analyses={
+ Array [
+ Object {
+ "date": 2017-03-01T08:36:01.000Z,
+ "events": Array [
+ Object {
+ "category": "QUALITY_GATE",
+ "description": "Lorem ipsum dolor sit amet",
+ "key": "E11",
+ "name": "Lorem ipsum",
+ "qualityGate": Object {
+ "failing": Array [
+ Object {
+ "branch": "master",
+ "key": "foo",
+ "name": "Foo",
+ },
+ Object {
+ "branch": "feature/bar",
+ "key": "bar",
+ "name": "Bar",
+ },
+ ],
+ "status": "ERROR",
+ "stillFailing": true,
+ },
+ },
+ ],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ Object {
+ "date": 2017-03-01T08:36:01.000Z,
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ ]
+ }
+ graph="issues"
+ graphs={
+ Array [
+ Array [
+ Object {
+ "data": Array [
+ Object {
+ "x": 2016-10-27T14:33:50.000Z,
+ "y": 20,
+ },
+ ],
+ "name": "bugs",
+ "translatedName": "Bugs",
+ "type": "PERCENT",
+ },
+ ],
+ ]
+ }
+ loading={false}
+ measuresHistory={
+ Array [
+ Object {
+ "bestValue": true,
+ "history": Array [
+ Object {
+ "date": 2016-10-27T14:33:50.000Z,
+ "value": "20",
+ },
+ ],
+ "metric": "bugs",
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ series={
+ Array [
+ Object {
+ "data": Array [
+ Object {
+ "x": 2016-10-27T14:33:50.000Z,
+ "y": 20,
+ },
+ ],
+ "name": "bugs",
+ "translatedName": "Bugs",
+ "type": "PERCENT",
+ },
+ ]
+ }
+ />
+ </div>
+ <div
+ className="overview-panel-padded bordered-top text-right"
+ >
+ <ActivityLink
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component="my-project"
+ graph="issues"
+ />
+ </div>
+ </div>
+ <div
+ className="overview-panel-padded bordered-left width-30"
+ >
+ <div
+ data-test="overview__activity-analyses"
+ >
+ <DeferredSpinner
+ className="spacer-top spacer-left"
+ loading={false}
+ timeout={100}
+ >
+ <ul
+ className="spacer-top spacer-left"
+ >
+ <Memo(Analysis)
+ analysis={
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [
+ Object {
+ "category": "QUALITY_GATE",
+ "description": "Lorem ipsum dolor sit amet",
+ "key": "E11",
+ "name": "Lorem ipsum",
+ "qualityGate": Object {
+ "failing": Array [
+ Object {
+ "branch": "master",
+ "key": "foo",
+ "name": "Foo",
+ },
+ Object {
+ "branch": "feature/bar",
+ "key": "bar",
+ "name": "Bar",
+ },
+ ],
+ "status": "ERROR",
+ "stillFailing": true,
+ },
+ },
+ ],
+ "key": "foo",
+ "projectVersion": "1.0",
+ }
+ }
+ key="foo"
+ qualifier="TRK"
+ />
+ </ul>
+ </DeferredSpinner>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly 2`] = `
+<div
+ className="overview-panel big-spacer-top"
+ data-test="overview__activity-panel"
+>
+ <h2
+ className="overview-panel-title"
+ >
+ overview.activity
+ </h2>
+ <div
+ className="overview-panel-content"
+ >
+ <div
+ className="display-flex-row"
+ >
+ <div
+ className="display-flex-column flex-1"
+ >
+ <div
+ aria-hidden={true}
+ className="overview-panel-padded display-flex-column flex-1"
+ >
+ <GraphsHeader
+ graph="issues"
+ metrics={
+ Array [
+ Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ ]
+ }
+ updateGraph={[MockFunction]}
+ />
+ <GraphsHistory
+ analyses={Array []}
+ graph="issues"
+ graphs={
+ Array [
+ Array [
+ Object {
+ "data": Array [
+ Object {
+ "x": 2016-10-27T14:33:50.000Z,
+ "y": 20,
+ },
+ ],
+ "name": "bugs",
+ "translatedName": "Bugs",
+ "type": "PERCENT",
+ },
+ ],
+ ]
+ }
+ loading={true}
+ measuresHistory={
+ Array [
+ Object {
+ "bestValue": true,
+ "history": Array [
+ Object {
+ "date": 2016-10-27T14:33:50.000Z,
+ "value": "20",
+ },
+ ],
+ "metric": "bugs",
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ series={
+ Array [
+ Object {
+ "data": Array [
+ Object {
+ "x": 2016-10-27T14:33:50.000Z,
+ "y": 20,
+ },
+ ],
+ "name": "bugs",
+ "translatedName": "Bugs",
+ "type": "PERCENT",
+ },
+ ]
+ }
+ />
+ </div>
+ <div
+ className="overview-panel-padded bordered-top text-right"
+ >
+ <ActivityLink
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component="my-project"
+ graph="issues"
+ />
+ </div>
+ </div>
+ <div
+ className="overview-panel-padded bordered-left width-30"
+ >
+ <div
+ data-test="overview__activity-analyses"
+ >
+ <DeferredSpinner
+ className="spacer-top spacer-left"
+ loading={true}
+ timeout={100}
+ >
+ <p
+ className="spacer-top spacer-left note"
+ >
+ no_results
+ </p>
+ </DeferredSpinner>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Analysis-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Analysis-test.tsx.snap
new file mode 100644
index 00000000000..e8a36493871
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Analysis-test.tsx.snap
@@ -0,0 +1,81 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<li
+ className="overview-analysis"
+>
+ <div
+ className="small little-spacer-bottom"
+ >
+ <strong>
+ <DateTooltipFormatter
+ date="2017-03-01T09:36:01+0100"
+ />
+ </strong>
+ </div>
+ <div
+ className="overview-activity-events"
+ >
+ <Memo(Event)
+ event={
+ Object {
+ "category": "VERSION",
+ "key": "2",
+ "name": "6.5-SNAPSHOT",
+ }
+ }
+ key="2"
+ />
+ <Memo(Event)
+ event={
+ Object {
+ "category": "OTHER",
+ "key": "1",
+ "name": "test",
+ }
+ }
+ key="1"
+ />
+ </div>
+</li>
+`;
+
+exports[`should render correctly 2`] = `
+<li
+ className="overview-analysis"
+>
+ <div
+ className="small little-spacer-bottom"
+ >
+ <strong>
+ <DateTooltipFormatter
+ date="2017-03-01T09:36:01+0100"
+ />
+ </strong>
+ </div>
+ <div
+ className="overview-activity-events"
+ >
+ <Memo(Event)
+ event={
+ Object {
+ "category": "VERSION",
+ "key": "2",
+ "name": "6.5-SNAPSHOT",
+ }
+ }
+ key="2"
+ />
+ <Memo(Event)
+ event={
+ Object {
+ "category": "OTHER",
+ "key": "1",
+ "name": "test",
+ }
+ }
+ key="1"
+ />
+ </div>
+</li>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ApplicationLeakPeriodInfo-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ApplicationLeakPeriodInfo-test.tsx.snap
new file mode 100644
index 00000000000..8a0e03c64df
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ApplicationLeakPeriodInfo-test.tsx.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div
+ className="note spacer-top display-inline-flex-center"
+>
+ <DateFromNow
+ date="2017-10-01"
+ >
+ <Component />
+ </DateFromNow>
+ <HelpTooltip
+ className="little-spacer-left"
+ overlay="overview.max_new_code_period_from_x.Foo"
+ />
+</div>
+`;
+
+exports[`renders correctly 2`] = `"overview.started_x.2017-10-01"`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverview-test.tsx.snap
new file mode 100644
index 00000000000..a7e7dc16f27
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverview-test.tsx.snap
@@ -0,0 +1,1702 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`application overview should render correctly 1`] = `
+<Memo(BranchOverviewRenderer)
+ analyses={
+ Array [
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ ]
+ }
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [
+ Object {
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ ],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ graph="coverage"
+ leakPeriod={
+ Object {
+ "date": "2017-01-05",
+ "project": "foo",
+ "projectName": "Foo",
+ }
+ }
+ loadingHistory={false}
+ loadingStatus={false}
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "alert_status",
+ "key": "alert_status",
+ "name": "alert_status",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "quality_gate_details",
+ "key": "quality_gate_details",
+ "name": "quality_gate_details",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "bugs",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "new_bugs",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "reliability_rating",
+ "key": "reliability_rating",
+ "name": "reliability_rating",
+ "type": "RATING",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_reliability_rating",
+ "key": "new_reliability_rating",
+ "name": "new_reliability_rating",
+ "type": "RATING",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "vulnerabilities",
+ "key": "vulnerabilities",
+ "name": "vulnerabilities",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_vulnerabilities",
+ "key": "new_vulnerabilities",
+ "name": "new_vulnerabilities",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "security_rating",
+ "key": "security_rating",
+ "name": "security_rating",
+ "type": "RATING",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_security_rating",
+ "key": "new_security_rating",
+ "name": "new_security_rating",
+ "type": "RATING",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "security_hotspots",
+ "key": "security_hotspots",
+ "name": "security_hotspots",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_security_hotspots",
+ "key": "new_security_hotspots",
+ "name": "new_security_hotspots",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "code_smells",
+ "key": "code_smells",
+ "name": "code_smells",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_code_smells",
+ "key": "new_code_smells",
+ "name": "new_code_smells",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "sqale_rating",
+ "key": "sqale_rating",
+ "name": "sqale_rating",
+ "type": "RATING",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_maintainability_rating",
+ "key": "new_maintainability_rating",
+ "name": "new_maintainability_rating",
+ "type": "RATING",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "sqale_index",
+ "key": "sqale_index",
+ "name": "sqale_index",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_technical_debt",
+ "key": "new_technical_debt",
+ "name": "new_technical_debt",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "coverage",
+ "type": "PERCENT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "new_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "lines_to_cover",
+ "key": "lines_to_cover",
+ "name": "lines_to_cover",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_lines_to_cover",
+ "key": "new_lines_to_cover",
+ "name": "new_lines_to_cover",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "tests",
+ "key": "tests",
+ "name": "tests",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "duplicated_lines_density",
+ "key": "duplicated_lines_density",
+ "name": "duplicated_lines_density",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_duplicated_lines_density",
+ "key": "new_duplicated_lines_density",
+ "name": "new_duplicated_lines_density",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "duplicated_blocks",
+ "key": "duplicated_blocks",
+ "name": "duplicated_blocks",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "ncloc",
+ "key": "ncloc",
+ "name": "ncloc",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "ncloc_language_distribution",
+ "key": "ncloc_language_distribution",
+ "name": "ncloc_language_distribution",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "projects",
+ "key": "projects",
+ "name": "projects",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "lines",
+ "key": "lines",
+ "name": "lines",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_lines",
+ "key": "new_lines",
+ "name": "new_lines",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ measuresHistory={
+ Array [
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-05",
+ "value": "2.0",
+ },
+ ],
+ "metric": "bugs",
+ },
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-05",
+ "value": "0",
+ },
+ ],
+ "metric": "vulnerabilities",
+ },
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-01",
+ "value": "1.0",
+ },
+ ],
+ "metric": "sqale_index",
+ },
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-02",
+ "value": "1.0",
+ },
+ ],
+ "metric": "duplicated_lines_density",
+ },
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-03",
+ "value": "10000",
+ },
+ ],
+ "metric": "ncloc",
+ },
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-04",
+ "value": "95.5",
+ },
+ ],
+ "metric": "coverage",
+ },
+ ]
+ }
+ metrics={
+ Array [
+ Object {
+ "id": "alert_status",
+ "key": "alert_status",
+ "name": "alert_status",
+ "type": "INT",
+ },
+ Object {
+ "id": "quality_gate_details",
+ "key": "quality_gate_details",
+ "name": "quality_gate_details",
+ "type": "INT",
+ },
+ Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "bugs",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "new_bugs",
+ "type": "INT",
+ },
+ Object {
+ "id": "reliability_rating",
+ "key": "reliability_rating",
+ "name": "reliability_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "new_reliability_rating",
+ "key": "new_reliability_rating",
+ "name": "new_reliability_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "vulnerabilities",
+ "key": "vulnerabilities",
+ "name": "vulnerabilities",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_vulnerabilities",
+ "key": "new_vulnerabilities",
+ "name": "new_vulnerabilities",
+ "type": "INT",
+ },
+ Object {
+ "id": "security_rating",
+ "key": "security_rating",
+ "name": "security_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "new_security_rating",
+ "key": "new_security_rating",
+ "name": "new_security_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "security_hotspots",
+ "key": "security_hotspots",
+ "name": "security_hotspots",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_security_hotspots",
+ "key": "new_security_hotspots",
+ "name": "new_security_hotspots",
+ "type": "INT",
+ },
+ Object {
+ "id": "code_smells",
+ "key": "code_smells",
+ "name": "code_smells",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_code_smells",
+ "key": "new_code_smells",
+ "name": "new_code_smells",
+ "type": "INT",
+ },
+ Object {
+ "id": "sqale_rating",
+ "key": "sqale_rating",
+ "name": "sqale_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "new_maintainability_rating",
+ "key": "new_maintainability_rating",
+ "name": "new_maintainability_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "sqale_index",
+ "key": "sqale_index",
+ "name": "sqale_index",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_technical_debt",
+ "key": "new_technical_debt",
+ "name": "new_technical_debt",
+ "type": "INT",
+ },
+ Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "coverage",
+ "type": "PERCENT",
+ },
+ Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "new_coverage",
+ "type": "PERCENT",
+ },
+ Object {
+ "id": "lines_to_cover",
+ "key": "lines_to_cover",
+ "name": "lines_to_cover",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_lines_to_cover",
+ "key": "new_lines_to_cover",
+ "name": "new_lines_to_cover",
+ "type": "INT",
+ },
+ Object {
+ "id": "tests",
+ "key": "tests",
+ "name": "tests",
+ "type": "INT",
+ },
+ Object {
+ "id": "duplicated_lines_density",
+ "key": "duplicated_lines_density",
+ "name": "duplicated_lines_density",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_duplicated_lines_density",
+ "key": "new_duplicated_lines_density",
+ "name": "new_duplicated_lines_density",
+ "type": "INT",
+ },
+ Object {
+ "id": "duplicated_blocks",
+ "key": "duplicated_blocks",
+ "name": "duplicated_blocks",
+ "type": "INT",
+ },
+ Object {
+ "id": "ncloc",
+ "key": "ncloc",
+ "name": "ncloc",
+ "type": "INT",
+ },
+ Object {
+ "id": "ncloc_language_distribution",
+ "key": "ncloc_language_distribution",
+ "name": "ncloc_language_distribution",
+ "type": "INT",
+ },
+ Object {
+ "id": "projects",
+ "key": "projects",
+ "name": "projects",
+ "type": "INT",
+ },
+ Object {
+ "id": "lines",
+ "key": "lines",
+ "name": "lines",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_lines",
+ "key": "new_lines",
+ "name": "new_lines",
+ "type": "INT",
+ },
+ ]
+ }
+ onGraphChange={[Function]}
+ projectIsEmpty={false}
+ qgStatuses={
+ Array [
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "10",
+ "error": "1.0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "coverage",
+ "type": "PERCENT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ "metric": "coverage",
+ "op": "GT",
+ "period": undefined,
+ },
+ Object {
+ "actual": "5",
+ "error": "1.0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "new_bugs",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "new_bugs",
+ "op": "GT",
+ "period": 1,
+ },
+ ],
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ },
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "15",
+ "error": "5.0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "new_bugs",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "new_bugs",
+ "op": "GT",
+ "period": 1,
+ },
+ ],
+ "key": "bar",
+ "name": "Bar",
+ "status": "ERROR",
+ },
+ ]
+ }
+/>
+`;
+
+exports[`project overview should render correctly 1`] = `
+<Memo(BranchOverviewRenderer)
+ analyses={
+ Array [
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ Object {
+ "date": "2017-03-01T09:36:01+0100",
+ "events": Array [],
+ "key": "foo",
+ "projectVersion": "1.0",
+ },
+ ]
+ }
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [
+ Object {
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ ],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ graph="coverage"
+ loadingHistory={false}
+ loadingStatus={false}
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "alert_status",
+ "key": "alert_status",
+ "name": "alert_status",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "quality_gate_details",
+ "key": "quality_gate_details",
+ "name": "quality_gate_details",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "bugs",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "new_bugs",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "reliability_rating",
+ "key": "reliability_rating",
+ "name": "reliability_rating",
+ "type": "RATING",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_reliability_rating",
+ "key": "new_reliability_rating",
+ "name": "new_reliability_rating",
+ "type": "RATING",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "vulnerabilities",
+ "key": "vulnerabilities",
+ "name": "vulnerabilities",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_vulnerabilities",
+ "key": "new_vulnerabilities",
+ "name": "new_vulnerabilities",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "security_rating",
+ "key": "security_rating",
+ "name": "security_rating",
+ "type": "RATING",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_security_rating",
+ "key": "new_security_rating",
+ "name": "new_security_rating",
+ "type": "RATING",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "security_hotspots",
+ "key": "security_hotspots",
+ "name": "security_hotspots",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_security_hotspots",
+ "key": "new_security_hotspots",
+ "name": "new_security_hotspots",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "code_smells",
+ "key": "code_smells",
+ "name": "code_smells",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_code_smells",
+ "key": "new_code_smells",
+ "name": "new_code_smells",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "sqale_rating",
+ "key": "sqale_rating",
+ "name": "sqale_rating",
+ "type": "RATING",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_maintainability_rating",
+ "key": "new_maintainability_rating",
+ "name": "new_maintainability_rating",
+ "type": "RATING",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "sqale_index",
+ "key": "sqale_index",
+ "name": "sqale_index",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_technical_debt",
+ "key": "new_technical_debt",
+ "name": "new_technical_debt",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "coverage",
+ "type": "PERCENT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "new_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "lines_to_cover",
+ "key": "lines_to_cover",
+ "name": "lines_to_cover",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_lines_to_cover",
+ "key": "new_lines_to_cover",
+ "name": "new_lines_to_cover",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "tests",
+ "key": "tests",
+ "name": "tests",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "duplicated_lines_density",
+ "key": "duplicated_lines_density",
+ "name": "duplicated_lines_density",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_duplicated_lines_density",
+ "key": "new_duplicated_lines_density",
+ "name": "new_duplicated_lines_density",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "duplicated_blocks",
+ "key": "duplicated_blocks",
+ "name": "duplicated_blocks",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "ncloc",
+ "key": "ncloc",
+ "name": "ncloc",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "ncloc_language_distribution",
+ "key": "ncloc_language_distribution",
+ "name": "ncloc_language_distribution",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "projects",
+ "key": "projects",
+ "name": "projects",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "lines",
+ "key": "lines",
+ "name": "lines",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_lines",
+ "key": "new_lines",
+ "name": "new_lines",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ measuresHistory={
+ Array [
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-05",
+ "value": "2.0",
+ },
+ ],
+ "metric": "bugs",
+ },
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-05",
+ "value": "0",
+ },
+ ],
+ "metric": "vulnerabilities",
+ },
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-01",
+ "value": "1.0",
+ },
+ ],
+ "metric": "sqale_index",
+ },
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-02",
+ "value": "1.0",
+ },
+ ],
+ "metric": "duplicated_lines_density",
+ },
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-03",
+ "value": "10000",
+ },
+ ],
+ "metric": "ncloc",
+ },
+ Object {
+ "history": Array [
+ Object {
+ "date": "PARSED:2019-01-04",
+ "value": "95.5",
+ },
+ ],
+ "metric": "coverage",
+ },
+ ]
+ }
+ metrics={
+ Array [
+ Object {
+ "id": "alert_status",
+ "key": "alert_status",
+ "name": "alert_status",
+ "type": "INT",
+ },
+ Object {
+ "id": "quality_gate_details",
+ "key": "quality_gate_details",
+ "name": "quality_gate_details",
+ "type": "INT",
+ },
+ Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "bugs",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "new_bugs",
+ "type": "INT",
+ },
+ Object {
+ "id": "reliability_rating",
+ "key": "reliability_rating",
+ "name": "reliability_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "new_reliability_rating",
+ "key": "new_reliability_rating",
+ "name": "new_reliability_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "vulnerabilities",
+ "key": "vulnerabilities",
+ "name": "vulnerabilities",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_vulnerabilities",
+ "key": "new_vulnerabilities",
+ "name": "new_vulnerabilities",
+ "type": "INT",
+ },
+ Object {
+ "id": "security_rating",
+ "key": "security_rating",
+ "name": "security_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "new_security_rating",
+ "key": "new_security_rating",
+ "name": "new_security_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "security_hotspots",
+ "key": "security_hotspots",
+ "name": "security_hotspots",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_security_hotspots",
+ "key": "new_security_hotspots",
+ "name": "new_security_hotspots",
+ "type": "INT",
+ },
+ Object {
+ "id": "code_smells",
+ "key": "code_smells",
+ "name": "code_smells",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_code_smells",
+ "key": "new_code_smells",
+ "name": "new_code_smells",
+ "type": "INT",
+ },
+ Object {
+ "id": "sqale_rating",
+ "key": "sqale_rating",
+ "name": "sqale_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "new_maintainability_rating",
+ "key": "new_maintainability_rating",
+ "name": "new_maintainability_rating",
+ "type": "RATING",
+ },
+ Object {
+ "id": "sqale_index",
+ "key": "sqale_index",
+ "name": "sqale_index",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_technical_debt",
+ "key": "new_technical_debt",
+ "name": "new_technical_debt",
+ "type": "INT",
+ },
+ Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "coverage",
+ "type": "PERCENT",
+ },
+ Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "new_coverage",
+ "type": "PERCENT",
+ },
+ Object {
+ "id": "lines_to_cover",
+ "key": "lines_to_cover",
+ "name": "lines_to_cover",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_lines_to_cover",
+ "key": "new_lines_to_cover",
+ "name": "new_lines_to_cover",
+ "type": "INT",
+ },
+ Object {
+ "id": "tests",
+ "key": "tests",
+ "name": "tests",
+ "type": "INT",
+ },
+ Object {
+ "id": "duplicated_lines_density",
+ "key": "duplicated_lines_density",
+ "name": "duplicated_lines_density",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_duplicated_lines_density",
+ "key": "new_duplicated_lines_density",
+ "name": "new_duplicated_lines_density",
+ "type": "INT",
+ },
+ Object {
+ "id": "duplicated_blocks",
+ "key": "duplicated_blocks",
+ "name": "duplicated_blocks",
+ "type": "INT",
+ },
+ Object {
+ "id": "ncloc",
+ "key": "ncloc",
+ "name": "ncloc",
+ "type": "INT",
+ },
+ Object {
+ "id": "ncloc_language_distribution",
+ "key": "ncloc_language_distribution",
+ "name": "ncloc_language_distribution",
+ "type": "INT",
+ },
+ Object {
+ "id": "projects",
+ "key": "projects",
+ "name": "projects",
+ "type": "INT",
+ },
+ Object {
+ "id": "lines",
+ "key": "lines",
+ "name": "lines",
+ "type": "INT",
+ },
+ Object {
+ "id": "new_lines",
+ "key": "new_lines",
+ "name": "new_lines",
+ "type": "INT",
+ },
+ ]
+ }
+ onGraphChange={[Function]}
+ projectIsEmpty={false}
+ qgStatuses={
+ Array [
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "2",
+ "error": "1.0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "new_bugs",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "new_bugs",
+ "op": "GT",
+ "period": 1,
+ },
+ Object {
+ "actual": "5",
+ "error": "2.0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "bugs",
+ "type": "INT",
+ },
+ "periods": undefined,
+ "value": "1.0",
+ },
+ "metric": "bugs",
+ "op": "GT",
+ "period": 0,
+ },
+ ],
+ "ignoredConditions": false,
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ },
+ ]
+ }
+/>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverviewRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverviewRenderer-test.tsx.snap
new file mode 100644
index 00000000000..26d005be471
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverviewRenderer-test.tsx.snap
@@ -0,0 +1,386 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview"
+ >
+ <A11ySkipTarget
+ anchor="overview_main"
+ />
+ <div
+ className="display-flex-row"
+ >
+ <div
+ className="width-25 big-spacer-right"
+ >
+ <Memo(QualityGatePanel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ loading={false}
+ />
+ </div>
+ <div
+ className="flex-1"
+ >
+ <div
+ className="display-flex-column"
+ >
+ <MeasuresPanel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ loading={false}
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ />
+ <Memo(ActivityPanel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ graph="issues"
+ loading={false}
+ measuresHistory={Array []}
+ metrics={Array []}
+ onGraphChange={[MockFunction]}
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly 2`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview"
+ >
+ <A11ySkipTarget
+ anchor="overview_main"
+ />
+ <Memo(NoCodeWarning)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ />
+ </div>
+</div>
+`;
+
+exports[`should render correctly 3`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview"
+ >
+ <A11ySkipTarget
+ anchor="overview_main"
+ />
+ <div
+ className="display-flex-row"
+ >
+ <div
+ className="width-25 big-spacer-right"
+ >
+ <Memo(QualityGatePanel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ loading={true}
+ />
+ </div>
+ <div
+ className="flex-1"
+ >
+ <div
+ className="display-flex-column"
+ >
+ <MeasuresPanel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ loading={true}
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ />
+ <Memo(ActivityPanel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ graph="issues"
+ loading={true}
+ measuresHistory={Array []}
+ metrics={Array []}
+ onGraphChange={[MockFunction]}
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DebtValue-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DebtValue-test.tsx.snap
new file mode 100644
index 00000000000..a96ac567ff1
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DebtValue-test.tsx.snap
@@ -0,0 +1,65 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+ <DrilldownLink
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ className="overview-measures-value text-light"
+ component="my-project"
+ metric="sqale_index"
+ >
+ work_duration.x_minutes.1
+ </DrilldownLink>
+ <span
+ className="big-spacer-left"
+ >
+ Sqale_index
+ </span>
+</Fragment>
+`;
+
+exports[`should render correctly 2`] = `
+<Fragment>
+ <DrilldownLink
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ className="overview-measures-value text-light"
+ component="my-project"
+ metric="new_technical_debt"
+ >
+ work_duration.x_minutes.1
+ </DrilldownLink>
+ <span
+ className="big-spacer-left"
+ >
+ New_technical_debt
+ </span>
+</Fragment>
+`;
+
+exports[`should render correctly 3`] = `
+<Fragment>
+ <span
+ aria-label="no_data"
+ className="overview-measures-empty-value"
+ />
+ <span
+ className="big-spacer-left"
+ >
+ metric.sqale_index.name
+ </span>
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DrilldownMeasureValue-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DrilldownMeasureValue-test.tsx.snap
new file mode 100644
index 00000000000..210bb6293e2
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DrilldownMeasureValue-test.tsx.snap
@@ -0,0 +1,47 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<div
+ className="display-flex-column display-flex-center"
+>
+ <span>
+ <DrilldownLink
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ className="overview-measures-value text-light"
+ component="my-project"
+ metric="tests"
+ >
+ 1
+ </DrilldownLink>
+ </span>
+ <span
+ className="spacer-top"
+ >
+ tests
+ </span>
+</div>
+`;
+
+exports[`should render correctly: measure not found 1`] = `
+<div
+ className="display-flex-column display-flex-center"
+>
+ <span
+ className="overview-measures-value text-light"
+ >
+ -
+ </span>
+ <span
+ className="spacer-top"
+ >
+ bugs
+ </span>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Event-test.tsx.snap
index 56508dbaede..56508dbaede 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Event-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap
new file mode 100644
index 00000000000..a6a8d910dfa
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap
@@ -0,0 +1,25 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly for applications 1`] = `
+<Memo(ApplicationLeakPeriodInfo)
+ leakPeriod={
+ Object {
+ "date": "2017-10-01",
+ "project": "foo",
+ "projectName": "Foo",
+ }
+ }
+/>
+`;
+
+exports[`renders correctly for projects 1`] = `
+<Memo(InjectIntl(ProjectLeakPeriodInfo))
+ leakPeriod={
+ Object {
+ "date": "2019-04-23T02:12:32+0100",
+ "index": 0,
+ "mode": "previous_version",
+ }
+ }
+/>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap
new file mode 100644
index 00000000000..299370e948f
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap
@@ -0,0 +1,5943 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly for applications 1`] = `
+<div
+ className="overview-panel"
+ data-test="overview__measures-panel"
+>
+ <h2
+ className="overview-panel-title"
+ >
+ overview.measures
+ </h2>
+ <BoxedTabs
+ onSelect={[Function]}
+ selected={0}
+ tabs={
+ Array [
+ Object {
+ "key": 0,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ >
+ overview.new_code
+ </span>
+ </div>,
+ },
+ Object {
+ "key": 1,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ style={
+ Object {
+ "position": "absolute",
+ "top": 16,
+ }
+ }
+ >
+ overview.overall_code
+ </span>
+ </div>,
+ },
+ ]
+ }
+ />
+ <div
+ className="overview-panel-content flex-1 bordered"
+ >
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-bug"
+ key="BUG"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="BUG"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-vulnerability"
+ key="VULNERABILITY"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="VULNERABILITY"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="flex-1 small display-flex-center"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ docTooltip={Promise {}}
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="SECURITY_HOTSPOT"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-code_smell"
+ key="CODE_SMELL"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(DebtValue)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="flex-1 small display-flex-center"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="CODE_SMELL"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ >
+ <div
+ className="overview-panel-huge-padded flex-1 bordered-right display-flex-center"
+ data-test="overview__measures-coverage"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ centered={true}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="COVERAGE"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="overview-panel-huge-padded flex-1 display-flex-center"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ centered={true}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="DUPLICATION"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly for applications 2`] = `
+<div
+ className="overview-panel"
+ data-test="overview__measures-panel"
+>
+ <h2
+ className="overview-panel-title"
+ >
+ overview.measures
+ </h2>
+ <BoxedTabs
+ onSelect={[Function]}
+ selected={1}
+ tabs={
+ Array [
+ Object {
+ "key": 0,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ >
+ overview.new_code
+ </span>
+ </div>,
+ },
+ Object {
+ "key": 1,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ style={
+ Object {
+ "position": "absolute",
+ "top": 16,
+ }
+ }
+ >
+ overview.overall_code
+ </span>
+ </div>,
+ },
+ ]
+ }
+ />
+ <div
+ className="overview-panel-content flex-1 bordered"
+ >
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-bug"
+ key="BUG"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="BUG"
+ useDiffMetric={false}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="BUG"
+ useDiffMetric={false}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-vulnerability"
+ key="VULNERABILITY"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="VULNERABILITY"
+ useDiffMetric={false}
+ />
+ </div>
+ <div
+ className="flex-1 small display-flex-center"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ docTooltip={Promise {}}
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="SECURITY_HOTSPOT"
+ useDiffMetric={false}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="VULNERABILITY"
+ useDiffMetric={false}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-code_smell"
+ key="CODE_SMELL"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(DebtValue)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ useDiffMetric={false}
+ />
+ </div>
+ <div
+ className="flex-1 small display-flex-center"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="CODE_SMELL"
+ useDiffMetric={false}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="CODE_SMELL"
+ useDiffMetric={false}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ >
+ <div
+ className="overview-panel-huge-padded flex-1 bordered-right display-flex-center"
+ data-test="overview__measures-coverage"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ centered={false}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="COVERAGE"
+ useDiffMetric={false}
+ />
+ <div
+ className="huge-spacer-left"
+ >
+ <DrilldownMeasureValue
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ metric="tests"
+ />
+ </div>
+ </div>
+ <div
+ className="overview-panel-huge-padded flex-1 display-flex-center"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ centered={false}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="DUPLICATION"
+ useDiffMetric={false}
+ />
+ <div
+ className="huge-spacer-left"
+ >
+ <DrilldownMeasureValue
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ metric="duplicated_blocks"
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly for projects 1`] = `
+<div
+ className="overview-panel"
+ data-test="overview__measures-panel"
+>
+ <h2
+ className="overview-panel-title"
+ >
+ overview.measures
+ </h2>
+ <BoxedTabs
+ onSelect={[Function]}
+ selected={0}
+ tabs={
+ Array [
+ Object {
+ "key": 0,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ >
+ overview.new_code
+ </span>
+ </div>,
+ },
+ Object {
+ "key": 1,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ style={
+ Object {
+ "position": "absolute",
+ "top": 16,
+ }
+ }
+ >
+ overview.overall_code
+ </span>
+ </div>,
+ },
+ ]
+ }
+ />
+ <div
+ className="overview-panel-content flex-1 bordered"
+ >
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-bug"
+ key="BUG"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="BUG"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="BUG"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-vulnerability"
+ key="VULNERABILITY"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="VULNERABILITY"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="flex-1 small display-flex-center"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ docTooltip={Promise {}}
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="SECURITY_HOTSPOT"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="VULNERABILITY"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-code_smell"
+ key="CODE_SMELL"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(DebtValue)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="flex-1 small display-flex-center"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="CODE_SMELL"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="CODE_SMELL"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ >
+ <div
+ className="overview-panel-huge-padded flex-1 bordered-right display-flex-center"
+ data-test="overview__measures-coverage"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ centered={true}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="COVERAGE"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="overview-panel-huge-padded flex-1 display-flex-center"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ centered={true}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="DUPLICATION"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly for projects 2`] = `
+<div
+ className="overview-panel"
+ data-test="overview__measures-panel"
+>
+ <h2
+ className="overview-panel-title"
+ >
+ overview.measures
+ </h2>
+ <BoxedTabs
+ onSelect={[Function]}
+ selected={1}
+ tabs={
+ Array [
+ Object {
+ "key": 0,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ >
+ overview.new_code
+ </span>
+ </div>,
+ },
+ Object {
+ "key": 1,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ style={
+ Object {
+ "position": "absolute",
+ "top": 16,
+ }
+ }
+ >
+ overview.overall_code
+ </span>
+ </div>,
+ },
+ ]
+ }
+ />
+ <div
+ className="overview-panel-content flex-1 bordered"
+ >
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-bug"
+ key="BUG"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="BUG"
+ useDiffMetric={false}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="BUG"
+ useDiffMetric={false}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-vulnerability"
+ key="VULNERABILITY"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="VULNERABILITY"
+ useDiffMetric={false}
+ />
+ </div>
+ <div
+ className="flex-1 small display-flex-center"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ docTooltip={Promise {}}
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="SECURITY_HOTSPOT"
+ useDiffMetric={false}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="VULNERABILITY"
+ useDiffMetric={false}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-code_smell"
+ key="CODE_SMELL"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(DebtValue)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ useDiffMetric={false}
+ />
+ </div>
+ <div
+ className="flex-1 small display-flex-center"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="CODE_SMELL"
+ useDiffMetric={false}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="CODE_SMELL"
+ useDiffMetric={false}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ >
+ <div
+ className="overview-panel-huge-padded flex-1 bordered-right display-flex-center"
+ data-test="overview__measures-coverage"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ centered={false}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="COVERAGE"
+ useDiffMetric={false}
+ />
+ <div
+ className="huge-spacer-left"
+ >
+ <DrilldownMeasureValue
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ metric="tests"
+ />
+ </div>
+ </div>
+ <div
+ className="overview-panel-huge-padded flex-1 display-flex-center"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ centered={false}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="DUPLICATION"
+ useDiffMetric={false}
+ />
+ <div
+ className="huge-spacer-left"
+ >
+ <DrilldownMeasureValue
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_coverage",
+ "key": "new_coverage",
+ "name": "New_coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ metric="duplicated_blocks"
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly if the data is still loading 1`] = `
+<div
+ className="overview-panel"
+ data-test="overview__measures-panel"
+>
+ <h2
+ className="overview-panel-title"
+ >
+ overview.measures
+ </h2>
+ <div
+ className="overview-panel-content overview-panel-big-padded"
+ >
+ <DeferredSpinner
+ loading={true}
+ timeout={100}
+ />
+ </div>
+</div>
+`;
+
+exports[`should render correctly if there is no coverage 1`] = `
+<div
+ className="overview-panel"
+ data-test="overview__measures-panel"
+>
+ <h2
+ className="overview-panel-title"
+ >
+ overview.measures
+ </h2>
+ <BoxedTabs
+ onSelect={[Function]}
+ selected={0}
+ tabs={
+ Array [
+ Object {
+ "key": 0,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ >
+ overview.new_code
+ </span>
+ </div>,
+ },
+ Object {
+ "key": 1,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ style={
+ Object {
+ "position": "absolute",
+ "top": 16,
+ }
+ }
+ >
+ overview.overall_code
+ </span>
+ </div>,
+ },
+ ]
+ }
+ />
+ <div
+ className="overview-panel-content flex-1 bordered"
+ >
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-bug"
+ key="BUG"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="BUG"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="BUG"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-vulnerability"
+ key="VULNERABILITY"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="VULNERABILITY"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="flex-1 small display-flex-center"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ docTooltip={Promise {}}
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="SECURITY_HOTSPOT"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="VULNERABILITY"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ data-test="overview__measures-code_smell"
+ key="CODE_SMELL"
+ >
+ <div
+ className="overview-panel-big-padded flex-1 small display-flex-center big-spacer-left"
+ >
+ <Memo(DebtValue)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="flex-1 small display-flex-center"
+ >
+ <Memo(IssueLabel)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="CODE_SMELL"
+ useDiffMetric={true}
+ />
+ </div>
+ <div
+ className="overview-panel-big-padded overview-measures-aside display-flex-center"
+ >
+ <Memo(IssueRating)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="CODE_SMELL"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ <div
+ className="display-flex-row overview-measures-row"
+ >
+ <div
+ className="overview-panel-huge-padded flex-1 display-flex-center"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ centered={true}
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ measures={
+ Array [
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "bugs",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_bugs",
+ "key": "new_bugs",
+ "name": "New_bugs",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ ]
+ }
+ type="DUPLICATION"
+ useDiffMetric={true}
+ />
+ </div>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly if there is no new code measures 1`] = `
+<div
+ className="overview-panel"
+ data-test="overview__measures-panel"
+>
+ <h2
+ className="overview-panel-title"
+ >
+ overview.measures
+ </h2>
+ <BoxedTabs
+ onSelect={[Function]}
+ selected={0}
+ tabs={
+ Array [
+ Object {
+ "key": 0,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ >
+ overview.new_code
+ </span>
+ </div>,
+ },
+ Object {
+ "key": 1,
+ "label": <div
+ className="text-left overview-measures-tab"
+ >
+ <span
+ className="text-bold"
+ style={
+ Object {
+ "position": "absolute",
+ "top": 16,
+ }
+ }
+ >
+ overview.overall_code
+ </span>
+ </div>,
+ },
+ ]
+ }
+ />
+ <div
+ className="overview-panel-content flex-1 bordered"
+ >
+ <div
+ className="display-flex-center display-flex-justify-center"
+ style={
+ Object {
+ "height": 500,
+ }
+ }
+ >
+ <img
+ alt=""
+ className="spacer-right"
+ height={52}
+ src="/images/source-code.svg"
+ />
+ <div
+ className="big-spacer-left text-muted"
+ style={
+ Object {
+ "maxWidth": 500,
+ }
+ }
+ >
+ <p
+ className="spacer-bottom big-spacer-top big"
+ >
+ overview.measures.empty_explanation
+ </p>
+ <p>
+ <FormattedMessage
+ defaultMessage="overview.measures.empty_link"
+ id="overview.measures.empty_link"
+ values={
+ Object {
+ "learn_more_link": <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/documentation/user-guide/clean-as-you-code/"
+ >
+ learn_more
+ </Link>,
+ }
+ }
+ />
+ </p>
+ </div>
+ </div>
+ </div>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ProjectLeakPeriodInfo-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ProjectLeakPeriodInfo-test.tsx.snap
new file mode 100644
index 00000000000..dacc2a60a94
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ProjectLeakPeriodInfo-test.tsx.snap
@@ -0,0 +1,115 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render a more precise date 1`] = `
+<Fragment>
+ <div
+ className="note spacer-top"
+ >
+ overview.period.previous_version_only_date
+ </div>
+ <DateFromNow
+ date={2018-08-16T22:00:00.000Z}
+ >
+ <Component />
+ </DateFromNow>
+</Fragment>
+`;
+
+exports[`should render correctly for "manual_baseline" 1`] = `
+<Fragment>
+ <div
+ className="note spacer-top"
+ >
+ overview.period.manual_baseline.formattedTime.2019-04-23T02:12:32+0100
+ </div>
+ <DateFromNow
+ date={2019-04-23T01:12:32.000Z}
+ >
+ <Component />
+ </DateFromNow>
+</Fragment>
+`;
+
+exports[`should render correctly for "manual_baseline" 2`] = `
+<Fragment>
+ <div
+ className="note spacer-top"
+ >
+ overview.period.manual_baseline.1.1.2
+ </div>
+ <DateFromNow
+ date={2019-04-23T01:12:32.000Z}
+ >
+ <Component />
+ </DateFromNow>
+</Fragment>
+`;
+
+exports[`should render correctly for "previous_analysis" 1`] = `
+<Fragment>
+ <div
+ className="note spacer-top"
+ >
+ overview.period.previous_analysis.
+ </div>
+ <DateFromNow
+ date={2019-04-23T01:12:32.000Z}
+ >
+ <Component />
+ </DateFromNow>
+</Fragment>
+`;
+
+exports[`should render correctly for "previous_version" 1`] = `
+<Fragment>
+ <div
+ className="note spacer-top"
+ >
+ overview.period.previous_version_only_date
+ </div>
+ <DateFromNow
+ date={2019-04-23T01:12:32.000Z}
+ >
+ <Component />
+ </DateFromNow>
+</Fragment>
+`;
+
+exports[`should render correctly for 10 days 1`] = `
+<div
+ className="note spacer-top"
+>
+ overview.period.days.10
+
+</div>
+`;
+
+exports[`should render correctly for a specific date 1`] = `
+<Fragment>
+ <div
+ className="note spacer-top"
+ >
+ overview.period.date.formatted.2013-01-01
+ </div>
+ <DateFromNow
+ date={2019-04-23T01:12:32.000Z}
+ >
+ <Component />
+ </DateFromNow>
+</Fragment>
+`;
+
+exports[`should render correctly for a specific version 1`] = `
+<Fragment>
+ <div
+ className="note spacer-top"
+ >
+ overview.period.version.0.1
+ </div>
+ <DateFromNow
+ date={2019-04-23T01:12:32.000Z}
+ >
+ <Component />
+ </DateFromNow>
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap
new file mode 100644
index 00000000000..3940bb8d720
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap
@@ -0,0 +1,625 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly for applications 1`] = `
+<div
+ className="overview-panel"
+ data-test="overview__quality-gate-panel"
+>
+ <h2
+ className="overview-panel-title display-inline-flex-center"
+ >
+ overview.quality_gate
+
+ <DocTooltip
+ className="little-spacer-left"
+ doc={Promise {}}
+ />
+ </h2>
+ <div
+ className="overview-panel-content"
+ >
+ <div
+ className="overview-quality-gate-badge-large failed"
+ >
+ <h3
+ className="big-spacer-bottom huge"
+ >
+ metric.level.ERROR
+ </h3>
+ <span
+ className="small"
+ >
+ overview.X_conditions_failed.3
+ </span>
+ </div>
+ <div
+ data-test="overview__quality-gate-conditions"
+ >
+ <Memo(QualityGatePanelSection)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ key="foo"
+ qgStatus={
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "foo",
+ "op": "GT",
+ },
+ ],
+ "ignoredConditions": false,
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ }
+ }
+ />
+ <Memo(QualityGatePanelSection)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ key="foo"
+ qgStatus={
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "foo",
+ "op": "GT",
+ },
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "new_code_smells",
+ "key": "new_code_smells",
+ "name": "New_code_smells",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "new_code_smells",
+ "op": "GT",
+ },
+ ],
+ "ignoredConditions": false,
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ }
+ }
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly for applications 2`] = `
+<div
+ className="overview-panel"
+ data-test="overview__quality-gate-panel"
+>
+ <h2
+ className="overview-panel-title display-inline-flex-center"
+ >
+ overview.quality_gate
+
+ <DocTooltip
+ className="little-spacer-left"
+ doc={Promise {}}
+ />
+ </h2>
+ <div
+ className="overview-panel-content"
+ >
+ <div
+ className="overview-quality-gate-badge-large failed"
+ >
+ <h3
+ className="big-spacer-bottom huge"
+ >
+ metric.level.ERROR
+ </h3>
+ <span
+ className="small"
+ >
+ overview.X_conditions_failed.1
+ </span>
+ </div>
+ <div
+ data-test="overview__quality-gate-conditions"
+ >
+ <Memo(QualityGatePanelSection)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ key="foo"
+ qgStatus={
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "foo",
+ "op": "GT",
+ },
+ ],
+ "ignoredConditions": false,
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ }
+ }
+ />
+ <Memo(QualityGatePanelSection)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "APP",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ key="foo"
+ qgStatus={
+ Object {
+ "failedConditions": Array [],
+ "ignoredConditions": false,
+ "key": "foo",
+ "name": "Foo",
+ "status": "OK",
+ }
+ }
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly for projects 1`] = `
+<div
+ className="overview-panel"
+ data-test="overview__quality-gate-panel"
+>
+ <h2
+ className="overview-panel-title display-inline-flex-center"
+ >
+ overview.quality_gate
+
+ <DocTooltip
+ className="little-spacer-left"
+ doc={Promise {}}
+ />
+ </h2>
+ <div
+ className="overview-panel-content"
+ >
+ <div
+ className="overview-quality-gate-badge-large failed"
+ >
+ <h3
+ className="big-spacer-bottom huge"
+ >
+ metric.level.ERROR
+ </h3>
+ <span
+ className="small"
+ >
+ overview.X_conditions_failed.1
+ </span>
+ </div>
+ <div
+ data-test="overview__quality-gate-conditions"
+ >
+ <Memo(QualityGatePanelSection)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ key="foo"
+ qgStatus={
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "foo",
+ "op": "GT",
+ },
+ ],
+ "ignoredConditions": false,
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ }
+ }
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly for projects 2`] = `
+<div
+ className="overview-panel"
+ data-test="overview__quality-gate-panel"
+>
+ <h2
+ className="overview-panel-title display-inline-flex-center"
+ >
+ overview.quality_gate
+
+ <DocTooltip
+ className="little-spacer-left"
+ doc={Promise {}}
+ />
+ </h2>
+ <div
+ className="overview-panel-content"
+ >
+ <div
+ className="overview-quality-gate-badge-large success"
+ >
+ <h3
+ className="big-spacer-bottom huge"
+ >
+ metric.level.OK
+ </h3>
+ <span
+ className="small"
+ >
+ overview.quality_gate_all_conditions_passed
+ </span>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render correctly for projects 3`] = `
+<div
+ className="overview-panel"
+ data-test="overview__quality-gate-panel"
+>
+ <h2
+ className="overview-panel-title display-inline-flex-center"
+ >
+ overview.quality_gate
+
+ <DocTooltip
+ className="little-spacer-left"
+ doc={Promise {}}
+ />
+ </h2>
+ <Alert
+ className="big-spacer-bottom"
+ display="inline"
+ variant="info"
+ >
+ <span
+ className="text-middle"
+ >
+ overview.quality_gate.ignored_conditions
+ </span>
+ <HelpTooltip
+ className="spacer-left"
+ overlay="overview.quality_gate.ignored_conditions.tooltip"
+ />
+ </Alert>
+ <div
+ className="overview-panel-content"
+ >
+ <div
+ className="overview-quality-gate-badge-large failed"
+ >
+ <h3
+ className="big-spacer-bottom huge"
+ >
+ metric.level.ERROR
+ </h3>
+ <span
+ className="small"
+ >
+ overview.X_conditions_failed.1
+ </span>
+ </div>
+ <div
+ data-test="overview__quality-gate-conditions"
+ >
+ <Memo(QualityGatePanelSection)
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ key="foo"
+ qgStatus={
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "foo",
+ "op": "GT",
+ },
+ ],
+ "ignoredConditions": true,
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ }
+ }
+ />
+ </div>
+ </div>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap
new file mode 100644
index 00000000000..23dfdaf13b7
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap
@@ -0,0 +1,436 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="overview-quality-gate-conditions"
+>
+ <h4
+ className="overview-quality-gate-conditions-section-title"
+ >
+ quality_gates.conditions.new_code
+ </h4>
+ <QualityGateConditions
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "bugs",
+ "op": "GT",
+ },
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "new_bugs",
+ "op": "GT",
+ },
+ ],
+ "ignoredConditions": false,
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ }
+ }
+ failedConditions={
+ Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "new_bugs",
+ "op": "GT",
+ },
+ ]
+ }
+ />
+ <h4
+ className="overview-quality-gate-conditions-section-title"
+ >
+ quality_gates.conditions.overall_code
+ </h4>
+ <QualityGateConditions
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "bugs",
+ "op": "GT",
+ },
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "new_bugs",
+ "op": "GT",
+ },
+ ],
+ "ignoredConditions": false,
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ }
+ }
+ failedConditions={
+ Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "bugs",
+ "op": "GT",
+ },
+ ]
+ }
+ />
+</div>
+`;
+
+exports[`should render correctly 2`] = `
+<div
+ className="overview-quality-gate-conditions"
+>
+ <h3
+ className="overview-quality-gate-conditions-project-name"
+ >
+ Foo
+ </h3>
+ <h4
+ className="overview-quality-gate-conditions-section-title"
+ >
+ quality_gates.conditions.new_code
+ </h4>
+ <QualityGateConditions
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "bugs",
+ "op": "GT",
+ },
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "new_bugs",
+ "op": "GT",
+ },
+ ],
+ "ignoredConditions": false,
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ }
+ }
+ failedConditions={
+ Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "new_bugs",
+ "op": "GT",
+ },
+ ]
+ }
+ />
+ <h4
+ className="overview-quality-gate-conditions-section-title"
+ >
+ quality_gates.conditions.overall_code
+ </h4>
+ <QualityGateConditions
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "excludedFromPurge": true,
+ "isMain": true,
+ "name": "master",
+ }
+ }
+ component={
+ Object {
+ "failedConditions": Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "bugs",
+ "op": "GT",
+ },
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "new_bugs",
+ "op": "GT",
+ },
+ ],
+ "ignoredConditions": false,
+ "key": "foo",
+ "name": "Foo",
+ "status": "ERROR",
+ }
+ }
+ failedConditions={
+ Array [
+ Object {
+ "actual": "10",
+ "error": "0",
+ "level": "ERROR",
+ "measure": Object {
+ "bestValue": true,
+ "leak": "1",
+ "metric": Object {
+ "id": "coverage",
+ "key": "coverage",
+ "name": "Coverage",
+ "type": "PERCENT",
+ },
+ "periods": Array [
+ Object {
+ "bestValue": true,
+ "index": 1,
+ "value": "1.0",
+ },
+ ],
+ "value": "1.0",
+ },
+ "metric": "bugs",
+ "op": "GT",
+ },
+ ]
+ }
+ />
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/components/App.tsx b/server/sonar-web/src/main/js/apps/overview/components/App.tsx
index 3a25fa68865..7790272f2e4 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/App.tsx
@@ -18,19 +18,15 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad';
-import { getBaseUrl, getPathUrlAsString } from 'sonar-ui-common/helpers/urls';
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import { Router, withRouter } from '../../../components/hoc/withRouter';
import { isPullRequest } from '../../../helpers/branch-like';
-import { isSonarCloud } from '../../../helpers/system';
-import { getProjectUrl } from '../../../helpers/urls';
import { BranchLike } from '../../../types/branch-like';
-import OverviewApp from './OverviewApp';
+import BranchOverview from '../branches/BranchOverview';
const EmptyOverview = lazyLoad(() => import('./EmptyOverview'));
-const ReviewApp = lazyLoad(() => import('../pullRequests/ReviewApp'));
+const PullRequestOverview = lazyLoad(() => import('../pullRequests/PullRequestOverview'));
interface Props {
branchLike?: BranchLike;
@@ -38,7 +34,6 @@ interface Props {
component: T.Component;
isInProgress?: boolean;
isPending?: boolean;
- onComponentChange: (changes: Partial<T.Component>) => void;
router: Pick<Router, 'replace'>;
}
@@ -67,19 +62,10 @@ export class App extends React.PureComponent<Props> {
return (
<>
- {isSonarCloud() && (
- <Helmet>
- <link
- href={getBaseUrl() + getPathUrlAsString(getProjectUrl(component.key))}
- rel="canonical"
- />
- </Helmet>
- )}
-
{isPullRequest(branchLike) ? (
<>
<Suggestions suggestions="pull_requests" />
- <ReviewApp branchLike={branchLike} component={component} />
+ <PullRequestOverview branchLike={branchLike} component={component} />
</>
) : (
<>
@@ -91,16 +77,9 @@ export class App extends React.PureComponent<Props> {
branchLikes={branchLikes}
component={component}
hasAnalyses={this.props.isPending || this.props.isInProgress}
- onComponentChange={this.props.onComponentChange}
/>
) : (
- <OverviewApp
- branchLike={branchLike}
- component={component}
- isInProgress={this.props.isInProgress}
- isPending={this.props.isPending}
- onComponentChange={this.props.onComponentChange}
- />
+ <BranchOverview branchLike={branchLike} component={component} />
)}
</>
)}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx
index eb78fc506ca..970ee8560a6 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx
@@ -22,109 +22,71 @@ import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { Alert } from 'sonar-ui-common/components/ui/Alert';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { isBranch, isMainBranch } from '../../../helpers/branch-like';
-import { isSonarCloud } from '../../../helpers/system';
+import { getBranchLikeDisplayName, isBranch, isMainBranch } from '../../../helpers/branch-like';
import { isLoggedIn } from '../../../helpers/users';
import { getCurrentUser, Store } from '../../../store/rootReducer';
import { BranchLike } from '../../../types/branch-like';
import AnalyzeTutorial from '../../tutorials/analyzeProject/AnalyzeTutorial';
-import AnalyzeTutorialSonarCloud from '../../tutorials/analyzeProject/AnalyzeTutorialSonarCloud';
-import MetaContainer from '../meta/MetaContainer';
-interface OwnProps {
+interface Props {
branchLike?: BranchLike;
branchLikes: BranchLike[];
component: T.Component;
+ currentUser: T.CurrentUser;
hasAnalyses?: boolean;
- onComponentChange: (changes: {}) => void;
}
-interface StateProps {
- currentUser: T.CurrentUser;
-}
+export function EmptyOverview(props: Props) {
+ const { branchLike, branchLikes, component, currentUser, hasAnalyses } = props;
-type Props = OwnProps & StateProps;
+ if (!isBranch(branchLike)) {
+ return null;
+ }
-export function EmptyOverview({
- branchLike,
- branchLikes,
- component,
- currentUser,
- hasAnalyses,
- onComponentChange
-}: Props) {
const hasBranches = branchLikes.length > 1;
const hasBadBranchConfig =
branchLikes.length > 2 ||
- (branchLikes.length === 2 &&
- branchLikes.some(branch => isBranch(branch) && !isMainBranch(branchLike)));
- return (
- <div className="page page-limited">
- <div className="overview page-with-sidebar">
- <div className="overview-main page-main">
- {isLoggedIn(currentUser) && isMainBranch(branchLike) ? (
- <>
- {hasBranches && (
- <WarningMessage
- branchLike={branchLike}
- message={
- hasBadBranchConfig
- ? translate('provisioning.no_analysis_on_main_branch.bad_configuration')
- : translate('provisioning.no_analysis_on_main_branch')
- }
- />
- )}
- {!hasBranches &&
- !hasAnalyses &&
- (isSonarCloud() ? (
- <AnalyzeTutorialSonarCloud component={component} currentUser={currentUser} />
- ) : (
- <AnalyzeTutorial component={component} currentUser={currentUser} />
- ))}
- </>
- ) : (
- <WarningMessage
- branchLike={branchLike}
- message={translate('provisioning.no_analysis_on_main_branch')}
- />
- )}
- </div>
+ (branchLikes.length === 2 && branchLikes.some(branch => isBranch(branch)));
- {!isSonarCloud() && (
- <div className="overview-sidebar page-sidebar-fixed">
- <MetaContainer
- branchLike={branchLike}
- component={component}
- onComponentChange={onComponentChange}
- />
- </div>
- )}
- </div>
- </div>
- );
-}
+ const showWarning = isMainBranch(branchLike) && hasBranches;
+ const showTutorial =
+ isMainBranch(branchLike) && !hasBranches && !hasAnalyses && component.qualifier !== 'APP';
-export function WarningMessage({
- branchLike,
- message
-}: {
- branchLike?: BranchLike;
- message: string;
-}) {
- if (!isBranch(branchLike)) {
- return null;
- }
- return (
- <Alert variant="warning">
+ let warning;
+ if (isLoggedIn(currentUser) && showWarning && hasBadBranchConfig) {
+ warning = (
<FormattedMessage
- defaultMessage={message}
- id={message}
+ defaultMessage={translate('provisioning.no_analysis_on_main_branch.bad_configuration')}
+ id="provisioning.no_analysis_on_main_branch.bad_configuration"
values={{
- branchName: branchLike.name,
+ branchName: getBranchLikeDisplayName(branchLike),
branchType: translate('branches.main_branch')
}}
/>
- </Alert>
+ );
+ } else {
+ warning = (
+ <FormattedMessage
+ defaultMessage={translate('provisioning.no_analysis_on_main_branch')}
+ id="provisioning.no_analysis_on_main_branch"
+ values={{
+ branchName: getBranchLikeDisplayName(branchLike)
+ }}
+ />
+ );
+ }
+
+ return (
+ <div className="page page-limited">
+ {isLoggedIn(currentUser) ? (
+ <>
+ {showWarning && <Alert variant="warning">{warning}</Alert>}
+ {showTutorial && <AnalyzeTutorial component={component} currentUser={currentUser} />}
+ </>
+ ) : (
+ <Alert variant="warning">{warning}</Alert>
+ )}
+ </div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx
deleted file mode 100644
index 4a9ae70d613..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { uniq } from 'lodash';
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import { parseDate } from 'sonar-ui-common/helpers/dates';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { isDiffMetric } from 'sonar-ui-common/helpers/measures';
-import { getMeasuresAndMeta } from '../../../api/measures';
-import { getAllTimeMachineData } from '../../../api/time-machine';
-import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget';
-import {
- getBranchLikeDisplayName,
- getBranchLikeQuery,
- isBranch,
- isMainBranch,
- isSameBranchLike
-} from '../../../helpers/branch-like';
-import { enhanceMeasuresWithMetrics } from '../../../helpers/measures';
-import { getLeakPeriod } from '../../../helpers/periods';
-import { fetchMetrics } from '../../../store/rootActions';
-import { getMetrics, Store } from '../../../store/rootReducer';
-import { BranchLike } from '../../../types/branch-like';
-import { ComponentQualifier } from '../../../types/component';
-import {
- DEFAULT_GRAPH,
- getDisplayedHistoryMetrics,
- getProjectActivityGraph
-} from '../../projectActivity/utils';
-import Bugs from '../main/Bugs';
-import CodeSmells from '../main/CodeSmells';
-import Coverage from '../main/Coverage';
-import Duplications from '../main/Duplications';
-import VulnerabilitiesAndHotspots from '../main/VulnerabilitiesAndHotspots';
-import MetaContainer from '../meta/MetaContainer';
-import ApplicationQualityGate from '../qualityGate/ApplicationQualityGate';
-import QualityGate from '../qualityGate/QualityGate';
-import '../styles.css';
-import { HISTORY_METRICS_LIST, METRICS } from '../utils';
-
-interface Props {
- branchLike?: BranchLike;
- component: T.Component;
- isInProgress?: boolean;
- isPending?: boolean;
- fetchMetrics: () => void;
- onComponentChange: (changes: {}) => void;
- metrics: T.Dict<T.Metric>;
-}
-
-interface State {
- history?: {
- [metric: string]: Array<{ date: Date; value?: string }>;
- };
- historyStartDate?: Date;
- loading: boolean;
- measures: T.MeasureEnhanced[];
- periods?: T.Period[];
-}
-
-export class OverviewApp extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { loading: true, measures: [] };
-
- componentDidMount() {
- this.mounted = true;
- this.props.fetchMetrics();
- this.loadMeasures().then(this.loadHistory, () => {});
- }
-
- componentDidUpdate(prevProps: Props) {
- if (
- this.props.component.key !== prevProps.component.key ||
- !isSameBranchLike(this.props.branchLike, prevProps.branchLike)
- ) {
- this.loadMeasures().then(this.loadHistory, () => {});
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- getApplicationLeakPeriod = () => {
- return this.state.measures.find(measure => measure.metric.key === 'new_bugs')
- ? ({ index: 1 } as T.Period)
- : undefined;
- };
-
- isEmpty = () => {
- const { measures } = this.state;
- return (
- measures === undefined ||
- measures.find(measure => ['lines', 'new_lines'].includes(measure.metric.key)) === undefined
- );
- };
-
- loadHistory = () => {
- const { branchLike, component } = this.props;
-
- const { graph, customGraphs } = getProjectActivityGraph(component.key);
- let graphMetrics = getDisplayedHistoryMetrics(graph, customGraphs);
- if (!graphMetrics || graphMetrics.length <= 0) {
- graphMetrics = getDisplayedHistoryMetrics(DEFAULT_GRAPH, []);
- }
-
- const metrics = uniq(HISTORY_METRICS_LIST.concat(graphMetrics));
- return getAllTimeMachineData({
- ...getBranchLikeQuery(branchLike),
- component: component.key,
- metrics: metrics.join()
- }).then(r => {
- if (this.mounted) {
- const history: T.Dict<Array<{ date: Date; value?: string }>> = {};
- r.measures.forEach(measure => {
- const measureHistory = measure.history.map(analysis => ({
- date: parseDate(analysis.date),
- value: analysis.value
- }));
- history[measure.metric] = measureHistory;
- });
- const historyStartDate = history[HISTORY_METRICS_LIST[0]][0].date;
- this.setState({ history, historyStartDate });
- }
- });
- };
-
- loadMeasures = () => {
- const { branchLike, component } = this.props;
- this.setState({ loading: true });
-
- return getMeasuresAndMeta(component.key, METRICS, {
- additionalFields: 'metrics,periods',
- ...getBranchLikeQuery(branchLike)
- }).then(
- ({ component, metrics, periods }) => {
- if (this.mounted && metrics && component.measures) {
- this.setState({
- loading: false,
- measures: enhanceMeasuresWithMetrics(component.measures, metrics),
- periods
- });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- renderEmpty = () => {
- const { branchLike, component } = this.props;
- const isApp = component.qualifier === ComponentQualifier.Application;
-
- /* eslint-disable no-lonely-if */
- // - Is App
- // - No measures, OR measures, but no projects => empty
- // - Else => no lines of code
- // - Else
- // - No measures => empty
- // - Main branch?
- // - LLB?
- // - No branch info?
- // - Measures, but no ncloc (checked in isEmpty()) => no lines of code
- // - Main branch?
- // - LLB?
- // - No branch info?
- let title;
- if (isApp) {
- if (
- this.state.measures === undefined ||
- this.state.measures.find(measure => measure.metric.key === 'projects') === undefined
- ) {
- title = translate('portfolio.app.empty');
- } else {
- title = translate('portfolio.app.no_lines_of_code');
- }
- } else {
- if (this.state.measures === undefined || this.state.measures.length === 0) {
- if (isMainBranch(branchLike)) {
- title = translate('overview.project.main_branch_empty');
- } else if (branchLike !== undefined) {
- title = translateWithParameters(
- 'overview.project.branch_X_empty',
- getBranchLikeDisplayName(branchLike)
- );
- } else {
- title = translate('overview.project.empty');
- }
- } else {
- if (isMainBranch(branchLike)) {
- title = translate('overview.project.main_branch_no_lines_of_code');
- } else if (branchLike !== undefined) {
- title = translateWithParameters(
- 'overview.project.branch_X_no_lines_of_code',
- getBranchLikeDisplayName(branchLike)
- );
- } else {
- title = translate('overview.project.no_lines_of_code');
- }
- }
- }
- /* eslint-enable no-lonely-if */
- return (
- <div className="overview-main page-main">
- {this.renderNewAnalysisRequired()}
- <h3>{title}</h3>
- </div>
- );
- };
-
- renderNewAnalysisRequired = () => {
- const { component, isInProgress, isPending } = this.props;
- const { measures, periods } = this.state;
- const leakPeriod = getLeakPeriod(periods);
-
- if (
- !isInProgress &&
- !isPending &&
- component.qualifier !== ComponentQualifier.Application &&
- measures.some(m => isDiffMetric(m.metric.key)) &&
- leakPeriod === undefined
- ) {
- return (
- <Alert className="big-spacer-bottom" display="inline" variant="warning">
- {translate('overview.project.branch_needs_new_analysis')}
- </Alert>
- );
- } else {
- return null;
- }
- };
-
- renderLoading = () => {
- return (
- <div className="text-center">
- <i className="spinner spacer" />
- </div>
- );
- };
-
- renderMain = () => {
- const { branchLike, component } = this.props;
- const { periods, measures, history, historyStartDate } = this.state;
- const leakPeriod =
- component.qualifier === ComponentQualifier.Application
- ? this.getApplicationLeakPeriod()
- : getLeakPeriod(periods);
- const domainProps = {
- branchLike,
- component,
- measures,
- leakPeriod,
- history,
- historyStartDate
- };
-
- if (this.isEmpty()) {
- return this.renderEmpty();
- }
-
- return (
- <div className="overview-main page-main">
- {this.renderNewAnalysisRequired()}
-
- {component.qualifier === ComponentQualifier.Application ? (
- <ApplicationQualityGate
- branch={isBranch(branchLike) && !isMainBranch(branchLike) ? branchLike : undefined}
- component={component}
- />
- ) : (
- <QualityGate branchLike={branchLike} component={component} measures={measures} />
- )}
-
- <div className="overview-domains-list">
- <Bugs {...domainProps} />
- <VulnerabilitiesAndHotspots {...domainProps} />
- <CodeSmells {...domainProps} />
- <Coverage {...domainProps} />
- <Duplications {...domainProps} />
- </div>
- </div>
- );
- };
-
- render() {
- const { branchLike, component } = this.props;
- const { loading, measures, history } = this.state;
-
- if (loading) {
- return this.renderLoading();
- }
-
- return (
- <div className="page page-limited">
- <div className="overview page-with-sidebar">
- <A11ySkipTarget anchor="overview_main" />
-
- {this.renderMain()}
-
- <div className="overview-sidebar page-sidebar-fixed">
- <MetaContainer
- branchLike={branchLike}
- component={component}
- history={history}
- measures={measures}
- metrics={this.props.metrics}
- onComponentChange={this.props.onComponentChange}
- />
- </div>
- </div>
- </div>
- );
- }
-}
-
-const mapDispatchToProps = { fetchMetrics };
-
-const mapStateToProps = (state: Store) => ({ metrics: getMetrics(state) });
-
-export default connect(mapStateToProps, mapDispatchToProps)(OverviewApp);
diff --git a/server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx b/server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx
deleted file mode 100644
index e6cf42920f9..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { max } from 'd3-array';
-import * as React from 'react';
-import LineChart from 'sonar-ui-common/components/charts/LineChart';
-
-const HEIGHT = 80;
-
-interface Props {
- history: Array<{ date: Date; value?: string }>;
- before?: Date;
- after?: Date;
-}
-
-export default class Timeline extends React.PureComponent<Props> {
- filterSnapshots() {
- const { history, before, after } = this.props;
-
- return history.filter(s => {
- const matchBefore = !before || s.date <= before;
- const matchAfter = !after || s.date >= after;
- return matchBefore && matchAfter;
- });
- }
-
- render() {
- const snapshots = this.filterSnapshots();
-
- if (snapshots.length < 2) {
- return null;
- }
-
- const data = snapshots.map((snapshot, index) => {
- return { x: index, y: snapshot.value !== undefined ? Number(snapshot.value) : undefined };
- });
- const domain = [
- 0,
- max(this.props.history, d => (d.value !== undefined ? parseFloat(d.value) : 0))
- ] as [number, number];
- return (
- <LineChart
- data={data}
- displayBackdrop={true}
- displayPoints={false}
- displayVerticalGrid={false}
- domain={domain}
- height={HEIGHT}
- padding={[0, 0, 0, 0]}
- />
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx
index 49f38f54c7a..3d2050e8bb8 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx
@@ -20,6 +20,7 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { isSonarCloud } from '../../../../helpers/system';
+import BranchOverview from '../../branches/BranchOverview';
import { App } from '../App';
jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
@@ -39,22 +40,16 @@ beforeEach(() => {
(isSonarCloud as jest.Mock<any>).mockReturnValue(false);
});
-it('should render OverviewApp', () => {
+it('should render BranchOverview', () => {
expect(
getWrapper()
- .find('Connect(OverviewApp)')
+ .find(BranchOverview)
.exists()
).toBeTruthy();
});
function getWrapper(props = {}) {
return shallow(
- <App
- branchLikes={[]}
- component={component}
- onComponentChange={jest.fn()}
- router={{ replace: jest.fn() }}
- {...props}
- />
+ <App branchLikes={[]} component={component} router={{ replace: jest.fn() }} {...props} />
);
}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx
index 385df2e3933..655ff347aee 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx
@@ -19,76 +19,41 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import { mockMainBranch, mockPullRequest } from '../../../../helpers/mocks/branch-like';
-import { mockComponent, mockLoggedInUser } from '../../../../helpers/testMocks';
-import { EmptyOverview, WarningMessage } from '../EmptyOverview';
-
-const branch = mockMainBranch();
-const component = mockComponent({ version: '0.0.1' });
-const LoggedInUser = mockLoggedInUser();
+import { mockBranch, mockMainBranch, mockPullRequest } from '../../../../helpers/mocks/branch-like';
+import { mockComponent, mockCurrentUser, mockLoggedInUser } from '../../../../helpers/testMocks';
+import { EmptyOverview } from '../EmptyOverview';
it('renders correctly', () => {
- expect(
- shallow(
- <EmptyOverview
- branchLike={branch}
- branchLikes={[branch]}
- component={component}
- currentUser={LoggedInUser}
- onComponentChange={jest.fn()}
- />
- )
- ).toMatchSnapshot();
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ hasAnalyses: true })).toMatchSnapshot();
+ expect(shallowRender({ currentUser: mockCurrentUser() })).toMatchSnapshot();
});
it('should render another message when there are branches', () => {
+ expect(shallowRender({ branchLikes: [mockMainBranch(), mockBranch()] })).toMatchSnapshot();
expect(
- shallow(
- <EmptyOverview
- branchLike={branch}
- branchLikes={[branch, branch]}
- component={component}
- currentUser={LoggedInUser}
- onComponentChange={jest.fn()}
- />
- )
- ).toMatchSnapshot();
- expect(
- shallow(
- <EmptyOverview
- branchLike={branch}
- branchLikes={[branch, branch, branch]}
- component={component}
- currentUser={LoggedInUser}
- onComponentChange={jest.fn()}
- />
- )
+ shallowRender({
+ branchLikes: [mockMainBranch(), mockBranch(), mockBranch({ name: 'branch-7.8' })]
+ })
).toMatchSnapshot();
});
-it('should not render the tutorial', () => {
- expect(
- shallow(
- <EmptyOverview
- branchLike={branch}
- branchLikes={[branch]}
- component={component}
- currentUser={LoggedInUser}
- hasAnalyses={true}
- onComponentChange={jest.fn()}
- />
- )
- ).toMatchSnapshot();
+it('should not render warning message for pull requests', () => {
+ expect(shallowRender({ branchLike: mockPullRequest() }).type()).toBeNull();
});
-it('should render warning message', () => {
- expect(shallow(<WarningMessage branchLike={branch} message="foo" />)).toMatchSnapshot();
+it('should not render the tutorial for applications', () => {
+ expect(shallowRender({ component: mockComponent({ qualifier: 'APP' }) })).toMatchSnapshot();
});
-it('should not render warning message', () => {
- expect(
- shallow(<WarningMessage branchLike={mockPullRequest()} message="foo" />)
- .find('FormattedMessage')
- .exists()
- ).toBeFalsy();
-});
+function shallowRender(props = {}) {
+ return shallow(
+ <EmptyOverview
+ branchLike={mockMainBranch()}
+ branchLikes={[mockMainBranch()]}
+ component={mockComponent({ version: '0.0.1' })}
+ currentUser={mockLoggedInUser()}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx
deleted file mode 100644
index e12b636ad18..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { getMeasuresAndMeta } from '../../../../api/measures';
-import { getAllTimeMachineData } from '../../../../api/time-machine';
-import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like';
-import { mockComponent, mockMeasure, mockMetric } from '../../../../helpers/testMocks';
-import { OverviewApp } from '../OverviewApp';
-
-jest.mock('../../../../api/measures', () => {
- const { mockMeasure, mockMetric } = getMockHelpers();
- return {
- getMeasuresAndMeta: jest.fn().mockResolvedValue({
- component: {
- measures: [mockMeasure({ metric: 'lines' }), mockMeasure({ metric: 'coverage' })],
- name: 'foo'
- },
- metrics: [mockMetric({ key: 'lines' }), mockMetric()]
- })
- };
-});
-
-jest.mock('sonar-ui-common/helpers/dates', () => ({
- parseDate: jest.fn(date => date)
-}));
-
-jest.mock('../../../../api/time-machine', () => ({
- getAllTimeMachineData: jest.fn().mockResolvedValue({
- measures: [
- { metric: 'bugs', history: [{ date: '2019-01-05', value: '2.0' }] },
- { metric: 'vulnerabilities', history: [{ date: '2019-01-05', value: '0' }] },
- { metric: 'sqale_index', history: [{ date: '2019-01-01', value: '1.0' }] },
- { metric: 'duplicated_lines_density', history: [{ date: '2019-01-02', value: '1.0' }] },
- { metric: 'lines', history: [{ date: '2019-01-03', value: '10000' }] },
- { metric: 'coverage', history: [{ date: '2019-01-04', value: '95.5' }] }
- ]
- })
-}));
-
-it('should render correctly', async () => {
- const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
-
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(getMeasuresAndMeta).toBeCalled();
- expect(getAllTimeMachineData).toBeCalled();
-});
-
-it('should show the correct message if the application is empty or has no lines of code', async () => {
- (getMeasuresAndMeta as jest.Mock).mockResolvedValue({
- component: {
- measures: [mockMeasure({ metric: 'projects' })],
- name: 'foo'
- },
- metrics: [mockMetric({ key: 'projects' })]
- });
-
- const wrapper = shallowRender({
- component: mockComponent({ key: 'foo', name: 'foo', qualifier: 'APP' })
- });
- await waitAndUpdate(wrapper);
- expect(wrapper.find('h3').text()).toBe('portfolio.app.no_lines_of_code');
-
- (getMeasuresAndMeta as jest.Mock).mockResolvedValue({
- component: {
- measures: [],
- name: 'bar'
- },
- metrics: []
- });
- wrapper.setProps({ component: mockComponent({ key: 'bar', name: 'bar', qualifier: 'APP' }) });
- await waitAndUpdate(wrapper);
- expect(wrapper.find('h3').text()).toBe('portfolio.app.empty');
-});
-
-it('should show the correct message if the project is empty', async () => {
- (getMeasuresAndMeta as jest.Mock).mockResolvedValue({
- component: {
- measures: [],
- name: 'foo'
- },
- metrics: []
- });
- const wrapper = shallowRender({ branchLike: mockMainBranch() });
-
- await waitAndUpdate(wrapper);
- expect(wrapper.find('h3').text()).toBe('overview.project.main_branch_empty');
-
- wrapper.setProps({ branchLike: mockBranch({ name: 'branch-foo' }) });
- await waitAndUpdate(wrapper);
- expect(wrapper.find('h3').text()).toBe('overview.project.branch_X_empty.branch-foo');
-
- wrapper.setProps({ branchLike: undefined });
- await waitAndUpdate(wrapper);
- expect(wrapper.find('h3').text()).toBe('overview.project.empty');
-});
-
-it('should show the correct message if the project has no lines of code', async () => {
- (getMeasuresAndMeta as jest.Mock).mockResolvedValue({
- component: {
- measures: [mockMeasure({ metric: 'bugs' })],
- name: 'foo'
- },
- metrics: [mockMetric({ key: 'bugs' })]
- });
- const wrapper = shallowRender({ branchLike: mockMainBranch() });
-
- await waitAndUpdate(wrapper);
- expect(wrapper.find('h3').text()).toBe('overview.project.main_branch_no_lines_of_code');
-
- wrapper.setProps({ branchLike: mockBranch({ name: 'branch-foo' }) });
- await waitAndUpdate(wrapper);
- expect(wrapper.find('h3').text()).toBe('overview.project.branch_X_no_lines_of_code.branch-foo');
-
- wrapper.setProps({ branchLike: undefined });
- await waitAndUpdate(wrapper);
- expect(wrapper.find('h3').text()).toBe('overview.project.no_lines_of_code');
-});
-
-it('should show a warning if the project has new measures, but no period info', async () => {
- (getMeasuresAndMeta as jest.Mock).mockResolvedValue({
- component: {
- measures: [mockMeasure({ metric: 'bugs' }), mockMeasure({ metric: 'new_bugs' })],
- name: 'foo'
- },
- metrics: [mockMetric({ key: 'bugs' }), mockMetric({ key: 'new_bugs' })]
- });
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- expect(
- wrapper
- .find('Alert')
- .dive()
- .text()
- ).toContain('overview.project.branch_needs_new_analysis');
-});
-
-function getMockHelpers() {
- // We use this little "force-requiring" instead of an import statement in
- // order to prevent a hoisting race condition while mocking. If we want to use
- // a mock helper in a Jest mock, we have to require it like this. Otherwise,
- // we get errors like:
- // ReferenceError: testMocks_1 is not defined
- return require.requireActual('../../../../helpers/testMocks');
-}
-
-function shallowRender(props: Partial<OverviewApp['props']> = {}) {
- return shallow(
- <OverviewApp
- branchLike={mockMainBranch()}
- component={mockComponent({ name: 'foo' })}
- fetchMetrics={jest.fn()}
- metrics={{ coverage: mockMetric() }}
- onComponentChange={jest.fn()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.tsx
deleted file mode 100644
index eadfbdc155d..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { parseDate } from 'sonar-ui-common/helpers/dates';
-import Timeline from '../Timeline';
-
-const range = parseDate('2017-05-01T00:00:00.000Z');
-const history = [
- { date: parseDate('2017-04-08T00:00:00.000Z'), value: '29.6' },
- { date: parseDate('2017-04-09T00:00:00.000Z'), value: '170.8' },
- { date: parseDate('2017-05-08T00:00:00.000Z'), value: '360' },
- { date: parseDate('2017-05-09T00:00:00.000Z'), value: '39' }
-];
-
-it('should render correctly with an "after" range', () => {
- expect(shallow(<Timeline after={range} history={history} />)).toMatchSnapshot();
-});
-
-it('should render correctly with a "before" range', () => {
- expect(shallow(<Timeline before={range} history={history} />)).toMatchSnapshot();
-});
-
-it('should have a correct domain with strings or numbers', () => {
- const date = parseDate('2017-05-08T00:00:00.000Z');
- const wrapper = shallow(<Timeline after={range} history={history} />);
- expect(wrapper.find('LineChart').prop('domain')).toEqual([0, 360]);
-
- wrapper.setProps({
- history: [
- { date, value: '360.33' },
- { date, value: '39.54' }
- ]
- });
- expect(wrapper.find('LineChart').prop('domain')).toEqual([0, 360.33]);
-
- wrapper.setProps({
- history: [
- { date, value: 360 },
- { date, value: 39 }
- ]
- });
- expect(wrapper.find('LineChart').prop('domain')).toEqual([0, 360]);
-});
-
-it('should not fail when a value is missing', () => {
- expect(
- shallow(
- <Timeline
- before={range}
- history={[{ date: parseDate('2017-04-07T00:00:00.000Z') }, ...history]}
- />
- )
- ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap
index 99f1d1577a4..204c5941596 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap
@@ -4,206 +4,94 @@ exports[`renders correctly 1`] = `
<div
className="page page-limited"
>
- <div
- className="overview page-with-sidebar"
- >
- <div
- className="overview-main page-main"
- >
- <AnalyzeTutorial
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- "version": "0.0.1",
- }
- }
- currentUser={
- Object {
- "groups": Array [],
- "isLoggedIn": true,
- "login": "luke",
- "name": "Skywalker",
- "scmAccounts": Array [],
- }
- }
- />
- </div>
- <div
- className="overview-sidebar page-sidebar-fixed"
- >
- <Connect(Meta)
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component={
+ <AnalyzeTutorial
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- "version": "0.0.1",
- }
- }
- onComponentChange={[MockFunction]}
- />
- </div>
- </div>
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ "version": "0.0.1",
+ }
+ }
+ currentUser={
+ Object {
+ "groups": Array [],
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ "scmAccounts": Array [],
+ }
+ }
+ />
</div>
`;
-exports[`should not render the tutorial 1`] = `
+exports[`renders correctly 2`] = `
+<div
+ className="page page-limited"
+/>
+`;
+
+exports[`renders correctly 3`] = `
<div
className="page page-limited"
>
- <div
- className="overview page-with-sidebar"
+ <Alert
+ variant="warning"
>
- <div
- className="overview-main page-main"
- />
- <div
- className="overview-sidebar page-sidebar-fixed"
- >
- <Connect(Meta)
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- "version": "0.0.1",
- }
+ <FormattedMessage
+ defaultMessage="provisioning.no_analysis_on_main_branch"
+ id="provisioning.no_analysis_on_main_branch"
+ values={
+ Object {
+ "branchName": "master",
}
- onComponentChange={[MockFunction]}
- />
- </div>
- </div>
+ }
+ />
+ </Alert>
</div>
`;
+exports[`should not render the tutorial for applications 1`] = `
+<div
+ className="page page-limited"
+/>
+`;
+
exports[`should render another message when there are branches 1`] = `
<div
className="page page-limited"
>
- <div
- className="overview page-with-sidebar"
+ <Alert
+ variant="warning"
>
- <div
- className="overview-main page-main"
- >
- <WarningMessage
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- message="provisioning.no_analysis_on_main_branch"
- />
- </div>
- <div
- className="overview-sidebar page-sidebar-fixed"
- >
- <Connect(Meta)
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
+ <FormattedMessage
+ defaultMessage="provisioning.no_analysis_on_main_branch.bad_configuration"
+ id="provisioning.no_analysis_on_main_branch.bad_configuration"
+ values={
+ Object {
+ "branchName": "master",
+ "branchType": "branches.main_branch",
}
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- "version": "0.0.1",
- }
- }
- onComponentChange={[MockFunction]}
- />
- </div>
- </div>
+ }
+ />
+ </Alert>
</div>
`;
@@ -211,80 +99,19 @@ exports[`should render another message when there are branches 2`] = `
<div
className="page page-limited"
>
- <div
- className="overview page-with-sidebar"
+ <Alert
+ variant="warning"
>
- <div
- className="overview-main page-main"
- >
- <WarningMessage
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
+ <FormattedMessage
+ defaultMessage="provisioning.no_analysis_on_main_branch.bad_configuration"
+ id="provisioning.no_analysis_on_main_branch.bad_configuration"
+ values={
+ Object {
+ "branchName": "master",
+ "branchType": "branches.main_branch",
}
- message="provisioning.no_analysis_on_main_branch.bad_configuration"
- />
- </div>
- <div
- className="overview-sidebar page-sidebar-fixed"
- >
- <Connect(Meta)
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- "version": "0.0.1",
- }
- }
- onComponentChange={[MockFunction]}
- />
- </div>
- </div>
-</div>
-`;
-
-exports[`should render warning message 1`] = `
-<Alert
- variant="warning"
->
- <FormattedMessage
- defaultMessage="foo"
- id="foo"
- values={
- Object {
- "branchName": "master",
- "branchType": "branches.main_branch",
}
- }
- />
-</Alert>
+ />
+ </Alert>
+</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap
deleted file mode 100644
index 17432f3a5e6..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap
+++ /dev/null
@@ -1,790 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
- className="text-center"
->
- <i
- className="spinner spacer"
- />
-</div>
-`;
-
-exports[`should render correctly 2`] = `
-<div
- className="page page-limited"
->
- <div
- className="overview page-with-sidebar"
- >
- <A11ySkipTarget
- anchor="overview_main"
- />
- <div
- className="overview-main page-main"
- >
- <QualityGate
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "foo",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- measures={
- Array [
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "lines",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "coverage",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- ]
- }
- />
- <div
- className="overview-domains-list"
- >
- <enhance(Bugs)
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "foo",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- history={
- Object {
- "bugs": Array [
- Object {
- "date": "2019-01-05",
- "value": "2.0",
- },
- ],
- "coverage": Array [
- Object {
- "date": "2019-01-04",
- "value": "95.5",
- },
- ],
- "duplicated_lines_density": Array [
- Object {
- "date": "2019-01-02",
- "value": "1.0",
- },
- ],
- "lines": Array [
- Object {
- "date": "2019-01-03",
- "value": "10000",
- },
- ],
- "sqale_index": Array [
- Object {
- "date": "2019-01-01",
- "value": "1.0",
- },
- ],
- "vulnerabilities": Array [
- Object {
- "date": "2019-01-05",
- "value": "0",
- },
- ],
- }
- }
- historyStartDate="2019-01-05"
- measures={
- Array [
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "lines",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "coverage",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- ]
- }
- />
- <enhance(VulnerabiltiesAndHotspots)
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "foo",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- history={
- Object {
- "bugs": Array [
- Object {
- "date": "2019-01-05",
- "value": "2.0",
- },
- ],
- "coverage": Array [
- Object {
- "date": "2019-01-04",
- "value": "95.5",
- },
- ],
- "duplicated_lines_density": Array [
- Object {
- "date": "2019-01-02",
- "value": "1.0",
- },
- ],
- "lines": Array [
- Object {
- "date": "2019-01-03",
- "value": "10000",
- },
- ],
- "sqale_index": Array [
- Object {
- "date": "2019-01-01",
- "value": "1.0",
- },
- ],
- "vulnerabilities": Array [
- Object {
- "date": "2019-01-05",
- "value": "0",
- },
- ],
- }
- }
- historyStartDate="2019-01-05"
- measures={
- Array [
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "lines",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "coverage",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- ]
- }
- />
- <enhance(CodeSmells)
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "foo",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- history={
- Object {
- "bugs": Array [
- Object {
- "date": "2019-01-05",
- "value": "2.0",
- },
- ],
- "coverage": Array [
- Object {
- "date": "2019-01-04",
- "value": "95.5",
- },
- ],
- "duplicated_lines_density": Array [
- Object {
- "date": "2019-01-02",
- "value": "1.0",
- },
- ],
- "lines": Array [
- Object {
- "date": "2019-01-03",
- "value": "10000",
- },
- ],
- "sqale_index": Array [
- Object {
- "date": "2019-01-01",
- "value": "1.0",
- },
- ],
- "vulnerabilities": Array [
- Object {
- "date": "2019-01-05",
- "value": "0",
- },
- ],
- }
- }
- historyStartDate="2019-01-05"
- measures={
- Array [
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "lines",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "coverage",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- ]
- }
- />
- <enhance(Coverage)
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "foo",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- history={
- Object {
- "bugs": Array [
- Object {
- "date": "2019-01-05",
- "value": "2.0",
- },
- ],
- "coverage": Array [
- Object {
- "date": "2019-01-04",
- "value": "95.5",
- },
- ],
- "duplicated_lines_density": Array [
- Object {
- "date": "2019-01-02",
- "value": "1.0",
- },
- ],
- "lines": Array [
- Object {
- "date": "2019-01-03",
- "value": "10000",
- },
- ],
- "sqale_index": Array [
- Object {
- "date": "2019-01-01",
- "value": "1.0",
- },
- ],
- "vulnerabilities": Array [
- Object {
- "date": "2019-01-05",
- "value": "0",
- },
- ],
- }
- }
- historyStartDate="2019-01-05"
- measures={
- Array [
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "lines",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "coverage",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- ]
- }
- />
- <enhance(Duplications)
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "foo",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- history={
- Object {
- "bugs": Array [
- Object {
- "date": "2019-01-05",
- "value": "2.0",
- },
- ],
- "coverage": Array [
- Object {
- "date": "2019-01-04",
- "value": "95.5",
- },
- ],
- "duplicated_lines_density": Array [
- Object {
- "date": "2019-01-02",
- "value": "1.0",
- },
- ],
- "lines": Array [
- Object {
- "date": "2019-01-03",
- "value": "10000",
- },
- ],
- "sqale_index": Array [
- Object {
- "date": "2019-01-01",
- "value": "1.0",
- },
- ],
- "vulnerabilities": Array [
- Object {
- "date": "2019-01-05",
- "value": "0",
- },
- ],
- }
- }
- historyStartDate="2019-01-05"
- measures={
- Array [
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "lines",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "coverage",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- ]
- }
- />
- </div>
- </div>
- <div
- className="overview-sidebar page-sidebar-fixed"
- >
- <Connect(Meta)
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "foo",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- history={
- Object {
- "bugs": Array [
- Object {
- "date": "2019-01-05",
- "value": "2.0",
- },
- ],
- "coverage": Array [
- Object {
- "date": "2019-01-04",
- "value": "95.5",
- },
- ],
- "duplicated_lines_density": Array [
- Object {
- "date": "2019-01-02",
- "value": "1.0",
- },
- ],
- "lines": Array [
- Object {
- "date": "2019-01-03",
- "value": "10000",
- },
- ],
- "sqale_index": Array [
- Object {
- "date": "2019-01-01",
- "value": "1.0",
- },
- ],
- "vulnerabilities": Array [
- Object {
- "date": "2019-01-05",
- "value": "0",
- },
- ],
- }
- }
- measures={
- Array [
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "lines",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- Object {
- "bestValue": true,
- "metric": Object {
- "id": "coverage",
- "key": "coverage",
- "name": "Coverage",
- "type": "PERCENT",
- },
- "periods": Array [
- Object {
- "bestValue": true,
- "index": 1,
- "value": "1.0",
- },
- ],
- "value": "1.0",
- },
- ]
- }
- metrics={
- Object {
- "coverage": Object {
- "id": "coverage",
- "key": "coverage",
- "name": "Coverage",
- "type": "PERCENT",
- },
- }
- }
- onComponentChange={[MockFunction]}
- />
- </div>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.tsx.snap
deleted file mode 100644
index 710cbbf695a..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.tsx.snap
+++ /dev/null
@@ -1,110 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should not fail when a value is missing 1`] = `
-<LineChart
- data={
- Array [
- Object {
- "x": 0,
- "y": undefined,
- },
- Object {
- "x": 1,
- "y": 29.6,
- },
- Object {
- "x": 2,
- "y": 170.8,
- },
- ]
- }
- displayBackdrop={true}
- displayPoints={false}
- displayVerticalGrid={false}
- domain={
- Array [
- 0,
- 360,
- ]
- }
- height={80}
- padding={
- Array [
- 0,
- 0,
- 0,
- 0,
- ]
- }
-/>
-`;
-
-exports[`should render correctly with a "before" range 1`] = `
-<LineChart
- data={
- Array [
- Object {
- "x": 0,
- "y": 29.6,
- },
- Object {
- "x": 1,
- "y": 170.8,
- },
- ]
- }
- displayBackdrop={true}
- displayPoints={false}
- displayVerticalGrid={false}
- domain={
- Array [
- 0,
- 360,
- ]
- }
- height={80}
- padding={
- Array [
- 0,
- 0,
- 0,
- 0,
- ]
- }
-/>
-`;
-
-exports[`should render correctly with an "after" range 1`] = `
-<LineChart
- data={
- Array [
- Object {
- "x": 0,
- "y": 360,
- },
- Object {
- "x": 1,
- "y": 39,
- },
- ]
- }
- displayBackdrop={true}
- displayPoints={false}
- displayVerticalGrid={false}
- domain={
- Array [
- 0,
- 360,
- ]
- }
- height={80}
- padding={
- Array [
- 0,
- 0,
- 0,
- 0,
- ]
- }
-/>
-`;
diff --git a/server/sonar-web/src/main/js/apps/overview/events/AnalysesList.tsx b/server/sonar-web/src/main/js/apps/overview/events/AnalysesList.tsx
deleted file mode 100644
index a66a705cda1..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/events/AnalysesList.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 * as React from 'react';
-import { Link } from 'react-router';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { getProjectActivity } from '../../../api/projectActivity';
-import PreviewGraph from '../../../components/preview-graph/PreviewGraph';
-import { getBranchLikeQuery, isSameBranchLike } from '../../../helpers/branch-like';
-import { getActivityUrl } from '../../../helpers/urls';
-import { BranchLike } from '../../../types/branch-like';
-import Analysis from './Analysis';
-
-interface Props {
- branchLike?: BranchLike;
- component: T.Component;
- history?: {
- [metric: string]: Array<{ date: Date; value?: string }>;
- };
- metrics: T.Dict<T.Metric>;
- qualifier: string;
-}
-
-interface State {
- analyses: T.Analysis[];
- loading: boolean;
-}
-
-const PAGE_SIZE = 3;
-
-export default class AnalysesList extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { analyses: [], loading: true };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchData();
- }
-
- componentDidUpdate(prevProps: Props) {
- if (
- prevProps.component.key !== this.props.component.key ||
- !isSameBranchLike(prevProps.branchLike, this.props.branchLike)
- ) {
- this.fetchData();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- getTopLevelComponent = () => {
- const { component } = this.props;
- let current = component.breadcrumbs.length - 1;
- while (
- current > 0 &&
- !['TRK', 'VW', 'APP'].includes(component.breadcrumbs[current].qualifier)
- ) {
- current--;
- }
- return component.breadcrumbs[current].key;
- };
-
- fetchData = () => {
- this.setState({ loading: true });
-
- getProjectActivity({
- ...getBranchLikeQuery(this.props.branchLike),
- project: this.getTopLevelComponent(),
- ps: PAGE_SIZE
- }).then(
- ({ analyses }) => {
- if (this.mounted) {
- this.setState({ analyses, loading: false });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- renderList(analyses: T.Analysis[]) {
- if (!analyses.length) {
- return <p className="spacer-top note">{translate('no_results')}</p>;
- }
-
- return (
- <ul className="spacer-top">
- {analyses.map(analysis => (
- <Analysis analysis={analysis} key={analysis.key} qualifier={this.props.qualifier} />
- ))}
- </ul>
- );
- }
-
- render() {
- const { analyses, loading } = this.state;
-
- if (loading) {
- return null;
- }
-
- return (
- <div className="overview-meta-card">
- <h4 className="overview-meta-header">
- {translate('overview.project_activity', this.props.component.qualifier)}
- </h4>
-
- <PreviewGraph
- branchLike={this.props.branchLike}
- history={this.props.history}
- metrics={this.props.metrics}
- project={this.props.component.key}
- />
-
- {this.renderList(analyses)}
-
- <div className="spacer-top small">
- <Link to={getActivityUrl(this.props.component.key, this.props.branchLike)}>
- {translate('show_more')}
- </Link>
- </div>
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/AnalysesList-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/AnalysesList-test.tsx.snap
deleted file mode 100644
index 2320d0d0c4f..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/AnalysesList-test.tsx.snap
+++ /dev/null
@@ -1,18 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render show more link 1`] = `
-<Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "id": "foo",
- },
- }
- }
->
- show_more
-</Link>
-`;
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.tsx.snap
deleted file mode 100644
index f61e89ebd8a..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.tsx.snap
+++ /dev/null
@@ -1,41 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should sort the events with version first 1`] = `
-<li
- className="overview-analysis"
->
- <div
- className="small little-spacer-bottom"
- >
- <strong>
- <DateTooltipFormatter
- date="2017-06-10T16:10:59+0200"
- />
- </strong>
- </div>
- <div
- className="overview-activity-events"
- >
- <Event
- event={
- Object {
- "category": "VERSION",
- "key": "2",
- "name": "6.5-SNAPSHOT",
- }
- }
- key="2"
- />
- <Event
- event={
- Object {
- "category": "OTHER",
- "key": "1",
- "name": "test",
- }
- }
- key="1"
- />
- </div>
-</li>
-`;
diff --git a/server/sonar-web/src/main/js/apps/overview/main/Bugs.tsx b/server/sonar-web/src/main/js/apps/overview/main/Bugs.tsx
deleted file mode 100644
index 1ef59518983..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/Bugs.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 * as React from 'react';
-import BugIcon from 'sonar-ui-common/components/icons/BugIcon';
-import { translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../../components/docs/DocTooltip';
-import DateFromNow from '../../../components/intl/DateFromNow';
-import { isBranch, isMainBranch } from '../../../helpers/branch-like';
-import ApplicationLeakPeriodLegend from '../components/ApplicationLeakPeriodLegend';
-import LeakPeriodLegend from '../components/LeakPeriodLegend';
-import { getMetricName } from '../utils';
-import enhance, { ComposedProps } from './enhance';
-
-export class Bugs extends React.PureComponent<ComposedProps> {
- renderHeader() {
- return this.props.renderHeader('Reliability');
- }
-
- renderTimelineStartDate(historyStartDate?: Date) {
- if (!historyStartDate) {
- return undefined;
- }
- return (
- <DateFromNow date={historyStartDate}>
- {fromNow => (
- <span className="overview-domain-timeline-date">
- {translateWithParameters('overview.started_x', fromNow)}
- </span>
- )}
- </DateFromNow>
- );
- }
-
- renderTimeline(range: string, historyStartDate?: Date) {
- return this.props.renderTimeline('bugs', range, this.renderTimelineStartDate(historyStartDate));
- }
-
- renderLeak() {
- const { branchLike, component, leakPeriod } = this.props;
- if (!this.props.hasDiffMetrics()) {
- return null;
- }
-
- return (
- <div className="overview-domain-leak">
- {component.qualifier === 'APP' && (
- <ApplicationLeakPeriodLegend
- branch={isBranch(branchLike) && !isMainBranch(branchLike) ? branchLike : undefined}
- component={component}
- />
- )}
-
- {component.qualifier !== 'APP' && leakPeriod !== undefined && (
- <LeakPeriodLegend period={leakPeriod} />
- )}
-
- <div className="overview-domain-measures">
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- <span className="offset-left">{this.props.renderIssues('new_bugs', 'BUG')}</span>
- {this.props.renderRating('new_reliability_rating')}
- </div>
- <div className="overview-domain-measure-label">
- <BugIcon className="little-spacer-right" />
- {getMetricName('new_bugs')}
- </div>
- </div>
- </div>
- {this.renderTimeline('after')}
- </div>
- );
- }
-
- renderNutshell() {
- return (
- <div className="overview-domain-nutshell">
- <div className="overview-domain-measures">
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- <span className="offset-left">{this.props.renderIssues('bugs', 'BUG')}</span>
- {this.props.renderRating('reliability_rating')}
- </div>
- <div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
- <BugIcon className="little-spacer-right " />
- {getMetricName('bugs')}
- <DocTooltip
- className="little-spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/bugs.md')}
- />
- </div>
- {this.props.renderHistoryLink('bugs')}
- </div>
- </div>
- {this.renderTimeline('before', this.props.historyStartDate)}
- </div>
- );
- }
-
- render() {
- const { measures } = this.props;
- const bugsMeasure = measures.find(measure => measure.metric.key === 'bugs');
- if (!bugsMeasure) {
- return null;
- }
- return (
- <div className="overview-card">
- {this.renderHeader()}
-
- <div className="overview-domain-panel">
- {this.renderNutshell()}
- {this.renderLeak()}
- </div>
- </div>
- );
- }
-}
-
-export default enhance(Bugs);
diff --git a/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx b/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx
deleted file mode 100644
index 28b8b868883..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 * as React from 'react';
-import CodeSmellIcon from 'sonar-ui-common/components/icons/CodeSmellIcon';
-import { formatMeasure } from 'sonar-ui-common/helpers/measures';
-import DocTooltip from '../../../components/docs/DocTooltip';
-import DrilldownLink from '../../../components/shared/DrilldownLink';
-import { getMetricName } from '../utils';
-import enhance, { ComposedProps } from './enhance';
-
-export class CodeSmells extends React.PureComponent<ComposedProps> {
- renderHeader() {
- return this.props.renderHeader('Maintainability');
- }
-
- renderDebt(metric: string) {
- const { branchLike, measures, component } = this.props;
- const measure = measures.find(measure => measure.metric.key === metric);
- const value = measure ? this.props.getValue(measure) : undefined;
-
- return (
- <DrilldownLink branchLike={branchLike} component={component.key} metric={metric}>
- {formatMeasure(value, 'SHORT_WORK_DUR')}
- </DrilldownLink>
- );
- }
-
- renderTimeline(range: string) {
- return this.props.renderTimeline('sqale_index', range);
- }
-
- renderLeak() {
- if (!this.props.hasDiffMetrics()) {
- return null;
- }
-
- return (
- <div className="overview-domain-leak">
- <div className="overview-domain-measures">
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- <span className="offset-left">{this.renderDebt('new_technical_debt')}</span>
- {this.props.renderRating('new_maintainability_rating')}
- </div>
- <div className="overview-domain-measure-label">{getMetricName('new_effort')}</div>
- </div>
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- {this.props.renderIssues('new_code_smells', 'CODE_SMELL')}
- </div>
- <div className="overview-domain-measure-label">
- <CodeSmellIcon className="little-spacer-right" />
- {getMetricName('new_code_smells')}
- </div>
- </div>
- </div>
- {this.renderTimeline('after')}
- </div>
- );
- }
-
- renderNutshell() {
- return (
- <div className="overview-domain-nutshell">
- <div className="overview-domain-measures">
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- <span className="offset-left">{this.renderDebt('sqale_index')}</span>
- {this.props.renderRating('sqale_rating')}
- </div>
- <div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
- {getMetricName('effort')}
- <DocTooltip
- className="little-spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/debt.md')}
- />
- </div>
- {this.props.renderHistoryLink('sqale_index')}
- </div>
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- {this.props.renderIssues('code_smells', 'CODE_SMELL')}
- </div>
- <div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
- <CodeSmellIcon className="little-spacer-right " />
- {getMetricName('code_smells')}
- <DocTooltip
- className="little-spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/code-smells.md')}
- />
- </div>
- {this.props.renderHistoryLink('code_smells')}
- </div>
- </div>
- {this.renderTimeline('before')}
- </div>
- );
- }
-
- render() {
- const { measures } = this.props;
- const codeSmellsMeasure = measures.find(measure => measure.metric.key === 'code_smells');
- if (!codeSmellsMeasure) {
- return null;
- }
- return (
- <div className="overview-card" id="overview-code-smells">
- {this.renderHeader()}
-
- <div className="overview-domain-panel">
- {this.renderNutshell()}
- {this.renderLeak()}
- </div>
- </div>
- );
- }
-}
-
-export default enhance(CodeSmells);
diff --git a/server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx b/server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx
deleted file mode 100644
index fe24f269adc..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 * as React from 'react';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import {
- formatMeasure,
- getMinDecimalsCountToBeDistinctFromThreshold
-} from 'sonar-ui-common/helpers/measures';
-import DocTooltip from '../../../components/docs/DocTooltip';
-import DrilldownLink from '../../../components/shared/DrilldownLink';
-import CoverageRating from '../../../components/ui/CoverageRating';
-import { getMetricName, getThreshold } from '../utils';
-import enhance, { ComposedProps } from './enhance';
-
-export class Coverage extends React.PureComponent<ComposedProps> {
- getCoverage() {
- const measure = this.props.measures.find(measure => measure.metric.key === 'coverage');
- return Number(measure ? measure.value : undefined);
- }
-
- renderHeader() {
- return this.props.renderHeader('Coverage', translate('metric.coverage.name'));
- }
-
- renderTimeline(range: string) {
- return this.props.renderTimeline('coverage', range);
- }
-
- renderTests() {
- return this.props.renderMeasure(
- 'tests',
- <DocTooltip
- className="little-spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/unit-tests.md')}
- />
- );
- }
-
- renderCoverage() {
- const { branchLike, component } = this.props;
- const metric = 'coverage';
- const coverage = this.getCoverage();
-
- return (
- <div className="overview-domain-measure">
- <div className="display-inline-block text-middle big-spacer-right neg-offset-left">
- <CoverageRating size="big" value={coverage} />
- </div>
-
- <div className="display-inline-block text-middle">
- <div className="overview-domain-measure-value">
- <DrilldownLink branchLike={branchLike} component={component.key} metric={metric}>
- <span className="js-overview-main-coverage">
- {formatMeasure(coverage, 'PERCENT')}
- </span>
- </DrilldownLink>
- </div>
-
- <div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
- {getMetricName('coverage')}
- <DocTooltip
- className="little-spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/coverage.md')}
- />
- </div>
- {this.props.renderHistoryLink('coverage')}
- </div>
- {this.props.renderHistoryLink('coverage')}
- </div>
- );
- }
-
- renderNewCoverage() {
- const { branchLike, component, measures } = this.props;
-
- const newCoverageMeasure = measures.find(measure => measure.metric.key === 'new_coverage');
- const newCoverageValue = newCoverageMeasure && this.props.getValue(newCoverageMeasure);
- const formattedValue =
- newCoverageMeasure && newCoverageValue !== undefined ? (
- <div>
- <DrilldownLink
- branchLike={branchLike}
- component={component.key}
- metric={newCoverageMeasure.metric.key}>
- <span className="js-overview-main-new-coverage">
- {formatMeasure(newCoverageValue, 'PERCENT', {
- decimals: getMinDecimalsCountToBeDistinctFromThreshold(
- parseFloat(newCoverageValue),
- getThreshold(measures, 'new_coverage')
- )
- })}
- </span>
- </DrilldownLink>
- </div>
- ) : (
- <span className="big">—</span>
- );
-
- const newLinesToCover = measures.find(measure => measure.metric.key === 'new_lines_to_cover');
- const newLinesToCoverValue = newLinesToCover && this.props.getValue(newLinesToCover);
- const label =
- newLinesToCover && newLinesToCoverValue !== undefined && Number(newLinesToCoverValue) > 0 ? (
- <div className="overview-domain-measure-label">
- {translate('overview.coverage_on')}
- <br />
- <DrilldownLink
- branchLike={branchLike}
- className="spacer-right overview-domain-secondary-measure-value"
- component={component.key}
- metric={newLinesToCover.metric.key}>
- <span className="js-overview-main-new-coverage">
- {formatMeasure(newLinesToCoverValue, 'SHORT_INT')}
- </span>
- </DrilldownLink>
- {getMetricName('new_lines_to_cover')}
- </div>
- ) : (
- <div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
- {getMetricName('new_coverage')}
- </div>
- );
-
- return (
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">{formattedValue}</div>
- {label}
- </div>
- );
- }
-
- renderNutshell() {
- return (
- <div className="overview-domain-nutshell">
- <div className="overview-domain-measures overview-domain-measures-big">
- {this.renderCoverage()}
- {this.renderTests()}
- </div>
-
- {this.renderTimeline('before')}
- </div>
- );
- }
-
- renderLeak() {
- if (!this.props.hasDiffMetrics()) {
- return null;
- }
- return (
- <div className="overview-domain-leak">
- <div className="overview-domain-measures">{this.renderNewCoverage()}</div>
-
- {this.renderTimeline('after')}
- </div>
- );
- }
-
- render() {
- const { measures } = this.props;
- const coverageMeasure = measures.find(measure => measure.metric.key === 'coverage');
- if (!coverageMeasure) {
- return null;
- }
- return (
- <div className="overview-card">
- {this.renderHeader()}
-
- <div className="overview-domain-panel">
- {this.renderNutshell()}
- {this.renderLeak()}
- </div>
- </div>
- );
- }
-}
-
-export default enhance(Coverage);
diff --git a/server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx b/server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx
deleted file mode 100644
index a22c2f09cbd..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 * as React from 'react';
-import DuplicationsRating from 'sonar-ui-common/components/ui/DuplicationsRating';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import {
- formatMeasure,
- getMinDecimalsCountToBeDistinctFromThreshold
-} from 'sonar-ui-common/helpers/measures';
-import DocTooltip from '../../../components/docs/DocTooltip';
-import DrilldownLink from '../../../components/shared/DrilldownLink';
-import { getMetricName, getThreshold } from '../utils';
-import enhance, { ComposedProps } from './enhance';
-
-export class Duplications extends React.PureComponent<ComposedProps> {
- renderHeader() {
- return this.props.renderHeader('Duplications', translate('overview.domain.duplications'));
- }
-
- renderTimeline(range: string) {
- return this.props.renderTimeline('duplicated_lines_density', range);
- }
-
- renderDuplicatedBlocks() {
- return this.props.renderMeasure(
- 'duplicated_blocks',
- <DocTooltip
- className="little-spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/duplicated-blocks.md')}
- />
- );
- }
-
- renderDuplications() {
- const { branchLike, component, measures } = this.props;
- const measure = measures.find(measure => measure.metric.key === 'duplicated_lines_density');
- if (!measure) {
- return null;
- }
-
- const duplications = Number(measure.value);
-
- return (
- <div className="overview-domain-measure">
- <div className="display-inline-block text-middle big-spacer-right neg-offset-left">
- <DuplicationsRating size="big" value={duplications} />
- </div>
-
- <div className="display-inline-block text-middle">
- <div className="overview-domain-measure-value">
- <DrilldownLink
- branchLike={branchLike}
- component={component.key}
- metric="duplicated_lines_density">
- {formatMeasure(duplications, 'PERCENT')}
- </DrilldownLink>
- </div>
-
- <div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
- {getMetricName('duplications')}
- <DocTooltip
- className="little-spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/duplications.md')}
- />
- </div>
- {this.props.renderHistoryLink('duplicated_lines_density')}
- </div>
- </div>
- );
- }
-
- renderNewDuplications() {
- const { branchLike, component, measures } = this.props;
- const newDuplicationsMeasure = measures.find(
- measure => measure.metric.key === 'new_duplicated_lines_density'
- );
- const newDuplicationsValue =
- newDuplicationsMeasure && this.props.getValue(newDuplicationsMeasure);
- const formattedValue =
- newDuplicationsMeasure && newDuplicationsValue ? (
- <div>
- <DrilldownLink
- branchLike={branchLike}
- component={component.key}
- metric={newDuplicationsMeasure.metric.key}>
- <span className="js-overview-main-new-duplications">
- {formatMeasure(newDuplicationsValue, 'PERCENT', {
- decimals: getMinDecimalsCountToBeDistinctFromThreshold(
- parseFloat(newDuplicationsValue),
- getThreshold(measures, 'new_duplicated_lines_density')
- )
- })}
- </span>
- </DrilldownLink>
- </div>
- ) : (
- <span className="big">—</span>
- );
-
- const newLinesMeasure = measures.find(measure => measure.metric.key === 'new_lines');
- const newLinesValue = newLinesMeasure && this.props.getValue(newLinesMeasure);
- const label =
- newLinesMeasure && newLinesValue !== undefined && Number(newLinesValue) > 0 ? (
- <div className="overview-domain-measure-label">
- {translate('overview.duplications_on')}
- <br />
- <DrilldownLink
- branchLike={branchLike}
- className="spacer-right overview-domain-secondary-measure-value"
- component={component.key}
- metric={newLinesMeasure.metric.key}>
- <span className="js-overview-main-new-lines">
- {formatMeasure(newLinesValue, 'SHORT_INT')}
- </span>
- </DrilldownLink>
- {getMetricName('new_lines')}
- </div>
- ) : (
- <div className="overview-domain-measure-label">{getMetricName('new_duplications')}</div>
- );
-
- return (
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">{formattedValue}</div>
- {label}
- </div>
- );
- }
-
- renderNutshell() {
- return (
- <div className="overview-domain-nutshell">
- <div className="overview-domain-measures overview-domain-measures-big">
- {this.renderDuplications()}
- {this.renderDuplicatedBlocks()}
- </div>
-
- {this.renderTimeline('before')}
- </div>
- );
- }
-
- renderLeak() {
- if (!this.props.hasDiffMetrics()) {
- return null;
- }
- return (
- <div className="overview-domain-leak">
- <div className="overview-domain-measures">{this.renderNewDuplications()}</div>
-
- {this.renderTimeline('after')}
- </div>
- );
- }
-
- render() {
- const { measures } = this.props;
- const duplications = measures.find(
- measure => measure.metric.key === 'duplicated_lines_density'
- );
- if (duplications == null) {
- return null;
- }
- return (
- <div className="overview-card">
- {this.renderHeader()}
-
- <div className="overview-domain-panel">
- {this.renderNutshell()}
- {this.renderLeak()}
- </div>
- </div>
- );
- }
-}
-
-export default enhance(Duplications);
diff --git a/server/sonar-web/src/main/js/apps/overview/main/VulnerabilitiesAndHotspots.tsx b/server/sonar-web/src/main/js/apps/overview/main/VulnerabilitiesAndHotspots.tsx
deleted file mode 100644
index 513879fed34..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/VulnerabilitiesAndHotspots.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 * as React from 'react';
-import SecurityHotspotIcon from 'sonar-ui-common/components/icons/SecurityHotspotIcon';
-import VulnerabilityIcon from 'sonar-ui-common/components/icons/VulnerabilityIcon';
-import DocTooltip from '../../../components/docs/DocTooltip';
-import { getMetricName } from '../utils';
-import enhance, { ComposedProps } from './enhance';
-
-export class VulnerabiltiesAndHotspots extends React.PureComponent<ComposedProps> {
- renderHeader() {
- return this.props.renderHeader('Security');
- }
-
- renderTimeline(range: string) {
- return this.props.renderTimeline('vulnerabilities', range);
- }
-
- renderLeak() {
- if (!this.props.hasDiffMetrics()) {
- return null;
- }
-
- return (
- <div className="overview-domain-leak">
- <div className="overview-domain-measures">
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- <span className="offset-left">
- {this.props.renderIssues('new_vulnerabilities', 'VULNERABILITY')}
- </span>
- {this.props.renderRating('new_security_rating')}
- </div>
- <div className="overview-domain-measure-label">
- <VulnerabilityIcon className="little-spacer-right" />
- {getMetricName('new_vulnerabilities')}
- </div>
- </div>
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- {this.props.renderIssues('new_security_hotspots', 'SECURITY_HOTSPOT')}
- </div>
- <div className="overview-domain-measure-label">
- <SecurityHotspotIcon className="little-spacer-right" />
- {getMetricName('new_security_hotspots')}
- </div>
- </div>
- </div>
- {this.renderTimeline('after')}
- </div>
- );
- }
-
- renderNutshell() {
- return (
- <div className="overview-domain-nutshell">
- <div className="overview-domain-measures">
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- <span className="offset-left">
- {this.props.renderIssues('vulnerabilities', 'VULNERABILITY')}
- </span>
- {this.props.renderRating('security_rating')}
- </div>
- <div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
- <VulnerabilityIcon className="little-spacer-right" />
- {getMetricName('vulnerabilities')}
- <DocTooltip
- className="little-spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/vulnerabilities.md')}
- />
- </div>
- {this.props.renderHistoryLink('vulnerabilities')}
- </div>
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- {this.props.renderIssues('security_hotspots', 'SECURITY_HOTSPOT')}
- </div>
- <div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
- <SecurityHotspotIcon className="little-spacer-right" />
- {getMetricName('security_hotspots')}
- <DocTooltip
- className="little-spacer-left"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/metrics/security-hotspots.md'
- )}
- />
- </div>
- {this.props.renderHistoryLink('security_hotspots')}
- </div>
- </div>
- {this.renderTimeline('before')}
- </div>
- );
- }
-
- render() {
- return (
- <div className="overview-card">
- {this.renderHeader()}
-
- <div className="overview-domain-panel">
- {this.renderNutshell()}
- {this.renderLeak()}
- </div>
- </div>
- );
- }
-}
-
-export default enhance(VulnerabiltiesAndHotspots);
diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/Bugs-test.tsx b/server/sonar-web/src/main/js/apps/overview/main/__tests__/Bugs-test.tsx
deleted file mode 100644
index ae0fdfcc297..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/__tests__/Bugs-test.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
-import { mockComponent, mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks';
-import Bugs from '../Bugs';
-import { ComposedProps } from '../enhance';
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<ComposedProps> = {}) {
- return shallow(
- <Bugs
- branchLike={mockMainBranch()}
- component={mockComponent()}
- history={{ bugs: [] }}
- historyStartDate={new Date('2019-01-14T15:44:51.000Z')}
- leakPeriod={{ index: 1, mode: 'days' } as T.Period}
- measures={[
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'bugs',
- key: 'bugs',
- name: 'Bugs',
- type: 'INT'
- }),
- value: '5'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_bugs',
- key: 'new_bugs',
- name: 'New Bugs',
- type: 'INT'
- }),
- value: '2'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'reliability_rating',
- key: 'reliability_rating',
- name: 'Reliability',
- type: 'RATING'
- }),
- value: '1.0'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_reliability_rating',
- key: 'new_reliability_rating',
- name: 'New Reliability',
- type: 'RATING'
- }),
- value: '2.0'
- })
- ]}
- {...props}
- />
- ).dive();
-}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/CodeSmells-test.tsx b/server/sonar-web/src/main/js/apps/overview/main/__tests__/CodeSmells-test.tsx
deleted file mode 100644
index d87e979a344..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/__tests__/CodeSmells-test.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
-import { mockComponent, mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks';
-import CodeSmells from '../CodeSmells';
-import { ComposedProps } from '../enhance';
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<ComposedProps> = {}) {
- return shallow(
- <CodeSmells
- branchLike={mockMainBranch()}
- component={mockComponent()}
- history={{ sqale_index: [] }}
- leakPeriod={{ index: 1 } as T.Period}
- measures={[
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'code_smells',
- key: 'code_smells',
- name: 'Code Smells',
- type: 'INT'
- }),
- value: '15'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'sqale_index',
- key: 'sqale_index',
- name: 'Debt',
- type: 'INT'
- }),
- value: '1052'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'sqale_rating',
- key: 'sqale_rating',
- name: 'Maintainability',
- type: 'RATING'
- }),
- value: '2.0'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_code_smells',
- key: 'new_code_smells',
- name: 'New Code Smells',
- type: 'INT'
- }),
- periods: [
- {
- bestValue: true,
- index: 1,
- value: '52'
- }
- ]
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_technical_debt',
- key: 'new_technical_debt',
- name: 'New Debt',
- type: 'INT'
- }),
- periods: [
- {
- bestValue: true,
- index: 1,
- value: '85'
- }
- ]
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_maintainability_rating',
- key: 'new_maintainability_rating',
- name: 'New Maintainability',
- type: 'RATING'
- }),
- value: '3.0'
- })
- ]}
- {...props}
- />
- ).dive();
-}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/Duplications-test.tsx b/server/sonar-web/src/main/js/apps/overview/main/__tests__/Duplications-test.tsx
deleted file mode 100644
index 63d915c677d..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/__tests__/Duplications-test.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
-import { mockComponent, mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks';
-import Duplications from '../Duplications';
-import { ComposedProps } from '../enhance';
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<ComposedProps> = {}) {
- return shallow(
- <Duplications
- branchLike={mockMainBranch()}
- component={mockComponent()}
- leakPeriod={{ index: 1 } as T.Period}
- measures={[
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'duplicated_lines_density',
- key: 'duplicated_lines_density',
- name: 'Duplicated Lines'
- }),
- value: '0.5'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_lines',
- key: 'new_lines',
- name: 'New Lines',
- type: 'INT'
- }),
- value: '52'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_duplicated_lines_density',
- key: 'new_duplicated_lines_density',
- name: 'New Duplicated Lines'
- }),
- periods: [
- {
- bestValue: true,
- index: 1,
- value: '1.5'
- }
- ]
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'duplicated_blocks',
- key: 'duplicated_blocks',
- name: 'Duplicated Blocks',
- type: 'INT'
- }),
- periods: [
- {
- bestValue: true,
- index: 1,
- value: '2'
- }
- ]
- })
- ]}
- {...props}
- />
- ).dive();
-}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/VulnerabilitiesAndHotspots-test.tsx b/server/sonar-web/src/main/js/apps/overview/main/__tests__/VulnerabilitiesAndHotspots-test.tsx
deleted file mode 100644
index d25f902c2cf..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/__tests__/VulnerabilitiesAndHotspots-test.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
-import { mockComponent, mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks';
-import { ComposedProps } from '../enhance';
-import VulnerabilitiesAndHotspots from '../VulnerabilitiesAndHotspots';
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<ComposedProps> = {}) {
- return shallow(
- <VulnerabilitiesAndHotspots
- branchLike={mockMainBranch()}
- component={mockComponent()}
- history={{ vulnerabilities: [] }}
- leakPeriod={{ index: 1 } as T.Period}
- measures={[
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'vulnerabilities',
- key: 'vulnerabilities',
- name: 'Vulnerabilities',
- type: 'INT'
- }),
- value: '0'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'security_hotspots',
- key: 'security_hotspots',
- name: 'Security Hotspots',
- type: 'INT'
- }),
- value: '0'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'security_rating',
- key: 'security_rating',
- name: 'Security',
- type: 'RATING'
- }),
- value: '1.0'
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_vulnerabilities',
- key: 'new_vulnerabilities',
- name: 'New Vulnerabilities',
- type: 'INT'
- }),
- periods: [
- {
- bestValue: true,
- index: 1,
- value: '1'
- }
- ]
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_security_hotspots',
- key: 'new_security_hotspots',
- name: 'New Security Hotspots',
- type: 'INT'
- }),
- periods: [
- {
- bestValue: true,
- index: 1,
- value: '10'
- }
- ]
- }),
- mockMeasureEnhanced({
- metric: mockMetric({
- id: 'new_security_rating',
- key: 'new_security_rating',
- name: 'New Security Rating',
- type: 'RATING'
- }),
- periods: [
- {
- bestValue: true,
- index: 1,
- value: '5.0'
- }
- ]
- })
- ]}
- {...props}
- />
- ).dive();
-}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Bugs-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Bugs-test.tsx.snap
deleted file mode 100644
index 83f8ef8442a..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Bugs-test.tsx.snap
+++ /dev/null
@@ -1,229 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
- className="overview-card"
->
- <div
- className="overview-card-header"
- >
- <div
- className="overview-title"
- >
- <span>
- metric_domain.Reliability
- </span>
- <Link
- className="spacer-left small"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/component_measures",
- "query": Object {
- "id": "my-project",
- "metric": "Reliability",
- },
- }
- }
- >
- layout.measures
- </Link>
- </div>
- </div>
- <div
- className="overview-domain-panel"
- >
- <div
- className="overview-domain-nutshell"
- >
- <div
- className="overview-domain-measures"
- >
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <span
- className="offset-left"
- >
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/issues",
- "query": Object {
- "id": "my-project",
- "resolved": "false",
- "types": "BUG",
- },
- }
- }
- >
- 5
- </Link>
- </span>
- <Tooltip
- overlay="metric.reliability_rating.tooltip.A"
- >
- <div
- className="overview-domain-measure-sup"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- className="link-no-underline"
- component="my-project"
- metric="reliability_rating"
- >
- <Rating
- value="1.0"
- />
- </DrilldownLink>
- </div>
- </Tooltip>
- </div>
- <div
- className="overview-domain-measure-label display-flex-center display-flex-justify-center"
- >
- <BugIcon
- className="little-spacer-right "
- />
- overview.metric.bugs
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- </div>
- <Link
- className="overview-domain-measure-history-link"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "custom_metrics": "bugs",
- "graph": "custom",
- "id": "my-project",
- },
- }
- }
- >
- <HistoryIcon />
- <span>
- project_activity.page
- </span>
- </Link>
- </div>
- </div>
- <div
- className="overview-domain-timeline"
- >
- <Timeline
- history={Array []}
- />
- <DateFromNow
- date={2019-01-14T15:44:51.000Z}
- >
- <Component />
- </DateFromNow>
- </div>
- </div>
- <div
- className="overview-domain-leak"
- >
- <InjectIntl(LeakPeriodLegend)
- period={
- Object {
- "index": 1,
- "mode": "days",
- }
- }
- />
- <div
- className="overview-domain-measures"
- >
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <span
- className="offset-left"
- >
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/issues",
- "query": Object {
- "id": "my-project",
- "resolved": "false",
- "sinceLeakPeriod": "true",
- "types": "BUG",
- },
- }
- }
- >
- 1
- </Link>
- </span>
- <Tooltip
- overlay="metric.reliability_rating.tooltip.A"
- >
- <div
- className="overview-domain-measure-sup"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- className="link-no-underline"
- component="my-project"
- metric="new_reliability_rating"
- >
- <Rating
- value="1.0"
- />
- </DrilldownLink>
- </div>
- </Tooltip>
- </div>
- <div
- className="overview-domain-measure-label"
- >
- <BugIcon
- className="little-spacer-right"
- />
- overview.metric.new_bugs
- </div>
- </div>
- </div>
- <div
- className="overview-domain-timeline"
- >
- <Timeline
- history={Array []}
- />
- </div>
- </div>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/CodeSmells-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/CodeSmells-test.tsx.snap
deleted file mode 100644
index 88d0a6bac8b..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/CodeSmells-test.tsx.snap
+++ /dev/null
@@ -1,295 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
- className="overview-card"
- id="overview-code-smells"
->
- <div
- className="overview-card-header"
- >
- <div
- className="overview-title"
- >
- <span>
- metric_domain.Maintainability
- </span>
- <Link
- className="spacer-left small"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/component_measures",
- "query": Object {
- "id": "my-project",
- "metric": "Maintainability",
- },
- }
- }
- >
- layout.measures
- </Link>
- </div>
- </div>
- <div
- className="overview-domain-panel"
- >
- <div
- className="overview-domain-nutshell"
- >
- <div
- className="overview-domain-measures"
- >
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <span
- className="offset-left"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component="my-project"
- metric="sqale_index"
- >
- work_duration.x_days.2
- </DrilldownLink>
- </span>
- <Tooltip
- overlay="metric.sqale_rating.tooltip.B.0.0%"
- >
- <div
- className="overview-domain-measure-sup"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- className="link-no-underline"
- component="my-project"
- metric="sqale_rating"
- >
- <Rating
- value="2.0"
- />
- </DrilldownLink>
- </div>
- </Tooltip>
- </div>
- <div
- className="overview-domain-measure-label display-flex-center display-flex-justify-center"
- >
- overview.metric.effort
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- </div>
- <Link
- className="overview-domain-measure-history-link"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "custom_metrics": "sqale_index",
- "graph": "custom",
- "id": "my-project",
- },
- }
- }
- >
- <HistoryIcon />
- <span>
- project_activity.page
- </span>
- </Link>
- </div>
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/issues",
- "query": Object {
- "id": "my-project",
- "resolved": "false",
- "types": "CODE_SMELL",
- },
- }
- }
- >
- 15
- </Link>
- </div>
- <div
- className="overview-domain-measure-label display-flex-center display-flex-justify-center"
- >
- <CodeSmellIcon
- className="little-spacer-right "
- />
- overview.metric.code_smells
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- </div>
- <Link
- className="overview-domain-measure-history-link"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "custom_metrics": "code_smells",
- "graph": "custom",
- "id": "my-project",
- },
- }
- }
- >
- <HistoryIcon />
- <span>
- project_activity.page
- </span>
- </Link>
- </div>
- </div>
- <div
- className="overview-domain-timeline"
- >
- <Timeline
- history={Array []}
- />
- </div>
- </div>
- <div
- className="overview-domain-leak"
- >
- <div
- className="overview-domain-measures"
- >
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <span
- className="offset-left"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component="my-project"
- metric="new_technical_debt"
- >
- work_duration.x_hours.1
- </DrilldownLink>
- </span>
- <Tooltip
- overlay="metric.sqale_rating.tooltip.A.0.0%"
- >
- <div
- className="overview-domain-measure-sup"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- className="link-no-underline"
- component="my-project"
- metric="new_maintainability_rating"
- >
- <Rating
- value="1.0"
- />
- </DrilldownLink>
- </div>
- </Tooltip>
- </div>
- <div
- className="overview-domain-measure-label"
- >
- overview.metric.new_effort
- </div>
- </div>
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/issues",
- "query": Object {
- "id": "my-project",
- "resolved": "false",
- "sinceLeakPeriod": "true",
- "types": "CODE_SMELL",
- },
- }
- }
- >
- 52
- </Link>
- </div>
- <div
- className="overview-domain-measure-label"
- >
- <CodeSmellIcon
- className="little-spacer-right"
- />
- overview.metric.new_code_smells
- </div>
- </div>
- </div>
- <div
- className="overview-domain-timeline"
- >
- <Timeline
- history={Array []}
- />
- </div>
- </div>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Coverage-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Coverage-test.tsx.snap
deleted file mode 100644
index 53140c34d90..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Coverage-test.tsx.snap
+++ /dev/null
@@ -1,251 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
- className="overview-card"
->
- <div
- className="overview-card-header"
- >
- <div
- className="overview-title"
- >
- <span>
- metric.coverage.name
- </span>
- <Link
- className="spacer-left small"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/component_measures",
- "query": Object {
- "id": "my-project",
- "metric": "Coverage",
- },
- }
- }
- >
- layout.measures
- </Link>
- </div>
- </div>
- <div
- className="overview-domain-panel"
- >
- <div
- className="overview-domain-nutshell"
- >
- <div
- className="overview-domain-measures overview-domain-measures-big"
- >
- <div
- className="overview-domain-measure"
- >
- <div
- className="display-inline-block text-middle big-spacer-right neg-offset-left"
- >
- <CoverageRating
- size="big"
- value={1}
- />
- </div>
- <div
- className="display-inline-block text-middle"
- >
- <div
- className="overview-domain-measure-value"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component="my-project"
- metric="coverage"
- >
- <span
- className="js-overview-main-coverage"
- >
- 1.0%
- </span>
- </DrilldownLink>
- </div>
- <div
- className="overview-domain-measure-label display-flex-center display-flex-justify-center"
- >
- overview.metric.coverage
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- </div>
- <Link
- className="overview-domain-measure-history-link"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "custom_metrics": "coverage",
- "graph": "custom",
- "id": "my-project",
- },
- }
- }
- >
- <HistoryIcon />
- <span>
- project_activity.page
- </span>
- </Link>
- </div>
- <Link
- className="overview-domain-measure-history-link"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "custom_metrics": "coverage",
- "graph": "custom",
- "id": "my-project",
- },
- }
- }
- >
- <HistoryIcon />
- <span>
- project_activity.page
- </span>
- </Link>
- </div>
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component="my-project"
- metric="tests"
- >
- <span
- className="js-overview-main-tests"
- >
- 15
- </span>
- </DrilldownLink>
- </div>
- <div
- className="overview-domain-measure-label display-flex-center display-flex-justify-center"
- >
- Unit Tests
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- <Link
- className="overview-domain-measure-history-link"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "custom_metrics": "tests",
- "graph": "custom",
- "id": "my-project",
- },
- }
- }
- >
- <HistoryIcon />
- <span>
- project_activity.page
- </span>
- </Link>
- </div>
- </div>
- </div>
- </div>
- <div
- className="overview-domain-leak"
- >
- <div
- className="overview-domain-measures"
- >
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <div>
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component="my-project"
- metric="new_coverage"
- >
- <span
- className="js-overview-main-new-coverage"
- >
- 1.0%
- </span>
- </DrilldownLink>
- </div>
- </div>
- <div
- className="overview-domain-measure-label"
- >
- overview.coverage_on
- <br />
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- className="spacer-right overview-domain-secondary-measure-value"
- component="my-project"
- metric="new_lines_to_cover"
- >
- <span
- className="js-overview-main-new-coverage"
- >
- 1
- </span>
- </DrilldownLink>
- overview.metric.new_lines_to_cover
- </div>
- </div>
- </div>
- </div>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Duplications-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Duplications-test.tsx.snap
deleted file mode 100644
index af8b3b669d3..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/Duplications-test.tsx.snap
+++ /dev/null
@@ -1,227 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
- className="overview-card"
->
- <div
- className="overview-card-header"
- >
- <div
- className="overview-title"
- >
- <span>
- overview.domain.duplications
- </span>
- <Link
- className="spacer-left small"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/component_measures",
- "query": Object {
- "id": "my-project",
- "metric": "Duplications",
- },
- }
- }
- >
- layout.measures
- </Link>
- </div>
- </div>
- <div
- className="overview-domain-panel"
- >
- <div
- className="overview-domain-nutshell"
- >
- <div
- className="overview-domain-measures overview-domain-measures-big"
- >
- <div
- className="overview-domain-measure"
- >
- <div
- className="display-inline-block text-middle big-spacer-right neg-offset-left"
- >
- <DuplicationsRating
- size="big"
- value={0.5}
- />
- </div>
- <div
- className="display-inline-block text-middle"
- >
- <div
- className="overview-domain-measure-value"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component="my-project"
- metric="duplicated_lines_density"
- >
- 0.5%
- </DrilldownLink>
- </div>
- <div
- className="overview-domain-measure-label display-flex-center display-flex-justify-center"
- >
- overview.metric.duplications
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- </div>
- <Link
- className="overview-domain-measure-history-link"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "custom_metrics": "duplicated_lines_density",
- "graph": "custom",
- "id": "my-project",
- },
- }
- }
- >
- <HistoryIcon />
- <span>
- project_activity.page
- </span>
- </Link>
- </div>
- </div>
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component="my-project"
- metric="duplicated_blocks"
- >
- <span
- className="js-overview-main-tests"
- >
- 1
- </span>
- </DrilldownLink>
- </div>
- <div
- className="overview-domain-measure-label display-flex-center display-flex-justify-center"
- >
- Duplicated Blocks
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- <Link
- className="overview-domain-measure-history-link"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "custom_metrics": "duplicated_blocks",
- "graph": "custom",
- "id": "my-project",
- },
- }
- }
- >
- <HistoryIcon />
- <span>
- project_activity.page
- </span>
- </Link>
- </div>
- </div>
- </div>
- </div>
- <div
- className="overview-domain-leak"
- >
- <div
- className="overview-domain-measures"
- >
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <div>
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- component="my-project"
- metric="new_duplicated_lines_density"
- >
- <span
- className="js-overview-main-new-duplications"
- >
- 1.5%
- </span>
- </DrilldownLink>
- </div>
- </div>
- <div
- className="overview-domain-measure-label"
- >
- overview.duplications_on
- <br />
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- className="spacer-right overview-domain-secondary-measure-value"
- component="my-project"
- metric="new_lines"
- >
- <span
- className="js-overview-main-new-lines"
- >
- 1
- </span>
- </DrilldownLink>
- overview.metric.new_lines
- </div>
- </div>
- </div>
- </div>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/VulnerabilitiesAndHotspots-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/VulnerabilitiesAndHotspots-test.tsx.snap
deleted file mode 100644
index 7aed1c83259..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/__tests__/__snapshots__/VulnerabilitiesAndHotspots-test.tsx.snap
+++ /dev/null
@@ -1,307 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
- className="overview-card"
->
- <div
- className="overview-card-header"
- >
- <div
- className="overview-title"
- >
- <span>
- metric_domain.Security
- </span>
- <Link
- className="spacer-left small"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/component_measures",
- "query": Object {
- "id": "my-project",
- "metric": "Security",
- },
- }
- }
- >
- layout.measures
- </Link>
- </div>
- </div>
- <div
- className="overview-domain-panel"
- >
- <div
- className="overview-domain-nutshell"
- >
- <div
- className="overview-domain-measures"
- >
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <span
- className="offset-left"
- >
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/issues",
- "query": Object {
- "id": "my-project",
- "resolved": "false",
- "types": "VULNERABILITY",
- },
- }
- }
- >
- 0
- </Link>
- </span>
- <Tooltip
- overlay="metric.security_rating.tooltip.A"
- >
- <div
- className="overview-domain-measure-sup"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- className="link-no-underline"
- component="my-project"
- metric="security_rating"
- >
- <Rating
- value="1.0"
- />
- </DrilldownLink>
- </div>
- </Tooltip>
- </div>
- <div
- className="overview-domain-measure-label display-flex-center display-flex-justify-center"
- >
- <VulnerabilityIcon
- className="little-spacer-right"
- />
- overview.metric.vulnerabilities
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- </div>
- <Link
- className="overview-domain-measure-history-link"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "custom_metrics": "vulnerabilities",
- "graph": "custom",
- "id": "my-project",
- },
- }
- }
- >
- <HistoryIcon />
- <span>
- project_activity.page
- </span>
- </Link>
- </div>
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/security_hotspots",
- "query": Object {
- "assignedToMe": "false",
- "id": "my-project",
- "resolved": "false",
- "types": "SECURITY_HOTSPOT",
- },
- }
- }
- >
- 0
- </Link>
- </div>
- <div
- className="overview-domain-measure-label display-flex-center display-flex-justify-center"
- >
- <SecurityHotspotIcon
- className="little-spacer-right"
- />
- overview.metric.security_hotspots
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- </div>
- <Link
- className="overview-domain-measure-history-link"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/activity",
- "query": Object {
- "custom_metrics": "security_hotspots",
- "graph": "custom",
- "id": "my-project",
- },
- }
- }
- >
- <HistoryIcon />
- <span>
- project_activity.page
- </span>
- </Link>
- </div>
- </div>
- <div
- className="overview-domain-timeline"
- >
- <Timeline
- history={Array []}
- />
- </div>
- </div>
- <div
- className="overview-domain-leak"
- >
- <div
- className="overview-domain-measures"
- >
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <span
- className="offset-left"
- >
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project/issues",
- "query": Object {
- "id": "my-project",
- "resolved": "false",
- "sinceLeakPeriod": "true",
- "types": "VULNERABILITY",
- },
- }
- }
- >
- 1
- </Link>
- </span>
- <Tooltip
- overlay="metric.security_rating.tooltip.E"
- >
- <div
- className="overview-domain-measure-sup"
- >
- <DrilldownLink
- branchLike={
- Object {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": true,
- "name": "master",
- }
- }
- className="link-no-underline"
- component="my-project"
- metric="new_security_rating"
- >
- <Rating
- value="5.0"
- />
- </DrilldownLink>
- </div>
- </Tooltip>
- </div>
- <div
- className="overview-domain-measure-label"
- >
- <VulnerabilityIcon
- className="little-spacer-right"
- />
- overview.metric.new_vulnerabilities
- </div>
- </div>
- <div
- className="overview-domain-measure"
- >
- <div
- className="overview-domain-measure-value"
- >
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/security_hotspots",
- "query": Object {
- "assignedToMe": "false",
- "id": "my-project",
- "resolved": "false",
- "sinceLeakPeriod": "true",
- "types": "SECURITY_HOTSPOT",
- },
- }
- }
- >
- 10
- </Link>
- </div>
- <div
- className="overview-domain-measure-label"
- >
- <SecurityHotspotIcon
- className="little-spacer-right"
- />
- overview.metric.new_security_hotspots
- </div>
- </div>
- </div>
- <div
- className="overview-domain-timeline"
- >
- <Timeline
- history={Array []}
- />
- </div>
- </div>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/overview/main/enhance.tsx b/server/sonar-web/src/main/js/apps/overview/main/enhance.tsx
deleted file mode 100644
index 4caf589f566..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/main/enhance.tsx
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 * as React from 'react';
-import { Link } from 'react-router';
-import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
-import HistoryIcon from 'sonar-ui-common/components/icons/HistoryIcon';
-import Rating from 'sonar-ui-common/components/ui/Rating';
-import { getLocalizedMetricName, translate } from 'sonar-ui-common/helpers/l10n';
-import { formatMeasure } from 'sonar-ui-common/helpers/measures';
-import { getWrappedDisplayName } from '../../../components/hoc/utils';
-import { getLeakValue } from '../../../components/measure/utils';
-import DrilldownLink from '../../../components/shared/DrilldownLink';
-import { getBranchLikeQuery } from '../../../helpers/branch-like';
-import { getRatingTooltip, getShortType, isDiffMetric } from '../../../helpers/measures';
-import { getPeriodDate } from '../../../helpers/periods';
-import {
- getComponentDrilldownUrl,
- getComponentIssuesUrl,
- getMeasureHistoryUrl
-} from '../../../helpers/urls';
-import { BranchLike } from '../../../types/branch-like';
-import Timeline from '../components/Timeline';
-
-export interface EnhanceProps {
- branchLike?: BranchLike;
- component: T.Component;
- measures: T.MeasureEnhanced[];
- leakPeriod?: T.Period;
- history?: {
- [metric: string]: Array<{ date: Date; value?: string }>;
- };
- historyStartDate?: Date;
-}
-
-export interface ComposedProps extends EnhanceProps {
- getValue: (measure: T.MeasureEnhanced) => string | undefined;
- hasDiffMetrics: () => boolean;
- renderHeader: (domain: string, label?: string) => React.ReactNode;
- renderMeasure: (metricKey: string, tooltip?: React.ReactNode) => React.ReactNode;
- renderRating: (metricKey: string) => React.ReactNode;
- renderIssues: (metric: string, type: T.IssueType) => React.ReactNode;
- renderHistoryLink: (metricKey: string) => React.ReactNode;
- renderTimeline: (metricKey: string, range: string, children?: React.ReactNode) => React.ReactNode;
-}
-
-export default function enhance(ComposedComponent: React.ComponentType<ComposedProps>) {
- return class extends React.PureComponent<EnhanceProps> {
- static displayName = getWrappedDisplayName(ComposedComponent, 'enhance');
-
- getValue = (measure: T.MeasureEnhanced) => {
- if (!measure) {
- return '0';
- }
- return isDiffMetric(measure.metric.key) ? getLeakValue(measure) : measure.value;
- };
-
- hasDiffMetrics = () => {
- const { measures } = this.props;
- return measures.some(m => isDiffMetric(m.metric.key));
- };
-
- renderHeader = (domain: string, label?: string) => {
- const { branchLike, component } = this.props;
- label = label !== undefined ? label : translate('metric_domain', domain);
- return (
- <div className="overview-card-header">
- <div className="overview-title">
- <span>{label}</span>
- <Link
- className="spacer-left small"
- to={getComponentDrilldownUrl({
- componentKey: component.key,
- metric: domain,
- branchLike
- })}>
- {translate('layout.measures')}
- </Link>
- </div>
- </div>
- );
- };
-
- renderMeasure = (metricKey: string, tooltip?: React.ReactNode) => {
- const { branchLike, measures, component } = this.props;
- const measure = measures.find(measure => measure.metric.key === metricKey);
- if (!measure) {
- return null;
- }
-
- return (
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">
- <DrilldownLink branchLike={branchLike} component={component.key} metric={metricKey}>
- <span className="js-overview-main-tests">
- {formatMeasure(measure.value, getShortType(measure.metric.type))}
- </span>
- </DrilldownLink>
- </div>
-
- <div className="overview-domain-measure-label display-flex-center display-flex-justify-center">
- {getLocalizedMetricName(measure.metric)}
- {tooltip}
- {this.renderHistoryLink(measure.metric.key)}
- </div>
- </div>
- );
- };
-
- renderRating = (metricKey: string) => {
- const { branchLike, component, measures } = this.props;
- const measure = measures.find(measure => measure.metric.key === metricKey);
- if (!measure) {
- return null;
- }
-
- const value = this.getValue(measure);
- const title = value && getRatingTooltip(metricKey, value);
- return (
- <Tooltip overlay={title}>
- <div className="overview-domain-measure-sup">
- <DrilldownLink
- branchLike={branchLike}
- className="link-no-underline"
- component={component.key}
- metric={metricKey}>
- <Rating value={value} />
- </DrilldownLink>
- </div>
- </Tooltip>
- );
- };
-
- renderIssues = (metric: string, type: string) => {
- const { branchLike, measures, component } = this.props;
- const measure = measures.find(measure => measure.metric.key === metric);
- if (!measure) {
- return <span className="big">—</span>;
- }
-
- const value = this.getValue(measure);
- const params = { ...getBranchLikeQuery(branchLike), resolved: 'false', types: type };
- if (isDiffMetric(metric)) {
- Object.assign(params, { sinceLeakPeriod: 'true' });
- }
-
- if (metric.endsWith('security_hotspots')) {
- return (
- <Link
- to={{
- pathname: '/security_hotspots',
- query: { ...params, id: component.key, assignedToMe: 'false' }
- }}>
- {formatMeasure(value, 'SHORT_INT')}
- </Link>
- );
- }
-
- return (
- <Link to={getComponentIssuesUrl(component.key, params)}>
- {formatMeasure(value, 'SHORT_INT')}
- </Link>
- );
- };
-
- renderHistoryLink = (metricKey: string) => {
- const linkClass = 'overview-domain-measure-history-link';
- return (
- <Link
- className={linkClass}
- to={getMeasureHistoryUrl(this.props.component.key, metricKey, this.props.branchLike)}>
- <HistoryIcon />
- <span>{translate('project_activity.page')}</span>
- </Link>
- );
- };
-
- renderTimeline = (metricKey: string, range: 'before' | 'after', children?: React.ReactNode) => {
- if (!this.props.history) {
- return null;
- }
- const history = this.props.history[metricKey];
- if (!history) {
- return null;
- }
- const props = { history, [range]: getPeriodDate(this.props.leakPeriod) };
- return (
- <div className="overview-domain-timeline">
- <Timeline {...props} />
- {children}
- </div>
- );
- };
-
- render() {
- return (
- <ComposedComponent
- {...this.props}
- getValue={this.getValue}
- hasDiffMetrics={this.hasDiffMetrics}
- renderHeader={this.renderHeader}
- renderHistoryLink={this.renderHistoryLink}
- renderIssues={this.renderIssues}
- renderMeasure={this.renderMeasure}
- renderRating={this.renderRating}
- renderTimeline={this.renderTimeline}
- />
- );
- }
- };
-}
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx
index 2161ceba139..bd9fbfaca1a 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx
@@ -32,13 +32,11 @@ import {
Store
} from '../../../store/rootReducer';
import { BranchLike } from '../../../types/branch-like';
-import AnalysesList from '../events/AnalysesList';
import MetaKey from './MetaKey';
import MetaLinks from './MetaLinks';
import MetaOrganizationKey from './MetaOrganizationKey';
import MetaQualityGate from './MetaQualityGate';
import MetaQualityProfiles from './MetaQualityProfiles';
-import MetaSize from './MetaSize';
import MetaTags from './MetaTags';
const ProjectBadges = lazyLoadComponent(() => import('../badges/ProjectBadges'), 'ProjectBadges');
@@ -103,7 +101,7 @@ export class Meta extends React.PureComponent<Props> {
render() {
const { organizationsEnabled } = this.props.appState;
- const { branchLike, component, currentUser, measures, metrics, organization } = this.props;
+ const { branchLike, component, currentUser, metrics, organization } = this.props;
const { qualifier, description, visibility } = component;
const isProject = qualifier === 'TRK';
@@ -131,21 +129,8 @@ export class Meta extends React.PureComponent<Props> {
{isProject && (
<MetaTags component={component} onComponentChange={this.props.onComponentChange} />
)}
- {measures && (
- <MetaSize branchLike={branchLike} component={component} measures={measures} />
- )}
</div>
- {metrics && (
- <AnalysesList
- branchLike={branchLike}
- component={component}
- history={this.props.history}
- metrics={metrics}
- qualifier={component.qualifier}
- />
- )}
-
{this.renderQualityInfos()}
{isProject && <MetaLinks component={component} />}
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx
index 3a8b2281593..353ccfed13b 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx
@@ -25,7 +25,6 @@ import { formatMeasure } from 'sonar-ui-common/helpers/measures';
import LanguageDistributionContainer from '../../../components/charts/LanguageDistributionContainer';
import DrilldownLink from '../../../components/shared/DrilldownLink';
import { BranchLike } from '../../../types/branch-like';
-import { getMetricName } from '../utils';
interface Props {
branchLike?: BranchLike;
@@ -55,7 +54,6 @@ export default class MetaSize extends React.PureComponent<Props> {
) : (
<span>0</span>
)}
- <div className="spacer-top text-muted">{getMetricName('ncloc')}</div>
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaContainer-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaContainer-test.tsx.snap
index e7b7c3c489a..0ca8d471138 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaContainer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaContainer-test.tsx.snap
@@ -39,33 +39,6 @@ exports[`should hide QG and QP links if the organization has a paid plan, and th
onComponentChange={[MockFunction]}
/>
</div>
- <AnalysesList
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- metrics={Object {}}
- qualifier="TRK"
- />
<MetaLinks
component={
Object {
@@ -179,33 +152,6 @@ exports[`should render correctly 1`] = `
onComponentChange={[MockFunction]}
/>
</div>
- <AnalysesList
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- metrics={Object {}}
- qualifier="TRK"
- />
<div
className="overview-meta-card"
id="overview-meta-quality-gate"
@@ -348,33 +294,6 @@ exports[`should show QG and QP links if the organization has a paid plan, and th
onComponentChange={[MockFunction]}
/>
</div>
- <AnalysesList
- component={
- Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- }
- }
- metrics={Object {}}
- qualifier="TRK"
- />
<div
className="overview-meta-card"
id="overview-meta-quality-gate"
diff --git a/server/sonar-web/src/main/js/apps/overview/styles.css b/server/sonar-web/src/main/js/apps/overview/styles.css
index 10deade8fd1..6074716b4b5 100644
--- a/server/sonar-web/src/main/js/apps/overview/styles.css
+++ b/server/sonar-web/src/main/js/apps/overview/styles.css
@@ -21,286 +21,156 @@
animation: fadeIn 0.5s forwards;
}
-.overview-main {
- background-color: var(--barBackgroundColor);
- transition: transform 0.5s ease, opacity 0.5s ease;
- width: calc(100% - 300px);
-}
-
-.overview-sidebar {
- margin-top: calc(-1 * var(--pagePadding));
- margin-bottom: calc(-1 * var(--pagePadding));
- margin-left: var(--pagePadding);
- padding-left: calc(var(--pagePadding) - 1px);
- padding-top: var(--pagePadding);
- padding-bottom: var(--pagePadding);
- border-left: 1px solid var(--barBorderColor);
-}
-
-/*
- * Title
- */
-
-.overview-title {
- font-size: var(--bigFontSize);
- font-weight: 400;
- line-height: 1.3;
-}
-
-/*
- * Quality Gate
- */
-
-.overview-quality-gate {
- padding-bottom: 15px;
- border-bottom: 1px solid var(--barBorderColor);
- background-color: var(--barBackgroundColor);
+.overview-panel {
+ min-height: 100%;
}
-.overview-quality-gate-conditions-list {
- display: flex;
- flex-wrap: wrap;
- align-items: flex-start;
-}
-
-.overview-quality-gate-conditions-list-collapse {
- margin: calc(2 * var(--gridSize)) 0;
+.overview-panel-content {
+ background: white;
+ border: 1px solid var(--barBorderColor);
}
-.overview-quality-gate-condition {
- display: block;
- margin-top: 15px;
- margin-right: 30px;
- border: none;
- border-left: 5px solid;
- border-top-right-radius: 2px;
- border-bottom-right-radius: 2px;
- background-color: #fff;
- color: var(--baseFontColor);
- transition: none;
+.overview-panel-title {
+ text-transform: uppercase;
+ font-weight: 600;
+ font-size: var(--smallFontSize);
+ margin-bottom: var(--gridSize);
}
-.overview-quality-gate-condition:hover,
-.overview-quality-gate-condition:focus {
- color: var(--baseFontColor);
+.overview-panel-padded {
+ padding: calc(2 * var(--gridSize));
}
-.overview-quality-gate-condition:hover .overview-quality-gate-condition-container,
-.overview-quality-gate-condition:focus .overview-quality-gate-condition-container {
- border-color: inherit;
+.overview-panel-big-padded {
+ padding: calc(3 * var(--gridSize));
}
-.overview-quality-gate-condition-leak {
- background-color: var(--leakPrimaryColor);
+.overview-panel-huge-padded {
+ padding: calc(5 * var(--gridSize));
}
-.overview-quality-gate-condition-metric,
-.overview-quality-gate-condition-period {
- max-width: 125px;
- line-height: 16px;
- font-size: var(--smallFontSize);
-}
+/*
+ * Measures
+ */
-.overview-quality-gate-condition-period {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
+.overview-measures-row {
+ min-height: 105px;
+ box-sizing: border-box;
}
-.overview-quality-gate-condition-container {
- display: flex;
- align-items: center;
- min-width: 150px;
- /* three lines by 16px and 4px margin */
- min-height: 52px;
- padding: 10px;
+.overview-measures-row + .overview-measures-row {
border-top: 1px solid var(--barBorderColor);
- border-bottom: 1px solid var(--barBorderColor);
- border-right: 1px solid var(--barBorderColor);
- transition: border-color 0.3s ease;
}
-.overview-quality-gate-condition-value {
+.overview-measures-value {
line-height: 1;
- margin-right: 10px;
- font-size: 24px;
- font-weight: normal;
-
- /* for consistency with ratings */
- min-width: 24px;
- text-align: center;
+ font-size: var(--giganticFontSize);
+ white-space: nowrap;
}
-.overview-quality-gate-condition-value span {
- display: inline-block;
- vertical-align: top;
+.overview-measures-empty-value {
+ height: 1px;
+ width: var(--bigFontSize);
+ background: var(--baseFontColor);
}
-.overview-quality-gate-threshold {
- margin-top: 4px;
- font-size: var(--smallFontSize);
- color: var(--secondFontColor);
-}
-
-.overview-quality-gate-warning {
- margin: 15px 0 0;
+.overview-measures-aside {
+ flex-basis: 180px;
+ box-sizing: border-box;
}
-.overview-quality-gate-condition-error {
- border-color: var(--red);
+.overview-measures-tab {
+ width: calc(160px - calc(4 * var(--gridSize)));
}
-.overview-quality-gate-condition-warn {
- border-color: var(--orange);
+.overview-measures-emphasis {
+ background: var(--veryLightGreen);
}
/*
- * Domain
+ * Quality Gate
*/
-.overview-domains-list {
- animation: fadeIn 0.5s forwards;
-}
-
-.overview-card {
- margin: calc(2 * var(--gridSize)) 0;
- padding-top: 3px;
-}
-
-.overview-card .offset-left {
- margin-left: 30px;
-}
-
-.overview-card .neg-offset-left {
- margin-left: -30px;
-}
-
-.overview-card-header {
- display: flex;
- align-items: baseline;
- justify-content: space-between;
- margin-bottom: 10px;
- line-height: var(--controlHeight);
+.overview-quality-gate-badge-large {
+ padding: calc(2 * var(--gridSize));
+ color: white;
+ box-sizing: border-box;
}
-.overview-domain-panel {
- display: flex;
- margin-top: 10px;
- border: 1px solid var(--barBorderColor);
- background-color: #fff;
+.overview-quality-gate-badge-large.failed {
+ background: var(--red);
}
-.overview-domain-nutshell,
-.overview-domain-leak {
- position: relative;
- display: flex;
+.overview-quality-gate-badge-large.success {
+ background: var(--green);
+ height: 160px;
}
-.overview-domain-nutshell {
- flex: 3;
+.overview-quality-gate-badge-large h3 {
+ color: white;
}
-.overview-domain-nutshell .line-chart-backdrop {
- fill: #e5f1f9;
+.overview-quality-gate-conditions {
+ padding-bottom: calc(2 * var(--gridSize));
}
-.overview-domain-leak {
- flex: 2;
- background-color: var(--leakPrimaryColor);
+.overview-quality-gate-conditions-project-name {
+ padding: var(--gridSize) 0 var(--gridSize) calc(2 * var(--gridSize));
+ font-size: var(--bigFontSize);
+ background: var(--barBorderColor);
}
-.overview-domain-leak .overview-domain-measures {
- padding: 0;
+.overview-quality-gate-conditions-section-title {
+ padding: calc(2 * var(--gridSize)) calc(2 * var(--gridSize)) var(--gridSize)
+ calc(2 * var(--gridSize));
+ border-bottom: 1px solid var(--barBorderColor);
+ margin: 0;
+ font-size: var(--baseFontSize);
}
-.overview-domain-leak .line-chart-backdrop {
- fill: var(--leakSecondaryColor);
+.overview-quality-gate-conditions-list {
+ margin-bottom: calc(2 * var(--gridSize));
}
-.overview-domain-measures {
- position: relative;
- z-index: var(--normalZIndex);
- display: flex;
- flex: 1;
- padding: 0;
+.overview-quality-gate-conditions-list-collapse {
+ margin: calc(2 * var(--gridSize)) 0;
}
-.overview-domain-measure {
- flex: 1;
- text-align: center;
- padding: 15px 10px;
- position: relative;
+.overview-quality-gate-condition,
+.overview-quality-gate-condition:hover {
+ display: block;
+ color: var(--baseFontColor);
+ border: none;
+ transition: background-color 0.3s ease;
}
-.overview-domain-measures-big .overview-domain-measure {
- padding-top: 24px;
+.overview-quality-gate-condition:hover {
+ background-color: var(--rowHoverHighlight);
}
-.overview-domain-measure-value {
- line-height: 1;
- font-size: 36px;
- font-weight: 300;
- white-space: nowrap;
+.overview-quality-gate-condition-container {
+ padding: calc(1.5 * var(--gridSize)) var(--gridSize) calc(1.5 * var(--gridSize))
+ calc(4 * var(--gridSize));
+ border-bottom: 1px solid var(--barBorderColor);
}
-.overview-domain-secondary-measure-value {
+.overview-quality-gate-condition-value {
line-height: 1;
- font-size: 20px;
- font-weight: 300;
-}
-
-.overview-domain-measure-label {
- margin-top: 10px;
-}
-
-.overview-domain-measure-history-link {
- position: absolute;
- top: var(--gridSize);
- right: var(--gridSize);
- border-bottom: 0;
- visibility: hidden;
-}
-
-.overview-domain-measure-history-link span {
- border-bottom: 1px solid var(--lightBlue);
-}
+ margin-right: 10px;
+ font-size: var(--bigFontSize);
-.overview-domain-measure:hover .overview-domain-measure-history-link {
- visibility: visible;
+ /* for consistency with ratings */
+ min-width: 24px;
}
-.overview-domain-measure-sup {
+.overview-quality-gate-condition-value span {
display: inline-block;
vertical-align: top;
- margin-top: -4px;
- margin-left: 6px;
- font-size: var(--bigFontSize);
-}
-
-.overview-domain-timeline {
- position: absolute;
- z-index: var(--belowNormalZIndex);
- bottom: 0;
- left: 0;
- right: 0;
- animation: fadeIn 0.5s forwards;
-}
-
-.overview-domain-timeline .line-chart-path {
- fill: none;
- stroke: none;
-}
-
-.overview-domain-timeline-date {
- position: absolute;
- bottom: 2px;
- left: 5px;
- color: rgba(119, 119, 119, 0.6);
- font-size: 11px;
}
/*
* Meta
+ TODO REMOVE ME!!
*/
.overview-meta {
@@ -342,25 +212,6 @@
position: relative;
}
-.overview-meta-size-ncloc {
- display: inline-block;
- vertical-align: middle;
- width: 100px;
- text-align: center;
-}
-
-.overview-meta-size-ncloc.is-half-width {
- width: 50%;
- box-sizing: border-box;
-}
-
-.overview-meta-size-ncloc a,
-.overview-meta-size-ncloc span {
- line-height: var(--controlHeight);
- font-size: 18px;
- font-weight: 300;
-}
-
.overview-meta-size-lang-dist {
display: inline-block;
vertical-align: middle;
@@ -370,96 +221,6 @@
box-sizing: border-box;
}
-.overview-analysis {
- color: var(--secondFontColor);
-}
-
-.overview-analysis + .overview-analysis {
- margin-top: calc(2 * var(--gridSize));
-}
-
-.overview-analysis-graph {
- display: block;
- cursor: pointer;
- outline: none;
- border: none;
-}
-
-.overview-analysis-graph-popup {
- opacity: 0.8;
- padding: 0;
-}
-
-.overview-analysis-graph-tooltip {
- padding: 4px;
- pointer-events: none;
- font-size: var(--smallFontSize);
- overflow: hidden;
-}
-
-.overview-analysis-graph-tooltip-line {
- padding-bottom: 2px;
-}
-
-.overview-analysis-graph-tooltip-title {
- font-weight: bold;
- margin-bottom: 4px;
-}
-
-.overview-analysis-graph-tooltip-value {
- font-weight: bold;
-}
-
-.overview-analysis-graph-tooltip-description {
- max-width: 80px;
-}
-
-.overview-activity-events {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
-}
-
-.overview-analysis-event {
- display: inline-block;
-}
-
-.overview-analysis-event.badge {
- /* 260px to match the sidebar width on project dashboard */
- max-width: 260px;
- border-radius: 2px;
- font-weight: bold;
- font-size: var(--smallFontSize);
- letter-spacing: 0;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.overview-analysis-event + .overview-analysis-event {
- margin-top: 4px;
-}
-
-/*
- * Other
- */
-
-.overview-legend {
- position: absolute;
- bottom: 100%;
- left: 0;
- right: -1px;
- padding: 5px 0 2px;
- border: 1px solid var(--barBorderColor);
- background-color: var(--leakPrimaryColor);
- font-size: var(--mediumFontSize);
- text-align: center;
- transform: translateY(-4px);
-}
-
-.overview-legend-spaced-line {
- padding: 14px 0 10px;
-}
-
.overview-key {
width: 100%;
background-color: transparent !important;
@@ -491,6 +252,7 @@
/*
* PRs and SLBs
*/
+
.pr-overview {
max-width: 1020px;
margin: 0 auto;
@@ -500,10 +262,6 @@
max-width: 1260px;
}
-.pr-overview h3 {
- text-transform: uppercase;
-}
-
.pr-overview-failed-conditions {
flex: 0 0 240px;
}
@@ -513,78 +271,109 @@
}
.pr-overview .overview-quality-gate-condition {
- margin-right: 0;
margin-top: 12px;
- box-sizing: border-box;
- width: 100%;
+ background-color: #fff;
+ border-left: 5px solid;
+ border-top-right-radius: 2px;
+ border-bottom-right-radius: 2px;
}
-.pr-overview-measurements-row {
- min-height: 85px;
- box-sizing: border-box;
- background: white;
- border: 1px solid var(--barBorderColor);
+.pr-overview .overview-quality-gate-condition-error {
+ border-color: var(--red);
}
-.pr-overview-measurements-row + .pr-overview-measurements-row {
- border-top: 0;
+.pr-overview .overview-quality-gate-condition-warn {
+ border-color: var(--orange);
}
-.pr-overview-measurements-value,
-.pr-overview-measurements-rating,
-.pr-overview-measurements-estimate {
- padding: calc(3 * var(--gridSize));
+.pr-overview .overview-quality-gate-condition:hover .overview-quality-gate-condition-container,
+.pr-overview .overview-quality-gate-condition:focus .overview-quality-gate-condition-container {
+ border-color: inherit;
}
-.pr-overview-measurements-value + .pr-overview-measurements-value {
- padding-right: 0;
- padding-left: 0;
+.pr-overview .overview-quality-gate-condition-metric,
+.pr-overview .overview-quality-gate-condition-period {
+ display: block;
+ max-width: 125px;
+ line-height: 16px;
+ font-size: var(--smallFontSize);
}
-.pr-overview-measurements-value .measure-empty {
- margin-top: -4px;
- font-size: var(--bigFontSize);
+.pr-overview .overview-quality-gate-condition-container {
+ min-width: 150px;
+ /* three lines by 16px and 4px margin */
+ min-height: 52px;
+ padding: var(--gridSize);
+ border-top: 1px solid var(--barBorderColor);
+ border-right: 1px solid var(--barBorderColor);
+ transition: border-color 0.3s ease;
+}
+
+.pr-overview .overview-quality-gate-condition-value {
+ font-size: var(--hugeFontSize);
}
-.pr-overview-measurements-rating,
-.pr-overview-measurements-estimate {
+.pr-overview .overview-quality-gate-badge-large {
+ width: 240px;
+ min-height: 160px;
+ color: var(--transparentWhite);
+}
+
+.pr-pverview .overview-measures-row {
+ min-height: 85px;
+}
+
+.pr-overview .overview-measures-aside {
flex-basis: 270px;
- text-align: right;
- box-sizing: border-box;
}
@media (max-width: 1200px) {
- .pr-overview-measurements-rating,
- .pr-overview-measurements-estimate {
+ .pr-overview .overview-measures-aside {
flex-basis: 220px;
}
}
-.pr-overview-measurements-estimate {
- background: var(--veryLightGreen);
-}
+/*
+ * ACTIVITY
+ */
-.pr-overview-measurements-estimate .label {
- margin-left: var(--gridSize);
+.overview-panel .activity-graph-legends {
text-align: right;
+ margin-top: -30px;
}
-.quality-gate-badge-large {
- width: 240px;
- min-height: 160px;
- padding: calc(2 * var(--gridSize));
- color: var(--transparentWhite);
- box-sizing: border-box;
+.overview-analysis {
+ color: var(--secondFontColor);
}
-.quality-gate-badge-large.failed {
- background: var(--red);
+.overview-analysis + .overview-analysis {
+ margin-top: calc(2 * var(--gridSize));
}
-.quality-gate-badge-large.success {
- background: var(--green);
+.overview-activity-events {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
}
-.quality-gate-badge-large h4 {
- color: white;
+.overview-analysis-event {
+ display: inline-block;
+}
+
+.overview-analysis-event.badge {
+ border-radius: 2px;
+ font-weight: bold;
+ font-size: var(--smallFontSize);
+ letter-spacing: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.overview-analysis-event + .overview-analysis-event {
+ margin-top: 4px;
+}
+
+.overview-panel .activity-graph-container {
+ min-height: 200px;
+ padding-bottom: 0;
}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/Analysis-test.tsx b/server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx
index cfeae8a7a8c..762fcb26a48 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/Analysis-test.tsx
+++ b/server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx
@@ -17,19 +17,14 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { shallow } from 'enzyme';
import * as React from 'react';
-import Analysis from '../Analysis';
+import { DateSource } from 'react-intl';
-const ANALYSIS = {
- key: '1',
- date: '2017-06-10T16:10:59+0200',
- events: [
- { key: '1', category: 'OTHER', name: 'test' },
- { key: '2', category: 'VERSION', name: '6.5-SNAPSHOT' }
- ]
-};
+interface Props {
+ children?: (formattedDate: string) => React.ReactNode;
+ date: DateSource;
+}
-it('should sort the events with version first', () => {
- expect(shallow(<Analysis analysis={ANALYSIS} qualifier="TRK" />)).toMatchSnapshot();
-});
+export default function DateFromNow({ children, date }: Props) {
+ return children && children(date.toString());
+}