]> source.dussan.org Git - redmine.git/commitdiff
Ability to filter issues blocked by any/no open issues (#16621).
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sat, 7 Nov 2015 09:20:36 +0000 (09:20 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sat, 7 Nov 2015 09:20:36 +0000 (09:20 +0000)
Patch by Arthur Andersen.

git-svn-id: http://svn.redmine.org/redmine/trunk@14809 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/models/issue_query.rb
app/models/query.rb
config/locales/en-GB.yml
config/locales/en.yml
config/locales/fr.yml
public/javascripts/application.js
test/unit/query_test.rb

index b167c5d9f3fd201fd25cd810ffd35333083901b8..fdb5e30cf4e8cd9f295cb63da73fd502a447752b 100644 (file)
@@ -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]
index ed59c5526eb6c70ed7bfb68516300f6429295b1e..0ba7a8c4bb4d6a99719029bd9faff61313e52f49 100644 (file)
@@ -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
 
index bfe68573df09c2e600cc9284d2445ca1d07b0339..9ab5d3776982ef4c0c280f53f14abb13862edd4f 100644 (file)
@@ -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
index 4ea8ecda3e69f3ecb23deb360d396305067225b9..7a9bd19d6ceef483d3e911ce132deeb60ab952d6 100644 (file)
@@ -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
index e2bc59b457341378eb4a027c9b7a1d6ceaadaf71..76dcfe4d161a1c72bda5f283f68eeae31fdd0b6c 100644 (file)
@@ -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
index b39b0fead82448506784c72f0f37c2a7ef7da41b..3a2703990411c3c789daacae362c0fc9656697de 100644 (file)
@@ -275,6 +275,8 @@ function toggleOperator(field) {
     case "y":
     case "o":
     case "c":
+    case "*o":
+    case "!o":
       enableValues(field, []);
       break;
     case "><":
index af079eb53382d451cea61e4ab4708df0f0286729..f7480e2afc701b1c1309ae869764dd43c131feb1 100644 (file)
@@ -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))