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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/plutonium.css +1 -1
  3. data/app/views/components/sidebar_menu/sidebar_menu_component.rb +1 -1
  4. data/app/views/components/table_search_input/table_search_input_component.html.erb +3 -3
  5. data/app/views/resource/_resource_table.html.erb +0 -321
  6. data/lib/plutonium/core/controllers/authorizable.rb +5 -0
  7. data/lib/plutonium/core/controllers/entity_scoping.rb +4 -4
  8. data/lib/plutonium/definition/base.rb +8 -0
  9. data/lib/plutonium/definition/defineable_props.rb +1 -1
  10. data/lib/plutonium/definition/presentable.rb +71 -0
  11. data/lib/plutonium/interaction/README.md +1 -1
  12. data/lib/plutonium/interaction/base.rb +6 -6
  13. data/lib/plutonium/lib/deep_freezer.rb +31 -0
  14. data/lib/plutonium/query/adhoc_block.rb +19 -0
  15. data/lib/plutonium/query/base.rb +29 -0
  16. data/lib/plutonium/query/filter.rb +12 -0
  17. data/lib/plutonium/query/filters/text.rb +77 -0
  18. data/lib/plutonium/query/model_scope.rb +19 -0
  19. data/lib/plutonium/resource/controller.rb +14 -7
  20. data/lib/plutonium/resource/controllers/authorizable.rb +1 -1
  21. data/lib/plutonium/resource/controllers/crud_actions/index_action.rb +26 -0
  22. data/lib/plutonium/resource/controllers/crud_actions.rb +2 -5
  23. data/lib/plutonium/resource/controllers/defineable.rb +0 -2
  24. data/lib/plutonium/resource/controllers/queryable.rb +36 -20
  25. data/lib/plutonium/resource/policy.rb +1 -1
  26. data/lib/plutonium/resource/query_object.rb +61 -147
  27. data/lib/plutonium/{refinements/parameter_refinements.rb → support/parameters.rb} +5 -7
  28. data/lib/plutonium/ui/component/methods.rb +1 -1
  29. data/lib/plutonium/ui/display/resource.rb +19 -15
  30. data/lib/plutonium/ui/form/query.rb +171 -0
  31. data/lib/plutonium/ui/form/resource.rb +21 -17
  32. data/lib/plutonium/ui/table/components/scopes_bar.rb +1 -1
  33. data/lib/plutonium/ui/table/components/search_bar.rb +6 -139
  34. data/lib/plutonium/ui/table/resource.rb +10 -9
  35. data/lib/plutonium/version.rb +1 -1
  36. data/package-lock.json +2 -2
  37. data/package.json +1 -1
  38. metadata +12 -4
  39. 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[scoped_entity_param_key] = current_scoped_entity
176
- input_params[:"#{scoped_entity_param_key}_id"] = current_scoped_entity.id
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[parent_input_param] = current_parent
185
- input_params[:"#{parent_input_param}_id"] = current_parent.id
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 current_authorized_scope_count
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
- @search_object = current_query_object
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
@@ -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 :resource_query_params, :current_query_object
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 ||= Plutonium::Resource::QueryObject.new(resource_context, resource_query_params) do |query_object|
20
- if current_definition.search_definition
21
- query_object.define_search proc { |scope, search:|
22
- current_definition.search_definition.call(scope, search)
23
- }
24
- end
25
-
26
- current_definition.defined_scopes.each do |key, value|
27
- query_object.define_scope key, value[:block], **value[:options]
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
- current_definition.defined_sorts.each do |key, value|
31
- query_object.define_sorter key, value[:block], **value[:options]
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
@@ -87,7 +87,7 @@ module Plutonium
87
87
  update?
88
88
  end
89
89
 
90
- # Checks if the search action is permitted.
90
+ # Checks if record search is permitted.
91
91
  #
92
92
  # @return [Boolean] Delegates to index?.
93
93
  def search?
@@ -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 context and parameters.
6
+ # Initializes a QueryObject with the given resource_class and parameters.
102
7
  #
103
- # @param context [Object] The context in which the query object is used.
8
+ # @param resource_class [Object] The resource class.
104
9
  # @param params [Hash] The parameters for initialization.
105
- def initialize(context, params, &)
106
- @context = context
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
- extract_filter_params(params)
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 = nil, &)
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.define_field_input :direction
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.define_field_input :search
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
- "?#{{q: q}.to_param}"
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
- scope = search_filter.apply(scope, {search: search_query}) if search_filter.present?
184
- scope = scope_definitions[selected_scope_filter].apply(scope, {}) if selected_scope_filter.present?
185
- apply_sorts(scope)
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 :context, :selected_sort_fields, :selected_sort_directions, :selected_scope_filter
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(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(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
- ScopeQuery.new(body, &)
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
- BlockQuery.new(body, &)
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
- next unless sorter.present?
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
- params = {direction: selected_sort_directions[name] || "ASC"}
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
- # @return [Object] The resource class from the context.
337
- def resource_class = context.resource_class
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 Refinements
5
- module ParameterRefinements
6
- refine ActionController::Parameters do
7
- def nilify
8
- transform_values { |value| nilify_internal value }
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
@@ -41,7 +41,7 @@ module Plutonium
41
41
  :resource_url_for,
42
42
  :current_definition,
43
43
  :current_query_object,
44
- :resource_query_params,
44
+ :raw_resource_query_params,
45
45
  :current_policy,
46
46
  :current_turbo_frame,
47
47
  :current_interactive_action,
@@ -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
- display_field_options = display_options.delete(:field) || {}
53
- display_block = display_definition[:block] || ->(f) {
54
- display_field_as ||= f.inferred_field_component
55
- f.send(:"#{display_field_as}_tag", **display_field_options)
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 = resource_definition.defined_fields[name] ? resource_definition.defined_fields[name][:options] : {}
59
- render field(name, **field_options).wrapped(**display_options) do |f|
60
- render display_block.call(f)
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