Project

General

Profile

Feature #31589 » 0001-Show-warning-and-the-reason-when-the-issue-cannot-be.patch

Marius BĂLTEANU, 2020-01-12 20:24

View differences:

app/models/issue.rb
56 56

  
57 57
  DONE_RATIO_OPTIONS = %w(issue_field issue_status)
58 58

  
59
  attr_reader :transition_warning
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
      @transition_warning = l(:notice_issue_not_closable_by_open_tasks)
977
      return false
978
    end
979
    if blocked?
980
      @transition_warning = l(:notice_issue_not_closable_by_blocking_issue)
981
      return false
982
    end
983
    return true
984
  end
985

  
986
  # Returns true if this issue can be reopen and if not, returns false and populates the reason
987
  def reopenable?
988
    if ancestors.open(false).any?
989
      @transition_warning = l(:notice_issue_not_reopenable_by_closed_parent_issue)
990
      return false
991
    end
992
    return true
993
  end
994

  
972 995
  # Returns the default status of the issue based on its tracker
973 996
  # Returns nil if tracker is nil
974 997
  def default_status
......
1008 1031
    statuses << default_status if include_default || (new_record? && statuses.empty?)
1009 1032

  
1010 1033
    statuses = statuses.compact.uniq.sort
1011
    if blocked? || descendants.open.any?
1034
    unless closable?
1012 1035
      # cannot close a blocked issue or a parent with open subtasks
1013 1036
      statuses.reject!(&:is_closed?)
1014 1037
    end
1015
    if ancestors.open(false).any?
1038
    unless reopenable?
1016 1039
      # cannot reopen a subtask of a closed parent
1017 1040
      statuses.select!(&:is_closed?)
1018 1041
    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
  <% if @issue.transition_warning %>
10
    <span class="icon-only icon-warning" title="<%= @issue.transition_warning %>"><%= @issue.transition_warning %></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 at least one open subtask."
195
  notice_issue_not_closable_by_blocking_issue: "This issue cannot be closed because it is blocked by at least one open issue."
196
  notice_issue_not_reopenable_by_closed_parent_issue: "This issue cannot be reopened because its parent issue is closed."
194 197

  
195 198
  error_can_t_load_default_data: "Default configuration could not be loaded: %{value}"
196 199
  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_issue_with_transition_warning_should_show_the_warning
5312
    @request.session[:user_id] = 2
5313

  
5314
    get(
5315
      :edit,
5316
      :params => {
5317
        :id => 9,
5318
      }
5319
    )
5320

  
5321
    assert_response :success
5322
    reason = l(:notice_issue_not_closable_by_blocking_issue)
5323
    assert_select 'span.icon-warning[title=?]', reason, :text => reason
5324
  end
5325

  
5310 5326
  def test_update_form_for_existing_issue
5311 5327
    @request.session[:user_id] = 2
5312 5328
    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.transition_warning
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.transition_warning
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.transition_warning
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.transition_warning
3264
  end
3265

  
3266
  def test_reopenable
3267
    parent = Issue.generate!(:status_id => 5)
3268
    child = parent.generate_child!(:status_id => 5)
3269

  
3270
    assert !child.reopenable?
3271
    assert_equal l(:notice_issue_not_reopenable_by_closed_parent_issue), child.transition_warning
3272
  end
3247 3273
end
(4-4/4)