summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorGo MAEDA <maeda@farend.jp>2023-05-11 02:08:41 +0000
committerGo MAEDA <maeda@farend.jp>2023-05-11 02:08:41 +0000
commit2caf5eaf973f82d3a9177f63378a642aec8b7d3b (patch)
treefce2bf5a112d3850ad4b6145aa02ae435431823e /app
parent8e170b1ec2f29666aea0166c9bad5575cf5eacce (diff)
downloadredmine-2caf5eaf973f82d3a9177f63378a642aec8b7d3b.tar.gz
redmine-2caf5eaf973f82d3a9177f63378a642aec8b7d3b.zip
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
Diffstat (limited to 'app')
-rw-r--r--app/models/issue_query.rb10
-rw-r--r--app/models/query.rb30
2 files changed, 34 insertions, 6 deletions
diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb
index e573f8782..a0420c994 100644
--- a/app/models/issue_query.rb
+++ b/app/models/issue_query.rb
@@ -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
diff --git a/app/models/query.rb b/app/models/query.rb
index 00d99c24f..f4bbfb5cd 100644
--- a/app/models/query.rb
+++ b/app/models/query.rb
@@ -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