diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2015-03-31 14:19:01 +0200 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2015-03-31 15:06:10 +0200 |
commit | ac60aa9eef80689f24b10857dbaf83dd1eb412fe (patch) | |
tree | 26ca0078baf516cbe24a389990907e47acbdf79c /server/sonar-web/src/main/js | |
parent | db171f5d73c0b6468efdd612553876406a673786 (diff) | |
download | sonarqube-ac60aa9eef80689f24b10857dbaf83dd1eb412fe.tar.gz sonarqube-ac60aa9eef80689f24b10857dbaf83dd1eb412fe.zip |
SONAR-6331 refactor overview page
Diffstat (limited to 'server/sonar-web/src/main/js')
4 files changed, 172 insertions, 439 deletions
diff --git a/server/sonar-web/src/main/js/graphics/sparkline.js b/server/sonar-web/src/main/js/graphics/sparkline.js index c4c22920271..461c03e13c4 100644 --- a/server/sonar-web/src/main/js/graphics/sparkline.js +++ b/server/sonar-web/src/main/js/graphics/sparkline.js @@ -55,7 +55,7 @@ xScale = d3.time.scale() .domain(d3.extent(data, function (d) { - return new Date(d.val); + return moment(d.val).toDate(); })), yScale = d3.scale.linear() @@ -65,7 +65,7 @@ line = d3.svg.line() .x(function (d) { - return xScale(new Date(d.val)); + return xScale(moment(d.val).toDate()); }) .y(function (d) { return yScale(d.count); diff --git a/server/sonar-web/src/main/js/graphics/timeline.js b/server/sonar-web/src/main/js/graphics/timeline.js deleted file mode 100644 index ef9fd2b0273..00000000000 --- a/server/sonar-web/src/main/js/graphics/timeline.js +++ /dev/null @@ -1,136 +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. - */ -(function ($) { - - function trans (left, top) { - return 'translate(' + left + ', ' + top + ')'; - } - - var defaults = { - height: 140, - color: '#1f77b4', - interpolate: 'basis', - type: 'UNKNOWN' - }; - - /* - * data = [ - * { val: '2015-01-30', count: 30 }, - * ... - * ] - */ - - $.fn.timeline = function (data, opts) { - $(this).each(function () { - var options = _.defaults(opts || {}, $(this).data(), defaults); - _.extend(options, { width: $(this).width() }); - - var container = d3.select(this), - svg = container.append('svg') - .attr('width', options.width + 12) - .attr('height', options.height + 12) - .classed('sonar-d3', true), - - extra = svg.append('g'), - - plot = svg.append('g') - .classed('plot', true), - - xScale = d3.time.scale() - .domain(d3.extent(data, function (d) { - return new Date(d.val); - })), - - yScale = d3.scale.linear() - .domain(d3.extent(data, function (d) { - return d.count; - })), - - line = d3.svg.line() - .x(function (d) { - return xScale(new Date(d.val)); - }) - .y(function (d) { - return yScale(d.count); - }) - .interpolate(options.interpolate); - - // Medians - var medianValue = getNiceMedian(0.5, data, function (d) { - return d.count; - }), - medianLabel = extra.append('text') - .text(window.formatMeasure(medianValue, options.type)) - .style('text-anchor', 'end') - .style('font-size', '10px') - .style('fill', '#ccc') - .attr('dy', '0.32em'), - medianLabelWidth = medianLabel.node().getBBox().width; - - _.extend(options, { - marginLeft: 1, - marginRight: 1 + medianLabelWidth + 4, - marginTop: 6, - marginBottom: 6 - }); - - _.extend(options, { - availableWidth: options.width - options.marginLeft - options.marginRight, - availableHeight: options.height - options.marginTop - options.marginBottom - }); - - plot.attr('transform', trans(options.marginLeft, options.marginTop)); - xScale.range([0, options.availableWidth]); - yScale.range([options.availableHeight, 0]); - - plot.append('path') - .datum(data) - .attr('d', line) - .classed('line', true) - .style('stroke', options.color); - - medianLabel - .attr('x', options.width - 1) - .attr('y', options.marginTop + yScale(medianValue)); - extra.append('line') - .attr('x1', options.marginLeft) - .attr('y1', options.marginTop + yScale(medianValue)) - .attr('x2', options.availableWidth + options.marginLeft) - .attr('y2', options.marginTop + yScale(medianValue)) - .style('stroke', '#eee') - .style('shape-rendering', 'crispedges'); - } - ) - ; - }; - - function getNiceMedian (p, array, accessor) { - var min = d3.min(array, accessor), - max = d3.max(array, accessor), - median = d3.median(array, accessor), - threshold = (max - min) / 2, - threshold10 = Math.pow(10, Math.floor(Math.log(threshold) / Math.LN10) - 1); - return (p - 0.5) > 0.0001 ? - Math.floor(median / threshold10) * threshold10 : - Math.ceil(median / threshold10) * threshold10; - } - -}) -(window.jQuery); diff --git a/server/sonar-web/src/main/js/nav/context-navbar-view.js b/server/sonar-web/src/main/js/nav/context-navbar-view.js index 7c8d3e911c9..6f37d7ab2e4 100644 --- a/server/sonar-web/src/main/js/nav/context-navbar-view.js +++ b/server/sonar-web/src/main/js/nav/context-navbar-view.js @@ -60,10 +60,9 @@ define([ serializeData: function () { var href = window.location.href, - search = window.location.search, isMoreActive = _.some(OVERVIEW_URLS, function (url) { return href.indexOf(url) !== -1; - }); + }), isSettingsActive = _.some(SETTINGS_URLS, function (url) { return href.indexOf(url) !== -1; }); 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 10d51657a77..c8b2f228aeb 100644 --- a/server/sonar-web/src/main/js/overview/models/state.js +++ b/server/sonar-web/src/main/js/overview/models/state.js @@ -19,369 +19,239 @@ */ define(function () { - var $ = jQuery; + var $ = jQuery, + GATE_METRIC = 'quality_gate_details', + SIZE_METRIC = 'ncloc', + ISSUES_METRIC = 'violations', + DEBT_METRIC = 'sqale_index', + COVERAGE_METRIC = 'overall_coverage', + NEW_COVERAGE_METRIC = 'new_overall_coverage', + DUPLICATIONS_METRIC = 'duplicated_lines_density'; return Backbone.Model.extend({ + defaults: function () { return { qualityGateStatus: 'ERROR' }; }, - fetch: function () { - return $.when( - this.fetchGate(), - - this.fetchSize(), - this.fetchSizeTrend(), - - this.fetchIssues(), - this.fetchIssues1(), - this.fetchIssues2(), - this.fetchIssues3(), - this.fetchIssuesTrend(), - - this.fetchDebt(), - this.fetchDebtTrend(), + hasPeriod: function (index) { + var property = 'period' + index + 'Date'; + return !!this.get(property); + }, - this.fetchCoverage(), - this.fetchCoverageTrend(), + fetch: function () { + var that = this; + this.fetchMetrics().done(function () { + that.fetchMeasures(); + that.fetchTrends(); + that.fetchIssues(); + }); + }, - this.fetchDuplications(), - this.fetchDuplicationsTrend() - ); + fetchMetrics: function () { + var that = this, + url = baseUrl + '/api/metrics'; + return $.get(url).done(function (r) { + that.set('metrics', r); + }); }, - fetchGate: function () { + fetchMeasures: function () { var that = this, url = baseUrl + '/api/resources/index', options = { resource: this.get('componentKey'), - metrics: 'quality_gate_details' + metrics: [ + GATE_METRIC, + SIZE_METRIC, + DEBT_METRIC, + COVERAGE_METRIC, + NEW_COVERAGE_METRIC, + DUPLICATIONS_METRIC + ].join(','), + includetrends: true }; return $.get(url, options).done(function (r) { - if (!r || !r[0] || !r[0].msr || !r[0].msr[0] || !r[0].msr[0].data) { + if (!_.isArray(r) || !_.isArray(r[0].msr)) { return; } - var gateData = JSON.parse(r[0].msr[0].data), - gateConditions = gateData.conditions, - urlMetrics = baseUrl + '/api/metrics'; - $.get(urlMetrics).done(function (r) { - var gateConditionsWithMetric = gateConditions.map(function (c) { - var metric = _.findWhere(r, { key: c.metric }), - type = metric != null ? metric.val_type : null, - periodDate = that.get('period' + c.period + 'Date'), - periodName = that.get('period' + c.period + 'Name'); - return _.extend(c, { - type: type, - periodName: periodName, - periodDate: periodDate - }); - }); - that.set({ - gateStatus: gateData.level, - gateConditions: gateConditionsWithMetric - }); - }); + that.parseGate(r[0].msr); + that.parseSize(r[0].msr); + that.parseDebt(r[0].msr); + that.parseCoverage(r[0].msr); + that.parseDuplications(r[0].msr); }); }, - fetchSize: function () { + parseGate: function (msr) { var that = this, - url = baseUrl + '/api/resources/index', - options = { - resource: this.get('componentKey'), - metrics: 'ncloc,ncloc_language_distribution,function_complexity,file_complexity', - includetrends: true - }; - return $.get(url, options).done(function (r) { - var msr = r[0].msr, - nclocMeasure = _.findWhere(msr, { key: 'ncloc' }), - nclocLangMeasure = _.findWhere(msr, { key: 'ncloc_language_distribution' }), - nclocLangParsed = nclocLangMeasure.data.split(';').map(function (token) { - var tokens = token.split('='); - return { key: tokens[0], value: +tokens[1] }; - }), - nclocLangSorted = _.sortBy(nclocLangParsed, function (item) { - return -item.value; - }), - nclocLang = _.first(nclocLangSorted, 2), - functionComplexityMeasure = _.findWhere(msr, { key: 'function_complexity' }), - fileComplexityMeasure = _.findWhere(msr, { key: 'file_complexity' }); - that.set({ - ncloc: nclocMeasure && nclocMeasure.val, - ncloc1: nclocMeasure && nclocMeasure.var1, - ncloc2: nclocMeasure && nclocMeasure.var2, - ncloc3: nclocMeasure && nclocMeasure.var3, - nclocLang: nclocLang, - - functionComplexity: functionComplexityMeasure && functionComplexityMeasure.val, - functionComplexity1: functionComplexityMeasure && functionComplexityMeasure.var1, - functionComplexity2: functionComplexityMeasure && functionComplexityMeasure.var2, - functionComplexity3: functionComplexityMeasure && functionComplexityMeasure.var3, - - fileComplexity: fileComplexityMeasure && fileComplexityMeasure.val, - fileComplexity1: fileComplexityMeasure && fileComplexityMeasure.var1, - fileComplexity2: fileComplexityMeasure && fileComplexityMeasure.var2, - fileComplexity3: fileComplexityMeasure && fileComplexityMeasure.var3 + measure = _.findWhere(msr, { key: GATE_METRIC }); + if (measure != null) { + var metrics = this.get('metrics'), + gateData = JSON.parse(measure.data), + gateConditions = gateData.conditions, + gateConditionsWithMetric = gateConditions.map(function (c) { + var metric = _.findWhere(metrics, { key: c.metric }), + type = metric != null ? metric.val_type : null, + periodDate = that.get('period' + c.period + 'Date'), + periodName = that.get('period' + c.period + 'Name'); + return _.extend(c, { + type: type, + periodName: periodName, + periodDate: periodDate + }); + }); + this.set({ + gateStatus: gateData.level, + gateConditions: gateConditionsWithMetric }); - }); + } }, - fetchSizeTrend: function () { - var that = this, - url = baseUrl + '/api/timemachine/index', - options = { - resource: this.get('componentKey'), - metrics: 'ncloc' - }; - return $.get(url, options).done(function (r) { - var trend = r[0].cells.map(function (cell) { - return { val: cell.d, count: cell.v[0] }; + parseSize: function (msr) { + var nclocMeasure = _.findWhere(msr, { key: SIZE_METRIC }); + if (nclocMeasure != null) { + this.set({ + ncloc: nclocMeasure.val, + ncloc1: nclocMeasure.var1, + ncloc2: nclocMeasure.var2, + ncloc3: nclocMeasure.var3 }); - that.set({ sizeTrend: trend }); - }); + } }, fetchIssues: function () { - var that = this, - url = baseUrl + '/api/issues/search', - options = { - ps: 1, - resolved: 'false', - componentUuids: this.get('componentUuid'), - facets: 'severities,statuses,tags' - }; - return $.get(url, options).done(function (r) { - var severityFacet = _.findWhere(r.facets, { property: 'severities' }), - statusFacet = _.findWhere(r.facets, { property: 'statuses' }), - tagFacet = _.findWhere(r.facets, { property: 'tags' }), - tags = _.first(tagFacet.values, 10), - minTagCount = _.min(tags, function (t) { - return t.count; - }).count, - maxTagCount = _.max(tags, function (t) { - return t.count; - }).count, - tagScale = d3.scale.linear().domain([minTagCount, maxTagCount]).range([10, 24]), - sizedTags = tags.map(function (tag) { - return _.extend(tag, { size: tagScale(tag.count) }); - }); - that.set({ - issues: r.total, - blockerIssues: _.findWhere(severityFacet.values, { val: 'BLOCKER' }).count, - criticalIssues: _.findWhere(severityFacet.values, { val: 'CRITICAL' }).count, - majorIssues: _.findWhere(severityFacet.values, { val: 'MAJOR' }).count, - openIssues: _.findWhere(statusFacet.values, { val: 'OPEN' }).count + - _.findWhere(statusFacet.values, { val: 'REOPENED' }).count, - issuesTags: sizedTags + var that = this; + + function _fetch (field, createdAfter) { + var url = baseUrl + '/api/issues/search', + options = { + ps: 1, + resolved: 'false', + componentUuids: that.get('componentUuid') + }; + if (createdAfter != null) { + _.extend(options, { createdAfter: createdAfter }); + } + return $.get(url, options).done(function (r) { + that.set(field, r.total); }); - }); - }, + } - fetchIssues1: function () { - if (!this.get('period1Date')) { - return; + _fetch('issues', null); + if (this.hasPeriod(1)) { + _fetch('issues1', this.get('period1Date')); } - var that = this, - url = baseUrl + '/api/issues/search', - options = { - ps: 1, - resolved: 'false', - createdAfter: this.get('period1Date'), - componentUuids: this.get('componentUuid'), - facets: 'severities,statuses' - }; - return $.get(url, options).done(function (r) { - var severityFacet = _.findWhere(r.facets, { property: 'severities' }), - statusFacet = _.findWhere(r.facets, { property: 'statuses' }); - that.set({ - issues1: r.total, - blockerIssues1: _.findWhere(severityFacet.values, { val: 'BLOCKER' }).count, - criticalIssues1: _.findWhere(severityFacet.values, { val: 'CRITICAL' }).count, - majorIssues1: _.findWhere(severityFacet.values, { val: 'MAJOR' }).count, - openIssues1: _.findWhere(statusFacet.values, { val: 'OPEN' }).count + - _.findWhere(statusFacet.values, { val: 'REOPENED' }).count + if (this.hasPeriod(2)) { + _fetch('issues2', this.get('period2Date')); + } + if (this.hasPeriod(3)) { + _fetch('issues3', this.get('period3Date')); + } + }, + + parseDebt: function (msr) { + var debtMeasure = _.findWhere(msr, { key: DEBT_METRIC }); + if (debtMeasure != null) { + this.set({ + debt: debtMeasure.val, + debt1: debtMeasure.var1, + debt2: debtMeasure.var2, + debt3: debtMeasure.var3 }); - }); + } }, - fetchIssues2: function () { - if (!this.get('period2Date')) { - return; + parseCoverage: function (msr) { + var coverageMeasure = _.findWhere(msr, { key: COVERAGE_METRIC }), + newCoverageMeasure = _.findWhere(msr, { key: NEW_COVERAGE_METRIC }); + if (coverageMeasure != null) { + this.set({ + coverage: coverageMeasure.val, + coverage1: coverageMeasure.var1, + coverage2: coverageMeasure.var2, + coverage3: coverageMeasure.var3 + }); } - var that = this, - url = baseUrl + '/api/issues/search', - options = { - ps: 1, - resolved: 'false', - createdAfter: this.get('period2Date'), - componentUuids: this.get('componentUuid'), - facets: 'severities,statuses' - }; - return $.get(url, options).done(function (r) { - var severityFacet = _.findWhere(r.facets, { property: 'severities' }), - statusFacet = _.findWhere(r.facets, { property: 'statuses' }); - that.set({ - issues2: r.total, - blockerIssues2: _.findWhere(severityFacet.values, { val: 'BLOCKER' }).count, - criticalIssues2: _.findWhere(severityFacet.values, { val: 'CRITICAL' }).count, - majorIssues2: _.findWhere(severityFacet.values, { val: 'MAJOR' }).count, - openIssues2: _.findWhere(statusFacet.values, { val: 'OPEN' }).count + - _.findWhere(statusFacet.values, { val: 'REOPENED' }).count + if (newCoverageMeasure != null) { + this.set({ + newCoverage1: newCoverageMeasure.var1, + newCoverage2: newCoverageMeasure.var2, + newCoverage3: newCoverageMeasure.var3 }); - }); + } }, - fetchIssues3: function () { - if (!this.get('period3Date')) { - return; - } - var that = this, - url = baseUrl + '/api/issues/search', - options = { - ps: 1, - resolved: 'false', - createdAfter: this.get('period3Date'), - componentUuids: this.get('componentUuid'), - facets: 'severities,statuses' - }; - return $.get(url, options).done(function (r) { - var severityFacet = _.findWhere(r.facets, { property: 'severities' }), - statusFacet = _.findWhere(r.facets, { property: 'statuses' }); - that.set({ - issues3: r.total, - blockerIssues3: _.findWhere(severityFacet.values, { val: 'BLOCKER' }).count, - criticalIssues3: _.findWhere(severityFacet.values, { val: 'CRITICAL' }).count, - majorIssues3: _.findWhere(severityFacet.values, { val: 'MAJOR' }).count, - openIssues3: _.findWhere(statusFacet.values, { val: 'OPEN' }).count + - _.findWhere(statusFacet.values, { val: 'REOPENED' }).count + parseDuplications: function (msr) { + var duplicationsMeasure = _.findWhere(msr, { key: DUPLICATIONS_METRIC }); + if (duplicationsMeasure != null) { + this.set({ + duplications: duplicationsMeasure.val, + duplications1: duplicationsMeasure.var1, + duplications2: duplicationsMeasure.var2, + duplications3: duplicationsMeasure.var3 }); - }); + } }, - fetchIssuesTrend: function () { + fetchTrends: function () { var that = this, url = baseUrl + '/api/timemachine/index', options = { resource: this.get('componentKey'), - metrics: 'violations' + metrics: [ + SIZE_METRIC, + ISSUES_METRIC, + DEBT_METRIC, + COVERAGE_METRIC, + DUPLICATIONS_METRIC + ].join(',') }; return $.get(url, options).done(function (r) { - var trend = r[0].cells.map(function (cell) { - return { val: cell.d, count: cell.v[0] }; - }); - that.set({ issuesTrend: trend }); + if (_.isArray(r)) { + that.parseSizeTrend(r[0]); + that.parseIssuesTrend(r[0]); + that.parseDebtTrend(r[0]); + that.parseCoverageTrend(r[0]); + that.parseDuplicationsTrend(r[0]); + } }); }, - fetchDebt: function () { + parseTrend: function (r, property, metric) { var that = this, - url = baseUrl + '/api/resources/index', - options = { - resource: this.get('componentKey'), - metrics: 'sqale_index', - includetrends: true - }; - return $.get(url, options).done(function (r) { - var msr = r[0].msr, - debtMeasure = _.findWhere(msr, { key: 'sqale_index' }); - that.set({ - debt: debtMeasure && debtMeasure.val, - debt1: debtMeasure && debtMeasure.var1, - debt2: debtMeasure && debtMeasure.var2, - debt3: debtMeasure && debtMeasure.var3 - }); - }); + index = _.pluck(r.cols, 'metric').indexOf(metric); + if (index !== -1) { + var trend = r.cells.map(function (cell) { + return { val: cell.d, count: cell.v[index] }; + }), + filteredTrend = trend.filter(function (t) { + return t.val != null && t.count != null; + }); + that.set(property, filteredTrend); + } }, - fetchDebtTrend: function () { - var that = this, - url = baseUrl + '/api/timemachine/index', - options = { - resource: this.get('componentKey'), - metrics: 'sqale_index' - }; - return $.get(url, options).done(function (r) { - var trend = r[0].cells.map(function (cell) { - return { val: cell.d, count: cell.v[0] }; - }); - that.set({ debtTrend: trend }); - }); + parseSizeTrend: function (r) { + this.parseTrend(r, 'sizeTrend', SIZE_METRIC); }, - fetchCoverage: function () { - var that = this, - url = baseUrl + '/api/resources/index', - options = { - resource: this.get('componentKey'), - metrics: 'overall_coverage,new_overall_coverage', - includetrends: true - }; - return $.get(url, options).done(function (r) { - var msr = r[0].msr, - coverageMeasure = _.findWhere(msr, { key: 'overall_coverage' }), - newCoverageMeasure = _.findWhere(msr, { key: 'new_overall_coverage' }); - that.set({ - coverage: coverageMeasure && coverageMeasure.val, - coverage1: coverageMeasure && coverageMeasure.var1, - coverage2: coverageMeasure && coverageMeasure.var2, - coverage3: coverageMeasure && coverageMeasure.var3, - newCoverage1: newCoverageMeasure && newCoverageMeasure.var1, - newCoverage2: newCoverageMeasure && newCoverageMeasure.var2, - newCoverage3: newCoverageMeasure && newCoverageMeasure.var3 - }); - }); + parseIssuesTrend: function (r) { + this.parseTrend(r, 'issuesTrend', ISSUES_METRIC); }, - fetchCoverageTrend: function () { - var that = this, - url = baseUrl + '/api/timemachine/index', - options = { - resource: this.get('componentKey'), - metrics: 'coverage' - }; - return $.get(url, options).done(function (r) { - var trend = r[0].cells.map(function (cell) { - return { val: cell.d, count: cell.v[0] }; - }); - that.set({ coverageTrend: trend }); - }); + parseDebtTrend: function (r) { + this.parseTrend(r, 'debtTrend', DEBT_METRIC); }, - fetchDuplications: function () { - var that = this, - url = baseUrl + '/api/resources/index', - options = { - resource: this.get('componentKey'), - metrics: 'duplicated_lines_density', - includetrends: true - }; - return $.get(url, options).done(function (r) { - var msr = r[0].msr, - duplicationsMeasure = _.findWhere(msr, { key: 'duplicated_lines_density' }); - that.set({ - duplications: duplicationsMeasure && duplicationsMeasure.val, - duplications1: duplicationsMeasure && duplicationsMeasure.var1, - duplications2: duplicationsMeasure && duplicationsMeasure.var2, - duplications3: duplicationsMeasure && duplicationsMeasure.var3 - }); - }); + parseCoverageTrend: function (r) { + this.parseTrend(r, 'coverageTrend', COVERAGE_METRIC); }, - fetchDuplicationsTrend: function () { - var that = this, - url = baseUrl + '/api/timemachine/index', - options = { - resource: this.get('componentKey'), - metrics: 'duplicated_lines_density' - }; - return $.get(url, options).done(function (r) { - var trend = r[0].cells.map(function (cell) { - return { val: cell.d, count: cell.v[0] }; - }); - that.set({ duplicationsTrend: trend }); - }); + parseDuplicationsTrend: function (r) { + this.parseTrend(r, 'duplicationsTrend', DUPLICATIONS_METRIC); } }); |