]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9418 Add tooltips on the project dashboard preview graph
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 10 Jul 2017 09:23:58 +0000 (11:23 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Thu, 13 Jul 2017 12:34:17 +0000 (14:34 +0200)
17 files changed:
server/sonar-web/src/main/js/apps/overview/events/AnalysesList.js
server/sonar-web/src/main/js/apps/overview/events/PreviewGraph.js
server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltips.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltipsContent.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/events/__tests__/PreviewGraphTooltips-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/events/__tests__/PreviewGraphTooltipsContent-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltips-test.js.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltipsContent-test.js.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/meta/Meta.js
server/sonar-web/src/main/js/apps/overview/styles.css
server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js
server/sonar-web/src/main/js/apps/projectActivity/components/GraphsTooltips.js
server/sonar-web/src/main/js/apps/projectActivity/components/GraphsTooltipsContent.js
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsTooltips-test.js
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsTooltipsContent-test.js
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsTooltips-test.js.snap
server/sonar-web/src/main/less/init/misc.less

index 9b199036fb294f6b1439df8335a4e2edc33c52a3..9746ea02c4a269a5cd81a15ff2deb364a9d9905b 100644 (file)
@@ -31,7 +31,8 @@ import type { History, Metric } from '../types';
 
 type Props = {
   history: History,
-  project: string
+  project: string,
+  router: { replace: ({ pathname: string, query?: {} }) => void }
 };
 
 type State = {
@@ -107,6 +108,7 @@ export default class AnalysesList extends React.PureComponent {
           history={this.props.history}
           project={this.props.project}
           metrics={this.state.metrics}
+          router={this.props.router}
         />
 
         {this.renderList(analyses)}
index d5cd5f6aea567d5315efc9a1576ae3a570884d1f..148557d6b68383bfdb7846d1b08ac29e9f4c5310 100644 (file)
 // @flow
 import React from 'react';
 import { map } from 'lodash';
-import { Link } from 'react-router';
 import { AutoSizer } from 'react-virtualized';
 import { generateSeries, GRAPHS_METRICS_DISPLAYED } from '../../projectActivity/utils';
 import { getGraph } from '../../../helpers/storage';
 import AdvancedTimeline from '../../../components/charts/AdvancedTimeline';
+import PreviewGraphTooltips from './PreviewGraphTooltips';
+import { formatMeasure, getShortType } from '../../../helpers/measures';
 import type { Serie } from '../../../components/charts/AdvancedTimeline';
 import type { History, Metric } from '../types';
 
 type Props = {
   history: History,
   metrics: Array<Metric>,
-  project: string
+  project: string,
+  router: { replace: ({ pathname: string, query?: {} }) => void }
 };
 
 type State = {
   graph: string,
   metricsType: string,
-  series: Array<Serie>
+  selectedDate: ?Date,
+  series: Array<Serie>,
+  tooltipIdx: ?number,
+  tooltipXPos: ?number
 };
 
+const GRAPH_PADDING = [4, 0, 4, 0];
+
 export default class PreviewGraph extends React.PureComponent {
   props: Props;
   state: State;
@@ -51,7 +58,10 @@ export default class PreviewGraph extends React.PureComponent {
     this.state = {
       graph,
       metricsType,
-      series: this.getSeries(props.history, graph, metricsType)
+      selectedDate: null,
+      series: this.getSeries(props.history, graph, metricsType),
+      tooltipIdx: null,
+      tooltipXPos: null
     };
   }
 
@@ -67,15 +77,18 @@ export default class PreviewGraph extends React.PureComponent {
     }
   }
 
-  getDisplayedMetrics = (graph: string) => {
-    const metrics = GRAPHS_METRICS_DISPLAYED[graph];
+  formatValue = (tick: number | string) =>
+    formatMeasure(tick, getShortType(this.state.metricsType));
+
+  getDisplayedMetrics = (graph: string): Array<string> => {
+    const metrics: Array<string> = GRAPHS_METRICS_DISPLAYED[graph];
     if (!metrics || metrics.length <= 0) {
       return GRAPHS_METRICS_DISPLAYED['overview'];
     }
     return metrics;
   };
 
-  getSeries = (history: History, graph: string, metricsType: string): Array<Serie> => {
+  getSeries = (history: History, graph: string, metricsType: string) => {
     const measureHistory = map(history, (item, key) => ({
       metric: key,
       history: item.filter(p => p.value != null)
@@ -89,14 +102,24 @@ export default class PreviewGraph extends React.PureComponent {
     return metric ? metric.type : 'INT';
   };
 
+  handleClick = () => {
+    this.props.router.replace({ pathname: '/project/activity', query: { id: this.props.project } });
+  };
+
+  updateTooltip = (selectedDate: ?Date, tooltipXPos: ?number, tooltipIdx: ?number) =>
+    this.setState({ selectedDate, tooltipXPos, tooltipIdx });
+
   render() {
+    const { graph, selectedDate, tooltipIdx, tooltipXPos } = this.state;
     return (
-      <div className="big-spacer-bottom spacer-top">
-        <Link
-          className="overview-analysis-graph"
-          to={{ pathname: '/project/activity', query: { id: this.props.project } }}>
-          <AutoSizer disableHeight={true}>
-            {({ width }) => (
+      <div
+        className="overview-analysis-graph big-spacer-bottom spacer-top"
+        onClick={this.handleClick}
+        tabIndex={0}
+        role="link">
+        <AutoSizer disableHeight={true}>
+          {({ width }) => (
+            <div>
               <AdvancedTimeline
                 endDate={null}
                 startDate={null}
@@ -106,13 +129,27 @@ export default class PreviewGraph extends React.PureComponent {
                 hideXAxis={true}
                 interpolate="linear"
                 metricType={this.state.metricsType}
-                padding={[4, 0, 4, 0]}
+                padding={GRAPH_PADDING}
                 series={this.state.series}
-                showAreas={['coverage', 'duplications'].includes(this.state.graph)}
+                showAreas={['coverage', 'duplications'].includes(graph)}
+                updateTooltip={this.updateTooltip}
               />
-            )}
-          </AutoSizer>
-        </Link>
+              {selectedDate != null &&
+                tooltipXPos != null &&
+                tooltipIdx != null &&
+                <PreviewGraphTooltips
+                  formatValue={this.formatValue}
+                  graph={graph}
+                  graphWidth={width}
+                  metrics={this.props.metrics}
+                  selectedDate={selectedDate}
+                  series={this.state.series}
+                  tooltipIdx={tooltipIdx}
+                  tooltipPos={tooltipXPos}
+                />}
+            </div>
+          )}
+        </AutoSizer>
       </div>
     );
   }
diff --git a/server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltips.js b/server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltips.js
new file mode 100644 (file)
index 0000000..dfcf88e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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 BubblePopup from '../../../components/common/BubblePopup';
+import FormattedDate from '../../../components/ui/FormattedDate';
+import PreviewGraphTooltipsContent from './PreviewGraphTooltipsContent';
+import type { Metric } from '../types';
+import type { Serie } from '../../../components/charts/AdvancedTimeline';
+
+type Props = {
+  formatValue: (number | string) => string,
+  graph: string,
+  graphWidth: number,
+  metrics: Array<Metric>,
+  selectedDate: Date,
+  series: Array<Serie & { translatedName: string }>,
+  tooltipIdx: number,
+  tooltipPos: number
+};
+
+const TOOLTIP_WIDTH = 150;
+
+export default class PreviewGraphTooltips extends React.PureComponent {
+  props: Props;
+
+  render() {
+    const { tooltipIdx } = this.props;
+    const top = 16;
+    let left = this.props.tooltipPos;
+    let customClass;
+    if (left > this.props.graphWidth - TOOLTIP_WIDTH + 20) {
+      left -= TOOLTIP_WIDTH;
+      customClass = 'bubble-popup-right';
+    }
+
+    return (
+      <BubblePopup customClass={customClass} position={{ top, left, width: TOOLTIP_WIDTH }}>
+        <div className="overview-analysis-graph-tooltip">
+          <div className="overview-analysis-graph-tooltip-title">
+            <FormattedDate date={this.props.selectedDate} format="LL" />
+          </div>
+          <table className="width-100">
+            <tbody>
+              {this.props.series.map(serie => {
+                const point = serie.data[tooltipIdx];
+                if (!point || (!point.y && point.y !== 0)) {
+                  return null;
+                }
+                const metric = this.props.metrics.find(metric => metric.key === serie.name);
+                return (
+                  <PreviewGraphTooltipsContent
+                    key={serie.name}
+                    serie={serie}
+                    translatedName={metric && metric.custom ? metric.name : serie.translatedName}
+                    value={this.props.formatValue(point.y)}
+                  />
+                );
+              })}
+            </tbody>
+          </table>
+        </div>
+      </BubblePopup>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltipsContent.js b/server/sonar-web/src/main/js/apps/overview/events/PreviewGraphTooltipsContent.js
new file mode 100644 (file)
index 0000000..a91af02
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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';
+import ChartLegendIcon from '../../../components/icons-components/ChartLegendIcon';
+import type { Serie } from '../../../components/charts/AdvancedTimeline';
+
+type Props = {
+  serie: Serie,
+  translatedName: string,
+  value: string
+};
+
+export default function PreviewGraphTooltipsContent({ serie, translatedName, value }: Props) {
+  return (
+    <tr className="overview-analysis-graph-tooltip-line">
+      <td className="thin">
+        <ChartLegendIcon
+          className={'little-spacer-right line-chart-legend line-chart-legend-' + serie.style}
+        />
+      </td>
+      <td className="overview-analysis-graph-tooltip-value text-right little-spacer-right thin">
+        {value}
+      </td>
+      <td className="text-ellipsis">{translatedName}</td>
+    </tr>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/PreviewGraphTooltips-test.js b/server/sonar-web/src/main/js/apps/overview/events/__tests__/PreviewGraphTooltips-test.js
new file mode 100644 (file)
index 0000000..10a9a08
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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 PreviewGraphTooltips from '../PreviewGraphTooltips';
+
+const SERIES_OVERVIEW = [
+  {
+    name: 'code_smells',
+    translatedName: 'Code Smells',
+    style: 1,
+    data: [
+      {
+        x: '2011-10-01T22:01:00.000Z',
+        y: 18
+      },
+      {
+        x: '2011-10-25T10:27:41.000Z',
+        y: 15
+      }
+    ]
+  },
+  {
+    name: 'bugs',
+    translatedName: 'Bugs',
+    style: 0,
+    data: [
+      {
+        x: '2011-10-01T22:01:00.000Z',
+        y: 3
+      },
+      {
+        x: '2011-10-25T10:27:41.000Z',
+        y: 0
+      }
+    ]
+  },
+  {
+    name: 'vulnerabilities',
+    translatedName: 'Vulnerabilities',
+    style: 2,
+    data: [
+      {
+        x: '2011-10-01T22:01:00.000Z',
+        y: 0
+      },
+      {
+        x: '2011-10-25T10:27:41.000Z',
+        y: 1
+      }
+    ]
+  }
+];
+
+const METRICS = [
+  { key: 'bugs', name: 'Bugs', type: 'INT' },
+  { key: 'vulnerabilities', name: 'Vulnerabilities', type: 'INT', custom: true }
+];
+
+const DEFAULT_PROPS = {
+  formatValue: val => 'Formated.' + val,
+  graph: 'overview',
+  graphWidth: 150,
+  metrics: METRICS,
+  selectedDate: new Date('2011-10-01T22:01:00.000Z'),
+  series: SERIES_OVERVIEW,
+  tooltipIdx: 0,
+  tooltipPos: 25
+};
+
+it('should render correctly', () => {
+  expect(
+    shallow(
+      <PreviewGraphTooltips
+        {...DEFAULT_PROPS}
+        graph="random"
+        selectedDate={new Date('2011-10-25T10:27:41.000Z')}
+        tooltipIdx={1}
+      />
+    )
+  ).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/PreviewGraphTooltipsContent-test.js b/server/sonar-web/src/main/js/apps/overview/events/__tests__/PreviewGraphTooltipsContent-test.js
new file mode 100644 (file)
index 0000000..4195a9c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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 PreviewGraphTooltipsContent from '../PreviewGraphTooltipsContent';
+
+const DEFAULT_PROPS = {
+  serie: {
+    name: 'code_smells',
+    translatedName: 'metric.code_smells.name',
+    style: 1
+  },
+  translatedName: 'Code Smells',
+  value: '1.2k'
+};
+
+it('should render correctly', () => {
+  expect(shallow(<PreviewGraphTooltipsContent {...DEFAULT_PROPS} />)).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltips-test.js.snap b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltips-test.js.snap
new file mode 100644 (file)
index 0000000..e809058
--- /dev/null
@@ -0,0 +1,96 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<BubblePopup
+  customClass="bubble-popup-right"
+  position={
+    Object {
+      "left": -125,
+      "top": 16,
+      "width": 150,
+    }
+  }
+>
+  <div
+    className="overview-analysis-graph-tooltip"
+  >
+    <div
+      className="overview-analysis-graph-tooltip-title"
+    >
+      <FormattedDate
+        date={2011-10-25T10:27:41.000Z}
+        format="LL"
+      />
+    </div>
+    <table
+      className="width-100"
+    >
+      <tbody>
+        <PreviewGraphTooltipsContent
+          serie={
+            Object {
+              "data": Array [
+                Object {
+                  "x": "2011-10-01T22:01:00.000Z",
+                  "y": 18,
+                },
+                Object {
+                  "x": "2011-10-25T10:27:41.000Z",
+                  "y": 15,
+                },
+              ],
+              "name": "code_smells",
+              "style": 1,
+              "translatedName": "Code Smells",
+            }
+          }
+          translatedName="Code Smells"
+          value="Formated.15"
+        />
+        <PreviewGraphTooltipsContent
+          serie={
+            Object {
+              "data": Array [
+                Object {
+                  "x": "2011-10-01T22:01:00.000Z",
+                  "y": 3,
+                },
+                Object {
+                  "x": "2011-10-25T10:27:41.000Z",
+                  "y": 0,
+                },
+              ],
+              "name": "bugs",
+              "style": 0,
+              "translatedName": "Bugs",
+            }
+          }
+          translatedName="Bugs"
+          value="Formated.0"
+        />
+        <PreviewGraphTooltipsContent
+          serie={
+            Object {
+              "data": Array [
+                Object {
+                  "x": "2011-10-01T22:01:00.000Z",
+                  "y": 0,
+                },
+                Object {
+                  "x": "2011-10-25T10:27:41.000Z",
+                  "y": 1,
+                },
+              ],
+              "name": "vulnerabilities",
+              "style": 2,
+              "translatedName": "Vulnerabilities",
+            }
+          }
+          translatedName="Vulnerabilities"
+          value="Formated.1"
+        />
+      </tbody>
+    </table>
+  </div>
+</BubblePopup>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltipsContent-test.js.snap b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/PreviewGraphTooltipsContent-test.js.snap
new file mode 100644 (file)
index 0000000..db45985
--- /dev/null
@@ -0,0 +1,25 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<tr
+  className="overview-analysis-graph-tooltip-line"
+>
+  <td
+    className="thin"
+  >
+    <ChartLegendIcon
+      className="little-spacer-right line-chart-legend line-chart-legend-1"
+    />
+  </td>
+  <td
+    className="overview-analysis-graph-tooltip-value text-right little-spacer-right thin"
+  >
+    1.2k
+  </td>
+  <td
+    className="text-ellipsis"
+  >
+    Code Smells
+  </td>
+</tr>
+`;
index 3f8cd994a1eaa2e616ef3e4603f10635fe422d4a..db9b0cb523c7774caa07731a150eebc0cf9235bc 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import React from 'react';
+import { withRouter } from 'react-router';
 import { connect } from 'react-redux';
 import MetaKey from './MetaKey';
 import MetaOrganizationKey from './MetaOrganizationKey';
@@ -29,7 +30,7 @@ import MetaSize from './MetaSize';
 import MetaTags from './MetaTags';
 import { areThereCustomOrganizations } from '../../../store/rootReducer';
 
-const Meta = ({ component, history, measures, areThereCustomOrganizations }) => {
+const Meta = ({ component, history, measures, areThereCustomOrganizations, router }) => {
   const { qualifier, description, qualityProfiles, qualityGate } = component;
 
   const isProject = qualifier === 'TRK';
@@ -70,7 +71,7 @@ const Meta = ({ component, history, measures, areThereCustomOrganizations }) =>
 
       {shouldShowOrganizationKey && <MetaOrganizationKey component={component} />}
 
-      {isProject && <AnalysesList project={component.key} history={history} />}
+      {isProject && <AnalysesList project={component.key} history={history} router={router} />}
     </div>
   );
 };
@@ -79,4 +80,4 @@ const mapStateToProps = state => ({
   areThereCustomOrganizations: areThereCustomOrganizations(state)
 });
 
-export default connect(mapStateToProps)(Meta);
+export default connect(mapStateToProps)(withRouter(Meta));
index 575ff4a859f4273561d16bea488c1fb8b5dfcba6..45911113921c71a4b83a1c76b93b73e90ef5c31f 100644 (file)
 
 .overview-analysis-graph {
   display: block;
+  cursor: pointer;
   outline: none;
   border: none;
 }
 
+.overview-analysis-graph .bubble-popup {
+  opacity: 0.8;
+  padding: 0;
+}
+
+.overview-analysis-graph-tooltip {
+  padding: 4px;
+  pointer-events: none;
+  font-size: 12px;
+  overflow: hidden;
+}
+
+.overview-analysis-graph-tooltip-line {
+  padding-bottom: 2px;
+}
+
+.overview-analysis-graph-tooltip-title {
+  font-weight: bold;
+  margin-bottom: 4px;
+}
+
+.overview-analysis-graph-tooltip-value {
+  font-weight: bold;
+}
+
 .overview-analysis-event {}
 
 .overview-analysis-event.badge {
index 130bf03e018a94006d6ca9309a9ba3bd2d5702fa..6ce8ad5825bb11c80453203b5da4cca3e756980a 100644 (file)
@@ -43,7 +43,7 @@ type Props = {
   metrics: Array<Metric>,
   metricsType: string,
   removeCustomMetric: (metric: string) => void,
-  selectedDate?: ?Date => void,
+  selectedDate: ?Date,
   series: Array<Serie>,
   updateGraphZoom: (from: ?Date, to: ?Date) => void,
   updateSelectedDate: (selectedDate: ?Date) => void
@@ -62,7 +62,8 @@ export default class GraphsHistory extends React.PureComponent {
     tooltipXPos: null
   };
 
-  formatValue = tick => formatMeasure(tick, getShortType(this.props.metricsType));
+  formatValue = (tick: string | number) =>
+    formatMeasure(tick, getShortType(this.props.metricsType));
 
   getEvents = () => {
     const { analyses, eventFilter } = this.props;
@@ -172,6 +173,7 @@ export default class GraphsHistory extends React.PureComponent {
                     graph={graph}
                     graphWidth={width}
                     measuresHistory={this.props.measuresHistory}
+                    metrics={this.props.metrics}
                     selectedDate={selectedDate}
                     series={series}
                     tooltipIdx={tooltipIdx}
index 6162767369a4b37f3c422d96042d85431c1e4d39..d4b13addd4a2b8794d1b313de0efc11a9e1bcb26 100644 (file)
@@ -26,7 +26,7 @@ import GraphsTooltipsContentEvents from './GraphsTooltipsContentEvents';
 import GraphsTooltipsContentCoverage from './GraphsTooltipsContentCoverage';
 import GraphsTooltipsContentDuplication from './GraphsTooltipsContentDuplication';
 import GraphsTooltipsContentOverview from './GraphsTooltipsContentOverview';
-import type { Event, MeasureHistory } from '../types';
+import type { Event, MeasureHistory, Metric } from '../types';
 import type { Serie } from '../../../components/charts/AdvancedTimeline';
 
 type Props = {
@@ -35,6 +35,7 @@ type Props = {
   graph: string,
   graphWidth: number,
   measuresHistory: Array<MeasureHistory>,
+  metrics: Array<Metric>,
   selectedDate: Date,
   series: Array<Serie & { translatedName: string }>,
   tooltipIdx: number,
@@ -68,19 +69,27 @@ export default class GraphsTooltips extends React.PureComponent {
                 if (!point || (!point.y && point.y !== 0)) {
                   return null;
                 }
-                return this.props.graph === 'overview'
-                  ? <GraphsTooltipsContentOverview
+                if (this.props.graph === 'overview') {
+                  return (
+                    <GraphsTooltipsContentOverview
                       key={serie.name}
                       measuresHistory={measuresHistory}
                       serie={serie}
                       tooltipIdx={tooltipIdx}
                       value={this.props.formatValue(point.y)}
                     />
-                  : <GraphsTooltipsContent
+                  );
+                } else {
+                  const metric = this.props.metrics.find(metric => metric.key === serie.name);
+                  return (
+                    <GraphsTooltipsContent
                       key={serie.name}
                       serie={serie}
+                      translatedName={metric && metric.custom ? metric.name : serie.translatedName}
                       value={this.props.formatValue(point.y)}
-                    />;
+                    />
+                  );
+                }
               })}
             </tbody>
             {this.props.graph === 'coverage' &&
index 43eebc411fb3329b668b437f42f6b987531a3c62..f3dae718ad688e8f7ffb3a2e2a909028e005b41e 100644 (file)
@@ -24,11 +24,12 @@ import ChartLegendIcon from '../../../components/icons-components/ChartLegendIco
 import type { Serie } from '../../../components/charts/AdvancedTimeline';
 
 type Props = {
-  serie: Serie & { translatedName: string },
+  serie: Serie,
+  translatedName: string,
   value: string
 };
 
-export default function GraphsTooltipsContent({ serie, value }: Props) {
+export default function GraphsTooltipsContent({ serie, translatedName, value }: Props) {
   return (
     <tr key={serie.name} className="project-activity-graph-tooltip-line">
       <td className="thin">
@@ -42,7 +43,7 @@ export default function GraphsTooltipsContent({ serie, value }: Props) {
       <td className="project-activity-graph-tooltip-value text-right spacer-right thin">
         {value}
       </td>
-      <td>{serie.translatedName}</td>
+      <td>{translatedName}</td>
     </tr>
   );
 }
index 206491eff31410cd2cde7d801e254c3f730a86ee..cebdb8265a7904200d2e443b350b08b249e7cd80 100644 (file)
@@ -24,7 +24,7 @@ import GraphsTooltips from '../GraphsTooltips';
 const SERIES_OVERVIEW = [
   {
     name: 'code_smells',
-    translatedName: 'Code Smells',
+    translatedName: 'metric.code_smells.name',
     style: 1,
     data: [
       {
@@ -39,7 +39,7 @@ const SERIES_OVERVIEW = [
   },
   {
     name: 'bugs',
-    translatedName: 'Bugs',
+    translatedName: 'metric.bugs.name',
     style: 0,
     data: [
       {
@@ -54,7 +54,7 @@ const SERIES_OVERVIEW = [
   },
   {
     name: 'vulnerabilities',
-    translatedName: 'Vulnerabilities',
+    translatedName: 'metric.vulnerabilities.name',
     style: 2,
     data: [
       {
@@ -69,11 +69,17 @@ const SERIES_OVERVIEW = [
   }
 ];
 
+const METRICS = [
+  { key: 'bugs', name: 'Bugs', type: 'INT' },
+  { key: 'vulnerabilities', name: 'Vulnerabilities', type: 'INT', custom: true }
+];
+
 const DEFAULT_PROPS = {
   formatValue: val => 'Formated.' + val,
   graph: 'overview',
   graphWidth: 500,
   measuresHistory: [],
+  metrics: METRICS,
   selectedDate: new Date('2011-10-01T22:01:00.000Z'),
   series: SERIES_OVERVIEW,
   tooltipIdx: 0,
index 46de44dffa6e29cdf8c0ff561ed5275a8a559764..ce610f0bdf9d804addc7e19d69d78c6f57b4a1d7 100644 (file)
@@ -24,9 +24,10 @@ import GraphsTooltipsContent from '../GraphsTooltipsContent';
 const DEFAULT_PROPS = {
   serie: {
     name: 'code_smells',
-    translatedName: 'Code Smells',
+    translatedName: 'metric.code_smells.name',
     style: 1
   },
+  translatedName: 'Code Smells',
   value: '1.2k'
 };
 
index a43f2d4b0fb89d2faa86f2f0b2cabceb151719ad..8cc911548dca2d71f05cf6bec60e7668980a0680 100644 (file)
@@ -42,7 +42,7 @@ exports[`should render correctly for overview graphs 1`] = `
               ],
               "name": "code_smells",
               "style": 1,
-              "translatedName": "Code Smells",
+              "translatedName": "metric.code_smells.name",
             }
           }
           tooltipIdx={0}
@@ -64,7 +64,7 @@ exports[`should render correctly for overview graphs 1`] = `
               ],
               "name": "bugs",
               "style": 0,
-              "translatedName": "Bugs",
+              "translatedName": "metric.bugs.name",
             }
           }
           tooltipIdx={0}
@@ -86,7 +86,7 @@ exports[`should render correctly for overview graphs 1`] = `
               ],
               "name": "vulnerabilities",
               "style": 2,
-              "translatedName": "Vulnerabilities",
+              "translatedName": "metric.vulnerabilities.name",
             }
           }
           tooltipIdx={0}
@@ -139,9 +139,10 @@ exports[`should render correctly for random graphs 1`] = `
               ],
               "name": "code_smells",
               "style": 1,
-              "translatedName": "Code Smells",
+              "translatedName": "metric.code_smells.name",
             }
           }
+          translatedName="metric.code_smells.name"
           value="Formated.15"
         />
         <GraphsTooltipsContent
@@ -159,9 +160,10 @@ exports[`should render correctly for random graphs 1`] = `
               ],
               "name": "bugs",
               "style": 0,
-              "translatedName": "Bugs",
+              "translatedName": "metric.bugs.name",
             }
           }
+          translatedName="metric.bugs.name"
           value="Formated.0"
         />
         <GraphsTooltipsContent
@@ -179,9 +181,10 @@ exports[`should render correctly for random graphs 1`] = `
               ],
               "name": "vulnerabilities",
               "style": 2,
-              "translatedName": "Vulnerabilities",
+              "translatedName": "metric.vulnerabilities.name",
             }
           }
+          translatedName="Vulnerabilities"
           value="Formated.1"
         />
       </tbody>
index 91b035a151ba98bf80d8b637833e9c0af635a319..ccb7e7671961a4edcf64a2c081d85fce2f272452 100644 (file)
@@ -60,6 +60,9 @@ table.nowrap td, td.nowrap, th.nowrap { white-space: nowrap; }
 .little-spacer-bottom { margin-bottom: 4px; }
 .little-spacer-top    { margin-top: 4px; }
 
+td.little-spacer-left   { padding-left: 4px; }
+td.little-spacer-right  { padding-right: 4px; }
+
 td.spacer-left   { padding-left: 8px; }
 td.spacer-right  { padding-right: 8px; }
 td.spacer-bottom { padding-bottom: 8px; }