]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6331 apply feedback
authorStas Vilchik <vilchiks@gmail.com>
Wed, 8 Apr 2015 12:13:10 +0000 (14:13 +0200)
committerStas Vilchik <vilchiks@gmail.com>
Wed, 8 Apr 2015 12:27:22 +0000 (14:27 +0200)
28 files changed:
server/sonar-web/src/main/hbs/overview/_overview-gate-condition.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/overview/overview-coverage.hbs
server/sonar-web/src/main/hbs/overview/overview-debt.hbs [new file with mode: 0644]
server/sonar-web/src/main/hbs/overview/overview-duplications.hbs
server/sonar-web/src/main/hbs/overview/overview-gate.hbs
server/sonar-web/src/main/hbs/overview/overview-issues.hbs
server/sonar-web/src/main/hbs/overview/overview-main-layout.hbs
server/sonar-web/src/main/hbs/overview/overview-size.hbs
server/sonar-web/src/main/js/application.js
server/sonar-web/src/main/js/common/handlebars-extensions.js
server/sonar-web/src/main/js/graphics/sparkline.js
server/sonar-web/src/main/js/overview/app.js
server/sonar-web/src/main/js/overview/controller.js
server/sonar-web/src/main/js/overview/main/coverage-view.js
server/sonar-web/src/main/js/overview/main/debt-view.js [new file with mode: 0644]
server/sonar-web/src/main/js/overview/main/duplications-view.js
server/sonar-web/src/main/js/overview/main/issues-view.js
server/sonar-web/src/main/js/overview/main/layout.js
server/sonar-web/src/main/js/overview/main/size-view.js
server/sonar-web/src/main/js/overview/models/state.js
server/sonar-web/src/main/js/overview/trend-view.js [new file with mode: 0644]
server/sonar-web/src/main/less/components/columns.less
server/sonar-web/src/main/less/pages/overview.less
server/sonar-web/src/test/js/overview.js
server/sonar-web/src/test/json/overview/measures.json
server/sonar-web/src/test/json/overview/timemachine.json
server/sonar-web/src/test/views/overview.jade
sonar-core/src/main/resources/org/sonar/l10n/core.properties

