plutonium 0.15.3 → 0.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/plutonium.css +1 -1
- data/app/views/components/sidebar_menu/sidebar_menu_component.rb +1 -1
- data/app/views/components/table_search_input/table_search_input_component.html.erb +3 -3
- data/app/views/resource/_resource_table.html.erb +0 -321
- data/lib/plutonium/core/controllers/authorizable.rb +5 -0
- data/lib/plutonium/core/controllers/entity_scoping.rb +4 -4
- data/lib/plutonium/definition/base.rb +8 -0
- data/lib/plutonium/definition/defineable_props.rb +1 -1
- data/lib/plutonium/definition/presentable.rb +71 -0
- data/lib/plutonium/interaction/README.md +1 -1
- data/lib/plutonium/interaction/base.rb +6 -6
- data/lib/plutonium/lib/deep_freezer.rb +31 -0
- data/lib/plutonium/query/adhoc_block.rb +19 -0
- data/lib/plutonium/query/base.rb +29 -0
- data/lib/plutonium/query/filter.rb +12 -0
- data/lib/plutonium/query/filters/text.rb +77 -0
- data/lib/plutonium/query/model_scope.rb +19 -0
- data/lib/plutonium/resource/controller.rb +14 -7
- data/lib/plutonium/resource/controllers/authorizable.rb +1 -1
- data/lib/plutonium/resource/controllers/crud_actions/index_action.rb +26 -0
- data/lib/plutonium/resource/controllers/crud_actions.rb +2 -5
- data/lib/plutonium/resource/controllers/defineable.rb +0 -2
- data/lib/plutonium/resource/controllers/queryable.rb +36 -20
- data/lib/plutonium/resource/policy.rb +1 -1
- data/lib/plutonium/resource/query_object.rb +61 -147
- data/lib/plutonium/{refinements/parameter_refinements.rb → support/parameters.rb} +5 -7
- data/lib/plutonium/ui/component/methods.rb +1 -1
- data/lib/plutonium/ui/display/resource.rb +19 -15
- data/lib/plutonium/ui/form/query.rb +171 -0
- data/lib/plutonium/ui/form/resource.rb +21 -17
- data/lib/plutonium/ui/table/components/scopes_bar.rb +1 -1
- data/lib/plutonium/ui/table/components/search_bar.rb +6 -139
- data/lib/plutonium/ui/table/resource.rb +10 -9
- data/lib/plutonium/version.rb +1 -1
- data/package-lock.json +2 -2
- data/package.json +1 -1
- metadata +12 -4
- data/lib/plutonium/interaction/concerns/presentable.rb +0 -73
@@ -0,0 +1,77 @@
|
|
1
|
+
module Plutonium
|
2
|
+
module Query
|
3
|
+
module Filters
|
4
|
+
class Text < Filter
|
5
|
+
VALID_PREDICATES = [
|
6
|
+
:eq, # Equal
|
7
|
+
:not_eq, # Not equal
|
8
|
+
:matches, # LIKE with wildcards
|
9
|
+
:not_matches, # NOT LIKE with wildcards
|
10
|
+
:starts_with, # LIKE with suffix wildcard
|
11
|
+
:ends_with, # LIKE with prefix wildcard
|
12
|
+
:contains, # LIKE with wildcards on both sides
|
13
|
+
:not_contains # NOT LIKE with wildcards on both sides
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
def initialize(predicate: :eq, **)
|
17
|
+
super(**)
|
18
|
+
unless VALID_PREDICATES.include?(predicate)
|
19
|
+
raise ArgumentError, "unsupported predicate #{predicate}. Valid predicates are: #{VALID_PREDICATES.join(", ")}"
|
20
|
+
end
|
21
|
+
@predicate = predicate
|
22
|
+
end
|
23
|
+
|
24
|
+
def apply(scope, query:)
|
25
|
+
case @predicate
|
26
|
+
when :eq
|
27
|
+
scope.where(key => query)
|
28
|
+
when :not_eq
|
29
|
+
scope.where.not(key => query)
|
30
|
+
when :matches
|
31
|
+
scope.where("#{key} LIKE ?", query.tr("*", "%"))
|
32
|
+
when :not_matches
|
33
|
+
scope.where.not("#{key} LIKE ?", query.tr("*", "%"))
|
34
|
+
when :starts_with
|
35
|
+
scope.where("#{key} LIKE ?", "#{sanitize_like(query)}%")
|
36
|
+
when :ends_with
|
37
|
+
scope.where("#{key} LIKE ?", "%#{sanitize_like(query)}")
|
38
|
+
when :contains
|
39
|
+
scope.where("#{key} LIKE ?", "%#{sanitize_like(query)}%")
|
40
|
+
when :not_contains
|
41
|
+
scope.where.not("#{key} LIKE ?", "%#{sanitize_like(query)}%")
|
42
|
+
else
|
43
|
+
raise NotImplementedError, "text filter predicate #{@predicate}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def customize_inputs
|
48
|
+
input :query
|
49
|
+
field :query, placeholder: generate_placeholder
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def generate_placeholder
|
55
|
+
base = key.to_s.humanize
|
56
|
+
case @predicate
|
57
|
+
when :matches, :not_matches
|
58
|
+
"#{base} (use * as wildcard)"
|
59
|
+
when :starts_with
|
60
|
+
"#{base} starts with..."
|
61
|
+
when :ends_with
|
62
|
+
"#{base} ends with..."
|
63
|
+
when :contains, :not_contains
|
64
|
+
"#{base} contains..."
|
65
|
+
else
|
66
|
+
base
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def sanitize_like(string)
|
71
|
+
# Escape special LIKE characters: %, _, and \
|
72
|
+
string.gsub(/[%_\\]/) { |char| "\\#{char}" }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Plutonium
|
2
|
+
module Query
|
3
|
+
class ModelScope < Base
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
# Initializes a ModelScope with a given name.
|
7
|
+
#
|
8
|
+
# @param name [Symbol] The name of the scope.
|
9
|
+
def initialize(name)
|
10
|
+
super()
|
11
|
+
@name = name
|
12
|
+
end
|
13
|
+
|
14
|
+
def apply(scope, **)
|
15
|
+
scope.public_send(name, **)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,9 +1,6 @@
|
|
1
1
|
require "action_controller"
|
2
2
|
require "pagy"
|
3
3
|
|
4
|
-
require File.expand_path("refinements/parameter_refinements", Plutonium.lib_root)
|
5
|
-
using Plutonium::Refinements::ParameterRefinements
|
6
|
-
|
7
4
|
module Plutonium
|
8
5
|
module Resource
|
9
6
|
# Controller module to handle resource actions and concerns
|
@@ -172,8 +169,13 @@ module Plutonium
|
|
172
169
|
# @param [Hash] input_params The input parameters
|
173
170
|
def override_entity_scoping_params(input_params)
|
174
171
|
if scoped_to_entity?
|
175
|
-
input_params
|
176
|
-
|
172
|
+
if input_params.key?(scoped_entity_param_key) || resource_class.method_defined?(:"#{scoped_entity_param_key}=")
|
173
|
+
input_params[scoped_entity_param_key] = current_scoped_entity
|
174
|
+
end
|
175
|
+
|
176
|
+
if input_params.key?(:"#{scoped_entity_param_key}_id") || resource_class.method_defined?(:"#{scoped_entity_param_key}_id=")
|
177
|
+
input_params[:"#{scoped_entity_param_key}_id"] = current_scoped_entity.id
|
178
|
+
end
|
177
179
|
end
|
178
180
|
end
|
179
181
|
|
@@ -181,8 +183,13 @@ module Plutonium
|
|
181
183
|
# @param [Hash] input_params The input parameters
|
182
184
|
def override_parent_params(input_params)
|
183
185
|
if current_parent.present?
|
184
|
-
input_params
|
185
|
-
|
186
|
+
if input_params.key?(parent_input_param) || resource_class.method_defined?(:"#{parent_input_param}=")
|
187
|
+
input_params[parent_input_param] = current_parent
|
188
|
+
end
|
189
|
+
|
190
|
+
if input_params.key?(:"#{parent_input_param}_id") || resource_class.method_defined?(:"#{parent_input_param}_id=")
|
191
|
+
input_params[:"#{parent_input_param}_id"] = current_parent.id
|
192
|
+
end
|
186
193
|
end
|
187
194
|
end
|
188
195
|
|
@@ -77,7 +77,7 @@ module Plutonium
|
|
77
77
|
#
|
78
78
|
# @raise [ActionMissingCurrentAuthorizedScope] if current_authorized_scope hasn't been called
|
79
79
|
def verify_current_authorized_scope
|
80
|
-
return if
|
80
|
+
return if verify_current_authorized_scope_skipped
|
81
81
|
return if current_authorized_scope_count > 0
|
82
82
|
|
83
83
|
raise ActionMissingCurrentAuthorizedScope.new(controller_path, action_name)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Plutonium
|
2
|
+
module Resource
|
3
|
+
module Controllers
|
4
|
+
module CrudActions
|
5
|
+
module IndexAction
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def setup_index_action!
|
11
|
+
@pagy, @resource_records = pagy filtered_resource_collection
|
12
|
+
end
|
13
|
+
|
14
|
+
def filtered_resource_collection
|
15
|
+
query_params = current_definition
|
16
|
+
.query_form.new(nil, query_object: current_query_object, page_size: nil)
|
17
|
+
.extract_input(params)[:q]
|
18
|
+
|
19
|
+
base_query = current_authorized_scope
|
20
|
+
current_query_object.apply(base_query, query_params)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -3,6 +3,7 @@ module Plutonium
|
|
3
3
|
module Controllers
|
4
4
|
module CrudActions
|
5
5
|
extend ActiveSupport::Concern
|
6
|
+
include IndexAction
|
6
7
|
|
7
8
|
included do
|
8
9
|
helper_method :preferred_action_after_submit
|
@@ -13,11 +14,7 @@ module Plutonium
|
|
13
14
|
authorize_current! resource_class
|
14
15
|
set_page_title resource_class.model_name.human.pluralize.titleize
|
15
16
|
|
16
|
-
|
17
|
-
base_query = current_authorized_scope
|
18
|
-
base_query = @search_object.apply(base_query)
|
19
|
-
# base_query = base_query.public_send(params[:scope].to_sym) if params[:scope].present?
|
20
|
-
@pagy, @resource_records = pagy base_query
|
17
|
+
setup_index_action!
|
21
18
|
|
22
19
|
render :index
|
23
20
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
using Plutonium::Refinements::ParameterRefinements
|
2
|
-
|
3
1
|
module Plutonium
|
4
2
|
module Resource
|
5
3
|
module Controllers
|
@@ -7,7 +5,7 @@ module Plutonium
|
|
7
5
|
extend ActiveSupport::Concern
|
8
6
|
|
9
7
|
included do
|
10
|
-
helper_method :
|
8
|
+
helper_method :raw_resource_query_params, :current_query_object
|
11
9
|
end
|
12
10
|
|
13
11
|
def resource_query_object(resource_class, params)
|
@@ -16,28 +14,46 @@ module Plutonium
|
|
16
14
|
end
|
17
15
|
|
18
16
|
def current_query_object
|
19
|
-
@current_query_object ||=
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
17
|
+
@current_query_object ||=
|
18
|
+
Plutonium::Resource::QueryObject.new(resource_class, raw_resource_query_params) do |query_object|
|
19
|
+
if current_definition.search_definition
|
20
|
+
query_object.define_search proc { |scope, search:|
|
21
|
+
current_definition.search_definition.call(scope, search)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
current_definition.defined_scopes.each do |key, value|
|
26
|
+
query_object.define_scope key, value[:block], **value[:options]
|
27
|
+
end
|
28
|
+
|
29
|
+
current_definition.defined_sorts.each do |key, value|
|
30
|
+
query_object.define_sorter key, value[:block], **value[:options]
|
31
|
+
end
|
32
|
+
|
33
|
+
current_definition.defined_filters.each do |key, value|
|
34
|
+
with = value[:options][:with]
|
35
|
+
if with.is_a?(Class) && with < Plutonium::Query::Filter
|
36
|
+
options = value[:options].except(:with)
|
37
|
+
options[:key] ||= key
|
38
|
+
with = with.new(**options)
|
39
|
+
end
|
40
|
+
query_object.define_filter key, with, &value[:block]
|
41
|
+
end
|
42
|
+
|
43
|
+
query_object
|
28
44
|
end
|
45
|
+
end
|
29
46
|
|
30
|
-
|
31
|
-
|
47
|
+
def raw_resource_query_params
|
48
|
+
@raw_resource_query_params ||= begin
|
49
|
+
query_params = params[:q]
|
50
|
+
if query_params.is_a?(ActionController::Parameters)
|
51
|
+
query_params.to_unsafe_h
|
52
|
+
else
|
53
|
+
{}.with_indifferent_access
|
32
54
|
end
|
33
|
-
|
34
|
-
query_object
|
35
55
|
end
|
36
56
|
end
|
37
|
-
|
38
|
-
def resource_query_params
|
39
|
-
(params[:q]&.nilify&.to_unsafe_h || {}).with_indifferent_access
|
40
|
-
end
|
41
57
|
end
|
42
58
|
end
|
43
59
|
end
|
@@ -1,127 +1,27 @@
|
|
1
1
|
module Plutonium
|
2
2
|
module Resource
|
3
3
|
class QueryObject
|
4
|
-
class << self
|
5
|
-
end
|
6
|
-
|
7
|
-
class Query
|
8
|
-
include Plutonium::Core::Definers::FieldInputDefiner
|
9
|
-
|
10
|
-
# Applies the query to the given scope using the provided parameters.
|
11
|
-
#
|
12
|
-
# @param scope [Object] The initial scope to which the query will be applied.
|
13
|
-
# @param params [Hash] The parameters for the query.
|
14
|
-
# @return [Object] The modified scope.
|
15
|
-
def apply(scope, params)
|
16
|
-
params = extract_query_params(params)
|
17
|
-
|
18
|
-
if input_definitions.size == params.size
|
19
|
-
apply_internal(scope, params)
|
20
|
-
else
|
21
|
-
scope
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
# Abstract method to apply the query logic to the scope.
|
28
|
-
# Should be implemented by subclasses.
|
29
|
-
#
|
30
|
-
# @param scope [Object] The initial scope.
|
31
|
-
# @param params [Hash] The parameters for the query.
|
32
|
-
# @raise [NotImplementedError] If the method is not implemented.
|
33
|
-
def apply_internal(scope, params)
|
34
|
-
raise NotImplementedError, "#{self.class}#apply_internal"
|
35
|
-
end
|
36
|
-
|
37
|
-
# Extracts query parameters based on the defined inputs.
|
38
|
-
#
|
39
|
-
# @param params [Hash] The parameters to extract.
|
40
|
-
# @return [Hash] The extracted and symbolized parameters.
|
41
|
-
def extract_query_params(params)
|
42
|
-
input_definitions.collect_all(params).compact.symbolize_keys
|
43
|
-
end
|
44
|
-
|
45
|
-
# @return [nil] The resource class (default implementation returns nil).
|
46
|
-
def resource_class = nil
|
47
|
-
end
|
48
|
-
|
49
|
-
class ScopeQuery < Query
|
50
|
-
attr_reader :name
|
51
|
-
|
52
|
-
# Initializes a ScopeQuery with a given name.
|
53
|
-
#
|
54
|
-
# @param name [Symbol] The name of the scope.
|
55
|
-
def initialize(name)
|
56
|
-
@name = name
|
57
|
-
yield self if block_given?
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
# Applies the scope query to the given scope.
|
63
|
-
#
|
64
|
-
# @param scope [Object] The initial scope.
|
65
|
-
# @param params [Hash] The parameters for the query.
|
66
|
-
# @return [Object] The modified scope.
|
67
|
-
def apply_internal(scope, params)
|
68
|
-
scope.public_send(name, **params)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
class BlockQuery < Query
|
73
|
-
attr_reader :body
|
74
|
-
|
75
|
-
# Initializes a BlockQuery with a given block of code.
|
76
|
-
#
|
77
|
-
# @param body [Proc] The block of code for the query.
|
78
|
-
def initialize(body)
|
79
|
-
@body = body
|
80
|
-
yield self if block_given?
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
# Applies the block query to the given scope.
|
86
|
-
#
|
87
|
-
# @param scope [Object] The initial scope.
|
88
|
-
# @param params [Hash] The parameters for the query.
|
89
|
-
# @return [Object] The modified scope.
|
90
|
-
def apply_internal(scope, params)
|
91
|
-
if body.arity == 1
|
92
|
-
body.call(scope)
|
93
|
-
else
|
94
|
-
body.call(scope, **params)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
4
|
attr_reader :search_filter, :search_query
|
100
5
|
|
101
|
-
# Initializes a QueryObject with the given
|
6
|
+
# Initializes a QueryObject with the given resource_class and parameters.
|
102
7
|
#
|
103
|
-
# @param
|
8
|
+
# @param resource_class [Object] The resource class.
|
104
9
|
# @param params [Hash] The parameters for initialization.
|
105
|
-
def initialize(
|
106
|
-
@
|
10
|
+
def initialize(resource_class, params, &)
|
11
|
+
@resource_class = resource_class
|
12
|
+
@params = params
|
107
13
|
|
108
14
|
define_standard_queries
|
109
|
-
define_scopes
|
110
|
-
define_filters
|
111
|
-
define_sorters
|
112
|
-
|
113
15
|
yield self if block_given?
|
114
|
-
|
115
|
-
|
116
|
-
extract_sort_params(params)
|
16
|
+
extract_filter_params
|
17
|
+
extract_sort_params
|
117
18
|
end
|
118
19
|
|
119
20
|
# Defines a filter with the given name and body.
|
120
21
|
#
|
121
22
|
# @param name [Symbol] The name of the filter.
|
122
23
|
# @param body [Proc, nil] The body of the filter.
|
123
|
-
def define_filter(name, body
|
124
|
-
body ||= name
|
24
|
+
def define_filter(name, body, &)
|
125
25
|
filter_definitions[name] = build_query(body, &)
|
126
26
|
end
|
127
27
|
|
@@ -145,7 +45,7 @@ module Plutonium
|
|
145
45
|
end
|
146
46
|
|
147
47
|
sort_definitions[name] = build_query(body) do |query|
|
148
|
-
query.
|
48
|
+
query.input :direction
|
149
49
|
end
|
150
50
|
end
|
151
51
|
|
@@ -154,7 +54,7 @@ module Plutonium
|
|
154
54
|
# @param body [Proc, Symbol] The body of the search filter.
|
155
55
|
def define_search(body)
|
156
56
|
@search_filter = build_query(body) do |query|
|
157
|
-
query.
|
57
|
+
query.input :search
|
158
58
|
end
|
159
59
|
end
|
160
60
|
|
@@ -172,17 +72,21 @@ module Plutonium
|
|
172
72
|
q[:sort_fields] = selected_sort_fields.dup
|
173
73
|
handle_sort_options!(q, options)
|
174
74
|
|
175
|
-
|
75
|
+
q.merge! params.slice(*filter_definitions.keys)
|
76
|
+
query_params = deep_compact({q: q}).to_param
|
77
|
+
"?#{query_params}"
|
176
78
|
end
|
177
79
|
|
178
80
|
# Applies the defined filters and sorts to the given scope.
|
179
81
|
#
|
180
82
|
# @param scope [Object] The initial scope to which filters and sorts are applied.
|
181
83
|
# @return [Object] The modified scope.
|
182
|
-
def apply(scope)
|
183
|
-
|
184
|
-
scope =
|
185
|
-
|
84
|
+
def apply(scope, params)
|
85
|
+
params = deep_compact(params.with_indifferent_access)
|
86
|
+
scope = search_filter.apply(scope, search: params[:search]) if search_filter && params[:search]
|
87
|
+
scope = scope_definitions[params[:scope]].apply(scope, **{}) if scope_definitions[params[:scope]]
|
88
|
+
scope = apply_sorts(scope, params)
|
89
|
+
apply_filters(scope, params)
|
186
90
|
end
|
187
91
|
|
188
92
|
def scope_definitions = @scope_definitions ||= {}.with_indifferent_access
|
@@ -208,22 +112,7 @@ module Plutonium
|
|
208
112
|
|
209
113
|
private
|
210
114
|
|
211
|
-
attr_reader :
|
212
|
-
|
213
|
-
# Defines standard filters.
|
214
|
-
def define_filters
|
215
|
-
# Implement filter definitions if needed
|
216
|
-
end
|
217
|
-
|
218
|
-
# Defines standard scopes.
|
219
|
-
def define_scopes
|
220
|
-
# Implement scope definitions if needed
|
221
|
-
end
|
222
|
-
|
223
|
-
# Defines standard sorters.
|
224
|
-
def define_sorters
|
225
|
-
# Implement sorter definitions if needed
|
226
|
-
end
|
115
|
+
attr_reader :resource_class, :params, :selected_sort_fields, :selected_sort_directions, :selected_scope_filter
|
227
116
|
|
228
117
|
# Defines standard queries for search and scope.
|
229
118
|
def define_standard_queries
|
@@ -233,7 +122,7 @@ module Plutonium
|
|
233
122
|
# Extracts filter parameters from the given params.
|
234
123
|
#
|
235
124
|
# @param params [Hash] The parameters to extract.
|
236
|
-
def extract_filter_params
|
125
|
+
def extract_filter_params
|
237
126
|
@search_query = params[:search]
|
238
127
|
@selected_scope_filter = params[:scope]
|
239
128
|
end
|
@@ -241,7 +130,7 @@ module Plutonium
|
|
241
130
|
# Extracts sort parameters from the given params.
|
242
131
|
#
|
243
132
|
# @param params [Hash] The parameters to extract.
|
244
|
-
def extract_sort_params
|
133
|
+
def extract_sort_params
|
245
134
|
@selected_sort_fields = Array(params[:sort_fields])
|
246
135
|
@selected_sort_fields &= sort_definitions.keys
|
247
136
|
|
@@ -251,17 +140,24 @@ module Plutonium
|
|
251
140
|
# Builds a query object based on the given body and optional block.
|
252
141
|
#
|
253
142
|
# @param body [Proc, Symbol] The body of the query.
|
254
|
-
# @yieldparam query [Query] The query object.
|
255
|
-
# @return [Query] The constructed query object.
|
256
|
-
def build_query(body
|
257
|
-
case body
|
143
|
+
# @yieldparam query [Plutonium::Query::Base] The query object.
|
144
|
+
# @return [Plutonium::Query::Base] The constructed query object.
|
145
|
+
def build_query(body)
|
146
|
+
query = case body
|
258
147
|
when Symbol
|
259
148
|
raise "Cannot find scope :#{body} on #{resource_class}" unless resource_class.respond_to?(body)
|
260
149
|
|
261
|
-
|
150
|
+
Plutonium::Query::ModelScope.new(body)
|
151
|
+
when Proc
|
152
|
+
Plutonium::Query::AdhocBlock.new(body)
|
153
|
+
when Plutonium::Query::Filter
|
154
|
+
body
|
262
155
|
else
|
263
|
-
|
156
|
+
raise NotImplementedError, "Unsupported query body: #{body.class} -> #{body}"
|
264
157
|
end
|
158
|
+
|
159
|
+
yield query if block_given?
|
160
|
+
query
|
265
161
|
end
|
266
162
|
|
267
163
|
# Determines the sort field for the given name.
|
@@ -284,7 +180,7 @@ module Plutonium
|
|
284
180
|
# @param params [Hash] The parameters to extract.
|
285
181
|
# @return [Hash] The extracted sort directions.
|
286
182
|
def extract_sort_directions(params)
|
287
|
-
params[:sort_directions]&.slice(*sort_definitions.keys) || {}
|
183
|
+
params[:sort_directions]&.slice(*sort_definitions.keys.map(&:to_sym)) || {}
|
288
184
|
end
|
289
185
|
|
290
186
|
# Handles the sort options for building the URL.
|
@@ -322,19 +218,37 @@ module Plutonium
|
|
322
218
|
#
|
323
219
|
# @param scope [Object] The initial scope.
|
324
220
|
# @return [Object] The modified scope.
|
325
|
-
def apply_sorts(scope)
|
221
|
+
def apply_sorts(scope, params)
|
222
|
+
selected_sort_directions = extract_sort_directions(params)
|
326
223
|
selected_sort_fields.each do |name|
|
327
|
-
sorter = sort_definitions[name]
|
328
|
-
|
224
|
+
next unless (sorter = sort_definitions[name])
|
225
|
+
|
226
|
+
direction = selected_sort_directions[name] || "ASC"
|
227
|
+
scope = sorter.apply(scope, direction:)
|
228
|
+
end
|
229
|
+
scope
|
230
|
+
end
|
231
|
+
|
232
|
+
def apply_filters(scope, params)
|
233
|
+
filter_definitions.each do |name, filter|
|
234
|
+
name = name.to_sym
|
235
|
+
filter_params = params[name]
|
236
|
+
next if filter_params.blank?
|
329
237
|
|
330
|
-
|
331
|
-
scope = sorter.apply(scope, params)
|
238
|
+
scope = filter.apply(scope, **filter_params.symbolize_keys)
|
332
239
|
end
|
333
240
|
scope
|
334
241
|
end
|
335
242
|
|
336
|
-
|
337
|
-
|
243
|
+
def deep_compact(hash)
|
244
|
+
hash.transform_values do |value|
|
245
|
+
if value.respond_to?(:transform_values)
|
246
|
+
deep_compact(value).presence
|
247
|
+
else
|
248
|
+
value.presence
|
249
|
+
end
|
250
|
+
end.compact
|
251
|
+
end
|
338
252
|
end
|
339
253
|
end
|
340
254
|
end
|
@@ -1,11 +1,9 @@
|
|
1
|
-
require "action_controller"
|
2
|
-
|
3
1
|
module Plutonium
|
4
|
-
module
|
5
|
-
module
|
6
|
-
|
7
|
-
def nilify
|
8
|
-
transform_values { |value| nilify_internal
|
2
|
+
module Support
|
3
|
+
module Parameters
|
4
|
+
class << self
|
5
|
+
def nilify(params)
|
6
|
+
params.transform_values { |value| nilify_internal(value) }
|
9
7
|
end
|
10
8
|
|
11
9
|
private
|
@@ -37,27 +37,31 @@ module Plutonium
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def render_resource_field(name)
|
40
|
-
# display :name, as: :string
|
41
|
-
# display :description, class: "col-span-full"
|
42
|
-
# display :age, field: {class: "max-h-fit"}
|
43
|
-
# display :dob do |f|
|
44
|
-
# f.date_tag
|
45
|
-
# end
|
46
|
-
|
47
40
|
when_permitted(name) do
|
41
|
+
# field :name, as: :string
|
42
|
+
# display :name, as: :string
|
43
|
+
# display :description, class: "col-span-full"
|
44
|
+
# display :age, tag: {class: "max-h-fit"}
|
45
|
+
# display :dob do |f|
|
46
|
+
# f.date_tag
|
47
|
+
# end
|
48
|
+
|
49
|
+
field_options = resource_definition.defined_fields[name] ? resource_definition.defined_fields[name][:options] : {}
|
50
|
+
|
48
51
|
display_definition = resource_definition.defined_displays[name] || {}
|
49
52
|
display_options = display_definition[:options] || {}
|
50
|
-
display_field_as = display_options.delete(:as)
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
f.
|
54
|
+
tag = field_options[:as] || display_options[:as]
|
55
|
+
tag_attributes = display_options[:tag] || {}
|
56
|
+
tag_block = display_definition[:block] || ->(f) {
|
57
|
+
tag ||= f.inferred_field_component
|
58
|
+
f.send(:"#{tag}_tag", **tag_attributes)
|
56
59
|
}
|
57
60
|
|
58
|
-
field_options =
|
59
|
-
|
60
|
-
|
61
|
+
field_options = field_options.except(:as)
|
62
|
+
wrapper_options = display_options.except(:tag, :as)
|
63
|
+
render field(name, **field_options).wrapped(**wrapper_options) do |f|
|
64
|
+
render tag_block.call(f)
|
61
65
|
end
|
62
66
|
end
|
63
67
|
end
|