]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9546 Sync tooltips from the two graphs
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 17 Jul 2017 15:26:44 +0000 (17:26 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Wed, 19 Jul 2017 08:10:10 +0000 (10:10 +0200)
server/sonar-web/src/main/js/apps/projectActivity/components/GraphHistory.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphHistory-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsHistory-test.js
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityGraphs-test.js
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphHistory-test.js.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsHistory-test.js.snap
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityGraphs-test.js.snap
server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css
server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js

diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphHistory.js b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphHistory.js
new file mode 100644 (file)
index 0000000..64cbfe5
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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 { 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 type { Event, MeasureHistory } from '../types';
+import type { Serie } from '../../../components/charts/AdvancedTimeline';
+
+type Props = {
+  events: Array<Event>,
+  graph: string,
+  graphEndDate: ?Date,
+  graphStartDate: ?Date,
+  leakPeriodDate: Date,
+  isCustom: boolean,
+  measuresHistory: Array<MeasureHistory>,
+  metricsType: string,
+  removeCustomMetric: (metric: string) => void,
+  showAreas: boolean,
+  series: Array<Serie>,
+  selectedDate?: ?Date,
+  updateGraphZoom: (from: ?Date, to: ?Date) => void,
+  updateSelectedDate: (selectedDate: ?Date) => void,
+  updateTooltip: (selectedDate: ?Date) => void
+};
+
+type State = {
+  tooltipIdx: ?number,
+  tooltipXPos: ?number
+};
+
+export default class GraphHistory extends React.PureComponent {
+  props: Props;
+  state: State = {
+    tooltipIdx: null,
+    tooltipXPos: null
+  };
+
+  formatValue = (tick: string | number) =>
+    formatMeasure(tick, getShortType(this.props.metricsType));
+
+  updateTooltip = (selectedDate: ?Date, tooltipXPos: ?number, tooltipIdx: ?number) => {
+    this.props.updateTooltip(selectedDate);
+    this.setState({ tooltipXPos, tooltipIdx });
+  };
+
+  render() {
+    const { graph, selectedDate, series } = this.props;
+    const { tooltipIdx, tooltipXPos } = this.state;
+
+    return (
+      <div className="project-activity-graph-container">
+        {this.props.isCustom
+          ? <GraphsLegendCustom series={series} removeMetric={this.props.removeCustomMetric} />
+          : <GraphsLegendStatic series={series} />}
+        <div className="project-activity-graph">
+          <AutoSizer>
+            {({ height, width }) =>
+              <div>
+                <AdvancedTimeline
+                  endDate={this.props.graphEndDate}
+                  height={height}
+                  width={width}
+                  interpolate="linear"
+                  formatYTick={this.formatValue}
+                  leakPeriodDate={this.props.leakPeriodDate}
+                  metricType={this.props.metricsType}
+                  selectedDate={selectedDate}
+                  series={series}
+                  showAreas={this.props.showAreas}
+                  startDate={this.props.graphStartDate}
+                  updateSelectedDate={this.props.updateSelectedDate}
+                  updateTooltip={this.updateTooltip}
+                  updateZoom={this.props.updateGraphZoom}
+                />
+                {selectedDate != null &&
+                  tooltipXPos != null &&
+                  <GraphsTooltips
+                    events={this.props.events}
+                    formatValue={this.formatValue}
+                    graph={graph}
+                    graphWidth={width}
+                    measuresHistory={this.props.measuresHistory}
+                    selectedDate={selectedDate}
+                    series={series}
+                    tooltipIdx={tooltipIdx}
+                    tooltipPos={tooltipXPos}
+                  />}
+              </div>}
+          </AutoSizer>
+        </div>
+      </div>
+    );
+  }
+}
index bb72897ea26b8780d9921ba3ccbad00c4096edfd..3fae4284ddda5a44abf9c4c2877c7dc00db04d05 100644 (file)
  */
 import React from 'react';
 import moment from 'moment';
-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, isCustomGraph } from '../utils';
+import { isEqual, sortBy } from 'lodash';
+import GraphHistory from './GraphHistory';
+import { EVENT_TYPES, getSeriesMetricType, hasHistoryData, isCustomGraph } from '../utils';
+import { translate } from '../../../helpers/l10n';
 import type { Analysis, MeasureHistory } from '../types';
 import type { Serie } from '../../../components/charts/AdvancedTimeline';
 
@@ -34,11 +30,12 @@ type Props = {
   analyses: Array<Analysis>,
   eventFilter: string,
   graph: string,
+  graphs: Array<Array<Serie>>,
   graphEndDate: ?Date,
   graphStartDate: ?Date,
   leakPeriodDate: Date,
+  loading: boolean,
   measuresHistory: Array<MeasureHistory>,
-  metricsType: string,
   removeCustomMetric: (metric: string) => void,
   selectedDate: ?Date,
   series: Array<Serie>,
@@ -47,20 +44,25 @@ type Props = {
 };
 
 type State = {
-  selectedDate?: ?Date,
-  tooltipIdx: ?number,
-  tooltipXPos: ?number
+  selectedDate?: ?Date
 };
 
 export default class GraphsHistory extends React.PureComponent {
   props: Props;
-  state: State = {
-    tooltipIdx: null,
-    tooltipXPos: null
-  };
+  state: State;
 
-  formatValue = (tick: string | number) =>
-    formatMeasure(tick, getShortType(this.props.metricsType));
+  constructor(props: Props) {
+    super(props);
+    this.state = {
+      selectedDate: props.selectedDate
+    };
+  }
+
+  componentWillReceiveProps(nextProps: Props) {
+    if (!isEqual(nextProps.selectedDate, this.props.selectedDate)) {
+      this.setState({ selectedDate: nextProps.selectedDate });
+    }
+  }
 
   getEvents = () => {
     const { analyses, eventFilter } = this.props;
@@ -100,54 +102,59 @@ export default class GraphsHistory extends React.PureComponent {
     return [];
   };
 
-  updateTooltip = (selectedDate: ?Date, tooltipXPos: ?number, tooltipIdx: ?number) =>
-    this.setState({ selectedDate, tooltipXPos, tooltipIdx });
+  updateTooltip = (selectedDate: ?Date) => this.setState({ selectedDate });
 
   render() {
     const { graph, series } = this.props;
     const isCustom = isCustomGraph(graph);
-    const { selectedDate, tooltipIdx, tooltipXPos } = this.state;
-    return (
-      <div className="project-activity-graph-container">
-        {isCustom
-          ? <GraphsLegendCustom series={series} removeMetric={this.props.removeCustomMetric} />
-          : <GraphsLegendStatic series={series} />}
-        <div className="project-activity-graph">
-          <AutoSizer>
-            {({ height, width }) =>
-              <div>
-                <AdvancedTimeline
-                  endDate={this.props.graphEndDate}
-                  height={height}
-                  width={width}
-                  interpolate="linear"
-                  formatYTick={this.formatValue}
-                  leakPeriodDate={this.props.leakPeriodDate}
-                  metricType={this.props.metricsType}
-                  selectedDate={this.props.selectedDate}
-                  series={series}
-                  showAreas={['coverage', 'duplications'].includes(graph)}
-                  startDate={this.props.graphStartDate}
-                  updateSelectedDate={this.props.updateSelectedDate}
-                  updateTooltip={this.updateTooltip}
-                  updateZoom={this.props.updateGraphZoom}
-                />
-                {selectedDate != null &&
-                  tooltipXPos != null &&
-                  <GraphsTooltips
-                    events={this.getSelectedDateEvents()}
-                    formatValue={this.formatValue}
-                    graph={graph}
-                    graphWidth={width}
-                    measuresHistory={this.props.measuresHistory}
-                    selectedDate={selectedDate}
-                    series={series}
-                    tooltipIdx={tooltipIdx}
-                    tooltipPos={tooltipXPos}
-                  />}
-              </div>}
-          </AutoSizer>
+
+    if (this.props.loading) {
+      return (
+        <div className="project-activity-graph-container">
+          <div className="text-center">
+            <i className="spinner" />
+          </div>
         </div>
+      );
+    }
+
+    if (!hasHistoryData(series)) {
+      return (
+        <div className="project-activity-graph-container">
+          <div className="note text-center">
+            {translate(
+              isCustom
+                ? 'project_activity.graphs.custom.no_history'
+                : 'component_measures.no_history'
+            )}
+          </div>
+        </div>
+      );
+    }
+    const events = this.getSelectedDateEvents();
+    const showAreas = ['coverage', 'duplications'].includes(graph);
+    return (
+      <div className="project-activity-graphs">
+        {this.props.graphs.map((series, idx) =>
+          <GraphHistory
+            key={idx}
+            events={events}
+            graph={graph}
+            graphEndDate={this.props.graphEndDate}
+            graphStartDate={this.props.graphStartDate}
+            isCustom={isCustom}
+            leakPeriodDate={this.props.leakPeriodDate}
+            measuresHistory={this.props.measuresHistory}
+            metricsType={getSeriesMetricType(series)}
+            removeCustomMetric={this.props.removeCustomMetric}
+            selectedDate={this.state.selectedDate}
+            series={series}
+            showAreas={showAreas}
+            updateGraphZoom={this.props.updateGraphZoom}
+            updateSelectedDate={this.props.updateSelectedDate}
+            updateTooltip={this.updateTooltip}
+          />
+        )}
       </div>
     );
   }
index 80e881c755ac100989e0e3b7dca76b47f1cb2732..a743645085c1a4657c860940bca3f2f6f4937703 100644 (file)
@@ -30,10 +30,8 @@ import {
   generateSeries,
   getDisplayedHistoryMetrics,
   getSeriesMetricType,
-  hasHistoryData,
   historyQueryChanged
 } from '../utils';
-import { translate } from '../../../helpers/l10n';
 import type { RawQuery } from '../../../helpers/query';
 import type { Analysis, MeasureHistory, Metric, Query } from '../types';
 import type { Serie } from '../../../components/charts/AdvancedTimeline';
@@ -192,55 +190,6 @@ export default class ProjectActivityGraphs extends React.PureComponent {
     }
   };
 
-  renderGraphs() {
-    const { leakPeriodDate, loading, query } = this.props;
-    const { graphEndDate, graphs, graphStartDate, series } = this.state;
-    const isCustom = isCustomGraph(query.graph);
-
-    if (loading) {
-      return (
-        <div className="project-activity-graph-container">
-          <div className="text-center">
-            <i className="spinner" />
-          </div>
-        </div>
-      );
-    }
-
-    if (!hasHistoryData(series)) {
-      return (
-        <div className="project-activity-graph-container">
-          <div className="note text-center">
-            {translate(
-              isCustom
-                ? 'project_activity.graphs.custom.no_history'
-                : 'component_measures.no_history'
-            )}
-          </div>
-        </div>
-      );
-    }
-
-    return graphs.map((series, idx) =>
-      <GraphsHistory
-        key={idx}
-        analyses={this.props.analyses}
-        eventFilter={query.category}
-        graph={query.graph}
-        graphEndDate={graphEndDate}
-        graphStartDate={graphStartDate}
-        leakPeriodDate={leakPeriodDate}
-        measuresHistory={this.props.measuresHistory}
-        metricsType={getSeriesMetricType(series)}
-        removeCustomMetric={this.removeCustomMetric}
-        selectedDate={this.props.query.selectedDate}
-        series={series}
-        updateGraphZoom={this.updateGraphZoom}
-        updateSelectedDate={this.updateSelectedDate}
-      />
-    );
-  }
-
   render() {
     const { leakPeriodDate, loading, metrics, query } = this.props;
     const { graphEndDate, graphStartDate, series } = this.state;
@@ -255,7 +204,22 @@ export default class ProjectActivityGraphs extends React.PureComponent {
           selectedMetrics={this.props.query.customMetrics}
           updateGraph={this.updateGraph}
         />
-        {this.renderGraphs()}
+        <GraphsHistory
+          analyses={this.props.analyses}
+          eventFilter={query.category}
+          graph={query.graph}
+          graphs={this.state.graphs}
+          graphEndDate={graphEndDate}
+          graphStartDate={graphStartDate}
+          leakPeriodDate={leakPeriodDate}
+          loading={loading}
+          measuresHistory={this.props.measuresHistory}
+          removeCustomMetric={this.removeCustomMetric}
+          selectedDate={this.props.query.selectedDate}
+          series={series}
+          updateGraphZoom={this.updateGraphZoom}
+          updateSelectedDate={this.updateSelectedDate}
+        />
         <GraphsZoom
           graphEndDate={graphEndDate}
           graphStartDate={graphStartDate}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphHistory-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphHistory-test.js
new file mode 100644 (file)
index 0000000..adeeb1a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 GraphHistory from '../GraphHistory';
+
+const SERIES = [
+  {
+    name: 'bugs',
+    translatedName: 'metric.bugs.name',
+    data: [
+      { x: new Date('2016-10-27T16:33:50+0200'), y: 5 },
+      { x: new Date('2016-10-27T12:21:15+0200'), y: 16 },
+      { x: new Date('2016-10-26T12:17:29+0200'), y: 12 }
+    ]
+  }
+];
+
+const DEFAULT_PROPS = {
+  events: [],
+  graph: 'overview',
+  graphEndDate: null,
+  graphStartDate: null,
+  leakPeriodDate: '2017-05-16T13:50:02+0200',
+  isCustom: false,
+  measuresHistory: [],
+  metrics: [],
+  metricsType: 'INT',
+  removeCustomMetric: () => {},
+  showAreas: true,
+  selectedDate: null,
+  series: SERIES,
+  updateGraphZoom: () => {},
+  updateSelectedDate: () => {},
+  updateTooltip: () => {}
+};
+
+it('should correctly render a graph', () => {
+  expect(shallow(<GraphHistory {...DEFAULT_PROPS} />)).toMatchSnapshot();
+});
index ab4fec25fb008a72abbbc395757c640b8dfdb545..ea9e7c419b095a5a8ade2f682661cede3c58710c 100644 (file)
@@ -72,11 +72,12 @@ const DEFAULT_PROPS = {
   analyses: ANALYSES,
   eventFilter: '',
   graph: 'overview',
+  graphs: [SERIES],
   graphEndDate: null,
   graphStartDate: null,
   leakPeriodDate: '2017-05-16T13:50:02+0200',
+  loading: false,
   measuresHistory: [],
-  metricsType: 'INT',
   removeCustomMetric: () => {},
   selectedDate: null,
   series: SERIES,
@@ -88,9 +89,37 @@ it('should correctly render a graph', () => {
   expect(shallow(<GraphsHistory {...DEFAULT_PROPS} />)).toMatchSnapshot();
 });
 
+it('should correctly render multiple graphs', () => {
+  expect(shallow(<GraphsHistory {...DEFAULT_PROPS} graphs={[SERIES, SERIES]} />)).toMatchSnapshot();
+});
+
 it('should correctly filter events', () => {
   expect(shallow(<GraphsHistory {...DEFAULT_PROPS} />).instance().getEvents()).toMatchSnapshot();
   expect(
     shallow(<GraphsHistory {...DEFAULT_PROPS} eventFilter="OTHER" />).instance().getEvents()
   ).toMatchSnapshot();
 });
+
+it('should show a loading view instead of the graph', () => {
+  expect(
+    shallow(<GraphsHistory {...DEFAULT_PROPS} loading={true} />).find('.spinner')
+  ).toHaveLength(1);
+});
+
+it('should show that there is no history data', () => {
+  expect(shallow(<GraphsHistory {...DEFAULT_PROPS} series={[]} />)).toMatchSnapshot();
+  expect(
+    shallow(
+      <GraphsHistory
+        {...DEFAULT_PROPS}
+        series={[
+          {
+            name: 'bugs',
+            translatedName: 'metric.bugs.name',
+            data: [{ x: new Date('2016-10-27T16:33:50+0200'), y: undefined }]
+          }
+        ]}
+      />
+    )
+  ).toMatchSnapshot();
+});
index 69327953ec2dfb46dae1a73b77d7e317ed45593b..4a6f3ba02e27652caf2f62ca97f8132dff625663 100644 (file)
@@ -90,39 +90,3 @@ it('should render correctly with filter history on dates', () => {
   );
   expect(wrapper.state()).toMatchSnapshot();
 });
-
-it('should show a loading view instead of the graph', () => {
-  expect(
-    shallow(<ProjectActivityGraphs {...DEFAULT_PROPS} loading={true} />).find('.spinner')
-  ).toHaveLength(1);
-});
-
-it('should show that there is no history data', () => {
-  expect(
-    shallow(
-      <ProjectActivityGraphs
-        {...DEFAULT_PROPS}
-        measuresHistory={[{ metric: 'code_smells', history: [] }]}
-      />
-    )
-  ).toMatchSnapshot();
-  expect(
-    shallow(
-      <ProjectActivityGraphs
-        {...DEFAULT_PROPS}
-        measuresHistory={[
-          {
-            metric: 'code_smells',
-            history: [{ date: new Date('2016-10-26T12:17:29+0200'), value: undefined }]
-          }
-        ]}
-        query={{
-          category: '',
-          graph: 'custom',
-          project: 'org.sonarsource.sonarqube:sonarqube',
-          customMetrics: ['code_smells']
-        }}
-      />
-    )
-  ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphHistory-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphHistory-test.js.snap
new file mode 100644 (file)
index 0000000..2b9e964
--- /dev/null
@@ -0,0 +1,39 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should correctly render a graph 1`] = `
+<div
+  className="project-activity-graph-container"
+>
+  <GraphsLegendStatic
+    series={
+      Array [
+        Object {
+          "data": Array [
+            Object {
+              "x": 2016-10-27T14:33:50.000Z,
+              "y": 5,
+            },
+            Object {
+              "x": 2016-10-27T10:21:15.000Z,
+              "y": 16,
+            },
+            Object {
+              "x": 2016-10-26T10:17:29.000Z,
+              "y": 12,
+            },
+          ],
+          "name": "bugs",
+          "translatedName": "metric.bugs.name",
+        },
+      ]
+    }
+  />
+  <div
+    className="project-activity-graph"
+  >
+    <AutoSizer
+      onResize={[Function]}
+    />
+  </div>
+</div>
+`;
index 7f82cd14330d15e5fb72c4a37094a4825a7fa2e2..0621e71f0290ced90e8a4b249f5b1d2018ef8f0d 100644 (file)
@@ -27,9 +27,62 @@ Array [
 
 exports[`should correctly render a graph 1`] = `
 <div
-  className="project-activity-graph-container"
+  className="project-activity-graphs"
+>
+  <GraphHistory
+    events={Array []}
+    graph="overview"
+    graphEndDate={null}
+    graphStartDate={null}
+    isCustom={false}
+    leakPeriodDate="2017-05-16T13:50:02+0200"
+    measuresHistory={Array []}
+    removeCustomMetric={[Function]}
+    selectedDate={null}
+    series={
+      Array [
+        Object {
+          "data": Array [
+            Object {
+              "x": 2016-10-27T14:33:50.000Z,
+              "y": 5,
+            },
+            Object {
+              "x": 2016-10-27T10:21:15.000Z,
+              "y": 16,
+            },
+            Object {
+              "x": 2016-10-26T10:17:29.000Z,
+              "y": 12,
+            },
+          ],
+          "name": "bugs",
+          "translatedName": "metric.bugs.name",
+        },
+      ]
+    }
+    showAreas={false}
+    updateGraphZoom={[Function]}
+    updateSelectedDate={[Function]}
+    updateTooltip={[Function]}
+  />
+</div>
+`;
+
+exports[`should correctly render multiple graphs 1`] = `
+<div
+  className="project-activity-graphs"
 >
-  <GraphsLegendStatic
+  <GraphHistory
+    events={Array []}
+    graph="overview"
+    graphEndDate={null}
+    graphStartDate={null}
+    isCustom={false}
+    leakPeriodDate="2017-05-16T13:50:02+0200"
+    measuresHistory={Array []}
+    removeCustomMetric={[Function]}
+    selectedDate={null}
     series={
       Array [
         Object {
@@ -52,13 +105,71 @@ exports[`should correctly render a graph 1`] = `
         },
       ]
     }
+    showAreas={false}
+    updateGraphZoom={[Function]}
+    updateSelectedDate={[Function]}
+    updateTooltip={[Function]}
   />
+  <GraphHistory
+    events={Array []}
+    graph="overview"
+    graphEndDate={null}
+    graphStartDate={null}
+    isCustom={false}
+    leakPeriodDate="2017-05-16T13:50:02+0200"
+    measuresHistory={Array []}
+    removeCustomMetric={[Function]}
+    selectedDate={null}
+    series={
+      Array [
+        Object {
+          "data": Array [
+            Object {
+              "x": 2016-10-27T14:33:50.000Z,
+              "y": 5,
+            },
+            Object {
+              "x": 2016-10-27T10:21:15.000Z,
+              "y": 16,
+            },
+            Object {
+              "x": 2016-10-26T10:17:29.000Z,
+              "y": 12,
+            },
+          ],
+          "name": "bugs",
+          "translatedName": "metric.bugs.name",
+        },
+      ]
+    }
+    showAreas={false}
+    updateGraphZoom={[Function]}
+    updateSelectedDate={[Function]}
+    updateTooltip={[Function]}
+  />
+</div>
+`;
+
+exports[`should show that there is no history data 1`] = `
+<div
+  className="project-activity-graph-container"
+>
+  <div
+    className="note text-center"
+  >
+    component_measures.no_history
+  </div>
+</div>
+`;
+
+exports[`should show that there is no history data 2`] = `
+<div
+  className="project-activity-graph-container"
+>
   <div
-    className="project-activity-graph"
+    className="note text-center"
   >
-    <AutoSizer
-      onResize={[Function]}
-    />
+    component_measures.no_history
   </div>
 </div>
 `;
index 3d4be8af2fadcf66cf25cad03c88e742e962802e..5fccf4aef7cf52772a6ef65d625e012d18b54900 100644 (file)
@@ -60,7 +60,33 @@ exports[`should render correctly the graph and legends 1`] = `
     graph="overview"
     graphEndDate={null}
     graphStartDate={null}
+    graphs={
+      Array [
+        Array [
+          Object {
+            "data": Array [
+              Object {
+                "x": 2016-10-26T10:17:29.000Z,
+                "y": 2286,
+              },
+              Object {
+                "x": 2016-10-27T10:21:15.000Z,
+                "y": 1749,
+              },
+              Object {
+                "x": 2016-10-27T14:33:50.000Z,
+                "y": 500,
+              },
+            ],
+            "name": "code_smells",
+            "translatedName": "Code Smells",
+            "type": "INT",
+          },
+        ],
+      ]
+    }
     leakPeriodDate="2017-05-16T13:50:02+0200"
+    loading={false}
     measuresHistory={
       Array [
         Object {
@@ -82,7 +108,6 @@ exports[`should render correctly the graph and legends 1`] = `
         },
       ]
     }
-    metricsType="INT"
     removeCustomMetric={[Function]}
     series={
       Array [
@@ -195,113 +220,3 @@ Object {
   ],
 }
 `;
-
-exports[`should show that there is no history data 1`] = `
-<div
-  className="project-activity-layout-page-main-inner boxed-group boxed-group-inner"
->
-  <ProjectActivityGraphsHeader
-    addCustomMetric={[Function]}
-    graph="overview"
-    metrics={
-      Array [
-        Object {
-          "key": "code_smells",
-          "name": "Code Smells",
-          "type": "INT",
-        },
-      ]
-    }
-    metricsTypeFilter={null}
-    updateGraph={[Function]}
-  />
-  <div
-    className="project-activity-graph-container"
-  >
-    <div
-      className="note text-center"
-    >
-      component_measures.no_history
-    </div>
-  </div>
-  <GraphsZoom
-    graphEndDate={null}
-    graphStartDate={null}
-    leakPeriodDate="2017-05-16T13:50:02+0200"
-    loading={false}
-    metricsType="INT"
-    series={
-      Array [
-        Object {
-          "data": Array [],
-          "name": "code_smells",
-          "translatedName": "Code Smells",
-          "type": "INT",
-        },
-      ]
-    }
-    showAreas={false}
-    updateGraphZoom={[Function]}
-  />
-</div>
-`;
-
-exports[`should show that there is no history data 2`] = `
-<div
-  className="project-activity-layout-page-main-inner boxed-group boxed-group-inner"
->
-  <ProjectActivityGraphsHeader
-    addCustomMetric={[Function]}
-    graph="custom"
-    metrics={
-      Array [
-        Object {
-          "key": "code_smells",
-          "name": "Code Smells",
-          "type": "INT",
-        },
-      ]
-    }
-    metricsTypeFilter={null}
-    selectedMetrics={
-      Array [
-        "code_smells",
-      ]
-    }
-    updateGraph={[Function]}
-  />
-  <div
-    className="project-activity-graph-container"
-  >
-    <div
-      className="note text-center"
-    >
-      project_activity.graphs.custom.no_history
-    </div>
-  </div>
-  <GraphsZoom
-    graphEndDate={null}
-    graphStartDate={null}
-    leakPeriodDate="2017-05-16T13:50:02+0200"
-    loading={false}
-    metricsType="INT"
-    series={
-      Array [
-        Object {
-          "data": Array [
-            Object {
-              "x": 2016-10-26T10:17:29.000Z,
-              "y": NaN,
-            },
-          ],
-          "name": "code_smells",
-          "translatedName": "Code Smells",
-          "type": "INT",
-        },
-      ]
-    }
-    showAreas={false}
-    updateGraphZoom={[Function]}
-  />
-</div>
-`;
index 5ef705363f2655c453197b8ae14af106b1767419..8ef83fa028c3b9ad6181ace0045ed4b796cbcebe 100644 (file)
   padding-top: 52px;
 }
 
+.project-activity-graphs {
+  flex-grow: 1;
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  justify-content: center;
+}
+
 .project-activity-graph-container {
   padding: 10px 0;
   flex-grow: 1;
index 872a1a8bee6548c704393922c7c31fe3c5dc1ed7..9578a6726f62f1b2c4c237d95c2de4da07ee16c8 100644 (file)
@@ -168,7 +168,7 @@ export default class AdvancedTimeline extends React.PureComponent {
         // $FlowFixMe selectedDate can't be null there
         p => p.x.valueOf() === selectedDate.valueOf()
       );
-      const xRange = xScale.range();
+      const xRange = xScale.range().sort();
       const xPos = xScale(selectedDate);
       if (idx >= 0 && xPos >= xRange[0] && xPos <= xRange[1]) {
         return {