diff --git a/server/sonar-web/src/main/hbs/overview/_overview-gate-condition.hbs b/server/sonar-web/src/main/hbs/overview/_overview-gate-condition.hbs
new file mode 100644 (file)
index 0000000..c3c278b
--- /dev/null
@@ -0,0 +1,15 @@
+<li class="overview-gate-condition spacer-bottom text-ellipsis">
+  <i class="{{alertIconClass level}}"></i>
+  {{#canHaveDrilldownUrl metric period}}
+    <a href="{{urlForDrilldown ../../componentKey metric period periodDate}}"
+       class="overview-status overview-status-{{level}}"
+       title="{{#notEq level 'OK'}}{{t 'quality_gates.operator' op 'short'}} {{/notEq}}{{#eq level 'ERROR'}}{{formatMeasure error type}}{{/eq}}{{#eq level 'WARN'}}{{formatMeasure warning type}}{{/eq}}"
+       data-toggle="tooltip" data-placement="bottom">{{formatMeasure actual type}}</a>
+  {{else}}
+    <span class="overview-status overview-status-{{level}}"
+          title="{{#notEq level 'OK'}}{{t 'quality_gates.operator' op 'short'}} {{/notEq}}{{#eq level 'ERROR'}}{{formatMeasure error type}}{{/eq}}{{#eq level 'WARN'}}{{formatMeasure warning type}}{{/eq}}"
+          data-toggle="tooltip" data-placement="bottom">{{formatMeasure actual type}}</span>
+  {{/canHaveDrilldownUrl}}
+  <span class="note text-lowercase" style="padding-top: 4px;">{{t 'metric' metric 'name'}}</span>
+  <span class="note text-lowercase">{{default periodName period}}</span>
+</li>
index bdca7c4d95b39f69cfeadd92d389b05e9cfced30..ce3d7a411094ff49dfdb4038a7069367d56f89c4 100644 (file)
@@ -1,26 +1,25 @@
+<header class="overview-card-header page-header">
+  <h2 class="page-title">{{t 'overview.testing'}}</h2>
+</header>
+
 <div class="overview-highlight">
-  <h6 class="note">{{t 'overview.coverage'}}</h6>
+  <h6 class="note">{{t 'metric.coverage.name'}}</h6>
   <div class="overview-main-measure">
     {{#notNull coverage}}
-      <a href="{{urlForDrilldown componentKey 'overall_coverage'}}">{{formatMeasure coverage 'PERCENT'}}</a>
+      <a href="{{urlForDrilldown componentKey 'coverage'}}">{{formatMeasure coverage 'PERCENT'}}</a>
     {{else}}
       –
     {{/notNull}}
   </div>
-  {{#notNull coverage3}}
-    <div class="spacer-top">
-      <span class="overview-measure {{#gt coverage3 0}}text-success{{/gt}}{{#lt coverage3 0}}text-danger{{/lt}}">{{formatMeasureVariation coverage3 'PERCENT'}}</span>
-      <span class="note">{{period3Name}}</span>
-    </div>
-  {{/notNull}}
   {{#notNull newCoverage3}}
-    <div class="spacer-top">
-      <a class="overview-measure spacer-top" href="{{urlForDrilldown componentKey 'new_overall_coverage' 3}}">{{formatMeasure newCoverage3 'PERCENT'}}</a>
-      <span class="note">on new code</span>
-    </div>
+    <h6 class="note">{{period3Name}}</h6>
+    <a class="overview-measure spacer-top"
+       href="{{urlForDrilldown componentKey 'new_coverage' 3}}">{{formatMeasure newCoverage3 'PERCENT'}}</a>
+    <span class="note">{{t 'overview.on_new_code'}}</span>
   {{/notNull}}
 </div>
 
 <div class="overview-trend">
-  <div class="overview-sparkline" id="overview-coverage-trend" data-width="300" data-height="50" data-color="#f3ca8e" data-type="PERCENT"></div>
+  <div class="overview-sparkline" id="overview-coverage-trend" data-height="120" data-color="#f3ca8e"
+       data-type="PERCENT"></div>
 </div>
diff --git a/server/sonar-web/src/main/hbs/overview/overview-debt.hbs b/server/sonar-web/src/main/hbs/overview/overview-debt.hbs
new file mode 100644 (file)
index 0000000..6c4e644
--- /dev/null
@@ -0,0 +1,21 @@
+<header class="overview-card-header page-header">
+  <h2 class="page-title">{{t 'overview.debt'}}</h2>
+</header>
+
+<div class="overview-highlight">
+  <h6 class="note">{{t 'metric.sqale_index.name'}}</h6>
+  <div class="overview-main-measure">
+    <a href="{{urlForDrilldown componentKey 'sqale_index'}}">{{formatMeasure debt 'WORK_DUR'}}</a>
+  </div>
+  {{#notNull issues3}}
+    <h6 class="note">{{period3Name}}</h6>
+    <a href="{{urlForDrilldown componentKey 'new_technical_debt'}}"
+       class="overview-measure {{#gt newDebt 0}}text-danger{{else}}text-success{{/gt}}">{{formatMeasure newDebt 'WORK_DUR'}}</a>
+    <span class="note">{{t 'overview.new'}}</span>
+  {{/notNull}}
+</div>
+
+<div class="overview-trend">
+  <div class="overview-sparkline" id="overview-debt-trend" data-height="120" data-color="#f3ca8e"
+       data-type="WORK_DUR"></div>
+</div>
index 68b7ecf174821db0907a8ce8bce628564a0ba508..6c67559574881ec99ffe504915ee5e31a1ce2cf7 100644 (file)
@@ -1,19 +1,22 @@
+<header class="overview-card-header page-header">
+  <h2 class="page-title">{{t 'overview.duplications'}}</h2>
+</header>
+
 <div class="overview-highlight">
-  <h6 class="note">{{t 'overview.duplications'}}</h6>
+  <h6 class="note">{{t 'metric.duplicated_lines_density.short_name'}}</h6>
   <div class="overview-main-measure">
     <a href="{{urlForDrilldown componentKey 'duplicated_lines_density'}}">
       {{formatMeasure duplications 'PERCENT'}}
     </a>
   </div>
   {{#notNull duplications3}}
-    <div class="spacer-top">
-      <a class="overview-measure {{#gt duplications3 0}}text-danger{{/gt}}{{#lt duplications3 0}}text-success{{/lt}}"
-         href="{{urlForDrilldown componentKey 'duplicated_lines_density' 3}}">{{formatMeasureVariation duplications3 'PERCENT'}}</a>
-      <span class="note">{{period3Name}}</span>
-    </div>
+    <h6 class="note">{{period3Name}}</h6>
+    <a class="overview-measure {{#gt duplications3 0}}text-danger{{/gt}}{{#lt duplications3 0}}text-success{{/lt}}"
+       href="{{urlForDrilldown componentKey 'duplicated_lines_density' 3}}">{{formatMeasureVariation duplications3 'PERCENT'}}</a>
   {{/notNull}}
 </div>
 
 <div class="overview-trend">
-  <div class="overview-sparkline" id="overview-duplications-trend" data-width="300" data-height="50" data-color="#f3ca8e" data-type="PERCENT"></div>
+  <div class="overview-sparkline" id="overview-duplications-trend" data-height="120" data-color="#f3ca8e"
+       data-type="PERCENT"></div>
 </div>
index a43f972baaca0259bd2e48f40f5f7e2c7090df89..a354e431b1ef7a2d5f7c1fc8540af485fe46e1d6 100644 (file)
@@ -1,22 +1,22 @@
-<div class="text-center">
-  {{#notEmpty gateConditions}}
-    <ul class="list-inline spacer-top" style="display: inline-block;">
-      {{#each gateConditions}}
-        <li>
-          {{#canHaveDrilldownUrl metric period}}
-            <a href="{{urlForDrilldown ../../componentKey metric period periodDate}}"
-               class="overview-status overview-status-{{level}}"
-               title="{{#notEq level 'OK'}}{{t 'quality_gates.operator' op 'short'}} {{/notEq}}{{#eq level 'ERROR'}}{{formatMeasure error type}}{{/eq}}{{#eq level 'WARN'}}{{formatMeasure warning type}}{{/eq}}"
-               data-toggle="tooltip" data-placement="bottom">{{formatMeasure actual type}}</a>
-          {{else}}
-            <span class="overview-status overview-status-{{level}}"
-               title="{{#notEq level 'OK'}}{{t 'quality_gates.operator' op 'short'}} {{/notEq}}{{#eq level 'ERROR'}}{{formatMeasure error type}}{{/eq}}{{#eq level 'WARN'}}{{formatMeasure warning type}}{{/eq}}"
-               data-toggle="tooltip" data-placement="bottom">{{formatMeasure actual type}}</span>
-          {{/canHaveDrilldownUrl}}
-          <p class="note text-lowercase" style="padding-top: 4px;">{{t 'metric' metric 'name'}}</p>
-          <p class="note">{{default periodName period}}</p>
-        </li>
-      {{/each}}
-    </ul>
-  {{/notEmpty}}
-</div>
+<header class="overview-card-header page-header">
+  <h2 class="page-title">{{t 'overview.gate'}}</h2>
+</header>
+
+{{#notEmpty gateConditions}}
+  <div class="columns">
+    <div class="column-half">
+      <ul>
+        {{#eachEven gateConditions}}
+          {{> '_overview-gate-condition'}}
+        {{/eachEven}}
+      </ul>
+    </div>
+    <div class="column-half">
+      <ul>
+        {{#eachOdd gateConditions}}
+          {{> '_overview-gate-condition'}}
+        {{/eachOdd}}
+      </ul>
+    </div>
+  </div>
+{{/notEmpty}}
index ddc1ebdc3508432530cbab153e7e709822f37335..09940d8cc953b9ac348fab1b2043d13e8b53c0d5 100644 (file)
@@ -1,24 +1,21 @@
+<header class="overview-card-header page-header">
+  <h2 class="page-title">{{t 'overview.issues'}}</h2>
+</header>
+
 <div class="overview-highlight">
   <h6 class="note">{{t 'overview.issues'}}</h6>
   <div class="overview-main-measure">
-    <a href="{{urlForIssuesOverview componentKey}}">{{formatMeasure issues 'INT'}}</a>
-  </div>
-  <div class="spacer-top">
-    {{#notNull sqaleRating}}
-      <a class="overview-measure" href="{{urlForDrilldown componentKey 'sqale_rating'}}"><span class="rating rating-{{formatMeasure sqaleRating 'RATING'}}">{{formatMeasure sqaleRating 'RATING'}}</span></a>
-    {{/notNull}}
-    &nbsp;&nbsp;
-    <a class="overview-measure" href="{{urlForDrilldown componentKey 'sqale_index'}}">{{formatMeasure debt 'WORK_DUR'}}</a>
+    <a href="{{urlForIssuesOverview componentKey}}">{{formatMeasure issues 'SHORT_INT'}}</a>
   </div>
   {{#notNull issues3}}
-    <div class="spacer-top">
-      <a href="{{urlForIssuesOverview componentKey period3Date}}"
-         class="overview-measure {{#gt issues3 0}}text-danger{{else}}text-success{{/gt}}">{{formatMeasureVariation issues3 'INT'}}</a>
-      <span class="note">new {{period3Name}}</span>
-    </div>
+    <h6 class="note">{{period3Name}}</h6>
+    <a href="{{urlForIssuesOverview componentKey period3Date}}"
+       class="overview-measure {{#gt issues3 0}}text-danger{{else}}text-success{{/gt}}">{{formatMeasure issues3 'INT'}}</a>
+    <span class="note">{{t 'overview.new'}}</span>
   {{/notNull}}
 </div>
 
 <div class="overview-trend">
-  <div class="overview-sparkline" id="overview-issues-trend" data-width="300" data-height="50" data-color="#f3ca8e" data-type="INT"></div>
+  <div class="overview-sparkline" id="overview-issues-trend" data-height="120" data-color="#f3ca8e"
+       data-type="SHORT_INT"></div>
 </div>
index 8ce2a7d4e4f40b9ba53fc8f8e3ab04f9bdd61044..827246359f9bd31c86cda4398ac8bf2811237e48 100644 (file)
@@ -1,18 +1,12 @@
-<div class="overview-card overview-gate" id="overview-gate"></div>
-
-<div class="overview-container columns">
-  <div class="column-half">
-    <div class="overview-card" id="overview-size"></div>
-  </div>
+<div class="columns">
   <div class="column-half">
+    <div class="overview-card overview-gate" id="overview-gate"></div>
     <div class="overview-card" id="overview-issues"></div>
+    <div class="overview-card" id="overview-debt"></div>
   </div>
-</div>
-<div class="overview-container columns">
   <div class="column-half">
+    <div class="overview-card" id="overview-size"></div>
     <div class="overview-card" id="overview-coverage"></div>
-  </div>
-  <div class="column-half">
     <div class="overview-card" id="overview-duplications"></div>
   </div>
 </div>
index b06b14ed706fe1857414a3e10f5127189e7c098b..907e4727c9f4a9c2b1a7f8353a0d81984ed560c3 100644 (file)
@@ -1,16 +1,24 @@
+<header class="overview-card-header page-header">
+  <h2 class="page-title">{{t 'overview.size'}}</h2>
+</header>
+
 <div class="overview-highlight">
-  <h6 class="note">{{t 'overview.lines_of_code'}}</h6>
+  <h6 class="note">{{t 'metric.ncloc.name'}}</h6>
   <div class="overview-main-measure">
-    <a href="{{urlForDrilldown componentKey 'ncloc'}}">{{formatMeasure ncloc 'INT'}}</a>
+    <a href="{{urlForDrilldown componentKey 'ncloc'}}">{{formatMeasure ncloc 'SHORT_INT'}}</a>
   </div>
+
   {{#notNull ncloc3}}
     <div class="spacer-top">
-      <span class="overview-measure">{{formatMeasureVariation ncloc3 'INT'}}</span>
-      <span class="note">{{period3Name}}</span>
+      <h6 class="note">{{period3Name}}</h6>
+      <span class="overview-measure">{{formatMeasureVariation ncloc3 'SHORT_INT'}}</span>
     </div>
   {{/notNull}}
 </div>
 
 <div class="overview-trend">
-  <div class="overview-sparkline" id="overview-size-trend" data-width="300" data-height="50" data-color="#f3ca8e" data-type="INT"></div>
+  <div class="overview-sparkline" id="overview-size-trend" data-height="120" data-color="#f3ca8e"
+       data-type="SHORT_INT"></div>
 </div>
+
+
index 530f2eba50411733a9253b712e9102337a5e2944..592c12654935376a80a1c962a4a7ccc2ab4085b9 100644 (file)
@@ -288,6 +288,28 @@ function closeModalWindow () {
 
 (function () {
 
+  function shortIntFormatter (value) {
+    var format = '0,0';
+    if (value >= 1000) {
+      format = '0.[0]a';
+    }
+    if (value >= 10000) {
+      format = '0a';
+    }
+    return numeral(value).format(format);
+  }
+
+  function shortIntVariationFormatter (value) {
+    var format = '+0,0';
+    if (value >= 1000) {
+      format = '+0.[0]a';
+    }
+    if (value >= 10000) {
+      format = '+0a';
+    }
+    return numeral(value).format(format);
+  }
+
   /**
    * Check if days should be displayed for a work duration
    * @param {number} days
@@ -324,7 +346,7 @@ function closeModalWindow () {
    * @returns {string}
    */
   function addSpaceIfNeeded (value) {
-    return value.length > 0 ? value : value + ' ';
+    return value.length > 0 ? value + ' ' : value;
   }
 
   /**
@@ -402,6 +424,7 @@ function closeModalWindow () {
           'INT': function (value) {
             return numeral(value).format('0,0');
           },
+          'SHORT_INT': shortIntFormatter,
           'FLOAT': function (value) {
             return numeral(value).format('0,0.0');
           },
@@ -429,6 +452,7 @@ function closeModalWindow () {
           'INT': function (value) {
             return value === 0 ? '0' : numeral(value).format('+0,0');
           },
+          'SHORT_INT': shortIntVariationFormatter,
           'FLOAT': function (value) {
             return value === 0 ? '0' : numeral(value).format('+0,0.0');
           },
index 86b4286efb46e4021633280c92de95dd8e6a6d22..1a8fb87bef3f725d5dd84da96d5004c182827b90 100644 (file)
   });
 
   Handlebars.registerHelper('numberShort', function (number) {
-    if (number > 9999) {
-      return numeral(number).format('0.[0]a');
-    } else {
-      return numeral(number).format('0,0');
+    var format = '0,0';
+    if (number >= 10000) {
+      format = '0.[0]a';
+    }
+    if (number >= 100000) {
+      format = '0a';
     }
+    return numeral(number).format(format);
   });
 
   Handlebars.registerHelper('pluginActions', function (actions, options) {
index 986011c0e5885daa167912bcf16ba953e4acb4ea..6d2397f72102989f078cac6d6f402126c0d1bfdb 100644 (file)
@@ -26,7 +26,7 @@
   var defaults = {
     height: 30,
     color: '#1f77b4',
-    interpolate: 'bundle',
+    interpolate: 'linear',
     tension: 1,
     type: 'INT'
   };
               xScale = d3.time.scale()
                   .domain(d3.extent(data, function (d) {
                     return moment(d.val).toDate();
-                  })),
+                  }))
+                  .nice(),
 
               yScale = d3.scale.linear()
                   .domain(d3.extent(data, function (d) {
                     return d.count;
-                  })),
+                  }))
+                  .nice(),
 
-              minValue = yScale.domain()[0],
-              maxValue = yScale.domain()[1],
+              xTicks = xScale.ticks(5),
+              yTicks = yScale.ticks(3),
 
               line = d3.svg.line()
                   .x(function (d) {
                     return yScale(d.count);
                   })
                   .interpolate(options.interpolate)
-                  .tension(options.tension),
-
-              minLabel = plot.append('text')
-                  .text(window.formatMeasure(minValue, options.type))
-                  .attr('dy', '3px')
-                  .style('text-anchor', 'end')
-                  .style('font-size', '10px')
-                  .style('font-weight', '300')
-                  .style('fill', '#aaa'),
-
-              maxLabel = plot.append('text')
-                  .text(window.formatMeasure(maxValue, options.type))
-                  .attr('dy', '5px')
-                  .style('text-anchor', 'end')
-                  .style('font-size', '10px')
-                  .style('font-weight', '300')
-                  .style('fill', '#aaa'),
-
-              maxLabelWidth = Math.max(minLabel.node().getBBox().width, maxLabel.node().getBBox().width) + 3;
+                  .tension(options.tension);
 
           _.extend(options, {
-            marginLeft: 1,
-            marginRight: 1 + maxLabelWidth,
-            marginTop: 6,
-            marginBottom: 6
+            marginLeft: 20,
+            marginRight: 50,
+            marginTop: 0,
+            marginBottom: 25
           });
 
           _.extend(options, {
           xScale.range([0, options.availableWidth]);
           yScale.range([options.availableHeight, 0]);
 
+          xTicks.forEach(function (tick) {
+            plot.append('text')
+                .text(xScale.tickFormat()(tick))
+                .attr('x', xScale(tick))
+                .attr('y', options.availableHeight + 20)
+                .attr('dy', '0')
+                .style('text-anchor', 'middle')
+                .style('font-size', '10px')
+                .style('font-weight', '300')
+                .style('fill', '#aaa');
+            plot.append('line')
+                .attr('x1', xScale(tick))
+                .attr('x2', xScale(tick))
+                .attr('y1', 0)
+                .attr('y2', options.availableHeight)
+                .style('stroke', '#eee')
+                .style('shape-rendering', 'crispedges');
+          });
+
+          yTicks.forEach(function (tick) {
+            plot.append('text')
+                .text(window.formatMeasure(tick, options.type))
+                .attr('x', options.availableWidth + 50)
+                .attr('y', yScale(tick))
+                .attr('dy', '5px')
+                .style('text-anchor', 'end')
+                .style('font-size', '10px')
+                .style('font-weight', '300')
+                .style('fill', '#aaa');
+            plot.append('line')
+                .attr('x1', 0)
+                .attr('x2', options.availableWidth)
+                .attr('y1', yScale(tick))
+                .attr('y2', yScale(tick))
+                .style('stroke', '#eee')
+                .style('shape-rendering', 'crispedges');
+          });
+
           plot.append('path')
               .datum(data)
               .attr('d', line)
               .classed('line', true)
               .style('stroke', options.color);
-
-          minLabel
-              .attr('x', options.availableWidth + maxLabelWidth)
-              .attr('y', yScale(minValue));
-          maxLabel
-              .attr('x', options.availableWidth + maxLabelWidth)
-              .attr('y', yScale(maxValue));
         }
     );
   };
index 4bf5db63969c90d108b6530821e1bcf8bee14f70..04f885f26831b1bbc9dc8700b706441aa850934c 100644 (file)
@@ -35,6 +35,7 @@ requirejs([
 
     // add state model
     this.state = new State(window.overviewConf);
+    this.state.set('period3Name', 'During Leak Period');
 
     // create and render layout
     this.layout = new Layout({
index f72b99cefdf5dee13a8bc3a0dba94f3ce3b81658..69f50d885bda6e2aa80803c9d4249331402b405c 100644 (file)
@@ -22,12 +22,14 @@ define([
   'overview/main/gate-view',
   'overview/main/size-view',
   'overview/main/issues-view',
+  'overview/main/debt-view',
   'overview/main/coverage-view',
   'overview/main/duplications-view'
 ], function (MainLayout,
              GateView,
              SizeView,
              IssuesView,
+             DebtView,
              CoverageView,
              DuplicationsView) {
 
@@ -45,6 +47,7 @@ define([
       mainLayout.gateRegion.show(new GateView(options));
       mainLayout.sizeRegion.show(new SizeView(options));
       mainLayout.issuesRegion.show(new IssuesView(options));
+      mainLayout.debtRegion.show(new DebtView(options));
       mainLayout.coverageRegion.show(new CoverageView(options));
       mainLayout.duplicationsRegion.show(new DuplicationsView(options));
       this.state.fetch();
index 8b807e4d6ed135480da313a95e3068db598069ec..28bb1e5c7a00d5191e6dc469a29fdceaf8e7df77 100644 (file)
@@ -18,8 +18,9 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 define([
+  'overview/trend-view',
   'templates/overview'
-], function () {
+], function (TrendView) {
 
   return Marionette.Layout.extend({
     template: Templates['overview-coverage'],
@@ -32,7 +33,16 @@ define([
       var trend = this.model.get('coverageTrend'),
           hasCoverage = this.model.get('coverage') != null;
       if (_.size(trend) > 1 && hasCoverage) {
-        this.$('#overview-coverage-trend').sparkline(this.model.get('coverageTrend'));
+        this.trendView = new TrendView({ data: trend, type: 'PERCENT' });
+        this.trendView.render()
+            .$el.appendTo(this.$('#overview-coverage-trend'));
+        this.trendView.update();
+      }
+    },
+
+    onClose: function () {
+      if (this.trendView != null) {
+        this.trendView.detachEvents().remove();
       }
     }
   });
diff --git a/server/sonar-web/src/main/js/overview/main/debt-view.js b/server/sonar-web/src/main/js/overview/main/debt-view.js
new file mode 100644 (file)
index 0000000..80861a8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+define([
+  'overview/trend-view',
+  'templates/overview'
+], function (TrendView) {
+
+  return Marionette.Layout.extend({
+    template: Templates['overview-debt'],
+
+    modelEvents: {
+      'change': 'render'
+    },
+
+    onRender: function () {
+      var trend = this.model.get('debtTrend'),
+          hasDebt = this.model.get('debt') != null;
+      if (_.size(trend) > 1 && hasDebt) {
+        this.trendView = new TrendView({ data: trend, type: 'WORK_DUR' });
+        this.trendView.render()
+            .$el.appendTo(this.$('#overview-debt-trend'));
+        this.trendView.update();
+      }
+    },
+
+    onClose: function () {
+      if (this.trendView != null) {
+        this.trendView.detachEvents().remove();
+      }
+    }
+  });
+
+});
index 18e69af549b30211df7104e2078f2797dc63a0ba..a1310587288abeaa3fa9ace6160c122522f54581 100644 (file)
@@ -18,8 +18,9 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 define([
+  'overview/trend-view',
   'templates/overview'
-], function () {
+], function (TrendView) {
 
   return Marionette.Layout.extend({
     template: Templates['overview-duplications'],
@@ -32,7 +33,16 @@ define([
       var trend = this.model.get('duplicationsTrend'),
           hasDuplications = this.model.get('duplications') != null;
       if (_.size(trend) > 1 && hasDuplications) {
-        this.$('#overview-duplications-trend').sparkline(this.model.get('duplicationsTrend'));
+        this.trendView = new TrendView({ data: trend, type: 'PERCENT' });
+        this.trendView.render()
+            .$el.appendTo(this.$('#overview-duplications-trend'));
+        this.trendView.update();
+      }
+    },
+
+    onClose: function () {
+      if (this.trendView != null) {
+        this.trendView.detachEvents().remove();
       }
     }
   });
index a17a1d9547aacd791625e2b0378d6dc073d23d91..bfda55b257880f0bd6dee0e372d554b6f28864f1 100644 (file)
@@ -18,8 +18,9 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 define([
+  'overview/trend-view',
   'templates/overview'
-], function () {
+], function (TrendView) {
 
   return Marionette.Layout.extend({
     template: Templates['overview-issues'],
@@ -32,7 +33,16 @@ define([
       var trend = this.model.get('issuesTrend'),
           hasIssues = this.model.get('issues') != null;
       if (_.size(trend) > 1 && hasIssues) {
-        this.$('#overview-issues-trend').sparkline(this.model.get('issuesTrend'));
+        this.trendView = new TrendView({ data: trend, type: 'SHORT_INT' });
+        this.trendView.render()
+            .$el.appendTo(this.$('#overview-issues-trend'));
+        this.trendView.update();
+      }
+    },
+
+    onClose: function () {
+      if (this.trendView != null) {
+        this.trendView.detachEvents().remove();
       }
     }
   });
index 8db7c1e088d2c8cff4b3007eef8853b4a30a5180..c0e46deffd508371b9b84510d56d663b22861a3e 100644 (file)
@@ -28,6 +28,7 @@ define([
       gateRegion: '#overview-gate',
       sizeRegion: '#overview-size',
       issuesRegion: '#overview-issues',
+      debtRegion: '#overview-debt',
       coverageRegion: '#overview-coverage',
       duplicationsRegion: '#overview-duplications'
     },
@@ -39,7 +40,7 @@ define([
     toggleRegions: function () {
       var conditions = this.model.get('gateConditions'),
           hasGate = _.isArray(conditions) && conditions.length > 0;
-      this.$(this.gateRegion.el).toggle(hasGate);
+      this.$(this.gateRegion.el).toggleClass('hidden', !hasGate);
     }
   });
 
index db1ab7e41a8f3358a15297d634da0524e17b2704..07917e89c5281e76307bab778fc9c986c707724c 100644 (file)
@@ -18,8 +18,9 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 define([
+  'overview/trend-view',
   'templates/overview'
-], function () {
+], function (TrendView) {
 
   return Marionette.Layout.extend({
     template: Templates['overview-size'],
@@ -32,7 +33,16 @@ define([
       var trend = this.model.get('sizeTrend'),
           hasSize = this.model.get('ncloc') != null;
       if (_.size(trend) > 1 && hasSize) {
-        this.$('#overview-size-trend').sparkline(this.model.get('sizeTrend'));
+        this.trendView = new TrendView({ data: trend, type: 'SHORT_INT' });
+        this.trendView.render()
+            .$el.appendTo(this.$('#overview-size-trend'));
+        this.trendView.update();
+      }
+    },
+
+    onClose: function () {
+      if (this.trendView != null) {
+        this.trendView.detachEvents().remove();
       }
     }
   });
index 6b19a4152873b6eaad4b8b3f74d80cba34003d63..d3be4446ee16e2b47eec44dd5216ad5a856a3e8a 100644 (file)
@@ -24,9 +24,10 @@ define(function () {
       SIZE_METRIC = 'ncloc',
       ISSUES_METRIC = 'violations',
       DEBT_METRIC = 'sqale_index',
+      NEW_DEBT_METRIC = 'new_technical_debt',
       SQALE_RATING_METRIC = 'sqale_rating',
-      COVERAGE_METRIC = 'overall_coverage',
-      NEW_COVERAGE_METRIC = 'new_overall_coverage',
+      COVERAGE_METRIC = 'coverage',
+      NEW_COVERAGE_METRIC = 'new_coverage',
       DUPLICATIONS_METRIC = 'duplicated_lines_density';
 
   return Backbone.Model.extend({
@@ -68,6 +69,7 @@ define(function () {
               GATE_METRIC,
               SIZE_METRIC,
               DEBT_METRIC,
+              NEW_DEBT_METRIC,
               SQALE_RATING_METRIC,
               COVERAGE_METRIC,
               NEW_COVERAGE_METRIC,
@@ -148,10 +150,14 @@ define(function () {
 
     parseDebt: function (msr) {
       var debtMeasure = _.findWhere(msr, { key: DEBT_METRIC }),
+          newDebtMeasure = _.findWhere(msr, { key: NEW_DEBT_METRIC }),
           sqaleRatingMeasure = _.findWhere(msr, { key: SQALE_RATING_METRIC });
       if (debtMeasure != null) {
         this.set({ debt: debtMeasure.val });
       }
+      if (newDebtMeasure != null) {
+        this.set({ newDebt: newDebtMeasure.var3 });
+      }
       if (sqaleRatingMeasure != null) {
         this.set({ sqaleRating: sqaleRatingMeasure.val });
       }
@@ -191,6 +197,7 @@ define(function () {
             metrics: [
               SIZE_METRIC,
               ISSUES_METRIC,
+              DEBT_METRIC,
               COVERAGE_METRIC,
               DUPLICATIONS_METRIC
             ].join(',')
@@ -199,6 +206,7 @@ define(function () {
         if (_.isArray(r)) {
           that.parseSizeTrend(r[0]);
           that.parseIssuesTrend(r[0]);
+          that.parseDebtTrend(r[0]);
           that.parseCoverageTrend(r[0]);
           that.parseDuplicationsTrend(r[0]);
         }
@@ -224,6 +232,10 @@ define(function () {
       this.parseTrend(r, 'issuesTrend', ISSUES_METRIC);
     },
 
+    parseDebtTrend: function (r) {
+      this.parseTrend(r, 'debtTrend', DEBT_METRIC);
+    },
+
     parseCoverageTrend: function (r) {
       this.parseTrend(r, 'coverageTrend', COVERAGE_METRIC);
     },
diff --git a/server/sonar-web/src/main/js/overview/trend-view.js b/server/sonar-web/src/main/js/overview/trend-view.js
new file mode 100644 (file)
index 0000000..aeaac5a
--- /dev/null
@@ -0,0 +1,163 @@
+define(function () {
+
+  function trans (left, top) {
+    return 'translate(' + left + ', ' + top + ')';
+  }
+
+  var $ = jQuery;
+
+
+  return Backbone.View.extend({
+
+    initialize: function (options) {
+      this.data = options.data;
+      this.type = options.type || 'INT';
+      this.width = 0;
+      this.height = 0;
+    },
+
+    attachEvents: function () {
+      this.detachEvents();
+      var event = 'resize.trend-' + this.cid,
+          update = _.throttle(_.bind(this.update, this), 50);
+      $(window).on(event, update);
+    },
+
+    detachEvents: function () {
+      var event = 'resize.trend-' + this.cid;
+      $(window).off(event);
+      return this;
+    },
+
+    render: function () {
+      var that = this,
+          data = this.data;
+      this.container = d3.select(this.el);
+      this.svg = this.container.append('svg')
+          .classed('sonar-d3', true);
+      this.plot = this.svg.append('g')
+          .classed('plot', true);
+
+      this.xScale = d3.time.scale()
+          .domain(d3.extent(data, function (d) {
+            return moment(d.val).toDate();
+          }))
+          .nice();
+      this.yScale = d3.scale.linear()
+          .domain(d3.extent(data, function (d) {
+            return d.count;
+          }))
+          .nice();
+
+      this.line = d3.svg.line()
+          .x(function (d) {
+            return that.xScale(moment(d.val).toDate());
+          })
+          .y(function (d) {
+            return that.yScale(d.count);
+          })
+          .interpolate('linear');
+
+      this.xScaleTicks = this.xScale.ticks(5);
+      this.yScaleTicks = this.yScale.ticks(3);
+
+      this.xTicks = this.xScaleTicks.map(function (tick) {
+        return that.plot.append('text')
+            .datum(tick)
+            .text(that.xScale.tickFormat()(tick))
+            .attr('dy', '0')
+            .style('text-anchor', 'middle')
+            .style('font-size', '10px')
+            .style('font-weight', '300')
+            .style('fill', '#aaa');
+      });
+      this.yTicks = this.yScaleTicks.map(function (tick) {
+        return that.plot.append('text')
+            .datum(tick)
+            .text(window.formatMeasure(tick, that.type))
+            .attr('dy', '5px')
+            .style('text-anchor', 'end')
+            .style('font-size', '10px')
+            .style('font-weight', '300')
+            .style('fill', '#aaa');
+      });
+
+      this.xTickLines = this.xScaleTicks.map(function (tick) {
+        return that.plot.append('line')
+            .datum(tick)
+            .style('stroke', '#eee')
+            .style('shape-rendering', 'crispedges');
+      });
+      this.yTickLines = this.yScaleTicks.map(function (tick) {
+        return that.plot.append('line')
+            .datum(tick)
+            .style('stroke', '#eee')
+            .style('shape-rendering', 'crispedges');
+      });
+
+      this.path = this.plot.append('path')
+          .datum(data)
+          .classed('line', true)
+          .style('stroke', 'rgb(31, 119, 180)');
+
+      this.attachEvents();
+
+      return this;
+    },
+
+    update: function () {
+      var that = this,
+          width = this.$el.closest('.overview-trend').width(),
+          height = 150,
+          marginLeft = 20,
+          marginRight = 50,
+          marginTop = 5,
+          marginBottom = 25,
+          availableWidth = width - marginLeft - marginRight,
+          availableHeight = height - marginTop - marginBottom;
+
+      this.svg
+          .attr('width', width)
+          .attr('height', height);
+
+      this.plot.attr('transform', trans(marginLeft, marginTop));
+      this.xScale.range([0, availableWidth]);
+      this.yScale.range([availableHeight, 0]);
+
+      this.path
+          .attr('d', this.line);
+
+      this.xTicks.forEach(function (tick) {
+        tick
+            .attr('x', that.xScale(tick.datum()))
+            .attr('y', availableHeight + 20);
+      });
+
+      this.yTicks.forEach(function (tick) {
+        tick
+            .attr('x', availableWidth + 50)
+            .attr('y', that.yScale(tick.datum()));
+      });
+
+      this.xTickLines.forEach(function (tick) {
+        tick
+            .attr('x1', that.xScale(tick.datum()))
+            .attr('x2', that.xScale(tick.datum()))
+            .attr('y1', 0)
+            .attr('y2', availableHeight);
+      });
+
+      this.yTickLines.forEach(function (tick) {
+        tick
+            .attr('x1', 0)
+            .attr('x2', availableWidth)
+            .attr('y1', that.yScale(tick.datum()))
+            .attr('y2', that.yScale(tick.datum()));
+      });
+
+      return this;
+    }
+
+  });
+
+});
index 0e4b489e74b57ed1f40e0cbe126edfce13f09599..699573084eea24e56af326fde6f22732fb9448ca 100644 (file)
 
 .column-third {
   float: left;
-  width: 33%;
+  width: 33.3333333333%;
+  padding: 0 10px;
+  .box-sizing(border-box);
+}
+
+.column-two-thirds {
+  float: left;
+  width: 66.6666666667%;
   padding: 0 10px;
   .box-sizing(border-box);
 }
index 311e5bb6bc4f988bd931bb5751b007b421523625..4582868d23e5a0ed79607ff05af654e5b07741e7 100644 (file)
 }
 
 .overview-card {
-  padding-top: 5px;
-  background: @white;
+  .clearfix;
+  padding: 20px;
   border: 1px solid @barBorderColor;
+  background: @white;
 }
 
-.overview-gate {
-  padding: 10px;
+.overview-card:not(.hidden) + .overview-card {
+  margin-top: 20px;
 }
 
 .overview-gate-ok { border: 2px solid @green; }
 
 .overview-gate-error { border: 2px solid @red; }
 
+.overview-gate-condition {
+  padding-left: 1px;
+}
+
 .overview-container {
   margin-top: 20px;
-  text-align: center;
 }
 
 .overview-card-header {
-  padding-bottom: 5px;
+  margin-bottom: 20px;
+  padding-bottom: 20px;
   border-bottom: 1px solid @barBorderColor;
 }
 
@@ -57,7 +62,6 @@
   margin: 0;
   padding: 0 6px;
   color: #fff !important;
-  font-size: 24px;
   font-weight: 300;
 
   a& {
 .overview-status-ERROR { background-color: @red; }
 
 .overview-highlight {
-  height: 145px;
-}
-
-.overview-main-measure {
-  line-height: 1.3;
-  font-size: 36px;
-  font-weight: 300;
+  float: left;
+  width: 160px;
+  padding-right: 20px;
+  .box-sizing(border-box);
 }
 
 .overview-trend {
-  height: 50px;
-  margin-top: 15px;
-  padding: 5px 10px;
-  border-top: 1px solid @barBorderColor;
-  background-color: #fdfdfd;
+  padding-left: 160px;
 
   .note { font-size: 10px; }
 }
 
-.overview-sparkline {
-  display: inline-block;
-  vertical-align: middle;
+.overview-main-measure {
+  line-height: 1.3;
+  margin-bottom: 20px;
+  font-size: 36px;
+  font-weight: 300;
+
+  .rating { font-size: 30px; }
 }
 
 .overview-measure {
-  font-size: 16px;
+  line-height: 1.5;
+  font-size: 20px;
   font-weight: 300;
 }
index 0a1cb43e0f1cfbc7f8dcf489a2b027c26e45e033..78c2dcbb23acd9303e13689deb276da50d61dd69 100644 (file)
@@ -26,7 +26,7 @@ lib.changeWorkingDirectory('overview');
 lib.configureCasper();
 
 
-casper.test.begin(testName(), 23, function (test) {
+casper.test.begin(testName(), 22, function (test) {
   casper
       .start(lib.buildUrl('overview'), function () {
         lib.setDefaultViewport();
@@ -44,7 +44,7 @@ casper.test.begin(testName(), 23, function (test) {
       })
 
       .then(function () {
-        casper.waitForText('165,077');
+        casper.waitForText('165k');
       })
 
       .then(function () {
@@ -58,17 +58,17 @@ casper.test.begin(testName(), 23, function (test) {
         test.assertElementCount('#overview-gate .overview-status-WARN', 1);
         test.assertElementCount('#overview-gate .overview-status-OK', 5);
 
-        test.assertSelectorContains('#overview-size', '165,077');
-        test.assertSelectorContains('#overview-size', '+3,916');
+        test.assertSelectorContains('#overview-size', '165k');
+        test.assertSelectorContains('#overview-size', '+3.9k');
         test.assertExists('#overview-size-trend path');
 
-        test.assertSelectorContains('#overview-issues', '1,605');
-        test.assertSelectorContains('#overview-issues', 'A');
-        test.assertSelectorContains('#overview-issues', '66');
+        test.assertSelectorContains('#overview-issues', '1.6k');
         test.assertExists('#overview-issues-trend path');
 
+        test.assertSelectorContains('#overview-debt', '66');
+        test.assertExists('#overview-debt-trend path');
+
         test.assertSelectorContains('#overview-coverage', '83.9%');
-        test.assertSelectorContains('#overview-coverage', '+0.6%');
         test.assertSelectorContains('#overview-coverage', '90.0%');
         test.assertExists('#overview-coverage-trend path');
 
index 33c235ca5751d0f75235aad32ce648071eb2bf1e..826a1ab308d3ff9049665d61eb54a2598a1e7016 100644 (file)
@@ -74,7 +74,7 @@
         "fvar3": "0"
       },
       {
-        "key": "overall_coverage",
+        "key": "coverage",
         "val": 83.9,
         "frmt_val": "83.9%",
         "trend": 0,
@@ -85,7 +85,7 @@
         "fvar3": "0.6%"
       },
       {
-        "key": "new_overall_coverage",
+        "key": "new_coverage",
         "var1": 88.2352941176471,
         "fvar1": "88.2%",
         "var2": 87.9254132585941,
index a2d4391d1e7d3705ef98dd07f524a430bc045f66..1ac438fc2bbe5a3405af436685e6f8b1cb9bbda9 100644 (file)
@@ -11,7 +11,7 @@
         "metric": "sqale_index"
       },
       {
-        "metric": "overall_coverage"
+        "metric": "coverage"
       },
       {
         "metric": "duplicated_lines_density"
index 7f50024c9556d0458164fc0dbb5698caa17e32f1..4e381f1ce6d31138f4e74289881d4055535e3a65 100644 (file)
@@ -14,4 +14,3 @@ block body
       componentKey: 'org.codehaus.sonar:sonar',
       componentUuid: '69e57151-be0d-4157-adff-c06741d88879'
     };
-    require(['overview/app']);
index 16d538afaff38c5b7f0acefdf451f62ccf73ed7b..0b1657038badf4be9686b531eb59593eec2287e0 100644 (file)
@@ -2259,7 +2259,7 @@ metric.generated_ncloc.abbreviation=Gen. LOC
 metric.lines.name=Lines
 metric.lines.description=Lines
 
-metric.ncloc.name=Lines of code
+metric.ncloc.name=Lines of Code
 metric.ncloc.description=Non Commenting Lines of Code
 metric.ncloc.abbreviation=LOC
 
@@ -2533,6 +2533,7 @@ metric.duplicated_files.description=Duplicated files
 metric.duplicated_files.abbreviation=Dup. files
 
 metric.duplicated_lines_density.name=Duplicated lines (%)
+metric.duplicated_lines_density.short_name=Duplications
 metric.duplicated_lines_density.description=Duplicated lines balanced by statements
 metric.duplicated_lines_density.abbreviation=Dup. lines(%)
 
@@ -2993,8 +2994,11 @@ workspace.close=Remove from the list of pinned files
 # OVERVIEW
 #
 #------------------------------------------------------------------------------
-overview.lines_of_code=Lines of Code
+overview.size=Size
+overview.gate=Quality Gate
 overview.issues=Issues
-overview.debt=Debt
-overview.coverage=Coverage
+overview.debt=Technical Debt
+overview.testing=Testing
 overview.duplications=Duplications
+overview.new=new
+overview.on_new_code=on new code