diff options
author | Wouter Admiraal <wouter.admiraal@sonarsource.com> | 2019-12-19 10:58:37 +0100 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2020-02-10 20:46:15 +0100 |
commit | 822405efd0ddde6b1e123c40cc1255e9b57c05f8 (patch) | |
tree | 5896c4f40e0240c563f48370b90b2450a0a061a8 /server/sonar-web/src | |
parent | 914f3a4e69b2d5896bf71e71ee63f45d45303efe (diff) | |
download | sonarqube-822405efd0ddde6b1e123c40cc1255e9b57c05f8.tar.gz sonarqube-822405efd0ddde6b1e123c40cc1255e9b57c05f8.zip |
SONAR-12632 SONAR-12678 Implement new Overview layout
Diffstat (limited to 'server/sonar-web/src')
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()); +} |