##// END OF EJS Templates
Remove special behaviour for listing issue time entries, use a filter for that....
Jean-Philippe Lang -
r15262:03dbf8abb881
parent child
Show More
@@ -22,7 +22,8 class TimelogController < ApplicationController
22 before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
22 before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
23 before_filter :authorize, :only => [:show, :edit, :update, :bulk_edit, :bulk_update, :destroy]
23 before_filter :authorize, :only => [:show, :edit, :update, :bulk_edit, :bulk_update, :destroy]
24
24
25 before_filter :find_optional_project, :only => [:new, :create, :index, :report]
25 before_filter :find_optional_issue, :only => [:new, :create]
26 before_filter :find_optional_project, :only => [:index, :report]
26 before_filter :authorize_global, :only => [:new, :create, :index, :report]
27 before_filter :authorize_global, :only => [:new, :create, :index, :report]
27
28
28 accept_rss_auth :index
29 accept_rss_auth :index
@@ -251,11 +252,17 private
251 end
252 end
252 end
253 end
253
254
254 def find_optional_project
255 def find_optional_issue
255 if params[:issue_id].present?
256 if params[:issue_id].present?
256 @issue = Issue.find(params[:issue_id])
257 @issue = Issue.find(params[:issue_id])
257 @project = @issue.project
258 @project = @issue.project
258 elsif params[:project_id].present?
259 else
260 find_optional_project
261 end
262 end
263
264 def find_optional_project
265 if params[:project_id].present?
259 @project = Project.find(params[:project_id])
266 @project = Project.find(params[:project_id])
260 end
267 end
261 rescue ActiveRecord::RecordNotFound
268 rescue ActiveRecord::RecordNotFound
@@ -264,11 +271,7 private
264
271
265 # Returns the TimeEntry scope for index and report actions
272 # Returns the TimeEntry scope for index and report actions
266 def time_entry_scope(options={})
273 def time_entry_scope(options={})
267 scope = @query.results_scope(options)
274 @query.results_scope(options)
268 if @issue
269 scope = scope.on_issue(@issue)
270 end
271 scope
272 end
275 end
273
276
274 def retrieve_time_entry_query
277 def retrieve_time_entry_query
@@ -135,11 +135,13 module IssuesHelper
135
135
136 def issue_spent_hours_details(issue)
136 def issue_spent_hours_details(issue)
137 if issue.total_spent_hours > 0
137 if issue.total_spent_hours > 0
138 path = project_time_entries_path(issue.project, :issue_id => "~#{issue.id}")
139
138 if issue.total_spent_hours == issue.spent_hours
140 if issue.total_spent_hours == issue.spent_hours
139 link_to(l_hours_short(issue.spent_hours), issue_time_entries_path(issue))
141 link_to(l_hours_short(issue.spent_hours), path)
140 else
142 else
141 s = issue.spent_hours > 0 ? l_hours_short(issue.spent_hours) : ""
143 s = issue.spent_hours > 0 ? l_hours_short(issue.spent_hours) : ""
142 s << " (#{l(:label_total)}: #{link_to l_hours_short(issue.total_spent_hours), issue_time_entries_path(issue)})"
144 s << " (#{l(:label_total)}: #{link_to l_hours_short(issue.total_spent_hours), path})"
143 s.html_safe
145 s.html_safe
144 end
146 end
145 end
147 end
@@ -24,8 +24,10 module QueriesHelper
24 ungrouped = []
24 ungrouped = []
25 grouped = {}
25 grouped = {}
26 query.available_filters.map do |field, field_options|
26 query.available_filters.map do |field, field_options|
27 if [:tree, :relation].include?(field_options[:type])
27 if field_options[:type] == :relation
28 group = :label_relations
28 group = :label_relations
29 elsif field_options[:type] == :tree
30 group = query.is_a?(IssueQuery) ? :label_relations : nil
29 elsif field =~ /^(.+)\./
31 elsif field =~ /^(.+)\./
30 # association filters
32 # association filters
31 group = "field_#{$1}"
33 group = "field_#{$1}"
@@ -54,9 +54,7 module RoutesHelper
54 end
54 end
55
55
56 def _time_entries_path(project, issue, *args)
56 def _time_entries_path(project, issue, *args)
57 if issue
57 if project
58 issue_time_entries_path(issue, *args)
59 elsif project
60 project_time_entries_path(project, *args)
58 project_time_entries_path(project, *args)
61 else
59 else
62 time_entries_path(*args)
60 time_entries_path(*args)
@@ -64,9 +62,7 module RoutesHelper
64 end
62 end
65
63
66 def _report_time_entries_path(project, issue, *args)
64 def _report_time_entries_path(project, issue, *args)
67 if issue
65 if project
68 report_issue_time_entries_path(issue, *args)
69 elsif project
70 report_project_time_entries_path(project, *args)
66 report_project_time_entries_path(project, *args)
71 else
67 else
72 report_time_entries_path(*args)
68 report_time_entries_path(*args)
@@ -20,20 +20,6
20 module TimelogHelper
20 module TimelogHelper
21 include ApplicationHelper
21 include ApplicationHelper
22
22
23 def render_timelog_breadcrumb
24 links = []
25 links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil})
26 links << link_to(h(@project), {:project_id => @project, :issue_id => nil}) if @project
27 if @issue
28 if @issue.visible?
29 links << link_to_issue(@issue, :subject => false)
30 else
31 links << "##{@issue.id}"
32 end
33 end
34 breadcrumb links
35 end
36
37 # Returns a collection of activities for a select field. time_entry
23 # Returns a collection of activities for a select field. time_entry
38 # is optional and will be used to check if the selected TimeEntryActivity
24 # is optional and will be used to check if the selected TimeEntryActivity
39 # is active.
25 # is active.
@@ -460,7 +460,7 class Query < ActiveRecord::Base
460 next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/
460 next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/
461 values = $1
461 values = $1
462 add_filter field, operator, values.present? ? values.split('|') : ['']
462 add_filter field, operator, values.present? ? values.split('|') : ['']
463 end || add_filter(field, '=', expression.split('|'))
463 end || add_filter(field, '=', expression.to_s.split('|'))
464 end
464 end
465
465
466 # Add multiple filters using +add_filter+
466 # Add multiple filters using +add_filter+
@@ -67,6 +67,9 class TimeEntryQuery < Query
67 ) unless project_values.empty?
67 ) unless project_values.empty?
68 end
68 end
69 end
69 end
70
71 add_available_filter("issue_id", :type => :tree, :label => :label_issue)
72
70 principals.uniq!
73 principals.uniq!
71 principals.sort!
74 principals.sort!
72 users = principals.select {|p| p.is_a?(User)}
75 users = principals.select {|p| p.is_a?(User)}
@@ -114,6 +117,24 class TimeEntryQuery < Query
114 includes(:activity).
117 includes(:activity).
115 references(:activity)
118 references(:activity)
116 end
119 end
120
121 def sql_for_issue_id_field(field, operator, value)
122 case operator
123 when "="
124 "#{TimeEntry.table_name}.issue_id = #{value.first.to_i}"
125 when "~"
126 issue = Issue.where(:id => value.first.to_i).first
127 if issue && (issue_ids = issue.self_and_descendants.pluck(:id)).any?
128 "#{TimeEntry.table_name}.issue_id IN (#{issue_ids.join(',')})"
129 else
130 "1=0"
131 end
132 when "!*"
133 "#{TimeEntry.table_name}.issue_id IS NULL"
134 when "*"
135 "#{TimeEntry.table_name}.issue_id IS NOT NULL"
136 end
137 end
117
138
118 def sql_for_activity_id_field(field, operator, value)
139 def sql_for_activity_id_field(field, operator, value)
119 condition_on_id = sql_for_field(field, operator, value, Enumeration.table_name, 'id')
140 condition_on_id = sql_for_field(field, operator, value, Enumeration.table_name, 'id')
@@ -41,11 +41,11
41 </div>
41 </div>
42
42
43 <div class="tabs hide-when-print">
43 <div class="tabs hide-when-print">
44 <% query_params = params.slice(:f, :op, :v, :sort, :query_id) %>
44 <% query_params = request.query_parameters %>
45 <ul>
45 <ul>
46 <li><%= link_to(l(:label_details), _time_entries_path(@project, @issue, query_params),
46 <li><%= link_to(l(:label_details), _time_entries_path(@project, nil, :params => query_params),
47 :class => (action_name == 'index' ? 'selected' : nil)) %></li>
47 :class => (action_name == 'index' ? 'selected' : nil)) %></li>
48 <li><%= link_to(l(:label_report), _report_time_entries_path(@project, @issue, query_params),
48 <li><%= link_to(l(:label_report), _report_time_entries_path(@project, nil, :params => query_params),
49 :class => (action_name == 'report' ? 'selected' : nil)) %></li>
49 :class => (action_name == 'report' ? 'selected' : nil)) %></li>
50 </ul>
50 </ul>
51 </div>
51 </div>
@@ -4,11 +4,9
4 :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project, :global => true) %>
4 :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project, :global => true) %>
5 </div>
5 </div>
6
6
7 <%= render_timelog_breadcrumb %>
8
9 <h2><%= @query.new_record? ? l(:label_spent_time) : @query.name %></h2>
7 <h2><%= @query.new_record? ? l(:label_spent_time) : @query.name %></h2>
10
8
11 <%= form_tag(params.slice(:project_id, :issue_id), :method => :get, :id => 'query_form') do %>
9 <%= form_tag(_time_entries_path(@project, nil), :method => :get, :id => 'query_form') do %>
12 <%= render :partial => 'date_range' %>
10 <%= render :partial => 'date_range' %>
13 <% end %>
11 <% end %>
14
12
@@ -4,11 +4,9
4 :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project, :global => true) %>
4 :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project, :global => true) %>
5 </div>
5 </div>
6
6
7 <%= render_timelog_breadcrumb %>
8
9 <h2><%= @query.new_record? ? l(:label_spent_time) : @query.name %></h2>
7 <h2><%= @query.new_record? ? l(:label_spent_time) : @query.name %></h2>
10
8
11 <%= form_tag(params.slice(:project_id, :issue_id), :method => :get, :id => 'query_form') do %>
9 <%= form_tag(_report_time_entries_path(@project, nil), :method => :get, :id => 'query_form') do %>
12 <% @report.criteria.each do |criterion| %>
10 <% @report.criteria.each do |criterion| %>
13 <%= hidden_field_tag 'criteria[]', criterion, :id => nil %>
11 <%= hidden_field_tag 'criteria[]', criterion, :id => nil %>
14 <% end %>
12 <% end %>
@@ -188,11 +188,7 Rails.application.routes.draw do
188 match 'bulk_edit', :via => [:get, :post]
188 match 'bulk_edit', :via => [:get, :post]
189 post 'bulk_update'
189 post 'bulk_update'
190 end
190 end
191 resources :time_entries, :controller => 'timelog', :except => [:show, :edit, :update, :destroy] do
191 resources :time_entries, :controller => 'timelog', :only => [:new, :create]
192 collection do
193 get 'report'
194 end
195 end
196 shallow do
192 shallow do
197 resources :relations, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
193 resources :relations, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
198 end
194 end
@@ -128,15 +128,6 class TimeEntryReportsControllerTest < ActionController::TestCase
128 assert_equal "4.25", "%.2f" % assigns(:report).total_hours
128 assert_equal "4.25", "%.2f" % assigns(:report).total_hours
129 end
129 end
130
130
131 def test_report_at_issue_level
132 get :report, :issue_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criteria => ["user", "activity"]
133 assert_response :success
134 assert_template 'report'
135 assert_not_nil assigns(:report)
136 assert_equal "154.25", "%.2f" % assigns(:report).total_hours
137 assert_select 'form#query_form[action=?]', '/issues/1/time_entries/report'
138 end
139
140 def test_report_by_week_should_use_commercial_year
131 def test_report_by_week_should_use_commercial_year
141 TimeEntry.delete_all
132 TimeEntry.delete_all
142 TimeEntry.generate!(:hours => '2', :spent_on => '2009-12-25') # 2009-52
133 TimeEntry.generate!(:hours => '2', :spent_on => '2009-12-25') # 2009-52
@@ -676,20 +676,6 class TimelogControllerTest < ActionController::TestCase
676 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
676 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
677 end
677 end
678
678
679 def test_index_at_issue_level
680 get :index, :issue_id => 1
681 assert_response :success
682 assert_template 'index'
683 assert_not_nil assigns(:entries)
684 assert_equal 2, assigns(:entries).size
685 assert_not_nil assigns(:total_hours)
686 assert_equal 154.25, assigns(:total_hours)
687 # display all time
688 assert_nil assigns(:from)
689 assert_nil assigns(:to)
690 assert_select 'form#query_form[action=?]', '/issues/1/time_entries'
691 end
692
693 def test_index_should_sort_by_spent_on_and_created_on
679 def test_index_should_sort_by_spent_on_and_created_on
694 t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10)
680 t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10)
695 t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10)
681 t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10)
@@ -809,15 +795,6 class TimelogControllerTest < ActionController::TestCase
809 end
795 end
810 end
796 end
811
797
812 def test_index_at_issue_level_should_include_csv_export_dialog
813 get :index, :issue_id => 3
814 assert_response :success
815
816 assert_select '#csv-export-options' do
817 assert_select 'form[action=?][method=get]', '/issues/3/time_entries.csv'
818 end
819 end
820
821 def test_index_csv_all_projects
798 def test_index_csv_all_projects
822 with_settings :date_format => '%m/%d/%Y' do
799 with_settings :date_format => '%m/%d/%Y' do
823 get :index, :format => 'csv'
800 get :index, :format => 'csv'
@@ -40,10 +40,7 class RoutingTimelogsTest < Redmine::RoutingTest
40 end
40 end
41
41
42 def test_timelogs_scoped_under_issues
42 def test_timelogs_scoped_under_issues
43 should_route 'GET /issues/234/time_entries' => 'timelog#index', :issue_id => '234'
43 should_route 'GET /issues/234/time_entries/new' => 'timelog#new', :issue_id => '234'
44 should_route 'GET /issues/234/time_entries.csv' => 'timelog#index', :issue_id => '234', :format => 'csv'
45 should_route 'GET /issues/234/time_entries.atom' => 'timelog#index', :issue_id => '234', :format => 'atom'
46 should_route 'GET /issues/234/time_entries/new' => 'timelog#new', :issue_id => '234'
47 should_route 'POST /issues/234/time_entries' => 'timelog#create', :issue_id => '234'
44 should_route 'POST /issues/234/time_entries' => 'timelog#create', :issue_id => '234'
48 end
45 end
49
46
@@ -53,9 +50,6 class RoutingTimelogsTest < Redmine::RoutingTest
53
50
54 should_route 'GET /projects/foo/time_entries/report' => 'timelog#report', :project_id => 'foo'
51 should_route 'GET /projects/foo/time_entries/report' => 'timelog#report', :project_id => 'foo'
55 should_route 'GET /projects/foo/time_entries/report.csv' => 'timelog#report', :project_id => 'foo', :format => 'csv'
52 should_route 'GET /projects/foo/time_entries/report.csv' => 'timelog#report', :project_id => 'foo', :format => 'csv'
56
57 should_route 'GET /issues/234/time_entries/report' => 'timelog#report', :issue_id => '234'
58 should_route 'GET /issues/234/time_entries/report.csv' => 'timelog#report', :issue_id => '234', :format => 'csv'
59 end
53 end
60
54
61 def test_timelogs_bulk_edit
55 def test_timelogs_bulk_edit
@@ -26,15 +26,11 class RoutesHelperTest < ActionView::TestCase
26
26
27 def test_time_entries_path
27 def test_time_entries_path
28 assert_equal '/projects/ecookbook/time_entries', _time_entries_path(Project.find(1), nil)
28 assert_equal '/projects/ecookbook/time_entries', _time_entries_path(Project.find(1), nil)
29 assert_equal '/issues/1/time_entries', _time_entries_path(Project.find(1), Issue.find(1))
30 assert_equal '/issues/1/time_entries', _time_entries_path(nil, Issue.find(1))
31 assert_equal '/time_entries', _time_entries_path(nil, nil)
29 assert_equal '/time_entries', _time_entries_path(nil, nil)
32 end
30 end
33
31
34 def test_report_time_entries_path
32 def test_report_time_entries_path
35 assert_equal '/projects/ecookbook/time_entries/report', _report_time_entries_path(Project.find(1), nil)
33 assert_equal '/projects/ecookbook/time_entries/report', _report_time_entries_path(Project.find(1), nil)
36 assert_equal '/issues/1/time_entries/report', _report_time_entries_path(Project.find(1), Issue.find(1))
37 assert_equal '/issues/1/time_entries/report', _report_time_entries_path(nil, Issue.find(1))
38 assert_equal '/time_entries/report', _report_time_entries_path(nil, nil)
34 assert_equal '/time_entries/report', _report_time_entries_path(nil, nil)
39 end
35 end
40
36
General Comments 0
You need to be logged in to leave comments. Login now