Feature #31589 » 0001-Show-an-warning-with-the-reason-for-why-an-issue-can.patch
| app/models/issue.rb | ||
|---|---|---|
| 56 | 56 | |
| 57 | 57 | DONE_RATIO_OPTIONS = %w(issue_field issue_status) | 
| 58 | 58 | |
| 59 | attr_reader :not_closable_reason | |
| 59 | 60 | attr_writer :deleted_attachment_ids | 
| 60 | 61 | delegate :notes, :notes=, :private_notes, :private_notes=, :to => :current_journal, :allow_nil => true | 
| 61 | 62 | |
| ... | ... | |
| 969 | 970 |     !relations_to.detect {|ir| ir.relation_type == 'blocks' && !ir.issue_from.closed?}.nil? | 
| 970 | 971 | end | 
| 971 | 972 | |
| 973 | # Returns true if this issue can be closed and if not, returns false and populates the reason | |
| 974 | def closable? | |
| 975 | if descendants.open.any? | |
| 976 | @not_closable_reason = l(:notice_issue_not_closable_by_open_tasks) | |
| 977 | return false | |
| 978 | end | |
| 979 | if blocked? | |
| 980 | @not_closable_reason = l(:notice_issue_not_closable_by_blocking_issue) | |
| 981 | return false | |
| 982 | end | |
| 983 | return true | |
| 984 | end | |
| 985 | ||
| 972 | 986 | # Returns the default status of the issue based on its tracker | 
| 973 | 987 | # Returns nil if tracker is nil | 
| 974 | 988 | def default_status | 
| ... | ... | |
| 1008 | 1022 | statuses << default_status if include_default || (new_record? && statuses.empty?) | 
| 1009 | 1023 | |
| 1010 | 1024 | statuses = statuses.compact.uniq.sort | 
| 1011 |     if blocked? || descendants.open.any? | |
| 1025 |     unless closable? | |
| 1012 | 1026 | # cannot close a blocked issue or a parent with open subtasks | 
| 1013 | 1027 | statuses.reject!(&:is_closed?) | 
| 1014 | 1028 | end | 
| app/views/issues/_attributes.html.erb | ||
|---|---|---|
| 3 | 3 | <div class="splitcontent"> | 
| 4 | 4 | <div class="splitcontentleft"> | 
| 5 | 5 | <% if @issue.safe_attribute?('status_id') && @allowed_statuses.present? %> | 
| 6 | <p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), {:required => true}, | |
| 7 |                 :onchange => "updateIssueFrom('#{escape_javascript(update_issue_form_path(@project, @issue))}', this)" %></p> | |
| 6 | <p> | |
| 7 |   <%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), {:required => true}, | |
| 8 |                 :onchange => "updateIssueFrom('#{escape_javascript(update_issue_form_path(@project, @issue))}', this)" %> | |
| 9 | <% unless @issue.closable? %> | |
| 10 | <span class="icon-only icon-warning" title="<%= @issue.not_closable_reason %>"><%= @issue.not_closable_reason %></span> | |
| 11 | <% end %> | |
| 12 | </p> | |
| 8 | 13 | <%= hidden_field_tag 'was_default_status', @issue.status_id, :id => nil if @issue.status == @issue.default_status %> | 
| 9 | 14 | <% else %> | 
| 10 | 15 | <p><label><%= l(:field_status) %></label> <%= @issue.status %></p> | 
| config/locales/en.yml | ||
|---|---|---|
| 191 | 191 | notice_new_password_must_be_different: The new password must be different from the current password | 
| 192 | 192 |   notice_import_finished: "%{count} items have been imported" | 
| 193 | 193 |   notice_import_finished_with_errors: "%{count} out of %{total} items could not be imported" | 
| 194 | notice_issue_not_closable_by_open_tasks: "This issue cannot be closed because it has open subtasks." | |
| 195 | notice_issue_not_closable_by_blocking_issue: "This issue cannot be closed because it is blocked by another issue." | |
| 194 | 196 | |
| 195 | 197 |   error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" | 
| 196 | 198 | error_scm_not_found: "The entry or revision was not found in the repository." | 
| test/functional/issues_controller_test.rb | ||
|---|---|---|
| 5196 | 5196 | assert_select 'select[name=?]', 'issue[priority_id]' do | 
| 5197 | 5197 | assert_select 'option[value="15"]', 0 | 
| 5198 | 5198 | end | 
| 5199 | assert_select 'span.icon-warning', 0 | |
| 5199 | 5200 | end | 
| 5200 | 5201 | |
| 5201 | 5202 | def test_edit_should_hide_project_if_user_is_not_allowed_to_change_project | 
| ... | ... | |
| 5307 | 5308 | end | 
| 5308 | 5309 | end | 
| 5309 | 5310 | |
| 5311 | def test_get_edit_for_non_closable_issue_should_show_the_reason | |
| 5312 | @request.session[:user_id] = 2 | |
| 5313 | get( | |
| 5314 | :edit, | |
| 5315 |       :params => { | |
| 5316 | :id => 9, | |
| 5317 | } | |
| 5318 | ) | |
| 5319 | ||
| 5320 | assert_response :success | |
| 5321 | reason = l(:notice_issue_not_closable_by_blocking_issue) | |
| 5322 | assert_select 'span.icon-warning[title=?]', reason, :text => reason | |
| 5323 | end | |
| 5324 | ||
| 5310 | 5325 | def test_update_form_for_existing_issue | 
| 5311 | 5326 | @request.session[:user_id] = 2 | 
| 5312 | 5327 | patch( | 
| test/unit/issue_test.rb | ||
|---|---|---|
| 2104 | 2104 | child = Issue.generate!(:parent_issue_id => parent.id) | 
| 2105 | 2105 | |
| 2106 | 2106 | allowed_statuses = parent.reload.new_statuses_allowed_to(users(:users_002)) | 
| 2107 | ||
| 2108 | assert !parent.closable? | |
| 2109 | assert_equal l(:notice_issue_not_closable_by_open_tasks), parent.not_closable_reason | |
| 2110 | ||
| 2107 | 2111 | assert allowed_statuses.any? | 
| 2108 | 2112 | assert_equal [], allowed_statuses.select(&:is_closed?) | 
| 2109 | 2113 | end | 
| ... | ... | |
| 2113 | 2117 | child = Issue.generate!(:parent_issue_id => parent.id, :status_id => 5) | 
| 2114 | 2118 | |
| 2115 | 2119 | allowed_statuses = parent.reload.new_statuses_allowed_to(users(:users_002)) | 
| 2120 | ||
| 2121 | assert parent.closable? | |
| 2122 | assert_nil parent.not_closable_reason | |
| 2116 | 2123 | assert allowed_statuses.any? | 
| 2117 | 2124 | assert allowed_statuses.select(&:is_closed?).any? | 
| 2118 | 2125 | end | 
| ... | ... | |
| 3244 | 3251 | User.current = user_in_asia | 
| 3245 | 3252 | assert issue.overdue? | 
| 3246 | 3253 | end | 
| 3254 | ||
| 3255 | def test_closable | |
| 3256 | issue10 = Issue.find(10) | |
| 3257 | assert issue10.closable? | |
| 3258 | assert_nil issue10.not_closable_reason | |
| 3259 | ||
| 3260 | # Issue blocked by another issue | |
| 3261 | issue9 = Issue.find(9) | |
| 3262 | assert !issue9.closable? | |
| 3263 | assert_equal l(:notice_issue_not_closable_by_blocking_issue), issue9.not_closable_reason | |
| 3264 | end | |
| 3247 | 3265 | end |