From: Jean-Philippe Lang Date: Sat, 7 Nov 2015 09:20:36 +0000 (+0000) Subject: Ability to filter issues blocked by any/no open issues (#16621). X-Git-Tag: 3.2.0~74 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d3d7678c7689ed6c90fd6058b16c18fc7130c0cf;p=redmine.git Ability to filter issues blocked by any/no open issues (#16621). Patch by Arthur Andersen. git-svn-id: http://svn.redmine.org/redmine/trunk@14809 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb index b167c5d9f..fdb5e30cf 100644 --- a/app/models/issue_query.rb +++ b/app/models/issue_query.rb @@ -535,6 +535,9 @@ class IssueQuery < Query op = (operator == "!p" ? 'NOT IN' : 'IN') comp = (operator == "=!p" ? '<>' : '=') "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name}, #{Issue.table_name} relissues WHERE #{IssueRelation.table_name}.relation_type = '#{self.class.connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = relissues.id AND relissues.project_id #{comp} #{value.first.to_i})" + when "*o", "!o" + op = (operator == "!o" ? 'NOT IN' : 'IN') + "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name}, #{Issue.table_name} relissues WHERE #{IssueRelation.table_name}.relation_type = '#{self.class.connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = relissues.id AND relissues.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{self.class.connection.quoted_false}))" end if relation_options[:sym] == field && !options[:reverse] diff --git a/app/models/query.rb b/app/models/query.rb index ed59c5526..0ba7a8c4b 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -203,7 +203,9 @@ class Query < ActiveRecord::Base "!~" => :label_not_contains, "=p" => :label_any_issues_in_project, "=!p" => :label_any_issues_not_in_project, - "!p" => :label_no_issues_in_project + "!p" => :label_no_issues_in_project, + "*o" => :label_any_open_issues, + "!o" => :label_no_open_issues } class_attribute :operators_by_filter_type @@ -218,7 +220,7 @@ class Query < ActiveRecord::Base :text => [ "~", "!~", "!*", "*" ], :integer => [ "=", ">=", "<=", "><", "!*", "*" ], :float => [ "=", ">=", "<=", "><", "!*", "*" ], - :relation => ["=", "=p", "=!p", "!p", "!*", "*"], + :relation => ["=", "=p", "=!p", "!p", "*o", "!o", "!*", "*"], :tree => ["=", "~", "!*", "*"] } @@ -281,7 +283,7 @@ class Query < ActiveRecord::Base # filter requires one or more values (values_for(field) and !values_for(field).first.blank?) or # filter doesn't require any value - ["o", "c", "!*", "*", "t", "ld", "w", "lw", "l2w", "m", "lm", "y"].include? operator_for(field) + ["o", "c", "!*", "*", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", "*o", "!o"].include? operator_for(field) end if filters end diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index bfe68573d..9ab5d3776 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -1061,6 +1061,8 @@ en-GB: permission_view_private_notes: View private notes permission_set_notes_private: Set notes as private label_no_issues_in_project: no issues in project + label_any_open_issues: any open issues + label_no_open_issues: no open issues label_any: all label_last_n_weeks: last %{count} weeks setting_cross_project_subtasks: Allow cross-project subtasks diff --git a/config/locales/en.yml b/config/locales/en.yml index 4ea8ecda3..7a9bd19d6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -712,6 +712,8 @@ en: label_any_issues_in_project: any issues in project label_any_issues_not_in_project: any issues not in project label_no_issues_in_project: no issues in project + label_any_open_issues: any open issues + label_no_open_issues: no open issues label_day_plural: days label_repository: Repository label_repository_new: New repository diff --git a/config/locales/fr.yml b/config/locales/fr.yml index e2bc59b45..76dcfe4d1 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -732,6 +732,8 @@ fr: label_any_issues_in_project: une demande du projet label_any_issues_not_in_project: une demande hors du projet label_no_issues_in_project: aucune demande du projet + label_any_open_issues: une demande ouverte + label_no_open_issues: aucune demande ouverte label_day_plural: jours label_repository: Dépôt label_repository_new: Nouveau dépôt diff --git a/public/javascripts/application.js b/public/javascripts/application.js index b39b0fead..3a2703990 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -275,6 +275,8 @@ function toggleOperator(field) { case "y": case "o": case "c": + case "*o": + case "!o": enableValues(field, []); break; case "><": diff --git a/test/unit/query_test.rb b/test/unit/query_test.rb index af079eb53..f7480e2af 100644 --- a/test/unit/query_test.rb +++ b/test/unit/query_test.rb @@ -846,6 +846,34 @@ class QueryTest < ActiveSupport::TestCase assert_not_include 3, ids end + def test_filter_on_relations_with_any_open_issues + IssueRelation.delete_all + # Issue 1 is blocked by 8, which is closed + IssueRelation.create!(:relation_type => "blocked", :issue_from => Issue.find(1), :issue_to => Issue.find(8)) + # Issue 2 is blocked by 3, which is open + IssueRelation.create!(:relation_type => "blocked", :issue_from => Issue.find(2), :issue_to => Issue.find(3)) + + query = IssueQuery.new(:name => '_') + query.filters = {"blocked" => {:operator => "*o", :values => ['']}} + ids = find_issues_with_query(query).map(&:id) + assert_equal [], ids & [1] + assert_include 2, ids + end + + def test_filter_on_relations_with_no_open_issues + IssueRelation.delete_all + # Issue 1 is blocked by 8, which is closed + IssueRelation.create!(:relation_type => "blocked", :issue_from => Issue.find(1), :issue_to => Issue.find(8)) + # Issue 2 is blocked by 3, which is open + IssueRelation.create!(:relation_type => "blocked", :issue_from => Issue.find(2), :issue_to => Issue.find(3)) + + query = IssueQuery.new(:name => '_') + query.filters = {"blocked" => {:operator => "!o", :values => ['']}} + ids = find_issues_with_query(query).map(&:id) + assert_equal [], ids & [2] + assert_include 1, ids + end + def test_filter_on_relations_with_no_issues IssueRelation.delete_all IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))