Mercurial > hg > soundsoftware-site
comparison app/helpers/issues_helper.rb @ 1464:261b3d9a4903 redmine-2.4
Update to Redmine 2.4 branch rev 12663
author | Chris Cannam |
---|---|
date | Tue, 14 Jan 2014 14:37:42 +0000 |
parents | 3e4c3460b6ca |
children | e248c7af89ec |
comparison
equal
deleted
inserted
replaced
1296:038ba2d95de8 | 1464:261b3d9a4903 |
---|---|
1 # encoding: utf-8 | 1 # encoding: utf-8 |
2 # | 2 # |
3 # Redmine - project management software | 3 # Redmine - project management software |
4 # Copyright (C) 2006-2012 Jean-Philippe Lang | 4 # Copyright (C) 2006-2013 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. |
92 end | 92 end |
93 s << '</table></form>' | 93 s << '</table></form>' |
94 s.html_safe | 94 s.html_safe |
95 end | 95 end |
96 | 96 |
97 # Returns an array of error messages for bulk edited issues | |
98 def bulk_edit_error_messages(issues) | |
99 messages = {} | |
100 issues.each do |issue| | |
101 issue.errors.full_messages.each do |message| | |
102 messages[message] ||= [] | |
103 messages[message] << issue | |
104 end | |
105 end | |
106 messages.map { |message, issues| | |
107 "#{message}: " + issues.map {|i| "##{i.id}"}.join(', ') | |
108 } | |
109 end | |
110 | |
97 # Returns a link for adding a new subtask to the given issue | 111 # Returns a link for adding a new subtask to the given issue |
98 def link_to_new_subtask(issue) | 112 def link_to_new_subtask(issue) |
99 attrs = { | 113 attrs = { |
100 :tracker_id => issue.tracker, | 114 :tracker_id => issue.tracker, |
101 :parent_issue_id => issue | 115 :parent_issue_id => issue |
144 yield r | 158 yield r |
145 r.to_html | 159 r.to_html |
146 end | 160 end |
147 | 161 |
148 def render_custom_fields_rows(issue) | 162 def render_custom_fields_rows(issue) |
149 return if issue.custom_field_values.empty? | 163 values = issue.visible_custom_field_values |
164 return if values.empty? | |
150 ordered_values = [] | 165 ordered_values = [] |
151 half = (issue.custom_field_values.size / 2.0).ceil | 166 half = (values.size / 2.0).ceil |
152 half.times do |i| | 167 half.times do |i| |
153 ordered_values << issue.custom_field_values[i] | 168 ordered_values << values[i] |
154 ordered_values << issue.custom_field_values[i + half] | 169 ordered_values << values[i + half] |
155 end | 170 end |
156 s = "<tr>\n" | 171 s = "<tr>\n" |
157 n = 0 | 172 n = 0 |
158 ordered_values.compact.each do |value| | 173 ordered_values.compact.each do |value| |
159 s << "</tr>\n<tr>\n" if n > 0 && (n % 2) == 0 | 174 s << "</tr>\n<tr>\n" if n > 0 && (n % 2) == 0 |
182 message | 197 message |
183 end | 198 end |
184 | 199 |
185 def sidebar_queries | 200 def sidebar_queries |
186 unless @sidebar_queries | 201 unless @sidebar_queries |
187 @sidebar_queries = Query.visible.all( | 202 @sidebar_queries = IssueQuery.visible. |
188 :order => "#{Query.table_name}.name ASC", | 203 order("#{Query.table_name}.name ASC"). |
189 # Project specific queries and global queries | 204 # Project specific queries and global queries |
190 :conditions => (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]) | 205 where(@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]). |
191 ) | 206 all |
192 end | 207 end |
193 @sidebar_queries | 208 @sidebar_queries |
194 end | 209 end |
195 | 210 |
196 def query_links(title, queries) | 211 def query_links(title, queries) |
212 return '' if queries.empty? | |
197 # links to #index on issues/show | 213 # links to #index on issues/show |
198 url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params | 214 url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params |
199 | 215 |
200 content_tag('h3', h(title)) + | 216 content_tag('h3', title) + "\n" + |
201 queries.collect {|query| | 217 content_tag('ul', |
202 css = 'query' | 218 queries.collect {|query| |
203 css << ' selected' if query == @query | 219 css = 'query' |
204 link_to(h(query.name), url_params.merge(:query_id => query), :class => css) | 220 css << ' selected' if query == @query |
205 }.join('<br />').html_safe | 221 content_tag('li', link_to(query.name, url_params.merge(:query_id => query), :class => css)) |
222 }.join("\n").html_safe, | |
223 :class => 'queries' | |
224 ) + "\n" | |
206 end | 225 end |
207 | 226 |
208 def render_sidebar_queries | 227 def render_sidebar_queries |
209 out = ''.html_safe | 228 out = ''.html_safe |
210 queries = sidebar_queries.select {|q| !q.is_public?} | 229 out << query_links(l(:label_my_queries), sidebar_queries.select(&:is_private?)) |
211 out << query_links(l(:label_my_queries), queries) if queries.any? | 230 out << query_links(l(:label_query_plural), sidebar_queries.reject(&:is_private?)) |
212 queries = sidebar_queries.select {|q| q.is_public?} | |
213 out << query_links(l(:label_query_plural), queries) if queries.any? | |
214 out | 231 out |
232 end | |
233 | |
234 def email_issue_attributes(issue, user) | |
235 items = [] | |
236 %w(author status priority assigned_to category fixed_version).each do |attribute| | |
237 unless issue.disabled_core_fields.include?(attribute+"_id") | |
238 items << "#{l("field_#{attribute}")}: #{issue.send attribute}" | |
239 end | |
240 end | |
241 issue.visible_custom_field_values(user).each do |value| | |
242 items << "#{value.custom_field.name}: #{show_value(value)}" | |
243 end | |
244 items | |
245 end | |
246 | |
247 def render_email_issue_attributes(issue, user, html=false) | |
248 items = email_issue_attributes(issue, user) | |
249 if html | |
250 content_tag('ul', items.map{|s| content_tag('li', s)}.join("\n").html_safe) | |
251 else | |
252 items.map{|s| "* #{s}"}.join("\n") | |
253 end | |
215 end | 254 end |
216 | 255 |
217 # Returns the textual representation of a journal details | 256 # Returns the textual representation of a journal details |
218 # as an array of strings | 257 # as an array of strings |
219 def details_to_strings(details, no_html=false, options={}) | 258 def details_to_strings(details, no_html=false, options={}) |
220 options[:only_path] = (options[:only_path] == false ? false : true) | 259 options[:only_path] = (options[:only_path] == false ? false : true) |
221 strings = [] | 260 strings = [] |
222 values_by_field = {} | 261 values_by_field = {} |
223 details.each do |detail| | 262 details.each do |detail| |
224 if detail.property == 'cf' | 263 if detail.property == 'cf' |
225 field_id = detail.prop_key | 264 field = detail.custom_field |
226 field = CustomField.find_by_id(field_id) | |
227 if field && field.multiple? | 265 if field && field.multiple? |
228 values_by_field[field_id] ||= {:added => [], :deleted => []} | 266 values_by_field[field] ||= {:added => [], :deleted => []} |
229 if detail.old_value | 267 if detail.old_value |
230 values_by_field[field_id][:deleted] << detail.old_value | 268 values_by_field[field][:deleted] << detail.old_value |
231 end | 269 end |
232 if detail.value | 270 if detail.value |
233 values_by_field[field_id][:added] << detail.value | 271 values_by_field[field][:added] << detail.value |
234 end | 272 end |
235 next | 273 next |
236 end | 274 end |
237 end | 275 end |
238 strings << show_detail(detail, no_html, options) | 276 strings << show_detail(detail, no_html, options) |
239 end | 277 end |
240 values_by_field.each do |field_id, changes| | 278 values_by_field.each do |field, changes| |
241 detail = JournalDetail.new(:property => 'cf', :prop_key => field_id) | 279 detail = JournalDetail.new(:property => 'cf', :prop_key => field.id.to_s) |
280 detail.instance_variable_set "@custom_field", field | |
242 if changes[:added].any? | 281 if changes[:added].any? |
243 detail.value = changes[:added] | 282 detail.value = changes[:added] |
244 strings << show_detail(detail, no_html, options) | 283 strings << show_detail(detail, no_html, options) |
245 elsif changes[:deleted].any? | 284 elsif changes[:deleted].any? |
246 detail.old_value = changes[:deleted] | 285 detail.old_value = changes[:deleted] |
279 when 'is_private' | 318 when 'is_private' |
280 value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank? | 319 value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank? |
281 old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank? | 320 old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank? |
282 end | 321 end |
283 when 'cf' | 322 when 'cf' |
284 custom_field = CustomField.find_by_id(detail.prop_key) | 323 custom_field = detail.custom_field |
285 if custom_field | 324 if custom_field |
286 multiple = custom_field.multiple? | 325 multiple = custom_field.multiple? |
287 label = custom_field.name | 326 label = custom_field.name |
288 value = format_value(detail.value, custom_field.field_format) if detail.value | 327 value = format_value(detail.value, custom_field.field_format) if detail.value |
289 old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value | 328 old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value |
290 end | 329 end |
291 when 'attachment' | 330 when 'attachment' |
292 label = l(:label_attachment) | 331 label = l(:label_attachment) |
332 when 'relation' | |
333 if detail.value && !detail.old_value | |
334 rel_issue = Issue.visible.find_by_id(detail.value) | |
335 value = rel_issue.nil? ? "#{l(:label_issue)} ##{detail.value}" : | |
336 (no_html ? rel_issue : link_to_issue(rel_issue, :only_path => options[:only_path])) | |
337 elsif detail.old_value && !detail.value | |
338 rel_issue = Issue.visible.find_by_id(detail.old_value) | |
339 old_value = rel_issue.nil? ? "#{l(:label_issue)} ##{detail.old_value}" : | |
340 (no_html ? rel_issue : link_to_issue(rel_issue, :only_path => options[:only_path])) | |
341 end | |
342 label = l(detail.prop_key.to_sym) | |
293 end | 343 end |
294 call_hook(:helper_issues_show_detail_after_setting, | 344 call_hook(:helper_issues_show_detail_after_setting, |
295 {:detail => detail, :label => label, :value => value, :old_value => old_value }) | 345 {:detail => detail, :label => label, :value => value, :old_value => old_value }) |
296 | 346 |
297 label ||= detail.prop_key | 347 label ||= detail.prop_key |
299 old_value ||= detail.old_value | 349 old_value ||= detail.old_value |
300 | 350 |
301 unless no_html | 351 unless no_html |
302 label = content_tag('strong', label) | 352 label = content_tag('strong', label) |
303 old_value = content_tag("i", h(old_value)) if detail.old_value | 353 old_value = content_tag("i", h(old_value)) if detail.old_value |
304 old_value = content_tag("del", old_value) if detail.old_value and detail.value.blank? | 354 if detail.old_value && detail.value.blank? && detail.property != 'relation' |
355 old_value = content_tag("del", old_value) | |
356 end | |
305 if detail.property == 'attachment' && !value.blank? && atta = Attachment.find_by_id(detail.prop_key) | 357 if detail.property == 'attachment' && !value.blank? && atta = Attachment.find_by_id(detail.prop_key) |
306 # Link to the attachment if it has not been removed | 358 # Link to the attachment if it has not been removed |
307 value = link_to_attachment(atta, :download => true, :only_path => options[:only_path]) | 359 value = link_to_attachment(atta, :download => true, :only_path => options[:only_path]) |
308 if options[:only_path] != false && atta.is_text? | 360 if options[:only_path] != false && atta.is_text? |
309 value += link_to( | 361 value += link_to( |
335 elsif multiple | 387 elsif multiple |
336 l(:text_journal_added, :label => label, :value => value).html_safe | 388 l(:text_journal_added, :label => label, :value => value).html_safe |
337 else | 389 else |
338 l(:text_journal_set_to, :label => label, :value => value).html_safe | 390 l(:text_journal_set_to, :label => label, :value => value).html_safe |
339 end | 391 end |
340 when 'attachment' | 392 when 'attachment', 'relation' |
341 l(:text_journal_added, :label => label, :value => value).html_safe | 393 l(:text_journal_added, :label => label, :value => value).html_safe |
342 end | 394 end |
343 else | 395 else |
344 l(:text_journal_deleted, :label => label, :old => old_value).html_safe | 396 l(:text_journal_deleted, :label => label, :old => old_value).html_safe |
345 end | 397 end |
346 end | 398 end |
347 | 399 |
348 # Find the name of an associated record stored in the field attribute | 400 # Find the name of an associated record stored in the field attribute |
349 def find_name_by_reflection(field, id) | 401 def find_name_by_reflection(field, id) |
402 unless id.present? | |
403 return nil | |
404 end | |
350 association = Issue.reflect_on_association(field.to_sym) | 405 association = Issue.reflect_on_association(field.to_sym) |
351 if association | 406 if association |
352 record = association.class_name.constantize.find_by_id(id) | 407 record = association.class_name.constantize.find_by_id(id) |
353 if record | 408 if record |
354 record.name.force_encoding('UTF-8') if record.name.respond_to?(:force_encoding) | 409 record.name.force_encoding('UTF-8') if record.name.respond_to?(:force_encoding) |
368 render_api_issue_children(child, api) | 423 render_api_issue_children(child, api) |
369 end | 424 end |
370 end | 425 end |
371 end | 426 end |
372 end | 427 end |
373 | |
374 def issues_to_csv(issues, project, query, options={}) | |
375 decimal_separator = l(:general_csv_decimal_separator) | |
376 encoding = l(:general_csv_encoding) | |
377 columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns) | |
378 if options[:description] | |
379 if description = query.available_columns.detect {|q| q.name == :description} | |
380 columns << description | |
381 end | |
382 end | |
383 | |
384 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| | |
385 # csv header fields | |
386 csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } | |
387 | |
388 # csv lines | |
389 issues.each do |issue| | |
390 col_values = columns.collect do |column| | |
391 s = if column.is_a?(QueryCustomFieldColumn) | |
392 cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id} | |
393 show_value(cv) | |
394 else | |
395 value = column.value(issue) | |
396 if value.is_a?(Date) | |
397 format_date(value) | |
398 elsif value.is_a?(Time) | |
399 format_time(value) | |
400 elsif value.is_a?(Float) | |
401 ("%.2f" % value).gsub('.', decimal_separator) | |
402 else | |
403 value | |
404 end | |
405 end | |
406 s.to_s | |
407 end | |
408 csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) } | |
409 end | |
410 end | |
411 export | |
412 end | |
413 end | 428 end |