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 = {})
|