diff options
author | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2017-07-12 14:34:59 +0200 |
---|---|---|
committer | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2017-07-13 14:34:17 +0200 |
commit | 6f1a53f106d2c658996f4b7a6a6e1e493b653c86 (patch) | |
tree | d1f6cf82ebf9174268b043abd5e1230d43909e56 /server/sonar-web | |
parent | 33c3ac6b2feb1ef97cb16bc949a0840c388cceaf (diff) | |
download | sonarqube-6f1a53f106d2c658996f4b7a6a6e1e493b653c86.tar.gz sonarqube-6f1a53f106d2c658996f4b7a6a6e1e493b653c86.zip |
SONAR-9403 Change style of metrics with no historical data in the custom graph legend
Diffstat (limited to 'server/sonar-web')
9 files changed, 134 insertions, 28 deletions
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 index e0236cb4e2f..540bb65961a 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendCustom.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendCustom.js @@ -19,6 +19,9 @@ */ import React from 'react'; import GraphsLegendItem from './GraphsLegendItem'; +import Tooltip from '../../../components/controls/Tooltip'; +import { hasDataValues } from '../utils'; +import { translate } from '../../../helpers/l10n'; import type { Metric } from '../types'; type Props = { @@ -32,14 +35,31 @@ export default function GraphsLegendCustom({ metrics, removeMetric, series }: Pr <div className="project-activity-graph-legends"> {series.map(serie => { const metric = metrics.find(metric => metric.key === serie.name); + const hasData = hasDataValues(serie); + const legendItem = ( + <GraphsLegendItem + metric={serie.name} + name={metric && metric.custom ? metric.name : serie.translatedName} + showWarning={!hasData} + style={serie.style} + removeMetric={removeMetric} + /> + ); + if (!hasData) { + return ( + <Tooltip + key={serie.name} + overlay={translate('project_activity.graphs.custom.metric_no_history')} + placement="bottom"> + <span className="spacer-left spacer-right"> + {legendItem} + </span> + </Tooltip> + ); + } return ( <span className="spacer-left spacer-right" key={serie.name}> - <GraphsLegendItem - metric={serie.name} - name={metric && metric.custom ? metric.name : serie.translatedName} - style={serie.style} - removeMetric={removeMetric} - /> + {legendItem} </span> ); })} 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 index 79d294505c0..a458455a85c 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendItem.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendItem.js @@ -17,15 +17,18 @@ * 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 CloseIcon from '../../../components/icons-components/CloseIcon'; +import AlertWarnIcon from '../../../components/icons-components/AlertWarnIcon'; import ChartLegendIcon from '../../../components/icons-components/ChartLegendIcon'; +import CloseIcon from '../../../components/icons-components/CloseIcon'; type Props = { className?: string, metric: string, name: string, + showWarning?: boolean, style: string, removeMetric?: string => void }; @@ -35,26 +38,30 @@ export default class GraphsLegendItem extends React.PureComponent { handleClick = (e: Event) => { e.preventDefault(); - this.props.removeMetric(this.props.metric); + if (this.props.removeMetric) { + this.props.removeMetric(this.props.metric); + } }; render() { const isActionable = this.props.removeMetric != null; const legendClass = classNames( { - 'project-activity-graph-legend-actionable': isActionable + 'project-activity-graph-legend-actionable': isActionable, + 'alert-warning': this.props.showWarning }, this.props.className ); - return ( <span className={legendClass}> - <ChartLegendIcon - className={classNames( - 'spacer-right line-chart-legend', - 'line-chart-legend-' + this.props.style - )} - /> + {this.props.showWarning + ? <AlertWarnIcon className="spacer-right" /> + : <ChartLegendIcon + className={classNames( + 'spacer-right line-chart-legend', + 'line-chart-legend-' + this.props.style + )} + />} {this.props.name} {isActionable && <a className="spacer-left button-clean text-text-top" href="#" onClick={this.handleClick}> 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 index 9b785f2213b..c115f0b5f13 100644 --- 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 @@ -22,8 +22,13 @@ 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: 'bugs', translatedName: 'Bugs', style: '2', data: [{ x: 1, y: 1 }] }, + { + name: 'my_metric', + translatedName: 'metric.my_metric.name', + style: '1', + data: [{ x: 1, y: 1 }] + }, { name: 'foo', translatedName: 'Foo', style: '0', data: [] } ]; 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 index a000a1dec04..5a0af033764 100644 --- 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 @@ -38,3 +38,11 @@ it('should render correctly an actionable legend', () => { ) ).toMatchSnapshot(); }); + +it('should render correctly legends with warning', () => { + expect( + shallow( + <GraphsLegendItem className="myclass" metric="foo" name="Foo" showWarning={true} style="1" /> + ) + ).toMatchSnapshot(); +}); 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 index b19b8e8e654..d90f7a6843d 100644 --- 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 @@ -11,6 +11,7 @@ exports[`should render correctly the list of series 1`] = ` metric="bugs" name="Bugs" removeMetric={[Function]} + showWarning={false} style="2" /> </span> @@ -21,18 +22,25 @@ exports[`should render correctly the list of series 1`] = ` metric="my_metric" name="My Metric" removeMetric={[Function]} + showWarning={false} style="1" /> </span> - <span - className="spacer-left spacer-right" + <Tooltip + overlay="project_activity.graphs.custom.metric_no_history" + placement="bottom" > - <GraphsLegendItem - metric="foo" - name="Foo" - removeMetric={[Function]} - style="0" - /> - </span> + <span + className="spacer-left spacer-right" + > + <GraphsLegendItem + metric="foo" + name="Foo" + removeMetric={[Function]} + showWarning={true} + style="0" + /> + </span> + </Tooltip> </div> `; 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 index 84dc737ae03..1c660cd406e 100644 --- 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 @@ -30,3 +30,14 @@ exports[`should render correctly an actionable legend 1`] = ` </a> </span> `; + +exports[`should render correctly legends with warning 1`] = ` +<span + className="alert-warning myclass" +> + <AlertWarnIcon + className="spacer-right" + /> + Foo +</span> +`; 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 4bec19f63e2..a42cbc13f2e 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 @@ -65,10 +65,15 @@ .project-activity-graph-legend-actionable { padding: 4px 12px; - border: 1px solid #e6e6e6; + border-width: 1px; + border-style: solid; border-radius: 12px; } +.project-activity-graph-legend-actionable:not(.alert-warning) { + border-color: #e6e6e6; +} + .project-activity-graph-tooltip { padding: 8px; pointer-events: none; diff --git a/server/sonar-web/src/main/js/apps/projectActivity/utils.js b/server/sonar-web/src/main/js/apps/projectActivity/utils.js index 6ea4c782138..83f5960b6e7 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/utils.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/utils.js @@ -65,6 +65,8 @@ export const datesQueryChanged = (prevQuery: Query, nextQuery: Query): boolean = return previousFrom !== nextFrom || previousTo !== nextTo; }; +export const hasDataValues = (serie: Serie) => serie.data.some(point => point.y || point.y === 0); + export const hasHistoryData = (series: Array<Serie>) => series.some(serie => serie.data && serie.data.length > 2); diff --git a/server/sonar-web/src/main/js/components/icons-components/AlertWarnIcon.js b/server/sonar-web/src/main/js/components/icons-components/AlertWarnIcon.js new file mode 100644 index 00000000000..3ecabfa4c5a --- /dev/null +++ b/server/sonar-web/src/main/js/components/icons-components/AlertWarnIcon.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. + */ +// @flow +import React from 'react'; + +type Props = { className?: string, size?: number }; + +export default function AlertWarnIcon({ className, size = 16 }: Props) { + /* eslint-disable max-len */ + return ( + <svg + xmlns="http://www.w3.org/2000/svg" + className={className} + height={size} + width={size} + viewBox="0 0 16 16"> + <path + style={{ fill: '#ed7d20' }} + d="M8 1.143q1.866 0 3.442.92t2.496 2.496.92 3.442-.92 3.442-2.496 2.496-3.442.92-3.442-.92-2.496-2.496-.92-3.442.92-3.442 2.496-2.496T8 1.143zm1.143 11.134v-1.696q0-.125-.08-.21t-.196-.085H7.153q-.116 0-.205.089t-.089.205v1.696q0 .116.089.205t.205.089h1.714q.116 0 .196-.085t.08-.21zm-.018-3.072l.161-5.545q0-.107-.089-.161-.089-.071-.214-.071H7.019q-.125 0-.214.071-.089.054-.089.161l.152 5.545q0 .089.089.156t.214.067h1.652q.125 0 .21-.067t.094-.156z" + /> + </svg> + ); +} |