diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2015-05-18 16:29:19 +0200 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2015-05-19 18:20:09 +0200 |
commit | e59e4aa2c06a57566f148f4217d286461231ae58 (patch) | |
tree | ad0918eb06b2474a6c71997b7ff573bbb93e0170 /server/sonar-web/src/main/js/widgets | |
parent | 8d82c9cf9ba88c1517604b4063ad0fc2a9a1bb9a (diff) | |
download | sonarqube-e59e4aa2c06a57566f148f4217d286461231ae58.tar.gz sonarqube-e59e4aa2c06a57566f148f4217d286461231ae58.zip |
change web structure: separate components
Diffstat (limited to 'server/sonar-web/src/main/js/widgets')
14 files changed, 159 insertions, 1900 deletions
diff --git a/server/sonar-web/src/main/js/widgets/bubble-chart.js b/server/sonar-web/src/main/js/widgets/bubble-chart.js deleted file mode 100644 index fc166404423..00000000000 --- a/server/sonar-web/src/main/js/widgets/bubble-chart.js +++ /dev/null @@ -1,541 +0,0 @@ -/* - * 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. - */ -/*global d3:false, baseUrl:false */ - -window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; - -(function () { - - window.SonarWidgets.BubbleChart = function () { - // Set default values - this._components = []; - this._metrics = []; - this._metricsPriority = []; - this._width = window.SonarWidgets.BubbleChart.defaults.width; - this._height = window.SonarWidgets.BubbleChart.defaults.height; - this._margin = window.SonarWidgets.BubbleChart.defaults.margin; - this._xLog = window.SonarWidgets.BubbleChart.defaults.xLog; - this._yLog = window.SonarWidgets.BubbleChart.defaults.yLog; - this._bubbleColor = window.SonarWidgets.BubbleChart.defaults.bubbleColor; - this._bubbleColorUndefined = window.SonarWidgets.BubbleChart.defaults.bubbleColorUndefined; - this._options = {}; - - // Export global variables - this.metrics = function (_) { - return param.call(this, '_metrics', _); - }; - - this.metricsPriority = function (_) { - return param.call(this, '_metricsPriority', _); - }; - - this.components = function (_) { - return param.call(this, '_components', _); - }; - - this.width = function (_) { - return param.call(this, '_width', _); - }; - - this.height = function (_) { - return param.call(this, '_height', _); - }; - - this.margin = function (_) { - return param.call(this, '_margin', _); - }; - - this.xLog = function (_) { - return param.call(this, '_xLog', _); - }; - - this.yLog = function (_) { - return param.call(this, '_yLog', _); - }; - - this.bubbleColor = function (_) { - return param.call(this, '_bubbleColor', _); - }; - - this.bubbleColorUndefined = function (_) { - return param.call(this, '_bubbleColorUndefined', _); - }; - - this.options = function (_) { - return param.call(this, '_options', _); - }; - }; - - - window.SonarWidgets.BubbleChart.prototype.hasValidData = function () { - var widget = this, - noInvalidEntry = true, - atLeastOneValueOnX = false, - atLeastOneValueOnY = false; - this.components().forEach(function(component) { - noInvalidEntry = noInvalidEntry && - !!component.measures[widget.metricsPriority()[0]] && - !!component.measures[widget.metricsPriority()[1]]; - atLeastOneValueOnX = atLeastOneValueOnX || - (component.measures[widget.metricsPriority()[0]] || {}).fval !== '-'; - atLeastOneValueOnY = atLeastOneValueOnY || - (component.measures[widget.metricsPriority()[1]] || {}).fval !== '-'; - }); - return !!noInvalidEntry && !!atLeastOneValueOnX && !!atLeastOneValueOnY; - }; - - - window.SonarWidgets.BubbleChart.prototype.init = function (container) { - this.width(container.property('offsetWidth')); - - this.svg = container.append('svg') - .attr('class', 'sonar-d3'); - this.gWrap = this.svg.append('g'); - - this.gxAxis = this.gWrap.append('g'); - this.gyAxis = this.gWrap.append('g'); - - this.gGrid = this.gWrap.append('g'); - this.gxGrid = this.gGrid.append('g'); - this.gyGrid = this.gGrid.append('g'); - - this.plotWrap = this.gWrap.append('g'); - - this.infoWrap = this.gWrap.append('g'); - this.infoDate = this.infoWrap.append('text'); - - this.gWrap - .attr('transform', trans(this.margin().left, this.margin().top)); - }; - - - window.SonarWidgets.BubbleChart.prototype.initMetrics = function () { - var widget = this; - - this.xMetric = this.metricsPriority()[0]; - this.getXMetric = function(d) { - return d.measures[widget.xMetric].val; - }; - - this.yMetric = this.metricsPriority()[1]; - this.getYMetric = function(d) { - return d.measures[widget.yMetric].val; - }; - - this.sizeMetric = this.metricsPriority()[2]; - this.getSizeMetric = function(d) { - return !!d.measures[widget.sizeMetric] ? d.measures[widget.sizeMetric].val : 0; - }; - }; - - - window.SonarWidgets.BubbleChart.prototype.initScales = function () { - var widget = this; - this - .xLog(this.options().xLog) - .yLog(this.options().yLog); - - this.x = this.xLog() ? d3.scale.log() : d3.scale.linear(); - this.y = this.yLog() ? d3.scale.log() : d3.scale.linear(); - this.size = d3.scale.linear(); - - this.x.range([0, this.availableWidth]); - this.y.range([this.availableHeight, 0]); - this.size.range([5, 45]); - - if (this.components().length > 1) { - this.x.domain(d3.extent(this.components(), function (d) { - return widget.getXMetric(d); - })); - this.y.domain(d3.extent(this.components(), function (d) { - return widget.getYMetric(d); - })); - this.size.domain(d3.extent(this.components(), function (d) { - return widget.getSizeMetric(d); - })); - } else { - var singleComponent = this.components()[0], - xm = this.getXMetric(singleComponent), - ym = this.getYMetric(singleComponent), - sm = this.getSizeMetric(singleComponent); - this.x.domain([xm * 0.8, xm * 1.2]); - this.y.domain([ym * 0.8, ym * 1.2]); - this.size.domain([sm * 0.8, sm * 1.2]); - } - }; - - - window.SonarWidgets.BubbleChart.prototype.initBubbles = function () { - var widget = this; - - // Create bubbles - this.items = this.plotWrap.selectAll('.item') - .data(this.components()); - - - // Render bubbles - this.items.enter().append('g') - .attr('class', 'item') - .attr('name', function (d) { - return d.longName; - }) - .style('cursor', 'pointer') - .append('circle') - .attr('r', function (d) { - return widget.size(widget.getSizeMetric(d)); - }) - .style('fill', function () { - return widget.bubbleColor(); - }) - .style('fill-opacity', 0.2) - .style('stroke', function () { - return widget.bubbleColor(); - }) - .style('transition', 'all 0.2s ease') - - .attr('title', function (d) { - var xMetricName = widget.metrics()[widget.xMetric].name, - yMetricName = widget.metrics()[widget.yMetric].name, - sizeMetricName = widget.metrics()[widget.sizeMetric].name, - - xMetricValue = d.measures[widget.xMetric].fval, - yMetricValue = d.measures[widget.yMetric].fval, - sizeMetricValue = d.measures[widget.sizeMetric].fval; - - return '<div class="text-left">' + - collapsedDirFromPath(d.longName) + '<br>' + - fileFromPath(d.longName) + '<br>' + '<br>' + - xMetricName + ': ' + xMetricValue + '<br>' + - yMetricName + ': ' + yMetricValue + '<br>' + - sizeMetricName + ': ' + sizeMetricValue + - '</div>'; - }) - .attr('data-placement', 'bottom') - .attr('data-toggle', 'tooltip'); - - this.items.exit().remove(); - - this.items.sort(function (a, b) { - return widget.getSizeMetric(b) - widget.getSizeMetric(a); - }); - }; - - - window.SonarWidgets.BubbleChart.prototype.initBubbleEvents = function () { - var widget = this; - this.items - .on('click', function (d) { - window.location = widget.options().baseUrl + '?id=' + encodeURIComponent(d.key); - }) - .on('mouseenter', function () { - d3.select(this).select('circle') - .style('fill-opacity', 0.8); - }) - .on('mouseleave', function () { - d3.select(this).select('circle') - .style('fill-opacity', 0.2); - }); - }; - - - window.SonarWidgets.BubbleChart.prototype.initAxes = function () { - // X - this.xAxis = d3.svg.axis() - .scale(this.x) - .orient('bottom'); - - this.gxAxisLabel = this.gxAxis.append('text') - .text(this.metrics()[this.xMetric].name) - .style('font-weight', 'bold') - .style('text-anchor', 'middle'); - - - // Y - this.yAxis = d3.svg.axis() - .scale(this.y) - .orient('left'); - - this.gyAxis.attr('transform', trans(60 - this.margin().left, 0)); - - this.gyAxisLabel = this.gyAxis.append('text') - .text(this.metrics()[this.yMetric].name) - .style('font-weight', 'bold') - .style('text-anchor', 'middle'); - }; - - - window.SonarWidgets.BubbleChart.prototype.initGrid = function () { - this.gxGridLines = this.gxGrid.selectAll('line').data(this.x.ticks()).enter() - .append('line'); - - this.gyGridLines = this.gyGrid.selectAll('line').data(this.y.ticks()).enter() - .append('line'); - - this.gGrid.selectAll('line') - .style('stroke', '#000') - .style('stroke-opacity', 0.25); - }; - - - window.SonarWidgets.BubbleChart.prototype.render = function (container) { - var containerS = container; - - container = d3.select(container); - - if (!this.hasValidData()) { - container.text(this.options().noMainMetric); - return; - } - - this.init(container); - this.initMetrics(); - this.initScales(); - this.initBubbles(); - this.initBubbleEvents(); - this.initAxes(); - this.initGrid(); - this.update(containerS); - - jQuery('[data-toggle="tooltip"]').tooltip({ container: 'body', html: true }); - - return this; - }; - - - window.SonarWidgets.BubbleChart.prototype.adjustScalesAfterUpdate = function () { - var widget = this; - // X - var minX = d3.min(this.components(), function (d) { - return widget.x(widget.getXMetric(d)) - widget.size(widget.getSizeMetric(d)); - }), - maxX = d3.max(this.components(), function (d) { - return widget.x(widget.getXMetric(d)) + widget.size(widget.getSizeMetric(d)); - }), - dMinX = minX < 0 ? this.x.range()[0] - minX : this.x.range()[0], - dMaxX = maxX > this.x.range()[1] ? maxX - this.x.range()[1] : 0; - this.x.range([dMinX, this.availableWidth - dMaxX]); - - // Y - var minY = d3.min(this.components(), function (d) { - return widget.y(widget.getYMetric(d)) - widget.size(widget.getSizeMetric(d)); - }), - maxY = d3.max(this.components(), function (d) { - return widget.y(widget.getYMetric(d)) + widget.size(widget.getSizeMetric(d)); - }), - dMinY = minY < 0 ? this.y.range()[1] - minY: this.y.range()[1], - dMaxY = maxY > this.y.range()[0] ? maxY - this.y.range()[0] : 0; - this.y.range([this.availableHeight - dMaxY, dMinY]); - - - // Format improvement for log scales - // X - if (this.xLog()) { - this.xAxis.tickFormat(function (d) { - var ticksCount = widget.availableWidth / 50; - return widget.x.tickFormat(ticksCount, d3.format(',d'))(d); - }); - } - - // Y - if (this.yLog()) { - this.yAxis.tickFormat(function (d) { - var ticksCount = widget.availableHeight / 30; - return widget.y.tickFormat(ticksCount, d3.format(',d'))(d); - }); - } - - // Make scale's domains nice - this.x.nice(); - this.y.nice(); - }; - - - window.SonarWidgets.BubbleChart.prototype.updateScales = function () { - var widget = this; - this.x.range([0, this.availableWidth]); - this.y.range([this.availableHeight, 0]); - - if (this.components().length > 1) { - this.x.domain(d3.extent(this.components(), function (d) { - return widget.getXMetric(d); - })); - this.y.domain(d3.extent(this.components(), function (d) { - return widget.getYMetric(d); - })); - } else { - var singleComponent = this.components()[0], - xm = this.getXMetric(singleComponent), - ym = this.getYMetric(singleComponent), - sm = this.getSizeMetric(singleComponent); - this.x.domain([xm * 0.8, xm * 1.2]); - this.y.domain([ym * 0.8, ym * 1.2]); - this.size.domain([sm * 0.8, sm * 1.2]); - } - - if (this.x.domain()[0] === 0 && this.x.domain()[1] === 0) { - this.x.domain([0, 1]); - } - if (this.y.domain()[0] === 0 && this.y.domain()[1] === 0) { - this.y.domain([0, 1]); - } - - // Avoid zero values when using log scale - if (this.xLog) { - var xDomain = this.x.domain(); - this.x - .domain([xDomain[0] > 0 ? xDomain[0] : 0.1, xDomain[1]]) - .clamp(true); - } - - if (this.yLog) { - var yDomain = this.y.domain(); - this.y - .domain([yDomain[0] > 0 ? yDomain[0] : 0.1, yDomain[1]]) - .clamp(true); - } - }; - - - window.SonarWidgets.BubbleChart.prototype.updateBubbles = function () { - var widget = this; - this.items - .transition() - .attr('transform', function (d) { - return trans(widget.x(widget.getXMetric(d)), widget.y(widget.getYMetric(d))); - }); - }; - - - window.SonarWidgets.BubbleChart.prototype.updateAxes = function () { - // X - this.gxAxis.attr('transform', trans(0, this.availableHeight + this.margin().bottom - 40)); - - this.gxAxis.transition().call(this.xAxis); - - this.gxAxis.selectAll('path') - .style('fill', 'none') - .style('stroke', '#444'); - - this.gxAxis.selectAll('text') - .style('fill', '#444'); - - this.gxAxisLabel - .attr('transform', trans(this.availableWidth / 2, 35)); - - // Y - this.gyAxis.transition().call(this.yAxis); - - this.gyAxis.selectAll('path') - .style('fill', 'none') - .style('stroke', '#444'); - - this.gyAxis.selectAll('text') - .style('fill', '#444'); - - this.gyAxisLabel - .attr('transform', trans(-45, this.availableHeight / 2) + ' rotate(-90)'); - }; - - - window.SonarWidgets.BubbleChart.prototype.updateGrid = function () { - var widget = this; - this.gxGridLines - .transition() - .attr({ - x1: function (d) { - return widget.x(d); - }, - x2: function (d) { - return widget.x(d); - }, - y1: widget.y.range()[0], - y2: widget.y.range()[1] - }); - - this.gyGridLines - .transition() - .attr({ - x1: widget.x.range()[0], - x2: widget.x.range()[1], - y1: function (d) { - return widget.y(d); - }, - y2: function (d) { - return widget.y(d); - } - }); - }; - - - window.SonarWidgets.BubbleChart.prototype.update = function (container) { - container = d3.select(container); - - var width = container.property('offsetWidth'); - - this.width(width > 100 ? width : 100); - - // Update svg canvas - this.svg - .attr('width', this.width()) - .attr('height', this.height()); - - // Update available size - this.availableWidth = this.width() - this.margin().left - this.margin().right; - this.availableHeight = this.height() - this.margin().top - this.margin().bottom; - - this.updateScales(); - this.adjustScalesAfterUpdate(); - this.updateBubbles(); - this.updateAxes(); - this.updateGrid(); - }; - - - - window.SonarWidgets.BubbleChart.defaults = { - width: 350, - height: 150, - margin: { top: 10, right: 10, bottom: 50, left: 70 }, - xLog: false, - yLog: false, - bubbleColor: '#4b9fd5', - bubbleColorUndefined: '#b3b3b3' - }; - - - - // Some helper functions - - // Gets or sets parameter - function param(name, value) { - if (value == null) { - return this[name]; - } else { - this[name] = value; - return this; - } - } - - // Helper for create the translate(x, y) string - function trans(left, top) { - return 'translate(' + left + ', ' + top + ')'; - } - -})(); diff --git a/server/sonar-web/src/main/js/widgets/issue-filter/templates/_widget-issue-filter-limit.hbs b/server/sonar-web/src/main/js/widgets/issue-filter/templates/_widget-issue-filter-limit.hbs new file mode 100644 index 00000000000..6da82834180 --- /dev/null +++ b/server/sonar-web/src/main/js/widgets/issue-filter/templates/_widget-issue-filter-limit.hbs @@ -0,0 +1 @@ +<div class="note text-center spacer-top">{{tp 'max_items_reached' maxResults}}</div> diff --git a/server/sonar-web/src/main/js/widgets/issue-filter/templates/_widget-issue-filter-total.hbs b/server/sonar-web/src/main/js/widgets/issue-filter/templates/_widget-issue-filter-total.hbs new file mode 100644 index 00000000000..03fb4134f4a --- /dev/null +++ b/server/sonar-web/src/main/js/widgets/issue-filter/templates/_widget-issue-filter-total.hbs @@ -0,0 +1,11 @@ +<tr> + <td> + <a href="{{issueFilterTotalLink parsedQuery}}"><strong>{{t 'total'}}</strong></a> + </td> + <td class="text-right"><strong>{{#notNull periodDate}}+{{/notNull}}{{numberShort total}}</strong></td> + <td class="barchart"> + <div class="barchart" style="width: 100%;"> + <div style="width: 100%;"></div> + </div> + </td> +</tr> diff --git a/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-action-plans.hbs b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-action-plans.hbs new file mode 100644 index 00000000000..07c9b17f40c --- /dev/null +++ b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-action-plans.hbs @@ -0,0 +1,26 @@ +<table class="data zebra"> + {{> '_widget-issue-filter-total'}} + {{#each items}} + <tr> + <td> + {{#eq val ''}} + <a href="{{issueFilterItemLink ../../parsedQuery 'planned' 'false'}}">{{t 'issue.unplanned'}}</a> + {{else}} + <a href="{{issueFilterItemLink ../../parsedQuery 'actionPlans' val}}">{{default label val}}</a> + {{/eq}} + </td> + <td class="text-right nowrap"> + {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + </td> + <td class="barchart"> + <div class="barchart" style="width: 100%;"> + <div style="width: {{percent count ../total}};"></div> + </div> + </td> + </tr> + {{/each}} +</table> + +{{#if maxResultsReached}} + {{> '_widget-issue-filter-limit'}} +{{/if}} diff --git a/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-assignees.hbs b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-assignees.hbs new file mode 100644 index 00000000000..494104f3ee9 --- /dev/null +++ b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-assignees.hbs @@ -0,0 +1,26 @@ +<table class="data zebra"> + {{> '_widget-issue-filter-total'}} + {{#each items}} + <tr> + <td> + {{#eq val ''}} + <a href="{{issueFilterItemLink ../../parsedQuery 'assigned' 'false'}}">{{t 'unassigned'}}</a> + {{else}} + <a href="{{issueFilterItemLink ../../parsedQuery 'assignees' val}}">{{default label val}}</a> + {{/eq}} + </td> + <td class="text-right nowrap"> + {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + </td> + <td class="barchart"> + <div class="barchart" style="width: 100%;"> + <div style="width: {{percent count ../total}};"></div> + </div> + </td> + </tr> + {{/each}} +</table> + +{{#if maxResultsReached}} + {{> '_widget-issue-filter-limit'}} +{{/if}} diff --git a/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-resolutions.hbs b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-resolutions.hbs new file mode 100644 index 00000000000..50827ba41bb --- /dev/null +++ b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-resolutions.hbs @@ -0,0 +1,26 @@ +<table class="data zebra"> + {{> '_widget-issue-filter-total'}} + {{#each items}} + <tr> + <td> + {{#eq val ''}} + <a href="{{issueFilterItemLink ../../parsedQuery 'resolved' 'false'}}">{{t 'unresolved'}}</a> + {{else}} + <a href="{{issueFilterItemLink ../../parsedQuery 'resolutions' val}}">{{t 'issue.resolution' val}}</a> + {{/eq}} + </td> + <td class="text-right nowrap"> + {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + </td> + <td class="barchart"> + <div class="barchart" style="width: 100%;"> + <div style="width: {{percent count ../total}};"></div> + </div> + </td> + </tr> + {{/each}} +</table> + +{{#if maxResultsReached}} + {{> '_widget-issue-filter-limit'}} +{{/if}} diff --git a/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-severities.hbs b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-severities.hbs new file mode 100644 index 00000000000..3ca50c03da5 --- /dev/null +++ b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-severities.hbs @@ -0,0 +1,23 @@ +<table class="data zebra"> + <tr> + <td> + <a href="{{issueFilterTotalLink parsedQuery}}"><strong>{{t 'total'}}</strong></a> + </td> + <td class="text-right"><strong>{{#notNull periodDate}}+{{/notNull}}{{numberShort total}}</strong></td> + </tr> + {{#each items}} + <tr> + <td> + {{severityIcon val}} + <a href="{{issueFilterItemLink ../parsedQuery ../property val}}">{{t 'severity' val}}</a> + </td> + <td class="text-right nowrap"> + {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + </td> + </tr> + {{/each}} +</table> + +{{#if maxResultsReached}} + {{> '_widget-issue-filter-limit'}} +{{/if}} diff --git a/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-statuses.hbs b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-statuses.hbs new file mode 100644 index 00000000000..70d5a57c765 --- /dev/null +++ b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter-statuses.hbs @@ -0,0 +1,23 @@ +<table class="data zebra"> + {{> '_widget-issue-filter-total'}} + {{#each items}} + <tr> + <td> + {{statusIcon val}} + <a href="{{issueFilterItemLink ../parsedQuery ../property val}}">{{t 'issue.status' val}}</a> + </td> + <td class="text-right nowrap"> + {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + </td> + <td class="barchart"> + <div class="barchart" style="width: 100%;"> + <div style="width: {{percent count ../total}};"></div> + </div> + </td> + </tr> + {{/each}} +</table> + +{{#if maxResultsReached}} + {{> '_widget-issue-filter-limit'}} +{{/if}} diff --git a/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter.hbs b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter.hbs new file mode 100644 index 00000000000..dc78bba0232 --- /dev/null +++ b/server/sonar-web/src/main/js/widgets/issue-filter/templates/widget-issue-filter.hbs @@ -0,0 +1,22 @@ +<table class="data zebra"> + {{> '_widget-issue-filter-total'}} + {{#each items}} + <tr> + <td> + <a href="{{searchLink}}">{{default label val}}</a> + </td> + <td class="text-right nowrap"> + {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + </td> + <td class="barchart"> + <div class="barchart" style="width: 100%;"> + <div style="width: {{percent count ../total}};"></div> + </div> + </td> + </tr> + {{/each}} +</table> + +{{#if maxResultsReached}} + {{> '_widget-issue-filter-limit'}} +{{/if}} diff --git a/server/sonar-web/src/main/js/widgets/issue-filter.js b/server/sonar-web/src/main/js/widgets/issue-filter/widget.js index cea0f151b50..2fb96c7d2e7 100644 --- a/server/sonar-web/src/main/js/widgets/issue-filter.js +++ b/server/sonar-web/src/main/js/widgets/issue-filter/widget.js @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -define(['templates/widgets'], function () { +define(['./templates'], function () { var $ = jQuery, FACET_LIMIT = 15, diff --git a/server/sonar-web/src/main/js/widgets/pie-chart.js b/server/sonar-web/src/main/js/widgets/pie-chart.js deleted file mode 100644 index a88f0941c55..00000000000 --- a/server/sonar-web/src/main/js/widgets/pie-chart.js +++ /dev/null @@ -1,417 +0,0 @@ -/* - * 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. - */ -/*global d3:false, baseUrl:false */ -/*jshint eqnull:true */ - -window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; - -(function () { - - window.SonarWidgets.PieChart = function () { - // Set default values - this._components = []; - this._metrics = []; - this._metricsPriority = []; - this._width = window.SonarWidgets.PieChart.defaults.width; - this._height = window.SonarWidgets.PieChart.defaults.height; - this._margin = window.SonarWidgets.PieChart.defaults.margin; - this._legendWidth = window.SonarWidgets.PieChart.defaults.legendWidth; - this._legendMargin = window.SonarWidgets.PieChart.defaults.legendMargin; - this._detailsWidth = window.SonarWidgets.PieChart.defaults.detailsWidth; - this._options = {}; - - this._lineHeight = 20; - - - // Export global variables - this.metrics = function (_) { - return param.call(this, '_metrics', _); - }; - - this.metricsPriority = function (_) { - return param.call(this, '_metricsPriority', _); - }; - - this.components = function (_) { - return param.call(this, '_components', _); - }; - - this.width = function (_) { - return param.call(this, '_width', _); - }; - - this.height = function (_) { - return param.call(this, '_height', _); - }; - - this.margin = function (_) { - return param.call(this, '_margin', _); - }; - - this.legendWidth = function (_) { - return param.call(this, '_legendWidth', _); - }; - - this.legendMargin = function (_) { - return param.call(this, '_legendMargin', _); - }; - - this.detailsWidth = function (_) { - return param.call(this, '_detailsWidth', _); - }; - - this.options = function (_) { - return param.call(this, '_options', _); - }; - }; - - window.SonarWidgets.PieChart.prototype.render = function (container) { - var widget = this, - containerS = container; - - container = d3.select(container); - - - var validData = this.components().reduce(function(p, c) { - return p && !!c.measures[widget.metricsPriority()[0]]; - }, true); - - if (!validData) { - container.text(this.options().noMainMetric); - return; - } - - - this.width(container.property('offsetWidth')); - - this.svg = container.append('svg') - .attr('class', 'sonar-d3'); - this.gWrap = this.svg.append('g'); - - this.plotWrap = this.gWrap.append('g') - .classed('plot', true); - - this.gWrap - .attr('transform', trans(this.margin().left, this.margin().top)); - - - // Configure metrics - this.mainMetric = this.metricsPriority()[0]; - this.getMainMetric = function(d) { - return d.measures[widget.mainMetric].val; - }; - - - // Configure scales - this.color = d3.scale.category10(); - - - // Configure arc - this.arc = d3.svg.arc() - .innerRadius(0); - - - // Configure pie - this.pie = d3.layout.pie() - .sort(null) - .value(function(d) { return widget.getMainMetric(d); }); - - - // Configure legend - this.legendWrap = this.gWrap.append('g'); - - - // Configure details - this._metricsCount = Object.keys(this.metrics()).length + 1; - this._detailsHeight = this._lineHeight * this._metricsCount; - - this.detailsWrap = this.gWrap.append('g') - .attr('width', this.legendWidth()) - .style('display', 'none'); - - this.detailsColorIndicator = this.detailsWrap.append('rect') - .classed('details-color-indicator', true) - .attr('transform', trans(-1, 0)) - .attr('x', 0) - .attr('y', 0) - .attr('width', 3) - .attr('height', this._detailsHeight) - .style('opacity', 0); - - this.donutLabel = this.plotWrap.append('text') - .style('text-anchor', 'middle') - .style('opacity', 0); - - this.donutLabel2 = this.plotWrap.append('text') - .style('text-anchor', 'middle') - .text(this.metrics()[this.mainMetric].name); - - - // Update widget - this.update(containerS); - - return this; - }; - - - window.SonarWidgets.PieChart.prototype.updateLegend = function () { - var widget = this; - this.legendWrap - .attr('transform', trans( - this.legendMargin() + 2 * this.radius, - (this.availableHeight - this._legendSize * this._lineHeight) / 2 - )); - - this.legends = this.legendWrap.selectAll('.legend') - .data(this.components().slice(0, this._legendSize)); - - this.legendsEnter = this.legends.enter() - .append('g') - .classed('legend pie-legend', true) - .attr('transform', function(d, i) { return trans(0, 10 + i * widget._lineHeight); }); - - this.legendsEnter.append('circle') - .attr('class', 'legend-bullet') - .attr('r', 4) - .style('fill', function(d, i) { return widget.color(i); }); - - this.legendsEnter.append('text') - .attr('class', 'legend-text') - .attr('dy', '0.1em') - .attr('transform', trans(10, 3)); - - this.legends.selectAll('text') - .text(function(d) { - return d.name.length > widget._legendSymbols ? d.name.substr(0, widget._legendSymbols) + '...' : d.name; - }); - }; - - - window.SonarWidgets.PieChart.prototype.updateDetails = function () { - var widget = this; - this.detailsWrap - .attr('width', this.legendWidth()) - .attr('transform', trans( - this.legendMargin() + 2 * this.radius, this.radius - this._detailsHeight / 2 - )); - - this.donutLabel - .transition() - .style('font-size', (this.radius / 6) + 'px'); - - var fz = Math.min( - 12, - this.radius / 10, - 1.5 * this.radius / this.metrics()[this.mainMetric].name.length - ); - this.donutLabel2 - .attr('transform', trans(0, widget.radius / 6)) - .style('font-size', fz + 'px'); - }; - - - window.SonarWidgets.PieChart.prototype.configureEvents = function () { - var widget = this; - var updateMetrics = function(metrics) { - widget.detailsMetrics = widget.detailsWrap.selectAll('.details-metric') - .data(metrics); - - widget.detailsMetrics.enter().append('text') - .classed('details-metric', true) - .classed('details-metric-main', function(d, i) { return i === 0; }) - .attr('transform', function(d, i) { return trans(10, i * widget._lineHeight); }) - .attr('dy', '1.2em'); - - widget.detailsMetrics - .text(function(d) { return d.name + (d.value ? ': ' + d.value : ''); }) - .style('opacity', 1); - - widget.detailsMetrics.exit().remove(); - }, - enterHandler = function(sector, d, i, showDetails) { - if (showDetails) { - var metrics = widget.metricsPriority().map(function(m) { - return { - name: widget.metrics()[m].name, - value: (!!d.measures[m] ? d.measures[m].fval : '–') - }; - }); - metrics.unshift({ - name: (d.name.length > widget._legendSymbols ? d.name.substr(0, widget._legendSymbols) + '...' : d.name) - }); - updateMetrics(metrics); - - widget.legendWrap - .style('opacity', 0); - - widget.detailsColorIndicator - .style('opacity', 1) - .style('fill', widget.color(i)); - - widget.detailsWrap - .style('display', 'block'); - } - widget.donutLabel - .style('opacity', 1) - .text(d.measures[widget.mainMetric].fval); - widget.donutLabel - .style('opacity', 1); - widget.plotWrap - .classed('hover', true); - sector. - classed('hover', true); - }, - - leaveHandler = function(sector) { - widget.legendWrap - .style('opacity', 1); - widget.detailsColorIndicator - .style('opacity', 0); - if (widget.detailsMetrics) { - widget.detailsMetrics - .style('opacity', 0); - } - widget.donutLabel - .style('opacity', 0) - .text(''); - widget.plotWrap - .classed('hover', false); - sector. - classed('hover', false); - widget.detailsWrap - .style('display', 'none'); - }, - - clickHandler = function(d) { - window.location = widget.options().baseUrl + '?id=' + encodeURIComponent(d.key); - }; - - this.sectors - .on('mouseenter', function(d, i) { - return enterHandler(d3.select(this), d.data, i, true); - }) - .on('mouseleave', function(d, i) { - return leaveHandler(d3.select(this), d.data, i, true); - }) - .on('click', function(d) { - return clickHandler(d.data); - }); - - this.legends - .on('mouseenter', function(d, i) { - return enterHandler(d3.select(widget.sectors[0][i]), d, i, false); - }) - .on('mouseleave', function(d, i) { - return leaveHandler(d3.select(widget.sectors[0][i]), d, i, false); - }) - .on('click', function(d) { - return clickHandler(d); - }); - }; - - - window.SonarWidgets.PieChart.prototype.update = function(container) { - container = d3.select(container); - - var widget = this, - width = container.property('offsetWidth'); - this.width(width > 100 ? width : 100); - - - // Update svg canvas - this.svg - .attr('width', this.width()) - .attr('height', this.height()); - - - // Update available size - this.availableWidth = this.width() - this.margin().left - this.margin().right - - this.legendWidth() - this.legendMargin(); - this.availableHeight = this.height() - this.margin().top - this.margin().bottom; - this.radius = Math.min(this.availableWidth, this.availableHeight) / 2; - this._legendSize = Math.floor(this.availableHeight / this._lineHeight); - this._legendSymbols = Math.floor((this.width() - this.margin().left - this.margin().right - - this.legendMargin() - 2 * this.radius) / 6.2); - - - // Update plot - this.plotWrap - .attr('transform', trans(this.radius, this.radius)); - - - // Update arc - this.arc - .innerRadius(this.radius / 2) - .outerRadius(this.radius); - - - // Configure sectors - this.sectors = this.plotWrap.selectAll('.arc') - .data(this.pie(this.components())); - - this.sectors - .enter() - .append('path') - .classed('arc', true) - .style('fill', function(d, i) { return widget.color(i); }); - - this.sectors - .transition() - .attr('d', this.arc); - - this.sectors - .exit().remove(); - - - this.updateLegend(); - this.updateDetails(); - this.configureEvents(); - }; - - - - window.SonarWidgets.PieChart.defaults = { - width: 350, - height: 300, - margin: { top: 10, right: 10, bottom: 10, left: 10 }, - legendWidth: 160, - legendMargin: 30 - }; - - - - // Some helper functions - - // Gets or sets parameter - function param(name, value) { - if (value == null) { - return this[name]; - } else { - this[name] = value; - return this; - } - } - - // Helper for create the translate(x, y) string - function trans(left, top) { - return 'translate(' + left + ', ' + top + ')'; - } - -})(); diff --git a/server/sonar-web/src/main/js/widgets/stack-area.js b/server/sonar-web/src/main/js/widgets/stack-area.js deleted file mode 100644 index 993828be5bf..00000000000 --- a/server/sonar-web/src/main/js/widgets/stack-area.js +++ /dev/null @@ -1,404 +0,0 @@ -/* - * 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. - */ -window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; - -(function () { - - window.SonarWidgets.StackArea = function (container) { - - // Ensure container is html id - if (container.indexOf('#') !== 0) { - container = '#' + container; - } - - this.container = d3.select(container); - - - // Set default values - this._data = []; - this._metrics = []; - this._snapshots = []; - this._colors = []; - this._width = window.SonarWidgets.StackArea.defaults.width; - this._height = window.SonarWidgets.StackArea.defaults.height; - this._margin = window.SonarWidgets.StackArea.defaults.margin; - - // Export global variables - this.data = function (_) { - return param.call(this, '_data', _); - }; - - this.metrics = function (_) { - return param.call(this, '_metrics', _); - }; - - this.snapshots = function (_) { - return param.call(this, '_snapshots', _); - }; - - this.colors = function (_) { - return param.call(this, '_colors', _); - }; - - this.width = function (_) { - return param.call(this, '_width', _); - }; - - this.height = function (_) { - return param.call(this, '_height', _); - }; - - this.margin = function (_) { - return param.call(this, '_margin', _); - }; - - }; - - - window.SonarWidgets.StackArea.prototype.initScales = function() { - var widget = this, - colorsLength = widget.colors().length; - var timeDomain = this.data() - .map(function(_) { - return d3.extent(_, function(d) { - return d.x; - }); - }) - .reduce(function(p, c) { - return p.concat(c); - }, []); - - this.time = d3.time.scale().domain(d3.extent(timeDomain)); - - this.y = d3.scale.linear() - .domain([0, d3.max(this.stackDataTop, function(d) { - return d.y0 + d.y; - })]) - .nice(); - - this.color = function(i) { - return widget.colors()[i % colorsLength][0]; - }; - }; - - - window.SonarWidgets.StackArea.prototype.initAxis = function() { - this.timeAxis = d3.svg.axis() - .scale(this.time) - .orient('bottom') - .ticks(5); - }; - - - window.SonarWidgets.StackArea.prototype.initArea = function() { - var widget = this; - this.area = d3.svg.area() - .x(function(d) { return widget.time(d.x); }) - .y0(function(d) { return widget.y(d.y0); }) - .y1(function(d) { return widget.y(d.y0 + d.y); }); - - this.areaLine = d3.svg.line() - .x(function(d) { return widget.time(d.x); }) - .y(function(d) { return widget.y(d.y0 + d.y); }); - }; - - - window.SonarWidgets.StackArea.prototype.initInfo = function() { - var widget = this; - this.infoWrap - .attr('class', 'info') - .attr('transform', trans(0, -60)); - - this.infoDate - .attr('class', 'info-text info-text-bold') - .attr('transform', trans(0, 0)); - - this.infoTotal - .attr('class', 'info-text info-text-small') - .attr('transform', trans(0, 18)); - - this.infoSnapshot - .attr('class', 'info-text info-text-small') - .attr('transform', trans(0, 54)); - - this.infoMetrics = []; - var prevX = 120; - this.metrics().forEach(function(d, i) { - var infoMetric = widget.infoWrap.append('g'); - - var infoMetricText = infoMetric.append('text') - .attr('class', 'info-text-small') - .attr('transform', trans(10, 0)) - .text(widget.metrics()[i]); - - infoMetric.append('circle') - .attr('transform', trans(0, -4)) - .attr('r', 4) - .style('fill', function() { return widget.color(i); }); - - // Align metric labels - infoMetric - .attr('transform', function() { - return trans(prevX, -1 + (i % 3) * 18); - }); - - widget.infoMetrics.push(infoMetric); - - if (i % 3 === 2) { - prevX += (infoMetricText.node().getComputedTextLength() + 70); - } - }); - }; - - - window.SonarWidgets.StackArea.prototype.initEvents = function() { - var widget = this; - this.events = widget.snapshots() - .filter(function(d) { return d.e.length > 0; }); - - this.gevents = this.gWrap.append('g') - .attr('class', 'axis events') - .selectAll('.event-tick') - .data(this.events); - - this.gevents.enter().append('line') - .attr('class', 'event-tick') - .attr('y2', -8); - - - this.selectSnapshot = function(cl) { - var dataX = widget.data()[0][cl].x, - sx = widget.time(dataX), - snapshotIndex = null, - eventIndex = null; - - // Update scanner position - widget.scanner - .attr('x1', sx) - .attr('x2', sx); - - - // Update metric labels - var metricsLines = widget.data().map(function(d, i) { - var value = d[cl].fy || d[cl].y; - return widget.metrics()[i] + ': ' + value; - }); - - metricsLines.forEach(function(d, i) { - widget.infoMetrics[i].select('text').text(d); - }); - - - // Update snapshot info - this.snapshots().forEach(function(d, i) { - if (d.d - dataX === 0) { - snapshotIndex = i; - } - }); - - if (snapshotIndex != null) { - widget.infoSnapshot - .text(this.snapshots()[snapshotIndex].e.join(', ')); - } - - - // Update info - widget.infoDate - .text(moment(widget.data()[0][cl].x).format('LL')); - - var snapshotValue = this.snapshots()[snapshotIndex].fy, - totalValue = snapshotValue || (widget.stackDataTop[cl].y0 + widget.stackDataTop[cl].y); - widget.infoTotal - .text('Total: ' + totalValue); - - - // Update event - this.events.forEach(function(d, i) { - if (d.d - dataX === 0) { - eventIndex = i; - } - }); - - widget.gevents.attr('y2', -8); - d3.select(widget.gevents[0][eventIndex]).attr('y2', -12); - }; - - - // Set event listeners - this.svg.on('mousemove', function() { - var mx = d3.mouse(widget.plotWrap.node())[0], - cl = closest(widget.data()[0], mx, function(d) { return widget.time(d.x); }); - widget.selectSnapshot(cl); - }); - }; - - - window.SonarWidgets.StackArea.prototype.render = function () { - this.svg = this.container.append('svg') - .attr('class', 'sonar-d3'); - - this.gWrap = this.svg.append('g'); - - this.gtimeAxis = this.gWrap.append('g') - .attr('class', 'axis x'); - - this.plotWrap = this.gWrap.append('g') - .attr('class', 'plot'); - - this.scanner = this.plotWrap.append('line'); - - this.infoWrap = this.gWrap.append('g'); - this.infoDate = this.infoWrap.append('text'); - this.infoSnapshot = this.infoWrap.append('text'); - this.infoTotal = this.infoWrap.append('text'); - - this.gWrap - .attr('transform', trans(this.margin().left, this.margin().top)); - - // Configure stack - this.stack = d3.layout.stack(); - this.stackData = this.stack(this.data()); - this.stackDataTop = this.stackData[this.stackData.length - 1]; - - this.initScales(); - this.initAxis(); - this.initArea(); - - // Configure scanner - this.scanner - .attr('class', 'scanner') - .attr('y1', 0); - - this.initInfo(); - this.initEvents(); - this.update(); - - return this; - }; - - - window.SonarWidgets.StackArea.prototype.update = function() { - var widget = this, - width = this.container.property('offsetWidth'); - - this.width(width > 100 ? width : 100); - - - // Update svg canvas - this.svg - .attr('width', this.width()) - .attr('height', this.height()); - - - // Update available size - this.availableWidth = this.width() - this.margin().left - this.margin().right; - this.availableHeight = this.height() - this.margin().top - this.margin().bottom; - - - // Update scales - this.time.range([0, this.availableWidth]); - this.y.range([widget.availableHeight, 0]); - - - // Update the axis - this.gtimeAxis.attr('transform', trans(0, this.availableHeight + this.margin().bottom - 30)); - this.gtimeAxis.transition().call(this.timeAxis); - - - // Update area - this.garea = this.plotWrap.selectAll('.area') - .data(this.stackData) - .enter() - .insert('path', ':first-child') - .attr('class', 'area') - .attr('d', function(d) { return widget.area(d); }) - .style('fill', function(d, i) { return widget.color(i); }); - - this.gareaLine = this.plotWrap.selectAll('.area-line') - .data(this.stackData) - .enter() - .insert('path') - .attr('class', 'area-line') - .attr('d', function(d) { return widget.areaLine(d); }) - .style('fill', 'none') - .style('stroke', '#808080'); - - - // Update scanner - this.scanner.attr('y2', this.availableHeight + 10); - - - // Update events - this.gevents - .transition() - .attr('transform', function(d) { - return trans(widget.time(d.d), widget.availableHeight + 10); - }); - - - // Select latest values if this it the first update - if (!this.firstUpdate) { - this.selectSnapshot(widget.data()[0].length - 1); - - this.firstUpdate = true; - } - - }; - - - - window.SonarWidgets.StackArea.defaults = { - width: 350, - height: 150, - margin: { top: 80, right: 10, bottom: 40, left: 40 } - }; - - - - // Some helper functions - - // Gets or sets parameter - function param(name, value) { - if (value == null) { - return this[name]; - } else { - this[name] = value; - return this; - } - } - - // Helper for create the translate(x, y) string - function trans(left, top) { - return 'translate(' + left + ', ' + top + ')'; - } - - // Helper for find the closest number in array - function closest(array, number, getter) { - var cl = null; - array.forEach(function(value, i) { - if (cl == null || - Math.abs(getter(value) - number) < Math.abs(getter(array[cl]) - number)) { - cl = i; - } - }); - return cl; - } - -})(); diff --git a/server/sonar-web/src/main/js/widgets/timeline.js b/server/sonar-web/src/main/js/widgets/timeline.js deleted file mode 100644 index 5b871e5994e..00000000000 --- a/server/sonar-web/src/main/js/widgets/timeline.js +++ /dev/null @@ -1,417 +0,0 @@ -/* - * 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. - */ -/*global d3:false*/ - -window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; - -(function () { - - window.SonarWidgets.Timeline = function (container) { - - // Ensure container is html id - if (container.indexOf('#') !== 0) { - container = '#' + container; - } - - this.container = d3.select(container); - - // Set default values - this._data = []; - this._metrics = []; - this._snapshots = []; - this._events = []; - this._width = window.SonarWidgets.Timeline.defaults.width; - this._height = window.SonarWidgets.Timeline.defaults.height; - this._margin = window.SonarWidgets.Timeline.defaults.margin; - - // Export global variables - this.data = function (_) { - return param.call(this, '_data', _); - }; - - this.metrics = function (_) { - return param.call(this, '_metrics', _); - }; - - this.snapshots = function (_) { - return param.call(this, '_snapshots', _); - }; - - this.events = function (_) { - return param.call(this, '_events', _); - }; - - this.width = function (_) { - return param.call(this, '_width', _); - }; - - this.height = function (_) { - return param.call(this, '_height', _); - }; - - this.margin = function (_) { - return param.call(this, '_margin', _); - }; - - }; - - - window.SonarWidgets.Timeline.prototype.initScalesAndAxis = function () { - // Configure scales - var timeDomain = this.data() - .map(function(_) { - return d3.extent(_, function(d) { - return d.x; - }); - }) - .reduce(function(p, c) { - return p.concat(c); - }, []); - - this.time = d3.time.scale().domain(d3.extent(timeDomain)); - - this.y = this.data().map(function(_) { - return d3.scale.linear() - .domain(d3.extent(_, function(d) { return d.y; })); - }); - - this.color = d3.scale.category10(); - - // Configure the axis - this.timeAxis = d3.svg.axis() - .scale(this.time) - .orient('bottom') - .ticks(5); - }; - - - window.SonarWidgets.Timeline.prototype.initEvents = function () { - var widget = this; - this.events(this.events().filter(function (event) { - return event.d >= widget.time.domain()[0]; - })); - - this.gevents = this.gWrap.append('g') - .attr('class', 'axis events') - .selectAll('.event-tick') - .data(this.events()); - - this.gevents.enter().append('line') - .attr('class', 'event-tick') - .attr('y2', -8); - - this.gevents.exit().remove(); - - - this.selectSnapshot = function(cl) { - var sx = widget.time(widget.data()[0][cl].x); - - widget.markers.forEach(function(marker) { - marker.style('opacity', 0); - d3.select(marker[0][cl]).style('opacity', 1); - }); - - widget.scanner - .attr('x1', sx) - .attr('x2', sx); - - widget.infoDate - .text(moment(widget.data()[0][cl].x).format('LL')); - - var metricsLines = widget.data().map(function(d, i) { - return widget.metrics()[i] + ': ' + d[cl].yl; - }); - - metricsLines.forEach(function(d, i) { - widget.infoMetrics[i].select('text').text(d); - }); - - widget.gevents.attr('y2', -8); - widget.infoEvent.text(''); - widget.events().forEach(function(d, i) { - if (d.d - widget.data()[0][cl].x === 0) { - d3.select(widget.gevents[0][i]).attr('y2', -12); - - widget.infoEvent - .text(widget.events()[i].l - .map(function(e) { return e.n; }) - .join(', ')); - } - }); - }; - - - // Set event listeners - this.svg.on('mousemove', function() { - var mx = d3.mouse(widget.plotWrap.node())[0], - cl = closest(widget.data()[0], mx, function(d) { return widget.time(d.x); }); - widget.selectSnapshot(cl); - }); - }; - - - window.SonarWidgets.Timeline.prototype.render = function () { - var widget = this; - - this.svg = this.container.append('svg') - .attr('class', 'sonar-d3'); - - this.gWrap = this.svg.append('g'); - - this.gtimeAxis = this.gWrap.append('g') - .attr('class', 'axis x'); - - this.plotWrap = this.gWrap.append('g') - .attr('class', 'plot'); - - this.scanner = this.plotWrap.append('line'); - - this.infoWrap = this.gWrap.append('g') - .attr('class', 'info'); - - this.infoDate = this.infoWrap.append('text') - .attr('class', 'info-text info-text-bold'); - - this.infoEvent = this.infoWrap.append('text') - .attr('class', 'info-text info-text-small'); - - this.gWrap - .attr('transform', trans(this.margin().left, this.margin().top)); - - this.initScalesAndAxis(); - this.showLimitHistoryMessage(); - - // Configure lines and points - this.lines = []; - this.glines = []; - this.markers = []; - this.data().forEach(function(_, i) { - var line = d3.svg.line() - .x(function(d) { return widget.time(d.x); }) - .y(function(d) { return widget.y[i](d.y); }) - .interpolate('linear'); - - var gline = widget.plotWrap.append('path') - .attr('class', 'line') - .style('stroke', function() { return widget.color(i); }); - - widget.lines.push(line); - widget.glines.push(gline); - - var marker = widget.plotWrap.selectAll('.marker').data(_); - marker.enter().append('circle') - .attr('class', 'line-marker') - .attr('r', 3) - .style('stroke', function() { return widget.color(i); }); - marker.exit().remove(); - - widget.markers.push(marker); - }); - - - // Configure scanner - this.scanner - .attr('class', 'scanner') - .attr('y1', 0); - - - // Configure info - this.infoWrap - .attr('transform', trans(0, -30)); - - this.infoDate - .attr('transform', trans(0, 0)); - - this.infoMetrics = []; - this.metrics().forEach(function(d, i) { - var infoMetric = widget.infoWrap.append('g') - .attr('class', 'metric-legend') - .attr('transform', function() { return trans(110 + i * 150, -1); }); - - infoMetric.append('text') - .attr('class', 'info-text-small') - .attr('transform', trans(10, 0)); - - infoMetric.append('circle') - .attr('class', 'metric-legend-line') - .attr('transform', trans(0, -4)) - .attr('r', 4) - .style('fill', function() { return widget.color(i); }); - - widget.infoMetrics.push(infoMetric); - }); - - this.initEvents(); - this.update(); - - return this; - }; - - - window.SonarWidgets.Timeline.prototype.showLimitHistoryMessage = function () { - var minEvent = d3.min(this.events(), function (d) { - return d.d; - }), - minData = this.time.domain()[0]; - if (minEvent < minData) { - var maxResultsReachedLabel = this.container.append('div').text(this.limitedHistoricalData); - maxResultsReachedLabel.classed('max-results-reached-message', true); - } - }; - - - window.SonarWidgets.Timeline.prototype.update = function() { - var widget = this, - width = this.container.property('offsetWidth'); - - this.width(width > 100 ? width : 100); - - - // Update svg canvas - this.svg - .attr('width', this.width()) - .attr('height', this.height()); - - - // Update available width - this.availableWidth = this.width() - this.margin().left - this.margin().right; - - - // Update metric lines - var metricY = -1; - this.infoMetrics.forEach(function(metric, i) { - var x = 120 + i * 170, - x2 = x + 170; - - if (x2 > widget.availableWidth) { - metricY += 18; - x = 120; - } - - metric - .transition() - .attr('transform', function() { return trans(x, metricY); }); - }); - - if (metricY > -1) { - metricY += 17; - } - - // Update available width - this.availableHeight = this.height() - this.margin().top - this.margin().bottom - metricY; - - - // Update scales - this.time - .range([0, this.availableWidth]); - - this.y.forEach(function(scale) { - scale.range([widget.availableHeight, 0]); - }); - - - // Update plot - this.plotWrap - .transition() - .attr('transform', trans(0, metricY)); - - - // Update the axis - this.gtimeAxis.attr('transform', trans(0, this.availableHeight + this.margin().bottom - 30 + metricY)); - - this.gtimeAxis.transition().call(this.timeAxis); - - - // Update lines and points - this.data().forEach(function(_, i) { - widget.glines[i] - .transition() - .attr('d', widget.lines[i](_)); - - widget.markers[i] - .data(_) - .transition() - .attr('transform', function(d) { return trans(widget.time(d.x), widget.y[i](d.y)); }); - }); - - - // Update scanner - this.scanner - .attr('y2', this.availableHeight + 10); - - - // Update events - this.infoEvent - .attr('transform', trans(0, metricY > -1 ? metricY : 18)); - - this.gevents - .transition() - .attr('transform', function(d) { return trans(widget.time(d.d), widget.availableHeight + 10 + metricY); }); - - - // Select latest values if this it the first update - if (!this.firstUpdate) { - this.selectSnapshot(widget.data()[0].length - 1); - - this.firstUpdate = true; - } - - }; - - - - window.SonarWidgets.Timeline.defaults = { - width: 350, - height: 150, - margin: { top: 50, right: 10, bottom: 40, left: 10 } - }; - - - - // Some helper functions - - // Gets or sets parameter - function param(name, value) { - if (value == null) { - return this[name]; - } else { - this[name] = value; - return this; - } - } - - // Helper for create the translate(x, y) string - function trans(left, top) { - return 'translate(' + left + ', ' + top + ')'; - } - - // Helper for find the closest number in array - function closest(array, number, getter) { - var cl = null; - array.forEach(function(value, i) { - if (cl == null || - Math.abs(getter(value) - number) < Math.abs(getter(array[cl]) - number)) { - cl = i; - } - }); - return cl; - } - -})(); diff --git a/server/sonar-web/src/main/js/widgets/widget.js b/server/sonar-web/src/main/js/widgets/widget.js deleted file mode 100644 index cd30319f885..00000000000 --- a/server/sonar-web/src/main/js/widgets/widget.js +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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. - */ -/*global d3:false, SonarWidgets:false */ -/*jshint eqnull:true */ - -window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; - -(function () { - - window.SonarWidgets.Widget = function () { - // Set default values - this._type = null; - this._source = null; - this._metricsPriority = null; - this._height = null; - this._options = {}; - - - // Export global variables - this.type = function (_) { - return param.call(this, '_type', _); - }; - - this.source = function (_) { - return param.call(this, '_source', _); - }; - - this.metricsPriority = function (_) { - return param.call(this, '_metricsPriority', _); - }; - - this.height = function (_) { - return param.call(this, '_height', _); - }; - - this.options = function (_) { - return param.call(this, '_options', _); - }; - }; - - - window.SonarWidgets.Widget.prototype.render = function(container) { - var that = this; - - this.showSpinner(container); - d3.json(this.source(), function(error, response) { - if (response && !error) { - that.hideSpinner(); - if (typeof response.components === 'undefined' || response.components.length > 0) { - that.widget = new SonarWidgets[that.type()](); - that.widget.metricsPriority(that.metricsPriority()); - that.widget.options(that.options()); - that.widget.metrics(response.metrics); - that.widget.components(response.components); - if(typeof that.widget.parseSource === 'function') { - that.widget.parseSource(response); - } - if (typeof that.widget.maxResultsReached === 'function') { - that.widget.maxResultsReached(response.paging != null && response.paging.pages > 1); - } - if (that.height()) { - that.widget.height(that.height()); - } - that.widget.render(container); - } else { - d3.select(container).html(that.options().noData); - } - } - }); - }; - - - window.SonarWidgets.Widget.prototype.showSpinner = function(container) { - this.spinner = d3.select(container).append('i').classed('spinner', true); - }; - - - window.SonarWidgets.Widget.prototype.hideSpinner = function() { - if (this.spinner) { - this.spinner.remove(); - } - }; - - - window.SonarWidgets.Widget.prototype.update = function(container) { - return this.widget && this.widget.update(container); - }; - - - - // Some helper functions - - // Gets or sets parameter - function param(name, value) { - if (value == null) { - return this[name]; - } else { - this[name] = value; - return this; - } - } - -})(); |