diff options
Diffstat (limited to 'server/sonar-web/src/main/js/overview')
10 files changed, 281 insertions, 11 deletions
diff --git a/server/sonar-web/src/main/js/overview/app.js b/server/sonar-web/src/main/js/overview/app.js index 4bf5db63969..04f885f2683 100644 --- a/server/sonar-web/src/main/js/overview/app.js +++ b/server/sonar-web/src/main/js/overview/app.js @@ -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({ diff --git a/server/sonar-web/src/main/js/overview/controller.js b/server/sonar-web/src/main/js/overview/controller.js index f72b99cefdf..69f50d885bd 100644 --- a/server/sonar-web/src/main/js/overview/controller.js +++ b/server/sonar-web/src/main/js/overview/controller.js @@ -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(); diff --git a/server/sonar-web/src/main/js/overview/main/coverage-view.js b/server/sonar-web/src/main/js/overview/main/coverage-view.js index 8b807e4d6ed..28bb1e5c7a0 100644 --- a/server/sonar-web/src/main/js/overview/main/coverage-view.js +++ b/server/sonar-web/src/main/js/overview/main/coverage-view.js @@ -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 index 00000000000..80861a82152 --- /dev/null +++ b/server/sonar-web/src/main/js/overview/main/debt-view.js @@ -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(); + } + } + }); + +}); diff --git a/server/sonar-web/src/main/js/overview/main/duplications-view.js b/server/sonar-web/src/main/js/overview/main/duplications-view.js index 18e69af549b..a1310587288 100644 --- a/server/sonar-web/src/main/js/overview/main/duplications-view.js +++ b/server/sonar-web/src/main/js/overview/main/duplications-view.js @@ -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(); } } }); diff --git a/server/sonar-web/src/main/js/overview/main/issues-view.js b/server/sonar-web/src/main/js/overview/main/issues-view.js index a17a1d9547a..bfda55b2578 100644 --- a/server/sonar-web/src/main/js/overview/main/issues-view.js +++ b/server/sonar-web/src/main/js/overview/main/issues-view.js @@ -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(); } } }); diff --git a/server/sonar-web/src/main/js/overview/main/layout.js b/server/sonar-web/src/main/js/overview/main/layout.js index 8db7c1e088d..c0e46deffd5 100644 --- a/server/sonar-web/src/main/js/overview/main/layout.js +++ b/server/sonar-web/src/main/js/overview/main/layout.js @@ -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); } }); diff --git a/server/sonar-web/src/main/js/overview/main/size-view.js b/server/sonar-web/src/main/js/overview/main/size-view.js index db1ab7e41a8..07917e89c52 100644 --- a/server/sonar-web/src/main/js/overview/main/size-view.js +++ b/server/sonar-web/src/main/js/overview/main/size-view.js @@ -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(); } } }); diff --git a/server/sonar-web/src/main/js/overview/models/state.js b/server/sonar-web/src/main/js/overview/models/state.js index 6b19a415287..d3be4446ee1 100644 --- a/server/sonar-web/src/main/js/overview/models/state.js +++ b/server/sonar-web/src/main/js/overview/models/state.js @@ -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 index 00000000000..aeaac5ad697 --- /dev/null +++ b/server/sonar-web/src/main/js/overview/trend-view.js @@ -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; + } + + }); + +}); |