@@ -34,6 +34,7 @@ closed=Closed | |||
code=Code | |||
color=Color | |||
compare=Compare | |||
component=Component | |||
configurable=Configurable | |||
configure=Configure | |||
confirm=Confirm | |||
@@ -554,6 +555,23 @@ issue.resolution.FALSE-POSITIVE=False-positive | |||
issue.resolution.FIXED=Fixed | |||
issue.planned_for_x=Planned for {0} | |||
#------------------------------------------------------------------------------ | |||
# | |||
# ISSUE FILTERS | |||
# | |||
#------------------------------------------------------------------------------ | |||
issue_filter.new_search=New search | |||
issue_filter.header.action_plan=Action plan | |||
issue_filter.header.assignee=Assignee | |||
issue_filter.header.creation_date=Creation date | |||
issue_filter.header.update_date=Update date | |||
issue_filter.criteria.severities=Severities | |||
issue_filter.criteria.project=Project | |||
issue_filter.criteria.status=Status | |||
issue_filter.criteria.assignee=Assignee | |||
issue_filter.criteria.reporter=Reporter | |||
issue_filter.criteria.creation_date=Creation date | |||
#------------------------------------------------------------------------------ | |||
# |
@@ -21,19 +21,21 @@ | |||
class IssuesController < ApplicationController | |||
def index | |||
init_params | |||
@issue_results = Api.issues.find(params) | |||
@paging = @issue_results.paging | |||
@issues = @issue_results.issues | |||
@filter = IssueFilter.new | |||
render :action => 'search' | |||
end | |||
def search | |||
@filter = IssueFilter.new | |||
@filter.criteria=criteria_params | |||
@filter.execute | |||
end | |||
private | |||
def init_params | |||
def criteria_params | |||
params.merge({:controller => nil, :action => nil, :search => nil, :widget_id => nil, :edit => nil}) | |||
params['pageSize'] = 25 | |||
params['pageIndex'] ||= 1 | |||
end | |||
end |
@@ -534,39 +534,6 @@ module ApplicationHelper | |||
html | |||
end | |||
# | |||
# Creates a pagination section for the given array (items_array) if its size exceeds the pagination size (default: 20). | |||
# Upon completion of this method, the HTML is returned and the given array contains only the selected elements. | |||
# | |||
# In any case, the HTML that is returned contains the message 'x results', where x is the total number of elements | |||
# in the items_array object. | |||
# | |||
# === Optional parameters | |||
# * page_size: the number of elements to display at the same time (= the pagination size) | |||
# | |||
def paginate_java(pagination) | |||
total = pagination.total.to_i | |||
page_index = pagination.pageIndex() ? pagination.pageIndex().to_i : 1 | |||
page_size = pagination.pageSize().to_i || 20 | |||
pages = pagination.pages().to_i | |||
html = total.to_s + " " + message('results').downcase | |||
if total > page_size | |||
# render the pagination links | |||
html += " | " | |||
html += link_to_if page_index>1, message('paging_previous'), {:overwrite_params => {:pageIndex => page_index-1}} | |||
html += " " | |||
for index in 1..pages | |||
html += link_to_unless index==page_index, index.to_s, {:overwrite_params => {:pageIndex => index}} | |||
html += " " | |||
end | |||
html += link_to_if page_index<pages, message('paging_next'), {:overwrite_params => {:pageIndex => 1+page_index}} | |||
end | |||
html | |||
end | |||
# | |||
# Used on the reviews listing page (http://localhost:9000/project_reviews) | |||
# Prints a label for the given parameter that is used to filter the review list. | |||
@@ -871,4 +838,70 @@ module ApplicationHelper | |||
html | |||
end | |||
# Add a <tfoot> section to a table with pagination details and links. | |||
# Options : | |||
# :id HTML id of the <tfoot> node | |||
# :colspan number of columns in the table | |||
# :include_loading_icon add a hidden loading icon, only if value is true and if the option :id is set as well. The HTML id of the generated icon | |||
# is '<id>_loading' | |||
def paginate_java(pagination, options={}, &block) | |||
total = pagination.total.to_i | |||
page_index = pagination.pageIndex() ? pagination.pageIndex().to_i : 1 | |||
pages = pagination.pages().to_i | |||
html = '<tfoot' | |||
html += " id='#{options[:id]}'" if options[:id] | |||
html += "><tr><td" | |||
html += " colspan='#{options[:colspan]}'" if options[:colspan] | |||
html += '>' | |||
if options[:include_loading_icon] && options[:id] | |||
html += "<img src='#{ApplicationController.root_context}/images/loading-small.gif' style='display: none' id='#{options[:id]}_loading'>" | |||
end | |||
html += '<div' | |||
html += " id='#{options[:id]}_pages'" if options[:id] | |||
html += '>' | |||
html += message('x_results', :params => [total]) if total>0 | |||
if pages > 1 | |||
max_pages = pages | |||
current_page = page_index | |||
start_page = 1 | |||
end_page = max_pages | |||
if max_pages > 20 | |||
if current_page < 12 | |||
start_page = 1 | |||
end_page = 20 | |||
elsif current_page > max_pages-10 | |||
start_page = max_pages-20 | |||
end_page = max_pages | |||
else | |||
start_page = current_page-10 | |||
end_page = current_page+9 | |||
end | |||
end | |||
html += ' | ' | |||
if max_pages > 20 && start_page > 1 | |||
html += (current_page!=1 ? yield(message('paging_first'), 1) : message('paging_first')) | |||
html += ' ' | |||
end | |||
html += (page_index>1 ? yield(message('paging_previous'), current_page-1) : message('paging_previous')) | |||
html += ' ' | |||
for index in start_page..end_page | |||
html += (index != current_page ? yield(index.to_s, index) : index.to_s) | |||
html += ' ' | |||
end | |||
html += (page_index<pages ? yield(message('paging_next'), current_page+1) : message('paging_next')) | |||
html += ' ' | |||
if max_pages > 20 && end_page < max_pages | |||
html += (current_page != max_pages ? yield(message('paging_last'), max_pages) : message('paging_last')) | |||
html += ' ' | |||
end | |||
end | |||
html += '</div></td></tr></tfoot>' | |||
html | |||
end | |||
end |
@@ -0,0 +1,82 @@ | |||
# | |||
# Sonar, entreprise quality control 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. | |||
# | |||
require 'set' | |||
class IssueFilter | |||
CRITERIA_SEPARATOR = '|' | |||
CRITERIA_KEY_VALUE_SEPARATOR = ',' | |||
attr_reader :paging, :issues, :issues_result | |||
def criteria(key=nil) | |||
@criteria ||= HashWithIndifferentAccess.new | |||
if key | |||
@criteria[key] | |||
else | |||
@criteria | |||
end | |||
end | |||
def criteria=(hash) | |||
@criteria = HashWithIndifferentAccess.new | |||
hash.each_pair do |k, v| | |||
set_criteria_value(k, v) | |||
end | |||
end | |||
def override_criteria(hash) | |||
@criteria ||= HashWithIndifferentAccess.new | |||
hash.each_pair do |k, v| | |||
set_criteria_value(k, v) | |||
end | |||
end | |||
# API used by Displays | |||
def set_criteria_value(key, value) | |||
@criteria ||= HashWithIndifferentAccess.new | |||
if key | |||
if value!=nil && value!='' && value!=[''] | |||
value = (value.kind_of?(Array) ? value : value.to_s) | |||
@criteria[key]=value | |||
else | |||
@criteria.delete(key) | |||
end | |||
end | |||
end | |||
def execute | |||
init_results | |||
@issues_result = Api.issues.find(criteria) | |||
@paging = @issues_result.paging | |||
@issues = @issues_result.issues | |||
self | |||
end | |||
private | |||
def init_results | |||
@issues_result = nil | |||
@paging = nil | |||
@issues = nil | |||
criteria['pageSize'] = 25 | |||
self | |||
end | |||
end |
@@ -1,69 +1,85 @@ | |||
<% | |||
if @issues && !@issues.empty? | |||
if @filter.issues && !@filter.issues.empty? | |||
colspan = 8 | |||
%> | |||
<table id="issues-list" class="data width100"> | |||
<thead> | |||
<tr> | |||
<th width="1%" nowrap> | |||
<%= message('status_abbreviated') -%> | |||
</th> | |||
<th width="1%" nowrap> | |||
<%= message('severity_abbreviated') -%> | |||
</th> | |||
<th> | |||
Message | |||
</th> | |||
<th width="1%" nowrap> | |||
Component name | |||
</th> | |||
<th> | |||
<%= message('assignee') -%> | |||
</th> | |||
<th> | |||
Creation date | |||
</th> | |||
</tr> | |||
</thead> | |||
<tfoot> | |||
<tr> | |||
<td colspan="6"> | |||
<%= paginate_java(@paging) -%> | |||
</td> | |||
</tr> | |||
</tfoot> | |||
<tbody> | |||
<% | |||
@issues.each do |issue| | |||
%> | |||
<tr class="<%= cycle('even', 'odd') -%>"> | |||
<td> | |||
<img src="<%= ApplicationController.root_context -%>/images/status/<%= issue.status -%>.png" title="<%= message(issue.status.downcase).capitalize -%>"/> | |||
</td> | |||
<td> | |||
<% if issue.severity %> | |||
<div> | |||
<table class="data width100"> | |||
<thead> | |||
<tr> | |||
<th width="1%" nowrap> | |||
<%= message('severity_abbreviated') -%> | |||
</th> | |||
<th width="1%" nowrap> | |||
<%= message('status_abbreviated') -%> | |||
</th> | |||
<th> | |||
<%= message('description') -%> | |||
</th> | |||
<th width="1%" nowrap> | |||
<%= message('component') -%> | |||
</th> | |||
<th> | |||
<%= message('issue_filter.header.assignee') -%> | |||
</th> | |||
<th> | |||
<%= message('issue_filter.header.action_plan') -%> | |||
</th> | |||
<th> | |||
<%= message('issue_filter.header.creation_date') -%> | |||
</th> | |||
<th> | |||
<%= message('issue_filter.header.update_date') -%> | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<% | |||
@filter.issues.each do |issue| | |||
%> | |||
<tr class="<%= cycle('even', 'odd') -%>"> | |||
<td> | |||
<img src="<%= ApplicationController.root_context -%>/images/priority/<%= issue.severity -%>.png" title="<%= message(issue.severity.downcase).capitalize -%>"/> | |||
<% end %> | |||
</td> | |||
<td> | |||
<%= link_to h(issue.message), :controller => "issue", :action => "view", :id => issue.key -%> | |||
</td> | |||
<td> | |||
<%= h(@issue_results.component(issue).name) -%> | |||
</td> | |||
<td> | |||
<%= @issue_results.user(issue.assignee).name if issue.assignee -%> | |||
</td> | |||
<td> | |||
<%= human_short_date(Api::Utils.java_to_ruby_datetime(issue.creationDate())) -%> | |||
</td> | |||
</tr> | |||
<% | |||
end | |||
%> | |||
</tbody> | |||
</table> | |||
</td> | |||
<td> | |||
<img src="<%= ApplicationController.root_context -%>/images/status/<%= issue.status -%>.png" title="<%= message(issue.status.downcase).capitalize -%>"/> | |||
</td> | |||
<td> | |||
<%= link_to h(issue.message), :controller => 'issue', :action => 'view', :id => issue.key -%> | |||
</td> | |||
<td> | |||
<%= h @filter.issues_result.component(issue).name -%> | |||
</td> | |||
<td> | |||
<%= h @filter.issues_result.user(issue.assignee).name if issue.assignee -%> | |||
</td> | |||
<td> | |||
<%= h @filter.issues_result.actionPlan(issue).name if issue.actionPlanKey() -%> | |||
</td> | |||
<td> | |||
<%= human_short_date(Api::Utils.java_to_ruby_datetime(issue.creationDate())) -%> | |||
</td> | |||
<td> | |||
<%= human_short_date(Api::Utils.java_to_ruby_datetime(issue.updateDate())) -%> | |||
</td> | |||
</tr> | |||
<% | |||
end | |||
%> | |||
<% if @filter.issues.empty? %> | |||
<tr class="even"> | |||
<td colspan="<%= colspan -%>"><%= message 'no_data' -%></td> | |||
</tr> | |||
<% end %> | |||
</tbody> | |||
<%= paginate_java(@filter.paging, :colspan => colspan, :include_loading_icon => true) { |label, page_id| | |||
link_to(label, @filter.criteria.merge({:pageIndex => page_id})) | |||
} -%> | |||
</table> | |||
</div> | |||
<% | |||
elsif @issues | |||
elsif @filter.issues | |||
%> | |||
<p><%= message('no_results') -%></p> | |||
<% |
@@ -0,0 +1,17 @@ | |||
<ul class="sidebar gray-sidebar"> | |||
<form method="GET" action="<%= ApplicationController.root_context -%>/issues/search" > | |||
<li class="sidebar-title"> | |||
<%= message('issue_filter.new_search') -%> | |||
</li> | |||
<li id="criteria-severity" class="marginbottom5"> | |||
<%= message 'issue_filter.criteria.severities' -%>: | |||
<%= dropdown_tag 'severities[]', options_for_select(RulesConfigurationController::RULE_PRIORITIES, @filter.criteria('severities')), | |||
{:width => '100%', :placeholder => message('issue_filter.criteria.severities')}, | |||
{:id => 'select-severities', :multiple => true}-%> | |||
</li> | |||
<li> | |||
<input type="submit" name="search" value="<%= message('search_verb') -%>" id="search-button" /> | |||
<a href="<%= ApplicationController.root_context -%>/issues" class="link-action"><%= message 'issue_filter.new_search' -%></a> | |||
</li> | |||
</form> | |||
</ul> |
@@ -1,5 +0,0 @@ | |||
<div id="reviews-search"> | |||
<div id="content"> | |||
<%= render :partial => "list" -%> | |||
</div> | |||
</div> |
@@ -0,0 +1,13 @@ | |||
<div xmlns="http://www.w3.org/1999/html"> | |||
<div class="page-split-left"> | |||
<%= render :partial => 'issues/sidebar' -%> | |||
</div> | |||
<div class="page-split-right"> | |||
<div id="content"> | |||
<div class="marginbottom10"> | |||
<%= render :partial => 'list' -%> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |