plutonium 0.12.9 → 0.12.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/app/views/components/form/form_component.html.erb +1 -3
  3. data/app/views/components/interactive_action_form/interactive_action_form_component.html.erb +5 -7
  4. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.html.erb +2 -2
  5. data/app/views/components/table_search_input/table_search_input_component.html.erb +8 -2
  6. data/app/views/resource/_interactive_resource_action_form.html.erb +1 -1
  7. data/app/views/resource/_resource_details.html.erb +9 -2
  8. data/app/views/resource/_resource_table.html.erb +9 -1
  9. data/lib/generators/pu/core/assets/templates/tailwind.config.js +2 -0
  10. data/lib/generators/pu/core/install/install_generator.rb +1 -1
  11. data/lib/generators/pu/core/install/templates/config/initializers/plutonium.rb +4 -0
  12. data/lib/generators/pu/eject/layout/layout_generator.rb +3 -2
  13. data/lib/generators/pu/eject/shell/shell_generator.rb +3 -2
  14. data/lib/generators/pu/field/input/input_generator.rb +32 -0
  15. data/lib/generators/pu/field/input/templates/.keep +0 -0
  16. data/lib/generators/pu/field/input/templates/input.rb.tt +15 -0
  17. data/lib/generators/pu/field/renderer/renderer_generator.rb +32 -0
  18. data/lib/generators/pu/field/renderer/templates/.keep +0 -0
  19. data/lib/generators/pu/field/renderer/templates/renderer.rb.tt +9 -0
  20. data/lib/plutonium/core/actions/interactive_action.rb +2 -2
  21. data/lib/plutonium/core/associations/renderers/base.rb +77 -0
  22. data/lib/plutonium/core/associations/renderers/factory.rb +0 -2
  23. data/lib/plutonium/core/associations/renderers/has_many_renderer.rb +6 -4
  24. data/lib/plutonium/core/controllers/crud_actions.rb +1 -1
  25. data/lib/plutonium/core/controllers/presentable.rb +3 -3
  26. data/lib/plutonium/core/definers/field_definer.rb +4 -4
  27. data/lib/plutonium/core/definers/{input_definer.rb → field_input_definer.rb} +4 -4
  28. data/lib/plutonium/core/definers/{renderer_definer.rb → field_renderer_definer.rb} +10 -10
  29. data/lib/plutonium/core/fields/inputs/attachment_input.rb +2 -2
  30. data/lib/plutonium/core/fields/inputs/base.rb +76 -10
  31. data/lib/plutonium/core/fields/inputs/checkbox_input.rb +3 -1
  32. data/lib/plutonium/core/fields/inputs/date_time_input.rb +3 -1
  33. data/lib/plutonium/core/fields/inputs/nested_input.rb +36 -21
  34. data/lib/plutonium/core/fields/inputs/noop_input.rb +1 -4
  35. data/lib/plutonium/core/fields/inputs/polymorphic_belongs_to_association_input.rb +8 -7
  36. data/lib/plutonium/core/fields/inputs/simple_form_association_input.rb +4 -5
  37. data/lib/plutonium/core/fields/inputs/simple_form_input.rb +2 -3
  38. data/lib/plutonium/core/fields/renderers/association_renderer.rb +11 -5
  39. data/lib/plutonium/core/fields/renderers/attachment_renderer.rb +3 -10
  40. data/lib/plutonium/core/fields/renderers/base.rb +83 -0
  41. data/lib/plutonium/core/fields/renderers/basic_renderer.rb +3 -17
  42. data/lib/plutonium/core/fields/renderers/factory.rb +0 -1
  43. data/lib/plutonium/core/renderable.rb +20 -0
  44. data/lib/plutonium/helpers/display_helper.rb +1 -1
  45. data/lib/plutonium/resource/controller.rb +1 -1
  46. data/lib/plutonium/resource/policy.rb +1 -1
  47. data/lib/plutonium/resource/presenter.rb +3 -3
  48. data/lib/plutonium/resource/query_object.rb +4 -4
  49. data/lib/plutonium/resource/record.rb +1 -1
  50. data/lib/plutonium/simple_form/attachment_component.rb +1 -1
  51. data/lib/plutonium/version.rb +1 -1
  52. data/package.json +1 -1
  53. metadata +13 -5
  54. data/lib/plutonium/core/associations/renderers/basic_renderer.rb +0 -28
