From 0ba8c56c9a7cddf225720f224e66b267f9bbf528 Mon Sep 17 00:00:00 2001 From: Grégoire Aubert Date: Mon, 20 Aug 2018 17:28:52 +0200 Subject: SONAR-11165 Migrate rest of component measures page to TS --- .../js/apps/component-measures/components/App.js | 235 ----------- .../js/apps/component-measures/components/App.tsx | 233 +++++++++++ .../component-measures/components/AppContainer.js | 80 ---- .../component-measures/components/AppContainer.tsx | 108 +++++ .../component-measures/components/FilesCounter.js | 46 --- .../component-measures/components/FilesCounter.tsx | 45 +++ .../components/LeakPeriodLegend.tsx | 4 +- .../components/MeasureContent.tsx | 8 +- .../components/MeasureContentContainer.tsx | 4 +- .../component-measures/components/MeasureHeader.js | 103 ----- .../components/MeasureHeader.tsx | 100 +++++ .../components/MeasureOverview.js | 184 --------- .../components/MeasureOverview.tsx | 188 +++++++++ .../components/MeasureOverviewContainer.js | 140 ------- .../components/MeasureOverviewContainer.tsx | 134 +++++++ .../components/MetricNotFound.js | 30 -- .../components/MetricNotFound.tsx | 29 ++ .../component-measures/components/PageActions.js | 82 ---- .../component-measures/components/PageActions.tsx | 81 ++++ .../components/__tests__/App-test.js | 69 ---- .../components/__tests__/App-test.tsx | 75 ++++ .../components/__tests__/FilesCounter-test.js | 30 -- .../components/__tests__/FilesCounter-test.tsx | 30 ++ .../components/__tests__/LeakPeriodLegend-test.tsx | 3 +- .../components/__tests__/MeasureHeader-test.js | 128 ------ .../components/__tests__/MeasureHeader-test.tsx | 112 ++++++ .../components/__tests__/PageActions-test.js | 66 --- .../components/__tests__/PageActions-test.tsx | 72 ++++ .../__tests__/__snapshots__/App-test.js.snap | 74 ---- .../__tests__/__snapshots__/App-test.tsx.snap | 106 +++++ .../__snapshots__/FilesCounter-test.js.snap | 25 -- .../__snapshots__/FilesCounter-test.tsx.snap | 25 ++ .../__snapshots__/MeasureHeader-test.js.snap | 268 ------------- .../__snapshots__/MeasureHeader-test.tsx.snap | 223 +++++++++++ .../__snapshots__/PageActions-test.js.snap | 144 ------- .../__snapshots__/PageActions-test.tsx.snap | 144 +++++++ .../js/apps/component-measures/config/bubbles.ts | 2 +- .../js/apps/component-measures/config/domains.ts | 7 +- .../component-measures/drilldown/BubbleChart.js | 223 ----------- .../component-measures/drilldown/BubbleChart.tsx | 202 ++++++++++ .../apps/component-measures/drilldown/CodeView.tsx | 9 +- .../component-measures/drilldown/ComponentCell.js | 133 ------- .../component-measures/drilldown/ComponentCell.tsx | 128 ++++++ .../drilldown/ComponentsListRow.js | 69 ---- .../drilldown/ComponentsListRow.tsx | 67 ++++ .../component-measures/drilldown/MeasureCell.js | 47 --- .../component-measures/drilldown/MeasureCell.tsx | 44 ++ .../drilldown/__tests__/MeasureCell-test.js | 47 --- .../drilldown/__tests__/MeasureCell-test.tsx | 47 +++ .../apps/component-measures/sidebar/DomainFacet.js | 164 -------- .../component-measures/sidebar/DomainFacet.tsx | 162 ++++++++ .../sidebar/FacetMeasureValue.js | 50 --- .../sidebar/FacetMeasureValue.tsx | 53 +++ .../sidebar/ProjectOverviewFacet.js | 53 --- .../sidebar/ProjectOverviewFacet.tsx | 49 +++ .../js/apps/component-measures/sidebar/Sidebar.js | 99 ----- .../js/apps/component-measures/sidebar/Sidebar.tsx | 96 +++++ .../sidebar/__tests__/DomainFacet-test.js | 119 ------ .../sidebar/__tests__/DomainFacet-test.tsx | 120 ++++++ .../sidebar/__tests__/FacetMeasureValue-test.js | 53 --- .../sidebar/__tests__/FacetMeasureValue-test.tsx | 54 +++ .../sidebar/__tests__/Sidebar-test.js | 77 ---- .../sidebar/__tests__/Sidebar-test.tsx | 80 ++++ .../__snapshots__/DomainFacet-test.js.snap | 427 -------------------- .../__snapshots__/DomainFacet-test.tsx.snap | 443 +++++++++++++++++++++ .../__snapshots__/FacetMeasureValue-test.js.snap | 27 -- .../__snapshots__/FacetMeasureValue-test.tsx.snap | 27 ++ .../__tests__/__snapshots__/Sidebar-test.js.snap | 87 ---- .../__tests__/__snapshots__/Sidebar-test.tsx.snap | 90 +++++ .../src/main/js/apps/component-measures/types.js | 58 --- .../src/main/js/apps/component-measures/utils.ts | 9 +- 71 files changed, 3392 insertions(+), 3458 deletions(-) delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/App.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/App.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/AppContainer.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/AppContainer.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/FilesCounter.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/FilesCounter.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/MetricNotFound.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/MetricNotFound.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/PageActions.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/PageActions.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/FilesCounter-test.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/FilesCounter-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/FilesCounter-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/FilesCounter-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/MeasureCell-test.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/MeasureCell-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/ProjectOverviewFacet.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/ProjectOverviewFacet.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/FacetMeasureValue-test.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/FacetMeasureValue-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.js create mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/component-measures/types.js (limited to 'server/sonar-web/src/main/js/apps/component-measures') diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/App.js b/server/sonar-web/src/main/js/apps/component-measures/components/App.js deleted file mode 100644 index f866fd0dd60..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/App.js +++ /dev/null @@ -1,235 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import Helmet from 'react-helmet'; -import key from 'keymaster'; -import MeasureContentContainer from './MeasureContentContainer'; -import MeasureOverviewContainer from './MeasureOverviewContainer'; -import Sidebar from '../sidebar/Sidebar'; -import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper'; -import { isProjectOverview, hasBubbleChart, parseQuery, serializeQuery } from '../utils'; -import { isSameBranchLike, getBranchLikeQuery } from '../../../helpers/branches'; -import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; -import { - getLocalizedMetricDomain, - translateWithParameters, - translate -} from '../../../helpers/l10n'; -import { getDisplayMetrics } from '../../../helpers/measures'; -/*:: import type { Component, Query, Period } from '../types'; */ -/*:: import type { RawQuery } from '../../../helpers/query'; */ -/*:: import type { Metric } from '../../../app/flow-types'; */ -/*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */ -import '../../../components/search-navigator.css'; -import '../style.css'; - -/*:: type Props = {| - branchLike?: { id?: string; name: string }, - component: Component, - currentUser: { isLoggedIn: boolean }, - location: { pathname: string, query: RawQuery }, - fetchMeasures: ( - component: string, - metricsKey: Array, - branchLike?: { id?: string; name: string } - ) => Promise<{ component: Component, measures: Array, leakPeriod: ?Period }>, - fetchMetrics: () => void, - metrics: { [string]: Metric }, - metricsKey: Array, - router: { - push: ({ pathname: string, query?: RawQuery }) => void - } -|}; */ - -/*:: type State = {| - loading: boolean, - measures: Array, - leakPeriod: ?Period -|}; */ - -export default class App extends React.PureComponent { - /*:: mounted: boolean; */ - /*:: props: Props; */ - /*:: state: State; */ - - constructor(props /*: Props */) { - super(props); - this.state = { - loading: true, - measures: [], - leakPeriod: null - }; - } - - componentDidMount() { - this.mounted = true; - // $FlowFixMe - document.body.classList.add('white-page'); - // $FlowFixMe - document.documentElement.classList.add('white-page'); - this.props.fetchMetrics(); - this.fetchMeasures(this.props); - key.setScope('measures-files'); - const footer = document.getElementById('footer'); - if (footer) { - footer.classList.add('page-footer-with-sidebar'); - } - } - - componentWillReceiveProps(nextProps /*: Props */) { - if ( - !isSameBranchLike(nextProps.branchLike, this.props.branchLike) || - nextProps.component.key !== this.props.component.key || - nextProps.metrics !== this.props.metrics - ) { - this.fetchMeasures(nextProps); - } - } - - componentWillUnmount() { - this.mounted = false; - // $FlowFixMe - document.body.classList.remove('white-page'); - // $FlowFixMe - document.documentElement.classList.remove('white-page'); - key.deleteScope('measures-files'); - const footer = document.getElementById('footer'); - if (footer) { - footer.classList.remove('page-footer-with-sidebar'); - } - } - - fetchMeasures = ({ branchLike, component, fetchMeasures, metrics } /*: Props */) => { - this.setState({ loading: true }); - const filteredKeys = getDisplayMetrics(Object.values(metrics)).map(metric => metric.key); - fetchMeasures(component.key, filteredKeys, branchLike).then( - ({ measures, leakPeriod }) => { - if (this.mounted) { - this.setState({ - loading: false, - leakPeriod, - measures: measures.filter(measure => measure.value != null || measure.leak != null) - }); - } - }, - () => { - if (this.mounted) { - this.setState({ loading: false }); - } - } - ); - }; - - updateQuery = (newQuery /*: Query */) => { - const query = serializeQuery({ - ...parseQuery(this.props.location.query), - ...newQuery - }); - this.props.router.push({ - pathname: this.props.location.pathname, - query: { - ...query, - ...getBranchLikeQuery(this.props.branchLike), - id: this.props.component.key - } - }); - }; - - getHelmetTitle = ( - metric /*: Metric */, - query /*: {metric: string, selected: string, view: string }*/ - ) => { - if (metric == null && hasBubbleChart(query.metric)) { - return isProjectOverview(query.metric) - ? translate('component_measures.overview.project_overview.facet') - : translateWithParameters( - 'component_measures.domain_x_overview', - getLocalizedMetricDomain(query.metric) - ); - } - return metric != null ? metric.name : translate('layout.measures'); - }; - - render() { - const isLoading = this.state.loading || this.props.metricsKey.length <= 0; - if (isLoading) { - return ; - } - const { branchLike, component, fetchMeasures, metrics } = this.props; - const { leakPeriod } = this.state; - const query = parseQuery(this.props.location.query); - const metric = metrics[query.metric]; - return ( -
- - - - - {({ top }) => ( -
-
-
- -
-
-
- )} -
- - {metric != null && ( - - )} - {metric == null && - hasBubbleChart(query.metric) && ( - - )} -
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/App.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/App.tsx new file mode 100644 index 00000000000..ff78d3a724a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/App.tsx @@ -0,0 +1,233 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 * as key from 'keymaster'; +import { InjectedRouter } from 'react-router'; +import Helmet from 'react-helmet'; +import MeasureContentContainer from './MeasureContentContainer'; +import MeasureOverviewContainer from './MeasureOverviewContainer'; +import Sidebar from '../sidebar/Sidebar'; +import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper'; +import { isProjectOverview, hasBubbleChart, parseQuery, serializeQuery, Query } from '../utils'; +import { isSameBranchLike, getBranchLikeQuery } from '../../../helpers/branches'; +import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; +import { + getLocalizedMetricDomain, + translateWithParameters, + translate +} from '../../../helpers/l10n'; +import { getDisplayMetrics } from '../../../helpers/measures'; +import { RawQuery } from '../../../helpers/query'; +import { + BranchLike, + ComponentMeasure, + MeasureEnhanced, + Metric, + CurrentUser, + Period +} from '../../../app/types'; +import '../../../components/search-navigator.css'; +import '../style.css'; + +interface Props { + branchLike?: BranchLike; + component: ComponentMeasure; + currentUser: CurrentUser; + location: { pathname: string; query: RawQuery }; + fetchMeasures: ( + component: string, + metricsKey: string[], + branchLike?: BranchLike + ) => Promise<{ component: ComponentMeasure; measures: MeasureEnhanced[]; leakPeriod?: Period }>; + fetchMetrics: () => void; + metrics: { [metric: string]: Metric }; + metricsKey: string[]; + router: InjectedRouter; +} + +interface State { + loading: boolean; + measures: MeasureEnhanced[]; + leakPeriod?: Period; +} + +export default class App extends React.PureComponent { + mounted = false; + + constructor(props: Props) { + super(props); + this.state = { loading: true, measures: [] }; + } + + componentDidMount() { + this.mounted = true; + + document.body.classList.add('white-page'); + document.documentElement.classList.add('white-page'); + const footer = document.getElementById('footer'); + if (footer) { + footer.classList.add('page-footer-with-sidebar'); + } + + key.setScope('measures-files'); + this.props.fetchMetrics(); + this.fetchMeasures(this.props); + } + + componentWillReceiveProps(nextProps: Props) { + if ( + !isSameBranchLike(nextProps.branchLike, this.props.branchLike) || + nextProps.component.key !== this.props.component.key || + nextProps.metrics !== this.props.metrics + ) { + this.fetchMeasures(nextProps); + } + } + + componentWillUnmount() { + this.mounted = false; + + document.body.classList.remove('white-page'); + document.documentElement.classList.remove('white-page'); + + const footer = document.getElementById('footer'); + if (footer) { + footer.classList.remove('page-footer-with-sidebar'); + } + + key.deleteScope('measures-files'); + } + + fetchMeasures = ({ branchLike, component, fetchMeasures, metrics }: Props) => { + this.setState({ loading: true }); + const filteredKeys = getDisplayMetrics(Object.values(metrics)).map(metric => metric.key); + + fetchMeasures(component.key, filteredKeys, branchLike).then( + ({ measures, leakPeriod }) => { + if (this.mounted) { + this.setState({ + loading: false, + leakPeriod, + measures: measures.filter( + measure => measure.value !== undefined || measure.leak !== undefined + ) + }); + } + }, + () => { + if (this.mounted) { + this.setState({ loading: false }); + } + } + ); + }; + + updateQuery = (newQuery: Partial) => { + const query = serializeQuery({ + ...parseQuery(this.props.location.query), + ...newQuery + }); + this.props.router.push({ + pathname: this.props.location.pathname, + query: { + ...query, + ...getBranchLikeQuery(this.props.branchLike), + id: this.props.component.key + } + }); + }; + + getHelmetTitle = (metric?: Metric) => { + if (metric && hasBubbleChart(metric.key)) { + return isProjectOverview(metric.key) + ? translate('component_measures.overview.project_overview.facet') + : translateWithParameters( + 'component_measures.domain_x_overview', + getLocalizedMetricDomain(metric.key) + ); + } + return metric ? metric.name : translate('layout.measures'); + }; + + render() { + const isLoading = this.state.loading || this.props.metricsKey.length <= 0; + if (isLoading) { + return ; + } + const { branchLike, component, fetchMeasures, metrics } = this.props; + const { leakPeriod } = this.state; + const query = parseQuery(this.props.location.query); + const metric = metrics[query.metric]; + return ( +
+ + + + + {({ top }) => ( +
+
+
+ +
+
+
+ )} +
+ + {metric && ( + + )} + {!metric && + hasBubbleChart(query.metric) && ( + + )} +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/AppContainer.js b/server/sonar-web/src/main/js/apps/component-measures/components/AppContainer.js deleted file mode 100644 index b02d379358c..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/AppContainer.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import { connect } from 'react-redux'; -import { withRouter } from 'react-router'; -import App from './App'; -import throwGlobalError from '../../../app/utils/throwGlobalError'; -import { getCurrentUser, getMetrics, getMetricsKey } from '../../../store/rootReducer'; -import { fetchMetrics } from '../../../store/rootActions'; -import { getMeasuresAndMeta } from '../../../api/measures'; -import { getLeakPeriod } from '../../../helpers/periods'; -import { enhanceMeasure } from '../../../components/measure/utils'; -import { getBranchLikeQuery } from '../../../helpers/branches'; -/*:: import type { Component, Period } from '../types'; */ -/*:: import type { Measure, MeasureEnhanced } from '../../../components/measure/types'; */ - -const mapStateToProps = state => ({ - currentUser: getCurrentUser(state), - metrics: getMetrics(state), - metricsKey: getMetricsKey(state) -}); - -function banQualityGate(component /*: Component */) /*: Array */ { - const bannedMetrics = []; - if (!['VW', 'SVW'].includes(component.qualifier)) { - bannedMetrics.push('alert_status'); - } - if (component.qualifier === 'APP') { - bannedMetrics.push('releasability_rating', 'releasability_effort'); - } - return component.measures.filter(measure => !bannedMetrics.includes(measure.metric)); -} - -const fetchMeasures = ( - component /*: string */, - metricsKey /*: Array */, - branchLike /*: { id?: string; name: string } | void */ -) => (dispatch, getState) => { - if (metricsKey.length <= 0) { - return Promise.resolve({ component: {}, measures: [], leakPeriod: null }); - } - - return getMeasuresAndMeta(component, metricsKey, { - additionalFields: 'periods', - ...getBranchLikeQuery(branchLike) - }).then(r => { - const measures = banQualityGate(r.component).map(measure => - enhanceMeasure(measure, getMetrics(getState())) - ); - - const newBugs = measures.find(measure => measure.metric.key === 'new_bugs'); - const applicationPeriods = newBugs ? [{ index: 1 }] : []; - const periods = r.component.qualifier === 'APP' ? applicationPeriods : r.periods; - return { component: r.component, measures, leakPeriod: getLeakPeriod(periods) }; - }, throwGlobalError); -}; - -const mapDispatchToProps = { fetchMeasures, fetchMetrics }; - -export default connect( - mapStateToProps, - mapDispatchToProps -)(withRouter(App)); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/AppContainer.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/AppContainer.tsx new file mode 100644 index 00000000000..86c347c7be4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/AppContainer.tsx @@ -0,0 +1,108 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { Dispatch } from 'redux'; +import { connect } from 'react-redux'; +import { withRouter, WithRouterProps } from 'react-router'; +import App from './App'; +import throwGlobalError from '../../../app/utils/throwGlobalError'; +import { getCurrentUser, getMetrics, getMetricsKey } from '../../../store/rootReducer'; +import { fetchMetrics } from '../../../store/rootActions'; +import { getMeasuresAndMeta } from '../../../api/measures'; +import { getLeakPeriod } from '../../../helpers/periods'; +import { enhanceMeasure } from '../../../components/measure/utils'; +import { getBranchLikeQuery } from '../../../helpers/branches'; +import { + BranchLike, + ComponentMeasure, + CurrentUser, + Measure, + MeasureEnhanced, + Metric, + Period +} from '../../../app/types'; + +interface StateToProps { + currentUser: CurrentUser; + metrics: { [metric: string]: Metric }; + metricsKey: string[]; +} + +interface DispatchToProps { + fetchMeasures: ( + component: string, + metricsKey: string[], + branchLike?: BranchLike + ) => Promise<{ component: ComponentMeasure; measures: MeasureEnhanced[]; leakPeriod?: Period }>; + fetchMetrics: () => void; +} + +interface OwnProps { + branchLike?: BranchLike; + component: ComponentMeasure; +} + +const mapStateToProps = (state: any): StateToProps => ({ + currentUser: getCurrentUser(state), + metrics: getMetrics(state), + metricsKey: getMetricsKey(state) +}); + +function banQualityGate({ measures = [], qualifier }: ComponentMeasure): Measure[] { + const bannedMetrics: string[] = []; + if (!['VW', 'SVW'].includes(qualifier)) { + bannedMetrics.push('alert_status'); + } + if (qualifier === 'APP') { + bannedMetrics.push('releasability_rating', 'releasability_effort'); + } + return measures.filter(measure => !bannedMetrics.includes(measure.metric)); +} + +const fetchMeasures = (component: string, metricsKey: string[], branchLike?: BranchLike) => ( + _dispatch: Dispatch, + getState: () => any +) => { + if (metricsKey.length <= 0) { + return Promise.resolve({ component: {}, measures: [], leakPeriod: null }); + } + + return getMeasuresAndMeta(component, metricsKey, { + additionalFields: 'periods', + ...getBranchLikeQuery(branchLike) + }).then(({ component, periods }) => { + const measures = banQualityGate(component).map(measure => + enhanceMeasure(measure, getMetrics(getState())) + ); + + const newBugs = measures.find(measure => measure.metric.key === 'new_bugs'); + const applicationPeriods = newBugs ? [{ index: 1 } as Period] : []; + const leakPeriod = getLeakPeriod(component.qualifier === 'APP' ? applicationPeriods : periods); + return { component, measures, leakPeriod }; + }, throwGlobalError); +}; + +const mapDispatchToProps: DispatchToProps = { fetchMeasures: fetchMeasures as any, fetchMetrics }; + +export default withRouter( + connect( + mapStateToProps, + mapDispatchToProps + )(App) +); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/FilesCounter.js b/server/sonar-web/src/main/js/apps/component-measures/components/FilesCounter.js deleted file mode 100644 index 94ab8b016f9..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/FilesCounter.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import { translate } from '../../../helpers/l10n'; -import { formatMeasure } from '../../../helpers/measures'; - -/*:: type Props = { - className?: string, - current: ?number, - total: number -}; */ - -export default function FilesCounter({ className, current, total } /*: Props */) { - return ( - - - {current != null && ( - - {formatMeasure(current, 'INT')} - {' / '} - - )} - {formatMeasure(total, 'INT')} - {' '} - {translate('component_measures.files')} - - ); -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/FilesCounter.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/FilesCounter.tsx new file mode 100644 index 00000000000..37e794a6ee8 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/FilesCounter.tsx @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 '../../../helpers/l10n'; +import { formatMeasure } from '../../../helpers/measures'; + +interface Props { + className?: string; + current?: number; + total: number; +} + +export default function FilesCounter({ className, current, total }: Props) { + return ( + + + {current !== undefined && ( + + {formatMeasure(current, 'INT')} + {' / '} + + )} + {formatMeasure(total, 'INT')} + {' '} + {translate('component_measures.files')} + + ); +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx index 8c61f4e87b7..f1d8747a2c8 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx @@ -24,10 +24,10 @@ import DateFromNow from '../../../components/intl/DateFromNow'; import DateFormatter, { longFormatterOption } from '../../../components/intl/DateFormatter'; import DateTimeFormatter from '../../../components/intl/DateTimeFormatter'; import Tooltip from '../../../components/controls/Tooltip'; -import { getPeriodLabel, getPeriodDate, Period, PeriodMode } from '../../../helpers/periods'; +import { getPeriodLabel, getPeriodDate } from '../../../helpers/periods'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { differenceInDays } from '../../../helpers/dates'; -import { ComponentMeasure } from '../../../app/types'; +import { ComponentMeasure, Period, PeriodMode } from '../../../app/types'; interface Props { className?: string; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx index 9472307bc7e..7eee54217b6 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx @@ -44,10 +44,10 @@ import { isLoggedIn, Metric, Paging, - MeasureEnhanced + MeasureEnhanced, + Period } from '../../../app/types'; import { RequestData } from '../../../helpers/request'; -import { Period } from '../../../helpers/periods'; interface Props { branchLike?: BranchLike; @@ -328,10 +328,8 @@ export default class MeasureContent extends React.PureComponent { diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContentContainer.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContentContainer.tsx index 3c3a636538f..c8a1301038d 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContentContainer.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContentContainer.tsx @@ -26,9 +26,9 @@ import { Metric, BranchLike, CurrentUser, - MeasureEnhanced + MeasureEnhanced, + Period } from '../../../app/types'; -import { Period } from '../../../helpers/periods'; interface Props { branchLike?: BranchLike; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js deleted file mode 100644 index c39214fba0b..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import { Link } from 'react-router'; -import LeakPeriodLegend from './LeakPeriodLegend'; -import HistoryIcon from '../../../components/icons-components/HistoryIcon'; -import IssueTypeIcon from '../../../components/ui/IssueTypeIcon'; -import LanguageDistributionContainer from '../../../components/charts/LanguageDistributionContainer'; -import Measure from '../../../components/measure/Measure'; -import Tooltip from '../../../components/controls/Tooltip'; -import { getLocalizedMetricName, translate } from '../../../helpers/l10n'; -import { getMeasureHistoryUrl } from '../../../helpers/urls'; -import { isDiffMetric } from '../../../helpers/measures'; -/*:: import type { Component, Period } from '../types'; */ -/*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */ -/*:: import type { Metric } from '../../../app/flow-types'; */ - -/*:: type Props = {| - branchLike?: { id?: string; name: string }, - component: Component, - components: Array, - leakPeriod?: Period, - measure?: MeasureEnhanced, - metric: Metric, - secondaryMeasure: ?MeasureEnhanced -|}; */ - -export default function MeasureHeader(props /*: Props*/) { - const { branchLike, component, leakPeriod, measure, metric, secondaryMeasure } = props; - const isDiff = isDiffMetric(metric.key); - const hasHistory = component.qualifier !== 'FIL' && component.qualifier !== 'UTS'; - return ( -
-
-
- - {getLocalizedMetricName(metric)} - - - {isDiff ? ( - - ) : ( - - )} - - - {!isDiff && - hasHistory && ( - - - - - - )} -
-
- {leakPeriod != null && ( - - )} -
-
- {secondaryMeasure && - secondaryMeasure.metric.key === 'ncloc_language_distribution' && ( -
- -
- )} -
- ); -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.tsx new file mode 100644 index 00000000000..61840e12d62 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.tsx @@ -0,0 +1,100 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 LeakPeriodLegend from './LeakPeriodLegend'; +import HistoryIcon from '../../../components/icons-components/HistoryIcon'; +import IssueTypeIcon from '../../../components/ui/IssueTypeIcon'; +import LanguageDistributionContainer from '../../../components/charts/LanguageDistributionContainer'; +import Measure from '../../../components/measure/Measure'; +import Tooltip from '../../../components/controls/Tooltip'; +import { getLocalizedMetricName, translate } from '../../../helpers/l10n'; +import { getMeasureHistoryUrl } from '../../../helpers/urls'; +import { isDiffMetric } from '../../../helpers/measures'; +import { MeasureEnhanced, Metric, ComponentMeasure, BranchLike, Period } from '../../../app/types'; + +interface Props { + branchLike?: BranchLike; + component: ComponentMeasure; + leakPeriod?: Period; + measure?: MeasureEnhanced; + metric: Metric; + secondaryMeasure?: MeasureEnhanced; +} + +export default function MeasureHeader(props: Props) { + const { branchLike, component, leakPeriod, measure, metric, secondaryMeasure } = props; + const isDiff = isDiffMetric(metric.key); + const hasHistory = component.qualifier !== 'FIL' && component.qualifier !== 'UTS'; + return ( +
+
+
+ + {getLocalizedMetricName(metric)} + + + {isDiff ? ( + + ) : ( + + )} + + + {!isDiff && + hasHistory && ( + + + + + + )} +
+
+ {leakPeriod && ( + + )} +
+
+ {secondaryMeasure && + secondaryMeasure.metric.key === 'ncloc_language_distribution' && + secondaryMeasure.value !== undefined && ( +
+ +
+ )} +
+ ); +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js deleted file mode 100644 index 495626eaede..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.js +++ /dev/null @@ -1,184 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import Breadcrumbs from './Breadcrumbs'; -import LeakPeriodLegend from './LeakPeriodLegend'; -import MeasureFavoriteContainer from './MeasureFavoriteContainer'; -import PageActions from './PageActions'; -import BubbleChart from '../drilldown/BubbleChart'; -import SourceViewer from '../../../components/SourceViewer/SourceViewer'; -import { getComponentLeaves } from '../../../api/components'; -import { enhanceComponent, getBubbleMetrics, isFileType } from '../utils'; -import { getBranchLikeQuery } from '../../../helpers/branches'; -import DeferredSpinner from '../../../components/common/DeferredSpinner'; -/*:: import type { Component, ComponentEnhanced, Paging, Period } from '../types'; */ -/*:: import type { Metric } from '../../../app/flow-types'; */ - -/*:: type Props = {| - branchLike?: { id?: string; name: string }, - className?: string, - component: Component, - currentUser: { isLoggedIn: boolean }, - domain: string, - leakPeriod: Period, - loading: boolean, - metrics: { [string]: Metric }, - rootComponent: Component, - updateLoading: ({ [string]: boolean }) => void, - updateSelected: string => void -|}; */ - -/*:: type State = { - components: Array, - paging?: Paging -}; */ - -const BUBBLES_LIMIT = 500; - -export default class MeasureOverview extends React.PureComponent { - /*:: mounted: boolean; */ - /*:: props: Props; */ - state /*: State */ = { - components: [], - paging: null - }; - - componentDidMount() { - this.mounted = true; - this.fetchComponents(this.props); - } - - componentWillReceiveProps(nextProps /*: Props */) { - if ( - nextProps.component !== this.props.component || - nextProps.metrics !== this.props.metrics || - nextProps.domain !== this.props.domain - ) { - this.fetchComponents(nextProps); - } - } - - componentWillUnmount() { - this.mounted = false; - } - - fetchComponents = (props /*: Props */) => { - const { branchLike, component, domain, metrics } = props; - if (isFileType(component)) { - this.setState({ components: [], paging: null }); - return; - } - const { x, y, size, colors } = getBubbleMetrics(domain, metrics); - const metricsKey = [x.key, y.key, size.key]; - if (colors) { - metricsKey.push(colors.map(metric => metric.key)); - } - const options = { - ...getBranchLikeQuery(branchLike), - s: 'metric', - metricSort: size.key, - asc: false, - ps: BUBBLES_LIMIT - }; - - this.props.updateLoading({ bubbles: true }); - getComponentLeaves(component.key, metricsKey, options).then( - r => { - if (domain === this.props.domain) { - if (this.mounted) { - this.setState({ - components: r.components.map(component => enhanceComponent(component, null, metrics)), - paging: r.paging - }); - } - this.props.updateLoading({ bubbles: false }); - } - }, - () => this.props.updateLoading({ bubbles: false }) - ); - }; - - renderContent() { - const { branchLike, component } = this.props; - if (isFileType(component)) { - return ( -
- -
- ); - } - - return ( - - ); - } - - render() { - const { branchLike, component, currentUser, leakPeriod, rootComponent } = this.props; - const isLoggedIn = currentUser && currentUser.isLoggedIn; - const isFile = isFileType(component); - return ( -
-
-
-
- - {component.key !== rootComponent.key && - isLoggedIn && ( - - )} - -
-
-
-
-
- {leakPeriod != null && ( - - )} -
- - {!this.props.loading && this.renderContent()} -
-
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.tsx new file mode 100644 index 00000000000..18c34ea5d4a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverview.tsx @@ -0,0 +1,188 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 Breadcrumbs from './Breadcrumbs'; +import LeakPeriodLegend from './LeakPeriodLegend'; +import MeasureFavoriteContainer from './MeasureFavoriteContainer'; +import PageActions from './PageActions'; +import BubbleChart from '../drilldown/BubbleChart'; +import SourceViewer from '../../../components/SourceViewer/SourceViewer'; +import { getComponentLeaves } from '../../../api/components'; +import { enhanceComponent, getBubbleMetrics, isFileType } from '../utils'; +import { getBranchLikeQuery } from '../../../helpers/branches'; +import DeferredSpinner from '../../../components/common/DeferredSpinner'; +import { + BranchLike, + ComponentMeasure, + ComponentMeasureEnhanced, + CurrentUser, + Metric, + Paging, + Period +} from '../../../app/types'; + +interface Props { + branchLike?: BranchLike; + className?: string; + component: ComponentMeasure; + currentUser: CurrentUser; + domain: string; + leakPeriod?: Period; + loading: boolean; + metrics: { [metric: string]: Metric }; + rootComponent: ComponentMeasure; + updateLoading: (param: { [key: string]: boolean }) => void; + updateSelected: (component: string) => void; +} + +interface State { + components: ComponentMeasureEnhanced[]; + paging?: Paging; +} + +const BUBBLES_LIMIT = 500; + +export default class MeasureOverview extends React.PureComponent { + mounted = false; + state: State = { components: [] }; + + componentDidMount() { + this.mounted = true; + this.fetchComponents(this.props); + } + + componentWillReceiveProps(nextProps: Props) { + if ( + nextProps.component !== this.props.component || + nextProps.metrics !== this.props.metrics || + nextProps.domain !== this.props.domain + ) { + this.fetchComponents(nextProps); + } + } + + componentWillUnmount() { + this.mounted = false; + } + + fetchComponents = (props: Props) => { + const { branchLike, component, domain, metrics } = props; + if (isFileType(component)) { + this.setState({ components: [], paging: undefined }); + return; + } + const { x, y, size, colors } = getBubbleMetrics(domain, metrics); + const metricsKey = [x.key, y.key, size.key]; + if (colors) { + metricsKey.push(...colors.map(metric => metric.key)); + } + const options = { + ...getBranchLikeQuery(branchLike), + s: 'metric', + metricSort: size.key, + asc: false, + ps: BUBBLES_LIMIT + }; + + this.props.updateLoading({ bubbles: true }); + getComponentLeaves(component.key, metricsKey, options).then( + r => { + if (domain === this.props.domain) { + if (this.mounted) { + this.setState({ + components: r.components.map(component => + enhanceComponent(component, undefined, metrics) + ), + paging: r.paging + }); + } + this.props.updateLoading({ bubbles: false }); + } + }, + () => this.props.updateLoading({ bubbles: false }) + ); + }; + + renderContent() { + const { branchLike, component } = this.props; + if (isFileType(component)) { + return ( +
+ +
+ ); + } + + return ( + + ); + } + + render() { + const { branchLike, component, currentUser, leakPeriod, rootComponent } = this.props; + const isLoggedIn = currentUser && currentUser.isLoggedIn; + const isFile = isFileType(component); + return ( +
+
+
+
+ + {component.key !== rootComponent.key && + isLoggedIn && ( + + )} + +
+
+
+
+
+ {leakPeriod && ( + + )} +
+ + {!this.props.loading && this.renderContent()} +
+
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.js deleted file mode 100644 index db4caed4947..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.js +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import MeasureOverview from './MeasureOverview'; -import { getComponentShow } from '../../../api/components'; -import { getProjectUrl } from '../../../helpers/urls'; -import { isViewType } from '../utils'; -import { getBranchLikeQuery } from '../../../helpers/branches'; -/*:: import type { Component, Period, Query } from '../types'; */ -/*:: import type { RawQuery } from '../../../helpers/query'; */ -/*:: import type { Metric } from '../../../app/flow-types'; */ - -/*:: type Props = {| - branchLike?: { id?: string; name: string }, - className?: string, - rootComponent: Component, - currentUser: { isLoggedIn: boolean }, - domain: string, - leakPeriod: Period, - metrics: { [string]: Metric }, - router: { - push: ({ pathname: string, query?: RawQuery }) => void - }, - selected: ?string, - updateQuery: Query => void -|}; */ - -/*:: type State = { - component: ?Component, - loading: { - component: boolean, - bubbles: boolean - } -}; */ - -export default class MeasureOverviewContainer extends React.PureComponent { - /*:: mounted: boolean; */ - /*:: props: Props; */ - state /*: State */ = { - component: null, - loading: { - component: false, - bubbles: false - } - }; - - componentDidMount() { - this.mounted = true; - this.fetchComponent(this.props); - } - - componentWillReceiveProps(nextProps /*: Props */) { - const { component } = this.state; - const componentChanged = - !component || - nextProps.rootComponent.key !== component.key || - nextProps.selected !== component.key; - if (componentChanged || nextProps.domain !== this.props.domain) { - this.fetchComponent(nextProps); - } - } - - componentWillUnmount() { - this.mounted = false; - } - - fetchComponent = ({ branchLike, rootComponent, selected } /*: Props */) => { - if (!selected || rootComponent.key === selected) { - this.setState({ component: rootComponent }); - this.updateLoading({ component: false }); - return; - } - this.updateLoading({ component: true }); - getComponentShow({ component: selected, ...getBranchLikeQuery(branchLike) }).then( - ({ component }) => { - if (this.mounted) { - this.setState({ component }); - this.updateLoading({ component: false }); - } - }, - () => this.updateLoading({ component: false }) - ); - }; - - updateLoading = (loading /*: { [string]: boolean } */) => { - if (this.mounted) { - this.setState(state => ({ loading: { ...state.loading, ...loading } })); - } - }; - - updateSelected = (component /*: string */) => { - if (this.state.component && isViewType(this.state.component)) { - this.props.router.push(getProjectUrl(component)); - } else { - this.props.updateQuery({ - selected: component !== this.props.rootComponent.key ? component : null - }); - } - }; - - render() { - if (!this.state.component) { - return null; - } - - return ( - - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.tsx new file mode 100644 index 00000000000..642cde71e20 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureOverviewContainer.tsx @@ -0,0 +1,134 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { InjectedRouter } from 'react-router'; +import MeasureOverview from './MeasureOverview'; +import { getComponentShow } from '../../../api/components'; +import { getProjectUrl } from '../../../helpers/urls'; +import { isViewType, Query } from '../utils'; +import { getBranchLikeQuery } from '../../../helpers/branches'; +import { BranchLike, ComponentMeasure, CurrentUser, Metric, Period } from '../../../app/types'; + +interface Props { + branchLike?: BranchLike; + className?: string; + currentUser: CurrentUser; + domain: string; + leakPeriod?: Period; + metrics: { [metric: string]: Metric }; + rootComponent: ComponentMeasure; + router: InjectedRouter; + selected?: string; + updateQuery: (query: Partial) => void; +} + +interface LoadingState { + bubbles: boolean; + component: boolean; +} + +interface State { + component?: ComponentMeasure; + loading: LoadingState; +} + +export default class MeasureOverviewContainer extends React.PureComponent { + mounted = false; + + state: State = { + loading: { bubbles: false, component: false } + }; + + componentDidMount() { + this.mounted = true; + this.fetchComponent(this.props); + } + + componentWillReceiveProps(nextProps: Props) { + const { component } = this.state; + const componentChanged = + !component || + nextProps.rootComponent.key !== component.key || + nextProps.selected !== component.key; + if (componentChanged || nextProps.domain !== this.props.domain) { + this.fetchComponent(nextProps); + } + } + + componentWillUnmount() { + this.mounted = false; + } + + fetchComponent = ({ branchLike, rootComponent, selected }: Props) => { + if (!selected || rootComponent.key === selected) { + this.setState({ component: rootComponent }); + this.updateLoading({ component: false }); + return; + } + this.updateLoading({ component: true }); + getComponentShow({ component: selected, ...getBranchLikeQuery(branchLike) }).then( + ({ component }) => { + if (this.mounted) { + this.setState({ component }); + this.updateLoading({ component: false }); + } + }, + () => this.updateLoading({ component: false }) + ); + }; + + updateLoading = (loading: Partial) => { + if (this.mounted) { + this.setState(state => ({ loading: { ...state.loading, ...loading } })); + } + }; + + updateSelected = (component: string) => { + if (this.state.component && isViewType(this.state.component)) { + this.props.router.push(getProjectUrl(component)); + } else { + this.props.updateQuery({ + selected: component !== this.props.rootComponent.key ? component : undefined + }); + } + }; + + render() { + if (!this.state.component) { + return null; + } + + return ( + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MetricNotFound.js b/server/sonar-web/src/main/js/apps/component-measures/components/MetricNotFound.js deleted file mode 100644 index e51270786d1..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MetricNotFound.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import { translate } from '../../../helpers/l10n'; - -export default function MetricNotFound({ className } /*: { className?: string } */) { - return ( -
-
{translate('component_measures.not_found')}
-
- ); -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MetricNotFound.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MetricNotFound.tsx new file mode 100644 index 00000000000..6009d74a6c9 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MetricNotFound.tsx @@ -0,0 +1,29 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 '../../../helpers/l10n'; + +export default function MetricNotFound({ className }: { className?: string }) { + return ( +
+
{translate('component_measures.not_found')}
+
+ ); +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/PageActions.js b/server/sonar-web/src/main/js/apps/component-measures/components/PageActions.js deleted file mode 100644 index 4b26994fa81..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/PageActions.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import FilesCounter from './FilesCounter'; -import { translate } from '../../../helpers/l10n'; -/*:: import type { Paging } from '../types'; */ - -/*:: type Props = {| - current: ?number, - isFile: ?boolean, - paging: ?Paging, - totalLoadedComponents?: number, - view?: string -|}; */ - -export default function PageActions(props /*: Props */) { - const { isFile, paging, totalLoadedComponents } = props; - const showShortcuts = ['list', 'tree'].includes(props.view); - return ( -
- {!isFile && showShortcuts && renderShortcuts()} - {isFile && paging && renderFileShortcuts()} -
- {paging != null && ( - - )} -
-
- ); -} - -function renderShortcuts() { - return ( - - - - - {translate('component_measures.to_select_files')} - - - - - - {translate('component_measures.to_navigate')} - - - ); -} - -function renderFileShortcuts() { - return ( - - - j - k - {translate('component_measures.to_navigate_files')} - - - ); -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/PageActions.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/PageActions.tsx new file mode 100644 index 00000000000..75078edb21a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/PageActions.tsx @@ -0,0 +1,81 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 FilesCounter from './FilesCounter'; +import { translate } from '../../../helpers/l10n'; +import { Paging } from '../../../app/types'; + +interface Props { + current?: number; + isFile?: boolean; + paging?: Paging; + totalLoadedComponents?: number; + view?: string; +} + +export default function PageActions(props: Props) { + const { isFile, paging, totalLoadedComponents } = props; + const showShortcuts = props.view && ['list', 'tree'].includes(props.view); + return ( +
+ {!isFile && showShortcuts && renderShortcuts()} + {isFile && paging && renderFileShortcuts()} +
+ {paging != null && ( + + )} +
+
+ ); +} + +function renderShortcuts() { + return ( + + + + + {translate('component_measures.to_select_files')} + + + + + + {translate('component_measures.to_navigate')} + + + ); +} + +function renderFileShortcuts() { + return ( + + + j + k + {translate('component_measures.to_navigate_files')} + + + ); +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.js b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.js deleted file mode 100644 index 5b19497408a..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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 React from 'react'; -import { shallow } from 'enzyme'; -import App from '../App'; - -const METRICS = { - lines_to_cover: { - key: 'lines_to_cover', - type: 'INT', - name: 'Lines to Cover', - domain: 'Coverage' - }, - coverage: { key: 'coverage', type: 'PERCENT', name: 'Coverage', domain: 'Coverage' }, - duplicated_lines_density: { - key: 'duplicated_lines_density', - type: 'PERCENT', - name: 'Duplicated Lines (%)', - domain: 'Duplications' - }, - new_bugs: { key: 'new_bugs', type: 'INT', name: 'New Bugs', domain: 'Reliability' } -}; - -const PROPS = { - branch: { isMain: true, name: 'master' }, - component: { key: 'foo' }, - location: { pathname: '/component_measures', query: { metric: 'coverage' } }, - fetchMeasures: () => Promise.resolve({ measures: [] }), - fetchMetrics: () => {}, - metrics: METRICS, - metricsKey: ['lines_to_cover', 'coverage', 'duplicated_lines_density', 'new_bugs'], - router: { push: () => {} } -}; - -it('should render correctly', () => { - const wrapper = shallow(); - expect(wrapper.find('.spinner')).toHaveLength(1); - wrapper.setState({ loading: false }); - expect(wrapper).toMatchSnapshot(); -}); - -it('should render a measure overview', () => { - const wrapper = shallow( - - ); - expect(wrapper.find('.spinner')).toHaveLength(1); - wrapper.setState({ loading: false }); - expect(wrapper.find('MeasureOverviewContainer')).toHaveLength(1); -}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx new file mode 100644 index 00000000000..f0202595073 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx @@ -0,0 +1,75 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 camelcase */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import App from '../App'; + +const COMPONENT = { key: 'foo', name: 'Foo', qualifier: 'TRK' }; + +const METRICS = { + lines_to_cover: { + id: '1', + key: 'lines_to_cover', + type: 'INT', + name: 'Lines to Cover', + domain: 'Coverage' + }, + coverage: { id: '2', key: 'coverage', type: 'PERCENT', name: 'Coverage', domain: 'Coverage' }, + duplicated_lines_density: { + id: '3', + key: 'duplicated_lines_density', + type: 'PERCENT', + name: 'Duplicated Lines (%)', + domain: 'Duplications' + }, + new_bugs: { id: '4', key: 'new_bugs', type: 'INT', name: 'New Bugs', domain: 'Reliability' } +}; + +const PROPS = { + branch: { isMain: true, name: 'master' }, + component: COMPONENT, + currentUser: { isLoggedIn: false }, + location: { pathname: '/component_measures', query: { metric: 'coverage' } }, + fetchMeasures: jest.fn().mockResolvedValue({ component: COMPONENT, measures: [] }), + fetchMetrics: jest.fn(), + metrics: METRICS, + metricsKey: ['lines_to_cover', 'coverage', 'duplicated_lines_density', 'new_bugs'], + router: { push: jest.fn() } as any +}; + +it('should render correctly', () => { + const wrapper = shallow(); + expect(wrapper.find('.spinner')).toHaveLength(1); + wrapper.setState({ loading: false }); + expect(wrapper).toMatchSnapshot(); +}); + +it('should render a measure overview', () => { + const wrapper = shallow( + + ); + expect(wrapper.find('.spinner')).toHaveLength(1); + wrapper.setState({ loading: false }); + expect(wrapper.find('MeasureOverviewContainer')).toHaveLength(1); +}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/FilesCounter-test.js b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/FilesCounter-test.js deleted file mode 100644 index 1cedf4a4238..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/FilesCounter-test.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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 React from 'react'; -import { shallow } from 'enzyme'; -import FilesCounter from '../FilesCounter'; - -it('should display x files on y total', () => { - expect(shallow()).toMatchSnapshot(); -}); - -it('should display only total of files', () => { - expect(shallow()).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/FilesCounter-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/FilesCounter-test.tsx new file mode 100644 index 00000000000..8d02bc65a1c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/FilesCounter-test.tsx @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { shallow } from 'enzyme'; +import FilesCounter from '../FilesCounter'; + +it('should display x files on y total', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('should display only total of files', () => { + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.tsx index 475b6e17bc6..be616b62017 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/LeakPeriodLegend-test.tsx @@ -20,9 +20,8 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import LeakPeriodLegend from '../LeakPeriodLegend'; -import { PeriodMode, Period } from '../../../../helpers/periods'; import { differenceInDays } from '../../../../helpers/dates'; -import { ComponentMeasure } from '../../../../app/types'; +import { ComponentMeasure, Period, PeriodMode } from '../../../../app/types'; jest.mock('../../../../helpers/dates', () => { const dates = require.requireActual('../../../../helpers/dates'); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.js b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.js deleted file mode 100644 index 5582f01e151..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.js +++ /dev/null @@ -1,128 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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 React from 'react'; -import { shallow } from 'enzyme'; -import MeasureHeader from '../MeasureHeader'; - -const METRIC = { - key: 'reliability_rating', - type: 'RATING', - name: 'Reliability Rating' -}; - -const MEASURE = { - value: '3.0', - periods: [{ index: 1, value: '0.0' }], - metric: METRIC, - leak: '0.0' -}; - -const LEAK_METRIC = { - key: 'new_reliability_rating', - type: 'RATING', - name: 'Reliability Rating on New Code' -}; - -const LEAK_MEASURE = { - periods: [{ index: 1, value: '3.0' }], - metric: LEAK_METRIC, - leak: '3.0' -}; - -const SECONDARY = { - value: 'java=175123;js=26382', - metric: { - key: 'ncloc_language_distribution', - type: 'DATA', - name: 'Lines of Code Per Language' - }, - leak: null -}; - -const PROPS = { - component: { key: 'foo', qualifier: 'TRK' }, - components: [], - handleSelect: () => {}, - leakPeriod: { - date: '2017-05-16T13:50:02+0200', - index: 1, - mode: 'previous_version', - parameter: '6,4' - }, - measure: MEASURE, - metric: METRIC, - paging: null, - secondaryMeasure: null, - selectedIdx: null -}; - -it('should render correctly', () => { - expect(shallow()).toMatchSnapshot(); -}); - -it('should render correctly for leak', () => { - expect( - shallow() - ).toMatchSnapshot(); -}); - -it('should render with branch', () => { - const shortBranch = { isMain: false, name: 'feature', mergeBranch: '', type: 'SHORT' }; - expect( - shallow().find('Link') - ).toMatchSnapshot(); -}); - -it('should not render link to activity page for files', () => { - expect( - shallow() - .find('HistoryIcon') - .exists() - ).toBeTruthy(); - - expect( - shallow() - .find('HistoryIcon') - .exists() - ).toBeFalsy(); -}); - -it('should display secondary measure too', () => { - const wrapper = shallow(); - expect(wrapper.find('Connect(LanguageDistribution)')).toHaveLength(1); -}); - -it('should display correctly for open file', () => { - const wrapper = shallow( - - ); - expect(wrapper.find('.measure-details-primary-actions')).toMatchSnapshot(); - wrapper.setProps({ components: [{ key: 'foo' }, { key: 'bar' }] }); - expect(wrapper.find('.measure-details-primary-actions')).toMatchSnapshot(); -}); - -it('should work with measure without value', () => { - expect(shallow()).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.tsx new file mode 100644 index 00000000000..965af1b5474 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureHeader-test.tsx @@ -0,0 +1,112 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { shallow } from 'enzyme'; +import MeasureHeader from '../MeasureHeader'; +import { PeriodMode } from '../../../../app/types'; + +const METRIC = { + id: '1', + key: 'reliability_rating', + type: 'RATING', + name: 'Reliability Rating' +}; + +const MEASURE = { + value: '3.0', + periods: [{ index: 1, value: '0.0' }], + metric: METRIC, + leak: '0.0' +}; + +const LEAK_METRIC = { + id: '2', + key: 'new_reliability_rating', + type: 'RATING', + name: 'Reliability Rating on New Code' +}; + +const LEAK_MEASURE = { + periods: [{ index: 1, value: '3.0' }], + metric: LEAK_METRIC, + leak: '3.0' +}; + +const SECONDARY = { + value: 'java=175123;js=26382', + metric: { + id: '3', + key: 'ncloc_language_distribution', + type: 'DATA', + name: 'Lines of Code Per Language' + } +}; + +const PROPS = { + component: { key: 'foo', name: 'Foo', qualifier: 'TRK' }, + leakPeriod: { + date: '2017-05-16T13:50:02+0200', + index: 1, + mode: PeriodMode.PreviousVersion, + parameter: '6,4' + }, + measure: MEASURE, + metric: METRIC +}; + +it('should render correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('should render correctly for leak', () => { + expect( + shallow() + ).toMatchSnapshot(); +}); + +it('should render with branch', () => { + const shortBranch = { isMain: false, name: 'feature', mergeBranch: '', type: 'SHORT' }; + expect( + shallow().find('Link') + ).toMatchSnapshot(); +}); + +it('should not render link to activity page for files', () => { + expect( + shallow() + .find('HistoryIcon') + .exists() + ).toBeTruthy(); + + expect( + shallow() + .find('HistoryIcon') + .exists() + ).toBeFalsy(); +}); + +it('should display secondary measure too', () => { + const wrapper = shallow(); + expect(wrapper.find('Connect(LanguageDistribution)')).toHaveLength(1); +}); + +it('should work with measure without value', () => { + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.js b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.js deleted file mode 100644 index 067ecb4d78d..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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 React from 'react'; -import { shallow } from 'enzyme'; -import PageActions from '../PageActions'; - -it('should display correctly for a project', () => { - expect( - shallow() - ).toMatchSnapshot(); -}); - -it('should display correctly for a file', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - wrapper.setProps({ paging: { total: 100 } }); - expect(wrapper).toMatchSnapshot(); -}); - -it('should not display shortcuts for treemap', () => { - expect( - shallow() - ).toMatchSnapshot(); -}); - -it('should display the total of files', () => { - expect( - shallow( - - ) - ).toMatchSnapshot(); - expect( - shallow( - - ) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.tsx new file mode 100644 index 00000000000..016e36de105 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/PageActions-test.tsx @@ -0,0 +1,72 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { shallow } from 'enzyme'; +import PageActions from '../PageActions'; + +const PAGING = { + pageIndex: 1, + pageSize: 100, + total: 120 +}; + +it('should display correctly for a project', () => { + expect( + shallow() + ).toMatchSnapshot(); +}); + +it('should display correctly for a file', () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + wrapper.setProps({ paging: { total: 100 } }); + expect(wrapper).toMatchSnapshot(); +}); + +it('should not display shortcuts for treemap', () => { + expect( + shallow() + ).toMatchSnapshot(); +}); + +it('should display the total of files', () => { + expect( + shallow( + + ) + ).toMatchSnapshot(); + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.js.snap deleted file mode 100644 index 70583de970f..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.js.snap +++ /dev/null @@ -1,74 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -
- - - - -
-`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.tsx.snap new file mode 100644 index 00000000000..b0436ae2851 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.tsx.snap @@ -0,0 +1,106 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` +
+ + + + +
+`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/FilesCounter-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/FilesCounter-test.js.snap deleted file mode 100644 index bb01a6121da..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/FilesCounter-test.js.snap +++ /dev/null @@ -1,25 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display only total of files 1`] = ` - - - 123,455 - - - component_measures.files - -`; - -exports[`should display x files on y total 1`] = ` - - - - 12 - / - - 123,455 - - - component_measures.files - -`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/FilesCounter-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/FilesCounter-test.tsx.snap new file mode 100644 index 00000000000..bb01a6121da --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/FilesCounter-test.tsx.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should display only total of files 1`] = ` + + + 123,455 + + + component_measures.files + +`; + +exports[`should display x files on y total 1`] = ` + + + + 12 + / + + 123,455 + + + component_measures.files + +`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.js.snap deleted file mode 100644 index 49f756bc4a6..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.js.snap +++ /dev/null @@ -1,268 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display correctly for open file 1`] = ` -
- -
-`; - -exports[`should display correctly for open file 2`] = ` -
- -
-`; - -exports[`should render correctly 1`] = ` -
-
-
- - Reliability Rating - - - - - - - - - - -
-
- -
-
-
-`; - -exports[`should render correctly for leak 1`] = ` -
-
-
- - Reliability Rating on New Code - - - - - -
-
- -
-
-
-`; - -exports[`should render with branch 1`] = ` - - - -`; - -exports[`should work with measure without value 1`] = ` -
-
-
- - Reliability Rating - - - - - - - - - - -
-
- -
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap new file mode 100644 index 00000000000..2ccafb98328 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.tsx.snap @@ -0,0 +1,223 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` +
+
+
+ + Reliability Rating + + + + + + + + + + +
+
+ +
+
+
+`; + +exports[`should render correctly for leak 1`] = ` +
+
+
+ + Reliability Rating on New Code + + + + + +
+
+ +
+
+
+`; + +exports[`should render with branch 1`] = ` + + + +`; + +exports[`should work with measure without value 1`] = ` +
+
+
+ + Reliability Rating + + + + + + + + + + +
+
+ +
+
+
+`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.js.snap deleted file mode 100644 index 9849310b4c2..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.js.snap +++ /dev/null @@ -1,144 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display correctly for a file 1`] = ` -
-
-
-`; - -exports[`should display correctly for a file 2`] = ` -
- - - - j - - - k - - component_measures.to_navigate_files - - -
- -
-
-`; - -exports[`should display correctly for a project 1`] = ` -
- - - - ↑ - - - ↓ - - component_measures.to_select_files - - - - ← - - - → - - component_measures.to_navigate - - -
-
-`; - -exports[`should display the total of files 1`] = ` -
-
- -
-
-`; - -exports[`should display the total of files 2`] = ` -
- - - - j - - - k - - component_measures.to_navigate_files - - -
- -
-
-`; - -exports[`should not display shortcuts for treemap 1`] = ` -
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.tsx.snap new file mode 100644 index 00000000000..9849310b4c2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/PageActions-test.tsx.snap @@ -0,0 +1,144 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should display correctly for a file 1`] = ` +
+
+
+`; + +exports[`should display correctly for a file 2`] = ` +
+ + + + j + + + k + + component_measures.to_navigate_files + + +
+ +
+
+`; + +exports[`should display correctly for a project 1`] = ` +
+ + + + ↑ + + + ↓ + + component_measures.to_select_files + + + + ← + + + → + + component_measures.to_navigate + + +
+
+`; + +exports[`should display the total of files 1`] = ` +
+
+ +
+
+`; + +exports[`should display the total of files 2`] = ` +
+ + + + j + + + k + + component_measures.to_navigate_files + + +
+ +
+
+`; + +exports[`should not display shortcuts for treemap 1`] = ` +
+
+
+`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/config/bubbles.ts b/server/sonar-web/src/main/js/apps/component-measures/config/bubbles.ts index 99c1b0e8e8c..0b432457a90 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/config/bubbles.ts +++ b/server/sonar-web/src/main/js/apps/component-measures/config/bubbles.ts @@ -23,7 +23,7 @@ export const bubbles: { y: string; size: string; colors?: string[]; - yDomain?: number[]; + yDomain?: [number, number]; }; } = { Reliability: { diff --git a/server/sonar-web/src/main/js/apps/component-measures/config/domains.ts b/server/sonar-web/src/main/js/apps/component-measures/config/domains.ts index d7022b680b4..fe45dd98450 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/config/domains.ts +++ b/server/sonar-web/src/main/js/apps/component-measures/config/domains.ts @@ -17,7 +17,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -export const domains: { [domain: string]: { categories?: string[]; order: string[] } } = { + +interface Domains { + [domain: string]: { categories?: string[]; order: string[] }; +} + +export const domains: Domains = { Reliability: { categories: ['new_code_category', 'overall_category'], order: [ diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js deleted file mode 100644 index 7a6fe3264ed..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js +++ /dev/null @@ -1,223 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import EmptyResult from './EmptyResult'; -import OriginalBubbleChart from '../../../components/charts/BubbleChart'; -import ColorRatingsLegend from '../../../components/charts/ColorRatingsLegend'; -import HelpTooltip from '../../../components/controls/HelpTooltip'; -import { formatMeasure, isDiffMetric } from '../../../helpers/measures'; -import { - getLocalizedMetricDomain, - getLocalizedMetricName, - translate, - translateWithParameters -} from '../../../helpers/l10n'; -import { getBubbleMetrics, getBubbleYDomain, isProjectOverview } from '../utils'; -import { RATING_COLORS } from '../../../helpers/constants'; -/*:: import type { Component, ComponentEnhanced } from '../types'; */ -/*:: import type { Metric } from '../../../app/flow-types'; */ - -const HEIGHT = 500; - -/*:: type Props = {| - component: Component, - components: Array, - domain: string, - metrics: { [string]: Metric }, - updateSelected: string => void -|}; */ - -export default class BubbleChart extends React.PureComponent { - /*:: props: Props; */ - - getMeasureVal = (component /*: ComponentEnhanced */, metric /*: Metric */) => { - const measure = component.measures.find(measure => measure.metric.key === metric.key); - if (measure) { - return Number(isDiffMetric(metric.key) ? measure.leak : measure.value); - } - }; - - getTooltip( - componentName /*: string */, - values /*: { - x: number, - y: number, - size: number, - colors: ?Array - }*/, - metrics /*: { - x: Metric , - y: Metric , - size: Metric , - colors: ?Array - }*/ - ) { - const inner = [ - componentName, - `${metrics.x.name}: ${formatMeasure(values.x, metrics.x.type)}`, - `${metrics.y.name}: ${formatMeasure(values.y, metrics.y.type)}`, - `${metrics.size.name}: ${formatMeasure(values.size, metrics.size.type)}` - ]; - if (values.colors && metrics.colors) { - metrics.colors.forEach((metric, idx) => { - // $FlowFixMe colors is always defined at this point - const colorValue = values.colors[idx]; - if (colorValue || colorValue === 0) { - inner.push(`${metric.name}: ${formatMeasure(colorValue, metric.type)}`); - } - }); - } - return ( -
- {inner.map((line, index) => ( - - {line} - {index < inner.length - 1 &&
} -
- ))} -
- ); - } - - handleBubbleClick = (component /*: ComponentEnhanced */) => - this.props.updateSelected(component.refKey || component.key); - - getDescription(domain /*: string */) { - const description = `component_measures.overview.${domain}.description`; - const translatedDescription = translate(description); - if (description === translatedDescription) { - return null; - } - return translatedDescription; - } - - renderBubbleChart( - metrics /*: { - x: Metric , - y: Metric , - size: Metric , - colors: ?Array - }*/ - ) { - const items = this.props.components - .map(component => { - const x = this.getMeasureVal(component, metrics.x); - const y = this.getMeasureVal(component, metrics.y); - const size = this.getMeasureVal(component, metrics.size); - const colors = - metrics.colors && metrics.colors.map(metric => this.getMeasureVal(component, metric)); - if ((!x && x !== 0) || (!y && y !== 0) || (!size && size !== 0)) { - return null; - } - return { - x, - y, - size, - color: - colors != null ? RATING_COLORS[Math.max(...colors.filter(Boolean)) - 1] : undefined, - link: component, - tooltip: this.getTooltip(component.name, { x, y, size, colors }, metrics) - }; - }) - .filter(Boolean); - - const formatXTick = tick => formatMeasure(tick, metrics.x.type); - const formatYTick = tick => formatMeasure(tick, metrics.y.type); - - return ( - - ); - } - - renderChartHeader( - domain /*: string */, - sizeMetric /*: Metric */, - colorsMetric /*: ?Array */ - ) { - const title = isProjectOverview(domain) - ? translate('component_measures.overview', domain, 'title') - : translateWithParameters( - 'component_measures.domain_x_overview', - getLocalizedMetricDomain(domain) - ); - return ( -
- - {title} - - - - - {colorsMetric && ( - - {translateWithParameters( - 'component_measures.legend.color_x', - colorsMetric.length > 1 - ? translateWithParameters( - 'component_measures.legend.worse_of_x_y', - ...colorsMetric.map(metric => getLocalizedMetricName(metric)) - ) - : getLocalizedMetricName(colorsMetric[0]) - )} - - )} - {translateWithParameters( - 'component_measures.legend.size_x', - getLocalizedMetricName(sizeMetric) - )} - - {colorsMetric && } - -
- ); - } - - render() { - if (this.props.components.length <= 0) { - return ; - } - const { domain } = this.props; - const metrics = getBubbleMetrics(domain, this.props.metrics); - - return ( -
- {this.renderChartHeader(domain, metrics.size, metrics.colors)} -
- {this.renderBubbleChart(metrics)} -
-
- {getLocalizedMetricName(metrics.x)} -
-
- {getLocalizedMetricName(metrics.y)} -
-
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.tsx new file mode 100644 index 00000000000..0c07b5a249f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.tsx @@ -0,0 +1,202 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 EmptyResult from './EmptyResult'; +import OriginalBubbleChart, { BubbleItem } from '../../../components/charts/BubbleChart'; +import ColorRatingsLegend from '../../../components/charts/ColorRatingsLegend'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; +import { formatMeasure, isDiffMetric } from '../../../helpers/measures'; +import { + getLocalizedMetricDomain, + getLocalizedMetricName, + translate, + translateWithParameters +} from '../../../helpers/l10n'; +import { getBubbleMetrics, getBubbleYDomain, isProjectOverview } from '../utils'; +import { RATING_COLORS } from '../../../helpers/constants'; +import { ComponentMeasure, ComponentMeasureEnhanced, Metric } from '../../../app/types'; + +const HEIGHT = 500; + +interface Props { + component: ComponentMeasure; + components: ComponentMeasureEnhanced[]; + domain: string; + metrics: { [metric: string]: Metric }; + updateSelected: (component: string) => void; +} + +export default class BubbleChart extends React.PureComponent { + getMeasureVal = (component: ComponentMeasureEnhanced, metric: Metric) => { + const measure = component.measures.find(measure => measure.metric.key === metric.key); + if (!measure) { + return undefined; + } + return Number(isDiffMetric(metric.key) ? measure.leak : measure.value); + }; + + getTooltip( + componentName: string, + values: { x: number; y: number; size: number; colors?: Array }, + metrics: { x: Metric; y: Metric; size: Metric; colors?: Array } + ) { + const inner = [ + componentName, + `${metrics.x.name}: ${formatMeasure(values.x, metrics.x.type)}`, + `${metrics.y.name}: ${formatMeasure(values.y, metrics.y.type)}`, + `${metrics.size.name}: ${formatMeasure(values.size, metrics.size.type)}` + ]; + const { colors: valuesColors } = values; + const { colors: metricColors } = metrics; + if (valuesColors && metricColors) { + metricColors.forEach((metric, idx) => { + const colorValue = valuesColors[idx]; + if (colorValue || colorValue === 0) { + inner.push(`${metric.name}: ${formatMeasure(colorValue, metric.type)}`); + } + }); + } + return ( +
+ {inner.map((line, index) => ( + + {line} + {index < inner.length - 1 &&
} +
+ ))} +
+ ); + } + + handleBubbleClick = (component: ComponentMeasureEnhanced) => + this.props.updateSelected(component.refKey || component.key); + + getDescription(domain: string) { + const description = `component_measures.overview.${domain}.description`; + const translatedDescription = translate(description); + if (description === translatedDescription) { + return null; + } + return translatedDescription; + } + + renderBubbleChart(metrics: { x: Metric; y: Metric; size: Metric; colors?: Metric[] }) { + const items = this.props.components + .map(component => { + const x = this.getMeasureVal(component, metrics.x); + const y = this.getMeasureVal(component, metrics.y); + const size = this.getMeasureVal(component, metrics.size); + const colors = + metrics.colors && metrics.colors.map(metric => this.getMeasureVal(component, metric)); + if ((!x && x !== 0) || (!y && y !== 0) || (!size && size !== 0)) { + return undefined; + } + return { + x, + y, + size, + color: + colors !== undefined + ? RATING_COLORS[Math.max(...colors.filter(Boolean) as number[]) - 1] + : undefined, + data: component, + tooltip: this.getTooltip(component.name, { x, y, size, colors }, metrics) + }; + }) + .filter(Boolean) as BubbleItem[]; + + const formatXTick = (tick: string | number | undefined) => formatMeasure(tick, metrics.x.type); + const formatYTick = (tick: string | number | undefined) => formatMeasure(tick, metrics.y.type); + + return ( + + formatXTick={formatXTick} + formatYTick={formatYTick} + height={HEIGHT} + items={items} + onBubbleClick={this.handleBubbleClick} + padding={[25, 60, 50, 60]} + yDomain={getBubbleYDomain(this.props.domain)} + /> + ); + } + + renderChartHeader(domain: string, sizeMetric: Metric, colorsMetric?: Metric[]) { + const title = isProjectOverview(domain) + ? translate('component_measures.overview', domain, 'title') + : translateWithParameters( + 'component_measures.domain_x_overview', + getLocalizedMetricDomain(domain) + ); + return ( +
+ + {title} + + + + + {colorsMetric && ( + + {translateWithParameters( + 'component_measures.legend.color_x', + colorsMetric.length > 1 + ? translateWithParameters( + 'component_measures.legend.worse_of_x_y', + ...colorsMetric.map(metric => getLocalizedMetricName(metric)) + ) + : getLocalizedMetricName(colorsMetric[0]) + )} + + )} + {translateWithParameters( + 'component_measures.legend.size_x', + getLocalizedMetricName(sizeMetric) + )} + + {colorsMetric && } + +
+ ); + } + + render() { + if (this.props.components.length <= 0) { + return ; + } + const { domain } = this.props; + const metrics = getBubbleMetrics(domain, this.props.metrics); + + return ( +
+ {this.renderChartHeader(domain, metrics.size, metrics.colors)} +
+ {this.renderBubbleChart(metrics)} +
+
+ {getLocalizedMetricName(metrics.x)} +
+
+ {getLocalizedMetricName(metrics.y)} +
+
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/CodeView.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/CodeView.tsx index 6f74390695b..a07eb4710c2 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/CodeView.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/CodeView.tsx @@ -20,8 +20,13 @@ import * as React from 'react'; import * as key from 'keymaster'; import SourceViewer from '../../../components/SourceViewer/SourceViewer'; -import { BranchLike, ComponentMeasure, ComponentMeasureEnhanced, Metric } from '../../../app/types'; -import { Period } from '../../../helpers/periods'; +import { + BranchLike, + ComponentMeasure, + ComponentMeasureEnhanced, + Metric, + Period +} from '../../../app/types'; interface Props { branchLike?: BranchLike; diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.js deleted file mode 100644 index 6ec4749855e..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.js +++ /dev/null @@ -1,133 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import { Link } from 'react-router'; -import LinkIcon from '../../../components/icons-components/LinkIcon'; -import QualifierIcon from '../../../components/icons-components/QualifierIcon'; -import LongLivingBranchIcon from '../../../components/icons-components/LongLivingBranchIcon'; -import { splitPath } from '../../../helpers/path'; -import { - getPathUrlAsString, - getBranchLikeUrl, - getLongLivingBranchUrl, - getComponentDrilldownUrlWithSelection -} from '../../../helpers/urls'; -import { translate } from '../../../helpers/l10n'; -/*:: import type { Component, ComponentEnhanced } from '../types'; */ -/*:: import type { Metric } from '../../../app/flow-types'; */ - -/*:: type Props = { - branchLike?: { id?: string; name: string }, - component: ComponentEnhanced, - onClick: string => void, - metric: Metric, - rootComponent: Component -}; */ - -export default class ComponentCell extends React.PureComponent { - /*:: props: Props; */ - - handleClick = (e /*: MouseEvent */) => { - const isLeftClickEvent = e.button === 0; - const isModifiedEvent = !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey); - - if (isLeftClickEvent && !isModifiedEvent) { - e.preventDefault(); - this.props.onClick(this.props.component.key); - } - }; - - renderInner() { - const { component } = this.props; - let head = ''; - let tail = component.name; - let branch = null; - - if (['DIR', 'FIL', 'UTS'].includes(component.qualifier)) { - const parts = splitPath(component.path); - ({ head, tail } = parts); - } - - if (this.props.rootComponent.qualifier === 'APP') { - branch = ( - - {component.branch ? ( - - - {component.branch} - - ) : ( - {translate('branches.main_branch')} - )} - - ); - } - return ( - - -   - {head.length > 0 && {head}/} - {tail} - {branch} - - ); - } - - render() { - const { branchLike, component, metric, rootComponent } = this.props; - const to = - this.props.rootComponent.qualifier === 'APP' - ? getLongLivingBranchUrl(component.refKey, component.branch) - : getBranchLikeUrl(component.refKey, branchLike); - return ( - -
- {component.refKey == null ? ( - - {this.renderInner()} - - ) : ( - - - - - {this.renderInner()} - - )} -
- - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.tsx new file mode 100644 index 00000000000..4ddcd665e7b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.tsx @@ -0,0 +1,128 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 LinkIcon from '../../../components/icons-components/LinkIcon'; +import QualifierIcon from '../../../components/icons-components/QualifierIcon'; +import LongLivingBranchIcon from '../../../components/icons-components/LongLivingBranchIcon'; +import { splitPath } from '../../../helpers/path'; +import { + getPathUrlAsString, + getBranchLikeUrl, + getComponentDrilldownUrlWithSelection, + getProjectUrl +} from '../../../helpers/urls'; +import { translate } from '../../../helpers/l10n'; +import { BranchLike, ComponentMeasure, ComponentMeasureEnhanced, Metric } from '../../../app/types'; + +interface Props { + branchLike?: BranchLike; + component: ComponentMeasureEnhanced; + onClick: (component: string) => void; + metric: Metric; + rootComponent: ComponentMeasure; +} + +export default class ComponentCell extends React.PureComponent { + handleClick = (event: React.MouseEvent) => { + const isLeftClickEvent = event.button === 0; + const isModifiedEvent = !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); + + if (isLeftClickEvent && !isModifiedEvent) { + event.preventDefault(); + this.props.onClick(this.props.component.key); + } + }; + + renderInner(componentKey: string) { + const { component } = this.props; + let head = ''; + let tail = component.name; + let branchComponent = null; + + if (['DIR', 'FIL', 'UTS'].includes(component.qualifier) && component.path) { + ({ head, tail } = splitPath(component.path)); + } + + if (this.props.rootComponent.qualifier === 'APP') { + branchComponent = ( + <> + {component.branch ? ( + <> + + {component.branch} + + ) : ( + {translate('branches.main_branch')} + )} + + ); + } + return ( + + +   + {head.length > 0 && {head}/} + {tail} + {branchComponent} + + ); + } + + render() { + const { branchLike, component, metric, rootComponent } = this.props; + return ( + +
+ {!component.refKey ? ( + + {this.renderInner(component.key)} + + ) : ( + + + + + {this.renderInner(component.refKey)} + + )} +
+ + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js deleted file mode 100644 index 49024fe6f07..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import classNames from 'classnames'; -import ComponentCell from './ComponentCell'; -import MeasureCell from './MeasureCell'; -/*:: import type { Component, ComponentEnhanced } from '../types'; */ -/*:: import type { Metric } from '../../../app/flow-types'; */ - -/*:: type Props = {| - branchLike?: { id?: string; name: string }, - component: ComponentEnhanced, - isSelected: boolean, - onClick: string => void, - otherMetrics: Array, - metric: Metric, - rootComponent: Component -|}; */ - -export default function ComponentsListRow(props /*: Props */) { - const { branchLike, component, rootComponent } = props; - const otherMeasures = props.otherMetrics.map(metric => { - const measure = component.measures.find(measure => measure.metric.key === metric.key); - return { ...measure, metric }; - }); - const rowClass = classNames('measure-details-component-row', { - selected: props.isSelected - }); - return ( - - - - - - {otherMeasures.map(measure => ( - - ))} - - ); -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.tsx new file mode 100644 index 00000000000..6ae4c80b619 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.tsx @@ -0,0 +1,67 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 * as classNames from 'classnames'; +import ComponentCell from './ComponentCell'; +import MeasureCell from './MeasureCell'; +import { ComponentMeasure, Metric, ComponentMeasureEnhanced, BranchLike } from '../../../app/types'; + +interface Props { + branchLike?: BranchLike; + component: ComponentMeasureEnhanced; + isSelected: boolean; + onClick: (component: string) => void; + otherMetrics: Metric[]; + metric: Metric; + rootComponent: ComponentMeasure; +} + +export default function ComponentsListRow(props: Props) { + const { branchLike, component, rootComponent } = props; + const otherMeasures = props.otherMetrics.map(metric => { + const measure = component.measures.find(measure => measure.metric.key === metric.key); + return { ...measure, metric }; + }); + const rowClass = classNames('measure-details-component-row', { + selected: props.isSelected + }); + return ( + + + + + + {otherMeasures.map(measure => ( + + ))} + + ); +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js deleted file mode 100644 index 8a984c5001f..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import Measure from '../../../components/measure/Measure'; -import { isDiffMetric } from '../../../helpers/measures'; -/*:: import type { ComponentEnhanced } from '../types'; */ -/*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */ -/*:: import type { Metric } from '../../../app/flow-types'; */ - -/*:: type Props = { - component: ComponentEnhanced, - measure?: MeasureEnhanced, - metric: Metric -}; */ - -export default function MeasureCell({ component, measure, metric } /*: Props */) { - const getValue = (item /*: { leak?: ?string; value?: string } */) => - isDiffMetric(metric.key) ? item.leak : item.value; - - const value = getValue(measure || component); - - return ( - - - - - - ); -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.tsx new file mode 100644 index 00000000000..951bb590f62 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.tsx @@ -0,0 +1,44 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 Measure from '../../../components/measure/Measure'; +import { isDiffMetric } from '../../../helpers/measures'; +import { Metric, MeasureEnhanced, ComponentMeasureEnhanced } from '../../../app/types'; + +interface Props { + component: ComponentMeasureEnhanced; + measure?: MeasureEnhanced; + metric: Metric; +} + +export default function MeasureCell({ component, measure, metric }: Props) { + const getValue = (item: { leak?: string; value?: string }) => + isDiffMetric(metric.key) ? item.leak : item.value; + + const value = getValue(measure || component); + + return ( + + + + + + ); +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/MeasureCell-test.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/MeasureCell-test.js deleted file mode 100644 index 6897ed8a623..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/MeasureCell-test.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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 React from 'react'; -import { shallow } from 'enzyme'; -import MeasureCell from '../MeasureCell'; - -describe('should correctly take the value', () => { - const renderAndTakeValue = props => - shallow() - .find('Measure') - .prop('value'); - - it('absolute value', () => { - const component = { value: '123' }; - const metric = { key: 'coverage' }; - const measure = { value: '567' }; - - expect(renderAndTakeValue({ component, metric })).toEqual('123'); - expect(renderAndTakeValue({ component, metric, measure })).toEqual('567'); - }); - - it('leak value', () => { - const component = { leak: '234' }; - const metric = { key: 'new_coverage' }; - const measure = { leak: '678' }; - - expect(renderAndTakeValue({ component, metric })).toEqual('234'); - expect(renderAndTakeValue({ component, metric, measure })).toEqual('678'); - }); -}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/MeasureCell-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/MeasureCell-test.tsx new file mode 100644 index 00000000000..cd0772fd03b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/__tests__/MeasureCell-test.tsx @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { shallow } from 'enzyme'; +import MeasureCell from '../MeasureCell'; + +describe('should correctly take the value', () => { + const renderAndTakeValue = (props: any) => + shallow() + .find('Measure') + .prop('value'); + + it('absolute value', () => { + const component = { value: '123' }; + const metric = { id: '1', key: 'coverage' }; + const measure = { value: '567' }; + + expect(renderAndTakeValue({ component, metric })).toEqual('123'); + expect(renderAndTakeValue({ component, metric, measure })).toEqual('567'); + }); + + it('leak value', () => { + const component = { leak: '234' }; + const metric = { id: '1', key: 'new_coverage' }; + const measure = { leak: '678' }; + + expect(renderAndTakeValue({ component, metric })).toEqual('234'); + expect(renderAndTakeValue({ component, metric, measure })).toEqual('678'); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.js deleted file mode 100644 index 47338d7ac0d..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.js +++ /dev/null @@ -1,164 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import FacetMeasureValue from './FacetMeasureValue'; -import BubblesIcon from '../../../components/icons-components/BubblesIcon'; -import FacetBox from '../../../components/facet/FacetBox'; -import FacetHeader from '../../../components/facet/FacetHeader'; -import FacetItem from '../../../components/facet/FacetItem'; -import FacetItemsList from '../../../components/facet/FacetItemsList'; -import { - addMeasureCategories, - filterMeasures, - hasBubbleChart, - hasFacetStat, - sortMeasures -} from '../utils'; -import { - getLocalizedCategoryMetricName, - getLocalizedMetricDomain, - getLocalizedMetricName, - translate -} from '../../../helpers/l10n'; -/*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */ - -/*:: type Props = {| - onChange: (metric: string) => void, - onToggle: (property: string) => void, - open: boolean, - domain: { name: string, measures: Array }, - selected: string -|}; */ - -export default class DomainFacet extends React.PureComponent { - /*:: props: Props; */ - - handleHeaderClick = () => this.props.onToggle(this.props.domain.name); - - hasFacetSelected = ( - domain /*: { name: string } */, - measures /*: Array */, - selected /*: string */ - ) => { - const measureSelected = measures.find(measure => measure.metric.key === selected); - const overviewSelected = domain.name === selected && hasBubbleChart(domain.name); - return measureSelected || overviewSelected; - }; - - getValues = () => { - const { domain, selected } = this.props; - const measureSelected = domain.measures.find(measure => measure.metric.key === selected); - const overviewSelected = domain.name === selected && hasBubbleChart(domain.name); - if (measureSelected) { - return [getLocalizedMetricName(measureSelected.metric)]; - } - return overviewSelected ? [translate('component_measures.domain_overview')] : []; - }; - - renderItemFacetStat = (item /*: MeasureEnhanced */) => - hasFacetStat(item.metric.key) ? : null; - - renderItemsFacet = () => { - const { domain, selected } = this.props; - const items = addMeasureCategories(domain.name, filterMeasures(domain.measures)); - const hasCategories = items.some(item => typeof item === 'string'); - const translateMetric = hasCategories ? getLocalizedCategoryMetricName : getLocalizedMetricName; - let sortedItems = sortMeasures(domain.name, items); - - sortedItems = sortedItems.filter((item, index) => { - return ( - typeof item !== 'string' || - (index + 1 !== sortedItems.length && typeof sortedItems[index + 1] !== 'string') - ); - }); - - return sortedItems.map( - item => - typeof item === 'string' ? ( - - - {translate('component_measures.facet_category', item)} - - - ) : ( - - {translateMetric(item.metric)} - - } - onClick={this.props.onChange} - stat={this.renderItemFacetStat(item)} - value={item.metric.key} - /> - ) - ); - }; - - renderOverviewFacet = () => { - const { domain, selected } = this.props; - if (!hasBubbleChart(domain.name)) { - return null; - } - return ( - - {translate('component_measures.domain_overview')} - - } - onClick={this.props.onChange} - stat={} - value={domain.name} - /> - ); - }; - - render() { - const { domain } = this.props; - const helper = `component_measures.domain_facets.${domain.name}.help`; - const translatedHelper = translate(helper); - return ( - - - - {this.props.open && ( - - {this.renderOverviewFacet()} - {this.renderItemsFacet()} - - )} - - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.tsx new file mode 100644 index 00000000000..3257089235c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainFacet.tsx @@ -0,0 +1,162 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 FacetMeasureValue from './FacetMeasureValue'; +import BubblesIcon from '../../../components/icons-components/BubblesIcon'; +import FacetBox from '../../../components/facet/FacetBox'; +import FacetHeader from '../../../components/facet/FacetHeader'; +import FacetItem from '../../../components/facet/FacetItem'; +import FacetItemsList from '../../../components/facet/FacetItemsList'; +import { + addMeasureCategories, + filterMeasures, + hasBubbleChart, + hasFacetStat, + sortMeasures +} from '../utils'; +import { + getLocalizedCategoryMetricName, + getLocalizedMetricDomain, + getLocalizedMetricName, + translate +} from '../../../helpers/l10n'; +import { MeasureEnhanced } from '../../../app/types'; + +interface Props { + domain: { name: string; measures: MeasureEnhanced[] }; + onChange: (metric: string) => void; + onToggle: (property: string) => void; + open: boolean; + selected: string; +} + +export default class DomainFacet extends React.PureComponent { + handleHeaderClick = () => { + this.props.onToggle(this.props.domain.name); + }; + + hasFacetSelected = (domain: { name: string }, measures: MeasureEnhanced[], selected: string) => { + const measureSelected = measures.find(measure => measure.metric.key === selected); + const overviewSelected = domain.name === selected && hasBubbleChart(domain.name); + return measureSelected || overviewSelected; + }; + + getValues = () => { + const { domain, selected } = this.props; + const measureSelected = domain.measures.find(measure => measure.metric.key === selected); + const overviewSelected = domain.name === selected && hasBubbleChart(domain.name); + if (measureSelected) { + return [getLocalizedMetricName(measureSelected.metric)]; + } + return overviewSelected ? [translate('component_measures.domain_overview')] : []; + }; + + renderItemFacetStat = (item: MeasureEnhanced) => { + return hasFacetStat(item.metric.key) ? : null; + }; + + renderItemsFacet = () => { + const { domain, selected } = this.props; + const items = addMeasureCategories(domain.name, filterMeasures(domain.measures)); + const hasCategories = items.some(item => typeof item === 'string'); + const translateMetric = hasCategories ? getLocalizedCategoryMetricName : getLocalizedMetricName; + let sortedItems = sortMeasures(domain.name, items); + + sortedItems = sortedItems.filter((item, index) => { + return ( + typeof item !== 'string' || + (index + 1 !== sortedItems.length && typeof sortedItems[index + 1] !== 'string') + ); + }); + + return sortedItems.map( + item => + typeof item === 'string' ? ( + + + {translate('component_measures.facet_category', item)} + + + ) : ( + + {translateMetric(item.metric)} + + } + onClick={this.props.onChange} + stat={this.renderItemFacetStat(item)} + tooltip={translateMetric(item.metric)} + value={item.metric.key} + /> + ) + ); + }; + + renderOverviewFacet = () => { + const { domain, selected } = this.props; + if (!hasBubbleChart(domain.name)) { + return null; + } + return ( + + {translate('component_measures.domain_overview')} + + } + onClick={this.props.onChange} + stat={} + tooltip={translate('component_measures.domain_overview')} + value={domain.name} + /> + ); + }; + + render() { + const { domain } = this.props; + const helper = `component_measures.domain_facets.${domain.name}.help`; + const translatedHelper = translate(helper); + return ( + + + + {this.props.open && ( + + {this.renderOverviewFacet()} + {this.renderItemsFacet()} + + )} + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.js deleted file mode 100644 index 70953357687..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import Measure from '../../../components/measure/Measure'; -import { isDiffMetric } from '../../../helpers/measures'; -/*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */ - -export default function FacetMeasureValue({ measure } /*: { measure: MeasureEnhanced } */) { - if (isDiffMetric(measure.metric.key)) { - return ( -
- -
- ); - } - - return ( -
- -
- ); -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.tsx new file mode 100644 index 00000000000..1829547f860 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.tsx @@ -0,0 +1,53 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 Measure from '../../../components/measure/Measure'; +import { isDiffMetric } from '../../../helpers/measures'; +import { MeasureEnhanced } from '../../../app/types'; + +interface Props { + measure: MeasureEnhanced; +} + +export default function FacetMeasureValue({ measure }: Props) { + if (isDiffMetric(measure.metric.key)) { + return ( +
+ +
+ ); + } + + return ( +
+ +
+ ); +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/ProjectOverviewFacet.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/ProjectOverviewFacet.js deleted file mode 100644 index c0877081176..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/ProjectOverviewFacet.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import FacetBox from '../../../components/facet/FacetBox'; -import FacetItem from '../../../components/facet/FacetItem'; -import FacetItemsList from '../../../components/facet/FacetItemsList'; -import { translate } from '../../../helpers/l10n'; - -/*:: type Props = {| - onChange: (metric: string) => void, - selected: string, - value: string -|}; */ - -export default function ProjectOverviewFacet({ value, selected, onChange } /*: Props */) { - const facetName = translate('component_measures.overview', value, 'facet'); - return ( - - - - {facetName} - - } - onClick={onChange} - value={value} - /> - - - ); -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/ProjectOverviewFacet.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/ProjectOverviewFacet.tsx new file mode 100644 index 00000000000..a91c6583bd2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/ProjectOverviewFacet.tsx @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 FacetBox from '../../../components/facet/FacetBox'; +import FacetItem from '../../../components/facet/FacetItem'; +import FacetItemsList from '../../../components/facet/FacetItemsList'; +import { translate } from '../../../helpers/l10n'; + +interface Props { + onChange: (metric: string) => void; + selected: string; + value: string; +} + +export default function ProjectOverviewFacet({ value, selected, onChange }: Props) { + const facetName = translate('component_measures.overview', value, 'facet'); + return ( + + + {facetName}} + onClick={onChange} + tooltip={facetName} + value={value} + /> + + + ); +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js deleted file mode 100644 index 183875dc425..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import ProjectOverviewFacet from './ProjectOverviewFacet'; -import DomainFacet from './DomainFacet'; -import { getDefaultView, groupByDomains, KNOWN_DOMAINS, PROJECT_OVERVEW } from '../utils'; -/*:: import type { MeasureEnhanced } from '../../../components/measure/types'; */ -/*:: import type { Query } from '../types'; */ - -/*:: type Props = {| - measures: Array, - selectedMetric: string, - updateQuery: Query => void -|}; */ - -/*:: type State = {| - openFacets: { [string]: boolean } -|}; */ - -export default class Sidebar extends React.PureComponent { - /*:: props: Props; */ - /*:: state: State; */ - - constructor(props /*: Props */) { - super(props); - this.state = { openFacets: this.getOpenFacets({}, props) }; - } - - componentWillReceiveProps(nextProps /*: Props */) { - if (nextProps.selectedMetric !== this.props.selectedMetric) { - this.setState(state => this.getOpenFacets(state.openFacets, nextProps)); - } - } - - getOpenFacets = ( - openFacets /*: { [string]: boolean } */, - { measures, selectedMetric } /*: Props */ - ) => { - const newOpenFacets = { ...openFacets }; - const measure = measures.find(measure => measure.metric.key === selectedMetric); - if (measure && measure.metric && measure.metric.domain) { - newOpenFacets[measure.metric.domain] = true; - } else if (KNOWN_DOMAINS.includes(selectedMetric)) { - newOpenFacets[selectedMetric] = true; - } - return newOpenFacets; - }; - - toggleFacet = (name /*: string */) => { - this.setState(({ openFacets } /*: State */) => ({ - openFacets: { ...openFacets, [name]: !openFacets[name] } - })); - }; - - resetSelection = (metric /*: string */) => ({ selected: null, view: getDefaultView(metric) }); - - changeMetric = (metric /*: string */) => - this.props.updateQuery({ metric, ...this.resetSelection(metric) }); - - render() { - return ( -
- - {groupByDomains(this.props.measures).map(domain => ( - - ))} -
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx new file mode 100644 index 00000000000..027d3593f4f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx @@ -0,0 +1,96 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 ProjectOverviewFacet from './ProjectOverviewFacet'; +import DomainFacet from './DomainFacet'; +import { getDefaultView, groupByDomains, KNOWN_DOMAINS, PROJECT_OVERVEW, Query } from '../utils'; +import { MeasureEnhanced } from '../../../app/types'; + +interface Props { + measures: MeasureEnhanced[]; + selectedMetric: string; + updateQuery: (query: Query) => void; +} + +interface State { + openFacets: { [metric: string]: boolean }; +} + +export default class Sidebar extends React.PureComponent { + constructor(props: Props) { + super(props); + this.state = { openFacets: this.getOpenFacets({}, props) }; + } + + componentWillReceiveProps(nextProps: Props) { + if (nextProps.selectedMetric !== this.props.selectedMetric) { + this.setState(({ openFacets }) => ({ + openFacets: this.getOpenFacets(openFacets, nextProps) + })); + } + } + + getOpenFacets = ( + openFacets: { [metric: string]: boolean }, + { measures, selectedMetric }: Props + ) => { + const newOpenFacets = { ...openFacets }; + const measure = measures.find(measure => measure.metric.key === selectedMetric); + if (measure && measure.metric && measure.metric.domain) { + newOpenFacets[measure.metric.domain] = true; + } else if (KNOWN_DOMAINS.includes(selectedMetric)) { + newOpenFacets[selectedMetric] = true; + } + return newOpenFacets; + }; + + toggleFacet = (name: string) => { + this.setState(({ openFacets }) => ({ + openFacets: { ...openFacets, [name]: !openFacets[name] } + })); + }; + + resetSelection = (metric: string) => ({ selected: undefined, view: getDefaultView(metric) }); + + changeMetric = (metric: string) => + this.props.updateQuery({ metric, ...this.resetSelection(metric) }); + + render() { + return ( +
+ + {groupByDomains(this.props.measures).map(domain => ( + + ))} +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.js deleted file mode 100644 index 551d11831e8..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.js +++ /dev/null @@ -1,119 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import { shallow } from 'enzyme'; -import DomainFacet from '../DomainFacet'; - -const DOMAIN = { - name: 'Reliability', - measures: [ - { - metric: { - key: 'bugs', - type: 'INT', - name: 'Bugs', - domain: 'Reliability' - }, - value: '5', - periods: [{ index: 1, value: '5' }], - leak: '5' - }, - { - metric: { - key: 'new_bugs', - type: 'INT', - name: 'New Bugs', - domain: 'Reliability' - }, - periods: [{ index: 1, value: '5' }], - leak: '5' - } - ] -}; - -const PROPS = { - onChange: () => {}, - onToggle: () => {}, - open: true, - domain: DOMAIN, - selected: 'foo' -}; - -it('should display facet item list', () => { - expect(shallow()).toMatchSnapshot(); -}); - -it('should display facet item list with bugs selected', () => { - expect(shallow()).toMatchSnapshot(); -}); - -it('should render closed', () => { - const wrapper = shallow(); - expect(wrapper.find('FacetItemsList')).toHaveLength(0); -}); - -it('should not display subtitles of new measures if there is none', () => { - const domain = { - name: 'Reliability', - measures: [ - { - metric: { key: 'bugs', type: 'INT', name: 'Bugs', domain: 'Reliability' }, - value: '5' - } - ] - }; - - expect( - shallow( - {}} - onToggle={() => {}} - open={true} - selected={'foo'} - /> - ) - ).toMatchSnapshot(); -}); - -it('should not display subtitles of new measures if there is none, even on last line', () => { - const domain = { - name: 'Reliability', - measures: [ - { - metric: { key: 'new_bugs', type: 'INT', name: 'New Bugs', domain: 'Reliability' }, - value: '5' - } - ] - }; - - expect( - shallow( - {}} - onToggle={() => {}} - open={true} - selected={'foo'} - /> - ) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.tsx new file mode 100644 index 00000000000..590536b454c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/DomainFacet-test.tsx @@ -0,0 +1,120 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { shallow } from 'enzyme'; +import DomainFacet from '../DomainFacet'; + +const DOMAIN = { + name: 'Reliability', + measures: [ + { + metric: { + id: '1', + key: 'bugs', + type: 'INT', + name: 'Bugs', + domain: 'Reliability' + }, + value: '5', + periods: [{ index: 1, value: '5' }], + leak: '5' + }, + { + metric: { + id: '2', + key: 'new_bugs', + type: 'INT', + name: 'New Bugs', + domain: 'Reliability' + }, + periods: [{ index: 1, value: '5' }], + leak: '5' + } + ] +}; + +const PROPS = { + onChange: () => {}, + onToggle: () => {}, + open: true, + domain: DOMAIN, + selected: 'foo' +}; + +it('should display facet item list', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('should display facet item list with bugs selected', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('should render closed', () => { + const wrapper = shallow(); + expect(wrapper.find('FacetItemsList')).toHaveLength(0); +}); + +it('should not display subtitles of new measures if there is none', () => { + const domain = { + name: 'Reliability', + measures: [ + { + metric: { id: '1', key: 'bugs', type: 'INT', name: 'Bugs', domain: 'Reliability' }, + value: '5' + } + ] + }; + + expect( + shallow( + {}} + onToggle={() => {}} + open={true} + selected={'foo'} + /> + ) + ).toMatchSnapshot(); +}); + +it('should not display subtitles of new measures if there is none, even on last line', () => { + const domain = { + name: 'Reliability', + measures: [ + { + metric: { id: '2', key: 'new_bugs', type: 'INT', name: 'New Bugs', domain: 'Reliability' }, + value: '5' + } + ] + }; + + expect( + shallow( + {}} + onToggle={() => {}} + open={true} + selected={'foo'} + /> + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/FacetMeasureValue-test.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/FacetMeasureValue-test.js deleted file mode 100644 index 542fc424aa7..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/FacetMeasureValue-test.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import { shallow } from 'enzyme'; -import FacetMeasureValue from '../FacetMeasureValue'; - -const MEASURE = { - metric: { - key: 'bugs', - type: 'INT', - name: 'Bugs', - domain: 'Reliability' - }, - value: '5', - periods: [{ index: 1, value: '5' }], - leak: '5' -}; -const LEAK_MEASURE = { - metric: { - key: 'new_bugs', - type: 'INT', - name: 'New Bugs', - domain: 'Reliability' - }, - periods: [{ index: 1, value: '5' }], - leak: '5' -}; - -it('should display measure value', () => { - expect(shallow()).toMatchSnapshot(); -}); - -it('should display leak measure value', () => { - expect(shallow()).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/FacetMeasureValue-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/FacetMeasureValue-test.tsx new file mode 100644 index 00000000000..971be2bbf3d --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/FacetMeasureValue-test.tsx @@ -0,0 +1,54 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { shallow } from 'enzyme'; +import FacetMeasureValue from '../FacetMeasureValue'; + +const MEASURE = { + metric: { + id: '1', + key: 'bugs', + type: 'INT', + name: 'Bugs', + domain: 'Reliability' + }, + value: '5', + periods: [{ index: 1, value: '5' }], + leak: '5' +}; +const LEAK_MEASURE = { + metric: { + id: '2', + key: 'new_bugs', + type: 'INT', + name: 'New Bugs', + domain: 'Reliability' + }, + periods: [{ index: 1, value: '5' }], + leak: '5' +}; + +it('should display measure value', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('should display leak measure value', () => { + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.js deleted file mode 100644 index e19a46431cf..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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 React from 'react'; -import { shallow } from 'enzyme'; -import Sidebar from '../Sidebar'; - -const MEASURES = [ - { - metric: { - key: 'lines_to_cover', - type: 'INT', - name: 'Lines to Cover', - domain: 'Coverage' - }, - value: '431', - periods: [{ index: 1, value: '70' }], - leak: '70' - }, - { - metric: { - key: 'coverage', - type: 'PERCENT', - name: 'Coverage', - domain: 'Coverage' - }, - value: '99.3', - periods: [{ index: 1, value: '0.0999999999999943' }], - leak: '0.0999999999999943' - }, - { - metric: { - key: 'duplicated_lines_density', - type: 'PERCENT', - name: 'Duplicated Lines (%)', - domain: 'Duplications' - }, - value: '3.2', - periods: [{ index: 1, value: '0.0' }], - leak: '0.0' - } -]; - -const PROPS = { - measures: MEASURES, - selectedMetric: 'duplicated_lines_density', - updateQuery: () => {} -}; - -it('should display two facets', () => { - expect(shallow()).toMatchSnapshot(); -}); - -it('should correctly toggle facets', () => { - const wrapper = shallow(); - expect(wrapper.state('openFacets').bugs).toBeUndefined(); - wrapper.instance().toggleFacet('bugs'); - expect(wrapper.state('openFacets').bugs).toBeTruthy(); - wrapper.instance().toggleFacet('bugs'); - expect(wrapper.state('openFacets').bugs).toBeFalsy(); -}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.tsx new file mode 100644 index 00000000000..9b629994ac3 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/Sidebar-test.tsx @@ -0,0 +1,80 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { shallow } from 'enzyme'; +import Sidebar from '../Sidebar'; + +const MEASURES = [ + { + metric: { + id: '1', + key: 'lines_to_cover', + type: 'INT', + name: 'Lines to Cover', + domain: 'Coverage' + }, + value: '431', + periods: [{ index: 1, value: '70' }], + leak: '70' + }, + { + metric: { + id: '2', + key: 'coverage', + type: 'PERCENT', + name: 'Coverage', + domain: 'Coverage' + }, + value: '99.3', + periods: [{ index: 1, value: '0.0999999999999943' }], + leak: '0.0999999999999943' + }, + { + metric: { + id: '3', + key: 'duplicated_lines_density', + type: 'PERCENT', + name: 'Duplicated Lines (%)', + domain: 'Duplications' + }, + value: '3.2', + periods: [{ index: 1, value: '0.0' }], + leak: '0.0' + } +]; + +const PROPS = { + measures: MEASURES, + selectedMetric: 'duplicated_lines_density', + updateQuery: () => {} +}; + +it('should display two facets', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('should correctly toggle facets', () => { + const wrapper = shallow(); + expect(wrapper.state('openFacets').bugs).toBeUndefined(); + (wrapper.instance() as Sidebar).toggleFacet('bugs'); + expect(wrapper.state('openFacets').bugs).toBeTruthy(); + (wrapper.instance() as Sidebar).toggleFacet('bugs'); + expect(wrapper.state('openFacets').bugs).toBeFalsy(); +}); diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.js.snap deleted file mode 100644 index 64c9678aaef..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.js.snap +++ /dev/null @@ -1,427 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display facet item list 1`] = ` - - - - - component_measures.domain_overview - - } - onClick={[Function]} - stat={ - - } - value="Reliability" - /> - - - component_measures.facet_category.new_code_category - - - - New Bugs - - } - onClick={[Function]} - stat={ - - } - value="new_bugs" - /> - - - component_measures.facet_category.overall_category - - - - Bugs - - } - onClick={[Function]} - stat={ - - } - value="bugs" - /> - - -`; - -exports[`should display facet item list with bugs selected 1`] = ` - - - - - component_measures.domain_overview - - } - onClick={[Function]} - stat={ - - } - value="Reliability" - /> - - - component_measures.facet_category.new_code_category - - - - New Bugs - - } - onClick={[Function]} - stat={ - - } - value="new_bugs" - /> - - - component_measures.facet_category.overall_category - - - - Bugs - - } - onClick={[Function]} - stat={ - - } - value="bugs" - /> - - -`; - -exports[`should not display subtitles of new measures if there is none 1`] = ` - - - - - component_measures.domain_overview - - } - onClick={[Function]} - stat={ - - } - value="Reliability" - /> - - - component_measures.facet_category.overall_category - - - - Bugs - - } - onClick={[Function]} - stat={ - - } - value="bugs" - /> - - -`; - -exports[`should not display subtitles of new measures if there is none, even on last line 1`] = ` - - - - - component_measures.domain_overview - - } - onClick={[Function]} - stat={ - - } - value="Reliability" - /> - - - component_measures.facet_category.new_code_category - - - - New Bugs - - } - onClick={[Function]} - stat={ - - } - value="new_bugs" - /> - - -`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.tsx.snap new file mode 100644 index 00000000000..0a4c85967f1 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/DomainFacet-test.tsx.snap @@ -0,0 +1,443 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should display facet item list 1`] = ` + + + + + component_measures.domain_overview + + } + onClick={[Function]} + stat={ + + } + tooltip="component_measures.domain_overview" + value="Reliability" + /> + + + component_measures.facet_category.new_code_category + + + + New Bugs + + } + onClick={[Function]} + stat={ + + } + tooltip="New Bugs" + value="new_bugs" + /> + + + component_measures.facet_category.overall_category + + + + Bugs + + } + onClick={[Function]} + stat={ + + } + tooltip="Bugs" + value="bugs" + /> + + +`; + +exports[`should display facet item list with bugs selected 1`] = ` + + + + + component_measures.domain_overview + + } + onClick={[Function]} + stat={ + + } + tooltip="component_measures.domain_overview" + value="Reliability" + /> + + + component_measures.facet_category.new_code_category + + + + New Bugs + + } + onClick={[Function]} + stat={ + + } + tooltip="New Bugs" + value="new_bugs" + /> + + + component_measures.facet_category.overall_category + + + + Bugs + + } + onClick={[Function]} + stat={ + + } + tooltip="Bugs" + value="bugs" + /> + + +`; + +exports[`should not display subtitles of new measures if there is none 1`] = ` + + + + + component_measures.domain_overview + + } + onClick={[Function]} + stat={ + + } + tooltip="component_measures.domain_overview" + value="Reliability" + /> + + + component_measures.facet_category.overall_category + + + + Bugs + + } + onClick={[Function]} + stat={ + + } + tooltip="Bugs" + value="bugs" + /> + + +`; + +exports[`should not display subtitles of new measures if there is none, even on last line 1`] = ` + + + + + component_measures.domain_overview + + } + onClick={[Function]} + stat={ + + } + tooltip="component_measures.domain_overview" + value="Reliability" + /> + + + component_measures.facet_category.new_code_category + + + + New Bugs + + } + onClick={[Function]} + stat={ + + } + tooltip="New Bugs" + value="new_bugs" + /> + + +`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.js.snap deleted file mode 100644 index 228f8a3e6d9..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.js.snap +++ /dev/null @@ -1,27 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display leak measure value 1`] = ` -
- -
-`; - -exports[`should display measure value 1`] = ` -
- -
-`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.tsx.snap new file mode 100644 index 00000000000..228f8a3e6d9 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.tsx.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should display leak measure value 1`] = ` +
+ +
+`; + +exports[`should display measure value 1`] = ` +
+ +
+`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.js.snap deleted file mode 100644 index f526bbb3a16..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.js.snap +++ /dev/null @@ -1,87 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display two facets 1`] = ` -
- - - -
-`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap new file mode 100644 index 00000000000..09f7788831c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.tsx.snap @@ -0,0 +1,90 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should display two facets 1`] = ` +
+ + + +
+`; diff --git a/server/sonar-web/src/main/js/apps/component-measures/types.js b/server/sonar-web/src/main/js/apps/component-measures/types.js deleted file mode 100644 index 4ce7d76cf75..00000000000 --- a/server/sonar-web/src/main/js/apps/component-measures/types.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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 type { Measure, MeasureEnhanced } from '../../components/measure/types'; */ - -/*:: type ComponentIntern = { - isFavorite?: boolean, - isRecentlyBrowsed?: boolean, - key: string, - match?: string, - name: string, - organization?: string, - project?: string, - qualifier: string -}; */ - -/*:: export type Component = ComponentIntern & { measures?: Array }; */ - -/*:: export type ComponentEnhanced = ComponentIntern & { - value?: ?string, - leak?: ?string, - measures: Array -}; */ - -/*:: export type Paging = { - pageIndex: number, - pageSize: number, - total: number -}; */ - -/*:: export type Period = { - index: number, - date: string, - mode: string, - parameter?: string -}; */ - -/*:: export type Query = { - metric: ?string, - selected: ?string, - view: string -}; */ diff --git a/server/sonar-web/src/main/js/apps/component-measures/utils.ts b/server/sonar-web/src/main/js/apps/component-measures/utils.ts index a02181c7e95..74befd184f0 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/utils.ts +++ b/server/sonar-web/src/main/js/apps/component-measures/utils.ts @@ -79,10 +79,7 @@ export function sortMeasures( ]); } -export function addMeasureCategories( - domainName: string, - measures: MeasureEnhanced[] -) /*: Array */ { +export function addMeasureCategories(domainName: string, measures: MeasureEnhanced[]) { const categories = domains[domainName] && domains[domainName].categories; if (categories && categories.length > 0) { return [...categories, ...measures]; @@ -121,7 +118,7 @@ export const groupByDomains = memoize((measures: MeasureEnhanced[]) => { })); return sortBy(domains, [ - (domain: { name: string; measure: MeasureEnhanced[] }) => { + (domain: { name: string; measures: MeasureEnhanced[] }) => { const idx = KNOWN_DOMAINS.indexOf(domain.name); return idx >= 0 ? idx : KNOWN_DOMAINS.length; }, @@ -162,7 +159,7 @@ export function getBubbleMetrics(domain: string, metrics: { [key: string]: Metri x: metrics[conf.x], y: metrics[conf.y], size: metrics[conf.size], - colors: conf.colors ? conf.colors.map(color => metrics[color]) : null + colors: conf.colors && conf.colors.map(color => metrics[color]) }; } -- cgit v1.2.3