Feature #37623 » feature-37623.patch
app/models/time_entry_query.rb | ||
---|---|---|
34 | 34 |
QueryAssociationColumn.new(:issue, :status, :caption => :field_status, :sortable => "#{IssueStatus.table_name}.position"), |
35 | 35 |
QueryAssociationColumn.new(:issue, :category, :caption => :field_category, :sortable => "#{IssueCategory.table_name}.name"), |
36 | 36 |
QueryAssociationColumn.new(:issue, :fixed_version, :caption => :field_fixed_version, :sortable => Version.fields_for_order_statement), |
37 |
QueryAssociationColumn.new(:issue, :parent, :caption => :field_parent_issue, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc'), |
|
37 | 38 |
QueryColumn.new(:comments), |
38 | 39 |
QueryColumn.new(:hours, :sortable => "#{TimeEntry.table_name}.hours", :totalable => true), |
39 | 40 |
] |
... | ... | |
71 | 72 |
:type => :list, |
72 | 73 |
:name => l("label_attribute_of_issue", :name => l(:field_fixed_version)), |
73 | 74 |
:values => lambda {fixed_version_values}) |
75 |
add_available_filter( |
|
76 |
"issue.parent_id", |
|
77 |
:type => :tree, |
|
78 |
:name => l("label_attribute_of_issue", :name => l(:field_parent_issue))) |
|
74 | 79 |
add_available_filter( |
75 | 80 |
"issue.category_id", |
76 | 81 |
:type => :list_optional, |
... | ... | |
200 | 205 |
end |
201 | 206 |
end |
202 | 207 | |
208 |
def sql_for_issue_parent_id_field(field, operator, value) |
|
209 |
case operator |
|
210 |
when "=" |
|
211 |
# accepts a comma separated list of ids |
|
212 |
parent_ids = value.first.to_s.scan(/\d+/).map(&:to_i).uniq |
|
213 |
issue_ids = Issue.where(:parent_id => parent_ids).pluck(:id) |
|
214 |
if issue_ids.present? |
|
215 |
"#{TimeEntry.table_name}.issue_id IN (#{issue_ids.join(',')})" |
|
216 |
else |
|
217 |
"1=0" |
|
218 |
end |
|
219 |
when "~" |
|
220 |
root_id, lft, rgt = Issue.where(:id => value.first.to_i).pick(:root_id, :lft, :rgt) |
|
221 |
issue_ids = Issue.where("#{Issue.table_name}.root_id = ? AND #{Issue.table_name}.lft > ? AND #{Issue.table_name}.rgt < ?", root_id, lft, rgt).pluck(:id) if root_id && lft && rgt |
|
222 |
if issue_ids.present? |
|
223 |
"#{TimeEntry.table_name}.issue_id IN (#{issue_ids.join(',')})" |
|
224 |
else |
|
225 |
"1=0" |
|
226 |
end |
|
227 |
else |
|
228 |
sql_for_field("parent_id", operator, value, Issue.table_name, "parent_id") |
|
229 |
end |
|
230 |
end |
|
231 | ||
203 | 232 |
def sql_for_activity_id_field(field, operator, value) |
204 | 233 |
ids = value.map(&:to_i).join(',') |
205 | 234 |
table_name = Enumeration.table_name |
test/functional/timelog_controller_test.rb | ||
---|---|---|
1374 | 1374 |
assert_select 'td.issue-category', :text => 'Printing' |
1375 | 1375 |
end |
1376 | 1376 | |
1377 |
def test_index_with_issue_parent_filter |
|
1378 |
issue1 = Issue.generate!(project_id: 'ecookbook', parent_id: 2) |
|
1379 |
entry1 = TimeEntry.generate!(issue: issue1, hours: 2.5) |
|
1380 |
issue2 = Issue.generate!(project_id: 'ecookbook', parent_id: 5) |
|
1381 |
entry2 = TimeEntry.generate!(issue: issue2, hours: 5.0) |
|
1382 | ||
1383 |
get :index, params: { |
|
1384 |
project_id: 'ecookbook', |
|
1385 |
f: ['issue.parent_id'], |
|
1386 |
op: {'issue.parent_id' => '='}, |
|
1387 |
v: {'issue.parent_id' => ['2,5']} |
|
1388 |
} |
|
1389 |
assert_response :success |
|
1390 |
assert_equal [entry1.id, entry2.id].sort, css_select('input[name="ids[]"]').map {|e| e.attr(:value).to_i}.sort |
|
1391 |
end |
|
1392 | ||
1393 |
def test_index_with_issue_parent_column |
|
1394 |
issue = Issue.generate!(project_id: 'ecookbook', parent_id: 2) |
|
1395 |
entry = TimeEntry.generate!(issue: issue, hours: 2.5) |
|
1396 | ||
1397 |
get :index, params: { |
|
1398 |
project_id: 'ecookbook', |
|
1399 |
c: %w(project spent_on issue comments hours issue.parent) |
|
1400 |
} |
|
1401 | ||
1402 |
assert_response :success |
|
1403 |
assert_select 'td.issue-parent', text: "#{issue.parent.tracker} ##{issue.parent.id}: #{issue.parent.subject}" |
|
1404 |
end |
|
1405 | ||
1406 |
def test_index_with_issue_parent_sort |
|
1407 |
issue1 = Issue.generate!(project_id: 'ecookbook', parent_id: 2) |
|
1408 |
entry1 = TimeEntry.generate!(issue: issue1, hours: 2.5) |
|
1409 |
issue2 = Issue.generate!(project_id: 'ecookbook', parent_id: 5) |
|
1410 |
entry2 = TimeEntry.generate!(issue: issue2, hours: 5.0) |
|
1411 | ||
1412 |
get :index, :params => { |
|
1413 |
:c => ["hours", 'issue.parent'], |
|
1414 |
:sort => 'issue.parent' |
|
1415 |
} |
|
1416 |
assert_response :success |
|
1417 | ||
1418 |
# Make sure that values are properly sorted |
|
1419 |
values = css_select("td.issue-parent").map(&:text).reject(&:blank?) |
|
1420 |
assert_equal ["#{issue1.parent.tracker} ##{issue1.parent.id}: #{issue1.parent.subject}", "#{issue2.parent.tracker} ##{issue2.parent.id}: #{issue2.parent.subject}"].sort, values.sort |
|
1421 |
end |
|
1422 | ||
1377 | 1423 |
def test_index_with_issue_fixed_version_column |
1378 | 1424 |
issue = Issue.find(1) |
1379 | 1425 |
issue.fixed_version = Version.find(3) |
test/unit/query_test.rb | ||
---|---|---|
504 | 504 |
find_issues_with_query(query) |
505 | 505 |
end |
506 | 506 | |
507 |
def test_time_entry_operator_is_on_issue_parent_id_should_accept_comma_separated_values |
|
508 |
issue1 = Issue.generate!(project_id: 'ecookbook', parent_id: 2) |
|
509 |
entry1 = TimeEntry.generate!(issue: issue1) |
|
510 |
issue2 = Issue.generate!(project_id: 'ecookbook', parent_id: 5) |
|
511 |
entry2 = TimeEntry.generate!(issue: issue2) |
|
512 | ||
513 |
query = TimeEntryQuery.new(:name => '_') |
|
514 |
query.add_filter("issue.parent_id", '=', ['2,5']) |
|
515 |
entries = TimeEntry.where(query.statement).to_a |
|
516 |
assert_equal 2, entries.size |
|
517 |
assert_equal [entry1.id, entry2.id].sort, entries.map(&:id).sort |
|
518 |
end |
|
519 | ||
520 |
def test_time_entry_contains_operator_is_on_issue_parent_id |
|
521 |
issue1 = Issue.generate!(project_id: 'ecookbook', parent_id: 2) |
|
522 |
entry1 = TimeEntry.generate!(issue: issue1) |
|
523 |
issue2 = Issue.generate!(project_id: 'ecookbook', parent_id: issue1.id) |
|
524 |
entry2 = TimeEntry.generate!(issue: issue2) |
|
525 | ||
526 |
query = TimeEntryQuery.new(:name => '_') |
|
527 |
query.add_filter("issue.parent_id", '~', ['2']) |
|
528 |
entries = TimeEntry.where(query.statement).to_a |
|
529 |
assert_equal 2, entries.size |
|
530 |
assert_equal [entry1.id, entry2.id].sort, entries.map(&:id).sort |
|
531 |
end |
|
532 | ||
507 | 533 |
def test_date_filter_should_not_accept_non_date_values |
508 | 534 |
query = IssueQuery.new(:name => '_') |
509 | 535 |
query.add_filter('created_on', '=', ['a']) |