@@ -3,17 +3,23 @@ module Plutonium
3
3
  module Fields
4
4
  module Inputs
5
5
  class Base
6
- attr_reader :name, :user_options
6
+ include Plutonium::Core::Renderable
7
7
 
8
+ attr_reader :name
9
+
10
+ # Initializes the Base input class with a name and user-defined options.
11
+ #
12
+ # @param name [String] the name of the input field.
13
+ # @param user_options [Hash] user-defined options for the input field.
8
14
  def initialize(name, **user_options)
9
15
  @name = name
10
16
  @user_options = user_options
11
17
  end
12
18
 
13
- def render(view_context, f, record, **)
14
- raise NotImplementedError, "#{self.class}#render"
15
- end
16
-
19
+ # Collects parameters matching the input field's name with multi-parameter attributes.
20
+ #
21
+ # @param params [Hash] the parameters to collect from.
22
+ # @return [Hash] the collected parameters.
17
23
  def collect(params)
18
24
  # Handles multi parameter attributes
19
25
  # https://www.cookieshq.co.uk/posts/rails-spelunking-date-select
@@ -26,17 +32,77 @@ module Plutonium
26
32
  # - parameter(1i)
27
33
  # - parameter(2f)
28
34
  regex = /^#{param}(\(\d+[if]?\))?$/
29
- keys = params.select { |key, value| regex.match?(key) }.keys
35
+ keys = params.select { |key, _| regex.match?(key) }.keys
30
36
  params.slice(*keys)
31
37
  end
32
38
 
33
- protected
39
+ # Sets the form and record objects on the input field.
40
+ #
41
+ # @param form [Object] the form object.
42
+ # @param record [Object] the record object.
43
+ # @param render_options [Hash] additional options for rendering.
44
+ def with(form:, record:, **render_options)
45
+ @form = form
46
+ @record = record
47
+ @render_options = render_options
48
+ @options = build_options(render_options)
49
+
50
+ self
51
+ end
52
+
53
+ private
54
+
55
+ # Returns input-specific options, can be overridden by subclasses.
56
+ #
57
+ # @return [Hash] the input-specific options.
58
+ def input_options
59
+ {}
60
+ end
61
+
62
+ # Returns the parameter name for the input field.
63
+ #
64
+ # @return [String] the parameter name.
65
+ def param
66
+ name
67
+ end
68
+
69
+ # Raises an error if #options is accessed before rendering.
70
+ #
71
+ # @raise [RuntimeError] if accessed before rendering.
72
+ # @return [Hash] the rendering options.
73
+ def options
74
+ raise "cannot access #options before calling #with" unless defined?(@options)
34
75
 
35
- def input_options = {}
76
+ @options
77
+ end
36
78
 
37
- def param = name
79
+ # Raises an error if #form is accessed before rendering.
80
+ #
81
+ # @raise [RuntimeError] if accessed before rendering.
82
+ # @return [Object] the form object.
83
+ def form
84
+ raise "cannot access #form before calling #with" unless defined?(@form)
85
+
86
+ @form
87
+ end
38
88
 
39
- def options = @options ||= input_options.deep_merge(@user_options)
89
+ # Raises an error if #record is accessed before rendering.
90
+ #
91
+ # @raise [RuntimeError] if accessed before rendering.
92
+ # @return [Object] the record object.
93
+ def record
94
+ raise "cannot access #record before calling #with" unless defined?(@record)
95
+
96
+ @record
97
+ end
98
+
99
+ # Builds the options for rendering by merging input options, user options, and render options.
100
+ #
101
+ # @param render_options [Hash] additional options for rendering.
102
+ # @return [Hash] the merged options.
103
+ def build_options(render_options)
104
+ input_options.deep_merge(@user_options).deep_merge(render_options)
105
+ end
40
106
  end
41
107
  end
42
108
  end
@@ -5,7 +5,9 @@ module Plutonium
5
5
  class CheckboxInput < SimpleFormInput
