]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6331 make it possible to display a timeline on RATING and LEVEL measures
authorStas Vilchik <vilchiks@gmail.com>
Fri, 13 Nov 2015 16:40:16 +0000 (17:40 +0100)
committerStas Vilchik <vilchiks@gmail.com>
Fri, 13 Nov 2015 16:40:16 +0000 (17:40 +0100)
server/sonar-web/src/main/js/apps/overview/components/domain-timeline.js
server/sonar-web/src/main/js/apps/overview/components/timeline-chart.js
server/sonar-web/tests/apps/overview/components/timeline-chart-test.js

index 62d4ab1f9f99e1562666eb601c15331664d33a4a..f58e536ddaf49865060d4498c1cfe851053a28b4 100644 (file)
@@ -133,6 +133,7 @@ export const DomainTimeline = React.createClass({
     return <div className={'overview-timeline-' + index}>
       <Timeline key={metric}
                 data={data}
+                metricType={metricType}
                 events={this.state.events}
                 height={HEIGHT}
                 interpolate="linear"
index 2b3947c04a5d7dda385a54b5c4b8f152fe71b968..3453d64918a0a30eba3d467ba32941d9def7defb 100644 (file)
@@ -28,8 +28,34 @@ export const Timeline = React.createClass({
     return { width: this.props.width, height: this.props.height };
   },
 
+  getRatingScale(availableHeight) {
+    return d3.scale.ordinal()
+        .domain([5, 4, 3, 2, 1])
+        .rangePoints([availableHeight, 0]);
+  },
+
+  getLevelScale(availableHeight) {
+    return d3.scale.ordinal()
+        .domain(['ERROR', 'WARN', 'OK'])
+        .rangePoints([availableHeight, 0]);
+  },
+
+  getYScale(availableHeight) {
+    if (this.props.metricType === 'RATING') {
+      return this.getRatingScale(availableHeight);
+    } else if (this.props.metricType === 'LEVEL') {
+      return this.getLevelScale(availableHeight);
+    } else {
+      return d3.scale.linear()
+          .range([availableHeight, 0])
+          .domain([0, d3.max(this.props.data, d => d.y || 0)])
+          .nice();
+    }
+  },
+
   renderHorizontalGrid (xScale, yScale) {
-    let ticks = yScale.ticks(4);
+    let hasTicks = typeof yScale.ticks === 'function';
+    let ticks = hasTicks ? yScale.ticks(4) : yScale.domain();
     if (!ticks.length) {
       ticks.push(yScale.domain()[1]);
     }
@@ -69,9 +95,9 @@ export const Timeline = React.createClass({
     }
     let opts = {
       x: xScale(this.props.leakPeriodDate),
-      y: yScale.range()[1],
+      y: _.last(yScale.range()),
       width: xScale.range()[1] - xScale(this.props.leakPeriodDate),
-      height: yScale.range()[0] - yScale.range()[1],
+      height: _.first(yScale.range()) - _.last(yScale.range()),
       fill: '#fffae7'
     };
     return <rect {...opts}/>;
@@ -118,10 +144,7 @@ export const Timeline = React.createClass({
         .domain(d3.extent(this.props.data, d => d.x || 0))
         .range([0, availableWidth])
         .clamp(true);
-    let yScale = d3.scale.linear()
-        .range([availableHeight, 0])
-        .domain([0, d3.max(this.props.data, d => d.y || 0)])
-        .nice();
+    let yScale = this.getYScale(availableHeight);
 
     return <svg className="line-chart" width={this.state.width} height={this.state.height}>
       <g transform={`translate(${this.props.padding[3]}, ${this.props.padding[0]})`}>
index 82d7d66a593fe2afed29ceea9f3bd9b72fa3917a..3aae4e12c6471b89c872f6017b4b9779f861fdd6 100644 (file)
@@ -23,6 +23,44 @@ const FORMAT = (tick) => tick;
 
 
 describe('TimelineChart', function () {
+  it('should work with LEVEL', function () {
+    const DATA = [
+      { x: new Date(2015, 0, 1), y: 'OK' },
+      { x: new Date(2015, 0, 2), y: 'WARN' },
+      { x: new Date(2015, 0, 3), y: 'ERROR' },
+      { x: new Date(2015, 0, 4), y: 'WARN' }
+    ];
+
+    let timeline = <Timeline width={100} height={100} data={DATA} metricType="LEVEL" events={[]}
+                             formatYTick={FORMAT}/>;
+    let output = TestUtils.renderIntoDocument(timeline);
+    let ticks = TestUtils.scryRenderedDOMComponentsWithClass(output, 'line-chart-tick-x');
+    expect(ticks).to.have.length(3);
+    expect(ticks[0].textContent).to.equal('ERROR');
+    expect(ticks[1].textContent).to.equal('WARN');
+    expect(ticks[2].textContent).to.equal('OK');
+  });
+
+  it('should work with RATING', function () {
+    const DATA = [
+      { x: new Date(2015, 0, 1), y: 1 },
+      { x: new Date(2015, 0, 2), y: 3 },
+      { x: new Date(2015, 0, 3), y: 1 },
+      { x: new Date(2015, 0, 4), y: 4 }
+    ];
+
+    let timeline = <Timeline width={100} height={100} data={DATA} metricType="RATING" events={[]}
+                             formatYTick={FORMAT}/>;
+    let output = TestUtils.renderIntoDocument(timeline);
+    let ticks = TestUtils.scryRenderedDOMComponentsWithClass(output, 'line-chart-tick-x');
+    expect(ticks).to.have.length(5);
+    expect(ticks[0].textContent).to.equal('5');
+    expect(ticks[1].textContent).to.equal('4');
+    expect(ticks[2].textContent).to.equal('3');
+    expect(ticks[3].textContent).to.equal('2');
+    expect(ticks[4].textContent).to.equal('1');
+  });
+
   it('should display the zero Y tick if all values are zero', function () {
     let timeline = <Timeline width={100} height={100} data={ZERO_DATA} events={[]} formatYTick={FORMAT}/>;
     let output = TestUtils.renderIntoDocument(timeline);