##// END OF EJS Templates
Don't preload all query filters (#24787)....
Jean-Philippe Lang -
r15788:fd3c08aaa107
parent child
Show More
@@ -17,7 +17,7
17
17
18 class QueriesController < ApplicationController
18 class QueriesController < ApplicationController
19 menu_item :issues
19 menu_item :issues
20 before_action :find_query, :except => [:new, :create, :index]
20 before_action :find_query, :only => [:edit, :update, :destroy]
21 before_action :find_optional_project, :only => [:new, :create]
21 before_action :find_optional_project, :only => [:new, :create]
22
22
23 accept_api_auth :index
23 accept_api_auth :index
@@ -85,6 +85,25 class QueriesController < ApplicationController
85 redirect_to_items(:set_filter => 1)
85 redirect_to_items(:set_filter => 1)
86 end
86 end
87
87
88 # Returns the values for a query filter
89 def filter
90 q = query_class.new
91 if params[:project_id].present?
92 q.project = Project.find(params[:project_id])
93 end
94
95 unless User.current.allowed_to?(q.class.view_permission, q.project, :global => true)
96 raise Unauthorized
97 end
98
99 filter = q.available_filters[params[:name].to_s]
100 values = filter ? filter.values : []
101
102 render :json => values
103 rescue ActiveRecord::RecordNotFound
104 render_404
105 end
106
88 private
107 private
89
108
90 def find_query
109 def find_query
@@ -78,80 +78,37 class IssueQuery < Query
78 end
78 end
79
79
80 def initialize_available_filters
80 def initialize_available_filters
81 principals = []
82 subprojects = []
83 versions = []
84 categories = []
85 issue_custom_fields = []
86
87 if project
88 principals += project.principals.visible
89 unless project.leaf?
90 subprojects = project.descendants.visible.to_a
91 principals += Principal.member_of(subprojects).visible
92 end
93 versions = project.shared_versions.to_a
94 categories = project.issue_categories.to_a
95 issue_custom_fields = project.all_issue_custom_fields
96 else
97 if all_projects.any?
98 principals += Principal.member_of(all_projects).visible
99 end
100 versions = Version.visible.where(:sharing => 'system').to_a
101 issue_custom_fields = IssueCustomField.where(:is_for_all => true)
102 end
103 principals.uniq!
104 principals.sort!
105 principals.reject! {|p| p.is_a?(GroupBuiltin)}
106 users = principals.select {|p| p.is_a?(User)}
107
108 add_available_filter "status_id",
81 add_available_filter "status_id",
109 :type => :list_status, :values => IssueStatus.sorted.collect{|s| [s.name, s.id.to_s] }
82 :type => :list_status, :values => lambda { IssueStatus.sorted.collect{|s| [s.name, s.id.to_s] } }
110
83
111 if project.nil?
84 add_available_filter("project_id",
112 project_values = []
85 :type => :list, :values => lambda { project_values }
113 if User.current.logged? && User.current.memberships.any?
86 ) if project.nil?
114 project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
115 end
116 project_values += all_projects_values
117 add_available_filter("project_id",
118 :type => :list, :values => project_values
119 ) unless project_values.empty?
120 end
121
87
122 add_available_filter "tracker_id",
88 add_available_filter "tracker_id",
123 :type => :list, :values => trackers.collect{|s| [s.name, s.id.to_s] }
89 :type => :list, :values => trackers.collect{|s| [s.name, s.id.to_s] }
90
124 add_available_filter "priority_id",
91 add_available_filter "priority_id",
125 :type => :list, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] }
92 :type => :list, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] }
126
93
127 author_values = []
128 author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
129 author_values += users.collect{|s| [s.name, s.id.to_s] }
130 add_available_filter("author_id",
94 add_available_filter("author_id",
131 :type => :list, :values => author_values
95 :type => :list, :values => lambda { author_values }
132 ) unless author_values.empty?
96 )
133
97
134 assigned_to_values = []
135 assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
136 assigned_to_values += (Setting.issue_group_assignment? ?
137 principals : users).collect{|s| [s.name, s.id.to_s] }
138 add_available_filter("assigned_to_id",
98 add_available_filter("assigned_to_id",
139 :type => :list_optional, :values => assigned_to_values
99 :type => :list_optional, :values => lambda { assigned_to_values }
140 ) unless assigned_to_values.empty?
100 )
141
101
142 group_values = Group.givable.visible.collect {|g| [g.name, g.id.to_s] }
143 add_available_filter("member_of_group",
102 add_available_filter("member_of_group",
144 :type => :list_optional, :values => group_values
103 :type => :list_optional, :values => lambda { Group.givable.visible.collect {|g| [g.name, g.id.to_s] } }
145 ) unless group_values.empty?
104 )
146
105
147 role_values = Role.givable.collect {|r| [r.name, r.id.to_s] }
148 add_available_filter("assigned_to_role",
106 add_available_filter("assigned_to_role",
149 :type => :list_optional, :values => role_values
107 :type => :list_optional, :values => lambda { Role.givable.collect {|r| [r.name, r.id.to_s] } }
150 ) unless role_values.empty?
108 )
151
109
152 add_available_filter "fixed_version_id",
110 add_available_filter "fixed_version_id",
153 :type => :list_optional,
111 :type => :list_optional, :values => lambda { fixed_version_values }
154 :values => Version.sort_by_status(versions).collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s, l("version_status_#{s.status}")] }
155
112
156 add_available_filter "fixed_version.due_date",
113 add_available_filter "fixed_version.due_date",
157 :type => :date,
114 :type => :date,
@@ -164,7 +121,7 class IssueQuery < Query
164
121
165 add_available_filter "category_id",
122 add_available_filter "category_id",
166 :type => :list_optional,
123 :type => :list_optional,
167 :values => categories.collect{|s| [s.name, s.id.to_s] }
124 :values => lambda { project.issue_categories.collect{|s| [s.name, s.id.to_s] } } if project
168
125
169 add_available_filter "subject", :type => :text
126 add_available_filter "subject", :type => :text
170 add_available_filter "description", :type => :text
127 add_available_filter "description", :type => :text
@@ -188,18 +145,20 class IssueQuery < Query
188 :type => :list, :values => [["<< #{l(:label_me)} >>", "me"]]
145 :type => :list, :values => [["<< #{l(:label_me)} >>", "me"]]
189 end
146 end
190
147
191 if subprojects.any?
148 if project && !project.leaf?
192 add_available_filter "subproject_id",
149 add_available_filter "subproject_id",
193 :type => :list_subprojects,
150 :type => :list_subprojects,
194 :values => subprojects.collect{|s| [s.name, s.id.to_s] }
151 :values => lambda { subproject_values }
195 end
152 end
196
153
154
155 issue_custom_fields = project ? project.all_issue_custom_fields : IssueCustomField.where(:is_for_all => true)
197 add_custom_fields_filters(issue_custom_fields)
156 add_custom_fields_filters(issue_custom_fields)
198
157
199 add_associations_custom_fields_filters :project, :author, :assigned_to, :fixed_version
158 add_associations_custom_fields_filters :project, :author, :assigned_to, :fixed_version
200
159
201 IssueRelation::TYPES.each do |relation_type, options|
160 IssueRelation::TYPES.each do |relation_type, options|
202 add_available_filter relation_type, :type => :relation, :label => options[:name]
161 add_available_filter relation_type, :type => :relation, :label => options[:name], :values => lambda {all_projects_values}
203 end
162 end
204 add_available_filter "parent_id", :type => :tree, :label => :field_parent_issue
163 add_available_filter "parent_id", :type => :tree, :label => :field_parent_issue
205 add_available_filter "child_id", :type => :tree, :label => :label_subtask_plural
164 add_available_filter "child_id", :type => :tree, :label => :label_subtask_plural
@@ -160,6 +160,40 class QueryAssociationCustomFieldColumn < QueryCustomFieldColumn
160 end
160 end
161 end
161 end
162
162
163 class QueryFilter
164 include Redmine::I18n
165
166 def initialize(field, options)
167 @field = field.to_s
168 @options = options
169 @options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, ''))
170 # Consider filters with a Proc for values as remote by default
171 @remote = options.key?(:remote) ? options[:remote] : options[:values].is_a?(Proc)
172 end
173
174 def [](arg)
175 if arg == :values
176 values
177 else
178 @options[arg]
179 end
180 end
181
182 def values
183 @values ||= begin
184 values = @options[:values]
185 if values.is_a?(Proc)
186 values = values.call
187 end
188 values
189 end
190 end
191
192 def remote
193 @remote
194 end
195 end
196
163 class Query < ActiveRecord::Base
197 class Query < ActiveRecord::Base
164 class StatementInvalid < ::ActiveRecord::StatementInvalid
198 class StatementInvalid < ::ActiveRecord::StatementInvalid
165 end
199 end
@@ -404,12 +438,17 class Query < ActiveRecord::Base
404 # Returns a representation of the available filters for JSON serialization
438 # Returns a representation of the available filters for JSON serialization
405 def available_filters_as_json
439 def available_filters_as_json
406 json = {}
440 json = {}
407 available_filters.each do |field, options|
441 available_filters.each do |field, filter|
408 options = options.slice(:type, :name, :values)
442 options = {:type => filter[:type], :name => filter[:name]}
409 if options[:values] && values_for(field)
443 options[:remote] = true if filter.remote
410 missing = Array(values_for(field)).select(&:present?) - options[:values].map(&:last)
444
411 if missing.any? && respond_to?(method = "find_#{field}_filter_values")
445 if has_filter?(field) || !filter.remote
412 options[:values] += send(method, missing)
446 options[:values] = filter.values
447 if options[:values] && values_for(field)
448 missing = Array(values_for(field)).select(&:present?) - options[:values].map(&:last)
449 if missing.any? && respond_to?(method = "find_#{field}_filter_values")
450 options[:values] += send(method, missing)
451 end
413 end
452 end
414 end
453 end
415 json[field] = options.stringify_keys
454 json[field] = options.stringify_keys
@@ -432,6 +471,65 class Query < ActiveRecord::Base
432 @all_projects_values = values
471 @all_projects_values = values
433 end
472 end
434
473
474 def project_values
475 project_values = []
476 if User.current.logged? && User.current.memberships.any?
477 project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
478 end
479 project_values += all_projects_values
480 project_values
481 end
482
483 def subproject_values
484 project.descendants.visible.collect{|s| [s.name, s.id.to_s] }
485 end
486
487 def principals
488 @principal ||= begin
489 principals = []
490 if project
491 principals += project.principals.visible
492 unless project.leaf?
493 principals += Principal.member_of(project.descendants.visible).visible
494 end
495 else
496 principals += Principal.member_of(all_projects).visible
497 end
498 principals.uniq!
499 principals.sort!
500 principals.reject! {|p| p.is_a?(GroupBuiltin)}
501 principals
502 end
503 end
504
505 def users
506 principals.select {|p| p.is_a?(User)}
507 end
508
509 def author_values
510 author_values = []
511 author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
512 author_values += users.collect{|s| [s.name, s.id.to_s] }
513 author_values
514 end
515
516 def assigned_to_values
517 assigned_to_values = []
518 assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
519 assigned_to_values += (Setting.issue_group_assignment? ? principals : users).collect{|s| [s.name, s.id.to_s] }
520 assigned_to_values
521 end
522
523 def fixed_version_values
524 versions = []
525 if project
526 versions = project.shared_versions.to_a
527 else
528 versions = Version.visible.where(:sharing => 'system').to_a
529 end
530 Version.sort_by_status(versions).collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s, l("version_status_#{s.status}")] }
531 end
532
435 # Adds available filters
533 # Adds available filters
436 def initialize_available_filters
534 def initialize_available_filters
437 # implemented by sub-classes
535 # implemented by sub-classes
@@ -441,7 +539,7 class Query < ActiveRecord::Base
441 # Adds an available filter
539 # Adds an available filter
442 def add_available_filter(field, options)
540 def add_available_filter(field, options)
443 @available_filters ||= ActiveSupport::OrderedHash.new
541 @available_filters ||= ActiveSupport::OrderedHash.new
444 @available_filters[field] = options
542 @available_filters[field] = QueryFilter.new(field, options)
445 @available_filters
543 @available_filters
446 end
544 end
447
545
@@ -457,9 +555,6 class Query < ActiveRecord::Base
457 unless @available_filters
555 unless @available_filters
458 initialize_available_filters
556 initialize_available_filters
459 @available_filters ||= {}
557 @available_filters ||= {}
460 @available_filters.each do |field, options|
461 options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, ''))
462 end
463 end
558 end
464 @available_filters
559 @available_filters
465 end
560 end
@@ -42,65 +42,38 class TimeEntryQuery < Query
42 def initialize_available_filters
42 def initialize_available_filters
43 add_available_filter "spent_on", :type => :date_past
43 add_available_filter "spent_on", :type => :date_past
44
44
45 principals = []
45 add_available_filter("project_id",
46 versions = []
46 :type => :list, :values => lambda { project_values }
47 if project
47 ) if project.nil?
48 principals += project.principals.visible.sort
48
49 unless project.leaf?
49 if project && !project.leaf?
50 subprojects = project.descendants.visible.to_a
50 add_available_filter "subproject_id",
51 if subprojects.any?
51 :type => :list_subprojects,
52 add_available_filter "subproject_id",
52 :values => lambda { subproject_values }
53 :type => :list_subprojects,
54 :values => subprojects.collect{|s| [s.name, s.id.to_s] }
55 principals += Principal.member_of(subprojects).visible
56 end
57 end
58 versions = project.shared_versions.to_a
59 else
60 if all_projects.any?
61 # members of visible projects
62 principals += Principal.member_of(all_projects).visible
63 # project filter
64 project_values = []
65 if User.current.logged? && User.current.memberships.any?
66 project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
67 end
68 project_values += all_projects_values
69 add_available_filter("project_id",
70 :type => :list, :values => project_values
71 ) unless project_values.empty?
72 end
73 end
53 end
74
54
75 add_available_filter("issue_id", :type => :tree, :label => :label_issue)
55 add_available_filter("issue_id", :type => :tree, :label => :label_issue)
76 add_available_filter("issue.tracker_id",
56 add_available_filter("issue.tracker_id",
77 :type => :list,
57 :type => :list,
78 :name => l("label_attribute_of_issue", :name => l(:field_tracker)),
58 :name => l("label_attribute_of_issue", :name => l(:field_tracker)),
79 :values => Tracker.sorted.map {|t| [t.name, t.id.to_s]})
59 :values => lambda { Tracker.sorted.map {|t| [t.name, t.id.to_s]} })
80 add_available_filter("issue.status_id",
60 add_available_filter("issue.status_id",
81 :type => :list,
61 :type => :list,
82 :name => l("label_attribute_of_issue", :name => l(:field_status)),
62 :name => l("label_attribute_of_issue", :name => l(:field_status)),
83 :values => IssueStatus.sorted.map {|s| [s.name, s.id.to_s]})
63 :values => lambda { IssueStatus.sorted.map {|s| [s.name, s.id.to_s]} })
84 add_available_filter("issue.fixed_version_id",
64 add_available_filter("issue.fixed_version_id",
85 :type => :list,
65 :type => :list,
86 :name => l("label_attribute_of_issue", :name => l(:field_fixed_version)),
66 :name => l("label_attribute_of_issue", :name => l(:field_fixed_version)),
87 :values => Version.sort_by_status(versions).collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s, l("version_status_#{s.status}")] })
67 :values => lambda { fixed_version_values }) if project
88
89 principals.uniq!
90 principals.sort!
91 users = principals.select {|p| p.is_a?(User)}
92
68
93 users_values = []
94 users_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
95 users_values += users.collect{|s| [s.name, s.id.to_s] }
96 add_available_filter("user_id",
69 add_available_filter("user_id",
97 :type => :list_optional, :values => users_values
70 :type => :list_optional, :values => lambda { author_values }
98 ) unless users_values.empty?
71 )
99
72
100 activities = (project ? project.activities : TimeEntryActivity.shared)
73 activities = (project ? project.activities : TimeEntryActivity.shared)
101 add_available_filter("activity_id",
74 add_available_filter("activity_id",
102 :type => :list, :values => activities.map {|a| [a.name, a.id.to_s]}
75 :type => :list, :values => activities.map {|a| [a.name, a.id.to_s]}
103 ) unless activities.empty?
76 )
104
77
105 add_available_filter "comments", :type => :text
78 add_available_filter "comments", :type => :text
106 add_available_filter "hours", :type => :float
79 add_available_filter "hours", :type => :float
@@ -3,7 +3,9 var operatorLabels = <%= raw_json Query.operators_labels %>;
3 var operatorByType = <%= raw_json Query.operators_by_filter_type %>;
3 var operatorByType = <%= raw_json Query.operators_by_filter_type %>;
4 var availableFilters = <%= raw_json query.available_filters_as_json %>;
4 var availableFilters = <%= raw_json query.available_filters_as_json %>;
5 var labelDayPlural = <%= raw_json l(:label_day_plural) %>;
5 var labelDayPlural = <%= raw_json l(:label_day_plural) %>;
6 var allProjects = <%= raw_json query.all_projects_values %>;
6
7 var filtersUrl = <%= raw_json queries_filter_path(:project_id => @query.project.try(:id), :type => @query.type) %>;
8
7 $(document).ready(function(){
9 $(document).ready(function(){
8 initFilters();
10 initFilters();
9 <% query.filters.each do |field, options| %>
11 <% query.filters.each do |field, options| %>
@@ -199,6 +199,7 Rails.application.routes.draw do
199 match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
199 match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
200
200
201 resources :queries, :except => [:show]
201 resources :queries, :except => [:show]
202 get '/queries/filter', :to => 'queries#filter', :as => 'queries_filter'
202
203
203 resources :news, :only => [:index, :show, :edit, :update, :destroy]
204 resources :news, :only => [:index, :show, :edit, :update, :destroy]
204 match '/news/:id/comments', :to => 'comments#create', :via => :post
205 match '/news/:id/comments', :to => 'comments#create', :via => :post
@@ -120,6 +120,18 function initFilters() {
120 function addFilter(field, operator, values) {
120 function addFilter(field, operator, values) {
121 var fieldId = field.replace('.', '_');
121 var fieldId = field.replace('.', '_');
122 var tr = $('#tr_'+fieldId);
122 var tr = $('#tr_'+fieldId);
123
124 var filterOptions = availableFilters[field];
125 if (!filterOptions) return;
126
127 if (filterOptions['remote'] && filterOptions['values'] == null) {
128 $.getJSON(filtersUrl, {'name': field}).done(function(data) {
129 filterOptions['values'] = data;
130 addFilter(field, operator, values) ;
131 });
132 return;
133 }
134
123 if (tr.length > 0) {
135 if (tr.length > 0) {
124 tr.show();
136 tr.show();
125 } else {
137 } else {
@@ -134,7 +146,7 function addFilter(field, operator, values) {
134 });
146 });
135 }
147 }
136
148
137 function buildFilterRow(field, operator, values) {
149 function buildFilterRow(field, operator, values, loadedValues) {
138 var fieldId = field.replace('.', '_');
150 var fieldId = field.replace('.', '_');
139 var filterTable = $("#filters-table");
151 var filterTable = $("#filters-table");
140 var filterOptions = availableFilters[field];
152 var filterOptions = availableFilters[field];
@@ -212,8 +224,8 function buildFilterRow(field, operator, values) {
212 );
224 );
213 $('#values_'+fieldId).val(values[0]);
225 $('#values_'+fieldId).val(values[0]);
214 select = tr.find('td.values select');
226 select = tr.find('td.values select');
215 for (i = 0; i < allProjects.length; i++) {
227 for (i = 0; i < filterValues.length; i++) {
216 var filterValue = allProjects[i];
228 var filterValue = filterValues[i];
217 var option = $('<option>');
229 var option = $('<option>');
218 option.val(filterValue[1]).text(filterValue[0]);
230 option.val(filterValue[1]).text(filterValue[0]);
219 if (values[0] == filterValue[1]) { option.attr('selected', true); }
231 if (values[0] == filterValue[1]) { option.attr('selected', true); }
@@ -18,7 +18,12
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class QueriesControllerTest < Redmine::ControllerTest
20 class QueriesControllerTest < Redmine::ControllerTest
21 fixtures :projects, :users, :members, :member_roles, :roles, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues, :custom_fields, :custom_values, :queries, :enabled_modules
21 fixtures :projects, :enabled_modules,
22 :users, :email_addresses,
23 :members, :member_roles, :roles,
24 :trackers, :issue_statuses, :issue_categories, :enumerations, :versions,
25 :issues, :custom_fields, :custom_values,
26 :queries
22
27
23 def setup
28 def setup
24 User.current = nil
29 User.current = nil
@@ -397,4 +402,24 class QueriesControllerTest < Redmine::ControllerTest
397 assert_response :success
402 assert_response :success
398 assert_include 'addFilter("subject", "=", ["foo\/bar"]);', response.body
403 assert_include 'addFilter("subject", "=", ["foo\/bar"]);', response.body
399 end
404 end
405
406 def test_filter_with_project_id_should_return_filter_values
407 @request.session[:user_id] = 2
408 get :filter, :project_id => 1, :name => 'fixed_version_id'
409
410 assert_response :success
411 assert_equal 'application/json', response.content_type
412 json = ActiveSupport::JSON.decode(response.body)
413 assert_include ["eCookbook - 2.0", "3", "open"], json
414 end
415
416 def test_filter_without_project_id_should_return_filter_values
417 @request.session[:user_id] = 2
418 get :filter, :name => 'fixed_version_id'
419
420 assert_response :success
421 assert_equal 'application/json', response.content_type
422 json = ActiveSupport::JSON.decode(response.body)
423 assert_include ["OnlineStore - Systemwide visible version", "7", "open"], json
424 end
400 end
425 end
@@ -21,6 +21,7 class RoutingQueriesTest < Redmine::RoutingTest
21 def test_queries
21 def test_queries
22 should_route 'GET /queries/new' => 'queries#new'
22 should_route 'GET /queries/new' => 'queries#new'
23 should_route 'POST /queries' => 'queries#create'
23 should_route 'POST /queries' => 'queries#create'
24 should_route 'GET /queries/filter' => 'queries#filter'
24
25
25 should_route 'GET /queries/1/edit' => 'queries#edit', :id => '1'
26 should_route 'GET /queries/1/edit' => 'queries#edit', :id => '1'
26 should_route 'PUT /queries/1' => 'queries#update', :id => '1'
27 should_route 'PUT /queries/1' => 'queries#update', :id => '1'
@@ -118,6 +118,28 class QueryTest < ActiveSupport::TestCase
118 assert_not_include 'start_date', query.available_filters
118 assert_not_include 'start_date', query.available_filters
119 end
119 end
120
120
121 def test_filter_values_without_project_should_be_arrays
122 q = IssueQuery.new
123 assert_nil q.project
124
125 q.available_filters.each do |name, filter|
126 values = filter.values
127 assert (values.nil? || values.is_a?(Array)),
128 "#values for #{name} filter returned a #{values.class.name}"
129 end
130 end
131
132 def test_filter_values_with_project_should_be_arrays
133 q = IssueQuery.new(:project => Project.find(1))
134 assert_not_nil q.project
135
136 q.available_filters.each do |name, filter|
137 values = filter.values
138 assert (values.nil? || values.is_a?(Array)),
139 "#values for #{name} filter returned a #{values.class.name}"
140 end
141 end
142
121 def find_issues_with_query(query)
143 def find_issues_with_query(query)
122 Issue.joins(:status, :tracker, :project, :priority).where(
144 Issue.joins(:status, :tracker, :project, :priority).where(
123 query.statement
145 query.statement
@@ -27,6 +27,28 class TimeEntryQueryTest < ActiveSupport::TestCase
27 :groups_users,
27 :groups_users,
28 :enabled_modules
28 :enabled_modules
29
29
30 def test_filter_values_without_project_should_be_arrays
31 q = TimeEntryQuery.new
32 assert_nil q.project
33
34 q.available_filters.each do |name, filter|
35 values = filter.values
36 assert (values.nil? || values.is_a?(Array)),
37 "#values for #{name} filter returned a #{values.class.name}"
38 end
39 end
40
41 def test_filter_values_with_project_should_be_arrays
42 q = TimeEntryQuery.new(:project => Project.find(1))
43 assert_not_nil q.project
44
45 q.available_filters.each do |name, filter|
46 values = filter.values
47 assert (values.nil? || values.is_a?(Array)),
48 "#values for #{name} filter returned a #{values.class.name}"
49 end
50 end
51
30 def test_cross_project_activity_filter_should_propose_non_active_activities
52 def test_cross_project_activity_filter_should_propose_non_active_activities
31 activity = TimeEntryActivity.create!(:name => 'Disabled', :active => false)
53 activity = TimeEntryActivity.create!(:name => 'Disabled', :active => false)
32 assert !activity.active?
54 assert !activity.active?
General Comments 0
You need to be logged in to leave comments. Login now