6
6
  private
7
7
 
8
- def input_options = {wrapper: :resource_checkbox}
8
+ def input_options
9
+ {wrapper: :resource_checkbox}
10
+ end
9
11
  end
10
12
  end
11
13
  end
@@ -5,7 +5,9 @@ module Plutonium
5
5
  class DateTimeInput < SimpleFormInput
6
6
  private
7
7
 
8
- def input_options = {wrapper: :resource_multi_select}
8
+ def input_options
9
+ {wrapper: :resource_multi_select}
10
+ end
9
11
  end
10
12
  end
11
13
  end
@@ -3,52 +3,67 @@ module Plutonium
3
3
  module Fields
4
4
  module Inputs
5
5
  class NestedInput < Base
6
- include Plutonium::Core::Definers::InputDefiner
6
+ include Plutonium::Core::Definers::FieldInputDefiner
7
7
 
8
8
  attr_reader :inputs, :resource_class
9
9
 
10
- def initialize(name, inputs:, resource_class:, allow_destroy:, update_only:, limit:, **user_options)
10
+ def initialize(name, inputs:, resource_class:, allow_destroy:, update_only:, limit:, **options)
11
11
  @inputs = inputs
12
12
  @resource_class = resource_class
13
13
  @allow_destroy = allow_destroy
14
14
  @update_only = update_only
15
15
  @limit = limit
16
16
 
17
- super(name, **user_options)
17
+ super(name, **options)
18
18
  end
19
19
 
20
- def render(view_context, f, record, **opts)
21
- opts = options.deep_merge opts
22
- view_context.render_component :nested_resource_form_fields, form: f, **opts
20
+ def render
21
+ render_component :nested_resource_form_fields, form:, **options
23
22
  end
24
23
 
25
24
  def collect(params)
25
+ nested_params = params[param] || {}
26
+ attributes = (nested_params.keys.first == "0") ? collect_indexed_attributes(nested_params) : collect_single_attributes(nested_params)
27
+ {param => attributes}
28
+ end
29
+
30
+ private
31
+
32
+ def collect_single_attributes(params)
33
+ collected = defined_inputs.collect_all(params)
34
+ collected[:id] = params[:id] if params.key?(:id) && !@update_only
35
+ collected[:_destroy] = params[:_destroy] if @allow_destroy
36
+ collected
37
+ end
38
+
39
+ def collect_indexed_attributes(params)
26
40
  attributes = {}
27
- params[param].each do |index, nested_params|
41
+ params.each do |index, nested_params|
28
42
  collected = defined_inputs.collect_all(nested_params)
29
43
  collected[:id] = nested_params[:id] if nested_params.key?(:id) && !@update_only
30
44
  collected[:_destroy] = nested_params[:_destroy] if @allow_destroy
31
45
  attributes[index] = collected
32
46
  end
33
-
34
- {param => attributes}
47
+ attributes
35
48
  end
36
49
 
37
- private
38
-
39
- def param = :"#{name}_attributes"
50
+ def param
51
+ :"#{name}_attributes"
52
+ end
40
53
 
41
- def input_options = {
42
- name:,
43
- resource_class:,
44
- allow_destroy: @allow_destroy,
45
- update_only: @update_only,
46
- limit: @limit,
47
- inputs: defined_inputs
48
- }
54
+ def input_options
55
+ {
56
+ name:,
57
+ resource_class:,
58
+ allow_destroy: @allow_destroy,
59
+ update_only: @update_only,
60
+ limit: @limit,
61
+ inputs: defined_inputs
62
+ }
63
+ end
49
64
 
50
65
  def defined_inputs
51
- @defined_inputs ||= defined_inputs_for(*inputs)
66
+ @defined_inputs ||= defined_field_inputs_for(*inputs)
52
67
  end
53
68
  end
54
69
  end
@@ -3,10 +3,7 @@ module Plutonium
3
3
  module Fields
4
4
  module Inputs
5
5
  class NoopInput
6
- def initialize(*)
7
- end
8
-
9
- def render(view_context, f, record, **)
6
+ def render
10
7
  end
11
8
 
12
9
  def collect(params)
@@ -3,9 +3,8 @@ module Plutonium
3
3
  module Fields
