Defect #33415 » 0001-Fix-33415-by-re-implementing-31589.patch
app/helpers/issues_helper.rb | ||
---|---|---|
640 | 640 |
end |
641 | 641 |
end |
642 | 642 | |
643 |
# Returns the transition warning message |
|
644 |
# Returns nil if @transition_warnings is nil |
|
645 |
def transition_warning_message(issue) |
|
646 |
tw = issue.transition_warnings |
|
647 |
if !tw.nil? |
|
648 |
if tw.include?(:not_closable_by_open_sub_tasks_and_blocking_issues) |
|
649 |
s = l(:notice_issue_not_closable_by_open_tasks_and_blocking_issue) |
|
650 |
elsif tw.include?(:not_closable_by_open_sub_tasks) |
|
651 |
s = l(:notice_issue_not_closable_by_open_tasks) |
|
652 |
elsif tw.include?(:not_closable_by_open_blocking_issues) |
|
653 |
s = l(:notice_issue_not_closable_by_blocking_issue) |
|
654 |
elsif tw.include?(:not_reopenable_by_closed_parent_issue) |
|
655 |
s = l(:notice_issue_not_reopenable_by_closed_parent_issue) |
|
656 |
end |
|
657 |
return s |
|
658 |
end |
|
659 |
end |
|
660 | ||
643 | 661 |
end |
app/models/issue.rb | ||
---|---|---|
56 | 56 | |
57 | 57 |
DONE_RATIO_OPTIONS = %w(issue_field issue_status) |
58 | 58 | |
59 |
attr_reader :transition_warning |
|
59 |
attr_reader :transition_warnings
|
|
60 | 60 |
attr_writer :deleted_attachment_ids |
61 | 61 |
delegate :notes, :notes=, :private_notes, :private_notes=, :to => :current_journal, :allow_nil => true |
62 | 62 | |
... | ... | |
971 | 971 |
end |
972 | 972 | |
973 | 973 |
# Returns true if this issue can be closed and if not, returns false and populates the reason |
974 |
# This does not take the workflow transitions into account |
|
974 | 975 |
def closable? |
976 |
@transition_warnings ||= [] |
|
975 | 977 |
if descendants.open.any? |
976 |
@transition_warning = l(:notice_issue_not_closable_by_open_tasks) |
|
977 |
return false |
|
978 |
open_sub_tasks = true |
|
978 | 979 |
end |
979 | 980 |
if blocked? |
980 |
@transition_warning = l(:notice_issue_not_closable_by_blocking_issue) |
|
981 |
return false |
|
981 |
open_blocking_issues = true |
|
982 | 982 |
end |
983 |
return true |
|
983 | ||
984 |
if (open_sub_tasks && open_blocking_issues) && !@transition_warnings.include?(:not_closable_by_open_sub_tasks_and_blocking_issues) |
|
985 |
@transition_warnings << :not_closable_by_open_sub_tasks_and_blocking_issues |
|
986 |
elsif open_sub_tasks && !@transition_warnings.include?(:not_closable_by_open_sub_tasks) |
|
987 |
@transition_warnings << :not_closable_by_open_sub_tasks |
|
988 |
elsif open_blocking_issues && !@transition_warnings.include?(:not_closable_by_open_blocking_issues) |
|
989 |
@transition_warnings << :not_closable_by_open_blocking_issues |
|
990 |
end |
|
991 | ||
992 |
open_sub_tasks || open_blocking_issues ? (return false) : (return true) |
|
984 | 993 |
end |
985 | 994 | |
986 |
# Returns true if this issue can be reopen and if not, returns false and populates the reason |
|
995 |
# Returns true if this issue can be reopened and if not, returns false and populates the reason |
|
996 |
# This does not take the workflow transitions into account |
|
987 | 997 |
def reopenable? |
998 |
@transition_warnings ||= [] |
|
988 | 999 |
if ancestors.open(false).any? |
989 |
@transition_warning = l(:notice_issue_not_reopenable_by_closed_parent_issue) |
|
990 |
return false |
|
1000 |
closed_parent_issue = true |
|
991 | 1001 |
end |
992 |
return true |
|
1002 | ||
1003 |
if closed_parent_issue && !@transition_warnings.include?(:not_reopenable_by_closed_parent_issue) |
|
1004 |
@transition_warnings << :not_reopenable_by_closed_parent_issue |
|
1005 |
end |
|
1006 | ||
1007 |
closed_parent_issue ? (return false) : (return true) |
|
993 | 1008 |
end |
994 | 1009 | |
995 | 1010 |
# Returns the default status of the issue based on its tracker |
app/views/issues/_attributes.html.erb | ||
---|---|---|
6 | 6 |
<p> |
7 | 7 |
<%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), {:required => true}, |
8 | 8 |
:onchange => "updateIssueFrom('#{escape_javascript(update_issue_form_path(@project, @issue))}', this)" %> |
9 |
<% if @issue.transition_warning %> |
|
10 |
<span class="icon-only icon-warning" title="<%= @issue.transition_warning %>"><%= @issue.transition_warning %></span>
|
|
9 |
<% if @issue.transition_warnings %>
|
|
10 |
<span class="icon-only icon-warning" title="<%= transition_warning_message(@issue) %>"><%= transition_warning_message(@issue) %></span>
|
|
11 | 11 |
<% end %> |
12 | 12 |
</p> |
13 | 13 |
<%= hidden_field_tag 'was_default_status', @issue.status_id, :id => nil if @issue.status == @issue.default_status %> |
config/locales/en.yml | ||
---|---|---|
193 | 193 |
notice_issue_not_closable_by_open_tasks: "This issue cannot be closed because it has at least one open subtask." |
194 | 194 |
notice_issue_not_closable_by_blocking_issue: "This issue cannot be closed because it is blocked by at least one open issue." |
195 | 195 |
notice_issue_not_reopenable_by_closed_parent_issue: "This issue cannot be reopened because its parent issue is closed." |
196 |
notice_issue_not_closable_by_open_tasks_and_blocking_issue: "This issue cannot be closed because it has at least one open subtask and it is blocked by at least one open issue." |
|
196 | 197 | |
197 | 198 |
error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" |
198 | 199 |
error_scm_not_found: "The entry or revision was not found in the repository." |
test/functional/issues_controller_test.rb | ||
---|---|---|
5439 | 5439 |
end |
5440 | 5440 | |
5441 | 5441 |
def test_get_edit_for_issue_with_transition_warning_should_show_the_warning |
5442 |
# Transition warning message for open issue blocked by another open issue |
|
5442 | 5443 |
@request.session[:user_id] = 2 |
5444 |
get( |
|
5445 |
:edit, |
|
5446 |
:params => { |
|
5447 |
:id => 9, |
|
5448 |
} |
|
5449 |
) |
|
5450 |
assert_response :success |
|
5451 |
reason = l(:notice_issue_not_closable_by_blocking_issue) |
|
5452 |
assert_select 'span.icon-warning[title=?]', reason, :text => reason |
|
5453 | ||
5454 |
# Transition warning message for open issue with open subtask and blocked by another open issue |
|
5455 |
subissue1 = Issue.generate!(:project_id => 5, :author_id => 2, :tracker_id => 1, :parent_issue_id => 9, :subject => 'Open Child Issue') |
|
5443 | 5456 | |
5444 | 5457 |
get( |
5445 | 5458 |
:edit, |
... | ... | |
5447 | 5460 |
:id => 9, |
5448 | 5461 |
} |
5449 | 5462 |
) |
5463 |
assert_response :success |
|
5464 |
reason = l(:notice_issue_not_closable_by_open_tasks_and_blocking_issue) |
|
5465 |
assert_select 'span.icon-warning[title=?]', reason, :text => reason |
|
5450 | 5466 | |
5467 |
# Transition warning message for open issue with open subtask |
|
5468 |
subissue2 = Issue.generate!(:project_id => 5, :author_id => 2, :tracker_id => 1, :parent_issue_id => subissue1.id, :subject => 'Open Child Issue') |
|
5469 |
|
|
5470 |
get( |
|
5471 |
:edit, |
|
5472 |
:params => { |
|
5473 |
:id => subissue1.id, |
|
5474 |
} |
|
5475 |
) |
|
5451 | 5476 |
assert_response :success |
5452 |
reason = l(:notice_issue_not_closable_by_blocking_issue) |
|
5477 |
reason = l(:notice_issue_not_closable_by_open_tasks) |
|
5478 |
assert_select 'span.icon-warning[title=?]', reason, :text => reason |
|
5479 | ||
5480 |
# Transition warning message for closed subtask with closed parent issue |
|
5481 |
subissue1.update_attribute :status_id, 5 |
|
5482 |
assert subissue1.closed? |
|
5483 |
subissue3 = Issue.generate!(:project_id => 5, :author_id => 2, :tracker_id => 1, :status_id => 5, :parent_issue_id => subissue1.id, :subject => 'Closed Child Issue') |
|
5484 |
assert subissue3.closed? |
|
5485 | ||
5486 |
get( |
|
5487 |
:edit, |
|
5488 |
:params => { |
|
5489 |
:id => subissue3.id, |
|
5490 |
} |
|
5491 |
) |
|
5492 |
assert_response :success |
|
5493 |
reason = l(:notice_issue_not_reopenable_by_closed_parent_issue) |
|
5453 | 5494 |
assert_select 'span.icon-warning[title=?]', reason, :text => reason |
5454 | 5495 |
end |
5455 | 5496 |
test/unit/issue_test.rb | ||
---|---|---|
2105 | 2105 | |
2106 | 2106 |
allowed_statuses = parent.reload.new_statuses_allowed_to(users(:users_002)) |
2107 | 2107 | |
2108 |
assert !parent.closable? |
|
2109 |
assert_equal l(:notice_issue_not_closable_by_open_tasks), parent.transition_warning |
|
2110 | ||
2111 | 2108 |
assert allowed_statuses.any? |
2112 | 2109 |
assert_equal [], allowed_statuses.select(&:is_closed?) |
2113 | 2110 |
end |
... | ... | |
2118 | 2115 | |
2119 | 2116 |
allowed_statuses = parent.reload.new_statuses_allowed_to(users(:users_002)) |
2120 | 2117 | |
2121 |
assert parent.closable? |
|
2122 |
assert_nil parent.transition_warning |
|
2123 | 2118 |
assert allowed_statuses.any? |
2124 | 2119 |
assert allowed_statuses.select(&:is_closed?).any? |
2125 | 2120 |
end |
... | ... | |
3296 | 3291 |
def test_closable |
3297 | 3292 |
issue10 = Issue.find(10) |
3298 | 3293 |
assert issue10.closable? |
3299 |
assert_nil issue10.transition_warning
|
|
3294 |
assert_empty(issue10.transition_warnings)
|
|
3300 | 3295 | |
3301 |
# Issue blocked by another issue |
|
3296 |
# Issue blocked by another open issue
|
|
3302 | 3297 |
issue9 = Issue.find(9) |
3303 | 3298 |
assert !issue9.closable? |
3304 |
assert_equal l(:notice_issue_not_closable_by_blocking_issue), issue9.transition_warning |
|
3299 |
assert_includes(issue9.transition_warnings, :not_closable_by_open_blocking_issues) |
|
3300 | ||
3301 |
# Issue with an open subtask and blocked by another open issue |
|
3302 |
child = issue9.generate_child!(:status_id => 1) |
|
3303 |
issue9.reload |
|
3304 |
assert !issue9.closable? |
|
3305 |
assert_includes(issue9.transition_warnings, :not_closable_by_open_sub_tasks_and_blocking_issues) |
|
3306 | ||
3307 |
# Issue with an open subtask |
|
3308 |
assert child.closable? |
|
3309 |
open_parent_issue = child.generate_child! |
|
3310 |
child.reload |
|
3311 |
assert !child.closable? |
|
3312 |
assert_includes(child.transition_warnings, :not_closable_by_open_sub_tasks) |
|
3313 | ||
3314 |
# Closed issue should be closable without a transition warning message |
|
3315 |
closed_issue = Issue.generate!(:status_id => 5) |
|
3316 |
assert closed_issue.closable? |
|
3317 |
assert_empty(closed_issue.transition_warnings) |
|
3305 | 3318 |
end |
3306 | 3319 | |
3307 | 3320 |
def test_reopenable |
3308 |
parent = Issue.generate!(:status_id => 5) |
|
3309 |
child = parent.generate_child!(:status_id => 5) |
|
3310 | ||
3311 |
assert !child.reopenable? |
|
3312 |
assert_equal l(:notice_issue_not_reopenable_by_closed_parent_issue), child.transition_warning |
|
3321 |
closed_parent = Issue.generate!(:status_id => 5) |
|
3322 |
closed_child = closed_parent.generate_child!(:status_id => 5) |
|
3323 |
assert !closed_child.reopenable? |
|
3324 |
assert_includes(closed_child.transition_warnings, :not_reopenable_by_closed_parent_issue) |
|
3325 | ||
3326 |
# Open issue should be reopenable without a transition warning message |
|
3327 |
open_issue = Issue.generate!(:status_id => 1) |
|
3328 |
assert open_issue.reopenable? |
|
3329 |
assert_empty(open_issue.transition_warnings) |
|
3313 | 3330 |
end |
3314 | 3331 |
end |