ActionPlansWidget.class,
UnresolvedIssuesPerAssigneeWidget.class,
UnresolvedIssuesStatusesWidget.class,
+ IssueFilterWidget.class,
org.sonar.api.issue.NoSonarFilter.class,
// issue notifications
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.GLOBAL;
+
+@WidgetCategory({"Filters", "Global", "Issues"})
+@WidgetScope(GLOBAL)
+@WidgetProperties({
+ @WidgetProperty(key = IssueFilterWidget.FILTER_PROPERTY, type = WidgetPropertyType.ISSUE_FILTER, optional = false),
+ @WidgetProperty(key = IssueFilterWidget.PAGE_SIZE_PROPERTY, type = WidgetPropertyType.INTEGER, defaultValue = "30"),
+ @WidgetProperty(key = IssueFilterWidget.DISPLAY_FILTER_DESCRIPTION, type = WidgetPropertyType.BOOLEAN, defaultValue = "false")
+})
+public class IssueFilterWidget extends CoreWidget {
+
+ public static final String FILTER_PROPERTY = "filter";
+ public static final String PAGE_SIZE_PROPERTY = "numberOfLines";
+ public static final String DISPLAY_FILTER_DESCRIPTION = "displayFilterDescription";
+ public static final String ID = "issue_filter";
+
+ public IssueFilterWidget() {
+ super(ID, "Issue Filter", "/org/sonar/plugins/core/widgets/issues/issue_filter.html.erb");
+ }
+}
issue_filter.criteria.severity=Severity
issue_filter.criteria.status=Status
issue_filter.max_results_reached=Only the first {0} issues matching the search criteria have been retrieved. Add some additional criteria to get fewer results to be able to sort this list.
+issue_filter.widget.max_results_reached=Only the first {0} issues matching the search criteria have been retrieved.
issue_filter.no_result=No matching issues found.
issue_filter.save_filter=Save Filter
issue_filter.edit_filter=Edit Filter
widget.action_plans.no_action_plan=No action plan
widget.action_plans.x_unresolved_issues={0} unresolved issues
+widget.issue_filter.name=Issue Filter
+widget.issue_filter.description=Displays the result of a pre-configured issue filter.
+widget.issue_filter.property.filter.name=Filter
+widget.issue_filter.property.numberOfLines.name=Page size
+widget.issue_filter.property.displayFilterDescription.name=Display filter description
+widget.issue_filter.unknown_filter_warning=This widget is configured to display an issue filter that doesn't exist anymore.
+
widget.treemap-widget.name=Treemap of Components
widget.treemap-widget.description=Displays a treemap of all direct components of the selected resource.
widget.treemap-widget.property.sizeMetric.name=Size metric
--- /dev/null
+<%
+ filter_id = widget_properties['filter']
+ filter = Internal.issues.findIssueFilterById(filter_id.to_i)
+ if filter
+ if Internal.issues.isUserAuthorized(filter)
+ search_options = {}
+ search_options['filter'] = filter_id
+ @widget_title = link_to h(filter.name), {:controller => 'issues', :action => 'filter', :id => filter.id}
+%>
+ <% if widget_properties['displayFilterDescription'] && !filter.description.blank? %>
+ <div style="padding-bottom: 5px">
+ <span class="note"><%= h filter.description -%></span>
+ </div>
+ <% end %>
+
+ <%= render :partial => 'project/widgets/issues/issues_list_widget',
+ :locals => {:search_options => search_options, :widget_id => widget.id.to_s, :widget_properties => widget_properties} %>
+ <%
+ end
+ else
+ %>
+ <p><%= image_tag 'warning.png' %> <%= message 'widget.issue_filter.unknown_filter_warning' -%></p>
+<%
+ end
+%>
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import org.junit.Test;
import org.reflections.Reflections;
import java.util.Collection;
import java.util.Set;
+import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;
public class CoreWidgetsTest {
}
private Collection<CoreWidget> widgets() {
- return Collections2.transform(widgetClasses(), new Function<Class<? extends CoreWidget>, CoreWidget>() {
+ return newArrayList(Iterables.transform(widgetClasses(), new Function<Class<? extends CoreWidget>, CoreWidget>() {
public CoreWidget apply(@Nullable Class<? extends CoreWidget> aClass) {
try {
return aClass.newInstance();
throw Throwables.propagate(e);
}
}
- });
+ }));
}
}
METRIC,
/**
- * Filter id
+ * Measure Filter id
*
* @since 3.1
*/
FILTER,
+ /**
+ * Issue Filter id
+ *
+ * @since 3.7
+ */
+ ISSUE_FILTER,
+
/**
* Multiple line text-area
*
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.ServerComponent;
-import org.sonar.api.issue.*;
+import org.sonar.api.issue.ActionPlan;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.IssueComment;
+import org.sonar.api.issue.IssueQuery;
import org.sonar.api.issue.action.Action;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.rule.RuleKey;
import org.sonar.server.user.UserSession;
import org.sonar.server.util.RubyUtils;
+import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import java.util.Collection;
return actionService.listAvailableActions(issue);
}
- public IssueQuery toQuery(Map<String, Object> props) {
- return PublicRubyIssueService.toQuery(props);
+ public IssueQuery emptyIssueQuery() {
+ return PublicRubyIssueService.toQuery(Maps.<String, Object>newHashMap());
}
- public IssueQuery toQuery(DefaultIssueFilter issueFilter) {
- return toQuery(issueFilterService.deserializeIssueFilterQuery(issueFilter));
+ @CheckForNull
+ public DefaultIssueFilter findIssueFilterById(Long id) {
+ return issueFilterService.findById(id);
}
+ /**
+ * Return the issue filter if the user has the right to see it
+ * Never return null
+ */
public DefaultIssueFilter findIssueFilter(Long id) {
- return issueFilterService.findById(id, UserSession.get());
+ return issueFilterService.find(id, UserSession.get());
}
public List<DefaultIssueFilter> findUserIssueFilters() {
return issueFilterService.findByUser(UserSession.get());
}
+ public boolean isUserAuthorized(DefaultIssueFilter issueFilter) {
+ try {
+ UserSession userSession = UserSession.get();
+ issueFilterService.verifyLoggedIn(userSession);
+ issueFilterService.verifyCurrentUserCanReadFilter(issueFilter, userSession);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
public String serializeFilterQuery(Map<String, Object> filterQuery){
return issueFilterService.serializeFilterQuery(filterQuery);
}
/**
- * Execute issue filter from issue query
+ * Execute issue filter from parameters
*/
- public IssueQueryResult execute(IssueQuery issueQuery) {
+ public IssueFilterResult execute(Map<String, Object> props) {
+ IssueQuery issueQuery = PublicRubyIssueService.toQuery(props);
return issueFilterService.execute(issueQuery);
}
/**
- * Execute issue filter from existing filter
+ * Execute issue filter from existing filter with optional overridable parameters
*/
- public IssueQueryResult execute(Long issueFilterId) {
- return issueFilterService.execute(issueFilterId, UserSession.get());
+ public IssueFilterResult execute(Long issueFilterId, Map<String, Object> overrideProps) {
+ DefaultIssueFilter issueFilter = issueFilterService.find(issueFilterId, UserSession.get());
+ Map<String, Object> props = issueFilterService.deserializeIssueFilterQuery(issueFilter);
+ overrideProps(props, overrideProps);
+ IssueQuery issueQuery = PublicRubyIssueService.toQuery(props);
+ return issueFilterService.execute(issueQuery);
+ }
+
+ private void overrideProps(Map<String, Object> props, Map<String, Object> overrideProps){
+ overrideProp(props, overrideProps, "pageSize");
+ overrideProp(props, overrideProps, "pageIndex");
+ }
+
+ private void overrideProp(Map<String, Object> props, Map<String, Object> overrideProps, String key){
+ if (overrideProps.containsKey(key)) {
+ props.put(key, overrideProps.get(key));
+ }
}
/**
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.server.issue;
+
+import org.sonar.api.issue.IssueQuery;
+import org.sonar.api.issue.IssueQueryResult;
+
+public class IssueFilterResult {
+
+ private IssueQueryResult issueQueryResult;
+ private IssueQuery issueQuery;
+
+ public IssueFilterResult(IssueQueryResult issueQueryResult, IssueQuery issueQuery) {
+ this.issueQueryResult = issueQueryResult;
+ this.issueQuery = issueQuery;
+ }
+
+ public IssueQueryResult result() {
+ return issueQueryResult;
+ }
+
+ public IssueQuery query() {
+ return issueQuery;
+ }
+}
this.issueFilterSerializer = issueFilterSerializer;
}
- public IssueQueryResult execute(IssueQuery issueQuery) {
- return issueFinder.find(issueQuery);
+ public IssueFilterResult execute(IssueQuery issueQuery) {
+ return createIssueFilterResult(issueFinder.find(issueQuery), issueQuery);
}
- public IssueQueryResult execute(Long issueFilterId, UserSession userSession) {
- IssueFilterDto issueFilterDto = findIssueFilter(issueFilterId, userSession);
-
- DefaultIssueFilter issueFilter = issueFilterDto.toIssueFilter();
- IssueQuery issueQuery = PublicRubyIssueService.toQuery(deserializeIssueFilterQuery(issueFilter));
- return issueFinder.find(issueQuery);
+ public DefaultIssueFilter find(Long id, UserSession userSession) {
+ return findIssueFilterDto(id, userSession).toIssueFilter();
}
@CheckForNull
- public DefaultIssueFilter findById(Long id, UserSession userSession) {
- IssueFilterDto issueFilterDto = findIssueFilter(id, userSession);
+ public DefaultIssueFilter findById(Long id) {
+ IssueFilterDto issueFilterDto = issueFilterDao.selectById(id);
return issueFilterDto.toIssueFilter();
}
}
public DefaultIssueFilter update(DefaultIssueFilter issueFilter, UserSession userSession) {
- IssueFilterDto issueFilterDto = findIssueFilter(issueFilter.id(), userSession);
- verifyCurrentUserCanModifyFilter(issueFilterDto, userSession);
+ IssueFilterDto issueFilterDto = findIssueFilterDto(issueFilter.id(), userSession);
+ verifyCurrentUserCanModifyFilter(issueFilterDto.toIssueFilter(), userSession);
validateFilter(issueFilter, userSession);
issueFilterDao.update(IssueFilterDto.toIssueFilter(issueFilter));
}
public DefaultIssueFilter updateFilterQuery(Long issueFilterId, Map<String, Object> filterQuery, UserSession userSession) {
- IssueFilterDto issueFilterDto = findIssueFilter(issueFilterId, userSession);
- verifyCurrentUserCanModifyFilter(issueFilterDto, userSession);
+ IssueFilterDto issueFilterDto = findIssueFilterDto(issueFilterId, userSession);
+ verifyCurrentUserCanModifyFilter(issueFilterDto.toIssueFilter(), userSession);
DefaultIssueFilter issueFilter = issueFilterDto.toIssueFilter();
issueFilter.setData(serializeFilterQuery(filterQuery));
}
public void delete(Long issueFilterId, UserSession userSession) {
- IssueFilterDto issueFilterDto = findIssueFilter(issueFilterId, userSession);
- verifyCurrentUserCanModifyFilter(issueFilterDto, userSession);
+ IssueFilterDto issueFilterDto = findIssueFilterDto(issueFilterId, userSession);
+ verifyCurrentUserCanModifyFilter(issueFilterDto.toIssueFilter(), userSession);
deleteFavouriteIssueFilters(issueFilterDto);
issueFilterDao.delete(issueFilterId);
}
public DefaultIssueFilter copy(Long issueFilterIdToCopy, DefaultIssueFilter issueFilter, UserSession userSession) {
- IssueFilterDto issueFilterDtoToCopy = findIssueFilter(issueFilterIdToCopy, userSession);
+ IssueFilterDto issueFilterDtoToCopy = findIssueFilterDto(issueFilterIdToCopy, userSession);
issueFilter.setUser(userSession.login());
issueFilter.setData(issueFilterDtoToCopy.getData());
validateFilter(issueFilter, userSession);
}
public void toggleFavouriteIssueFilter(Long issueFilterId, UserSession userSession) {
- findIssueFilter(issueFilterId, userSession);
+ findIssueFilterDto(issueFilterId, userSession);
IssueFilterFavouriteDto issueFilterFavouriteDto = findFavouriteIssueFilter(userSession.login(), issueFilterId);
if (issueFilterFavouriteDto == null) {
addFavouriteIssueFilter(issueFilterId, userSession.login());
}
}
- public IssueFilterDto findIssueFilter(Long id, UserSession userSession) {
+ public String serializeFilterQuery(Map<String, Object> filterQuery) {
+ return issueFilterSerializer.serialize(filterQuery);
+ }
+
+ public Map<String, Object> deserializeIssueFilterQuery(DefaultIssueFilter issueFilter) {
+ return issueFilterSerializer.deserialize(issueFilter.data());
+ }
+
+ private IssueFilterDto findIssueFilterDto(Long id, UserSession userSession) {
verifyLoggedIn(userSession);
IssueFilterDto issueFilterDto = issueFilterDao.selectById(id);
if (issueFilterDto == null) {
// TODO throw 404
throw new IllegalArgumentException("Filter not found: " + id);
}
- verifyCurrentUserCanReadFilter(issueFilterDto, userSession);
+ verifyCurrentUserCanReadFilter(issueFilterDto.toIssueFilter(), userSession);
return issueFilterDto;
}
- public String serializeFilterQuery(Map<String, Object> filterQuery){
- return issueFilterSerializer.serialize(filterQuery);
- }
-
- public Map<String, Object> deserializeIssueFilterQuery(DefaultIssueFilter issueFilter){
- return issueFilterSerializer.deserialize(issueFilter.data());
- }
-
- private void verifyLoggedIn(UserSession userSession) {
+ void verifyLoggedIn(UserSession userSession) {
if (!userSession.isLoggedIn() && userSession.login() != null) {
throw new IllegalStateException("User is not logged in");
}
}
- private void verifyCurrentUserCanReadFilter(IssueFilterDto issueFilterDto, UserSession userSession) {
- if (!issueFilterDto.getUserLogin().equals(userSession.login()) && !issueFilterDto.isShared()) {
+ void verifyCurrentUserCanReadFilter(DefaultIssueFilter issueFilter, UserSession userSession) {
+ if (!issueFilter.user().equals(userSession.login()) && !issueFilter.shared()) {
// TODO throw unauthorized
throw new IllegalStateException("User is not authorized to read this filter");
}
}
- private void verifyCurrentUserCanModifyFilter(IssueFilterDto issueFilterDto, UserSession userSession) {
- if (!issueFilterDto.getUserLogin().equals(userSession.login()) && !isAdmin(userSession.login())) {
+ private void verifyCurrentUserCanModifyFilter(DefaultIssueFilter issueFilter, UserSession userSession) {
+ if (!issueFilter.user().equals(userSession.login()) && !isAdmin(userSession.login())) {
// TODO throw unauthorized
throw new IllegalStateException("User is not authorized to modify this filter");
}
return authorizationDao.selectGlobalPermissions(user).contains(UserRole.ADMIN);
}
+ private IssueFilterResult createIssueFilterResult(IssueQueryResult issueQueryResult, IssueQuery issueQuery) {
+ return new IssueFilterResult(issueQueryResult, issueQuery);
+ }
+
}
@filter = find_filter(params[:id].to_i)
end
- @first_search = criteria_params.empty?
- @issue_query = Internal.issues.toQuery(criteria_params)
- @issues_result = Internal.issues.execute(@issue_query)
+ @criteria_params = criteria_params
+ @first_search = @criteria_params.empty?
+ issue_filter_result = Internal.issues.execute(@criteria_params)
+ @issue_query = issue_filter_result.query
+ @issues_result = issue_filter_result.result
end
# Load existing filter
def filter
require_parameters :id
- @filter = find_filter(params[:id].to_i)
@first_search = false
- @issue_query = Internal.issues.toQuery(@filter)
- @issues_result = Internal.issues.execute(@issue_query)
@unchanged = true
+ @criteria_params = criteria_params
+ issue_filter_result = Internal.issues.execute(params[:id].to_i, @criteria_params)
+ @issue_query = issue_filter_result.query
+ @issues_result = issue_filter_result.result
+
render :action => 'search'
end
# GET /issues/manage
def manage
- @issue_query = Internal.issues.toQuery({})
+ @issue_query = Internal.issues.emptyIssueQuery()
@filters = Internal.issues.findIssueFiltersForCurrentUser()
@shared_filters = Internal.issues.findSharedFiltersForCurrentUser()
@favourite_filter_ids = @favourite_filters.map { |filter| filter.id }
@filter = filter_result.get()
redirect_to :action => 'filter', :id => @filter.id.to_s
else
+ @unchanged = true
@errors = filter_result.errors
- @filter = find_filter(params[:id].to_i)
-
- @issue_query = Internal.issues.toQuery(@filter.dataAsMap)
- @issues_result = Internal.issues.execute(@issue_query)
- @unchanged = true
+ issue_filter_result = Internal.issues.execute(@filter.id, criteria_params)
+ @issue_query = issue_filter_result.query
+ @issues_result = issue_filter_result.result
render :action => 'search'
end
"#{filters_combo} #{filter_link}"
+ when PropertyType::TYPE_ISSUE_FILTER
+ user_filters = options_id(value, Internal.issues.findIssueFiltersForCurrentUser())
+ shared_filters = options_id(value, Internal.issues.findSharedFiltersForCurrentUser())
+
+ #user_filters = options_id(value, current_user.measure_filters)
+ #shared_filters = options_id(value, MeasureFilter.find(:all, :conditions => ['(user_id<>? or user_id is null) and shared=?', current_user.id, true]).sort_by(&:name))
+
+ filters_combo = select_tag name, option_group('My Filters', user_filters) + option_group('Shared Filters', shared_filters), html_options
+ filter_link = link_to message('widget.filter.edit'), {:controller => 'issues', :action => 'manage'}, :class => 'link-action'
+
+ "#{filters_combo} #{filter_link}"
+
when PropertyType::TYPE_SINGLE_SELECT_LIST
default_value = options[:default].blank? ? '' : message('default')
select_options = "<option value=''>#{ default_value }</option>"
TYPE_REGULAR_EXPRESSION = 'REGULAR_EXPRESSION'
TYPE_FILTER = 'FILTER'
+ # Since 3.7
+ TYPE_ISSUE_FILTER = 'ISSUE_FILTER'
def self.text_to_value(text, type)
case type
<%
table_limit = params[:table_limit] unless table_limit
widget_id = params[:widget_id] unless widget_id
- search_options = params.clone unless search_options
- # Hack to delete params coming from pagination
- search_options.delete(:controller)
- search_options.delete(:action)
- search_options.delete(:page_id)
- search_options.delete(:table_limit)
- search_options.delete(:widget_id)
- search_options.delete(:period)
+ search_options = params.clone unless search_options
+ search_options['pageIndex'] = params[:pageIndex] || 1
+ search_options['pageSize'] = table_limit.to_i
- search_options['sort'] = 'UPDATE_DATE'
- search_options['asc'] = 'FALSE'
- if @dashboard_configuration && @dashboard_configuration.selected_period?
- search_options['createdAfter'] = Api::Utils.format_datetime(@dashboard_configuration.from_datetime)
- search_options['createdBefore'] = Api::Utils.format_datetime(DateTime.now)
+ if search_options['filter']
+ issue_filter_result = Internal.issues.execute(search_options['filter'].to_i, search_options)
+ results = issue_filter_result.result
+ else
+ search_options['sort'] = 'UPDATE_DATE'
+ search_options['asc'] = 'FALSE'
+ if @dashboard_configuration && @dashboard_configuration.selected_period?
+ search_options['createdAfter'] = Api::Utils.format_datetime(@dashboard_configuration.from_datetime)
+ search_options['createdBefore'] = Api::Utils.format_datetime(DateTime.now)
+ end
+ results = Api.issues.find(search_options)
end
- results = Api.issues.find(search_options)
issues = results.issues
-
- # table pagination
- page_size = table_limit.to_i
- total_number = issues.size
- if issues.size > page_size
- page_id = (params[:page_id] ? params[:page_id].to_i : 1)
- page_count = issues.size / page_size
- page_count += 1 if (issues.size % page_size > 0)
- from = (page_id-1) * page_size
- to = (page_id*page_size)-1
- to = issues.size-1 if to >= issues.size
- issues = issues[from..to]
- end
+ paging = results.paging
%>
-<% if issues.size ==0 %>
+<% if paging.total() == 0 %>
<span class="empty_widget"><%= message('widget.my_reviews.no_issue') -%></span>
<% else %>
</th>
</tr>
</thead>
- <tfoot>
- <tr>
- <td colspan="3">
- <%= link_to(total_number, {:controller => 'issues', :action => 'search' }.merge(search_options)) -%> <%= message('results').downcase -%>
- <%
- if page_count
- page_count = 20 if page_count>20
- link_params = search_options.clone
- link_params[:controller] = 'issue'
- link_params[:action] = 'widget_issues_list'
- link_params[:snapshot_id] = @snapshot.id if @snapshot
- link_params[:table_limit] = table_limit
- link_params[:widget_id] = widget_id
- link_params[:period] = params[:period]
- %>
- |
- <%= link_to_remote(message('paging_previous'),
- :update => "issues-widget-#{widget_id}",
- :url => {:params => link_params.merge({:page_id => page_id-1})}) if page_id>1 %>
- <%= message('paging_previous') unless page_id>1 %>
- <% for index in 1..page_count %>
- <%= index.to_s if index==page_id %>
- <%= link_to_remote(index.to_s,
- :update => "issues-widget-#{widget_id}",
- :url => {:params => link_params.merge({:page_id => index})}) unless index==page_id %>
- <% end %>
- <%= link_to_remote(message('paging_next'),
- :update => "issues-widget-#{widget_id}",
- :url => {:params => link_params.merge({:page_id => page_id+1})}) if page_id<page_count %>
- <%= message('paging_next') unless page_id<page_count %>
- <%
- end
- %>
- </td>
- </tr>
- </tfoot>
<tbody>
<%
issues.each do |issue|
end
%>
</tbody>
+ <% if results.maxResultsReached() %>
+ <p class="notes"><%= message('issue_filter.widget.max_results_reached', :params => paging.total()) -%></p>
+ <% end %>
+ <%
+ link_params = search_options.clone
+ link_params[:controller] = 'issue'
+ link_params[:action] = 'widget_issues_list'
+ link_params[:snapshot_id] = @snapshot.id if @snapshot
+ link_params[:table_limit] = table_limit
+ link_params[:widget_id] = widget_id
+ link_params[:period] = params[:period]
+ %>
+ <%= paginate_java(paging, :colspan => 4, :id => "issue-filter-foot-#{widget_id}", :include_loading_icon => true) { |label, page_id|
+ link_to_remote(label,
+ :update => "issues-widget-#{widget_id}",
+ :url => link_params.merge({:pageIndex => page_id}))
+ } -%>
</table>
+
<% end %>
\ No newline at end of file
<%
- table_limit = widget_properties["numberOfLines"]
+ table_limit = widget_properties["numberOfLines"]
%>
-<h3><%= title -%></h3>
+<% if defined? title %>
+ <h3><%= title -%></h3>
+<% end %>
<div id="issues-widget-<%= widget_id -%>">
<%= render :partial => 'project/widgets/issues/issues_list',
package org.sonar.server.issue;
+import com.google.common.collect.Maps;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@Test
public void should_execute_issue_filter_from_issue_query() {
- service.execute(IssueQuery.builder().build());
+ service.execute(Maps.<String, Object>newHashMap());
verify(issueFilterService).execute(any(IssueQuery.class));
}
@Test
public void should_execute_issue_filter_from_existing_filter() {
- service.execute(10L);
- verify(issueFilterService).execute(eq(10L), any(UserSession.class));
+ Map<String, Object> props = newHashMap();
+ props.put("componentRoots", "struts");
+ when(issueFilterService.deserializeIssueFilterQuery(any(DefaultIssueFilter.class))).thenReturn(props);
+
+ Map<String, Object> overrideProps = newHashMap();
+ overrideProps.put("pageSize", 20);
+ overrideProps.put("pageIndex", 2);
+ service.execute(10L, overrideProps);
+ ArgumentCaptor<IssueQuery> captor = ArgumentCaptor.forClass(IssueQuery.class);
+ verify(issueFilterService).execute(captor.capture());
+ verify(issueFilterService).find(eq(10L), any(UserSession.class));
+
+ IssueQuery issueQuery = captor.getValue();
+ assertThat(issueQuery.componentRoots()).contains("struts");
+ assertThat(issueQuery.pageSize()).isEqualTo(20);
+ assertThat(issueQuery.pageIndex()).isEqualTo(2);
}
@Test
verify(issueFilterService).toggleFavouriteIssueFilter(eq(10L), any(UserSession.class));
}
+ @Test
+ public void should_check_is_user_is_authorized_to_see_issue_filter() {
+ DefaultIssueFilter issueFilter = new DefaultIssueFilter();
+ service.isUserAuthorized(issueFilter);
+ verify(issueFilterService).verifyLoggedIn(any(UserSession.class));
+ verify(issueFilterService).verifyCurrentUserCanReadFilter(eq(issueFilter), any(UserSession.class));
+ }
+
private String createLongString(int size) {
String result = "";
for (int i = 0; i < size; i++) {
IssueFilterDto issueFilterDto = new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("john");
when(issueFilterDao.selectById(1L)).thenReturn(issueFilterDto);
- DefaultIssueFilter issueFilter = service.findById(1L, userSession);
+ DefaultIssueFilter issueFilter = service.findById(1L);
+ assertThat(issueFilter).isNotNull();
+ assertThat(issueFilter.id()).isEqualTo(1L);
+ }
+
+ @Test
+ public void should_find_issue_filter() {
+ IssueFilterDto issueFilterDto = new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("john");
+ when(issueFilterDao.selectById(1L)).thenReturn(issueFilterDto);
+
+ DefaultIssueFilter issueFilter = service.find(1L, userSession);
assertThat(issueFilter).isNotNull();
assertThat(issueFilter.id()).isEqualTo(1L);
}
IssueFilterDto issueFilterDto = new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("arthur").setShared(true);
when(issueFilterDao.selectById(1L)).thenReturn(issueFilterDto);
- DefaultIssueFilter issueFilter = service.findById(1L, userSession);
+ DefaultIssueFilter issueFilter = service.find(1L, userSession);
assertThat(issueFilter).isNotNull();
assertThat(issueFilter.id()).isEqualTo(1L);
}
public void should_not_find_by_id_on_not_existing_issue() {
when(issueFilterDao.selectById(1L)).thenReturn(null);
try {
- service.findById(1L, userSession);
+ service.find(1L, userSession);
fail();
} catch (Exception e) {
assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Filter not found: 1");
public void should_not_find_by_id_if_not_logged() {
when(userSession.isLoggedIn()).thenReturn(false);
try {
- service.findById(1L, userSession);
+ service.find(1L, userSession);
fail();
} catch (Exception e) {
assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("User is not logged in");
}
-
verifyZeroInteractions(issueFilterDao);
}
when(issueFilterDao.selectById(1L)).thenReturn(issueFilterDto);
try {
// John is not authorized to see eric filters
- service.findById(1L, userSession);
+ service.find(1L, userSession);
fail();
} catch (Exception e) {
assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("User is not authorized to read this filter");
verify(issueFinder).find(issueQuery);
}
- @Test
- public void should_execute_from_filter_id() {
- Map<String, Object> map = newHashMap();
- map.put("componentRoots", "struts");
- when(issueFilterSerializer.deserialize(anyString())).thenReturn(map);
- when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Old Filter").setUserLogin("john").setData("componentRoots=struts"));
-
- ArgumentCaptor<IssueQuery> issueQueryCaptor = ArgumentCaptor.forClass(IssueQuery.class);
-
- service.execute(1L, userSession);
- verify(issueFinder).find(issueQueryCaptor.capture());
-
- IssueQuery issueQuery = issueQueryCaptor.getValue();
- assertThat(issueQuery.componentRoots()).contains("struts");
- }
-
@Test
public void should_find_shared_issue_filter() {
when(issueFilterDao.selectSharedWithoutUserFilters("john")).thenReturn(newArrayList(new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("john").setShared(true)));