4
4
  module Inputs
5
5
  class PolymorphicBelongsToAssociationInput < SimpleFormAssociationInput
6
- def render(view_context, f, record, **opts)
7
- opts = options.deep_merge opts
8
- f.input param, **opts
6
+ def render
7
+ form.input param, **options
9
8
  end
10
9
 
11
10
  private
@@ -15,12 +14,11 @@ module Plutonium
15
14
  end
16
15
 
17
16
  def input_options
17
+ collection = @user_options.delete(:collection).presence || associated_classes
18
18
  {
19
19
  as: :grouped_select,
20
+ collection:,
20
21
  label: reflection.name.to_s.humanize,
21
- collection: associated_classes.map { |klass|
22
- [klass.name, klass.all]
23
- }.to_h,
24
22
  group_label_method: :first,
25
23
  group_method: :last, include_blank: "Select One"
26
24
  }
@@ -38,7 +36,10 @@ module Plutonium
38
36
  end
39
37
  end
40
38
  end
41
- associated_classes
39
+
40
+ associated_classes.map { |klass|
41
+ [klass.name, klass.all]
42
+ }.to_h
42
43
  end
43
44
  end
44
45
  end
@@ -5,14 +5,13 @@ module Plutonium
5
5
  class SimpleFormAssociationInput < Base
6
6
  attr_reader :reflection
7
7
 
8
- def initialize(name, reflection:, **user_options)
8
+ def initialize(name, reflection:, **)
9
9
  @reflection = reflection
10
- super(name, **user_options)
10
+ super(name, **)
11
11
  end
12
12
 
13
- def render(view_context, f, record, **opts)
14
- opts = options.deep_merge opts
15
- f.association name, **opts
13
+ def render
14
+ form.association name, **options
16
15
  end
17
16
 
18
17
  private
@@ -3,9 +3,8 @@ module Plutonium
3
3
  module Fields
4
4
  module Inputs
5
5
  class SimpleFormInput < Base
6
- def render(view_context, f, record, **opts)
7
- opts = options.deep_merge opts
8
- f.input name, **opts
6
+ def render
7
+ form.input name, **options
9
8
  end
10
9
  end
11
10
  end
@@ -2,7 +2,7 @@ module Plutonium
2
2
  module Core
3
3
  module Fields
4
4
  module Renderers
5
- class AssociationRenderer < BasicRenderer
5
+ class AssociationRenderer < Base
6
6
  attr_reader :reflection
7
7
 
8
8
  def initialize(name, reflection:, **user_options)
@@ -10,10 +10,16 @@ module Plutonium
10
10
  super(name, **user_options)
11
11
  end
12
12
 
13
- def render(view_context, record)
14
- value = record.send(name)
15
- options = self.options.merge(helper: value.class.include?(Plutonium::Resource::Record) ? :display_association_value : :display_name_of)
16
- view_context.display_field value:, **options
13
+ def render
14
+ display_field value:, **options
15
+ end
16
+
17
+ private
18
+
19
+ def renderer_options
20
+ {
21
+ helper: value.class.include?(Plutonium::Resource::Record) ? :display_association_value : :display_name_of
22
+ }
17
23
  end
18
24
  end
19
25
  end
@@ -2,16 +2,9 @@ module Plutonium
2
2
  module Core
3
3
  module Fields
4
4
  module Renderers
5
- class AttachmentRenderer < BasicRenderer
6
- attr_reader :reflection
7
-
8
- def initialize(name, reflection:, **user_options)
9
- @reflection = reflection
10
- super(name, **user_options)
11
- end
12
-
13
- def render(view_context, record)
14
- view_context.attachment_preview record.send(name), **options
5
+ class AttachmentRenderer < AssociationRenderer
6
+ def render
7
+ attachment_preview value, **options
15
8
  end
16
9
 
17
10
  private
