##// END OF EJS Templates
Makes spent time queries savable (#14790)....
Jean-Philippe Lang -
r15257:beb5e6039166
parent child
Show More
@@ -60,7 +60,7 class QueriesController < ApplicationController
60
60
61 if @query.save
61 if @query.save
62 flash[:notice] = l(:notice_successful_create)
62 flash[:notice] = l(:notice_successful_create)
63 redirect_to_issues(:query_id => @query)
63 redirect_to_items(:query_id => @query)
64 else
64 else
65 render :action => 'new', :layout => !request.xhr?
65 render :action => 'new', :layout => !request.xhr?
66 end
66 end
@@ -74,7 +74,7 class QueriesController < ApplicationController
74
74
75 if @query.save
75 if @query.save
76 flash[:notice] = l(:notice_successful_update)
76 flash[:notice] = l(:notice_successful_update)
77 redirect_to_issues(:query_id => @query)
77 redirect_to_items(:query_id => @query)
78 else
78 else
79 render :action => 'edit'
79 render :action => 'edit'
80 end
80 end
@@ -82,7 +82,7 class QueriesController < ApplicationController
82
82
83 def destroy
83 def destroy
84 @query.destroy
84 @query.destroy
85 redirect_to_issues(:set_filter => 1)
85 redirect_to_items(:set_filter => 1)
86 end
86 end
87
87
88 private
88 private
@@ -117,7 +117,12 class QueriesController < ApplicationController
117 @query
117 @query
118 end
118 end
119
119
120 def redirect_to_issues(options)
120 def redirect_to_items(options)
121 method = "redirect_to_#{@query.class.name.underscore}"
122 send method, options
123 end
124
125 def redirect_to_issue_query(options)
121 if params[:gantt]
126 if params[:gantt]
122 if @project
127 if @project
123 redirect_to project_gantt_path(@project, options)
128 redirect_to project_gantt_path(@project, options)
@@ -129,6 +134,10 class QueriesController < ApplicationController
129 end
134 end
130 end
135 end
131
136
137 def redirect_to_time_entry_query(options)
138 redirect_to _time_entries_path(@project, nil, options)
139 end
140
132 # Returns the Query subclass, IssueQuery by default
141 # Returns the Query subclass, IssueQuery by default
133 # for compatibility with previous behaviour
142 # for compatibility with previous behaviour
134 def query_class
143 def query_class
@@ -40,8 +40,7 class TimelogController < ApplicationController
40 include QueriesHelper
40 include QueriesHelper
41
41
42 def index
42 def index
43 @query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_')
43 retrieve_time_entry_query
44
45 sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria)
44 sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria)
46 sort_update(@query.sortable_columns)
45 sort_update(@query.sortable_columns)
47 scope = time_entry_scope(:order => sort_clause).
46 scope = time_entry_scope(:order => sort_clause).
@@ -75,7 +74,7 class TimelogController < ApplicationController
75 end
74 end
76
75
77 def report
76 def report
78 @query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_')
77 retrieve_time_entry_query
79 scope = time_entry_scope
78 scope = time_entry_scope
80
79
81 @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope)
80 @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope)
@@ -271,4 +270,8 private
271 end
270 end
272 scope
271 scope
273 end
272 end
273
274 def retrieve_time_entry_query
275 retrieve_query(TimeEntryQuery, false)
276 end
274 end
277 end
@@ -204,26 +204,27 module QueriesHelper
204 end
204 end
205
205
206 # Retrieve query from session or build a new query
206 # Retrieve query from session or build a new query
207 def retrieve_query
207 def retrieve_query(klass=IssueQuery, use_session=true)
208 if !params[:query_id].blank?
208 session_key = klass.name.underscore.to_sym
209
210 if params[:query_id].present?
209 cond = "project_id IS NULL"
211 cond = "project_id IS NULL"
210 cond << " OR project_id = #{@project.id}" if @project
212 cond << " OR project_id = #{@project.id}" if @project
211 @query = IssueQuery.where(cond).find(params[:query_id])
213 @query = klass.where(cond).find(params[:query_id])
212 raise ::Unauthorized unless @query.visible?
214 raise ::Unauthorized unless @query.visible?
213 @query.project = @project
215 @query.project = @project
214 session[:query] = {:id => @query.id, :project_id => @query.project_id}
216 session[session_key] = {:id => @query.id, :project_id => @query.project_id} if use_session
215 sort_clear
217 sort_clear
216 elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
218 elsif api_request? || params[:set_filter] || !use_session || session[session_key].nil? || session[session_key][:project_id] != (@project ? @project.id : nil)
217 # Give it a name, required to be valid
219 # Give it a name, required to be valid
218 @query = IssueQuery.new(:name => "_")
220 @query = klass.new(:name => "_", :project => @project)
219 @query.project = @project
220 @query.build_from_params(params)
221 @query.build_from_params(params)
221 session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names, :totalable_names => @query.totalable_names}
222 session[session_key] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names, :totalable_names => @query.totalable_names} if use_session
222 else
223 else
223 # retrieve from session
224 # retrieve from session
224 @query = nil
225 @query = nil
225 @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
226 @query = klass.find_by_id(session[session_key][:id]) if session[session_key][:id]
226 @query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names], :totalable_names => session[:query][:totalable_names])
227 @query ||= klass.new(:name => "_", :filters => session[session_key][:filters], :group_by => session[session_key][:group_by], :column_names => session[session_key][:column_names], :totalable_names => session[session_key][:totalable_names])
227 @query.project = @project
228 @query.project = @project
228 end
229 end
229 end
230 end
@@ -1,6 +1,7
1 <h2><%= l(:label_query_new) %></h2>
1 <h2><%= l(:label_query_new) %></h2>
2
2
3 <%= form_tag(@project ? project_queries_path(@project) : queries_path, :id => "query-form") do %>
3 <%= form_tag(@project ? project_queries_path(@project) : queries_path, :id => "query-form") do %>
4 <%= hidden_field_tag 'type', @query.class.name %>
4 <%= render :partial => 'form', :locals => {:query => @query} %>
5 <%= render :partial => 'form', :locals => {:query => @query} %>
5 <%= submit_tag l(:button_save) %>
6 <%= submit_tag l(:button_save) %>
6 <% end %>
7 <% end %>
@@ -1,4 +1,5
1 <div id="query_form_with_buttons" class="hide-when-print">
1 <div id="query_form_with_buttons" class="hide-when-print">
2 <%= hidden_field_tag 'set_filter', '1' %>
2 <div id="query_form_content">
3 <div id="query_form_content">
3 <fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
4 <fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
4 <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
5 <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
@@ -22,11 +23,25
22 <p class="buttons">
23 <p class="buttons">
23 <%= link_to_function l(:button_apply), '$("#query_form").submit()', :class => 'icon icon-checked' %>
24 <%= link_to_function l(:button_apply), '$("#query_form").submit()', :class => 'icon icon-checked' %>
24 <%= link_to l(:button_clear), {:project_id => @project, :issue_id => @issue}, :class => 'icon icon-reload' %>
25 <%= link_to l(:button_clear), {:project_id => @project, :issue_id => @issue}, :class => 'icon icon-reload' %>
26 <% if @query.new_record? %>
27 <% if User.current.allowed_to?(:save_queries, @project, :global => true) %>
28 <%= link_to_function l(:button_save),
29 "$('#query_form').attr('action', '#{ @project ? new_project_query_path(@project) : new_query_path }').submit()",
30 :class => 'icon icon-save' %>
31 <% end %>
32 <% else %>
33 <% if @query.editable_by?(User.current) %>
34 <%= link_to l(:button_edit), edit_query_path(@query), :class => 'icon icon-edit' %>
35 <%= delete_link query_path(@query) %>
36 <% end %>
37 <% end %>
25 </p>
38 </p>
39
40 <%= hidden_field_tag 'type', 'TimeEntryQuery' %>
26 </div>
41 </div>
27
42
28 <div class="tabs hide-when-print">
43 <div class="tabs hide-when-print">
29 <% query_params = params.slice(:f, :op, :v, :sort) %>
44 <% query_params = params.slice(:f, :op, :v, :sort, :query_id) %>
30 <ul>
45 <ul>
31 <li><%= link_to(l(:label_details), _time_entries_path(@project, @issue, query_params),
46 <li><%= link_to(l(:label_details), _time_entries_path(@project, @issue, query_params),
32 :class => (action_name == 'index' ? 'selected' : nil)) %></li>
47 :class => (action_name == 'index' ? 'selected' : nil)) %></li>
@@ -6,7 +6,7
6
6
7 <%= render_timelog_breadcrumb %>
7 <%= render_timelog_breadcrumb %>
8
8
9 <h2><%= l(:label_spent_time) %></h2>
9 <h2><%= @query.new_record? ? l(:label_spent_time) : @query.name %></h2>
10
10
11 <%= form_tag(params.slice(:project_id, :issue_id), :method => :get, :id => 'query_form') do %>
11 <%= form_tag(params.slice(:project_id, :issue_id), :method => :get, :id => 'query_form') do %>
12 <%= render :partial => 'date_range' %>
12 <%= render :partial => 'date_range' %>
@@ -41,7 +41,7
41 </div>
41 </div>
42 <% end %>
42 <% end %>
43
43
44 <% html_title l(:label_spent_time), l(:label_details) %>
44 <% html_title(@query.new_record? ? l(:label_spent_time) : @query.name, l(:label_details)) %>
45
45
46 <% content_for :header_tags do %>
46 <% content_for :header_tags do %>
47 <%= auto_discovery_link_tag(:atom, {:issue_id => @issue, :format => 'atom', :key => User.current.rss_key}, :title => l(:label_spent_time)) %>
47 <%= auto_discovery_link_tag(:atom, {:issue_id => @issue, :format => 'atom', :key => User.current.rss_key}, :title => l(:label_spent_time)) %>
@@ -6,7 +6,7
6
6
7 <%= render_timelog_breadcrumb %>
7 <%= render_timelog_breadcrumb %>
8
8
9 <h2><%= l(:label_spent_time) %></h2>
9 <h2><%= @query.new_record? ? l(:label_spent_time) : @query.name %></h2>
10
10
11 <%= form_tag(params.slice(:project_id, :issue_id), :method => :get, :id => 'query_form') do %>
11 <%= form_tag(params.slice(:project_id, :issue_id), :method => :get, :id => 'query_form') do %>
12 <% @report.criteria.each do |criterion| %>
12 <% @report.criteria.each do |criterion| %>
@@ -70,5 +70,5
70 <% end %>
70 <% end %>
71 <% end %>
71 <% end %>
72
72
73 <% html_title l(:label_spent_time), l(:label_report) %>
73 <% html_title(@query.new_record? ? l(:label_spent_time) : @query.name, l(:label_report)) %>
74
74
@@ -806,7 +806,7 module Redmine
806 scope = object.project.shared_versions
806 scope = object.project.shared_versions
807 filtered_versions_options(custom_field, scope, all_statuses)
807 filtered_versions_options(custom_field, scope, all_statuses)
808 elsif object.nil?
808 elsif object.nil?
809 scope = Version.visible.where(:sharing => 'system')
809 scope = ::Version.visible.where(:sharing => 'system')
810 filtered_versions_options(custom_field, scope, all_statuses)
810 filtered_versions_options(custom_field, scope, all_statuses)
811 else
811 else
812 []
812 []
@@ -399,9 +399,9 class IssuesControllerTest < ActionController::TestCase
399 def test_index_with_query_id_and_project_id_should_set_session_query
399 def test_index_with_query_id_and_project_id_should_set_session_query
400 get :index, :project_id => 1, :query_id => 4
400 get :index, :project_id => 1, :query_id => 4
401 assert_response :success
401 assert_response :success
402 assert_kind_of Hash, session[:query]
402 assert_kind_of Hash, session[:issue_query]
403 assert_equal 4, session[:query][:id]
403 assert_equal 4, session[:issue_query][:id]
404 assert_equal 1, session[:query][:project_id]
404 assert_equal 1, session[:issue_query][:project_id]
405 end
405 end
406
406
407 def test_index_with_invalid_query_id_should_respond_404
407 def test_index_with_invalid_query_id_should_respond_404
@@ -411,7 +411,7 class IssuesControllerTest < ActionController::TestCase
411
411
412 def test_index_with_cross_project_query_in_session_should_show_project_issues
412 def test_index_with_cross_project_query_in_session_should_show_project_issues
413 q = IssueQuery.create!(:name => "test", :user_id => 2, :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
413 q = IssueQuery.create!(:name => "test", :user_id => 2, :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
414 @request.session[:query] = {:id => q.id, :project_id => 1}
414 @request.session[:issue_query] = {:id => q.id, :project_id => 1}
415
415
416 with_settings :display_subprojects_issues => '0' do
416 with_settings :display_subprojects_issues => '0' do
417 get :index, :project_id => 1
417 get :index, :project_id => 1
@@ -832,9 +832,9 class IssuesControllerTest < ActionController::TestCase
832 assert_equal columns, query.column_names.map(&:to_s)
832 assert_equal columns, query.column_names.map(&:to_s)
833
833
834 # columns should be stored in session
834 # columns should be stored in session
835 assert_kind_of Hash, session[:query]
835 assert_kind_of Hash, session[:issue_query]
836 assert_kind_of Array, session[:query][:column_names]
836 assert_kind_of Array, session[:issue_query][:column_names]
837 assert_equal columns, session[:query][:column_names].map(&:to_s)
837 assert_equal columns, session[:issue_query][:column_names].map(&:to_s)
838
838
839 # ensure only these columns are kept in the selected columns list
839 # ensure only these columns are kept in the selected columns list
840 assert_select 'select#selected_columns option' do
840 assert_select 'select#selected_columns option' do
@@ -58,6 +58,13 class QueriesControllerTest < ActionController::TestCase
58 assert_response 404
58 assert_response 404
59 end
59 end
60
60
61 def test_new_time_entry_query
62 @request.session[:user_id] = 2
63 get :new, :project_id => 1, :type => 'TimeEntryQuery'
64 assert_response :success
65 assert_select 'input[name=type][value=?]', 'TimeEntryQuery'
66 end
67
61 def test_create_project_public_query
68 def test_create_project_public_query
62 @request.session[:user_id] = 2
69 @request.session[:user_id] = 2
63 post :create,
70 post :create,
@@ -263,6 +270,26 class QueriesControllerTest < ActionController::TestCase
263 assert_equal Query::VISIBILITY_PUBLIC, query.visibility
270 assert_equal Query::VISIBILITY_PUBLIC, query.visibility
264 end
271 end
265
272
273 def test_create_project_public_time_entry_query
274 @request.session[:user_id] = 2
275
276 q = new_record(TimeEntryQuery) do
277 post :create,
278 :project_id => 'ecookbook',
279 :type => 'TimeEntryQuery',
280 :default_columns => '1',
281 :f => ["spent_on"],
282 :op => {"spent_on" => "="},
283 :v => { "spent_on" => ["2016-07-14"]},
284 :query => {"name" => "test_new_project_public_query", "visibility" => "2"}
285 end
286
287 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => 'ecookbook', :query_id => q.id
288 assert q.is_public?
289 assert q.has_default_columns?
290 assert q.valid?
291 end
292
266 def test_edit_global_public_query
293 def test_edit_global_public_query
267 @request.session[:user_id] = 1
294 @request.session[:user_id] = 1
268 get :edit, :id => 4
295 get :edit, :id => 4
@@ -759,6 +759,16 class TimelogControllerTest < ActionController::TestCase
759 assert_equal values.sort, values
759 assert_equal values.sort, values
760 end
760 end
761
761
762 def test_index_with_query
763 query = TimeEntryQuery.new(:project_id => 1, :name => 'Time Entry Query', :visibility => 2)
764 query.save!
765 @request.session[:user_id] = 2
766
767 get :index, :project_id => 'ecookbook', :query_id => query.id
768 assert_response :success
769 assert_select 'h2', :text => query.name
770 end
771
762 def test_index_atom_feed
772 def test_index_atom_feed
763 get :index, :project_id => 1, :format => 'atom'
773 get :index, :project_id => 1, :format => 'atom'
764 assert_response :success
774 assert_response :success
General Comments 0
You need to be logged in to leave comments. Login now