@@ -17,7 +17,7 | |||
|
17 | 17 | |
|
18 | 18 | class QueriesController < ApplicationController |
|
19 | 19 | menu_item :issues |
|
20 |
before_action :find_query, : |
|
|
20 | before_action :find_query, :only => [:edit, :update, :destroy] | |
|
21 | 21 | before_action :find_optional_project, :only => [:new, :create] |
|
22 | 22 | |
|
23 | 23 | accept_api_auth :index |
@@ -85,6 +85,25 class QueriesController < ApplicationController | |||
|
85 | 85 | redirect_to_items(:set_filter => 1) |
|
86 | 86 | end |
|
87 | 87 | |
|
88 | # Returns the values for a query filter | |
|
89 | def filter | |
|
90 | q = query_class.new | |
|
91 | if params[:project_id].present? | |
|
92 | q.project = Project.find(params[:project_id]) | |
|
93 | end | |
|
94 | ||
|
95 | unless User.current.allowed_to?(q.class.view_permission, q.project, :global => true) | |
|
96 | raise Unauthorized | |
|
97 | end | |
|
98 | ||
|
99 | filter = q.available_filters[params[:name].to_s] | |
|
100 | values = filter ? filter.values : [] | |
|
101 | ||
|
102 | render :json => values | |
|
103 | rescue ActiveRecord::RecordNotFound | |
|
104 | render_404 | |
|
105 | end | |
|
106 | ||
|
88 | 107 | private |
|
89 | 108 | |
|
90 | 109 | def find_query |
@@ -78,80 +78,37 class IssueQuery < Query | |||
|
78 | 78 | end |
|
79 | 79 | |
|
80 | 80 | def initialize_available_filters |
|
81 | principals = [] | |
|
82 | subprojects = [] | |
|
83 | versions = [] | |
|
84 | categories = [] | |
|
85 | issue_custom_fields = [] | |
|
86 | ||
|
87 | if project | |
|
88 | principals += project.principals.visible | |
|
89 | unless project.leaf? | |
|
90 | subprojects = project.descendants.visible.to_a | |
|
91 | principals += Principal.member_of(subprojects).visible | |
|
92 | end | |
|
93 | versions = project.shared_versions.to_a | |
|
94 | categories = project.issue_categories.to_a | |
|
95 | issue_custom_fields = project.all_issue_custom_fields | |
|
96 | else | |
|
97 | if all_projects.any? | |
|
98 | principals += Principal.member_of(all_projects).visible | |
|
99 | end | |
|
100 | versions = Version.visible.where(:sharing => 'system').to_a | |
|
101 | issue_custom_fields = IssueCustomField.where(:is_for_all => true) | |
|
102 | end | |
|
103 | principals.uniq! | |
|
104 | principals.sort! | |
|
105 | principals.reject! {|p| p.is_a?(GroupBuiltin)} | |
|
106 | users = principals.select {|p| p.is_a?(User)} | |
|
107 | ||
|
108 | 81 | add_available_filter "status_id", |
|
109 | :type => :list_status, :values => IssueStatus.sorted.collect{|s| [s.name, s.id.to_s] } | |
|
82 | :type => :list_status, :values => lambda { IssueStatus.sorted.collect{|s| [s.name, s.id.to_s] } } | |
|
110 | 83 | |
|
111 | if project.nil? | |
|
112 | project_values = [] | |
|
113 | if User.current.logged? && User.current.memberships.any? | |
|
114 | project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"] | |
|
115 | end | |
|
116 | project_values += all_projects_values | |
|
117 | add_available_filter("project_id", | |
|
118 | :type => :list, :values => project_values | |
|
119 | ) unless project_values.empty? | |
|
120 | end | |
|
84 | add_available_filter("project_id", | |
|
85 | :type => :list, :values => lambda { project_values } | |
|
86 | ) if project.nil? | |
|
121 | 87 | |
|
122 | 88 | add_available_filter "tracker_id", |
|
123 | 89 | :type => :list, :values => trackers.collect{|s| [s.name, s.id.to_s] } |
|
90 | ||
|
124 | 91 | add_available_filter "priority_id", |
|
125 | 92 | :type => :list, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] } |
|
126 | 93 | |
|
127 | author_values = [] | |
|
128 | author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? | |
|
129 | author_values += users.collect{|s| [s.name, s.id.to_s] } | |
|
130 | 94 | add_available_filter("author_id", |
|
131 | :type => :list, :values => author_values | |
|
132 | ) unless author_values.empty? | |
|
95 | :type => :list, :values => lambda { author_values } | |
|
96 | ) | |
|
133 | 97 | |
|
134 | assigned_to_values = [] | |
|
135 | assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? | |
|
136 | assigned_to_values += (Setting.issue_group_assignment? ? | |
|
137 | principals : users).collect{|s| [s.name, s.id.to_s] } | |
|
138 | 98 | add_available_filter("assigned_to_id", |
|
139 | :type => :list_optional, :values => assigned_to_values | |
|
140 | ) unless assigned_to_values.empty? | |
|
99 | :type => :list_optional, :values => lambda { assigned_to_values } | |
|
100 | ) | |
|
141 | 101 | |
|
142 | group_values = Group.givable.visible.collect {|g| [g.name, g.id.to_s] } | |
|
143 | 102 | add_available_filter("member_of_group", |
|
144 |
:type => :list_optional, :values => |
|
|
145 | ) unless group_values.empty? | |
|
103 | :type => :list_optional, :values => lambda { Group.givable.visible.collect {|g| [g.name, g.id.to_s] } } | |
|
104 | ) | |
|
146 | 105 | |
|
147 | role_values = Role.givable.collect {|r| [r.name, r.id.to_s] } | |
|
148 | 106 | add_available_filter("assigned_to_role", |
|
149 |
:type => :list_optional, :values => |
|
|
150 | ) unless role_values.empty? | |
|
107 | :type => :list_optional, :values => lambda { Role.givable.collect {|r| [r.name, r.id.to_s] } } | |
|
108 | ) | |
|
151 | 109 | |
|
152 | 110 | add_available_filter "fixed_version_id", |
|
153 | :type => :list_optional, | |
|
154 | :values => Version.sort_by_status(versions).collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s, l("version_status_#{s.status}")] } | |
|
111 | :type => :list_optional, :values => lambda { fixed_version_values } | |
|
155 | 112 | |
|
156 | 113 | add_available_filter "fixed_version.due_date", |
|
157 | 114 | :type => :date, |
@@ -164,7 +121,7 class IssueQuery < Query | |||
|
164 | 121 | |
|
165 | 122 | add_available_filter "category_id", |
|
166 | 123 | :type => :list_optional, |
|
167 | :values => categories.collect{|s| [s.name, s.id.to_s] } | |
|
124 | :values => lambda { project.issue_categories.collect{|s| [s.name, s.id.to_s] } } if project | |
|
168 | 125 | |
|
169 | 126 | add_available_filter "subject", :type => :text |
|
170 | 127 | add_available_filter "description", :type => :text |
@@ -188,18 +145,20 class IssueQuery < Query | |||
|
188 | 145 | :type => :list, :values => [["<< #{l(:label_me)} >>", "me"]] |
|
189 | 146 | end |
|
190 | 147 | |
|
191 |
if |
|
|
148 | if project && !project.leaf? | |
|
192 | 149 | add_available_filter "subproject_id", |
|
193 | 150 | :type => :list_subprojects, |
|
194 | :values => subprojects.collect{|s| [s.name, s.id.to_s] } | |
|
151 | :values => lambda { subproject_values } | |
|
195 | 152 | end |
|
196 | 153 | |
|
154 | ||
|
155 | issue_custom_fields = project ? project.all_issue_custom_fields : IssueCustomField.where(:is_for_all => true) | |
|
197 | 156 | add_custom_fields_filters(issue_custom_fields) |
|
198 | 157 | |
|
199 | 158 | add_associations_custom_fields_filters :project, :author, :assigned_to, :fixed_version |
|
200 | 159 | |
|
201 | 160 | IssueRelation::TYPES.each do |relation_type, options| |
|
202 | add_available_filter relation_type, :type => :relation, :label => options[:name] | |
|
161 | add_available_filter relation_type, :type => :relation, :label => options[:name], :values => lambda {all_projects_values} | |
|
203 | 162 | end |
|
204 | 163 | add_available_filter "parent_id", :type => :tree, :label => :field_parent_issue |
|
205 | 164 | add_available_filter "child_id", :type => :tree, :label => :label_subtask_plural |
@@ -160,6 +160,40 class QueryAssociationCustomFieldColumn < QueryCustomFieldColumn | |||
|
160 | 160 | end |
|
161 | 161 | end |
|
162 | 162 | |
|
163 | class QueryFilter | |
|
164 | include Redmine::I18n | |
|
165 | ||
|
166 | def initialize(field, options) | |
|
167 | @field = field.to_s | |
|
168 | @options = options | |
|
169 | @options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, '')) | |
|
170 | # Consider filters with a Proc for values as remote by default | |
|
171 | @remote = options.key?(:remote) ? options[:remote] : options[:values].is_a?(Proc) | |
|
172 | end | |
|
173 | ||
|
174 | def [](arg) | |
|
175 | if arg == :values | |
|
176 | values | |
|
177 | else | |
|
178 | @options[arg] | |
|
179 | end | |
|
180 | end | |
|
181 | ||
|
182 | def values | |
|
183 | @values ||= begin | |
|
184 | values = @options[:values] | |
|
185 | if values.is_a?(Proc) | |
|
186 | values = values.call | |
|
187 | end | |
|
188 | values | |
|
189 | end | |
|
190 | end | |
|
191 | ||
|
192 | def remote | |
|
193 | @remote | |
|
194 | end | |
|
195 | end | |
|
196 | ||
|
163 | 197 | class Query < ActiveRecord::Base |
|
164 | 198 | class StatementInvalid < ::ActiveRecord::StatementInvalid |
|
165 | 199 | end |
@@ -404,12 +438,17 class Query < ActiveRecord::Base | |||
|
404 | 438 | # Returns a representation of the available filters for JSON serialization |
|
405 | 439 | def available_filters_as_json |
|
406 | 440 | json = {} |
|
407 |
available_filters.each do |field, |
|
|
408 | options = options.slice(:type, :name, :values) | |
|
409 | if options[:values] && values_for(field) | |
|
410 | missing = Array(values_for(field)).select(&:present?) - options[:values].map(&:last) | |
|
411 | if missing.any? && respond_to?(method = "find_#{field}_filter_values") | |
|
412 |
|
|
|
441 | available_filters.each do |field, filter| | |
|
442 | options = {:type => filter[:type], :name => filter[:name]} | |
|
443 | options[:remote] = true if filter.remote | |
|
444 | ||
|
445 | if has_filter?(field) || !filter.remote | |
|
446 | options[:values] = filter.values | |
|
447 | if options[:values] && values_for(field) | |
|
448 | missing = Array(values_for(field)).select(&:present?) - options[:values].map(&:last) | |
|
449 | if missing.any? && respond_to?(method = "find_#{field}_filter_values") | |
|
450 | options[:values] += send(method, missing) | |
|
451 | end | |
|
413 | 452 | end |
|
414 | 453 | end |
|
415 | 454 | json[field] = options.stringify_keys |
@@ -432,6 +471,65 class Query < ActiveRecord::Base | |||
|
432 | 471 | @all_projects_values = values |
|
433 | 472 | end |
|
434 | 473 | |
|
474 | def project_values | |
|
475 | project_values = [] | |
|
476 | if User.current.logged? && User.current.memberships.any? | |
|
477 | project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"] | |
|
478 | end | |
|
479 | project_values += all_projects_values | |
|
480 | project_values | |
|
481 | end | |
|
482 | ||
|
483 | def subproject_values | |
|
484 | project.descendants.visible.collect{|s| [s.name, s.id.to_s] } | |
|
485 | end | |
|
486 | ||
|
487 | def principals | |
|
488 | @principal ||= begin | |
|
489 | principals = [] | |
|
490 | if project | |
|
491 | principals += project.principals.visible | |
|
492 | unless project.leaf? | |
|
493 | principals += Principal.member_of(project.descendants.visible).visible | |
|
494 | end | |
|
495 | else | |
|
496 | principals += Principal.member_of(all_projects).visible | |
|
497 | end | |
|
498 | principals.uniq! | |
|
499 | principals.sort! | |
|
500 | principals.reject! {|p| p.is_a?(GroupBuiltin)} | |
|
501 | principals | |
|
502 | end | |
|
503 | end | |
|
504 | ||
|
505 | def users | |
|
506 | principals.select {|p| p.is_a?(User)} | |
|
507 | end | |
|
508 | ||
|
509 | def author_values | |
|
510 | author_values = [] | |
|
511 | author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? | |
|
512 | author_values += users.collect{|s| [s.name, s.id.to_s] } | |
|
513 | author_values | |
|
514 | end | |
|
515 | ||
|
516 | def assigned_to_values | |
|
517 | assigned_to_values = [] | |
|
518 | assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? | |
|
519 | assigned_to_values += (Setting.issue_group_assignment? ? principals : users).collect{|s| [s.name, s.id.to_s] } | |
|
520 | assigned_to_values | |
|
521 | end | |
|
522 | ||
|
523 | def fixed_version_values | |
|
524 | versions = [] | |
|
525 | if project | |
|
526 | versions = project.shared_versions.to_a | |
|
527 | else | |
|
528 | versions = Version.visible.where(:sharing => 'system').to_a | |
|
529 | end | |
|
530 | Version.sort_by_status(versions).collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s, l("version_status_#{s.status}")] } | |
|
531 | end | |
|
532 | ||
|
435 | 533 | # Adds available filters |
|
436 | 534 | def initialize_available_filters |
|
437 | 535 | # implemented by sub-classes |
@@ -441,7 +539,7 class Query < ActiveRecord::Base | |||
|
441 | 539 | # Adds an available filter |
|
442 | 540 | def add_available_filter(field, options) |
|
443 | 541 | @available_filters ||= ActiveSupport::OrderedHash.new |
|
444 | @available_filters[field] = options | |
|
542 | @available_filters[field] = QueryFilter.new(field, options) | |
|
445 | 543 | @available_filters |
|
446 | 544 | end |
|
447 | 545 | |
@@ -457,9 +555,6 class Query < ActiveRecord::Base | |||
|
457 | 555 | unless @available_filters |
|
458 | 556 | initialize_available_filters |
|
459 | 557 | @available_filters ||= {} |
|
460 | @available_filters.each do |field, options| | |
|
461 | options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, '')) | |
|
462 | end | |
|
463 | 558 | end |
|
464 | 559 | @available_filters |
|
465 | 560 | end |
@@ -42,65 +42,38 class TimeEntryQuery < Query | |||
|
42 | 42 | def initialize_available_filters |
|
43 | 43 | add_available_filter "spent_on", :type => :date_past |
|
44 | 44 | |
|
45 | principals = [] | |
|
46 | versions = [] | |
|
47 | if project | |
|
48 | principals += project.principals.visible.sort | |
|
49 |
|
|
|
50 | subprojects = project.descendants.visible.to_a | |
|
51 |
|
|
|
52 | add_available_filter "subproject_id", | |
|
53 | :type => :list_subprojects, | |
|
54 | :values => subprojects.collect{|s| [s.name, s.id.to_s] } | |
|
55 | principals += Principal.member_of(subprojects).visible | |
|
56 | end | |
|
57 | end | |
|
58 | versions = project.shared_versions.to_a | |
|
59 | else | |
|
60 | if all_projects.any? | |
|
61 | # members of visible projects | |
|
62 | principals += Principal.member_of(all_projects).visible | |
|
63 | # project filter | |
|
64 | project_values = [] | |
|
65 | if User.current.logged? && User.current.memberships.any? | |
|
66 | project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"] | |
|
67 | end | |
|
68 | project_values += all_projects_values | |
|
69 | add_available_filter("project_id", | |
|
70 | :type => :list, :values => project_values | |
|
71 | ) unless project_values.empty? | |
|
72 | end | |
|
45 | add_available_filter("project_id", | |
|
46 | :type => :list, :values => lambda { project_values } | |
|
47 | ) if project.nil? | |
|
48 | ||
|
49 | if project && !project.leaf? | |
|
50 | add_available_filter "subproject_id", | |
|
51 | :type => :list_subprojects, | |
|
52 | :values => lambda { subproject_values } | |
|
73 | 53 | end |
|
74 | 54 | |
|
75 | 55 | add_available_filter("issue_id", :type => :tree, :label => :label_issue) |
|
76 | 56 | add_available_filter("issue.tracker_id", |
|
77 | 57 | :type => :list, |
|
78 | 58 | :name => l("label_attribute_of_issue", :name => l(:field_tracker)), |
|
79 | :values => Tracker.sorted.map {|t| [t.name, t.id.to_s]}) | |
|
59 | :values => lambda { Tracker.sorted.map {|t| [t.name, t.id.to_s]} }) | |
|
80 | 60 | add_available_filter("issue.status_id", |
|
81 | 61 | :type => :list, |
|
82 | 62 | :name => l("label_attribute_of_issue", :name => l(:field_status)), |
|
83 | :values => IssueStatus.sorted.map {|s| [s.name, s.id.to_s]}) | |
|
63 | :values => lambda { IssueStatus.sorted.map {|s| [s.name, s.id.to_s]} }) | |
|
84 | 64 | add_available_filter("issue.fixed_version_id", |
|
85 | 65 | :type => :list, |
|
86 | 66 | :name => l("label_attribute_of_issue", :name => l(:field_fixed_version)), |
|
87 | :values => Version.sort_by_status(versions).collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s, l("version_status_#{s.status}")] }) | |
|
88 | ||
|
89 | principals.uniq! | |
|
90 | principals.sort! | |
|
91 | users = principals.select {|p| p.is_a?(User)} | |
|
67 | :values => lambda { fixed_version_values }) if project | |
|
92 | 68 | |
|
93 | users_values = [] | |
|
94 | users_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? | |
|
95 | users_values += users.collect{|s| [s.name, s.id.to_s] } | |
|
96 | 69 | add_available_filter("user_id", |
|
97 |
:type => :list_optional, :values => |
|
|
98 | ) unless users_values.empty? | |
|
70 | :type => :list_optional, :values => lambda { author_values } | |
|
71 | ) | |
|
99 | 72 | |
|
100 | 73 | activities = (project ? project.activities : TimeEntryActivity.shared) |
|
101 | 74 | add_available_filter("activity_id", |
|
102 | 75 | :type => :list, :values => activities.map {|a| [a.name, a.id.to_s]} |
|
103 | ) unless activities.empty? | |
|
76 | ) | |
|
104 | 77 | |
|
105 | 78 | add_available_filter "comments", :type => :text |
|
106 | 79 | add_available_filter "hours", :type => :float |
@@ -3,7 +3,9 var operatorLabels = <%= raw_json Query.operators_labels %>; | |||
|
3 | 3 | var operatorByType = <%= raw_json Query.operators_by_filter_type %>; |
|
4 | 4 | var availableFilters = <%= raw_json query.available_filters_as_json %>; |
|
5 | 5 | var labelDayPlural = <%= raw_json l(:label_day_plural) %>; |
|
6 | var allProjects = <%= raw_json query.all_projects_values %>; | |
|
6 | ||
|
7 | var filtersUrl = <%= raw_json queries_filter_path(:project_id => @query.project.try(:id), :type => @query.type) %>; | |
|
8 | ||
|
7 | 9 | $(document).ready(function(){ |
|
8 | 10 | initFilters(); |
|
9 | 11 | <% query.filters.each do |field, options| %> |
@@ -199,6 +199,7 Rails.application.routes.draw do | |||
|
199 | 199 | match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete |
|
200 | 200 | |
|
201 | 201 | resources :queries, :except => [:show] |
|
202 | get '/queries/filter', :to => 'queries#filter', :as => 'queries_filter' | |
|
202 | 203 | |
|
203 | 204 | resources :news, :only => [:index, :show, :edit, :update, :destroy] |
|
204 | 205 | match '/news/:id/comments', :to => 'comments#create', :via => :post |
@@ -120,6 +120,18 function initFilters() { | |||
|
120 | 120 | function addFilter(field, operator, values) { |
|
121 | 121 | var fieldId = field.replace('.', '_'); |
|
122 | 122 | var tr = $('#tr_'+fieldId); |
|
123 | ||
|
124 | var filterOptions = availableFilters[field]; | |
|
125 | if (!filterOptions) return; | |
|
126 | ||
|
127 | if (filterOptions['remote'] && filterOptions['values'] == null) { | |
|
128 | $.getJSON(filtersUrl, {'name': field}).done(function(data) { | |
|
129 | filterOptions['values'] = data; | |
|
130 | addFilter(field, operator, values) ; | |
|
131 | }); | |
|
132 | return; | |
|
133 | } | |
|
134 | ||
|
123 | 135 | if (tr.length > 0) { |
|
124 | 136 | tr.show(); |
|
125 | 137 | } else { |
@@ -134,7 +146,7 function addFilter(field, operator, values) { | |||
|
134 | 146 | }); |
|
135 | 147 | } |
|
136 | 148 | |
|
137 | function buildFilterRow(field, operator, values) { | |
|
149 | function buildFilterRow(field, operator, values, loadedValues) { | |
|
138 | 150 | var fieldId = field.replace('.', '_'); |
|
139 | 151 | var filterTable = $("#filters-table"); |
|
140 | 152 | var filterOptions = availableFilters[field]; |
@@ -212,8 +224,8 function buildFilterRow(field, operator, values) { | |||
|
212 | 224 | ); |
|
213 | 225 | $('#values_'+fieldId).val(values[0]); |
|
214 | 226 | select = tr.find('td.values select'); |
|
215 |
for (i = 0; i < |
|
|
216 |
var filterValue = |
|
|
227 | for (i = 0; i < filterValues.length; i++) { | |
|
228 | var filterValue = filterValues[i]; | |
|
217 | 229 | var option = $('<option>'); |
|
218 | 230 | option.val(filterValue[1]).text(filterValue[0]); |
|
219 | 231 | if (values[0] == filterValue[1]) { option.attr('selected', true); } |
@@ -18,7 +18,12 | |||
|
18 | 18 | require File.expand_path('../../test_helper', __FILE__) |
|
19 | 19 | |
|
20 | 20 | class QueriesControllerTest < Redmine::ControllerTest |
|
21 | fixtures :projects, :users, :members, :member_roles, :roles, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues, :custom_fields, :custom_values, :queries, :enabled_modules | |
|
21 | fixtures :projects, :enabled_modules, | |
|
22 | :users, :email_addresses, | |
|
23 | :members, :member_roles, :roles, | |
|
24 | :trackers, :issue_statuses, :issue_categories, :enumerations, :versions, | |
|
25 | :issues, :custom_fields, :custom_values, | |
|
26 | :queries | |
|
22 | 27 | |
|
23 | 28 | def setup |
|
24 | 29 | User.current = nil |
@@ -397,4 +402,24 class QueriesControllerTest < Redmine::ControllerTest | |||
|
397 | 402 | assert_response :success |
|
398 | 403 | assert_include 'addFilter("subject", "=", ["foo\/bar"]);', response.body |
|
399 | 404 | end |
|
405 | ||
|
406 | def test_filter_with_project_id_should_return_filter_values | |
|
407 | @request.session[:user_id] = 2 | |
|
408 | get :filter, :project_id => 1, :name => 'fixed_version_id' | |
|
409 | ||
|
410 | assert_response :success | |
|
411 | assert_equal 'application/json', response.content_type | |
|
412 | json = ActiveSupport::JSON.decode(response.body) | |
|
413 | assert_include ["eCookbook - 2.0", "3", "open"], json | |
|
414 | end | |
|
415 | ||
|
416 | def test_filter_without_project_id_should_return_filter_values | |
|
417 | @request.session[:user_id] = 2 | |
|
418 | get :filter, :name => 'fixed_version_id' | |
|
419 | ||
|
420 | assert_response :success | |
|
421 | assert_equal 'application/json', response.content_type | |
|
422 | json = ActiveSupport::JSON.decode(response.body) | |
|
423 | assert_include ["OnlineStore - Systemwide visible version", "7", "open"], json | |
|
424 | end | |
|
400 | 425 | end |
@@ -21,6 +21,7 class RoutingQueriesTest < Redmine::RoutingTest | |||
|
21 | 21 | def test_queries |
|
22 | 22 | should_route 'GET /queries/new' => 'queries#new' |
|
23 | 23 | should_route 'POST /queries' => 'queries#create' |
|
24 | should_route 'GET /queries/filter' => 'queries#filter' | |
|
24 | 25 | |
|
25 | 26 | should_route 'GET /queries/1/edit' => 'queries#edit', :id => '1' |
|
26 | 27 | should_route 'PUT /queries/1' => 'queries#update', :id => '1' |
@@ -118,6 +118,28 class QueryTest < ActiveSupport::TestCase | |||
|
118 | 118 | assert_not_include 'start_date', query.available_filters |
|
119 | 119 | end |
|
120 | 120 | |
|
121 | def test_filter_values_without_project_should_be_arrays | |
|
122 | q = IssueQuery.new | |
|
123 | assert_nil q.project | |
|
124 | ||
|
125 | q.available_filters.each do |name, filter| | |
|
126 | values = filter.values | |
|
127 | assert (values.nil? || values.is_a?(Array)), | |
|
128 | "#values for #{name} filter returned a #{values.class.name}" | |
|
129 | end | |
|
130 | end | |
|
131 | ||
|
132 | def test_filter_values_with_project_should_be_arrays | |
|
133 | q = IssueQuery.new(:project => Project.find(1)) | |
|
134 | assert_not_nil q.project | |
|
135 | ||
|
136 | q.available_filters.each do |name, filter| | |
|
137 | values = filter.values | |
|
138 | assert (values.nil? || values.is_a?(Array)), | |
|
139 | "#values for #{name} filter returned a #{values.class.name}" | |
|
140 | end | |
|
141 | end | |
|
142 | ||
|
121 | 143 | def find_issues_with_query(query) |
|
122 | 144 | Issue.joins(:status, :tracker, :project, :priority).where( |
|
123 | 145 | query.statement |
@@ -27,6 +27,28 class TimeEntryQueryTest < ActiveSupport::TestCase | |||
|
27 | 27 | :groups_users, |
|
28 | 28 | :enabled_modules |
|
29 | 29 | |
|
30 | def test_filter_values_without_project_should_be_arrays | |
|
31 | q = TimeEntryQuery.new | |
|
32 | assert_nil q.project | |
|
33 | ||
|
34 | q.available_filters.each do |name, filter| | |
|
35 | values = filter.values | |
|
36 | assert (values.nil? || values.is_a?(Array)), | |
|
37 | "#values for #{name} filter returned a #{values.class.name}" | |
|
38 | end | |
|
39 | end | |
|
40 | ||
|
41 | def test_filter_values_with_project_should_be_arrays | |
|
42 | q = TimeEntryQuery.new(:project => Project.find(1)) | |
|
43 | assert_not_nil q.project | |
|
44 | ||
|
45 | q.available_filters.each do |name, filter| | |
|
46 | values = filter.values | |
|
47 | assert (values.nil? || values.is_a?(Array)), | |
|
48 | "#values for #{name} filter returned a #{values.class.name}" | |
|
49 | end | |
|
50 | end | |
|
51 | ||
|
30 | 52 | def test_cross_project_activity_filter_should_propose_non_active_activities |
|
31 | 53 | activity = TimeEntryActivity.create!(:name => 'Disabled', :active => false) |
|
32 | 54 | assert !activity.active? |
General Comments 0
You need to be logged in to leave comments.
Login now