##// END OF EJS Templates
Merged r15608 (#23206)....
Jean-Philippe Lang -
r15230:723857fc4281
parent child
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,277 +1,279
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2016 Jean-Philippe Lang
4 # Copyright (C) 2006-2016 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 module QueriesHelper
20 module QueriesHelper
21 include ApplicationHelper
21 include ApplicationHelper
22
22
23 def filters_options_for_select(query)
23 def filters_options_for_select(query)
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 [:tree, :relation].include?(field_options[:type])
28 group = :label_relations
28 group = :label_relations
29 elsif field =~ /^(.+)\./
29 elsif field =~ /^(.+)\./
30 # association filters
30 # association filters
31 group = "field_#{$1}"
31 group = "field_#{$1}"
32 elsif %w(member_of_group assigned_to_role).include?(field)
32 elsif %w(member_of_group assigned_to_role).include?(field)
33 group = :field_assigned_to
33 group = :field_assigned_to
34 elsif field_options[:type] == :date_past || field_options[:type] == :date
34 elsif field_options[:type] == :date_past || field_options[:type] == :date
35 group = :label_date
35 group = :label_date
36 end
36 end
37 if group
37 if group
38 (grouped[group] ||= []) << [field_options[:name], field]
38 (grouped[group] ||= []) << [field_options[:name], field]
39 else
39 else
40 ungrouped << [field_options[:name], field]
40 ungrouped << [field_options[:name], field]
41 end
41 end
42 end
42 end
43 # Don't group dates if there's only one (eg. time entries filters)
43 # Don't group dates if there's only one (eg. time entries filters)
44 if grouped[:label_date].try(:size) == 1
44 if grouped[:label_date].try(:size) == 1
45 ungrouped << grouped.delete(:label_date).first
45 ungrouped << grouped.delete(:label_date).first
46 end
46 end
47 s = options_for_select([[]] + ungrouped)
47 s = options_for_select([[]] + ungrouped)
48 if grouped.present?
48 if grouped.present?
49 localized_grouped = grouped.map {|k,v| [l(k), v]}
49 localized_grouped = grouped.map {|k,v| [l(k), v]}
50 s << grouped_options_for_select(localized_grouped)
50 s << grouped_options_for_select(localized_grouped)
51 end
51 end
52 s
52 s
53 end
53 end
54
54
55 def query_filters_hidden_tags(query)
55 def query_filters_hidden_tags(query)
56 tags = ''.html_safe
56 tags = ''.html_safe
57 query.filters.each do |field, options|
57 query.filters.each do |field, options|
58 tags << hidden_field_tag("f[]", field, :id => nil)
58 tags << hidden_field_tag("f[]", field, :id => nil)
59 tags << hidden_field_tag("op[#{field}]", options[:operator], :id => nil)
59 tags << hidden_field_tag("op[#{field}]", options[:operator], :id => nil)
60 options[:values].each do |value|
60 options[:values].each do |value|
61 tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
61 tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
62 end
62 end
63 end
63 end
64 tags
64 tags
65 end
65 end
66
66
67 def query_columns_hidden_tags(query)
67 def query_columns_hidden_tags(query)
68 tags = ''.html_safe
68 tags = ''.html_safe
69 query.columns.each do |column|
69 query.columns.each do |column|
70 tags << hidden_field_tag("c[]", column.name, :id => nil)
70 tags << hidden_field_tag("c[]", column.name, :id => nil)
71 end
71 end
72 tags
72 tags
73 end
73 end
74
74
75 def query_hidden_tags(query)
75 def query_hidden_tags(query)
76 query_filters_hidden_tags(query) + query_columns_hidden_tags(query)
76 query_filters_hidden_tags(query) + query_columns_hidden_tags(query)
77 end
77 end
78
78
79 def available_block_columns_tags(query)
79 def available_block_columns_tags(query)
80 tags = ''.html_safe
80 tags = ''.html_safe
81 query.available_block_columns.each do |column|
81 query.available_block_columns.each do |column|
82 tags << content_tag('label', check_box_tag('c[]', column.name.to_s, query.has_column?(column), :id => nil) + " #{column.caption}", :class => 'inline')
82 tags << content_tag('label', check_box_tag('c[]', column.name.to_s, query.has_column?(column), :id => nil) + " #{column.caption}", :class => 'inline')
83 end
83 end
84 tags
84 tags
85 end
85 end
86
86
87 def available_totalable_columns_tags(query)
87 def available_totalable_columns_tags(query)
88 tags = ''.html_safe
88 tags = ''.html_safe
89 query.available_totalable_columns.each do |column|
89 query.available_totalable_columns.each do |column|
90 tags << content_tag('label', check_box_tag('t[]', column.name.to_s, query.totalable_columns.include?(column), :id => nil) + " #{column.caption}", :class => 'inline')
90 tags << content_tag('label', check_box_tag('t[]', column.name.to_s, query.totalable_columns.include?(column), :id => nil) + " #{column.caption}", :class => 'inline')
91 end
91 end
92 tags << hidden_field_tag('t[]', '')
92 tags << hidden_field_tag('t[]', '')
93 tags
93 tags
94 end
94 end
95
95
96 def query_available_inline_columns_options(query)
96 def query_available_inline_columns_options(query)
97 (query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
97 (query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
98 end
98 end
99
99
100 def query_selected_inline_columns_options(query)
100 def query_selected_inline_columns_options(query)
101 (query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
101 (query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
102 end
102 end
103
103
104 def render_query_columns_selection(query, options={})
104 def render_query_columns_selection(query, options={})
105 tag_name = (options[:name] || 'c') + '[]'
105 tag_name = (options[:name] || 'c') + '[]'
106 render :partial => 'queries/columns', :locals => {:query => query, :tag_name => tag_name}
106 render :partial => 'queries/columns', :locals => {:query => query, :tag_name => tag_name}
107 end
107 end
108
108
109 def render_query_totals(query)
109 def render_query_totals(query)
110 return unless query.totalable_columns.present?
110 return unless query.totalable_columns.present?
111 totals = query.totalable_columns.map do |column|
111 totals = query.totalable_columns.map do |column|
112 total_tag(column, query.total_for(column))
112 total_tag(column, query.total_for(column))
113 end
113 end
114 content_tag('p', totals.join(" ").html_safe, :class => "query-totals")
114 content_tag('p', totals.join(" ").html_safe, :class => "query-totals")
115 end
115 end
116
116
117 def total_tag(column, value)
117 def total_tag(column, value)
118 label = content_tag('span', "#{column.caption}:")
118 label = content_tag('span', "#{column.caption}:")
119 value = content_tag('span', format_object(value), :class => 'value')
119 value = content_tag('span', format_object(value), :class => 'value')
120 content_tag('span', label + " " + value, :class => "total-for-#{column.name.to_s.dasherize}")
120 content_tag('span', label + " " + value, :class => "total-for-#{column.name.to_s.dasherize}")
121 end
121 end
122
122
123 def column_header(column)
123 def column_header(column)
124 column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
124 column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
125 :default_order => column.default_order) :
125 :default_order => column.default_order) :
126 content_tag('th', h(column.caption))
126 content_tag('th', h(column.caption))
127 end
127 end
128
128
129 def column_content(column, issue)
129 def column_content(column, issue)
130 value = column.value_object(issue)
130 value = column.value_object(issue)
131 if value.is_a?(Array)
131 if value.is_a?(Array)
132 value.collect {|v| column_value(column, issue, v)}.compact.join(', ').html_safe
132 value.collect {|v| column_value(column, issue, v)}.compact.join(', ').html_safe
133 else
133 else
134 column_value(column, issue, value)
134 column_value(column, issue, value)
135 end
135 end
136 end
136 end
137
137
138 def column_value(column, issue, value)
138 def column_value(column, issue, value)
139 case column.name
139 case column.name
140 when :id
140 when :id
141 link_to value, issue_path(issue)
141 link_to value, issue_path(issue)
142 when :subject
142 when :subject
143 link_to value, issue_path(issue)
143 link_to value, issue_path(issue)
144 when :parent
144 when :parent
145 value ? (value.visible? ? link_to_issue(value, :subject => false) : "##{value.id}") : ''
145 value ? (value.visible? ? link_to_issue(value, :subject => false) : "##{value.id}") : ''
146 when :description
146 when :description
147 issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : ''
147 issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : ''
148 when :done_ratio
148 when :done_ratio
149 progress_bar(value)
149 progress_bar(value)
150 when :relations
150 when :relations
151 content_tag('span',
151 content_tag('span',
152 value.to_s(issue) {|other| link_to_issue(other, :subject => false, :tracker => false)}.html_safe,
152 value.to_s(issue) {|other| link_to_issue(other, :subject => false, :tracker => false)}.html_safe,
153 :class => value.css_classes_for(issue))
153 :class => value.css_classes_for(issue))
154 else
154 else
155 format_object(value)
155 format_object(value)
156 end
156 end
157 end
157 end
158
158
159 def csv_content(column, issue)
159 def csv_content(column, issue)
160 value = column.value_object(issue)
160 value = column.value_object(issue)
161 if value.is_a?(Array)
161 if value.is_a?(Array)
162 value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
162 value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
163 else
163 else
164 csv_value(column, issue, value)
164 csv_value(column, issue, value)
165 end
165 end
166 end
166 end
167
167
168 def csv_value(column, object, value)
168 def csv_value(column, object, value)
169 format_object(value, false) do |value|
169 format_object(value, false) do |value|
170 case value.class.name
170 case value.class.name
171 when 'Float'
171 when 'Float'
172 sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
172 sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
173 when 'IssueRelation'
173 when 'IssueRelation'
174 value.to_s(object)
174 value.to_s(object)
175 when 'Issue'
175 when 'Issue'
176 if object.is_a?(TimeEntry)
176 if object.is_a?(TimeEntry)
177 "#{value.tracker} ##{value.id}: #{value.subject}"
177 "#{value.tracker} ##{value.id}: #{value.subject}"
178 else
178 else
179 value.id
179 value.id
180 end
180 end
181 else
181 else
182 value
182 value
183 end
183 end
184 end
184 end
185 end
185 end
186
186
187 def query_to_csv(items, query, options={})
187 def query_to_csv(items, query, options={})
188 options ||= {}
188 options ||= {}
189 columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
189 columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
190 query.available_block_columns.each do |column|
190 query.available_block_columns.each do |column|
191 if options[column.name].present?
191 if options[column.name].present?
192 columns << column
192 columns << column
193 end
193 end
194 end
194 end
195
195
196 Redmine::Export::CSV.generate do |csv|
196 Redmine::Export::CSV.generate do |csv|
197 # csv header fields
197 # csv header fields
198 csv << columns.map {|c| c.caption.to_s}
198 csv << columns.map {|c| c.caption.to_s}
199 # csv lines
199 # csv lines
200 items.each do |item|
200 items.each do |item|
201 csv << columns.map {|c| csv_content(c, item)}
201 csv << columns.map {|c| csv_content(c, item)}
202 end
202 end
203 end
203 end
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
208 if !params[:query_id].blank?
208 if !params[:query_id].blank?
209 cond = "project_id IS NULL"
209 cond = "project_id IS NULL"
210 cond << " OR project_id = #{@project.id}" if @project
210 cond << " OR project_id = #{@project.id}" if @project
211 @query = IssueQuery.where(cond).find(params[:query_id])
211 @query = IssueQuery.where(cond).find(params[:query_id])
212 raise ::Unauthorized unless @query.visible?
212 raise ::Unauthorized unless @query.visible?
213 @query.project = @project
213 @query.project = @project
214 session[:query] = {:id => @query.id, :project_id => @query.project_id}
214 session[:query] = {:id => @query.id, :project_id => @query.project_id}
215 sort_clear
215 sort_clear
216 elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
216 elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
217 # Give it a name, required to be valid
217 # Give it a name, required to be valid
218 @query = IssueQuery.new(:name => "_")
218 @query = IssueQuery.new(:name => "_")
219 @query.project = @project
219 @query.project = @project
220 @query.build_from_params(params)
220 @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}
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 else
222 else
223 # retrieve from session
223 # retrieve from session
224 @query = nil
224 @query = nil
225 @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
225 @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][: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])
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.project = @project
227 @query.project = @project
228 end
228 end
229 end
229 end
230
230
231 def retrieve_query_from_session
231 def retrieve_query_from_session
232 if session[:query]
232 if session[:query]
233 if session[:query][:id]
233 if session[:query][:id]
234 @query = IssueQuery.find_by_id(session[:query][:id])
234 @query = IssueQuery.find_by_id(session[:query][:id])
235 return unless @query
235 return unless @query
236 else
236 else
237 @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])
237 @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])
238 end
238 end
239 if session[:query].has_key?(:project_id)
239 if session[:query].has_key?(:project_id)
240 @query.project_id = session[:query][:project_id]
240 @query.project_id = session[:query][:project_id]
241 else
241 else
242 @query.project = @project
242 @query.project = @project
243 end
243 end
244 @query
244 @query
245 end
245 end
246 end
246 end
247
247
248 # Returns the query definition as hidden field tags
248 # Returns the query definition as hidden field tags
249 def query_as_hidden_field_tags(query)
249 def query_as_hidden_field_tags(query)
250 tags = hidden_field_tag("set_filter", "1", :id => nil)
250 tags = hidden_field_tag("set_filter", "1", :id => nil)
251
251
252 if query.filters.present?
252 if query.filters.present?
253 query.filters.each do |field, filter|
253 query.filters.each do |field, filter|
254 tags << hidden_field_tag("f[]", field, :id => nil)
254 tags << hidden_field_tag("f[]", field, :id => nil)
255 tags << hidden_field_tag("op[#{field}]", filter[:operator], :id => nil)
255 tags << hidden_field_tag("op[#{field}]", filter[:operator], :id => nil)
256 filter[:values].each do |value|
256 filter[:values].each do |value|
257 tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
257 tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
258 end
258 end
259 end
259 end
260 else
261 tags << hidden_field_tag("f[]", "", :id => nil)
260 end
262 end
261 if query.column_names.present?
263 if query.column_names.present?
262 query.column_names.each do |name|
264 query.column_names.each do |name|
263 tags << hidden_field_tag("c[]", name, :id => nil)
265 tags << hidden_field_tag("c[]", name, :id => nil)
264 end
266 end
265 end
267 end
266 if query.totalable_names.present?
268 if query.totalable_names.present?
267 query.totalable_names.each do |name|
269 query.totalable_names.each do |name|
268 tags << hidden_field_tag("t[]", name, :id => nil)
270 tags << hidden_field_tag("t[]", name, :id => nil)
269 end
271 end
270 end
272 end
271 if query.group_by.present?
273 if query.group_by.present?
272 tags << hidden_field_tag("group_by", query.group_by, :id => nil)
274 tags << hidden_field_tag("group_by", query.group_by, :id => nil)
273 end
275 end
274
276
275 tags
277 tags
276 end
278 end
277 end
279 end
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now