diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2015-06-29 13:21:37 +0200 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2015-06-29 14:49:35 +0200 |
commit | 390aa827d11c7a50c6916c3e80919873fc2266c2 (patch) | |
tree | d5627e685144c1189136bf8290532733a03a8617 | |
parent | da0c64602b7f8e8b09a7b11a6b9687e7fbfefb69 (diff) | |
download | sonarqube-390aa827d11c7a50c6916c3e80919873fc2266c2.tar.gz sonarqube-390aa827d11c7a50c6916c3e80919873fc2266c2.zip |
SONAR-6668 update issue filters widgets to display the technical debt
18 files changed, 305 insertions, 71 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/dashboard/widget/IssueFilterWidget.java b/server/sonar-server/src/main/java/org/sonar/server/dashboard/widget/IssueFilterWidget.java index d3bc92a44a5..f8042223c79 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/dashboard/widget/IssueFilterWidget.java +++ b/server/sonar-server/src/main/java/org/sonar/server/dashboard/widget/IssueFilterWidget.java @@ -34,13 +34,15 @@ import static org.sonar.api.web.WidgetScope.GLOBAL; @WidgetProperty(key = IssueFilterWidget.DISTRIBUTION_AXIS_PROPERTY, type = WidgetPropertyType.SINGLE_SELECT_LIST, defaultValue = "severities", options = {"severities", "resolutions", "statuses", "rules", "tags", "projectUuids", "assignees", "reporters", "authors", "languages", "actionPlans", "createdAt"}), - @WidgetProperty(key = IssueFilterWidget.DISPLAY_FILTER_DESCRIPTION, type = WidgetPropertyType.BOOLEAN, defaultValue = "false") + @WidgetProperty(key = IssueFilterWidget.DISPLAY_FILTER_DESCRIPTION, type = WidgetPropertyType.BOOLEAN, defaultValue = "false"), + @WidgetProperty(key = IssueFilterWidget.DISPLAY_MODE, type = WidgetPropertyType.SINGLE_SELECT_LIST, defaultValue = "count", options = {"count", "debt"}) }) public class IssueFilterWidget extends CoreWidget { public static final String FILTER_PROPERTY = "filter"; public static final String DISTRIBUTION_AXIS_PROPERTY = "distributionAxis"; public static final String DISPLAY_FILTER_DESCRIPTION = "displayFilterDescription"; + public static final String DISPLAY_MODE = "displayMode"; public static final String ID = "issue_filter"; public IssueFilterWidget() { diff --git a/server/sonar-server/src/main/java/org/sonar/server/dashboard/widget/ProjectIssueFilterWidget.java b/server/sonar-server/src/main/java/org/sonar/server/dashboard/widget/ProjectIssueFilterWidget.java index 3f4f1ff9275..6ac66e77d0a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/dashboard/widget/ProjectIssueFilterWidget.java +++ b/server/sonar-server/src/main/java/org/sonar/server/dashboard/widget/ProjectIssueFilterWidget.java @@ -34,13 +34,15 @@ import static org.sonar.api.web.WidgetScope.PROJECT; @WidgetProperty(key = ProjectIssueFilterWidget.DISTRIBUTION_AXIS_PROPERTY, type = WidgetPropertyType.SINGLE_SELECT_LIST, defaultValue = "severities", options = {"severities", "resolutions", "statuses", "rules", "tags", "assignees", "reporters", "authors", "languages", "actionPlans", "createdAt"}), - @WidgetProperty(key = ProjectIssueFilterWidget.DISPLAY_FILTER_DESCRIPTION, type = WidgetPropertyType.BOOLEAN, defaultValue = "false") + @WidgetProperty(key = ProjectIssueFilterWidget.DISPLAY_FILTER_DESCRIPTION, type = WidgetPropertyType.BOOLEAN, defaultValue = "false"), + @WidgetProperty(key = ProjectIssueFilterWidget.DISPLAY_MODE, type = WidgetPropertyType.SINGLE_SELECT_LIST, defaultValue = "count", options = {"count", "debt"}) }) public class ProjectIssueFilterWidget extends CoreWidget { public static final String FILTER_PROPERTY = "filter"; public static final String DISTRIBUTION_AXIS_PROPERTY = "distributionAxis"; public static final String DISPLAY_FILTER_DESCRIPTION = "displayFilterDescription"; + public static final String DISPLAY_MODE = "displayMode"; public static final String ID = "project_issue_filter"; public ProjectIssueFilterWidget() { diff --git a/server/sonar-server/src/main/resources/org/sonar/server/dashboard/widget/issue_filter.html.erb b/server/sonar-server/src/main/resources/org/sonar/server/dashboard/widget/issue_filter.html.erb index f70e79ec85b..5523fbfd11e 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/dashboard/widget/issue_filter.html.erb +++ b/server/sonar-server/src/main/resources/org/sonar/server/dashboard/widget/issue_filter.html.erb @@ -3,6 +3,7 @@ filter_id = widget_properties['filter'] filter = Internal.issues.findIssueFilterById(filter_id.to_i) distribution_axis = widget_properties['distributionAxis'] + display_mode = widget_properties['displayMode'] is_enough_permissions = filter.shared || (current_user && filter.userLogin == current_user.login) %> @@ -32,7 +33,8 @@ new IssueFilter({ el: '#<%= container_id -%>', query: query, - distributionAxis: '<%= distribution_axis -%>' + distributionAxis: '<%= distribution_axis -%>', + displayMode: '<%= display_mode -%>' }); }); }); diff --git a/server/sonar-server/src/main/resources/org/sonar/server/dashboard/widget/project_issue_filter.html.erb b/server/sonar-server/src/main/resources/org/sonar/server/dashboard/widget/project_issue_filter.html.erb index 16edb8192d1..0815b95e88e 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/dashboard/widget/project_issue_filter.html.erb +++ b/server/sonar-server/src/main/resources/org/sonar/server/dashboard/widget/project_issue_filter.html.erb @@ -3,6 +3,7 @@ filter_id = widget_properties['filter'] filter = Internal.issues.findIssueFilterById(filter_id.to_i) distribution_axis = widget_properties['distributionAxis'] + display_mode = widget_properties['displayMode'] is_enough_permissions = filter.shared || (current_user && filter.userLogin == current_user.login) if @dashboard_configuration.selected_period? @@ -39,6 +40,7 @@ el: '#<%= container_id -%>', query: query, distributionAxis: '<%= distribution_axis -%>', + displayMode: '<%= display_mode -%>', <% if period_date %> periodDate: '<%= period_date -%>', <% end %> 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 index 03fb4134f4a..376ea5611de 100644 --- 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 @@ -1,8 +1,10 @@ <tr> <td> - <a href="{{issueFilterTotalLink parsedQuery}}"><strong>{{t 'total'}}</strong></a> + <a href="{{issueFilterTotalLink parsedQuery displayMode}}"><strong>{{t 'total'}}</strong></a> + </td> + <td class="text-right nowrap"> + <strong>{{#notNull periodDate}}+{{/notNull}}{{issueFilterValue total displayMode}}</strong> </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> 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 index 07c9b17f40c..b5c93283194 100644 --- 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 @@ -4,13 +4,13 @@ <tr> <td> {{#eq val ''}} - <a href="{{issueFilterItemLink ../../parsedQuery 'planned' 'false'}}">{{t 'issue.unplanned'}}</a> + <a href="{{issueFilterItemLink ../../parsedQuery 'planned' 'false' ../../displayMode}}">{{t 'issue.unplanned'}}</a> {{else}} - <a href="{{issueFilterItemLink ../../parsedQuery 'actionPlans' val}}">{{default label val}}</a> + <a href="{{issueFilterItemLink ../../parsedQuery 'actionPlans' val ../../displayMode}}">{{default label val}}</a> {{/eq}} </td> <td class="text-right nowrap"> - {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + {{#notNull ../periodDate}}+{{/notNull}}{{issueFilterValue count ../displayMode}} </td> <td class="barchart"> <div class="barchart" style="width: 100%;"> 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 index 494104f3ee9..aef7f8fc9f6 100644 --- 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 @@ -4,13 +4,13 @@ <tr> <td> {{#eq val ''}} - <a href="{{issueFilterItemLink ../../parsedQuery 'assigned' 'false'}}">{{t 'unassigned'}}</a> + <a href="{{issueFilterItemLink ../../parsedQuery 'assigned' 'false' ../../displayMode}}">{{t 'unassigned'}}</a> {{else}} - <a href="{{issueFilterItemLink ../../parsedQuery 'assignees' val}}">{{default label val}}</a> + <a href="{{issueFilterItemLink ../../parsedQuery 'assignees' val ../../displayMode}}">{{default label val}}</a> {{/eq}} </td> <td class="text-right nowrap"> - {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + {{#notNull ../periodDate}}+{{/notNull}}{{issueFilterValue count ../displayMode}} </td> <td class="barchart"> <div class="barchart" style="width: 100%;"> 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 index 50827ba41bb..5d8d6c2554d 100644 --- 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 @@ -4,13 +4,13 @@ <tr> <td> {{#eq val ''}} - <a href="{{issueFilterItemLink ../../parsedQuery 'resolved' 'false'}}">{{t 'unresolved'}}</a> + <a href="{{issueFilterItemLink ../../parsedQuery 'resolved' 'false' ../../displayMode}}">{{t 'unresolved'}}</a> {{else}} - <a href="{{issueFilterItemLink ../../parsedQuery 'resolutions' val}}">{{t 'issue.resolution' val}}</a> + <a href="{{issueFilterItemLink ../../parsedQuery 'resolutions' val ../../displayMode}}">{{t 'issue.resolution' val}}</a> {{/eq}} </td> <td class="text-right nowrap"> - {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + {{#notNull ../periodDate}}+{{/notNull}}{{issueFilterValue count ../displayMode}} </td> <td class="barchart"> <div class="barchart" style="width: 100%;"> 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 index 3ca50c03da5..a292b57e2b9 100644 --- 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 @@ -1,18 +1,18 @@ <table class="data zebra"> <tr> <td> - <a href="{{issueFilterTotalLink parsedQuery}}"><strong>{{t 'total'}}</strong></a> + <a href="{{issueFilterTotalLink parsedQuery displayMode}}"><strong>{{t 'total'}}</strong></a> </td> - <td class="text-right"><strong>{{#notNull periodDate}}+{{/notNull}}{{numberShort total}}</strong></td> + <td class="text-right"><strong>{{#notNull periodDate}}+{{/notNull}}{{issueFilterValue total displayMode}}</strong></td> </tr> {{#each items}} <tr> <td> {{severityIcon val}} - <a href="{{issueFilterItemLink ../parsedQuery ../property val}}">{{t 'severity' val}}</a> + <a href="{{issueFilterItemLink ../parsedQuery ../property val ../displayMode}}">{{t 'severity' val}}</a> </td> <td class="text-right nowrap"> - {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + {{#notNull ../periodDate}}+{{/notNull}}{{issueFilterValue count ../displayMode}} </td> </tr> {{/each}} 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 index 70d5a57c765..a661cd7ff3d 100644 --- 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 @@ -4,10 +4,10 @@ <tr> <td> {{statusIcon val}} - <a href="{{issueFilterItemLink ../parsedQuery ../property val}}">{{t 'issue.status' val}}</a> + <a href="{{issueFilterItemLink ../parsedQuery ../property val ../displayMode}}">{{t 'issue.status' val}}</a> </td> <td class="text-right nowrap"> - {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + {{#notNull ../periodDate}}+{{/notNull}}{{issueFilterValue count ../displayMode}} </td> <td class="barchart"> <div class="barchart" style="width: 100%;"> 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 index dc78bba0232..b92cf91f995 100644 --- 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 @@ -6,7 +6,7 @@ <a href="{{searchLink}}">{{default label val}}</a> </td> <td class="text-right nowrap"> - {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}} + {{#notNull ../periodDate}}+{{/notNull}}{{issueFilterValue count ../displayMode}} </td> <td class="barchart"> <div class="barchart" style="width: 100%;"> diff --git a/server/sonar-web/src/main/js/widgets/issue-filter/widget.js b/server/sonar-web/src/main/js/widgets/issue-filter/widget.js index 2fb96c7d2e7..97c72ca75a1 100644 --- a/server/sonar-web/src/main/js/widgets/issue-filter/widget.js +++ b/server/sonar-web/src/main/js/widgets/issue-filter/widget.js @@ -32,10 +32,13 @@ define(['./templates'], function () { defaultLabel = function (item) { return item.val; }, - defaultLink = function (item, property, query) { + defaultLink = function (item, property, query, index, items, mode) { var criterion = {}; criterion[property] = item.val; var r = _.extend({}, query, criterion); + if (mode === 'debt') { + r.facetMode = 'debt'; + } if (r.componentKey != null) { return baseUrl + '/component_issues/index?id=' + encodeURIComponent(r.componentKey) + '#' + getQuery(_.omit(r, 'componentKey')); @@ -164,7 +167,7 @@ define(['./templates'], function () { isSameDay = ending.diff(beginning, 'days') <= 1; return beginning.format('LL') + (isSameDay ? '' : (' – ' + ending.format('LL'))); }, - link: function (item, property, query, index, items) { + link: function (item, property, query, index, items, mode) { var createdAfter = moment(item.val), endDate = query.createdBefore != null ? moment(query.createdBefore) : moment(), createdBefore = index < items.length - 1 ? moment(items[index + 1].val).subtract(1, 'days') : endDate, @@ -176,6 +179,9 @@ define(['./templates'], function () { createdAfter: createdAfter.format('YYYY-MM-DD'), createdBefore: createdBefore.format('YYYY-MM-DD') }); + if (mode === 'debt') { + r.facetMode = 'debt'; + } if (r.componentKey != null) { return baseUrl + '/component_issues/index?id=' + encodeURIComponent(r.componentKey) + '#' + getQuery(_.omit(r, 'componentKey')); @@ -195,10 +201,13 @@ define(['./templates'], function () { return route.join(separator); } - Handlebars.registerHelper('issueFilterItemLink', function (query, property, value) { + Handlebars.registerHelper('issueFilterItemLink', function (query, property, value, mode) { var criterion = {}; criterion[property] = value; var r = _.extend({}, query, criterion); + if (mode === 'debt') { + r.facetMode = 'debt'; + } if (r.componentKey != null) { return baseUrl + '/component_issues/index?id=' + encodeURIComponent(r.componentKey) + '#' + getQuery(_.omit(r, 'componentKey')); @@ -207,8 +216,11 @@ define(['./templates'], function () { } }); - Handlebars.registerHelper('issueFilterTotalLink', function (query) { + Handlebars.registerHelper('issueFilterTotalLink', function (query, mode) { var r = _.extend({}, query); + if (mode === 'debt') { + r.facetMode = 'debt'; + } if (r.componentKey != null) { return baseUrl + '/component_issues/index?id=' + encodeURIComponent(r.componentKey) + '#' + getQuery(_.omit(r, 'componentKey')); @@ -217,6 +229,11 @@ define(['./templates'], function () { } }); + Handlebars.registerHelper('issueFilterValue', function (value, mode) { + var formatter = mode === 'debt' ? 'SHORT_WORK_DUR' : 'SHORT_INT'; + return window.formatMeasure(value, formatter); + }); + return Marionette.ItemView.extend({ getTemplate: function () { @@ -284,9 +301,10 @@ define(['./templates'], function () { withLink: function (items) { var link = this.conf != null && this.conf.link != null ? this.conf.link : defaultLink, property = this.options.distributionAxis, + mode = this.options.displayMode, query = this.model.get('parsedQuery'); return items.map(function (item, index) { - return _.extend(item, { searchLink: link(item, property, query, index, items) }); + return _.extend(item, { searchLink: link(item, property, query, index, items, mode) }); }); }, @@ -301,10 +319,12 @@ define(['./templates'], function () { requestIssues: function () { var that = this, + facetMode = this.options.displayMode, url = baseUrl + '/api/issues/search', options = _.extend({}, this.query, { ps: 1, - facets: this.options.distributionAxis + facets: this.options.distributionAxis, + facetMode: facetMode }); if (this.options.componentUuid != null) { _.extend(options, { componentUuids: this.options.componentUuid }); @@ -321,10 +341,14 @@ define(['./templates'], function () { items: items, maxResultsReached: items.length >= FACET_LIMIT, maxResults: items.length, - total: r.total + total: facetMode === 'debt' ? r.debtTotal : r.total }); } }); + }, + + serializeData: function () { + return _.extend(this._super(), { displayMode: this.options.displayMode }); } }); diff --git a/server/sonar-web/src/test/js/global-issue-filter-widget.js b/server/sonar-web/src/test/js/global-issue-filter-widget.js index 5cf3863ccdb..eedd5f275fc 100644 --- a/server/sonar-web/src/test/js/global-issue-filter-widget.js +++ b/server/sonar-web/src/test/js/global-issue-filter-widget.js @@ -61,12 +61,12 @@ casper.test.begin(testName('Unresolved Issues By Severity'), 13, function (test) test.assertElementCount('tr', 6); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); test.assertSelectorContains('tr:nth-child(2)', '1'); test.assertSelectorContains('tr:nth-child(3)', '105'); - test.assertSelectorContains('tr:nth-child(4)', '5,027'); + test.assertSelectorContains('tr:nth-child(4)', '5k'); test.assertSelectorContains('tr:nth-child(5)', '540'); - test.assertSelectorContains('tr:nth-child(6)', '1,178'); + test.assertSelectorContains('tr:nth-child(6)', '1.2k'); // check links test.assertExists('tr:nth-child(1) a[href="/issues/search#resolved=false"]'); @@ -120,10 +120,10 @@ casper.test.begin(testName('Red Issues By Severity'), 9, function (test) { test.assertElementCount('tr', 4); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); test.assertSelectorContains('tr:nth-child(2)', '1'); test.assertSelectorContains('tr:nth-child(3)', '105'); - test.assertSelectorContains('tr:nth-child(4)', '5,027'); + test.assertSelectorContains('tr:nth-child(4)', '5k'); // check links test.assertExists('tr:nth-child(1) a[href="/issues/search#resolved=false|severities=BLOCKER%2CCRITICAL%2CMAJOR"]'); @@ -174,12 +174,12 @@ casper.test.begin(testName('All Issues By Status'), 9, function (test) { test.assertElementCount('tr', 6); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '71.6k'); + test.assertSelectorContains('tr:nth-child(1)', '72k'); test.assertSelectorContains('tr:nth-child(2)', '238'); test.assertSelectorContains('tr:nth-child(3)', '4'); - test.assertSelectorContains('tr:nth-child(4)', '6,609'); - test.assertSelectorContains('tr:nth-child(5)', '1,307'); - test.assertSelectorContains('tr:nth-child(6)', '63.4k'); + test.assertSelectorContains('tr:nth-child(4)', '6.6k'); + test.assertSelectorContains('tr:nth-child(5)', '1.3k'); + test.assertSelectorContains('tr:nth-child(6)', '63k'); // check links test.assertExists('tr:nth-child(1) a[href="/issues/search#"]'); @@ -229,10 +229,10 @@ casper.test.begin(testName('Unresolved Issues By Status'), 9, function (test) { test.assertElementCount('tr', 4); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '71.6k'); + test.assertSelectorContains('tr:nth-child(1)', '72k'); test.assertSelectorContains('tr:nth-child(2)', '238'); test.assertSelectorContains('tr:nth-child(3)', '4'); - test.assertSelectorContains('tr:nth-child(4)', '6,609'); + test.assertSelectorContains('tr:nth-child(4)', '6.6k'); // check links test.assertExists('tr:nth-child(1) a[href="/issues/search#resolved=false"]'); @@ -283,12 +283,12 @@ casper.test.begin(testName('All Issues By Resolution'), 10, function (test) { test.assertElementCount('tr', 6); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '71.6k'); - test.assertSelectorContains('tr:nth-child(2)', '6,851'); + test.assertSelectorContains('tr:nth-child(1)', '72k'); + test.assertSelectorContains('tr:nth-child(2)', '6.9k'); test.assertSelectorContains('tr:nth-child(3)', '752'); test.assertSelectorContains('tr:nth-child(4)', '550'); - test.assertSelectorContains('tr:nth-child(5)', '47.1k'); - test.assertSelectorContains('tr:nth-child(6)', '16.3k'); + test.assertSelectorContains('tr:nth-child(5)', '47k'); + test.assertSelectorContains('tr:nth-child(6)', '16k'); // check links test.assertExists('tr:nth-child(1) a[href="/issues/search#"]'); @@ -339,8 +339,8 @@ casper.test.begin(testName('Unresolved Issues By Resolution'), 5, function (test test.assertElementCount('tr', 2); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); - test.assertSelectorContains('tr:nth-child(2)', '6,851'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); + test.assertSelectorContains('tr:nth-child(2)', '6.9k'); // check links test.assertExists('tr:nth-child(1) a[href="/issues/search#resolved=false"]'); @@ -390,7 +390,7 @@ casper.test.begin(testName('Unresolved Issues By Rule'), 15, function (test) { test.assertElementCount('tr', 16); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); test.assertSelectorContains('tr:nth-child(2)', '879'); test.assertSelectorContains('tr:nth-child(3)', '571'); test.assertSelectorContains('tr:nth-child(15)', '113'); @@ -453,8 +453,8 @@ casper.test.begin(testName('Unresolved Issues By Project'), 15, function (test) test.assertElementCount('tr', 5); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '2,598'); - test.assertSelectorContains('tr:nth-child(2)', '1,766'); + test.assertSelectorContains('tr:nth-child(1)', '2.6k'); + test.assertSelectorContains('tr:nth-child(2)', '1.8k'); test.assertSelectorContains('tr:nth-child(3)', '442'); test.assertSelectorContains('tr:nth-child(4)', '283'); test.assertSelectorContains('tr:nth-child(5)', '107'); @@ -516,8 +516,8 @@ casper.test.begin(testName('Unresolved Issues By Assignee'), 15, function (test) test.assertElementCount('tr', 5); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); - test.assertSelectorContains('tr:nth-child(2)', '4,134'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); + test.assertSelectorContains('tr:nth-child(2)', '4.1k'); test.assertSelectorContains('tr:nth-child(3)', '698'); test.assertSelectorContains('tr:nth-child(4)', '504'); test.assertSelectorContains('tr:nth-child(5)', '426'); @@ -579,8 +579,8 @@ casper.test.begin(testName('Unresolved Unassigned Issues By Assignee'), 6, funct test.assertElementCount('tr', 2); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '4,134'); - test.assertSelectorContains('tr:nth-child(2)', '4,134'); + test.assertSelectorContains('tr:nth-child(1)', '4.1k'); + test.assertSelectorContains('tr:nth-child(2)', '4.1k'); // check links test.assertExists('tr:nth-child(1) a[href="/issues/search#resolved=false|assigned=false"]'); @@ -633,7 +633,7 @@ casper.test.begin(testName('Unresolved Issues By Reporter'), 12, function (test) test.assertElementCount('tr', 4); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); test.assertSelectorContains('tr:nth-child(2)', '698'); test.assertSelectorContains('tr:nth-child(3)', '504'); test.assertSelectorContains('tr:nth-child(4)', '426'); @@ -693,8 +693,8 @@ casper.test.begin(testName('Unresolved Issues By Language'), 15, function (test) test.assertElementCount('tr', 5); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); - test.assertSelectorContains('tr:nth-child(2)', '6,336'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); + test.assertSelectorContains('tr:nth-child(2)', '6.3k'); test.assertSelectorContains('tr:nth-child(3)', '444'); test.assertSelectorContains('tr:nth-child(4)', '22'); test.assertSelectorContains('tr:nth-child(5)', '15'); @@ -756,8 +756,8 @@ casper.test.begin(testName('Unresolved Issues By Action Plan'), 15, function (te test.assertElementCount('tr', 5); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); - test.assertSelectorContains('tr:nth-child(2)', '5,877'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); + test.assertSelectorContains('tr:nth-child(2)', '5.9k'); test.assertSelectorContains('tr:nth-child(3)', '532'); test.assertSelectorContains('tr:nth-child(4)', '56'); test.assertSelectorContains('tr:nth-child(5)', '52'); @@ -819,8 +819,8 @@ casper.test.begin(testName('Unresolved Unplanned Issues By Action Plan'), 6, fun test.assertElementCount('tr', 2); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '5,877'); - test.assertSelectorContains('tr:nth-child(2)', '5,877'); + test.assertSelectorContains('tr:nth-child(1)', '5.9k'); + test.assertSelectorContains('tr:nth-child(2)', '5.9k'); // check links test.assertExists('tr:nth-child(1) a[href="/issues/search#resolved=false|planned=false"]'); @@ -873,10 +873,10 @@ casper.test.begin(testName('Unresolved Issues By Date'), 18, function (test) { test.assertElementCount('tr', 6); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); - test.assertSelectorContains('tr:nth-child(2)', '1,724'); - test.assertSelectorContains('tr:nth-child(3)', '3,729'); - test.assertSelectorContains('tr:nth-child(4)', '1,262'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); + test.assertSelectorContains('tr:nth-child(2)', '1.7k'); + test.assertSelectorContains('tr:nth-child(3)', '3.7k'); + test.assertSelectorContains('tr:nth-child(4)', '1.3k'); test.assertSelectorContains('tr:nth-child(5)', '64'); test.assertSelectorContains('tr:nth-child(6)', '72'); @@ -941,7 +941,7 @@ casper.test.begin(testName('Unresolved Issues on a Limited Period By Date'), 12, test.assertElementCount('tr', 4); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); test.assertSelectorContains('tr:nth-child(2)', '47'); test.assertSelectorContains('tr:nth-child(3)', '48'); test.assertSelectorContains('tr:nth-child(4)', '49'); @@ -966,3 +966,125 @@ casper.test.begin(testName('Unresolved Issues on a Limited Period By Date'), 12, test.done(); }); }); + + +casper.test.begin(testName('Unresolved Issues By Severity Displaying Debt'), 13, function (test) { + casper + .start(lib.buildUrl('base'), function () { + lib.setDefaultViewport(); + + lib.mockRequestFromFile('/api/l10n/index', 'messages.json'); + lib.mockRequestFromFile('/api/issues/search', 'unresolved-issues-by-severity-debt.json', + { data: { resolved: 'false' } }); + }) + + .then(function () { + casper.evaluate(function () { + require(['widgets/issue-filter/widget'], function (IssueFilter) { + window.requestMessages().done(function () { + new IssueFilter({ + el: '#content', + query: 'resolved=false', + distributionAxis: 'severities', + displayMode: 'debt' + }); + }); + }); + }); + }) + + .then(function () { + casper.waitForSelector('#content > table'); + }) + + .then(function () { + // check count + test.assertElementCount('tr', 6); + + // check order and values + test.assertSelectorContains('tr:nth-child(1)', '~ 14d'); + test.assertSelectorContains('tr:nth-child(2)', '1min'); + test.assertSelectorContains('tr:nth-child(3)', '~ 1h'); + test.assertSelectorContains('tr:nth-child(4)', '~ 10d'); + test.assertSelectorContains('tr:nth-child(5)', '~ 1d'); + test.assertSelectorContains('tr:nth-child(6)', '~ 2d'); + + // check links + test.assertExists('tr:nth-child(1) a[href="/issues/search#resolved=false|facetMode=debt"]'); + test.assertExists('tr:nth-child(2) a[href="/issues/search#resolved=false|severities=BLOCKER|facetMode=debt"]'); + test.assertExists('tr:nth-child(3) a[href="/issues/search#resolved=false|severities=CRITICAL|facetMode=debt"]'); + test.assertExists('tr:nth-child(4) a[href="/issues/search#resolved=false|severities=MAJOR|facetMode=debt"]'); + test.assertExists('tr:nth-child(5) a[href="/issues/search#resolved=false|severities=MINOR|facetMode=debt"]'); + test.assertExists('tr:nth-child(6) a[href="/issues/search#resolved=false|severities=INFO|facetMode=debt"]'); + }) + + .then(function () { + lib.sendCoverage(); + }) + + .run(function () { + test.done(); + }); +}); + + +casper.test.begin(testName('Unresolved Issues By Date Displaying Debt'), 13, function (test) { + casper + .start(lib.buildUrl('base'), function () { + lib.setDefaultViewport(); + + lib.mockRequestFromFile('/api/l10n/index', 'messages.json'); + lib.mockRequestFromFile('/api/issues/search', 'unresolved-issues-by-date-debt.json', + { data: { resolved: 'false' } }); + }) + + .then(function () { + casper.evaluate(function () { + require(['widgets/issue-filter/widget'], function (IssueFilter) { + window.requestMessages().done(function () { + new IssueFilter({ + el: '#content', + query: 'resolved=false', + distributionAxis: 'createdAt', + displayMode: 'debt' + }); + }); + }); + }); + }) + + .then(function () { + casper.waitForSelector('#content > table'); + }) + + .then(function () { + // check count + test.assertElementCount('tr', 6); + + // check order and values + lib.capture(); + test.assertSelectorContains('tr:nth-child(1)', '~ 14d'); + test.assertSelectorContains('tr:nth-child(2)', '1min'); + test.assertSelectorContains('tr:nth-child(3)', '~ 1h'); + test.assertSelectorContains('tr:nth-child(4)', '~ 1d'); + test.assertSelectorContains('tr:nth-child(5)', '~ 2d'); + test.assertSelectorContains('tr:nth-child(6)', '~ 10d'); + + // check links + test.assertExists('tr:nth-child(1) a[href="/issues/search#resolved=false|facetMode=debt"]'); + // do not check createdBefore value, because it is set dynamically to *now* + test.assertExists('tr:nth-child(2) a[href^="/issues/search#resolved=false|createdAfter=2015-01-01|createdBefore="]'); + test.assertExists('tr:nth-child(3) a[href="/issues/search#resolved=false|createdAfter=2014-01-01|createdBefore=2014-12-31|facetMode=debt"]'); + test.assertExists('tr:nth-child(4) a[href="/issues/search#resolved=false|createdAfter=2013-01-01|createdBefore=2013-12-31|facetMode=debt"]'); + test.assertExists('tr:nth-child(5) a[href="/issues/search#resolved=false|createdAfter=2012-01-01|createdBefore=2012-12-31|facetMode=debt"]'); + test.assertExists('tr:nth-child(6) a[href="/issues/search#resolved=false|createdAfter=2011-01-01|createdBefore=2011-12-31|facetMode=debt"]'); + }) + + .then(function () { + lib.sendCoverage(); + }) + + .run(function () { + test.done(); + }); +}); diff --git a/server/sonar-web/src/test/js/project-issue-filter-widget.js b/server/sonar-web/src/test/js/project-issue-filter-widget.js index 8ec0127a1ad..2637edad29b 100644 --- a/server/sonar-web/src/test/js/project-issue-filter-widget.js +++ b/server/sonar-web/src/test/js/project-issue-filter-widget.js @@ -63,12 +63,12 @@ casper.test.begin(testName('Unresolved Issues By Severity'), 13, function (test) test.assertElementCount('tr', 6); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); test.assertSelectorContains('tr:nth-child(2)', '1'); test.assertSelectorContains('tr:nth-child(3)', '105'); - test.assertSelectorContains('tr:nth-child(4)', '5,027'); + test.assertSelectorContains('tr:nth-child(4)', '5k'); test.assertSelectorContains('tr:nth-child(5)', '540'); - test.assertSelectorContains('tr:nth-child(6)', '1,178'); + test.assertSelectorContains('tr:nth-child(6)', '1.2k'); // check links test.assertExists('tr:nth-child(1) a[href="/component_issues/index?id=org.codehaus.sonar%3Asonar#resolved=false"]'); @@ -124,10 +124,10 @@ casper.test.begin(testName('Unresolved Issues By Date'), 18, function (test) { test.assertElementCount('tr', 6); // check order and values - test.assertSelectorContains('tr:nth-child(1)', '6,851'); - test.assertSelectorContains('tr:nth-child(2)', '1,724'); - test.assertSelectorContains('tr:nth-child(3)', '3,729'); - test.assertSelectorContains('tr:nth-child(4)', '1,262'); + test.assertSelectorContains('tr:nth-child(1)', '6.9k'); + test.assertSelectorContains('tr:nth-child(2)', '1.7k'); + test.assertSelectorContains('tr:nth-child(3)', '3.7k'); + test.assertSelectorContains('tr:nth-child(4)', '1.3k'); test.assertSelectorContains('tr:nth-child(5)', '64'); test.assertSelectorContains('tr:nth-child(6)', '72'); diff --git a/server/sonar-web/src/test/json/global-issues-filter-widget/messages.json b/server/sonar-web/src/test/json/global-issues-filter-widget/messages.json new file mode 100644 index 00000000000..4b2848cc625 --- /dev/null +++ b/server/sonar-web/src/test/json/global-issues-filter-widget/messages.json @@ -0,0 +1,6 @@ +{ + "work_duration.x_days": "{0}d", + "work_duration.x_hours": "{0}h", + "work_duration.x_minutes": "{0}min", + "work_duration.about": "~ {0}" +} diff --git a/server/sonar-web/src/test/json/global-issues-filter-widget/unresolved-issues-by-date-debt.json b/server/sonar-web/src/test/json/global-issues-filter-widget/unresolved-issues-by-date-debt.json new file mode 100644 index 00000000000..c1eb80cb144 --- /dev/null +++ b/server/sonar-web/src/test/json/global-issues-filter-widget/unresolved-issues-by-date-debt.json @@ -0,0 +1,33 @@ +{ + "total": 6851, + "debtTotal": 6851, + "p": 1, + "ps": 1, + "facets": [ + { + "property": "createdAt", + "values": [ + { + "val": "2011-01-01T01:00:00+0000", + "count": 5027 + }, + { + "val": "2012-01-01T01:00:00+0000", + "count": 1178 + }, + { + "val": "2013-01-01T01:00:00+0000", + "count": 540 + }, + { + "val": "2014-01-01T01:00:00+0000", + "count": 105 + }, + { + "val": "2015-01-01T01:00:00+0000", + "count": 1 + } + ] + } + ] +} diff --git a/server/sonar-web/src/test/json/global-issues-filter-widget/unresolved-issues-by-severity-debt.json b/server/sonar-web/src/test/json/global-issues-filter-widget/unresolved-issues-by-severity-debt.json new file mode 100644 index 00000000000..15a51ee3033 --- /dev/null +++ b/server/sonar-web/src/test/json/global-issues-filter-widget/unresolved-issues-by-severity-debt.json @@ -0,0 +1,33 @@ +{ + "total": 6851, + "debtTotal": 6851, + "p": 1, + "ps": 1, + "facets": [ + { + "property": "severities", + "values": [ + { + "val": "MAJOR", + "count": 5027 + }, + { + "val": "INFO", + "count": 1178 + }, + { + "val": "MINOR", + "count": 540 + }, + { + "val": "CRITICAL", + "count": 105 + }, + { + "val": "BLOCKER", + "count": 1 + } + ] + } + ] +} diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 0e762b376cc..4a98a79471e 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1338,6 +1338,7 @@ widget.issue_filter.description=Displays the result of a pre-configured issue fi widget.issue_filter.property.filter.name=Filter widget.issue_filter.property.distributionAxis.name=Distribution Axis widget.issue_filter.property.displayFilterDescription.name=Display Filter Description +widget.issue_filter.property.displayMode.name=Display Mode widget.issue_filter.unknown_filter_warning=This widget is configured to display an issue filter that doesn't exist anymore. widget.issue_filter.insufficient_privileges_warning=Widget cannot be displayed: insufficient privileges. widget.issue_filter.property.distributionAxis.option.severities.name=By Severity @@ -1352,12 +1353,15 @@ widget.issue_filter.property.distributionAxis.option.resolutions.name=By Resolut widget.issue_filter.property.distributionAxis.option.languages.name=By Language widget.issue_filter.property.distributionAxis.option.reporters.name=By Reporter widget.issue_filter.property.distributionAxis.option.authors.name=By Author +widget.issue_filter.property.displayMode.option.count.name=Issues +widget.issue_filter.property.displayMode.option.debt.name=Technical Debt widget.project_issue_filter.name=Project Issue Filter widget.project_issue_filter.description=Displays the result of a pre-configured issue filter applied to the project. widget.project_issue_filter.property.filter.name=Filter widget.project_issue_filter.property.distributionAxis.name=Distribution Axis widget.project_issue_filter.property.displayFilterDescription.name=Display Filter Description +widget.project_issue_filter.property.displayMode.name=Display Mode widget.project_issue_filter.unknown_filter_warning=This widget is configured to display an issue filter that doesn't exist anymore. widget.project_issue_filter.insufficient_privileges_warning=Widget cannot be displayed: insufficient privileges. widget.project_issue_filter.property.distributionAxis.option.severities.name=By Severity @@ -1371,6 +1375,8 @@ widget.project_issue_filter.property.distributionAxis.option.resolutions.name=By widget.project_issue_filter.property.distributionAxis.option.languages.name=By Language widget.project_issue_filter.property.distributionAxis.option.reporters.name=By Reporter widget.project_issue_filter.property.distributionAxis.option.authors.name=By Author +widget.project_issue_filter.property.displayMode.option.count.name=Issues +widget.project_issue_filter.property.displayMode.option.debt.name=Technical Debt widget.issue_tag_cloud.name=Project Issue Tag Cloud widget.issue_tag_cloud.title=Issue Tag Cloud |