Feature #465 » 33-add_versions_inheritance-0.4.0.patch
app/controllers/issues_controller.rb | ||
---|---|---|
19 | 19 |
menu_item :new_issue, :only => :new |
20 | 20 |
|
21 | 21 |
before_filter :find_issue, :only => [:show, :edit, :reply] |
22 |
before_filter :check_issue_perms, :only => [:show, :edit] |
|
22 | 23 |
before_filter :find_issues, :only => [:bulk_edit, :move, :destroy] |
23 | 24 |
before_filter :find_project, :only => [:new, :update_form, :preview] |
24 | 25 |
before_filter :authorize, :except => [:index, :changes, :gantt, :calendar, :preview, :update_form, :context_menu] |
... | ... | |
63 | 64 |
:conditions => @query.statement, |
64 | 65 |
:limit => limit, |
65 | 66 |
:offset => @issue_pages.current.offset |
67 |
@issues.map!{ |issue| issue_without_hidden_fields(issue) } # don't show forbidden fields |
|
66 | 68 |
respond_to do |format| |
67 | 69 |
format.html { |
68 | 70 |
if @query.grouped? |
... | ... | |
113 | 115 |
@changesets.reverse! if User.current.wants_comments_in_reverse_order? |
114 | 116 |
@allowed_statuses = @issue.new_statuses_allowed_to(User.current) |
115 | 117 |
@edit_allowed = User.current.allowed_to?(:edit_issues, @project) |
118 |
@issue = issue_without_hidden_fields(@issue) |
|
119 |
@journals = journals_without_hidden_entries(@journals) |
|
116 | 120 |
@priorities = IssuePriority.all |
117 | 121 |
@time_entry = TimeEntry.new |
118 | 122 |
respond_to do |format| |
... | ... | |
355 | 359 |
events += Version.find(:all, :include => :project, |
356 | 360 |
:conditions => ["(#{@query.project_statement}) AND effective_date BETWEEN ? AND ?", @gantt.date_from, @gantt.date_to]) |
357 | 361 |
|
362 | ||
363 |
events += @project.related_versions.select { |v| ((v.project.id != @project.id) && (@gantt.date_from..@gantt.date_to).include?(v.effective_date)) } |
|
364 | ||
358 | 365 |
@gantt.events = events |
359 | 366 |
end |
360 | 367 |
|
... | ... | |
387 | 394 |
) |
388 | 395 |
events += Version.find(:all, :include => :project, |
389 | 396 |
:conditions => ["(#{@query.project_statement}) AND effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt]) |
390 |
|
|
397 | ||
398 |
events += @project.related_versions.select { |v| ((v.project.id != @project.id) && (@calendar.startdt..@calendar.enddt).include?(v.effective_date)) } |
|
399 |
|
|
391 | 400 |
@calendar.events = events |
392 | 401 |
end |
393 | 402 |
|
... | ... | |
471 | 480 |
render_404 |
472 | 481 |
end |
473 | 482 |
|
483 |
def issue_fixed_version_allowed?(issue) |
|
484 |
((not issue.fixed_version) || |
|
485 |
(User.current.allowed_to?(:view_issues, |
|
486 |
issue.fixed_version.project))) |
|
487 |
end |
|
488 | ||
489 |
def check_issue_perms |
|
490 |
@forbidden_fixed_version = (not issue_fixed_version_allowed?(@issue)) |
|
491 |
end |
|
492 | ||
493 |
## Filter journals to remove non allowed entries. We want here |
|
494 |
## to handle the _specific case_ of a user 'Joe' browsing 'Project |
|
495 |
## B' issues. 'Project B' is a subproject of 'Project A' and |
|
496 |
## inherits its versions. Joe can't see 'Project A, but issue |
|
497 |
## fixed_versions has been set at some point to a version belonging |
|
498 |
## to 'Project A', by an other member of 'Project B'. Joe should not |
|
499 |
## see this sensitive information. |
|
500 |
def journals_without_hidden_entries(journals) |
|
501 |
p = @project |
|
502 |
forbidden_parents = [] |
|
503 |
while p = p.parent do |
|
504 |
forbidden_parents.push p.id unless User.current.allowed_to?(:view_issues, p) |
|
505 |
end |
|
506 | ||
507 |
unless (journals.empty? || forbidden_parents.empty?) |
|
508 |
journals = journals.dup |
|
509 |
journals.delete_if do |j| |
|
510 |
j.details.map{ |d| (d.property == 'attr' && |
|
511 |
d.prop_key == 'fixed_version_id' && |
|
512 |
( |
|
513 |
(d.old_value && forbidden_parents.include?(Version.find(d.old_value.to_i).project_id)) || |
|
514 |
(d.value && forbidden_parents.include?(Version.find(d.value.to_i).project_id)) |
|
515 |
) |
|
516 |
) }.include?(true) |
|
517 |
end |
|
518 |
end |
|
519 |
journals |
|
520 |
end |
|
521 | ||
522 |
## Filter issue to remove non allowed fields. For more information, |
|
523 |
## see documentation of journals_without_hidden_entries |
|
524 |
def issue_without_hidden_fields(issue) |
|
525 |
unless issue_fixed_version_allowed?(issue) |
|
526 |
issue = issue.dup |
|
527 |
issue.fixed_version = nil |
|
528 |
end |
|
529 |
issue |
|
530 |
end |
|
531 |
|
|
474 | 532 |
# Retrieve query from session or build a new query |
475 | 533 |
def retrieve_query |
476 | 534 |
if !params[:query_id].blank? |
app/controllers/projects_controller.rb | ||
---|---|---|
221 | 221 | |
222 | 222 |
def add_file |
223 | 223 |
if request.post? |
224 |
container = (params[:version_id].blank? ? @project : @project.versions.find_by_id(params[:version_id]))
|
|
224 |
container = (params[:version_id].blank? ? @project : @project.related_versions.find { |v| v.id.to_s == params[:version_id] })
|
|
225 | 225 |
attachments = attach_files(container, params[:attachments]) |
226 | 226 |
if !attachments.empty? && Setting.notified_events.include?('file_added') |
227 | 227 |
Mailer.deliver_attachments_added(attachments) |
... | ... | |
229 | 229 |
redirect_to :controller => 'projects', :action => 'list_files', :id => @project |
230 | 230 |
return |
231 | 231 |
end |
232 |
@versions = @project.versions.sort |
|
232 |
@versions = @project.related_versions.sort
|
|
233 | 233 |
end |
234 | 234 |
|
235 | 235 |
def list_files |
... | ... | |
240 | 240 |
'downloads' => "#{Attachment.table_name}.downloads" |
241 | 241 |
|
242 | 242 |
@containers = [ Project.find(@project.id, :include => :attachments, :order => sort_clause)] |
243 |
@containers += @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
|
|
243 |
@containers += Version.find(:all, :include => :attachments, :order => sort_clause, :conditions => ['versions.id IN (?)', @project.related_versions.map {|v| v.id}]).sort.reverse
|
|
244 | 244 |
render :layout => !request.xhr? |
245 | 245 |
end |
246 | 246 |
|
... | ... | |
248 | 248 |
def changelog |
249 | 249 |
@trackers = @project.trackers.find(:all, :conditions => ["is_in_chlog=?", true], :order => 'position') |
250 | 250 |
retrieve_selected_tracker_ids(@trackers) |
251 |
@versions = @project.versions.sort |
|
251 |
@versions = @project.related_versions.sort
|
|
252 | 252 |
end |
253 | 253 | |
254 | 254 |
def roadmap |
255 | 255 |
@trackers = @project.trackers.find(:all, :conditions => ["is_in_roadmap=?", true]) |
256 | 256 |
retrieve_selected_tracker_ids(@trackers) |
257 |
@versions = @project.versions.sort |
|
258 |
@versions = @versions.select {|v| !v.completed? } unless params[:completed] |
|
257 |
@versions = retrieve_related_versions |
|
259 | 258 |
end |
260 | 259 |
|
261 | 260 |
def activity |
... | ... | |
316 | 315 |
render_404 |
317 | 316 |
end |
318 | 317 | |
318 |
def retrieve_related_versions |
|
319 |
related_versions=@project.related_versions |
|
320 |
# should this test be moved to projects_helper.rb : version_visible_issues ? |
|
321 |
params[:completed] ? related_versions : related_versions.select {|v| !v.completed? } |
|
322 |
end |
|
323 | ||
319 | 324 |
def retrieve_selected_tracker_ids(selectable_trackers) |
320 | 325 |
if ids = params[:tracker_ids] |
321 | 326 |
@selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s } |
app/controllers/reports_controller.rb | ||
---|---|---|
31 | 31 |
render :template => "reports/issue_report_details" |
32 | 32 |
when "version" |
33 | 33 |
@field = "fixed_version_id" |
34 |
@rows = @project.versions.sort |
|
34 |
@rows = @project.related_versions.sort
|
|
35 | 35 |
@data = issues_by_version |
36 | 36 |
@report_title = l(:field_version) |
37 | 37 |
render :template => "reports/issue_report_details" |
... | ... | |
67 | 67 |
render :template => "reports/issue_report_details" |
68 | 68 |
else |
69 | 69 |
@trackers = @project.trackers |
70 |
@versions = @project.versions.sort |
|
70 |
@versions = @project.related_versions.sort
|
|
71 | 71 |
@priorities = IssuePriority.all |
72 | 72 |
@categories = @project.issue_categories |
73 | 73 |
@assignees = @project.members.collect { |m| m.user } |
app/controllers/versions_controller.rb | ||
---|---|---|
19 | 19 |
menu_item :roadmap |
20 | 20 |
before_filter :find_project, :authorize |
21 | 21 | |
22 |
helper :projects |
|
23 |
include ProjectsHelper |
|
24 | ||
22 | 25 |
def show |
26 |
@issues = version_visible_issues(@version,@project,@project.trackers.collect { |x| x.id.to_s }) |
|
23 | 27 |
end |
24 | 28 |
|
25 | 29 |
def edit |
app/helpers/projects_helper.rb | ||
---|---|---|
33 | 33 |
] |
34 | 34 |
tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} |
35 | 35 |
end |
36 | ||
37 |
## return an array of the issues attached to version that a user should see |
|
38 |
## As a convenience, allow limitation by trackers with Array of tracker_ids |
|
39 |
def version_visible_issues(version,project,tracker_ids=[],user=User.current) |
|
40 |
# Returns void when user can not see issues or if tracker_ids is void |
|
41 |
return [] if ((not user.allowed_to?(:view_issues, |
|
42 |
version.project)) or |
|
43 |
tracker_ids.empty?) |
|
44 |
# user can see project issues, carry on, retrieve them ... |
|
45 |
issues = version. |
|
46 |
fixed_issues.find(:all, |
|
47 |
:include => [:status, :tracker], |
|
48 |
:conditions => ["tracker_id in (#{tracker_ids.join(',')})"], |
|
49 |
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") |
|
50 |
# Only keep issues from self, parent or children, |
|
51 |
related_projects = project.self_and_descendants.map { |t_item| t_item.id } |
|
52 | ||
53 |
# do we need parents at all? |
|
54 |
p = project |
|
55 |
while p = p.parent do |
|
56 |
related_projects.push p.id |
|
57 |
end |
|
58 |
related_projects = related_projects.select{|x| user.allowed_to?(:view_issues, Project.find(x))} |
|
59 |
|
|
60 |
# now only keep related issues. (issues from brother projects are discarded) |
|
61 |
issues.select {|x| related_projects.include?(x.project.id) } |
|
62 |
end |
|
63 | ||
64 |
def grouped_versions_for_select(versions_list) |
|
65 |
return [] if versions_list == nil |
|
66 | ||
67 |
grouped_structure = [] |
|
68 |
versions_list.each do |prj, ver| |
|
69 |
grouped_structure.push [prj.name, ver.collect { |v| [v.name, v.id] }] |
|
70 |
end |
|
71 |
grouped_structure |
|
72 |
end |
|
36 | 73 |
|
37 | 74 |
def parent_project_select_tag(project) |
38 | 75 |
options = '<option></option>' + project_tree_options_for_select(project.possible_parents, :selected => project.parent) |
app/models/project.rb | ||
---|---|---|
274 | 274 |
members.select {|m| m.mail_notification? || m.user.mail_notification?}.collect {|m| m.user.mail} |
275 | 275 |
end |
276 | 276 |
|
277 |
## Return versions attached to self, and to parents if relevant. |
|
278 |
## Sorting is done in the SQL request to take advantage of cache |
|
279 |
def related_versions(user=User.current) |
|
280 |
p = self |
|
281 |
parent_ids = [self.id] |
|
282 |
while p = p.parent do |
|
283 |
parent_ids.push p.id if user.allowed_to?(:view_issues, p) |
|
284 |
end |
|
285 | ||
286 |
Version.find(:all, |
|
287 |
:conditions => {:project_id => parent_ids}, |
|
288 |
:order => "effective_date ASC, name ASC ") |
|
289 |
end |
|
290 |
|
|
291 |
def grouped_versions(version_list=nil, user=User.current) |
|
292 |
version_list ||= related_versions(user) |
|
293 | ||
294 |
p, i = self, 0 |
|
295 |
parent_nesting = {} |
|
296 |
parent_nesting[p.id] = i |
|
297 | ||
298 |
while p = p.parent do |
|
299 |
i += 1 |
|
300 |
parent_nesting[p.id] = i |
|
301 |
end |
|
302 | ||
303 |
version_list.group_by(&:project).sort_by { |item| parent_nesting[item.first.id] } |
|
304 |
end |
|
305 | ||
277 | 306 |
# Returns an array of all custom fields enabled for project issues |
278 | 307 |
# (explictly associated custom fields and custom fields enabled for all projects) |
279 | 308 |
def all_issue_custom_fields |
app/models/query.rb | ||
---|---|---|
89 | 89 |
@@operators_by_filter_type = { :list => [ "=", "!" ], |
90 | 90 |
:list_status => [ "o", "=", "!", "c", "*" ], |
91 | 91 |
:list_optional => [ "=", "!", "!*", "*" ], |
92 |
:list_grouped => [ "=", "!", "!*", "*" ], |
|
92 | 93 |
:list_subprojects => [ "*", "!*", "=" ], |
93 | 94 |
:date => [ "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-" ], |
94 | 95 |
:date_past => [ ">t-", "<t-", "t-", "t", "w" ], |
... | ... | |
117 | 118 |
] |
118 | 119 |
cattr_reader :available_columns |
119 | 120 |
|
121 |
include ProjectsHelper |
|
122 | ||
120 | 123 |
def initialize(attributes = nil) |
121 | 124 |
super attributes |
122 | 125 |
self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} } |
... | ... | |
181 | 184 |
unless @project.issue_categories.empty? |
182 | 185 |
@available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } } |
183 | 186 |
end |
184 |
unless @project.versions.empty? |
|
185 |
@available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } } |
|
187 |
unless @project.related_versions.empty? |
|
188 |
@available_filters["fixed_version_id"] = { :type => :list_grouped, |
|
189 |
:order => 7, |
|
190 |
:values => grouped_versions_for_select(@project.grouped_versions) } |
|
186 | 191 |
end |
187 | 192 |
unless @project.descendants.active.empty? |
188 | 193 |
@available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.descendants.visible.collect{|s| [s.name, s.id.to_s] } } |
app/views/issues/_form.rhtml | ||
---|---|---|
32 | 32 |
{:controller => 'projects', :action => 'add_issue_category', :id => @project}, |
33 | 33 |
:class => 'small', :tabindex => 199) if authorize_for('projects', 'add_issue_category') %></p> |
34 | 34 |
<% end %> |
35 |
<%= content_tag('p', f.select(:fixed_version_id, |
|
36 |
(@project.versions.sort.collect {|v| [v.name, v.id]}), |
|
37 |
{ :include_blank => true })) unless @project.versions.empty? %> |
|
35 |
<% unless (@project.related_versions.empty? || @forbidden_fixed_version) then %> |
|
36 |
<%= content_tag('p', f.select_ex(:fixed_version_id, |
|
37 |
grouped_versions_for_select(@project.grouped_versions), |
|
38 |
{ :include_blank => true})) %> |
|
39 |
<% end %> |
|
38 | 40 |
</div> |
39 | 41 | |
40 | 42 |
<div class="splitcontentright"> |
app/views/issues/_form_update.rhtml | ||
---|---|---|
5 | 5 |
</div> |
6 | 6 |
<div class="splitcontentright"> |
7 | 7 |
<p><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></p> |
8 |
<%= content_tag('p', f.select(:fixed_version_id, |
|
9 |
(@project.versions.sort.collect {|v| [v.name, v.id]}), |
|
10 |
{ :include_blank => true })) unless @project.versions.empty? %> |
|
8 |
<%= unless (@issue.fixed_version && |
|
9 |
(not User.current.allowed_to?(:view_issues, |
|
10 |
@issue.fixed_version.project)) || |
|
11 |
@project.related_versions.empty?) then |
|
12 |
content_tag('p', f.select_ex(:fixed_version_id, |
|
13 |
grouped_versions_for_select(@project.grouped_versions), |
|
14 |
{ :include_blank => true })) |
|
15 |
end %> |
|
11 | 16 |
</div> |
12 | 17 |
</div> |
app/views/issues/bulk_edit.rhtml | ||
---|---|---|
27 | 27 |
<label><%= l(:field_fixed_version) %>: |
28 | 28 |
<%= select_tag('fixed_version_id', content_tag('option', l(:label_no_change_option), :value => '') + |
29 | 29 |
content_tag('option', l(:label_none), :value => 'none') + |
30 |
options_from_collection_for_select(@project.versions.sort, :id, :name)) %></label>
|
|
30 |
grouped_options_for_select(grouped_versions_for_select(@project.grouped_versions))) %></label>
|
|
31 | 31 |
</p> |
32 | 32 | |
33 | 33 |
<p> |
app/views/issues/context_menu.rhtml | ||
---|---|---|
27 | 27 |
<% end -%> |
28 | 28 |
</ul> |
29 | 29 |
</li> |
30 |
<% unless @project.nil? || @project.versions.empty? -%> |
|
30 |
<% unless @project.nil? || @project.related_versions.empty? -%>
|
|
31 | 31 |
<li class="folder"> |
32 | 32 |
<a href="#" class="submenu"><%= l(:field_fixed_version) %></a> |
33 | 33 |
<ul> |
34 |
<% @project.versions.sort.each do |v| -%> |
|
35 |
<li><%= context_menu_link v.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), 'fixed_version_id' => v, :back_to => @back}, :method => :post, |
|
36 |
:selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %></li> |
|
37 |
<% end -%> |
|
34 |
<% @project.grouped_versions.each do |p, vv| -%> |
|
35 |
<li class="<%= "folder" unless @project.id == p.id %>"> |
|
36 |
<% unless @project.id == p.id %> |
|
37 |
<a href="#" class="submenu"><%= p.name %></a> |
|
38 |
<ul> |
|
39 |
<% end %> |
|
40 |
<% vv.each do |v| %> |
|
41 |
<li><%= context_menu_link v.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), 'fixed_version_id' => v, :back_to => @back}, :method => :post, :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %></li> |
|
42 |
<% end %> |
|
43 |
<% unless @project.id == p.id %> |
|
44 |
</ul> |
|
45 |
<% end %> |
|
46 |
</li> |
|
47 |
<% end -%> |
|
38 | 48 |
<li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), 'fixed_version_id' => 'none', :back_to => @back}, :method => :post, |
39 | 49 |
:selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %></li> |
40 | 50 |
</ul> |
app/views/projects/add_file.rhtml | ||
---|---|---|
7 | 7 |
<% if @versions.any? %> |
8 | 8 |
<p><label for="version_id"><%=l(:field_version)%></label> |
9 | 9 |
<%= select_tag "version_id", content_tag('option', '') + |
10 |
options_from_collection_for_select(@versions, "id", "name") %></p>
|
|
10 |
grouped_options_for_select(grouped_versions_for_select(@project.grouped_versions)) %></p>
|
|
11 | 11 |
<% end %> |
12 | 12 | |
13 | 13 |
<p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p> |
app/views/projects/roadmap.rhtml | ||
---|---|---|
4 | 4 |
<p class="nodata"><%= l(:label_no_data) %></p> |
5 | 5 |
<% else %> |
6 | 6 |
<div id="roadmap"> |
7 |
<% @versions.each do |version| %> |
|
7 |
<% grouped_versions = @project.grouped_versions(@versions) %> |
|
8 |
<% grouped_versions.each do |projects, versions_in_project| %> |
|
9 |
<% unless @project.id == projects.id %> |
|
10 |
<fieldset> |
|
11 |
<legend><h3><%= l(:label_project) %>: <%= link_to h(projects.name), :controller => 'projects', :action => 'show', :id => projects, :jump => 'roadmap' %></h3></legend> |
|
12 |
<% end %> |
|
13 |
<% versions_in_project.each do |version| %> |
|
14 | ||
15 |
<% issues = version_visible_issues(version,@project,@selected_tracker_ids) %> |
|
16 | ||
8 | 17 |
<%= tag 'a', :name => version.name %> |
9 | 18 |
<h3 class="icon22 icon22-package"><%= link_to h(version.name), :controller => 'versions', :action => 'show', :id => version %></h3> |
10 | 19 |
<%= render :partial => 'versions/overview', :locals => {:version => version} %> |
11 | 20 |
<%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %> |
12 | 21 | |
13 |
<% issues = version.fixed_issues.find(:all, |
|
14 |
:include => [:status, :tracker], |
|
15 |
:conditions => ["tracker_id in (#{@selected_tracker_ids.join(',')})"], |
|
16 |
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") unless @selected_tracker_ids.empty? |
|
17 |
issues ||= [] |
|
18 |
%> |
|
19 | 22 |
<% if issues.size > 0 %> |
20 | 23 |
<fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend> |
21 | 24 |
<ul> |
22 | 25 |
<%- issues.each do |issue| -%> |
23 |
<li><%= link_to_issue(issue) %>: <%=h issue.subject %></li> |
|
26 |
<li><%= link_to_issue(issue) %>: <%=h issue.subject %> <%= (" <em>(<b>" + l(:label_project) + "</b>: " + issue.project.name + ")</em>") unless issue.project.id == @project.id %></li>
|
|
24 | 27 |
<%- end -%> |
25 | 28 |
</ul> |
26 | 29 |
</fieldset> |
27 | 30 |
<% end %> |
28 | 31 |
<%= call_hook :view_projects_roadmap_version_bottom, :version => version %> |
32 |
<% end %> |
|
33 | ||
34 |
<% unless @project.id == projects.id %> |
|
35 |
</fieldset> |
|
36 |
<% end %> |
|
29 | 37 |
<% end %> |
30 | 38 |
</div> |
31 | 39 |
<% end %> |
app/views/queries/_filters.rhtml | ||
---|---|---|
74 | 74 |
<td> |
75 | 75 |
<div id="div_values_<%= field %>" style="display:none;"> |
76 | 76 |
<% case options[:type] |
77 |
when :list, :list_optional, :list_status, :list_subprojects %> |
|
77 |
when :list, :list_optional, :list_grouped, :list_status, :list_subprojects %>
|
|
78 | 78 |
<select <%= "multiple=true" if query.values_for(field) and query.values_for(field).length > 1 %> name="values[<%= field %>][]" id="values_<%= field %>" class="select-small" style="vertical-align: top;"> |
79 |
<% if options[:type] == :list_grouped %> |
|
80 |
<%= grouped_options_for_select options[:values], query.values_for(field) %> |
|
81 |
<% else %> |
|
79 | 82 |
<%= options_for_select options[:values], query.values_for(field) %> |
83 |
<% end %> |
|
80 | 84 |
</select> |
81 | 85 |
<%= link_to_function image_tag('bullet_toggle_plus.png'), "toggle_multi_select('#{field}');", :style => "vertical-align: bottom;" %> |
82 | 86 |
<% when :date, :date_past %> |
app/views/versions/show.rhtml | ||
---|---|---|
32 | 32 |
<%= render :partial => 'versions/overview', :locals => {:version => @version} %> |
33 | 33 |
<%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %> |
34 | 34 | |
35 |
<% issues = @version.fixed_issues.find(:all, |
|
36 |
:include => [:status, :tracker], |
|
37 |
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") %> |
|
38 |
<% if issues.size > 0 %> |
|
35 |
<% if @issues.size > 0 %> |
|
39 | 36 |
<fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend> |
40 | 37 |
<ul> |
41 |
<% issues.each do |issue| -%> |
|
42 |
<li><%= link_to_issue(issue) %>: <%=h issue.subject %></li> |
|
38 |
<% @issues.each do |issue| -%>
|
|
39 |
<li><%= link_to_issue(issue) %>: <%=h issue.subject %> <%= (" <em>(" + issue.project.name + ")</em>") unless issue.project.id == @project.id %></li>
|
|
43 | 40 |
<% end -%> |
44 | 41 |
</ul> |
45 | 42 |
</fieldset> |
lib/redmine.rb | ||
---|---|---|
133 | 133 |
menu.push :overview, { :controller => 'projects', :action => 'show' } |
134 | 134 |
menu.push :activity, { :controller => 'projects', :action => 'activity' } |
135 | 135 |
menu.push :roadmap, { :controller => 'projects', :action => 'roadmap' }, |
136 |
:if => Proc.new { |p| p.versions.any? } |
|
136 |
:if => Proc.new { |p| p.related_versions.any? }
|
|
137 | 137 |
menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural |
138 | 138 |
menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new, |
139 | 139 |
:html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) } |
lib/redmine/core_ext/form_builder.rb | ||
---|---|---|
1 |
require 'action_view/helpers/form_helper' |
|
2 | ||
3 |
module ActionView::Helpers |
|
4 |
module FormOptionsHelper |
|
5 |
def select_ex(object, method, choices, options = {}, html_options = {}) |
|
6 |
InstanceTag.new(object, method, self, options.delete(:object)).to_select_tag_ex(choices, options, html_options) |
|
7 |
end |
|
8 | ||
9 |
def grouped_options_for_select(grouped_options, selected_key = nil, prompt = nil) |
|
10 |
body = '' |
|
11 |
body << content_tag(:option, prompt, :value => "") if prompt |
|
12 | ||
13 |
grouped_options = grouped_options.sort if grouped_options.is_a?(Hash) |
|
14 | ||
15 |
grouped_options.each do |group| |
|
16 |
body << content_tag(:optgroup, options_for_select(group[1], selected_key), :label => group[0]) |
|
17 |
end |
|
18 | ||
19 |
body |
|
20 |
end |
|
21 |
end |
|
22 | ||
23 |
class InstanceTag |
|
24 |
def to_select_tag_ex(choices, options, html_options) |
|
25 |
html_options = html_options.stringify_keys |
|
26 |
add_default_name_and_id(html_options) |
|
27 |
value = value(object) |
|
28 |
selected_value = options.has_key?(:selected) ? options[:selected] : value |
|
29 | ||
30 |
content_tag( |
|
31 |
"select", |
|
32 |
add_options( |
|
33 |
grouped_options_for_select(choices, selected_value), |
|
34 |
options, |
|
35 |
selected_value |
|
36 |
), |
|
37 |
html_options |
|
38 |
) |
|
39 |
end |
|
40 |
end |
|
41 | ||
42 |
class FormBuilder |
|
43 |
def select_ex(method, choices, options = {}, html_options = {}) |
|
44 |
@template.select_ex(@object_name, method, choices, objectify_options(options), @default_options.merge(html_options)) |
|
45 |
end |
|
46 |
end |
|
47 |
end |
lib/redmine/export/pdf.rb | ||
---|---|---|
260 | 260 |
pdf.SetFontStyle('B',9) |
261 | 261 |
pdf.Cell(190,5, l(:label_history), "B") |
262 | 262 |
pdf.Ln |
263 |
for journal in issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
|
|
263 |
for journal in @journals
|
|
264 | 264 |
pdf.SetFontStyle('B',8) |
265 | 265 |
pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name) |
266 | 266 |
pdf.Ln |
lib/tabular_form_builder.rb | ||
---|---|---|
37 | 37 |
def select(field, choices, options = {}, html_options = {}) |
38 | 38 |
label_for_field(field, options) + super |
39 | 39 |
end |
40 | ||
41 |
def select_ex(field, choices, options = {}, html_options = {}) |
|
42 |
label_for_field(field, options) + super |
|
43 |
end |
|
40 | 44 |
|
41 | 45 |
# Returns a label tag for the given field |
42 | 46 |
def label_for_field(field, options = {}) |