Feature #29470 » Option-to-set-a-tracker-only-as-subtask-r20091.patch
app/helpers/workflows_helper.rb | ||
---|---|---|
42 | 42 |
select_tag name, option_tags, {:multiple => multiple}.merge(options) |
43 | 43 |
end |
44 |
def field_required?(field) |
|
45 |
field.is_a?(CustomField) ? field.is_required? : %w(project_id tracker_id subject priority_id is_private).include?(field) |
|
44 |
def field_required?(field, trackers=[]) |
|
45 |
if field == 'parent_issue_id' |
|
46 |
subtasks = trackers.select {|t| t.subtask_only?} |
|
47 |
subtasks.count == trackers.count |
|
48 |
else |
|
49 |
field.is_a?(CustomField) ? field.is_required? : %w(project_id tracker_id subject priority_id is_private).include?(field) |
|
50 |
end |
|
46 | 51 |
end |
47 |
def field_permission_tag(permissions, status, field, roles) |
|
52 |
def field_permission_tag(permissions, status, field, roles, trackers=[])
|
|
48 | 53 |
name = field.is_a?(CustomField) ? field.id.to_s : field |
49 | 54 |
options = [["", ""], [l(:label_readonly), "readonly"]] |
50 |
options << [l(:label_required), "required"] unless field_required?(field) |
|
55 |
options << [l(:label_required), "required"] unless field_required?(field, trackers)
|
|
51 | 56 |
html_options = {} |
52 | 57 |
if perm = permissions[status.id][name] |
app/models/issue.rb | ||
---|---|---|
64 | 64 |
validates_presence_of :priority, :if => Proc.new {|issue| issue.new_record? || issue.priority_id_changed?} |
65 | 65 |
validates_presence_of :status, :if => Proc.new {|issue| issue.new_record? || issue.status_id_changed?} |
66 | 66 |
validates_presence_of :author, :if => Proc.new {|issue| issue.new_record? || issue.author_id_changed?} |
67 |
validates_presence_of :parent_issue_id, :if => Proc.new {|issue| issue.tracker && issue.tracker.subtask_only? && issue.tracker_id_changed?} |
|
67 | 68 |
validates_length_of :subject, :maximum => 255 |
68 | 69 |
validates_inclusion_of :done_ratio, :in => 0..100 |
... | ... | |
623 | 624 |
# Returns the names of attributes that are read-only for user or the current user |
624 | 625 |
# For users with multiple roles, the read-only fields are the intersection of |
625 | 626 |
# read-only fields of each role |
626 |
# The result is an array of strings where sustom fields are represented with their ids
|
|
627 |
# The result is an array of strings where custom fields are represented with their ids
|
|
627 | 628 |
# |
628 | 629 |
# Examples: |
629 | 630 |
# issue.read_only_attribute_names # => ['due_date', '2'] |
... | ... | |
635 | 636 |
# Returns the names of required attributes for user or the current user |
636 | 637 |
# For users with multiple roles, the required fields are the intersection of |
637 | 638 |
# required fields of each role |
638 |
# The result is an array of strings where sustom fields are represented with their ids
|
|
639 |
# The result is an array of strings where custom fields are represented with their ids
|
|
639 | 640 |
# |
640 | 641 |
# Examples: |
641 | 642 |
# issue.required_attribute_names # => ['due_date', '2'] |
app/models/tracker.rb | ||
---|---|---|
70 | 70 |
'name', |
71 | 71 |
'default_status_id', |
72 | 72 |
'is_in_roadmap', |
73 |
'subtask_only', |
|
73 | 74 |
'core_fields', |
74 | 75 |
'position', |
75 | 76 |
'custom_field_ids', |
app/views/issues/_attributes.html.erb | ||
---|---|---|
61 | 61 |
<div class="splitcontentright"> |
62 | 62 |
<% if @issue.safe_attribute? 'parent_issue_id' %> |
63 | 63 |
<p id="parent_issue"><%= f.text_field :parent_issue_id, :size => 10, |
64 |
:required => @issue.required_attribute?('parent_issue_id') %></p> |
|
65 |
<%= javascript_tag "observeAutocompleteField('issue_parent_issue_id', '#{escape_javascript(auto_complete_issues_path(:project_id => @issue.project, :scope => Setting.cross_project_subtasks, :status => @issue.closed? ? 'c' : 'o', :issue_id => @issue.id))}')" %>
|
|
64 |
:required => @issue.required_attribute?('parent_issue_id') || @issue.tracker.subtask_only? %></p>
|
|
65 |
<%= javascript_tag "observeAutocompleteField('issue_parent_issue_id', '#{escape_javascript auto_complete_issues_path(:project_id => @issue.project, :scope => Setting.cross_project_subtasks, :status => @issue.closed? ? 'c' : 'o', :issue_id => @issue.id)}')" %>
|
|
66 | 66 |
<% end %> |
67 | 67 |
<% if @issue.safe_attribute? 'start_date' %> |
app/views/trackers/_form.html.erb | ||
---|---|---|
10 | 10 |
:include_blank => @tracker.default_status.nil?, |
11 | 11 |
:required => true %> |
12 | 12 |
</p> |
13 |
<p><%= f.check_box :subtask_only %></p> |
|
13 | 14 |
<p><%= f.check_box :is_in_roadmap %></p> |
14 | 15 |
<p><%= f.text_area :description, :rows => 4 %></p> |
15 | 16 |
<p> |
app/views/trackers/index.api.rsb | ||
---|---|---|
4 | 4 |
api.id tracker.id |
5 | 5 |
api.name tracker.name |
6 | 6 |
api.default_status(:id => tracker.default_status.id, :name => tracker.default_status.name) unless tracker.default_status.nil? |
7 |
api.subtask_only tracker.subtask_only? |
|
7 | 8 |
api.description tracker.description |
8 | 9 |
end |
9 | 10 |
end |
app/views/trackers/index.html.erb | ||
---|---|---|
9 | 9 |
<thead><tr> |
10 | 10 |
<th><%=l(:label_tracker)%></th> |
11 | 11 |
<th><%=l(:field_default_status)%></th> |
12 |
<th><%=l(:field_subtask_only)%></th> |
|
12 | 13 |
<th><%=l(:field_description)%></th> |
13 | 14 |
<th></th> |
14 | 15 |
<th></th> |
... | ... | |
18 | 19 |
<tr> |
19 | 20 |
<td class="name"><%= link_to tracker.name, edit_tracker_path(tracker) %></td> |
20 | 21 |
<td><%= tracker.default_status.name %></td> |
22 |
<td class="subtask"><%= checked_image tracker.subtask_only? %></td> |
|
21 | 23 |
<td class="description"><%= tracker.description %></td> |
22 | 24 |
<td> |
23 | 25 |
<% unless tracker.workflow_rules.exists? %> |
app/views/workflows/permissions.html.erb | ||
---|---|---|
61 | 61 |
<% @fields.each do |field, name| %> |
62 | 62 |
<tr> |
63 | 63 |
<td class="name"> |
64 |
<%= name %> <%= content_tag('span', '*', :class => 'required') if field_required?(field) %> |
|
64 |
<%= name %> <%= content_tag('span', '*', :class => 'required') if field_required?(field, @trackers) %>
|
|
65 | 65 |
</td> |
66 | 66 |
<% for status in @statuses -%> |
67 | 67 |
<td class="<%= @permissions[status.id][field].try(:join, ' ') %>" title="<%= name %> (<%= status.name %>)"> |
config/locales/en.yml | ||
---|---|---|
403 | 403 |
field_history_default_tab: Issue's history default tab |
404 | 404 |
field_unique_id: Unique ID |
405 | 405 |
field_toolbar_language_options: Code highlighting toolbar languages |
406 |
field_subtask_only: Subtask only |
|
406 | 407 |
setting_app_title: Application title |
407 | 408 |
setting_welcome_text: Welcome text |
test/fixtures/projects_trackers.yml | ||
---|---|---|
1 |
--- |
|
2 |
projects_trackers_001: |
|
1 |
--- |
|
2 |
projects_trackers_001: |
|
3 | 3 |
project_id: 4 |
4 | 4 |
tracker_id: 3 |
5 |
projects_trackers_002: |
|
5 |
projects_trackers_002: |
|
6 | 6 |
project_id: 1 |
7 | 7 |
tracker_id: 1 |
8 |
projects_trackers_003: |
|
8 |
projects_trackers_003: |
|
9 | 9 |
project_id: 5 |
10 | 10 |
tracker_id: 1 |
11 |
projects_trackers_004: |
|
11 |
projects_trackers_004: |
|
12 | 12 |
project_id: 1 |
13 | 13 |
tracker_id: 2 |
14 |
projects_trackers_005: |
|
14 |
projects_trackers_005: |
|
15 | 15 |
project_id: 5 |
16 | 16 |
tracker_id: 2 |
17 |
projects_trackers_006: |
|
17 |
projects_trackers_006: |
|
18 | 18 |
project_id: 5 |
19 | 19 |
tracker_id: 3 |
20 |
projects_trackers_007: |
|
20 |
projects_trackers_007: |
|
21 | 21 |
project_id: 2 |
22 | 22 |
tracker_id: 1 |
23 |
projects_trackers_008: |
|
23 |
projects_trackers_008: |
|
24 | 24 |
project_id: 2 |
25 | 25 |
tracker_id: 2 |
26 |
projects_trackers_009: |
|
26 |
projects_trackers_009: |
|
27 | 27 |
project_id: 2 |
28 | 28 |
tracker_id: 3 |
29 |
projects_trackers_010: |
|
29 |
projects_trackers_010: |
|
30 | 30 |
project_id: 3 |
31 | 31 |
tracker_id: 2 |
32 |
projects_trackers_011: |
|
32 |
projects_trackers_011: |
|
33 | 33 |
project_id: 3 |
34 | 34 |
tracker_id: 3 |
35 |
projects_trackers_012: |
|
35 |
projects_trackers_012: |
|
36 | 36 |
project_id: 4 |
37 | 37 |
tracker_id: 1 |
38 |
projects_trackers_013: |
|
38 |
projects_trackers_013: |
|
39 | 39 |
project_id: 4 |
40 | 40 |
tracker_id: 2 |
41 |
projects_trackers_014: |
|
41 |
projects_trackers_014: |
|
42 | 42 |
project_id: 1 |
43 | 43 |
tracker_id: 3 |
44 |
projects_trackers_015: |
|
44 |
projects_trackers_015: |
|
45 | 45 |
project_id: 6 |
46 | 46 |
tracker_id: 1 |
47 | 47 |
projects_trackers_016: |
48 | 48 |
project_id: 3 |
49 | 49 |
tracker_id: 1 |
50 |
projects_trackers_017: |
|
51 |
project_id: 1 |
|
52 |
tracker_id: 4 |
test/fixtures/trackers.yml | ||
---|---|---|
1 |
--- |
|
2 |
trackers_001: |
|
1 |
--- |
|
2 |
trackers_001: |
|
3 | 3 |
name: Bug |
4 | 4 |
id: 1 |
5 | 5 |
is_in_chlog: true |
6 | 6 |
default_status_id: 1 |
7 | 7 |
position: 1 |
8 | 8 |
description: Description for Bug tracker |
9 |
trackers_002: |
|
9 |
subtask_only: false |
|
10 |
trackers_002: |
|
10 | 11 |
name: Feature request |
11 | 12 |
id: 2 |
12 | 13 |
is_in_chlog: true |
13 | 14 |
default_status_id: 1 |
14 | 15 |
position: 2 |
15 | 16 |
description: Description for Feature request tracker |
16 |
trackers_003: |
|
17 |
subtask_only: false |
|
18 |
trackers_003: |
|
17 | 19 |
name: Support request |
18 | 20 |
id: 3 |
19 | 21 |
is_in_chlog: false |
20 | 22 |
default_status_id: 1 |
21 | 23 |
position: 3 |
24 |
subtask_only: false |
|
25 |
trackers_004: |
|
26 |
name: Subtask |
|
27 |
id: 4 |
|
28 |
is_in_chlog: false |
|
29 |
default_status_id: 1 |
|
30 |
position: 4 |
|
31 |
subtask_only: true |
test/functional/issues_controller_test.rb | ||
---|---|---|
3207 | 3207 |
get(:new, :params => {:project_id => 1}) |
3208 | 3208 |
assert_response :success |
3209 | 3209 |
assert_select 'select[name=?]', 'issue[tracker_id]' do |
3210 |
assert_select 'option', 3
|
|
3210 |
assert_select 'option', 4
|
|
3211 | 3211 |
assert_select 'option[value="1"][selected=selected]' |
3212 | 3212 |
end |
3213 | 3213 |
end |
... | ... | |
3228 | 3228 |
) |
3229 | 3229 |
assert_response :success |
3230 | 3230 |
assert_select 'select[name=?]', 'issue[tracker_id]' do |
3231 |
assert_select 'option', 2
|
|
3231 |
assert_select 'option', 3
|
|
3232 | 3232 |
assert_select 'option[value="2"][selected=selected]' |
3233 | 3233 |
assert_select 'option[value="1"]', 0 |
3234 | 3234 |
end |
test/functional/trackers_controller_test.rb | ||
---|---|---|
31 | 31 |
get :index |
32 | 32 |
assert_response :success |
33 | 33 |
assert_select 'table.trackers' |
34 | ||
35 |
# assert subtask column |
|
36 |
assert_select 'td.subtask .icon-checked', 1 |
|
34 | 37 |
end |
35 | 38 |
def test_index_by_anonymous_should_redirect_to_login_form |
... | ... | |
49 | 52 |
get :new |
50 | 53 |
assert_response :success |
51 | 54 |
assert_select 'input[name=?]', 'tracker[name]' |
55 |
assert_select 'input[name=?]', 'tracker[subtask_only]' |
|
52 | 56 |
assert_select 'select[name=?]', 'tracker[default_status_id]' do |
53 | 57 |
assert_select 'option[value=?][selected=selected]', IssueStatus.sorted.first.id.to_s |
54 | 58 |
end |
... | ... | |
72 | 76 |
assert_equal Tracker::CORE_FIELDS, tracker.core_fields |
73 | 77 |
assert_equal [1, 6], tracker.custom_field_ids.sort |
74 | 78 |
assert_equal 0, tracker.workflow_rules.count |
79 |
assert !tracker.subtask_only |
|
75 | 80 |
end |
76 | 81 |
def test_create_with_disabled_core_fields |
test/functional/workflows_controller_test.rb | ||
---|---|---|
246 | 246 |
end |
247 | 247 |
end |
248 |
def test_get_permissions_with_role_and_subtask_tracker_should_mark_parent_task_field_required |
|
249 |
get :permissions, :params => {:role_id => 1, :tracker_id => 4} |
|
250 |
assert_response :success |
|
251 | ||
252 |
assert_select 'td.name', :text => 'Parent task *' |
|
253 |
end |
|
254 | ||
255 |
def test_get_permissions_with_role_and_multiple_subtask_trackers_should_mark_parent_task_field_required |
|
256 |
subtask = Tracker.find(1) |
|
257 |
subtask.subtask_only = true |
|
258 |
subtask.save! |
|
259 | ||
260 |
get :permissions, :params => {:role_id => 1, :tracker_id => [1, 4]} |
|
261 |
assert_response :success |
|
262 | ||
263 |
assert_select 'td.name', :text => 'Parent task *' |
|
264 |
end |
|
265 | ||
266 |
def test_get_permissions_with_role_and_mixed_trackers_should_not_mark_parent_task_field_required |
|
267 |
get :permissions, :params => {:role_id => 1, :tracker_id => [1, 4]} |
|
268 |
assert_response :success |
|
269 | ||
270 |
assert_select 'td.name', :text => 'Parent task' |
|
271 |
end |
|
272 | ||
248 | 273 |
def test_get_permissions_with_required_custom_field_should_not_show_required_option |
249 | 274 |
cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :tracker_ids => [1], :is_required => true) |
test/integration/api_test/trackers_test.rb | ||
---|---|---|
30 | 30 |
assert_select 'trackers[type=array] tracker id', :text => '2' do |
31 | 31 |
assert_select '~ name', :text => 'Feature request' |
32 |
assert_select '~ subtask_only', :text => 'false' |
|
32 | 33 |
assert_select '~ description', :text => 'Description for Feature request tracker' |
33 | 34 |
end |
35 | ||
36 |
assert_select 'trackers[type=array] tracker id', :text => '4' do |
|
37 |
assert_select '~ subtask_only', :text => 'true' |
|
38 |
end |
|
34 | 39 |
end |
35 | 40 |
end |
test/unit/issue_test.rb | ||
---|---|---|
214 | 214 |
assert_include 'Parent task is invalid', issue.errors.full_messages |
215 | 215 |
end |
216 |
def test_create_with_subtask_tracker |
|
217 |
issue = Issue.new(:project_id => 1, :tracker_id => 4, |
|
218 |
:author_id => 1, :subject => 'Group assignment', |
|
219 |
:parent_issue_id => 1) |
|
220 | ||
221 |
assert issue.save |
|
222 |
assert_equal 1, issue.parent_issue_id |
|
223 |
end |
|
224 | ||
225 |
def test_create_with_subtask_tracker_should_require_parent_task |
|
226 |
issue = Issue.new(:project_id => 1, :tracker_id => 4, |
|
227 |
:author_id => 1, :subject => 'Group assignment') |
|
228 | ||
229 |
assert !issue.save |
|
230 |
assert_include 'Parent task cannot be blank', issue.errors.full_messages |
|
231 |
end |
|
232 | ||
216 | 233 |
def assert_visibility_match(user, issues) |
217 | 234 |
assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort |
218 | 235 |
end |
... | ... | |
1706 | 1723 |
role.save! |
1707 | 1724 |
User.add_to_project(user, Project.find(1), role) |
1708 |
assert_equal [1, 2, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort |
|
1725 |
assert_equal [1, 2, 3, 4], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
|
|
1709 | 1726 |
end |
1710 | 1727 |
def test_allowed_target_trackers_with_one_role_allowed_on_some_trackers |
... | ... | |
1747 | 1764 |
role2.save! |
1748 | 1765 |
User.add_to_project(user, Project.find(1), [role1, role2]) |
1749 |
assert_equal [1, 2, 3], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort |
|
1766 |
assert_equal [1, 2, 3, 4], Issue.new(:project => Project.find(1)).allowed_target_trackers(user).ids.sort
|
|
1750 | 1767 |
end |
1751 | 1768 |
def test_allowed_target_trackers_should_not_consider_roles_without_add_issues_permission |
test/unit/lib/redmine/acts/positioned_without_scope_test.rb | ||
---|---|---|
26 | 26 |
t = Tracker.generate |
27 | 27 |
t.save! |
28 |
assert_equal 4, t.reload.position
|
|
28 |
assert_equal 5, t.reload.position
|
|
29 | 29 |
end |
30 | 30 |
def test_create_should_insert_at_given_position |
... | ... | |
35 | 35 |
t.save! |
36 | 36 |
assert_equal 2, t.reload.position |
37 |
assert_equal [1, 3, 4, 2], Tracker.order(:id).pluck(:position) |
|
37 |
assert_equal [1, 3, 4, 5, 2], Tracker.order(:id).pluck(:position)
|
|
38 | 38 |
end |
39 | 39 |
def test_destroy_should_remove_position |
... | ... | |
43 | 43 |
Tracker.generate! |
44 | 44 |
t.destroy |
45 |
assert_equal [1, 2, 3, 4], Tracker.order(:id).pluck(:position) |
|
45 |
assert_equal [1, 2, 3, 4, 5], Tracker.order(:id).pluck(:position)
|
|
46 | 46 |
end |
47 | 47 |
def test_update_should_update_positions |
48 | 48 |
t = Tracker.generate! |
49 |
assert_equal 4, t.position
|
|
49 |
assert_equal 5, t.position
|
|
50 | 50 |
t.position = 2 |
51 | 51 |
t.save! |
52 |
assert_equal [1, 3, 4, 2], Tracker.order(:id).pluck(:position) |
|
52 |
assert_equal [1, 3, 4, 5, 2], Tracker.order(:id).pluck(:position)
|
|
53 | 53 |
end |
54 | 54 |
end |
test/unit/tracker_test.rb | ||
---|---|---|
140 | 140 |
assert tracker.respond_to?(:description) |
141 | 141 |
assert_equal tracker.description, "Description for Bug tracker" |
142 | 142 |
end |
143 | ||
144 |
def test_set_tracker_subtask_only |
|
145 |
tracker = Tracker.find(1) |
|
146 |
tracker.subtask_only = true |
|
147 | ||
148 |
assert tracker.save! |
|
149 |
assert tracker.subtask_only? |
|
150 |
end |
|
143 | 151 |
end |
- « Previous
- 1
- …
- 3
- 4
- 5
- Next »