]> source.dussan.org Git - redmine.git/commitdiff
Added a cross-project issue list. It displays the issues of all the projects visible...
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Fri, 31 Aug 2007 17:02:44 +0000 (17:02 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Fri, 31 Aug 2007 17:02:44 +0000 (17:02 +0000)
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

app/controllers/issues_controller.rb
app/models/project.rb
app/models/query.rb
app/views/issues/index.rhtml [new file with mode: 0644]
app/views/my/blocks/_issuesassignedtome.rhtml
app/views/my/blocks/_issuesreportedbyme.rhtml
test/functional/my_controller_test.rb

index 56a9b11ca07fea768a3c981192f7f6a2f55a233a..fe1c78884906529d6dae5d9fbf5300f016007011 100644 (file)
@@ -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
index 241c6581786245e83a90f864987f22276eb3ad32..f994ed6a5d26bff00e131dd85a69ce6f6610d23b 100644 (file)
@@ -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
   
index ff519d71cfda39bc3c7afa94b3c10e884b14a100..c700242ede89c2ad711a415dae86f94b4ffd17aa 100644 (file)
@@ -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
diff --git a/app/views/issues/index.rhtml b/app/views/issues/index.rhtml
new file mode 100644 (file)
index 0000000..0f63ba9
--- /dev/null
@@ -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 />&nbsp;
+
+<%= error_messages_for 'query' %>
+<% if @query.valid? %>
+<% if @issues.empty? %>
+<p><i><%= l(:label_no_data) %></i></p>
+<% else %>
+&nbsp;
+<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 %>
index 0d49279f4b7c4c52b50f81e1595da9c475767426..9b97cb39d499740daabdcda5b627ea0249206747 100644 (file)
@@ -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 %>
index 250e8265dae0ae0ba5f0e65ed36a69ae1c99e699..a0770846c9d2aef419b068858a37d1b1cb768858 100644 (file)
@@ -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 %>
\ No newline at end of file
+<p class="small"><%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :set_filter => 1, :author_id => 'me' %></p>
+<% end %>
index a53991a260aa7cd09f24597cc426d91b3bddcfba..b2389c39b438b2064b82d62bacd4f15970fe4bee 100644 (file)
@@ -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