##// END OF EJS Templates
Preserve Issues/Gantt/Calendar tab when displaying a saved query (#7605)....
Jean-Philippe Lang -
r4789:a11e3a85d619
parent child
Show More
@@ -1,279 +1,282
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module IssuesHelper
18 module IssuesHelper
19 include ApplicationHelper
19 include ApplicationHelper
20
20
21 def issue_list(issues, &block)
21 def issue_list(issues, &block)
22 ancestors = []
22 ancestors = []
23 issues.each do |issue|
23 issues.each do |issue|
24 while (ancestors.any? && !issue.is_descendant_of?(ancestors.last))
24 while (ancestors.any? && !issue.is_descendant_of?(ancestors.last))
25 ancestors.pop
25 ancestors.pop
26 end
26 end
27 yield issue, ancestors.size
27 yield issue, ancestors.size
28 ancestors << issue unless issue.leaf?
28 ancestors << issue unless issue.leaf?
29 end
29 end
30 end
30 end
31
31
32 # Renders a HTML/CSS tooltip
32 # Renders a HTML/CSS tooltip
33 #
33 #
34 # To use, a trigger div is needed. This is a div with the class of "tooltip"
34 # To use, a trigger div is needed. This is a div with the class of "tooltip"
35 # that contains this method wrapped in a span with the class of "tip"
35 # that contains this method wrapped in a span with the class of "tip"
36 #
36 #
37 # <div class="tooltip"><%= link_to_issue(issue) %>
37 # <div class="tooltip"><%= link_to_issue(issue) %>
38 # <span class="tip"><%= render_issue_tooltip(issue) %></span>
38 # <span class="tip"><%= render_issue_tooltip(issue) %></span>
39 # </div>
39 # </div>
40 #
40 #
41 def render_issue_tooltip(issue)
41 def render_issue_tooltip(issue)
42 @cached_label_status ||= l(:field_status)
42 @cached_label_status ||= l(:field_status)
43 @cached_label_start_date ||= l(:field_start_date)
43 @cached_label_start_date ||= l(:field_start_date)
44 @cached_label_due_date ||= l(:field_due_date)
44 @cached_label_due_date ||= l(:field_due_date)
45 @cached_label_assigned_to ||= l(:field_assigned_to)
45 @cached_label_assigned_to ||= l(:field_assigned_to)
46 @cached_label_priority ||= l(:field_priority)
46 @cached_label_priority ||= l(:field_priority)
47 @cached_label_project ||= l(:field_project)
47 @cached_label_project ||= l(:field_project)
48
48
49 link_to_issue(issue) + "<br /><br />" +
49 link_to_issue(issue) + "<br /><br />" +
50 "<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" +
50 "<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" +
51 "<strong>#{@cached_label_status}</strong>: #{issue.status.name}<br />" +
51 "<strong>#{@cached_label_status}</strong>: #{issue.status.name}<br />" +
52 "<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
52 "<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
53 "<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
53 "<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
54 "<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />" +
54 "<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />" +
55 "<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}"
55 "<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}"
56 end
56 end
57
57
58 def render_issue_subject_with_tree(issue)
58 def render_issue_subject_with_tree(issue)
59 s = ''
59 s = ''
60 issue.ancestors.each do |ancestor|
60 issue.ancestors.each do |ancestor|
61 s << '<div>' + content_tag('p', link_to_issue(ancestor))
61 s << '<div>' + content_tag('p', link_to_issue(ancestor))
62 end
62 end
63 s << '<div>' + content_tag('h3', h(issue.subject))
63 s << '<div>' + content_tag('h3', h(issue.subject))
64 s << '</div>' * (issue.ancestors.size + 1)
64 s << '</div>' * (issue.ancestors.size + 1)
65 s
65 s
66 end
66 end
67
67
68 def render_descendants_tree(issue)
68 def render_descendants_tree(issue)
69 s = '<form><table class="list issues">'
69 s = '<form><table class="list issues">'
70 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
70 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
71 s << content_tag('tr',
71 s << content_tag('tr',
72 content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
72 content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
73 content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
73 content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
74 content_tag('td', h(child.status)) +
74 content_tag('td', h(child.status)) +
75 content_tag('td', link_to_user(child.assigned_to)) +
75 content_tag('td', link_to_user(child.assigned_to)) +
76 content_tag('td', progress_bar(child.done_ratio, :width => '80px')),
76 content_tag('td', progress_bar(child.done_ratio, :width => '80px')),
77 :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}")
77 :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}")
78 end
78 end
79 s << '</form></table>'
79 s << '</form></table>'
80 s
80 s
81 end
81 end
82
82
83 def render_custom_fields_rows(issue)
83 def render_custom_fields_rows(issue)
84 return if issue.custom_field_values.empty?
84 return if issue.custom_field_values.empty?
85 ordered_values = []
85 ordered_values = []
86 half = (issue.custom_field_values.size / 2.0).ceil
86 half = (issue.custom_field_values.size / 2.0).ceil
87 half.times do |i|
87 half.times do |i|
88 ordered_values << issue.custom_field_values[i]
88 ordered_values << issue.custom_field_values[i]
89 ordered_values << issue.custom_field_values[i + half]
89 ordered_values << issue.custom_field_values[i + half]
90 end
90 end
91 s = "<tr>\n"
91 s = "<tr>\n"
92 n = 0
92 n = 0
93 ordered_values.compact.each do |value|
93 ordered_values.compact.each do |value|
94 s << "</tr>\n<tr>\n" if n > 0 && (n % 2) == 0
94 s << "</tr>\n<tr>\n" if n > 0 && (n % 2) == 0
95 s << "\t<th>#{ h(value.custom_field.name) }:</th><td>#{ simple_format_without_paragraph(h(show_value(value))) }</td>\n"
95 s << "\t<th>#{ h(value.custom_field.name) }:</th><td>#{ simple_format_without_paragraph(h(show_value(value))) }</td>\n"
96 n += 1
96 n += 1
97 end
97 end
98 s << "</tr>\n"
98 s << "</tr>\n"
99 s
99 s
100 end
100 end
101
101
102 def sidebar_queries
102 def sidebar_queries
103 unless @sidebar_queries
103 unless @sidebar_queries
104 # User can see public queries and his own queries
104 # User can see public queries and his own queries
105 visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
105 visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
106 # Project specific queries and global queries
106 # Project specific queries and global queries
107 visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
107 visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
108 @sidebar_queries = Query.find(:all,
108 @sidebar_queries = Query.find(:all,
109 :select => 'id, name, is_public',
109 :select => 'id, name, is_public',
110 :order => "name ASC",
110 :order => "name ASC",
111 :conditions => visible.conditions)
111 :conditions => visible.conditions)
112 end
112 end
113 @sidebar_queries
113 @sidebar_queries
114 end
114 end
115
115
116 def query_links(title, queries)
116 def query_links(title, queries)
117 # links to #index on issues/show
118 url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params
119
117 content_tag('h3', title) +
120 content_tag('h3', title) +
118 queries.collect {|query|
121 queries.collect {|query|
119 link_to(h(query.name), :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query)
122 link_to(h(query.name), url_params.merge(:query_id => query))
120 }.join('<br />')
123 }.join('<br />')
121 end
124 end
122
125
123 def render_sidebar_queries
126 def render_sidebar_queries
124 out = ''
127 out = ''
125 queries = sidebar_queries.select {|q| !q.is_public?}
128 queries = sidebar_queries.select {|q| !q.is_public?}
126 out << query_links(l(:label_my_queries), queries) if queries.any?
129 out << query_links(l(:label_my_queries), queries) if queries.any?
127 queries = sidebar_queries.select {|q| q.is_public?}
130 queries = sidebar_queries.select {|q| q.is_public?}
128 out << query_links(l(:label_query_plural), queries) if queries.any?
131 out << query_links(l(:label_query_plural), queries) if queries.any?
129 out
132 out
130 end
133 end
131
134
132 def show_detail(detail, no_html=false)
135 def show_detail(detail, no_html=false)
133 case detail.property
136 case detail.property
134 when 'attr'
137 when 'attr'
135 field = detail.prop_key.to_s.gsub(/\_id$/, "")
138 field = detail.prop_key.to_s.gsub(/\_id$/, "")
136 label = l(("field_" + field).to_sym)
139 label = l(("field_" + field).to_sym)
137 case
140 case
138 when ['due_date', 'start_date'].include?(detail.prop_key)
141 when ['due_date', 'start_date'].include?(detail.prop_key)
139 value = format_date(detail.value.to_date) if detail.value
142 value = format_date(detail.value.to_date) if detail.value
140 old_value = format_date(detail.old_value.to_date) if detail.old_value
143 old_value = format_date(detail.old_value.to_date) if detail.old_value
141
144
142 when ['project_id', 'status_id', 'tracker_id', 'assigned_to_id', 'priority_id', 'category_id', 'fixed_version_id'].include?(detail.prop_key)
145 when ['project_id', 'status_id', 'tracker_id', 'assigned_to_id', 'priority_id', 'category_id', 'fixed_version_id'].include?(detail.prop_key)
143 value = find_name_by_reflection(field, detail.value)
146 value = find_name_by_reflection(field, detail.value)
144 old_value = find_name_by_reflection(field, detail.old_value)
147 old_value = find_name_by_reflection(field, detail.old_value)
145
148
146 when detail.prop_key == 'estimated_hours'
149 when detail.prop_key == 'estimated_hours'
147 value = "%0.02f" % detail.value.to_f unless detail.value.blank?
150 value = "%0.02f" % detail.value.to_f unless detail.value.blank?
148 old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank?
151 old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank?
149
152
150 when detail.prop_key == 'parent_id'
153 when detail.prop_key == 'parent_id'
151 label = l(:field_parent_issue)
154 label = l(:field_parent_issue)
152 value = "##{detail.value}" unless detail.value.blank?
155 value = "##{detail.value}" unless detail.value.blank?
153 old_value = "##{detail.old_value}" unless detail.old_value.blank?
156 old_value = "##{detail.old_value}" unless detail.old_value.blank?
154 end
157 end
155 when 'cf'
158 when 'cf'
156 custom_field = CustomField.find_by_id(detail.prop_key)
159 custom_field = CustomField.find_by_id(detail.prop_key)
157 if custom_field
160 if custom_field
158 label = custom_field.name
161 label = custom_field.name
159 value = format_value(detail.value, custom_field.field_format) if detail.value
162 value = format_value(detail.value, custom_field.field_format) if detail.value
160 old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value
163 old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value
161 end
164 end
162 when 'attachment'
165 when 'attachment'
163 label = l(:label_attachment)
166 label = l(:label_attachment)
164 end
167 end
165 call_hook(:helper_issues_show_detail_after_setting, {:detail => detail, :label => label, :value => value, :old_value => old_value })
168 call_hook(:helper_issues_show_detail_after_setting, {:detail => detail, :label => label, :value => value, :old_value => old_value })
166
169
167 label ||= detail.prop_key
170 label ||= detail.prop_key
168 value ||= detail.value
171 value ||= detail.value
169 old_value ||= detail.old_value
172 old_value ||= detail.old_value
170
173
171 unless no_html
174 unless no_html
172 label = content_tag('strong', label)
175 label = content_tag('strong', label)
173 old_value = content_tag("i", h(old_value)) if detail.old_value
176 old_value = content_tag("i", h(old_value)) if detail.old_value
174 old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?)
177 old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?)
175 if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key)
178 if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key)
176 # Link to the attachment if it has not been removed
179 # Link to the attachment if it has not been removed
177 value = link_to_attachment(a)
180 value = link_to_attachment(a)
178 else
181 else
179 value = content_tag("i", h(value)) if value
182 value = content_tag("i", h(value)) if value
180 end
183 end
181 end
184 end
182
185
183 if !detail.value.blank?
186 if !detail.value.blank?
184 case detail.property
187 case detail.property
185 when 'attr', 'cf'
188 when 'attr', 'cf'
186 if !detail.old_value.blank?
189 if !detail.old_value.blank?
187 l(:text_journal_changed, :label => label, :old => old_value, :new => value)
190 l(:text_journal_changed, :label => label, :old => old_value, :new => value)
188 else
191 else
189 l(:text_journal_set_to, :label => label, :value => value)
192 l(:text_journal_set_to, :label => label, :value => value)
190 end
193 end
191 when 'attachment'
194 when 'attachment'
192 l(:text_journal_added, :label => label, :value => value)
195 l(:text_journal_added, :label => label, :value => value)
193 end
196 end
194 else
197 else
195 l(:text_journal_deleted, :label => label, :old => old_value)
198 l(:text_journal_deleted, :label => label, :old => old_value)
196 end
199 end
197 end
200 end
198
201
199 # Find the name of an associated record stored in the field attribute
202 # Find the name of an associated record stored in the field attribute
200 def find_name_by_reflection(field, id)
203 def find_name_by_reflection(field, id)
201 association = Issue.reflect_on_association(field.to_sym)
204 association = Issue.reflect_on_association(field.to_sym)
202 if association
205 if association
203 record = association.class_name.constantize.find_by_id(id)
206 record = association.class_name.constantize.find_by_id(id)
204 return record.name if record
207 return record.name if record
205 end
208 end
206 end
209 end
207
210
208 # Renders issue children recursively
211 # Renders issue children recursively
209 def render_api_issue_children(issue, api)
212 def render_api_issue_children(issue, api)
210 return if issue.leaf?
213 return if issue.leaf?
211 api.array :children do
214 api.array :children do
212 issue.children.each do |child|
215 issue.children.each do |child|
213 api.issue(:id => child.id) do
216 api.issue(:id => child.id) do
214 api.tracker(:id => child.tracker_id, :name => child.tracker.name) unless child.tracker.nil?
217 api.tracker(:id => child.tracker_id, :name => child.tracker.name) unless child.tracker.nil?
215 api.subject child.subject
218 api.subject child.subject
216 render_api_issue_children(child, api)
219 render_api_issue_children(child, api)
217 end
220 end
218 end
221 end
219 end
222 end
220 end
223 end
221
224
222 def issues_to_csv(issues, project = nil)
225 def issues_to_csv(issues, project = nil)
223 ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
226 ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
224 decimal_separator = l(:general_csv_decimal_separator)
227 decimal_separator = l(:general_csv_decimal_separator)
225 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
228 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
226 # csv header fields
229 # csv header fields
227 headers = [ "#",
230 headers = [ "#",
228 l(:field_status),
231 l(:field_status),
229 l(:field_project),
232 l(:field_project),
230 l(:field_tracker),
233 l(:field_tracker),
231 l(:field_priority),
234 l(:field_priority),
232 l(:field_subject),
235 l(:field_subject),
233 l(:field_assigned_to),
236 l(:field_assigned_to),
234 l(:field_category),
237 l(:field_category),
235 l(:field_fixed_version),
238 l(:field_fixed_version),
236 l(:field_author),
239 l(:field_author),
237 l(:field_start_date),
240 l(:field_start_date),
238 l(:field_due_date),
241 l(:field_due_date),
239 l(:field_done_ratio),
242 l(:field_done_ratio),
240 l(:field_estimated_hours),
243 l(:field_estimated_hours),
241 l(:field_parent_issue),
244 l(:field_parent_issue),
242 l(:field_created_on),
245 l(:field_created_on),
243 l(:field_updated_on)
246 l(:field_updated_on)
244 ]
247 ]
245 # Export project custom fields if project is given
248 # Export project custom fields if project is given
246 # otherwise export custom fields marked as "For all projects"
249 # otherwise export custom fields marked as "For all projects"
247 custom_fields = project.nil? ? IssueCustomField.for_all : project.all_issue_custom_fields
250 custom_fields = project.nil? ? IssueCustomField.for_all : project.all_issue_custom_fields
248 custom_fields.each {|f| headers << f.name}
251 custom_fields.each {|f| headers << f.name}
249 # Description in the last column
252 # Description in the last column
250 headers << l(:field_description)
253 headers << l(:field_description)
251 csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
254 csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
252 # csv lines
255 # csv lines
253 issues.each do |issue|
256 issues.each do |issue|
254 fields = [issue.id,
257 fields = [issue.id,
255 issue.status.name,
258 issue.status.name,
256 issue.project.name,
259 issue.project.name,
257 issue.tracker.name,
260 issue.tracker.name,
258 issue.priority.name,
261 issue.priority.name,
259 issue.subject,
262 issue.subject,
260 issue.assigned_to,
263 issue.assigned_to,
261 issue.category,
264 issue.category,
262 issue.fixed_version,
265 issue.fixed_version,
263 issue.author.name,
266 issue.author.name,
264 format_date(issue.start_date),
267 format_date(issue.start_date),
265 format_date(issue.due_date),
268 format_date(issue.due_date),
266 issue.done_ratio,
269 issue.done_ratio,
267 issue.estimated_hours.to_s.gsub('.', decimal_separator),
270 issue.estimated_hours.to_s.gsub('.', decimal_separator),
268 issue.parent_id,
271 issue.parent_id,
269 format_time(issue.created_on),
272 format_time(issue.created_on),
270 format_time(issue.updated_on)
273 format_time(issue.updated_on)
271 ]
274 ]
272 custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) }
275 custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) }
273 fields << issue.description
276 fields << issue.description
274 csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
277 csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
275 end
278 end
276 end
279 end
277 export
280 export
278 end
281 end
279 end
282 end
General Comments 0
You need to be logged in to leave comments. Login now