mirror of
https://github.com/meineerde/redmine.git
synced 2026-01-31 11:37:14 +00:00
New issues filter operators "has been", "has never been", and "changed from" (#38527).
Patch by Go MAEDA. git-svn-id: https://svn.redmine.org/redmine/trunk@22240 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
8e170b1ec2
commit
2caf5eaf97
@ -155,11 +155,11 @@ class IssueQuery < Query
|
||||
) if project.nil?
|
||||
add_available_filter(
|
||||
"tracker_id",
|
||||
:type => :list, :values => trackers.collect{|s| [s.name, s.id.to_s]}
|
||||
:type => :list_with_history, :values => trackers.collect{|s| [s.name, s.id.to_s]}
|
||||
)
|
||||
add_available_filter(
|
||||
"priority_id",
|
||||
:type => :list, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s]}
|
||||
:type => :list_with_history, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s]}
|
||||
)
|
||||
add_available_filter(
|
||||
"author_id",
|
||||
@ -167,7 +167,7 @@ class IssueQuery < Query
|
||||
)
|
||||
add_available_filter(
|
||||
"assigned_to_id",
|
||||
:type => :list_optional, :values => lambda {assigned_to_values}
|
||||
:type => :list_optional_with_history, :values => lambda {assigned_to_values}
|
||||
)
|
||||
add_available_filter(
|
||||
"member_of_group",
|
||||
@ -179,7 +179,7 @@ class IssueQuery < Query
|
||||
)
|
||||
add_available_filter(
|
||||
"fixed_version_id",
|
||||
:type => :list_optional, :values => lambda {fixed_version_values}
|
||||
:type => :list_optional_with_history, :values => lambda {fixed_version_values}
|
||||
)
|
||||
add_available_filter(
|
||||
"fixed_version.due_date",
|
||||
@ -194,7 +194,7 @@ class IssueQuery < Query
|
||||
)
|
||||
add_available_filter(
|
||||
"category_id",
|
||||
:type => :list_optional,
|
||||
:type => :list_optional_with_history,
|
||||
:values => lambda {project.issue_categories.collect{|s| [s.name, s.id.to_s]}}
|
||||
) if project
|
||||
add_available_filter "subject", :type => :text
|
||||
|
||||
@ -314,13 +314,18 @@ class Query < ActiveRecord::Base
|
||||
"!p" => :label_no_issues_in_project,
|
||||
"*o" => :label_any_open_issues,
|
||||
"!o" => :label_no_open_issues,
|
||||
"ev" => :label_has_been, # "ev" stands for "ever"
|
||||
"!ev" => :label_has_never_been,
|
||||
"cf" => :label_changed_from
|
||||
}
|
||||
|
||||
class_attribute :operators_by_filter_type
|
||||
self.operators_by_filter_type = {
|
||||
:list => [ "=", "!" ],
|
||||
:list_status => [ "o", "=", "!", "c", "*" ],
|
||||
:list_with_history => [ "=", "!", "ev", "!ev", "cf" ],
|
||||
:list_status => [ "o", "=", "!", "ev", "!ev", "cf", "c", "*" ],
|
||||
:list_optional => [ "=", "!", "!*", "*" ],
|
||||
:list_optional_with_history => [ "=", "!", "ev", "!ev", "cf", "!*", "*" ],
|
||||
:list_subprojects => [ "*", "!*", "=", "!" ],
|
||||
:date => [ "=", ">=", "<=", "><", "<t+", ">t+", "><t+", "t+", "nd", "t", "ld", "nw", "w", "lw", "l2w", "nm", "m", "lm", "y", ">t-", "<t-", "><t-", "t-", "!*", "*" ],
|
||||
:date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "><t-", "t-", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", "!*", "*" ],
|
||||
@ -1438,6 +1443,29 @@ class Query < ActiveRecord::Base
|
||||
sql = sql_contains("#{db_table}.#{db_field}", value.first, :starts_with => true)
|
||||
when "$"
|
||||
sql = sql_contains("#{db_table}.#{db_field}", value.first, :ends_with => true)
|
||||
when "ev", "!ev", "cf"
|
||||
# has been, has never been, changed from
|
||||
if queried_class == Issue && value.present?
|
||||
neg = (operator.start_with?('!') ? 'NOT' : '')
|
||||
subquery =
|
||||
"SELECT 1 FROM #{Journal.table_name}" +
|
||||
" INNER JOIN #{JournalDetail.table_name} ON #{Journal.table_name}.id = #{JournalDetail.table_name}.journal_id" +
|
||||
" WHERE (#{Journal.visible_notes_condition(User.current, :skip_pre_condition => true)}" +
|
||||
" AND #{Journal.table_name}.journalized_type = 'Issue'" +
|
||||
" AND #{Journal.table_name}.journalized_id = #{db_table}.id" +
|
||||
" AND #{JournalDetail.table_name}.property = 'attr'" +
|
||||
" AND #{JournalDetail.table_name}.prop_key = '#{db_field}'" +
|
||||
" AND " +
|
||||
queried_class.send(:sanitize_sql_for_conditions, ["#{JournalDetail.table_name}.old_value IN (?)", value]) +
|
||||
")"
|
||||
if %w[ev !ev].include?(operator)
|
||||
subquery <<
|
||||
" OR " + queried_class.send(:sanitize_sql_for_conditions, ["#{db_table}.#{db_field} IN (?)", value])
|
||||
end
|
||||
sql = "#{neg} EXISTS (#{subquery})"
|
||||
else
|
||||
sql = '1=0'
|
||||
end
|
||||
else
|
||||
raise QueryError, "Unknown query operator #{operator}"
|
||||
end
|
||||
|
||||
@ -818,6 +818,9 @@ en:
|
||||
label_no_issues_in_project: no issues in project
|
||||
label_any_open_issues: any open issues
|
||||
label_no_open_issues: no open issues
|
||||
label_has_been: has been
|
||||
label_has_never_been: has never been
|
||||
label_changed_from: changed from
|
||||
label_day_plural: days
|
||||
label_repository: Repository
|
||||
label_repository_new: New repository
|
||||
|
||||
@ -180,7 +180,9 @@ function buildFilterRow(field, operator, values) {
|
||||
|
||||
switch (filterOptions['type']) {
|
||||
case "list":
|
||||
case "list_with_history":
|
||||
case "list_optional":
|
||||
case "list_optional_with_history":
|
||||
case "list_status":
|
||||
case "list_subprojects":
|
||||
tr.find('td.values').append(
|
||||
|
||||
@ -797,6 +797,73 @@ class QueryTest < ActiveSupport::TestCase
|
||||
assert_equal [2, 14], result.map(&:id).sort
|
||||
end
|
||||
|
||||
def test_operator_changed_from
|
||||
User.current = User.find(1)
|
||||
issue1 = Issue.find(2)
|
||||
issue1.init_journal(User.current)
|
||||
issue1.update(status_id: 1) # Assigned (2) -> New
|
||||
issue2 = Issue.find(8)
|
||||
issue2.init_journal(User.current)
|
||||
issue2.update(status_id: 2) # Closed (5) -> Assigned
|
||||
|
||||
query = IssueQuery.new(
|
||||
:name => '_',
|
||||
:filters => {
|
||||
'status_id' => {
|
||||
:operator => 'cf',
|
||||
:values => [2, 5] # Assigned, Closed
|
||||
}
|
||||
}
|
||||
)
|
||||
result = find_issues_with_query(query)
|
||||
assert_equal(
|
||||
[[2, 'New'], [8, 'Assigned']],
|
||||
result.sort_by(&:id).map {|issue| [issue.id, issue.status.name]}
|
||||
)
|
||||
end
|
||||
|
||||
def test_operator_has_been
|
||||
User.current = User.find(1)
|
||||
issue = Issue.find(8)
|
||||
issue.init_journal(User.current)
|
||||
issue.update(status_id: 2) # Closed (5) -> Assigned
|
||||
|
||||
query = IssueQuery.new(
|
||||
:name => '_',
|
||||
:filters => {
|
||||
'status_id' => {
|
||||
:operator => 'ev',
|
||||
:values => [5] # Closed
|
||||
}
|
||||
}
|
||||
)
|
||||
result = find_issues_with_query(query)
|
||||
assert_equal(
|
||||
[[8, 'Assigned'], [11, 'Closed'], [12, 'Closed']],
|
||||
result.sort_by(&:id).map {|issue| [issue.id, issue.status.name]}
|
||||
)
|
||||
end
|
||||
|
||||
def test_operator_has_never_been
|
||||
User.current = User.find(1)
|
||||
issue = Issue.find(8)
|
||||
issue.init_journal(User.current)
|
||||
issue.update(status_id: 2) # Closed (5) -> Assigned
|
||||
|
||||
query = IssueQuery.new(
|
||||
:name => '_',
|
||||
:filters => {
|
||||
'status_id' => {
|
||||
:operator => '!ev',
|
||||
:values => [5] # Closed
|
||||
}
|
||||
}
|
||||
)
|
||||
result = find_issues_with_query(query)
|
||||
expected = Issue.all.order(:id).ids - [8, 11, 12]
|
||||
assert_equal expected, result.map(&:id).sort
|
||||
end
|
||||
|
||||
def test_range_for_this_week_with_week_starting_on_monday
|
||||
I18n.locale = :fr
|
||||
assert_equal '1', I18n.t(:general_first_day_of_week)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user