##// END OF EJS Templates
Refactor: use an ordered hash to store available filters and remove :order option (#13154)....
Jean-Philippe Lang -
r11142:0be82ea2c45e
parent child
Show More
@@ -24,28 +24,7 module QueriesHelper
24
24
25 def filters_options(query)
25 def filters_options(query)
26 options = [[]]
26 options = [[]]
27 sorted_options = query.available_filters.sort do |a, b|
27 options += query.available_filters.map do |field, field_options|
28 ord = 0
29 if !(a[1][:order] == 20 && b[1][:order] == 20)
30 ord = a[1][:order] <=> b[1][:order]
31 else
32 cn = (CustomField::CUSTOM_FIELDS_NAMES.index(a[1][:field].class.name) <=>
33 CustomField::CUSTOM_FIELDS_NAMES.index(b[1][:field].class.name))
34 if cn != 0
35 ord = cn
36 else
37 f = (a[1][:field] <=> b[1][:field])
38 if f != 0
39 ord = f
40 else
41 # assigned_to or author
42 ord = (a[0] <=> b[0])
43 end
44 end
45 end
46 ord
47 end
48 options += sorted_options.map do |field, field_options|
49 [field_options[:name], field]
28 [field_options[:name], field]
50 end
29 end
51 end
30 end
@@ -58,141 +58,127 class IssueQuery < Query
58 (project.nil? || user.allowed_to?(:view_issues, project)) && (self.is_public? || self.user_id == user.id)
58 (project.nil? || user.allowed_to?(:view_issues, project)) && (self.is_public? || self.user_id == user.id)
59 end
59 end
60
60
61 def available_filters
61 def initialize_available_filters
62 return @available_filters if @available_filters
63 @available_filters = {
64 "status_id" => {
65 :type => :list_status, :order => 0,
66 :values => IssueStatus.sorted.all.collect{|s| [s.name, s.id.to_s] }
67 },
68 "tracker_id" => {
69 :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] }
70 },
71 "priority_id" => {
72 :type => :list, :order => 3, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] }
73 },
74 "subject" => { :type => :text, :order => 8 },
75 "created_on" => { :type => :date_past, :order => 9 },
76 "updated_on" => { :type => :date_past, :order => 10 },
77 "start_date" => { :type => :date, :order => 11 },
78 "due_date" => { :type => :date, :order => 12 },
79 "estimated_hours" => { :type => :float, :order => 13 },
80 "done_ratio" => { :type => :integer, :order => 14 }
81 }
82 IssueRelation::TYPES.each do |relation_type, options|
83 @available_filters[relation_type] = {
84 :type => :relation, :order => @available_filters.size + 100,
85 :label => options[:name]
86 }
87 end
88 principals = []
62 principals = []
63 subprojects = []
64 versions = []
65 categories = []
66 issue_custom_fields = []
67
89 if project
68 if project
90 principals += project.principals.sort
69 principals += project.principals.sort
91 unless project.leaf?
70 unless project.leaf?
92 subprojects = project.descendants.visible.all
71 subprojects = project.descendants.visible.all
93 if subprojects.any?
72 principals += Principal.member_of(subprojects)
94 @available_filters["subproject_id"] = {
95 :type => :list_subprojects, :order => 13,
96 :values => subprojects.collect{|s| [s.name, s.id.to_s] }
97 }
98 principals += Principal.member_of(subprojects)
99 end
100 end
73 end
74 versions = project.shared_versions.all
75 categories = project.issue_categories.all
76 issue_custom_fields = project.all_issue_custom_fields
101 else
77 else
102 if all_projects.any?
78 if all_projects.any?
103 # members of visible projects
104 principals += Principal.member_of(all_projects)
79 principals += Principal.member_of(all_projects)
105 # project filter
106 project_values = []
107 if User.current.logged? && User.current.memberships.any?
108 project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
109 end
110 project_values += all_projects_values
111 @available_filters["project_id"] = {
112 :type => :list, :order => 1, :values => project_values
113 } unless project_values.empty?
114 end
80 end
81 versions = Version.visible.find_all_by_sharing('system')
82 issue_custom_fields = IssueCustomField.where(:is_filter => true, :is_for_all => true).all
115 end
83 end
116 principals.uniq!
84 principals.uniq!
117 principals.sort!
85 principals.sort!
118 users = principals.select {|p| p.is_a?(User)}
86 users = principals.select {|p| p.is_a?(User)}
119
87
120 assigned_to_values = []
88
121 assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
89 add_available_filter "status_id",
122 assigned_to_values += (Setting.issue_group_assignment? ?
90 :type => :list_status, :values => IssueStatus.sorted.all.collect{|s| [s.name, s.id.to_s] }
123 principals : users).collect{|s| [s.name, s.id.to_s] }
91
124 @available_filters["assigned_to_id"] = {
92 if project.nil?
125 :type => :list_optional, :order => 4, :values => assigned_to_values
93 project_values = []
126 } unless assigned_to_values.empty?
94 if User.current.logged? && User.current.memberships.any?
95 project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
96 end
97 project_values += all_projects_values
98 add_available_filter("project_id",
99 :type => :list, :values => project_values
100 ) unless project_values.empty?
101 end
102
103 add_available_filter "tracker_id",
104 :type => :list, :values => trackers.collect{|s| [s.name, s.id.to_s] }
105 add_available_filter "priority_id",
106 :type => :list, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] }
127
107
128 author_values = []
108 author_values = []
129 author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
109 author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
130 author_values += users.collect{|s| [s.name, s.id.to_s] }
110 author_values += users.collect{|s| [s.name, s.id.to_s] }
131 @available_filters["author_id"] = {
111 add_available_filter("author_id",
132 :type => :list, :order => 5, :values => author_values
112 :type => :list, :values => author_values
133 } unless author_values.empty?
113 ) unless author_values.empty?
114
115 assigned_to_values = []
116 assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
117 assigned_to_values += (Setting.issue_group_assignment? ?
118 principals : users).collect{|s| [s.name, s.id.to_s] }
119 add_available_filter("assigned_to_id",
120 :type => :list_optional, :values => assigned_to_values
121 ) unless assigned_to_values.empty?
134
122
135 group_values = Group.all.collect {|g| [g.name, g.id.to_s] }
123 group_values = Group.all.collect {|g| [g.name, g.id.to_s] }
136 @available_filters["member_of_group"] = {
124 add_available_filter("member_of_group",
137 :type => :list_optional, :order => 6, :values => group_values
125 :type => :list_optional, :values => group_values
138 } unless group_values.empty?
126 ) unless group_values.empty?
139
127
140 role_values = Role.givable.collect {|r| [r.name, r.id.to_s] }
128 role_values = Role.givable.collect {|r| [r.name, r.id.to_s] }
141 @available_filters["assigned_to_role"] = {
129 add_available_filter("assigned_to_role",
142 :type => :list_optional, :order => 7, :values => role_values
130 :type => :list_optional, :values => role_values
143 } unless role_values.empty?
131 ) unless role_values.empty?
144
132
145 if User.current.logged?
133 if versions.any?
146 @available_filters["watcher_id"] = {
134 add_available_filter "fixed_version_id",
147 :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]]
135 :type => :list_optional,
148 }
136 :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] }
149 end
137 end
150
138
151 if project
139 if categories.any?
152 # project specific filters
140 add_available_filter "category_id",
153 categories = project.issue_categories.all
141 :type => :list_optional,
154 unless categories.empty?
142 :values => categories.collect{|s| [s.name, s.id.to_s] }
155 @available_filters["category_id"] = {
156 :type => :list_optional, :order => 6,
157 :values => categories.collect{|s| [s.name, s.id.to_s] }
158 }
159 end
160 versions = project.shared_versions.all
161 unless versions.empty?
162 @available_filters["fixed_version_id"] = {
163 :type => :list_optional, :order => 7,
164 :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] }
165 }
166 end
167 add_custom_fields_filters(project.all_issue_custom_fields)
168 else
169 # global filters for cross project issue list
170 system_shared_versions = Version.visible.find_all_by_sharing('system')
171 unless system_shared_versions.empty?
172 @available_filters["fixed_version_id"] = {
173 :type => :list_optional, :order => 7,
174 :values => system_shared_versions.sort.collect{|s|
175 ["#{s.project.name} - #{s.name}", s.id.to_s]
176 }
177 }
178 end
179 add_custom_fields_filters(IssueCustomField.where(:is_filter => true, :is_for_all => true).all)
180 end
143 end
181 add_associations_custom_fields_filters :project, :author, :assigned_to, :fixed_version
144
145 add_available_filter "subject", :type => :text
146 add_available_filter "created_on", :type => :date_past
147 add_available_filter "updated_on", :type => :date_past
148 add_available_filter "start_date", :type => :date
149 add_available_filter "due_date", :type => :date
150 add_available_filter "estimated_hours", :type => :float
151 add_available_filter "done_ratio", :type => :integer
152
182 if User.current.allowed_to?(:set_issues_private, nil, :global => true) ||
153 if User.current.allowed_to?(:set_issues_private, nil, :global => true) ||
183 User.current.allowed_to?(:set_own_issues_private, nil, :global => true)
154 User.current.allowed_to?(:set_own_issues_private, nil, :global => true)
184 @available_filters["is_private"] = {
155 add_available_filter "is_private",
185 :type => :list, :order => 16,
156 :type => :list,
186 :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]]
157 :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]]
187 }
188 end
158 end
159
160 if User.current.logged?
161 add_available_filter "watcher_id",
162 :type => :list, :values => [["<< #{l(:label_me)} >>", "me"]]
163 end
164
165 if subprojects.any?
166 add_available_filter "subproject_id",
167 :type => :list_subprojects,
168 :values => subprojects.collect{|s| [s.name, s.id.to_s] }
169 end
170
171 add_custom_fields_filters(issue_custom_fields)
172
173 add_associations_custom_fields_filters :project, :author, :assigned_to, :fixed_version
174
175 IssueRelation::TYPES.each do |relation_type, options|
176 add_available_filter relation_type, :type => :relation, :label => options[:name]
177 end
178
189 Tracker.disabled_core_fields(trackers).each {|field|
179 Tracker.disabled_core_fields(trackers).each {|field|
190 @available_filters.delete field
180 delete_available_filter field
191 }
181 }
192 @available_filters.each do |field, options|
193 options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, ''))
194 end
195 @available_filters
196 end
182 end
197
183
198 def available_columns
184 def available_columns
@@ -278,6 +278,37 class Query < ActiveRecord::Base
278 @all_projects_values = values
278 @all_projects_values = values
279 end
279 end
280
280
281 # Adds available filters
282 def initialize_available_filters
283 # implemented by sub-classes
284 end
285 protected :initialize_available_filters
286
287 # Adds an available filter
288 def add_available_filter(field, options)
289 @available_filters ||= ActiveSupport::OrderedHash.new
290 @available_filters[field] = options
291 @available_filters
292 end
293
294 # Removes an available filter
295 def delete_available_filter(field)
296 if @available_filters
297 @available_filters.delete(field)
298 end
299 end
300
301 # Return a hash of available filters
302 def available_filters
303 unless @available_filters
304 initialize_available_filters
305 @available_filters.each do |field, options|
306 options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, ''))
307 end
308 end
309 @available_filters
310 end
311
281 def add_filter(field, operator, values=nil)
312 def add_filter(field, operator, values=nil)
282 # values must be an array
313 # values must be an array
283 return unless values.nil? || values.is_a?(Array)
314 return unless values.nil? || values.is_a?(Array)
@@ -692,31 +723,30 class Query < ActiveRecord::Base
692
723
693 def add_custom_fields_filters(custom_fields, assoc=nil)
724 def add_custom_fields_filters(custom_fields, assoc=nil)
694 return unless custom_fields.present?
725 return unless custom_fields.present?
695 @available_filters ||= {}
696
726
697 custom_fields.select(&:is_filter?).each do |field|
727 custom_fields.select(&:is_filter?).sort.each do |field|
698 case field.field_format
728 case field.field_format
699 when "text"
729 when "text"
700 options = { :type => :text, :order => 20 }
730 options = { :type => :text }
701 when "list"
731 when "list"
702 options = { :type => :list_optional, :values => field.possible_values, :order => 20}
732 options = { :type => :list_optional, :values => field.possible_values }
703 when "date"
733 when "date"
704 options = { :type => :date, :order => 20 }
734 options = { :type => :date }
705 when "bool"
735 when "bool"
706 options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 }
736 options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]] }
707 when "int"
737 when "int"
708 options = { :type => :integer, :order => 20 }
738 options = { :type => :integer }
709 when "float"
739 when "float"
710 options = { :type => :float, :order => 20 }
740 options = { :type => :float }
711 when "user", "version"
741 when "user", "version"
712 next unless project
742 next unless project
713 values = field.possible_values_options(project)
743 values = field.possible_values_options(project)
714 if User.current.logged? && field.field_format == 'user'
744 if User.current.logged? && field.field_format == 'user'
715 values.unshift ["<< #{l(:label_me)} >>", "me"]
745 values.unshift ["<< #{l(:label_me)} >>", "me"]
716 end
746 end
717 options = { :type => :list_optional, :values => values, :order => 20}
747 options = { :type => :list_optional, :values => values }
718 else
748 else
719 options = { :type => :string, :order => 20 }
749 options = { :type => :string }
720 end
750 end
721 filter_id = "cf_#{field.id}"
751 filter_id = "cf_#{field.id}"
722 filter_name = field.name
752 filter_name = field.name
@@ -724,7 +754,7 class Query < ActiveRecord::Base
724 filter_id = "#{assoc}.#{filter_id}"
754 filter_id = "#{assoc}.#{filter_id}"
725 filter_name = l("label_attribute_of_#{assoc}", :name => filter_name)
755 filter_name = l("label_attribute_of_#{assoc}", :name => filter_name)
726 end
756 end
727 @available_filters[filter_id] = options.merge({
757 add_available_filter filter_id, options.merge({
728 :name => filter_name,
758 :name => filter_name,
729 :format => field.field_format,
759 :format => field.field_format,
730 :field => field
760 :field => field
@@ -35,13 +35,8 class TimeEntryQuery < Query
35 add_filter('spent_on', '*') unless filters.present?
35 add_filter('spent_on', '*') unless filters.present?
36 end
36 end
37
37
38 def available_filters
38 def initialize_available_filters
39 return @available_filters if @available_filters
39 add_available_filter "spent_on", :type => :date_past
40 @available_filters = {
41 "spent_on" => { :type => :date_past, :order => 0 },
42 "comments" => { :type => :text, :order => 5 },
43 "hours" => { :type => :float, :order => 6 }
44 }
45
40
46 principals = []
41 principals = []
47 if project
42 if project
@@ -49,10 +44,9 class TimeEntryQuery < Query
49 unless project.leaf?
44 unless project.leaf?
50 subprojects = project.descendants.visible.all
45 subprojects = project.descendants.visible.all
51 if subprojects.any?
46 if subprojects.any?
52 @available_filters["subproject_id"] = {
47 add_available_filter "subproject_id",
53 :type => :list_subprojects, :order => 1,
48 :type => :list_subprojects,
54 :values => subprojects.collect{|s| [s.name, s.id.to_s] }
49 :values => subprojects.collect{|s| [s.name, s.id.to_s] }
55 }
56 principals += Principal.member_of(subprojects)
50 principals += Principal.member_of(subprojects)
57 end
51 end
58 end
52 end
@@ -66,9 +60,9 class TimeEntryQuery < Query
66 project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
60 project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
67 end
61 end
68 project_values += all_projects_values
62 project_values += all_projects_values
69 @available_filters["project_id"] = {
63 add_available_filter("project_id",
70 :type => :list, :order => 1, :values => project_values
64 :type => :list, :values => project_values
71 } unless project_values.empty?
65 ) unless project_values.empty?
72 end
66 end
73 end
67 end
74 principals.uniq!
68 principals.uniq!
@@ -78,22 +72,20 class TimeEntryQuery < Query
78 users_values = []
72 users_values = []
79 users_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
73 users_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
80 users_values += users.collect{|s| [s.name, s.id.to_s] }
74 users_values += users.collect{|s| [s.name, s.id.to_s] }
81 @available_filters["user_id"] = {
75 add_available_filter("user_id",
82 :type => :list_optional, :order => 2, :values => users_values
76 :type => :list_optional, :values => users_values
83 } unless users_values.empty?
77 ) unless users_values.empty?
84
78
85 activities = (project ? project.activities : TimeEntryActivity.shared.active)
79 activities = (project ? project.activities : TimeEntryActivity.shared.active)
86 @available_filters["activity_id"] = {
80 add_available_filter("activity_id",
87 :type => :list, :order => 3, :values => activities.map {|a| [a.name, a.id.to_s]}
81 :type => :list, :values => activities.map {|a| [a.name, a.id.to_s]}
88 } unless activities.empty?
82 ) unless activities.empty?
83
84 add_available_filter "comments", :type => :text
85 add_available_filter "hours", :type => :float
89
86
90 add_custom_fields_filters(TimeEntryCustomField.where(:is_filter => true).all)
87 add_custom_fields_filters(TimeEntryCustomField.where(:is_filter => true).all)
91 add_associations_custom_fields_filters :project, :issue, :user
88 add_associations_custom_fields_filters :project, :issue, :user
92
93 @available_filters.each do |field, options|
94 options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, ''))
95 end
96 @available_filters
97 end
89 end
98
90
99 def available_columns
91 def available_columns
@@ -29,7 +29,7 class QueriesHelperTest < ActionView::TestCase
29 :projects_trackers,
29 :projects_trackers,
30 :custom_fields_trackers
30 :custom_fields_trackers
31
31
32 def test_order
32 def test_filters_options_should_be_ordered
33 User.current = User.find_by_login('admin')
33 User.current = User.find_by_login('admin')
34 query = IssueQuery.new(:project => nil, :name => '_')
34 query = IssueQuery.new(:project => nil, :name => '_')
35 assert_equal 30, query.available_filters.size
35 assert_equal 30, query.available_filters.size
@@ -40,17 +40,16 class QueriesHelperTest < ActionView::TestCase
40 assert_equal "project_id", fo[2][1]
40 assert_equal "project_id", fo[2][1]
41 assert_equal "tracker_id", fo[3][1]
41 assert_equal "tracker_id", fo[3][1]
42 assert_equal "priority_id", fo[4][1]
42 assert_equal "priority_id", fo[4][1]
43 assert_equal "watcher_id", fo[17][1]
43 assert_equal "is_private", fo[17][1]
44 assert_equal "is_private", fo[18][1]
44 assert_equal "watcher_id", fo[18][1]
45 end
45 end
46
46
47 def test_order_custom_fields
47 def test_filters_options_should_be_ordered_with_custom_fields
48 set_language_if_valid 'en'
48 set_language_if_valid 'en'
49 field = UserCustomField.new(
49 field = UserCustomField.create!(
50 :name => 'order test', :field_format => 'string',
50 :name => 'order test', :field_format => 'string',
51 :is_for_all => true, :is_filter => true
51 :is_for_all => true, :is_filter => true
52 )
52 )
53 assert field.save
54 User.current = User.find_by_login('admin')
53 User.current = User.find_by_login('admin')
55 query = IssueQuery.new(:project => nil, :name => '_')
54 query = IssueQuery.new(:project => nil, :name => '_')
56 assert_equal 32, query.available_filters.size
55 assert_equal 32, query.available_filters.size
@@ -59,7 +58,7 class QueriesHelperTest < ActionView::TestCase
59 assert_equal "Searchable field", fo[19][0]
58 assert_equal "Searchable field", fo[19][0]
60 assert_equal "Database", fo[20][0]
59 assert_equal "Database", fo[20][0]
61 assert_equal "Project's Development status", fo[21][0]
60 assert_equal "Project's Development status", fo[21][0]
62 assert_equal "Assignee's order test", fo[22][0]
61 assert_equal "Author's order test", fo[22][0]
63 assert_equal "Author's order test", fo[23][0]
62 assert_equal "Assignee's order test", fo[23][0]
64 end
63 end
65 end
64 end
@@ -28,6 +28,11 class QueryTest < ActiveSupport::TestCase
28 :projects_trackers,
28 :projects_trackers,
29 :custom_fields_trackers
29 :custom_fields_trackers
30
30
31 def test_available_filters_should_be_ordered
32 query = IssueQuery.new
33 assert_equal 0, query.available_filters.keys.index('status_id')
34 end
35
31 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
36 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
32 query = IssueQuery.new(:project => nil, :name => '_')
37 query = IssueQuery.new(:project => nil, :name => '_')
33 assert query.available_filters.has_key?('cf_1')
38 assert query.available_filters.has_key?('cf_1')
General Comments 0
You need to be logged in to leave comments. Login now