aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/Gruntfile.coffee7
-rw-r--r--server/sonar-web/src/main/hbs/widgets/_widget-issue-filter-total.hbs11
-rw-r--r--server/sonar-web/src/main/hbs/widgets/widget-issue-filter-action-plans.hbs22
-rw-r--r--server/sonar-web/src/main/hbs/widgets/widget-issue-filter-assignees.hbs22
-rw-r--r--server/sonar-web/src/main/hbs/widgets/widget-issue-filter-resolutions.hbs22
-rw-r--r--server/sonar-web/src/main/hbs/widgets/widget-issue-filter-severities.hbs19
-rw-r--r--server/sonar-web/src/main/hbs/widgets/widget-issue-filter-statuses.hbs27
-rw-r--r--server/sonar-web/src/main/hbs/widgets/widget-issue-filter.hbs18
-rw-r--r--server/sonar-web/src/main/js/widgets/issue-filter.js218
-rw-r--r--server/sonar-web/src/main/less/init/misc.less16
-rw-r--r--server/sonar-web/src/main/less/init/tables.less3
-rw-r--r--server/sonar-web/src/main/less/pages/dashboard.less16
-rw-r--r--server/sonar-web/src/main/less/style.less3
13 files changed, 386 insertions, 18 deletions
diff --git a/server/sonar-web/Gruntfile.coffee b/server/sonar-web/Gruntfile.coffee
index 29b2f98eb14..a6858a6a19d 100644
--- a/server/sonar-web/Gruntfile.coffee
+++ b/server/sonar-web/Gruntfile.coffee
@@ -243,6 +243,10 @@ module.exports = (grunt) ->
name: 'nav/app'
out: '<%= grunt.option("assetsDir") || pkg.assets %>build/js/nav/app.js'
+ issueFilterWidget: options:
+ name: 'widgets/issue-filter'
+ out: '<%= grunt.option("assetsDir") || pkg.assets %>build/js/widgets/issue-filter.js'
+
handlebars:
options:
@@ -296,6 +300,9 @@ module.exports = (grunt) ->
'<%= grunt.option("assetsDir") || pkg.assets %>js/templates/nav.js': [
'<%= pkg.sources %>hbs/nav/**/*.hbs'
]
+ '<%= grunt.option("assetsDir") || pkg.assets %>js/templates/widgets.js': [
+ '<%= pkg.sources %>hbs/widgets/**/*.hbs'
+ ]
clean:
diff --git a/server/sonar-web/src/main/hbs/widgets/_widget-issue-filter-total.hbs b/server/sonar-web/src/main/hbs/widgets/_widget-issue-filter-total.hbs
new file mode 100644
index 00000000000..407209bb5ab
--- /dev/null
+++ b/server/sonar-web/src/main/hbs/widgets/_widget-issue-filter-total.hbs
@@ -0,0 +1,11 @@
+<tr>
+ <td>
+ <a href="{{link '/issues/search#' query}}"><strong>{{t 'total'}}</strong></a>
+ </td>
+ <td class="text-right"><strong>{{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/hbs/widgets/widget-issue-filter-action-plans.hbs b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-action-plans.hbs
new file mode 100644
index 00000000000..748c57df613
--- /dev/null
+++ b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-action-plans.hbs
@@ -0,0 +1,22 @@
+<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">
+ {{numberShort count}}
+ </td>
+ <td class="barchart">
+ <div class="barchart" style="width: 100%;">
+ <div style="width: {{percent count ../total}};"></div>
+ </div>
+ </td>
+ </tr>
+ {{/each}}
+</table>
diff --git a/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-assignees.hbs b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-assignees.hbs
new file mode 100644
index 00000000000..030e94370c1
--- /dev/null
+++ b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-assignees.hbs
@@ -0,0 +1,22 @@
+<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">
+ {{numberShort count}}
+ </td>
+ <td class="barchart">
+ <div class="barchart" style="width: 100%;">
+ <div style="width: {{percent count ../total}};"></div>
+ </div>
+ </td>
+ </tr>
+ {{/each}}
+</table>
diff --git a/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-resolutions.hbs b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-resolutions.hbs
new file mode 100644
index 00000000000..2d83a97ba4a
--- /dev/null
+++ b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-resolutions.hbs
@@ -0,0 +1,22 @@
+<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">
+ {{numberShort count}}
+ </td>
+ <td class="barchart">
+ <div class="barchart" style="width: 100%;">
+ <div style="width: {{percent count ../total}};"></div>
+ </div>
+ </td>
+ </tr>
+ {{/each}}
+</table>
diff --git a/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-severities.hbs b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-severities.hbs
new file mode 100644
index 00000000000..64cb0477d9f
--- /dev/null
+++ b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-severities.hbs
@@ -0,0 +1,19 @@
+<table class="data zebra">
+ <tr>
+ <td>
+ <a href="{{link '/issues/search#' query}}"><strong>{{t 'total'}}</strong></a>
+ </td>
+ <td class="text-right"><strong>{{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">
+ {{numberShort count}}
+ </td>
+ </tr>
+ {{/each}}
+</table>
diff --git a/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-statuses.hbs b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-statuses.hbs
new file mode 100644
index 00000000000..97dc5ec5e70
--- /dev/null
+++ b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter-statuses.hbs
@@ -0,0 +1,27 @@
+<table class="data zebra">
+ <tr>
+ <td><strong>{{t 'total'}}</strong></td>
+ <td class="text-right"><strong>{{total}}</strong></td>
+ <td class="barchart">
+ <div class="barchart" style="width: 100%;">
+ <div style="width: 100%;"></div>
+ </div>
+ </td>
+ </tr>
+ {{#each items}}
+ <tr>
+ <td>
+ {{statusIcon val}}
+ <a href="{{issueFilterItemLink ../parsedQuery ../property val}}">{{t 'issue.status' val}}</a>
+ </td>
+ <td class="text-right nowrap">
+ {{numberShort count}}
+ </td>
+ <td class="barchart">
+ <div class="barchart" style="width: 100%;">
+ <div style="width: {{percent count ../total}};"></div>
+ </div>
+ </td>
+ </tr>
+ {{/each}}
+</table>
diff --git a/server/sonar-web/src/main/hbs/widgets/widget-issue-filter.hbs b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter.hbs
new file mode 100644
index 00000000000..e635a2fdcde
--- /dev/null
+++ b/server/sonar-web/src/main/hbs/widgets/widget-issue-filter.hbs
@@ -0,0 +1,18 @@
+<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">
+ {{numberShort count}}
+ </td>
+ <td class="barchart">
+ <div class="barchart" style="width: 100%;">
+ <div style="width: {{percent count ../total}};"></div>
+ </div>
+ </td>
+ </tr>
+ {{/each}}
+</table>
diff --git a/server/sonar-web/src/main/js/widgets/issue-filter.js b/server/sonar-web/src/main/js/widgets/issue-filter.js
new file mode 100644
index 00000000000..de810bf8e66
--- /dev/null
+++ b/server/sonar-web/src/main/js/widgets/issue-filter.js
@@ -0,0 +1,218 @@
+define(['templates/widgets'], function () {
+
+ var $ = jQuery,
+ defaultComparator = function (item) {
+ return -item.count;
+ },
+ defaultFilter = function (item) {
+ var items = this.query[this.property];
+ return items == null ||
+ (items != null && items.split(',').indexOf(item.val) !== -1);
+ },
+ defaultLabel = function (item) {
+ return item.val;
+ },
+ defaultLink = function (item, property, query) {
+ var criterion = {};
+ criterion[property] = item.val;
+ var r = _.extend({}, query, criterion);
+ return baseUrl + '/issues/search#' + getQuery(r);
+ },
+ byDistributionConf = {
+ 'severities': {
+ template: 'widget-issue-filter-severities',
+ comparator: function (item) {
+ var order = ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'];
+ return order.indexOf(item.val);
+ }
+ },
+ 'statuses': {
+ template: 'widget-issue-filter-statuses',
+ comparator: function (item) {
+ var order = ['OPEN', 'REOPENED', 'CONFIRMED', 'RESOLVED', 'CLOSED'];
+ return order.indexOf(item.val);
+ }
+ },
+ 'resolutions': {
+ template: 'widget-issue-filter-resolutions',
+ comparator: function (item) {
+ var order = ['', 'FALSE-POSITIVE', 'WONTFIX', 'FIXED', 'REMOVED'];
+ return order.indexOf(item.val);
+ }
+ },
+ 'rules': {
+ label: function (item, r) {
+ if (_.isArray(r.rules)) {
+ var rule = _.findWhere(r.rules, { key: item.val });
+ if (rule != null) {
+ return rule.name;
+ }
+ }
+ }
+ },
+ 'projectUuids': {
+ label: function (item, r) {
+ if (_.isArray(r.projects)) {
+ var project = _.findWhere(r.projects, { uuid: item.val });
+ if (project != null) {
+ return project.name;
+ }
+ }
+ }
+ },
+ 'assignees': {
+ template: 'widget-issue-filter-assignees',
+ label: function (item, r) {
+ if (_.isArray(r.users)) {
+ var user = _.findWhere(r.users, { login: item.val });
+ if (user != null) {
+ return user.name;
+ }
+ }
+ }
+ },
+ 'languages': {
+ label: function (item, r) {
+ if (_.isArray(r.languages)) {
+ var lang = _.findWhere(r.languages, { key: item.val });
+ if (lang != null) {
+ return lang.name;
+ }
+ }
+ }
+ },
+ 'actionPlans': {
+ template: 'widget-issue-filter-action-plans',
+ label: function (item, r) {
+ if (_.isArray(r.actionPlans)) {
+ var actionPlan = _.findWhere(r.actionPlans, { key: item.val });
+ if (actionPlan != null) {
+ return actionPlan.name;
+ }
+ }
+ }
+ },
+ 'createdAt': {
+ comparator: function (item) {
+ return moment(item.val).toDate();
+ },
+ label: function (item, r, items, index, query) {
+ var beginning = moment(item.val),
+ endDate = query.createdBefore != null ? moment(query.createdBefore) : moment(),
+ ending = index < items.length - 1 ? moment(items[index + 1].val).subtract(1, 'days') : endDate,
+ isSameDay = ending.diff(beginning, 'days') <= 1;
+ return beginning.format('LL') + (isSameDay ? '' : (' – ' + ending.format('LL')));
+ },
+ link: function (item, property, query, index, items) {
+ 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,
+ isSameDay = createdBefore.diff(createdAfter, 'days') <= 1;
+ if (isSameDay) {
+ createdBefore.add(1, 'days');
+ }
+ var r = _.extend({}, query, {
+ createdAfter: createdAfter.format('YYYY-MM-DD'),
+ createdBefore: createdBefore.format('YYYY-MM-DD')
+ });
+ return baseUrl + '/issues/search#' + getQuery(r);
+ }
+ }
+ };
+
+ function getQuery (query, separator) {
+ separator = separator || '|';
+ var route = [];
+ _.forEach(query, function (value, property) {
+ route.push('' + property + '=' + encodeURIComponent(value));
+ });
+ return route.join(separator);
+ }
+
+ Handlebars.registerHelper('issueFilterItemLink', function (query, property, value) {
+ var criterion = {};
+ criterion[property] = value;
+ var r = _.extend({}, query, criterion);
+ return baseUrl + '/issues/search#' + getQuery(r);
+ });
+
+ return Marionette.ItemView.extend({
+
+ getTemplate: function () {
+ var template = this.conf != null && this.conf.template != null ? this.conf.template : 'widget-issue-filter';
+ return Templates[template];
+ },
+
+ initialize: function () {
+ this.model = new Backbone.Model({
+ query: this.options.query,
+ parsedQuery: this.getParsedQuery(),
+ property: this.options.distributionAxis
+ });
+ this.listenTo(this.model, 'change', this.render);
+ this.conf = byDistributionConf[this.options.distributionAxis];
+ this.query = this.getParsedQuery();
+ this.requestIssues();
+ },
+
+ getParsedQuery: function () {
+ var queryString = this.options.query || '',
+ query = {};
+ queryString.split('|').forEach(function (criterionString) {
+ var criterion = criterionString.split('=');
+ if (criterion.length === 2) {
+ query[criterion[0]] = criterion[1];
+ }
+ });
+ return query;
+ },
+
+ sortItems: function (items) {
+ var comparator = this.conf != null && this.conf.comparator != null ? this.conf.comparator : defaultComparator;
+ return _.sortBy(items, comparator);
+ },
+
+ filterItems: function (items) {
+ var filter = this.conf != null && this.conf.filter != null ? this.conf.filter : defaultFilter;
+ return _.filter(items, filter, { query: this.query, property: this.options.distributionAxis });
+ },
+
+ withLink: function (items) {
+ var link = this.conf != null && this.conf.link != null ? this.conf.link : defaultLink,
+ property = this.options.distributionAxis,
+ query = this.model.get('parsedQuery');
+ return items.map(function (item, index) {
+ return _.extend(item, { searchLink: link(item, property, query, index, items) });
+ });
+ },
+
+ withLabels: function (items) {
+ var label = this.conf != null && this.conf.label != null ? this.conf.label : defaultLabel,
+ r = this.model.get('rawResponse'),
+ query = this.model.get('parsedQuery');
+ return items.map(function (item, index) {
+ return _.extend(item, { label: label(item, r, items, index, query) });
+ });
+ },
+
+ requestIssues: function () {
+ var that = this,
+ url = baseUrl + '/api/issues/search',
+ options = _.extend({}, this.query, {
+ ps: 1,
+ facets: this.options.distributionAxis
+ });
+ return $.get(url, options).done(function (r) {
+ if (_.isArray(r.facets) && r.facets.length === 1) {
+ // save response object, but do not trigger repaint
+ that.model.set({ rawResponse: r }, { silent: true });
+ that.model.set({
+ items: that.sortItems(that.withLabels(that.withLink(that.filterItems(r.facets[0].values)))),
+ total: r.total
+ });
+ }
+ });
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/less/init/misc.less b/server/sonar-web/src/main/less/init/misc.less
index f8b31448f3d..3dc7e5df1ec 100644
--- a/server/sonar-web/src/main/less/init/misc.less
+++ b/server/sonar-web/src/main/less/init/misc.less
@@ -103,3 +103,19 @@ td.spacer-top {
.bordered-top {
border-top: 1px solid @barBorderColor;
}
+
+.zero-font-size {
+ font-size: 0 !important;
+}
+
+.width-100 {
+ width: 100%;
+}
+
+.width-80 {
+ width: 80%;
+}
+
+.width-60 {
+ width: 60%;
+}
diff --git a/server/sonar-web/src/main/less/init/tables.less b/server/sonar-web/src/main/less/init/tables.less
index afca8360a88..aca9725e965 100644
--- a/server/sonar-web/src/main/less/init/tables.less
+++ b/server/sonar-web/src/main/less/init/tables.less
@@ -53,8 +53,9 @@ table.data > tfoot > tr > td {
}
table.data > tbody > tr > td {
- padding: 5px;
+ padding: 4px 5px;
vertical-align: text-top;
+ line-height: 20px;
}
table.data td.small, table.data th.small {
diff --git a/server/sonar-web/src/main/less/pages/dashboard.less b/server/sonar-web/src/main/less/pages/dashboard.less
index 8dc8cfdffe6..84fd6334170 100644
--- a/server/sonar-web/src/main/less/pages/dashboard.less
+++ b/server/sonar-web/src/main/less/pages/dashboard.less
@@ -325,22 +325,6 @@
.widget-span-11 { width: 91.666666666667%; }
.widget-span-12 { width: 100%; }
-@media (max-width: 1279px) {
- .widget-span-1 { width: 50%; }
- .widget-span-2 { width: 50%; }
- .widget-span-3 { width: 50%; }
- .widget-span-3-5 { width: 50%; }
- .widget-span-4 { width: 50%; }
- .widget-span-5 { width: 50%; }
- .widget-span-6 { width: 50%; }
- .widget-span-7 { width: 100%; }
- .widget-span-8 { width: 100%; }
- .widget-span-9 { width: 100%; }
- .widget-span-10 { width: 100%; }
- .widget-span-11 { width: 100%; }
- .widget-span-12 { width: 100%; }
-}
-
.widget-label {
display: block;
font-size: @baseFontSize;
diff --git a/server/sonar-web/src/main/less/style.less b/server/sonar-web/src/main/less/style.less
index 5278454f452..806d57bfc2c 100644
--- a/server/sonar-web/src/main/less/style.less
+++ b/server/sonar-web/src/main/less/style.less
@@ -707,7 +707,8 @@ div.barchart {
}
div.barchart > div {
- background-color: @darkBlue;
+ min-width: 1px;
+ background-color: #c4d6e1;
height: 0.9em;
}