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 »