Feature #37623 » 37623-v2.patch
app/helpers/queries_helper.rb | ||
---|---|---|
26 | 26 |
ungrouped = [] |
27 | 27 |
grouped = {label_string: [], label_date: [], label_time_tracking: [], label_attachment: []} |
28 | 28 |
query.available_filters.map do |field, field_options| |
29 |
if field_options[:type] == :relation |
|
29 |
if field =~ /^(.+)\./ |
|
30 |
# association filters |
|
31 |
group = "field_#{$1}".to_sym |
|
32 |
elsif field_options[:type] == :relation |
|
30 | 33 |
group = :label_relations |
31 | 34 |
elsif field_options[:type] == :tree |
32 | 35 |
group = query.is_a?(IssueQuery) ? :label_relations : nil |
33 | 36 |
elsif /^cf_\d+\./.match?(field) |
34 | 37 |
group = (field_options[:through] || field_options[:field]).try(:name) |
35 |
elsif field =~ /^(.+)\./ |
|
36 |
# association filters |
|
37 |
group = "field_#{$1}".to_sym |
|
38 | 38 |
elsif %w(member_of_group assigned_to_role).include?(field) |
39 | 39 |
group = :field_assigned_to |
40 | 40 |
elsif field_options[:type] == :date_past || field_options[:type] == :date |
... | ... | |
256 | 256 |
link_to value, issue_path(item) |
257 | 257 |
when :subject |
258 | 258 |
link_to value, issue_path(item) |
259 |
when :parent |
|
259 |
when :parent, :'issue.parent'
|
|
260 | 260 |
value ? (value.visible? ? link_to_issue(value, :subject => false) : "##{value.id}") : '' |
261 | 261 |
when :description |
262 | 262 |
item.description? ? content_tag('div', textilizable(item, :description), :class => "wiki") : '' |
app/models/time_entry_query.rb | ||
---|---|---|
31 | 31 |
QueryColumn.new(:activity, :sortable => "#{TimeEntryActivity.table_name}.position", :groupable => true), |
32 | 32 |
QueryColumn.new(:issue, :sortable => "#{Issue.table_name}.id", :groupable => true), |
33 | 33 |
QueryAssociationColumn.new(:issue, :tracker, :caption => :field_tracker, :sortable => "#{Tracker.table_name}.position"), |
34 |
QueryAssociationColumn.new(:issue, :parent, :caption => :field_parent_issue, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc'), |
|
34 | 35 |
QueryAssociationColumn.new(:issue, :status, :caption => :field_status, :sortable => "#{IssueStatus.table_name}.position"), |
35 | 36 |
QueryAssociationColumn.new(:issue, :category, :caption => :field_category, :sortable => "#{IssueCategory.table_name}.name"), |
36 | 37 |
QueryAssociationColumn.new(:issue, :fixed_version, :caption => :field_fixed_version, :sortable => Version.fields_for_order_statement), |
... | ... | |
61 | 62 |
:type => :list, |
62 | 63 |
:name => l("label_attribute_of_issue", :name => l(:field_tracker)), |
63 | 64 |
:values => lambda {trackers.map {|t| [t.name, t.id.to_s]}}) |
65 |
add_available_filter( |
|
66 |
"issue.parent_id", |
|
67 |
:type => :tree, |
|
68 |
:name => l("label_attribute_of_issue", :name => l(:field_parent_issue))) |
|
64 | 69 |
add_available_filter( |
65 | 70 |
"issue.status_id", |
66 | 71 |
:type => :list, |
67 | 72 |
:name => l("label_attribute_of_issue", :name => l(:field_status)), |
68 | 73 |
:values => lambda {issue_statuses_values}) |
74 |
add_available_filter( |
|
75 |
"issue.subject", |
|
76 |
:type => :text, |
|
77 |
:name => l("label_attribute_of_issue", :name => l(:field_subject)) |
|
78 |
) |
|
69 | 79 |
add_available_filter( |
70 | 80 |
"issue.fixed_version_id", |
71 | 81 |
:type => :list, |
... | ... | |
200 | 210 |
end |
201 | 211 |
end |
202 | 212 | |
213 |
def sql_for_issue_parent_id_field(field, operator, value) |
|
214 |
case operator |
|
215 |
when "=" |
|
216 |
# accepts a comma separated list of ids |
|
217 |
parent_ids = value.first.to_s.scan(/\d+/).map(&:to_i).uniq |
|
218 |
issue_ids = Issue.where(:parent_id => parent_ids).pluck(:id) |
|
219 |
if issue_ids.present? |
|
220 |
"#{TimeEntry.table_name}.issue_id IN (#{issue_ids.join(',')})" |
|
221 |
else |
|
222 |
"1=0" |
|
223 |
end |
|
224 |
when "~" |
|
225 |
root_id, lft, rgt = Issue.where(:id => value.first.to_i).pick(:root_id, :lft, :rgt) |
|
226 |
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 |
|
227 |
if issue_ids.present? |
|
228 |
"#{TimeEntry.table_name}.issue_id IN (#{issue_ids.join(',')})" |
|
229 |
else |
|
230 |
"1=0" |
|
231 |
end |
|
232 |
else |
|
233 |
sql_for_field("parent_id", operator, value, Issue.table_name, "parent_id") |
|
234 |
end |
|
235 |
end |
|
236 | ||
203 | 237 |
def sql_for_activity_id_field(field, operator, value) |
204 | 238 |
ids = value.map(&:to_i).join(',') |
205 | 239 |
table_name = Enumeration.table_name |
... | ... | |
222 | 256 |
sql_for_field("category_id", operator, value, Issue.table_name, "category_id") |
223 | 257 |
end |
224 | 258 | |
259 |
def sql_for_issue_subject_field(field, operator, value) |
|
260 |
sql_for_field("subject", operator, value, Issue.table_name, "subject") |
|
261 |
end |
|
262 | ||
225 | 263 |
def sql_for_project_status_field(field, operator, value, options={}) |
226 | 264 |
sql_for_field(field, operator, value, Project.table_name, "status") |
227 | 265 |
end |
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}" |
|
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}", "#{issue2.parent.tracker} ##{issue2.parent.id}"].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']) |
- « Previous
- 1
- …
- 3
- 4
- 5
- Next »