UnresolvedIssuesPerAssigneeWidget.class,
UnresolvedIssuesStatusesWidget.class,
IssueFilterWidget.class,
+ ProjectIssueFilterWidget.class,
IssueTagCloudWidget.class,
// batch
--- /dev/null
+/*
+ * 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.
+ */
+package org.sonar.plugins.core.widgets.issues;
+
+import org.sonar.api.web.*;
+import org.sonar.plugins.core.widgets.CoreWidget;
+
+import static org.sonar.api.web.WidgetScope.PROJECT;
+
+@WidgetCategory({"Filters", "Issues"})
+@WidgetScope(PROJECT)
+@WidgetProperties({
+ @WidgetProperty(key = ProjectIssueFilterWidget.FILTER_PROPERTY, type = WidgetPropertyType.ISSUE_FILTER, optional = false),
+ @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")
+})
+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 ID = "project_issue_filter";
+
+ public ProjectIssueFilterWidget() {
+ super(ID, "Issue Filter", "/org/sonar/plugins/core/widgets/issues/project_issue_filter.html.erb");
+ }
+}
--- /dev/null
+<%
+ container_id = 'widget-issue-filter-' + widget.id.to_s
+ filter_id = widget_properties['filter']
+ filter = Internal.issues.findIssueFilterById(filter_id.to_i)
+ distribution_axis = widget_properties['distributionAxis']
+
+ if @dashboard_configuration.selected_period?
+ period_date = @snapshot.period_datetime(@dashboard_configuration.period_index).strftime('%FT%T%z')
+ else
+ period_date = nil
+ end
+%>
+
+<% if filter %>
+ <% if Internal.issues.isUserAuthorized(filter) %>
+
+ <% @widget_title = "<a href=\"#{url_for({:controller => 'component_issues', :action => 'index'})}?id=#{u(@project.key)}##{filter.data}\">#{h(filter.name)}</a>" %>
+ <% if widget_properties['displayFilterDescription'] && !filter.description.blank? %>
+ <p class="note spacer-bottom"><%= h filter.description -%></p>
+ <% end %>
+
+ <div id="<%= container_id -%>"></div>
+ <script>
+ require(['widgets/issue-filter'], function (IssueFilter) {
+ window.requestMessages().done(function () {
+ new IssueFilter({
+ el: '#<%= container_id -%>',
+ query: '<%= filter.data -%>',
+ distributionAxis: '<%= distribution_axis -%>',
+ <% if period_date %>
+ periodDate: '<%= period_date -%>',
+ <% end %>
+ componentUuid: '<%= @project.uuid -%>',
+ componentKey: '<%= @project.key -%>'
+ });
+ });
+ });
+ </script>
+
+ <% else %>
+
+ <p class="message-alert"><%= message 'widget.issue_filter.insufficient_privileges_warning' -%></p>
+
+ <% end %>
+<% else %>
+
+ <p class="message-alert"><%= message 'widget.issue_filter.unknown_filter_warning' -%></p>
+
+<% end %>
<tr>
<td>
- <a href="{{link '/issues/search#' query}}"><strong>{{t 'total'}}</strong></a>
+ <a href="{{issueFilterTotalLink parsedQuery}}"><strong>{{t 'total'}}</strong></a>
</td>
- <td class="text-right"><strong>{{total}}</strong></td>
+ <td class="text-right"><strong>{{#notNull periodDate}}+{{/notNull}}{{total}}</strong></td>
<td class="barchart">
<div class="barchart" style="width: 100%;">
<div style="width: 100%;"></div>
{{/eq}}
</td>
<td class="text-right nowrap">
- {{numberShort count}}
+ {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}}
</td>
<td class="barchart">
<div class="barchart" style="width: 100%;">
{{/eq}}
</td>
<td class="text-right nowrap">
- {{numberShort count}}
+ {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}}
</td>
<td class="barchart">
<div class="barchart" style="width: 100%;">
{{/eq}}
</td>
<td class="text-right nowrap">
- {{numberShort count}}
+ {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}}
</td>
<td class="barchart">
<div class="barchart" style="width: 100%;">
<a href="{{issueFilterItemLink ../parsedQuery ../property val}}">{{t 'severity' val}}</a>
</td>
<td class="text-right nowrap">
- {{numberShort count}}
+ {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}}
</td>
</tr>
{{/each}}
<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>
+ {{> '_widget-issue-filter-total'}}
{{#each items}}
<tr>
<td>
<a href="{{issueFilterItemLink ../parsedQuery ../property val}}">{{t 'issue.status' val}}</a>
</td>
<td class="text-right nowrap">
- {{numberShort count}}
+ {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}}
</td>
<td class="barchart">
<div class="barchart" style="width: 100%;">
<a href="{{searchLink}}">{{default label val}}</a>
</td>
<td class="text-right nowrap">
- {{numberShort count}}
+ {{#notNull ../periodDate}}+{{/notNull}}{{numberShort count}}
</td>
<td class="barchart">
<div class="barchart" style="width: 100%;">
var criterion = {};
criterion[property] = item.val;
var r = _.extend({}, query, criterion);
- return baseUrl + '/issues/search#' + getQuery(r);
+ if (r.componentKey != null) {
+ return baseUrl + '/component_issues/index?id=' + encodeURIComponent(r.componentKey) +
+ '#' + getQuery(_.omit(r, 'componentKey'));
+ } else {
+ return baseUrl + '/issues/search#' + getQuery(r);
+ }
},
byDistributionConf = {
'severities': {
comparator: function (item) {
var order = ['', 'FALSE-POSITIVE', 'WONTFIX', 'FIXED', 'REMOVED'];
return order.indexOf(item.val);
+ },
+ filter: function (item) {
+ if ('' + this.query.resolved === 'false') {
+ return item.val === '';
+ } else {
+ return defaultFilter.call(this, item);
+ }
}
},
'rules': {
createdAfter: createdAfter.format('YYYY-MM-DD'),
createdBefore: createdBefore.format('YYYY-MM-DD')
});
- return baseUrl + '/issues/search#' + getQuery(r);
+ if (r.componentKey != null) {
+ return baseUrl + '/component_issues/index?id=' + encodeURIComponent(r.componentKey) +
+ '#' + getQuery(_.omit(r, 'componentKey'));
+ } else {
+ return baseUrl + '/issues/search#' + getQuery(r);
+ }
}
}
};
var criterion = {};
criterion[property] = value;
var r = _.extend({}, query, criterion);
- return baseUrl + '/issues/search#' + getQuery(r);
+ if (r.componentKey != null) {
+ return baseUrl + '/component_issues/index?id=' + encodeURIComponent(r.componentKey) +
+ '#' + getQuery(_.omit(r, 'componentKey'));
+ } else {
+ return baseUrl + '/issues/search#' + getQuery(r);
+ }
+ });
+
+ Handlebars.registerHelper('issueFilterTotalLink', function (query) {
+ var r = _.extend({}, query);
+ if (r.componentKey != null) {
+ return baseUrl + '/component_issues/index?id=' + encodeURIComponent(r.componentKey) +
+ '#' + getQuery(_.omit(r, 'componentKey'));
+ } else {
+ return baseUrl + '/issues/search#' + getQuery(r);
+ }
});
return Marionette.ItemView.extend({
this.model = new Backbone.Model({
query: this.options.query,
parsedQuery: this.getParsedQuery(),
- property: this.options.distributionAxis
+ property: this.options.distributionAxis,
+ periodDate: this.options.periodDate
});
this.listenTo(this.model, 'change', this.render);
this.conf = byDistributionConf[this.options.distributionAxis];
query[criterion[0]] = criterion[1];
}
});
+ if (this.options.componentKey != null) {
+ _.extend(query, { componentKey: this.options.componentKey });
+ }
+ if (this.options.periodDate != null) {
+ _.extend(query, { createdAfter: this.options.periodDate });
+ }
return query;
},
ps: 1,
facets: this.options.distributionAxis
});
+ if (this.options.componentUuid != null) {
+ _.extend(options, { componentUuids: this.options.componentUuid });
+ }
+ if (this.options.periodDate != null) {
+ _.extend(options, { createdAfter: this.options.periodDate });
+ }
return $.get(url, options).done(function (r) {
if (_.isArray(r.facets) && r.facets.length === 1) {
// save response object, but do not trigger repaint
widget.issue_filter.property.distributionAxis.option.reporters.name=By Reporter
widget.issue_filter.property.distributionAxis.option.authors.name=By Author
+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.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
+widget.project_issue_filter.property.distributionAxis.option.statuses.name=By Status
+widget.project_issue_filter.property.distributionAxis.option.createdAt.name=New Issues
+widget.project_issue_filter.property.distributionAxis.option.actionPlans.name=By Action Plan
+widget.project_issue_filter.property.distributionAxis.option.assignees.name=By Assignee
+widget.project_issue_filter.property.distributionAxis.option.tags.name=By Tag
+widget.project_issue_filter.property.distributionAxis.option.rules.name=By Rule
+widget.project_issue_filter.property.distributionAxis.option.resolutions.name=By Resolution
+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.issue_tag_cloud.name=Project Issue Tag Cloud
widget.issue_tag_cloud.title=Issue Tag Cloud
widget.issue_tag_cloud.description=Displays the cloud of tags associated to unresolved issues.