Added a cross-project issue list. It displays the issues of all the projects visible by the user.
The users list available in the filters ('assigned to' / 'created by') is made of the members of all projects the current user belongs to. For now, this view is only accessible from 'My page' ('issues assigned to me' or 'issues reported by me' blocks, to view the full lists) On 'My page', assigned issue are now sorted by priority. git-svn-id: http://redmine.rubyforge.org/svn/trunk@684 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
1187ad96ac
commit
404bfce446
|
@ -17,7 +17,7 @@
|
|||
|
||||
class IssuesController < ApplicationController
|
||||
layout 'base', :except => :export_pdf
|
||||
before_filter :find_project, :authorize
|
||||
before_filter :find_project, :authorize, :except => :index
|
||||
|
||||
cache_sweeper :issue_sweeper, :only => [ :edit, :change_status, :destroy ]
|
||||
|
||||
|
@ -32,8 +32,27 @@ class IssuesController < ApplicationController
|
|||
helper :watchers
|
||||
include WatchersHelper
|
||||
helper :attachments
|
||||
include AttachmentsHelper
|
||||
include AttachmentsHelper
|
||||
helper :queries
|
||||
helper :sort
|
||||
include SortHelper
|
||||
|
||||
def index
|
||||
sort_init "#{Issue.table_name}.id", "desc"
|
||||
sort_update
|
||||
retrieve_query
|
||||
if @query.valid?
|
||||
@issue_count = Issue.count(:include => [:status, :project], :conditions => @query.statement)
|
||||
@issue_pages = Paginator.new self, @issue_count, 25, params['page']
|
||||
@issues = Issue.find :all, :order => sort_clause,
|
||||
:include => [ :assigned_to, :status, :tracker, :project, :priority ],
|
||||
:conditions => @query.statement,
|
||||
:limit => @issue_pages.items_per_page,
|
||||
:offset => @issue_pages.current.offset
|
||||
end
|
||||
render :layout => false if request.xhr?
|
||||
end
|
||||
|
||||
def show
|
||||
@status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
|
||||
@custom_values = @issue.custom_values.find(:all, :include => :custom_field)
|
||||
|
@ -149,5 +168,25 @@ private
|
|||
@html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}"
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
end
|
||||
end
|
||||
|
||||
# Retrieve query from session or build a new query
|
||||
def retrieve_query
|
||||
if params[:set_filter] or !session[:query] or session[:query].project_id
|
||||
# Give it a name, required to be valid
|
||||
@query = Query.new(:name => "_", :executed_by => logged_in_user)
|
||||
if params[:fields] and params[:fields].is_a? Array
|
||||
params[:fields].each do |field|
|
||||
@query.add_filter(field, params[:operators][field], params[:values][field])
|
||||
end
|
||||
else
|
||||
@query.available_filters.keys.each do |field|
|
||||
@query.add_short_filter(field, params[field]) if params[field]
|
||||
end
|
||||
end
|
||||
session[:query] = @query
|
||||
else
|
||||
@query = session[:query]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -77,11 +77,11 @@ class Project < ActiveRecord::Base
|
|||
|
||||
def self.visible_by(user=nil)
|
||||
if user && user.admin?
|
||||
return ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"]
|
||||
return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
|
||||
elsif user && user.memberships.any?
|
||||
return ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND (#{Project.table_name}.is_public = ? or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')}))", true]
|
||||
return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND (#{Project.table_name}.is_public = #{connection.quoted_true} or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')}))"
|
||||
else
|
||||
return ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = ?", true]
|
||||
return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = #{connection.quoted_true}"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -91,14 +91,20 @@ class Query < ActiveRecord::Base
|
|||
"updated_on" => { :type => :date_past, :order => 10 },
|
||||
"start_date" => { :type => :date, :order => 11 },
|
||||
"due_date" => { :type => :date, :order => 12 } }
|
||||
unless project.nil?
|
||||
# project specific filters
|
||||
user_values = []
|
||||
|
||||
user_values = []
|
||||
if project
|
||||
user_values += project.users.collect{|s| [s.name, s.id.to_s] }
|
||||
elsif executed_by
|
||||
user_values << ["<< #{l(:label_me)} >>", "me"] if executed_by
|
||||
user_values += @project.users.collect{|s| [s.name, s.id.to_s] }
|
||||
|
||||
@available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values }
|
||||
@available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values }
|
||||
# members of the user's projects
|
||||
user_values += executed_by.projects.collect(&:users).flatten.uniq.sort.collect{|s| [s.name, s.id.to_s] }
|
||||
end
|
||||
@available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values } unless user_values.empty?
|
||||
@available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values } unless user_values.empty?
|
||||
|
||||
if project
|
||||
# project specific filters
|
||||
@available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
|
||||
@available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } }
|
||||
unless @project.active_children.empty?
|
||||
|
@ -166,7 +172,7 @@ class Query < ActiveRecord::Base
|
|||
def statement
|
||||
# project/subprojects clause
|
||||
clause = ''
|
||||
if has_filter?("subproject_id")
|
||||
if project && has_filter?("subproject_id")
|
||||
subproject_ids = []
|
||||
if operator_for("subproject_id") == "="
|
||||
subproject_ids = values_for("subproject_id").each(&:to_i)
|
||||
|
@ -174,8 +180,10 @@ class Query < ActiveRecord::Base
|
|||
subproject_ids = project.active_children.collect{|p| p.id}
|
||||
end
|
||||
clause << "#{Issue.table_name}.project_id IN (%d,%s)" % [project.id, subproject_ids.join(",")] if project
|
||||
elsif project
|
||||
clause << "#{Issue.table_name}.project_id=%d" % project.id
|
||||
else
|
||||
clause << "#{Issue.table_name}.project_id=%d" % project.id if project
|
||||
clause << Project.visible_by(executed_by)
|
||||
end
|
||||
|
||||
# filters clauses
|
||||
|
@ -239,7 +247,8 @@ class Query < ActiveRecord::Base
|
|||
filters_clauses << sql
|
||||
end if filters and valid?
|
||||
|
||||
clause << (' AND ' + filters_clauses.join(' AND ')) unless filters_clauses.empty?
|
||||
clause << ' AND ' unless clause.empty?
|
||||
clause << filters_clauses.join(' AND ') unless filters_clauses.empty?
|
||||
clause
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<h2><%=l(:label_issue_plural)%></h2>
|
||||
|
||||
<% form_tag({}, :id => 'query_form') do %>
|
||||
<%= render :partial => 'queries/filters', :locals => {:query => @query} %>
|
||||
<% end %>
|
||||
<div class="contextual">
|
||||
<%= link_to_remote l(:button_apply),
|
||||
{ :url => { :set_filter => 1 },
|
||||
:update => "content",
|
||||
:with => "Form.serialize('query_form')"
|
||||
}, :class => 'icon icon-edit' %>
|
||||
|
||||
<%= link_to_remote l(:button_clear),
|
||||
{ :url => { :set_filter => 1 },
|
||||
:update => "content",
|
||||
}, :class => 'icon icon-reload' %>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<%= error_messages_for 'query' %>
|
||||
<% if @query.valid? %>
|
||||
<% if @issues.empty? %>
|
||||
<p><i><%= l(:label_no_data) %></i></p>
|
||||
<% else %>
|
||||
|
||||
<table class="list">
|
||||
<thead><tr>
|
||||
<%= sort_header_tag("#{Issue.table_name}.id", :caption => '#') %>
|
||||
<%= sort_header_tag("#{Project.table_name}.name", :caption => l(:field_project)) %>
|
||||
<%= sort_header_tag("#{Issue.table_name}.tracker_id", :caption => l(:field_tracker)) %>
|
||||
<%= sort_header_tag("#{IssueStatus.table_name}.name", :caption => l(:field_status)) %>
|
||||
<%= sort_header_tag("#{Issue.table_name}.priority_id", :caption => l(:field_priority)) %>
|
||||
<th><%=l(:field_subject)%></th>
|
||||
<%= sort_header_tag("#{User.table_name}.lastname", :caption => l(:field_assigned_to)) %>
|
||||
<%= sort_header_tag("#{Issue.table_name}.updated_on", :caption => l(:field_updated_on)) %>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<% for issue in @issues %>
|
||||
<tr class="<%= cycle("odd", "even") %>">
|
||||
<td align="center" valign="top"><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %></td>
|
||||
<td align="center" valign="top" nowrap><%=h issue.project.name %></td>
|
||||
<td align="center" valign="top" nowrap><%= issue.tracker.name %></td>
|
||||
<td valign="top"nowrap><div class="square" style="background:#<%= issue.status.html_color %>;"></div> <%= issue.status.name %></td>
|
||||
<td align="center" valign="top"><%= issue.priority.name %></td>
|
||||
<td><%= link_to h(issue.subject), :controller => 'issues', :action => 'show', :id => issue %></td>
|
||||
<td align="center" valign="top" nowrap><%= issue.assigned_to.name if issue.assigned_to %></td>
|
||||
<td align="center" valign="top" nowrap><%= format_time(issue.updated_on) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><%= pagination_links_full @issue_pages %>
|
||||
[ <%= @issue_pages.current.first_item %> - <%= @issue_pages.current.last_item %> / <%= @issue_count %> ]</p>
|
||||
<% end %>
|
||||
<% end %>
|
|
@ -3,8 +3,8 @@
|
|||
:conditions => ["assigned_to_id=? AND #{IssueStatus.table_name}.is_closed=? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id, false],
|
||||
:limit => 10,
|
||||
:include => [ :status, :project, :tracker ],
|
||||
:order => "#{Issue.table_name}.updated_on DESC") %>
|
||||
:order => "#{Issue.table_name}.priority_id DESC, #{Issue.table_name}.updated_on DESC") %>
|
||||
<%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %>
|
||||
<% if assigned_issues.length > 0 %>
|
||||
<p><%=lwr(:label_last_updates, assigned_issues.length)%></p>
|
||||
<p class="small"><%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => 'me' %></p>
|
||||
<% end %>
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
:order => "#{Issue.table_name}.updated_on DESC") %>
|
||||
<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %>
|
||||
<% if reported_issues.length > 0 %>
|
||||
<p><%=lwr(:label_last_updates, reported_issues.length)%></p>
|
||||
<% end %>
|
||||
<p class="small"><%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :set_filter => 1, :author_id => 'me' %></p>
|
||||
<% end %>
|
||||
|
|
|
@ -22,6 +22,8 @@ require 'my_controller'
|
|||
class MyController; def rescue_action(e) raise e end; end
|
||||
|
||||
class MyControllerTest < Test::Unit::TestCase
|
||||
fixtures :users
|
||||
|
||||
def setup
|
||||
@controller = MyController.new
|
||||
@request = ActionController::TestRequest.new
|
||||
|
@ -50,8 +52,7 @@ class MyControllerTest < Test::Unit::TestCase
|
|||
|
||||
def test_update_account
|
||||
post :account, :user => {:firstname => "Joe", :login => "root", :admin => 1}
|
||||
assert_response :success
|
||||
assert_template 'account'
|
||||
assert_redirected_to 'my/account'
|
||||
user = User.find(2)
|
||||
assert_equal user, assigns(:user)
|
||||
assert_equal "Joe", user.firstname
|
||||
|
|
Loading…
Reference in New Issue