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
|
class IssuesController < ApplicationController
|
||||||
layout 'base', :except => :export_pdf
|
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 ]
|
cache_sweeper :issue_sweeper, :only => [ :edit, :change_status, :destroy ]
|
||||||
|
|
||||||
@ -32,8 +32,27 @@ class IssuesController < ApplicationController
|
|||||||
helper :watchers
|
helper :watchers
|
||||||
include WatchersHelper
|
include WatchersHelper
|
||||||
helper :attachments
|
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
|
def show
|
||||||
@status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
|
@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)
|
@custom_values = @issue.custom_values.find(:all, :include => :custom_field)
|
||||||
@ -149,5 +168,25 @@ private
|
|||||||
@html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}"
|
@html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}"
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render_404
|
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
|
end
|
||||||
|
@ -77,11 +77,11 @@ class Project < ActiveRecord::Base
|
|||||||
|
|
||||||
def self.visible_by(user=nil)
|
def self.visible_by(user=nil)
|
||||||
if user && user.admin?
|
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?
|
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
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -91,14 +91,20 @@ class Query < ActiveRecord::Base
|
|||||||
"updated_on" => { :type => :date_past, :order => 10 },
|
"updated_on" => { :type => :date_past, :order => 10 },
|
||||||
"start_date" => { :type => :date, :order => 11 },
|
"start_date" => { :type => :date, :order => 11 },
|
||||||
"due_date" => { :type => :date, :order => 12 } }
|
"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 << ["<< #{l(:label_me)} >>", "me"] if executed_by
|
||||||
user_values += @project.users.collect{|s| [s.name, s.id.to_s] }
|
# members of the user's projects
|
||||||
|
user_values += executed_by.projects.collect(&:users).flatten.uniq.sort.collect{|s| [s.name, s.id.to_s] }
|
||||||
@available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values }
|
end
|
||||||
@available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values }
|
@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["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] } }
|
@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?
|
unless @project.active_children.empty?
|
||||||
@ -166,7 +172,7 @@ class Query < ActiveRecord::Base
|
|||||||
def statement
|
def statement
|
||||||
# project/subprojects clause
|
# project/subprojects clause
|
||||||
clause = ''
|
clause = ''
|
||||||
if has_filter?("subproject_id")
|
if project && has_filter?("subproject_id")
|
||||||
subproject_ids = []
|
subproject_ids = []
|
||||||
if operator_for("subproject_id") == "="
|
if operator_for("subproject_id") == "="
|
||||||
subproject_ids = values_for("subproject_id").each(&:to_i)
|
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}
|
subproject_ids = project.active_children.collect{|p| p.id}
|
||||||
end
|
end
|
||||||
clause << "#{Issue.table_name}.project_id IN (%d,%s)" % [project.id, subproject_ids.join(",")] if project
|
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
|
else
|
||||||
clause << "#{Issue.table_name}.project_id=%d" % project.id if project
|
clause << Project.visible_by(executed_by)
|
||||||
end
|
end
|
||||||
|
|
||||||
# filters clauses
|
# filters clauses
|
||||||
@ -239,7 +247,8 @@ class Query < ActiveRecord::Base
|
|||||||
filters_clauses << sql
|
filters_clauses << sql
|
||||||
end if filters and valid?
|
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
|
clause
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
55
app/views/issues/index.rhtml
Normal file
55
app/views/issues/index.rhtml
Normal file
@ -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],
|
:conditions => ["assigned_to_id=? AND #{IssueStatus.table_name}.is_closed=? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id, false],
|
||||||
:limit => 10,
|
:limit => 10,
|
||||||
:include => [ :status, :project, :tracker ],
|
: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 } %>
|
<%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %>
|
||||||
<% if assigned_issues.length > 0 %>
|
<% 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 %>
|
<% end %>
|
||||||
|
@ -6,5 +6,5 @@
|
|||||||
:order => "#{Issue.table_name}.updated_on DESC") %>
|
:order => "#{Issue.table_name}.updated_on DESC") %>
|
||||||
<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %>
|
<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %>
|
||||||
<% if reported_issues.length > 0 %>
|
<% if reported_issues.length > 0 %>
|
||||||
<p><%=lwr(:label_last_updates, reported_issues.length)%></p>
|
<p class="small"><%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :set_filter => 1, :author_id => 'me' %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -22,6 +22,8 @@ require 'my_controller'
|
|||||||
class MyController; def rescue_action(e) raise e end; end
|
class MyController; def rescue_action(e) raise e end; end
|
||||||
|
|
||||||
class MyControllerTest < Test::Unit::TestCase
|
class MyControllerTest < Test::Unit::TestCase
|
||||||
|
fixtures :users
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@controller = MyController.new
|
@controller = MyController.new
|
||||||
@request = ActionController::TestRequest.new
|
@request = ActionController::TestRequest.new
|
||||||
@ -50,8 +52,7 @@ class MyControllerTest < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_update_account
|
def test_update_account
|
||||||
post :account, :user => {:firstname => "Joe", :login => "root", :admin => 1}
|
post :account, :user => {:firstname => "Joe", :login => "root", :admin => 1}
|
||||||
assert_response :success
|
assert_redirected_to 'my/account'
|
||||||
assert_template 'account'
|
|
||||||
user = User.find(2)
|
user = User.find(2)
|
||||||
assert_equal user, assigns(:user)
|
assert_equal user, assigns(:user)
|
||||||
assert_equal "Joe", user.firstname
|
assert_equal "Joe", user.firstname
|
||||||
|
Loading…
x
Reference in New Issue
Block a user