@@ -0,0 +1,83 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Renderers
5
+ class Base
6
+ include Plutonium::Core::Renderable
7
+
8
+ attr_reader :name
9
+
10
+ # Initializes the Base renderer class with a name and user-defined options.
11
+ #
12
+ # @param name [String] the name of the renderer.
13
+ # @param user_options [Hash] user-defined options for the renderer.
14
+ def initialize(name, **user_options)
15
+ @name = name
16
+ @user_options = user_options
17
+ end
18
+
19
+ # Sets the record object on the renderer and merges render options.
20
+ #
21
+ # @param record [Object] the record object.
22
+ # @param render_options [Hash] additional options for rendering.
23
+ # @return [self] the renderer instance.
24
+ def with(record:, **render_options)
25
+ @record = record
26
+ @render_options = render_options
27
+ @options = build_options(render_options)
28
+
29
+ self
30
+ end
31
+
32
+ def label
33
+ options[:label] || record.class.human_attribute_name(name)
34
+ end
35
+
36
+ private
37
+
38
+ # Returns the merged options for rendering.
39
+ #
40
+ # @raise [RuntimeError] if accessed before rendering.
41
+ # @return [Hash] the merged options.
42
+ def options
43
+ raise "cannot access #options before calling #with" unless defined?(@options)
44
+
45
+ @options
46
+ end
47
+
48
+ # Returns the record object.
49
+ #
50
+ # @raise [RuntimeError] if accessed before rendering.
51
+ # @return [Object] the record object.
52
+ def record
53
+ raise "cannot access #record before calling #with" unless defined?(@record)
54
+
55
+ @record
56
+ end
57
+
58
+ # Returns the value of the record's attribute corresponding to the renderer's name.
59
+ #
60
+ # @return [Object] the value of the attribute.
61
+ def value
62
+ record.public_send(name)
63
+ end
64
+
65
+ # Returns renderer-specific options, can be overridden by subclasses.
66
+ #
67
+ # @return [Hash] the renderer-specific options.
68
+ def renderer_options
69
+ {}
70
+ end
71
+
72
+ # Builds the options for rendering by merging renderer options, user options, and render options.
73
+ #
74
+ # @param render_options [Hash] additional options for rendering.
75
+ # @return [Hash] the merged options.
76
+ def build_options(render_options)
77
+ renderer_options.deep_merge(@user_options).deep_merge(render_options)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -2,24 +2,10 @@ module Plutonium
2
2
  module Core
3
3
  module Fields
4
4
  module Renderers
5
- class BasicRenderer
6
- attr_reader :name, :label, :user_options
7
-
8
- def initialize(name, label:, **user_options)
9
- @name = name
10
- @label = label
11
- @user_options = user_options
5
+ class BasicRenderer < Base
6
+ def render
7
+ display_field value:, **options
12
8
  end
13
-
14
- def render(view_context, record)
15
- view_context.display_field value: record.send(name), **options
16
- end
17
-
18
- def options = @options ||= renderer_options.deep_merge(@user_options)
19
-
20
- private
21
-
22
- def renderer_options = {}
23
9
  end
24
10
  end
25
11
  end
@@ -17,7 +17,6 @@ module Plutonium
17
17
 
18
18
  def self.for_resource_attribute(resource_class, attr_name, **options)
19
19
  type = nil
20
- options[:label] ||= resource_class.human_attribute_name(attr_name)
21
20
 
22
21
  if (attachment = resource_class.try(:reflect_on_attachment, attr_name))
23
22
  type = :attachment
@@ -0,0 +1,20 @@
1
+ module Plutonium
2
+ module Core
3
+ module Renderable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ delegate_missing_to :@view_context
8
+ end
9
+
10
+ def render_in(view_context)
11
+ @view_context = view_context
12
+ render
13
+ end
14
+
15
+ def render
16
+ raise NotImplementedError, "#{self.class}#render"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -73,7 +73,7 @@ module Plutonium
73
73
 
74
74
  # Fallback to retrieving the value from a predefined list
75
75
  %i[to_label name title].each do |method|
76
- name = obj.send(method) if obj.respond_to?(method)
76
+ name = obj.public_send(method) if obj.respond_to?(method)
77
77
  return name if name.present?
78
78
  end
79
79
 
@@ -69,7 +69,7 @@ module Plutonium
69
69
  override_entity_scoping_params(input_params)
70
70
  override_parent_params(input_params)
71
71
 
