From 70f4f8576349995eda926a82abc6d453e61b32eb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Gr=C3=A9goire=20Aubert?= Date: Thu, 6 Jul 2017 15:28:53 +0200 Subject: [PATCH] SONAR-9403 Allow to remove a metric fromt the custom graph --- .../components/GraphsHistory.js | 16 ++++- .../components/GraphsLegendCustom.js | 48 ++++++++++++++ .../components/GraphsLegendItem.js | 66 +++++++++++++++++++ .../components/GraphsLegendStatic.js | 19 +++--- .../components/ProjectActivityApp.js | 1 - .../components/ProjectActivityGraphs.js | 23 +++++-- .../components/ProjectActivityGraphsHeader.js | 13 ++-- .../__tests__/GraphsHistory-test.js | 2 + .../__tests__/GraphsLegendCustom-test.js | 39 +++++++++++ .../__tests__/GraphsLegendItem-test.js | 40 +++++++++++ .../__tests__/ProjectActivityGraphs-test.js | 1 - .../GraphsLegendCustom-test.js.snap | 38 +++++++++++ .../GraphsLegendItem-test.js.snap | 32 +++++++++ .../GraphsLegendStatic-test.js.snap | 24 +++---- .../ProjectActivityApp-test.js.snap | 1 - .../ProjectActivityGraphs-test.js.snap | 5 +- .../components/forms/AddGraphMetric.js | 5 +- .../components/projectActivity.css | 6 ++ 18 files changed, 330 insertions(+), 49 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendCustom.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendItem.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsLegendCustom-test.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsLegendItem-test.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendCustom-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendItem-test.js.snap diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js index 36ac11b372e..130bf03e018 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js @@ -23,11 +23,12 @@ import { sortBy } from 'lodash'; import { AutoSizer } from 'react-virtualized'; import AdvancedTimeline from '../../../components/charts/AdvancedTimeline'; import GraphsTooltips from './GraphsTooltips'; +import GraphsLegendCustom from './GraphsLegendCustom'; import GraphsLegendStatic from './GraphsLegendStatic'; import { formatMeasure, getShortType } from '../../../helpers/measures'; import { EVENT_TYPES, hasHistoryData, isCustomGraph } from '../utils'; import { translate } from '../../../helpers/l10n'; -import type { Analysis, MeasureHistory } from '../types'; +import type { Analysis, MeasureHistory, Metric } from '../types'; import type { Serie } from '../../../components/charts/AdvancedTimeline'; type Props = { @@ -39,7 +40,9 @@ type Props = { leakPeriodDate: Date, loading: boolean, measuresHistory: Array, + metrics: Array, metricsType: string, + removeCustomMetric: (metric: string) => void, selectedDate?: ?Date => void, series: Array, updateGraphZoom: (from: ?Date, to: ?Date) => void, @@ -105,6 +108,7 @@ export default class GraphsHistory extends React.PureComponent { render() { const { loading } = this.props; const { graph, series } = this.props; + const isCustom = isCustomGraph(graph); if (loading) { return ( @@ -121,7 +125,7 @@ export default class GraphsHistory extends React.PureComponent {
{translate( - isCustomGraph(this.props.graph) + isCustom ? 'project_activity.graphs.custom.no_history' : 'component_measures.no_history' )} @@ -133,7 +137,13 @@ export default class GraphsHistory extends React.PureComponent { const { selectedDate, tooltipIdx, tooltipXPos } = this.state; return (
- + {isCustom + ? + : }
{({ height, width }) => ( diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendCustom.js b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendCustom.js new file mode 100644 index 00000000000..e0236cb4e2f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendCustom.js @@ -0,0 +1,48 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 GraphsLegendItem from './GraphsLegendItem'; +import type { Metric } from '../types'; + +type Props = { + metrics: Array, + removeMetric: string => void, + series: Array<{ name: string, translatedName: string, style: string }> +}; + +export default function GraphsLegendCustom({ metrics, removeMetric, series }: Props) { + return ( +
+ {series.map(serie => { + const metric = metrics.find(metric => metric.key === serie.name); + return ( + + + + ); + })} +
+ ); +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendItem.js b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendItem.js new file mode 100644 index 00000000000..79d294505c0 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendItem.js @@ -0,0 +1,66 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 classNames from 'classnames'; +import CloseIcon from '../../../components/icons-components/CloseIcon'; +import ChartLegendIcon from '../../../components/icons-components/ChartLegendIcon'; + +type Props = { + className?: string, + metric: string, + name: string, + style: string, + removeMetric?: string => void +}; + +export default class GraphsLegendItem extends React.PureComponent { + props: Props; + + handleClick = (e: Event) => { + e.preventDefault(); + this.props.removeMetric(this.props.metric); + }; + + render() { + const isActionable = this.props.removeMetric != null; + const legendClass = classNames( + { + 'project-activity-graph-legend-actionable': isActionable + }, + this.props.className + ); + + return ( + + + {this.props.name} + {isActionable && + + + } + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendStatic.js b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendStatic.js index 7dffdf75321..123bc9548b7 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendStatic.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendStatic.js @@ -18,8 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import React from 'react'; -import classNames from 'classnames'; -import ChartLegendIcon from '../../../components/icons-components/ChartLegendIcon'; +import GraphsLegendItem from './GraphsLegendItem'; type Props = { series: Array<{ name: string, translatedName: string, style: string }> @@ -29,15 +28,13 @@ export default function GraphsLegendStatic({ series }: Props) { return (
{series.map(serie => ( - - - {serie.translatedName} - + ))}
); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js index 02a1f1b5eb3..d982bc837cc 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js @@ -127,7 +127,6 @@ export default class ProjectActivityApp extends React.PureComponent { measuresHistory={measuresHistory} metrics={this.props.metrics} metricsType={this.getMetricType()} - project={this.props.project.key} query={query} updateQuery={this.props.updateQuery} /> diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js index 0b86b71bdc5..13d42349be3 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js @@ -40,7 +40,6 @@ type Props = { measuresHistory: Array, metrics: Array, metricsType: string, - project: string, query: Query, updateQuery: RawQuery => void }; @@ -108,7 +107,15 @@ export default class ProjectActivityGraphs extends React.PureComponent { } }; - updateSelectedDate = (selectedDate: ?Date) => this.props.updateQuery({ selectedDate }); + addCustomMetric = (metric: string) => + this.props.updateQuery({ customMetrics: [...this.props.query.customMetrics, metric] }); + + removeCustomMetric = (removedMetric: string) => + this.props.updateQuery({ + customMetrics: this.props.query.customMetrics.filter(metric => metric !== removedMetric) + }); + + updateGraph = (graph: string) => this.props.updateQuery({ graph }); updateGraphZoom = (graphStartDate: ?Date, graphEndDate: ?Date) => { if (graphEndDate != null && graphStartDate != null) { @@ -123,6 +130,8 @@ export default class ProjectActivityGraphs extends React.PureComponent { this.updateQueryDateRange([graphStartDate, graphEndDate]); }; + updateSelectedDate = (selectedDate: ?Date) => this.props.updateQuery({ selectedDate }); + updateQueryDateRange = (dates: Array) => { if (dates[0] == null || dates[1] == null) { this.props.updateQuery({ from: dates[0], to: dates[1] }); @@ -133,15 +142,16 @@ export default class ProjectActivityGraphs extends React.PureComponent { }; render() { - const { leakPeriodDate, loading, metricsType, query } = this.props; + const { leakPeriodDate, loading, metrics, metricsType, query } = this.props; const { series } = this.state; return (
void, graph: string, metrics: Array, selectedMetrics: Array, - updateQuery: RawQuery => void + updateGraph: string => void }; export default class ProjectActivityGraphsHeader extends React.PureComponent { @@ -38,15 +38,10 @@ export default class ProjectActivityGraphsHeader extends React.PureComponent { handleGraphChange = (option: { value: string }) => { if (option.value !== this.props.graph) { - this.props.updateQuery({ graph: option.value }); + this.props.updateGraph(option.value); } }; - handleAddMetric = (metric: string) => { - const selectedMetrics = [...this.props.selectedMetrics, metric]; - this.props.updateQuery({ customMetrics: selectedMetrics }); - }; - render() { const selectOptions = GRAPH_TYPES.map(graph => ({ label: translate('project_activity.graphs', graph), @@ -65,7 +60,7 @@ export default class ProjectActivityGraphsHeader extends React.PureComponent { /> {isCustomGraph(this.props.graph) && {}, selectedDate: null, series: SERIES, updateGraphZoom: () => {}, diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsLegendCustom-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsLegendCustom-test.js new file mode 100644 index 00000000000..9b785f2213b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsLegendCustom-test.js @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 GraphsLegendCustom from '../GraphsLegendCustom'; + +const SERIES = [ + { name: 'bugs', translatedName: 'Bugs', style: '2', data: [] }, + { name: 'my_metric', translatedName: 'metric.my_metric.name', style: '1', data: [] }, + { name: 'foo', translatedName: 'Foo', style: '0', data: [] } +]; + +const METRICS = [ + { key: 'bugs', name: 'Bugs' }, + { key: 'my_metric', name: 'My Metric', custom: true } +]; + +it('should render correctly the list of series', () => { + expect( + shallow( {}} series={SERIES} />) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsLegendItem-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsLegendItem-test.js new file mode 100644 index 00000000000..a000a1dec04 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsLegendItem-test.js @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 GraphsLegendItem from '../GraphsLegendItem'; + +it('should render correctly a legend', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('should render correctly an actionable legend', () => { + expect( + shallow( + {}} + /> + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityGraphs-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityGraphs-test.js index 2b27845d57c..07930d40463 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityGraphs-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityGraphs-test.js @@ -71,7 +71,6 @@ const DEFAULT_PROPS = { } ], metricsType: 'INT', - project: 'org.sonarsource.sonarqube:sonarqube', query: { category: '', graph: 'overview', project: 'org.sonarsource.sonarqube:sonarqube' }, updateQuery: () => {} }; diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendCustom-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendCustom-test.js.snap new file mode 100644 index 00000000000..b19b8e8e654 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendCustom-test.js.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly the list of series 1`] = ` +
+ + + + + + + + + +
+`; diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendItem-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendItem-test.js.snap new file mode 100644 index 00000000000..84dc737ae03 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendItem-test.js.snap @@ -0,0 +1,32 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly a legend 1`] = ` + + + Bugs + +`; + +exports[`should render correctly an actionable legend 1`] = ` + + + Foo + + + + +`; diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendStatic-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendStatic-test.js.snap index 1fd564f69ef..97610c6365f 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendStatic-test.js.snap +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendStatic-test.js.snap @@ -4,21 +4,17 @@ exports[`should render correctly the list of series 1`] = `
- - - Bugs - - + - - Code Smells - + metric="code_smells" + name="Code Smells" + style="1" + />
`; diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap index 1943a2f48ac..7fa450f12c8 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap @@ -189,7 +189,6 @@ exports[`should render correctly 1`] = ` ] } metricsType="INT" - project="org.sonarsource.sonarqube:sonarqube" query={ Object { "category": "", diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityGraphs-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityGraphs-test.js.snap index 3c46221619f..a32cd28f590 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityGraphs-test.js.snap +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityGraphs-test.js.snap @@ -5,8 +5,9 @@ exports[`should render correctly the graph and legends 1`] = ` className="project-activity-layout-page-main-inner boxed-group boxed-group-inner" > + diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css b/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css index 35b51275992..cc0b6d1bd7a 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css @@ -62,6 +62,12 @@ text-align: center; } +.project-activity-graph-legend-actionable { + padding: 4px 12px; + border: 1px solid #e6e6e6; + border-radius: 12px; +} + .project-activity-graph-tooltip { padding: 8px; pointer-events: none; -- 2.39.5