##// END OF EJS Templates
Added a cross-project issue list. It displays the issues of all the projects visible by the user....
Jean-Philippe Lang -
r673:404bfce44691
parent child
Show More
@@ -0,0 +1,55
1 <h2><%=l(:label_issue_plural)%></h2>
2
3 <% form_tag({}, :id => 'query_form') do %>
4 <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
5 <% end %>
6 <div class="contextual">
7 <%= link_to_remote l(:button_apply),
8 { :url => { :set_filter => 1 },
9 :update => "content",
10 :with => "Form.serialize('query_form')"
11 }, :class => 'icon icon-edit' %>
12
13 <%= link_to_remote l(:button_clear),
14 { :url => { :set_filter => 1 },
15 :update => "content",
16 }, :class => 'icon icon-reload' %>
17 </div>
18 <br />&nbsp;
19
20 <%= error_messages_for 'query' %>
21 <% if @query.valid? %>
22 <% if @issues.empty? %>
23 <p><i><%= l(:label_no_data) %></i></p>
24 <% else %>
25 &nbsp;
26 <table class="list">
27 <thead><tr>
28 <%= sort_header_tag("#{Issue.table_name}.id", :caption => '#') %>
29 <%= sort_header_tag("#{Project.table_name}.name", :caption => l(:field_project)) %>
30 <%= sort_header_tag("#{Issue.table_name}.tracker_id", :caption => l(:field_tracker)) %>
31 <%= sort_header_tag("#{IssueStatus.table_name}.name", :caption => l(:field_status)) %>
32 <%= sort_header_tag("#{Issue.table_name}.priority_id", :caption => l(:field_priority)) %>
33 <th><%=l(:field_subject)%></th>
34 <%= sort_header_tag("#{User.table_name}.lastname", :caption => l(:field_assigned_to)) %>
35 <%= sort_header_tag("#{Issue.table_name}.updated_on", :caption => l(:field_updated_on)) %>
36 </tr></thead>
37 <tbody>
38 <% for issue in @issues %>
39 <tr class="<%= cycle("odd", "even") %>">
40 <td align="center" valign="top"><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %></td>
41 <td align="center" valign="top" nowrap><%=h issue.project.name %></td>
42 <td align="center" valign="top" nowrap><%= issue.tracker.name %></td>
43 <td valign="top"nowrap><div class="square" style="background:#<%= issue.status.html_color %>;"></div> <%= issue.status.name %></td>
44 <td align="center" valign="top"><%= issue.priority.name %></td>
45 <td><%= link_to h(issue.subject), :controller => 'issues', :action => 'show', :id => issue %></td>
46 <td align="center" valign="top" nowrap><%= issue.assigned_to.name if issue.assigned_to %></td>
47 <td align="center" valign="top" nowrap><%= format_time(issue.updated_on) %></td>
48 </tr>
49 <% end %>
50 </tbody>
51 </table>
52 <p><%= pagination_links_full @issue_pages %>
53 [ <%= @issue_pages.current.first_item %> - <%= @issue_pages.current.last_item %> / <%= @issue_count %> ]</p>
54 <% end %>
55 <% end %>
@@ -17,7 +17,7
17
17
18 class IssuesController < ApplicationController
18 class IssuesController < ApplicationController
19 layout 'base', :except => :export_pdf
19 layout 'base', :except => :export_pdf
20 before_filter :find_project, :authorize
20 before_filter :find_project, :authorize, :except => :index
21
21
22 cache_sweeper :issue_sweeper, :only => [ :edit, :change_status, :destroy ]
22 cache_sweeper :issue_sweeper, :only => [ :edit, :change_status, :destroy ]
23
23
@@ -32,8 +32,27 class IssuesController < ApplicationController
32 helper :watchers
32 helper :watchers
33 include WatchersHelper
33 include WatchersHelper
34 helper :attachments
34 helper :attachments
35 include AttachmentsHelper
35 include AttachmentsHelper
36 helper :queries
37 helper :sort
38 include SortHelper
36
39
40 def index
41 sort_init "#{Issue.table_name}.id", "desc"
42 sort_update
43 retrieve_query
44 if @query.valid?
45 @issue_count = Issue.count(:include => [:status, :project], :conditions => @query.statement)
46 @issue_pages = Paginator.new self, @issue_count, 25, params['page']
47 @issues = Issue.find :all, :order => sort_clause,
48 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
49 :conditions => @query.statement,
50 :limit => @issue_pages.items_per_page,
51 :offset => @issue_pages.current.offset
52 end
53 render :layout => false if request.xhr?
54 end
55
37 def show
56 def show
38 @status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
57 @status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
39 @custom_values = @issue.custom_values.find(:all, :include => :custom_field)
58 @custom_values = @issue.custom_values.find(:all, :include => :custom_field)
@@ -149,5 +168,25 private
149 @html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}"
168 @html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}"
150 rescue ActiveRecord::RecordNotFound
169 rescue ActiveRecord::RecordNotFound
151 render_404
170 render_404
152 end
171 end
172
173 # Retrieve query from session or build a new query
174 def retrieve_query
175 if params[:set_filter] or !session[:query] or session[:query].project_id
176 # Give it a name, required to be valid
177 @query = Query.new(:name => "_", :executed_by => logged_in_user)
178 if params[:fields] and params[:fields].is_a? Array
179 params[:fields].each do |field|
180 @query.add_filter(field, params[:operators][field], params[:values][field])
181 end
182 else
183 @query.available_filters.keys.each do |field|
184 @query.add_short_filter(field, params[field]) if params[field]
185 end
186 end
187 session[:query] = @query
188 else
189 @query = session[:query]
190 end
191 end
153 end
192 end
@@ -77,11 +77,11 class Project < ActiveRecord::Base
77
77
78 def self.visible_by(user=nil)
78 def self.visible_by(user=nil)
79 if user && user.admin?
79 if user && user.admin?
80 return ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"]
80 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
81 elsif user && user.memberships.any?
81 elsif user && user.memberships.any?
82 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]
82 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(',')}))"
83 else
83 else
84 return ["#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = ?", true]
84 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = #{connection.quoted_true}"
85 end
85 end
86 end
86 end
87
87
@@ -91,14 +91,20 class Query < ActiveRecord::Base
91 "updated_on" => { :type => :date_past, :order => 10 },
91 "updated_on" => { :type => :date_past, :order => 10 },
92 "start_date" => { :type => :date, :order => 11 },
92 "start_date" => { :type => :date, :order => 11 },
93 "due_date" => { :type => :date, :order => 12 } }
93 "due_date" => { :type => :date, :order => 12 } }
94 unless project.nil?
94
95 # project specific filters
95 user_values = []
96 user_values = []
96 if project
97 user_values += project.users.collect{|s| [s.name, s.id.to_s] }
98 elsif executed_by
97 user_values << ["<< #{l(:label_me)} >>", "me"] if executed_by
99 user_values << ["<< #{l(:label_me)} >>", "me"] if executed_by
98 user_values += @project.users.collect{|s| [s.name, s.id.to_s] }
100 # members of the user's projects
99
101 user_values += executed_by.projects.collect(&:users).flatten.uniq.sort.collect{|s| [s.name, s.id.to_s] }
100 @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values }
102 end
101 @available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values }
103 @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values } unless user_values.empty?
104 @available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values } unless user_values.empty?
105
106 if project
107 # project specific filters
102 @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
108 @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
103 @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } }
109 @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } }
104 unless @project.active_children.empty?
110 unless @project.active_children.empty?
@@ -166,7 +172,7 class Query < ActiveRecord::Base
166 def statement
172 def statement
167 # project/subprojects clause
173 # project/subprojects clause
168 clause = ''
174 clause = ''
169 if has_filter?("subproject_id")
175 if project && has_filter?("subproject_id")
170 subproject_ids = []
176 subproject_ids = []
171 if operator_for("subproject_id") == "="
177 if operator_for("subproject_id") == "="
172 subproject_ids = values_for("subproject_id").each(&:to_i)
178 subproject_ids = values_for("subproject_id").each(&:to_i)
@@ -174,8 +180,10 class Query < ActiveRecord::Base
174 subproject_ids = project.active_children.collect{|p| p.id}
180 subproject_ids = project.active_children.collect{|p| p.id}
175 end
181 end
176 clause << "#{Issue.table_name}.project_id IN (%d,%s)" % [project.id, subproject_ids.join(",")] if project
182 clause << "#{Issue.table_name}.project_id IN (%d,%s)" % [project.id, subproject_ids.join(",")] if project
183 elsif project
184 clause << "#{Issue.table_name}.project_id=%d" % project.id
177 else
185 else
178 clause << "#{Issue.table_name}.project_id=%d" % project.id if project
186 clause << Project.visible_by(executed_by)
179 end
187 end
180
188
181 # filters clauses
189 # filters clauses
@@ -239,7 +247,8 class Query < ActiveRecord::Base
239 filters_clauses << sql
247 filters_clauses << sql
240 end if filters and valid?
248 end if filters and valid?
241
249
242 clause << (' AND ' + filters_clauses.join(' AND ')) unless filters_clauses.empty?
250 clause << ' AND ' unless clause.empty?
251 clause << filters_clauses.join(' AND ') unless filters_clauses.empty?
243 clause
252 clause
244 end
253 end
245 end
254 end
@@ -3,8 +3,8
3 :conditions => ["assigned_to_id=? AND #{IssueStatus.table_name}.is_closed=? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id, false],
3 :conditions => ["assigned_to_id=? AND #{IssueStatus.table_name}.is_closed=? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id, false],
4 :limit => 10,
4 :limit => 10,
5 :include => [ :status, :project, :tracker ],
5 :include => [ :status, :project, :tracker ],
6 :order => "#{Issue.table_name}.updated_on DESC") %>
6 :order => "#{Issue.table_name}.priority_id DESC, #{Issue.table_name}.updated_on DESC") %>
7 <%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %>
7 <%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %>
8 <% if assigned_issues.length > 0 %>
8 <% if assigned_issues.length > 0 %>
9 <p><%=lwr(:label_last_updates, assigned_issues.length)%></p>
9 <p class="small"><%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => 'me' %></p>
10 <% end %>
10 <% end %>
@@ -6,5 +6,5
6 :order => "#{Issue.table_name}.updated_on DESC") %>
6 :order => "#{Issue.table_name}.updated_on DESC") %>
7 <%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %>
7 <%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %>
8 <% if reported_issues.length > 0 %>
8 <% if reported_issues.length > 0 %>
9 <p><%=lwr(:label_last_updates, reported_issues.length)%></p>
9 <p class="small"><%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :set_filter => 1, :author_id => 'me' %></p>
10 <% end %> No newline at end of file
10 <% end %>
@@ -22,6 +22,8 require 'my_controller'
22 class MyController; def rescue_action(e) raise e end; end
22 class MyController; def rescue_action(e) raise e end; end
23
23
24 class MyControllerTest < Test::Unit::TestCase
24 class MyControllerTest < Test::Unit::TestCase
25 fixtures :users
26
25 def setup
27 def setup
26 @controller = MyController.new
28 @controller = MyController.new
27 @request = ActionController::TestRequest.new
29 @request = ActionController::TestRequest.new
@@ -50,8 +52,7 class MyControllerTest < Test::Unit::TestCase
50
52
51 def test_update_account
53 def test_update_account
52 post :account, :user => {:firstname => "Joe", :login => "root", :admin => 1}
54 post :account, :user => {:firstname => "Joe", :login => "root", :admin => 1}
53 assert_response :success
55 assert_redirected_to 'my/account'
54 assert_template 'account'
55 user = User.find(2)
56 user = User.find(2)
56 assert_equal user, assigns(:user)
57 assert_equal user, assigns(:user)
57 assert_equal "Joe", user.firstname
58 assert_equal "Joe", user.firstname
General Comments 0
You need to be logged in to leave comments. Login now