72
- current_presenter.defined_inputs_for(*permitted_attributes).collect_all(input_params)
72
+ current_presenter.defined_field_inputs_for(*permitted_attributes).collect_all(input_params)
73
73
  end
74
74
 
75
75
  # Returns the resource parameter key
@@ -18,7 +18,7 @@ module Plutonium
18
18
  raise NotImplementedError, "#{self.class.name} does not implement the required #{method}"
19
19
  end
20
20
 
21
- send(method)
21
+ public_send(method)
22
22
  end
23
23
 
24
24
  # Core actions
@@ -63,7 +63,7 @@ module Plutonium
63
63
 
64
64
  nested_attribute_options_class = nested_attribute_options&.[](:class)
65
65
  if nested_attribute_options_class.nil? && model_class.nil?
66
- raise ArgumentError, "model_class is required if your field is not an association or is polymorphic"
66
+ raise ArgumentError, "model_class is required if your field is not an association or is polymorphic. also ensure you have called `accepts_nested_attributes_for :#{name}`"
67
67
  end
68
68
  model_class ||= nested_attribute_options_class
69
69
 
@@ -83,7 +83,7 @@ module Plutonium
83
83
  )
84
84
  yield input if block_given?
85
85
 
86
- define_input name, input:
86
+ define_field_input name, input:
87
87
  end
88
88
 
89
89
  # Determines the limit for a nested input
@@ -92,7 +92,7 @@ module Plutonium
92
92
  # @param [Integer, nil] nested_attribute_limit The limit from nested attributes
93
93
  # @return [Integer, nil] The determined limit
94
94
  def determine_nested_input_limit(macro, option_limit, nested_attribute_limit)
95
- if macro == :has_one
95
+ if %i[belongs_to has_one].include? macro
96
96
  1
97
97
  elsif option_limit
98
98
  option_limit
@@ -5,7 +5,7 @@ module Plutonium
5
5
  end
6
6
 
7
7
  class Query
8
- include Plutonium::Core::Definers::InputDefiner
8
+ include Plutonium::Core::Definers::FieldInputDefiner
9
9
 
10
10
  # Applies the query to the given scope using the provided parameters.
11
11
  #
@@ -65,7 +65,7 @@ module Plutonium
65
65
  # @param params [Hash] The parameters for the query.
66
66
  # @return [Object] The modified scope.
67
67
  def apply_internal(scope, params)
68
- scope.send(name, **params)
68
+ scope.public_send(name, **params)
69
69
  end
70
70
  end
71
71
 
@@ -215,7 +215,7 @@ module Plutonium
215
215
  end
216
216
 
217
217
  sort_definitions[name] = build_query(body) do |query|
218
- query.define_input :direction
218
+ query.define_field_input :direction
219
219
  end
220
220
  end
221
221
 
@@ -224,7 +224,7 @@ module Plutonium
224
224
  # @param body [Proc, Symbol] The body of the search filter.
225
225
  def define_search(body)
226
226
  @search_filter = build_query(body) do |query|
227
- query.define_input :search
227
+ query.define_field_input :search
228
228
  end
229
229
  end
230
230
 
@@ -22,7 +22,7 @@ module Plutonium
22
22
  record_association = klass.find_association_to_self(record)
23
23
  if record_association
24
24
  # TODO: add a warning here about a potentially poor performing query
25
- return where(id: record.send(record_association.name))
25
+ return where(id: record.public_send(record_association.name))
26
26
  end
27
27
 
28
28
  klass.raise_association_error(record, named_scope)
@@ -40,7 +40,7 @@ module Plutonium
40
40
  private
41
41
 
42
42
  def value
43
- @value ||= object.send(attribute_name) if object&.respond_to?(attribute_name)
43
+ @value ||= object.public_send(attribute_name) if object&.respond_to?(attribute_name)
44
44
  end
45
45
 
46
46
  def multiple?
@@ -1,3 +1,3 @@
1
1
  module Plutonium
2
- VERSION = "0.12.9"
2
+ VERSION = "0.12.10"
3
3
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radioactive-labs/plutonium",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Core assets for the Plutonium gem",
5
5
  "type": "module",
6
6
  "main": "src/js/core.js",