Feature #2568 ยป 2568-add-description-to-issue-statuses.patch
| app/models/issue_status.rb | ||
|---|---|---|
| 31 | 31 |
validates_presence_of :name |
| 32 | 32 |
validates_uniqueness_of :name, :case_sensitive => true |
| 33 | 33 |
validates_length_of :name, :maximum => 30 |
| 34 |
validates_length_of :description, :maximum => 255 |
|
| 34 | 35 |
validates_inclusion_of :default_done_ratio, :in => 0..100, :allow_nil => true |
| 35 | 36 | |
| 36 | 37 |
scope :sorted, lambda {order(:position)}
|
| ... | ... | |
| 38 | 39 | |
| 39 | 40 |
safe_attributes( |
| 40 | 41 |
'name', |
| 42 |
'description', |
|
| 41 | 43 |
'is_closed', |
| 42 | 44 |
'position', |
| 43 | 45 |
'default_done_ratio') |
| app/views/issue_statuses/_form.html.erb | ||
|---|---|---|
| 2 | 2 | |
| 3 | 3 |
<div class="box tabular"> |
| 4 | 4 |
<p><%= f.text_field :name, :required => true %></p> |
| 5 |
<p><%= f.text_area :description, :rows => 4 %></p> |
|
| 5 | 6 |
<% if Issue.use_status_for_done_ratio? %> |
| 6 | 7 |
<p><%= f.select :default_done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :include_blank => true, :label => :field_done_ratio %></p>
|
| 7 | 8 |
<% end %> |
| app/views/issue_statuses/index.api.rsb | ||
|---|---|---|
| 4 | 4 |
api.id status.id |
| 5 | 5 |
api.name status.name |
| 6 | 6 |
api.is_closed status.is_closed |
| 7 |
api.description status.description |
|
| 7 | 8 |
end |
| 8 | 9 |
end |
| 9 | 10 |
end |
| app/views/issue_statuses/index.html.erb | ||
|---|---|---|
| 12 | 12 |
<th><%=l(:field_done_ratio)%></th> |
| 13 | 13 |
<% end %> |
| 14 | 14 |
<th><%=l(:field_is_closed)%></th> |
| 15 |
<th><%=l(:field_description)%></th> |
|
| 15 | 16 |
<th></th> |
| 16 | 17 |
<th></th> |
| 17 | 18 |
</tr></thead> |
| ... | ... | |
| 23 | 24 |
<td><%= status.default_done_ratio %></td> |
| 24 | 25 |
<% end %> |
| 25 | 26 |
<td><%= checked_image status.is_closed? %></td> |
| 27 |
<td class="description"><%= status.description %></td> |
|
| 26 | 28 |
<td> |
| 27 | 29 |
<% unless WorkflowTransition.where('old_status_id = ? OR new_status_id = ?', status.id, status.id).exists? %>
|
| 28 | 30 |
<span class="icon icon-warning"> |
| app/views/issues/_attributes.html.erb | ||
|---|---|---|
| 5 | 5 |
<% if @issue.safe_attribute?('status_id') && @allowed_statuses.present? %>
|
| 6 | 6 |
<p> |
| 7 | 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)" %>
|
|
| 8 |
:onchange => "updateIssueFrom('#{escape_javascript(update_issue_form_path(@project, @issue))}', this)",
|
|
| 9 |
:title => @issue.status.description %> |
|
| 10 |
<%= content_tag 'a', l(:label_open_issue_status_description), :class => 'icon-only icon-help', :title => l(:label_open_issue_status_description), :onclick => "showModal('issue_statuses_description', '500px'); return false;", :href => '#' if @allowed_statuses.any? {|s| s.description.present? } %>
|
|
| 9 | 11 |
<% if @issue.transition_warning %> |
| 10 | 12 |
<span class="icon-only icon-warning" title="<%= @issue.transition_warning %>"><%= @issue.transition_warning %></span> |
| 11 | 13 |
<% end %> |
| 12 | 14 |
</p> |
| 15 |
<%= render partial: 'issues/issue_status_description', locals: { issue_statuses: @allowed_statuses } %>
|
|
| 13 | 16 |
<%= hidden_field_tag 'was_default_status', @issue.status_id, :id => nil if @issue.status == @issue.default_status %> |
| 14 | 17 |
<% else %> |
| 15 | 18 |
<p><label><%= l(:field_status) %></label> <%= @issue.status %></p> |
| app/views/issues/_issue_status_description.html.erb | ||
|---|---|---|
| 1 |
<% if issue_statuses.any? {|s| s.description.present? } %>
|
|
| 2 |
<div class="modal" id="issue_statuses_description"> |
|
| 3 |
<h3 class="title"><%= l(:label_issue_statuses_description) %></h3> |
|
| 4 |
<dl> |
|
| 5 |
<% issue_statuses.each do |issue_status| %> |
|
| 6 |
<% if issue_status.description.present? %> |
|
| 7 |
<dt><%= content_tag 'a', issue_status.name, :onclick => "selectIssueStatus('#{issue_status.id}'); return false;", :href => '#', :title => l(:text_select_apply_issue_status) %></dt>
|
|
| 8 |
<dd><%= issue_status.description %></dd> |
|
| 9 |
<% end %> |
|
| 10 |
<% end %> |
|
| 11 |
</dl> |
|
| 12 |
</div> |
|
| 13 |
<% end %> |
|
| 14 |
<%= javascript_tag do %> |
|
| 15 |
function selectIssueStatus(id) {
|
|
| 16 |
var target = $('#issue_status_id');
|
|
| 17 |
target.attr("selected", false);
|
|
| 18 |
target.find('option[value="' + id + '"]').prop('selected', true);
|
|
| 19 |
target.trigger('change');
|
|
| 20 |
hideModal('#issue_statuses_description h3');
|
|
| 21 |
} |
|
| 22 |
<% end %> |
|
| config/locales/en.yml | ||
|---|---|---|
| 1119 | 1119 |
label_inherited_from_group: "Inherited from group %{name}"
|
| 1120 | 1120 |
label_trackers_description: Trackers description |
| 1121 | 1121 |
label_open_trackers_description: View all trackers description |
| 1122 |
label_issue_statuses_description: Issue Status description |
|
| 1123 |
label_open_issue_status_description: View all issue statuses description |
|
| 1122 | 1124 |
label_preferred_body_part_text: Text |
| 1123 | 1125 |
label_preferred_body_part_html: HTML |
| 1124 | 1126 |
label_issue_history_properties: Property changes |
| ... | ... | |
| 1314 | 1316 |
text_project_closed: This project is closed and read-only. |
| 1315 | 1317 |
text_turning_multiple_off: "If you disable multiple values, multiple values will be removed in order to preserve only one value per item." |
| 1316 | 1318 |
text_select_apply_tracker: "Select tracker" |
| 1319 |
text_select_apply_issue_status: "Select issue status" |
|
| 1317 | 1320 |
text_avatar_server_config_html: The current avatar server is <a href="%{url}">%{url}</a>. You can configure it in config/configuration.yml.
|
| 1318 | 1321 |
text_no_subject: no subject |
| 1319 | 1322 |
text_allowed_queries_to_select: Public (to any users) queries only selectable |
| db/migrate/20230818020734_add_status_description.rb | ||
|---|---|---|
| 1 |
class AddStatusDescription < ActiveRecord::Migration[6.1] |
|
| 2 |
def up |
|
| 3 |
add_column :issue_statuses, :description, :string, :after => :name |
|
| 4 |
end |
|
| 5 | ||
| 6 |
def down |
|
| 7 |
remove_column :issue_statuses, :description |
|
| 8 |
end |
|
| 9 |
end |
|
| public/stylesheets/application.css | ||
|---|---|---|
| 578 | 578 |
#issue_tree .issue > td.assigned_to, #relations .issue > td.assigned_to {
|
| 579 | 579 |
white-space: nowrap; |
| 580 | 580 |
} |
| 581 |
#trackers_description {display:none;}
|
|
| 582 |
#trackers_description dt {font-weight: bold; text-decoration: underline;}
|
|
| 583 |
#trackers_description dd {margin: 0; padding: 0 0 1em 0;}
|
|
| 581 |
#trackers_description, #issue_statuses_description {display:none;}
|
|
| 582 |
#trackers_description dt, #issue_statuses_description dt {font-weight: bold; text-decoration: underline;}
|
|
| 583 |
#trackers_description dd, #issue_statuses_description dd {margin: 0; padding: 0 0 1em 0;}
|
|
| 584 | 584 | |
| 585 | 585 |
#issue-form .assign-to-me-link { padding-left: 5px; }
|
| 586 | 586 | |
| test/fixtures/issue_statuses.yml | ||
|---|---|---|
| 2 | 2 |
issue_statuses_001: |
| 3 | 3 |
id: 1 |
| 4 | 4 |
name: New |
| 5 |
description: Description for New issue status |
|
| 5 | 6 |
is_closed: false |
| 6 | 7 |
position: 1 |
| 7 | 8 |
issue_statuses_002: |
| 8 | 9 |
id: 2 |
| 9 | 10 |
name: Assigned |
| 11 |
description: Description for Assigned issue status |
|
| 10 | 12 |
is_closed: false |
| 11 | 13 |
position: 2 |
| 12 | 14 |
issue_statuses_003: |
| 13 | 15 |
id: 3 |
| 14 | 16 |
name: Resolved |
| 17 |
description: Description for Resolved issue status |
|
| 15 | 18 |
is_closed: false |
| 16 | 19 |
position: 3 |
| 17 | 20 |
issue_statuses_004: |
| 18 |
name: Feedback |
|
| 19 | 21 |
id: 4 |
| 22 |
name: Feedback |
|
| 20 | 23 |
is_closed: false |
| 21 | 24 |
position: 4 |
| 22 | 25 |
issue_statuses_005: |
| test/functional/issue_statuses_controller_test.rb | ||
|---|---|---|
| 64 | 64 |
get :new |
| 65 | 65 |
assert_response :success |
| 66 | 66 |
assert_select 'input[name=?]', 'issue_status[name]' |
| 67 |
assert_select 'textarea[name=?]', 'issue_status[description]' |
|
| 67 | 68 |
end |
| 68 | 69 | |
| 69 | 70 |
def test_create |
| ... | ... | |
| 72 | 73 |
:create, |
| 73 | 74 |
:params => {
|
| 74 | 75 |
:issue_status => {
|
| 75 |
:name => 'New status' |
|
| 76 |
:name => 'New status', |
|
| 77 |
:description => 'New status description' |
|
| 76 | 78 |
} |
| 77 | 79 |
} |
| 78 | 80 |
) |
| ... | ... | |
| 80 | 82 |
assert_redirected_to :action => 'index' |
| 81 | 83 |
status = IssueStatus.order('id DESC').first
|
| 82 | 84 |
assert_equal 'New status', status.name |
| 85 |
assert_equal 'New status description', status.description |
|
| 83 | 86 |
end |
| 84 | 87 | |
| 85 | 88 |
def test_create_with_failure |
| ... | ... | |
| 99 | 102 |
get(:edit, :params => {:id => '3'})
|
| 100 | 103 |
assert_response :success |
| 101 | 104 |
assert_select 'input[name=?][value=?]', 'issue_status[name]', 'Resolved' |
| 105 |
assert_select 'textarea[name=?]', 'issue_status[description]', 'Description for Resolved issue status' |
|
| 102 | 106 |
end |
| 103 | 107 | |
| 104 | 108 |
def test_update |
| ... | ... | |
| 107 | 111 |
:params => {
|
| 108 | 112 |
:id => '3', |
| 109 | 113 |
:issue_status => {
|
| 110 |
:name => 'Renamed status' |
|
| 114 |
:name => 'Renamed status', |
|
| 115 |
:description => 'Renamed status description' |
|
| 111 | 116 |
} |
| 112 | 117 |
} |
| 113 | 118 |
) |
| 114 | 119 |
assert_redirected_to :action => 'index' |
| 115 | 120 |
status = IssueStatus.find(3) |
| 116 | 121 |
assert_equal 'Renamed status', status.name |
| 122 |
assert_equal 'Renamed status description', status.description |
|
| 117 | 123 |
end |
| 118 | 124 | |
| 119 | 125 |
def test_update_with_failure |
| test/functional/issues_controller_test.rb | ||
|---|---|---|
| 3881 | 3881 |
assert_select 'div#trackers_description', 0 |
| 3882 | 3882 |
end |
| 3883 | 3883 | |
| 3884 |
def test_get_new_should_show_issue_status_description |
|
| 3885 |
@request.session[:user_id] = 2 |
|
| 3886 |
get :new, :params => {
|
|
| 3887 |
:project_id => 1, |
|
| 3888 |
:issue => {
|
|
| 3889 |
:status_id => 2 |
|
| 3890 |
} |
|
| 3891 |
} |
|
| 3892 |
assert_response :success |
|
| 3893 | ||
| 3894 |
assert_select 'form#issue-form' do |
|
| 3895 |
assert_select 'a[title=?]', 'View all issue statuses description', :text => 'View all issue statuses description' |
|
| 3896 |
assert_select 'select[name=?][title=?]', 'issue[status_id]', 'Description for Assigned issue status' |
|
| 3897 |
end |
|
| 3898 | ||
| 3899 |
assert_select 'div#issue_statuses_description' do |
|
| 3900 |
assert_select 'h3', :text => 'Issue Status description', :count => 1 |
|
| 3901 |
assert_select 'dt', 2 |
|
| 3902 |
assert_select 'dt', :text => 'New', :count => 1 |
|
| 3903 |
assert_select 'dd', :text => 'Description for New issue status', :count => 1 |
|
| 3904 |
end |
|
| 3905 |
end |
|
| 3906 | ||
| 3907 |
def test_get_new_should_not_show_issue_status_description |
|
| 3908 |
IssueStatus.update_all(:description => '') |
|
| 3909 | ||
| 3910 |
@request.session[:user_id] = 2 |
|
| 3911 |
get :new, :params => {
|
|
| 3912 |
:project_id => 1, |
|
| 3913 |
:issue => {
|
|
| 3914 |
:status_id => 2 |
|
| 3915 |
} |
|
| 3916 |
} |
|
| 3917 |
assert_response :success |
|
| 3918 | ||
| 3919 |
assert_select 'form#issue-form' do |
|
| 3920 |
assert_select 'a[title=?]', 'View all issue statuses description', 0 |
|
| 3921 |
assert_select 'select[name=?][title=?]', 'issue[status_id]', '' |
|
| 3922 |
end |
|
| 3923 | ||
| 3924 |
assert_select 'div#issue_statuses_description', 0 |
|
| 3925 |
end |
|
| 3926 | ||
| 3884 | 3927 |
def test_get_new_should_show_create_and_follow_button_when_issue_is_subtask_and_back_url_is_present |
| 3885 | 3928 |
@request.session[:user_id] = 2 |
| 3886 | 3929 |
get :new, params: {
|
| test/integration/api_test/issue_statuses_test.rb | ||
|---|---|---|
| 29 | 29 |
assert_equal 'application/xml', @response.media_type |
| 30 | 30 |
assert_select 'issue_statuses[type=array] issue_status id', :text => '2' do |
| 31 | 31 |
assert_select '~ name', :text => 'Assigned' |
| 32 |
assert_select '~ is_closed', :text => 'false' |
|
| 33 |
assert_select '~ description', :text => 'Description for Assigned issue status' |
|
| 32 | 34 |
end |
| 33 | 35 |
end |
| 34 | 36 |
end |
| test/unit/issue_status_test.rb | ||
|---|---|---|
| 151 | 151 |
assert !issue.closed? |
| 152 | 152 |
assert_nil issue.closed_on |
| 153 | 153 |
end |
| 154 | ||
| 155 |
def test_issue_status_should_have_description |
|
| 156 |
issue_status = IssueStatus.find(1) |
|
| 157 |
assert issue_status.respond_to?(:description) |
|
| 158 |
assert_equal 'Description for New issue status', issue_status.description |
|
| 159 |
end |
|
| 154 | 160 |
end |