plutonium 0.18.5 → 0.18.7
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.js +1 -1
- data/app/assets/plutonium.js.map +2 -2
- data/app/assets/plutonium.min.js +1 -1
- data/app/assets/plutonium.min.js.map +2 -2
- data/app/views/resource/interactive_bulk_action.html.erb +1 -1
- data/app/views/resource/interactive_resource_action.html.erb +1 -1
- data/lib/generators/pu/eject/layout/layout_generator.rb +1 -2
- data/lib/generators/pu/eject/shell/shell_generator.rb +1 -3
- data/lib/generators/pu/lib/plutonium_generators/concerns/logger.rb +4 -0
- data/lib/generators/pu/lib/plutonium_generators/concerns/package_selector.rb +80 -0
- data/lib/generators/pu/lib/plutonium_generators/concerns/resource_selector.rb +48 -0
- data/lib/generators/pu/lib/plutonium_generators/generator.rb +2 -42
- data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +1 -4
- data/lib/generators/pu/res/conn/conn_generator.rb +9 -21
- data/lib/generators/pu/res/scaffold/scaffold_generator.rb +10 -5
- data/lib/plutonium/models/has_cents.rb +4 -2
- data/lib/plutonium/resource/controller.rb +3 -3
- data/lib/plutonium/resource/controllers/authorizable.rb +1 -1
- data/lib/plutonium/resource/controllers/crud_actions.rb +17 -17
- data/lib/plutonium/resource/controllers/interactive_actions.rb +3 -3
- data/lib/plutonium/resource/controllers/presentable.rb +2 -2
- data/lib/plutonium/resource/record/associated_with.rb +83 -0
- data/lib/plutonium/resource/record/associations.rb +92 -0
- data/lib/plutonium/resource/record/field_names.rb +83 -0
- data/lib/plutonium/resource/record/labeling.rb +19 -0
- data/lib/plutonium/resource/record/routes.rb +66 -0
- data/lib/plutonium/resource/record.rb +6 -258
- data/lib/plutonium/ui/breadcrumbs.rb +4 -4
- data/lib/plutonium/ui/component/methods.rb +4 -12
- data/lib/plutonium/ui/form/base.rb +22 -10
- data/lib/plutonium/ui/form/components/secure_association.rb +112 -0
- data/lib/plutonium/ui/form/components/secure_polymorphic_association.rb +54 -0
- data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +0 -1
- data/lib/plutonium/ui/form/theme.rb +12 -1
- data/lib/plutonium/ui/page/show.rb +1 -1
- data/lib/plutonium/ui/page_header.rb +1 -1
- data/lib/plutonium/version.rb +1 -1
- data/package-lock.json +2 -2
- data/package.json +1 -1
- data/src/js/controllers/slim_select_controller.js +3 -1
- metadata +11 -4
- data/lib/plutonium/ui/form/components/belongs_to.rb +0 -66
- data/lib/plutonium/ui/form/components/has_many.rb +0 -66
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Plutonium
|
4
|
+
module UI
|
5
|
+
module Form
|
6
|
+
module Components
|
7
|
+
class SecureAssociation < Phlexi::Form::Components::AssociationBase
|
8
|
+
include Plutonium::UI::Component::Methods
|
9
|
+
|
10
|
+
def view_template
|
11
|
+
div(class: "flex space-x-1") do
|
12
|
+
super
|
13
|
+
render_add_button
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
delegate :association_reflection, to: :field
|
20
|
+
|
21
|
+
def render_add_button
|
22
|
+
return if @add_action == false || add_url.nil?
|
23
|
+
|
24
|
+
a(
|
25
|
+
href: add_url,
|
26
|
+
class:
|
27
|
+
"bg-gray-100 dark:bg-gray-600 dark:hover:bg-gray-700 dark:border-gray-500 hover:bg-gray-200 border border-gray-300 rounded-lg p-3 focus:ring-gray-100 dark:focus:ring-gray-700 focus:ring-2 focus:outline-none dark:text-white"
|
28
|
+
) do
|
29
|
+
render Phlex::TablerIcons::Plus.new(class: "w-3 h-3")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_url
|
34
|
+
@add_url ||= begin
|
35
|
+
return unless @skip_authorization || allowed_to?(:create?, association_reflection.klass)
|
36
|
+
|
37
|
+
url = @add_action || resource_url_for(association_reflection.klass, action: :new, parent: nil)
|
38
|
+
return unless url
|
39
|
+
|
40
|
+
uri = URI(url)
|
41
|
+
uri.query = URI.encode_www_form({return_to: request.original_url})
|
42
|
+
uri.to_s
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def choices
|
47
|
+
@choices ||= begin
|
48
|
+
collection = if (user_choices = attributes.delete(:choices))
|
49
|
+
user_choices
|
50
|
+
elsif @skip_authorization
|
51
|
+
choices_from_association(association_reflection.klass)
|
52
|
+
else
|
53
|
+
authorized_resource_scope(association_reflection.klass, relation: choices_from_association(association_reflection.klass))
|
54
|
+
end
|
55
|
+
build_choice_mapper(collection)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_attributes
|
60
|
+
build_association_attributes
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
def build_association_attributes
|
65
|
+
@skip_authorization = attributes.delete(:skip_authorization)
|
66
|
+
@add_action = attributes.delete(:add_action)
|
67
|
+
|
68
|
+
attributes.fetch(:value_method) { attributes[:value_method] = :to_signed_global_id }
|
69
|
+
|
70
|
+
case association_reflection.macro
|
71
|
+
when :belongs_to, :has_one
|
72
|
+
build_singluar_association_attributes
|
73
|
+
when :has_many, :has_and_belongs_to_many
|
74
|
+
build_collection_association_attributes
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def build_singluar_association_attributes
|
79
|
+
attributes.fetch(:input_param) { attributes[:input_param] = :"#{association_reflection.name}_sgid" }
|
80
|
+
end
|
81
|
+
|
82
|
+
def build_collection_association_attributes
|
83
|
+
attributes.fetch(:input_param) { attributes[:input_param] = :"#{association_reflection.name.to_s.singularize}_sgids" }
|
84
|
+
attributes[:multiple] = true
|
85
|
+
end
|
86
|
+
|
87
|
+
def normalize_simple_input(input_value)
|
88
|
+
@signed_global_ids ||= choices.values.map { |choice| SignedGlobalID.parse(choice) }
|
89
|
+
([SignedGlobalID.parse(input_value.presence)].compact & @signed_global_ids)[0]
|
90
|
+
end
|
91
|
+
|
92
|
+
def selected?(option)
|
93
|
+
case association_reflection.macro
|
94
|
+
when :belongs_to, :has_one
|
95
|
+
singular_field_value == SignedGlobalID.parse(option)
|
96
|
+
when :has_many, :has_and_belongs_to_many
|
97
|
+
collection_field_value.any? { |item| item == SignedGlobalID.parse(option) }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def singular_field_value
|
102
|
+
@singular_field_value ||= field.object.send :"#{association_reflection.name}_sgid"
|
103
|
+
end
|
104
|
+
|
105
|
+
def collection_field_value
|
106
|
+
@collection_field_value ||= field.object.send :"#{association_reflection.name.to_s.singularize}_sgids"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Plutonium
|
4
|
+
module UI
|
5
|
+
module Form
|
6
|
+
module Components
|
7
|
+
class SecurePolymorphicAssociation < SecureAssociation
|
8
|
+
protected
|
9
|
+
|
10
|
+
def build_attributes
|
11
|
+
attributes.fetch(:group_method) { attributes[:group_method] = :last }
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def choices
|
16
|
+
@choices ||= begin
|
17
|
+
Plutonium.eager_load_rails!
|
18
|
+
collection = if (user_choices = attributes.delete(:choices))
|
19
|
+
user_choices
|
20
|
+
else
|
21
|
+
associated_classes.map { |klass|
|
22
|
+
[
|
23
|
+
klass.model_name.human.pluralize,
|
24
|
+
@skip_authorization ? choices_from_association(klass) : authorized_resource_scope(klass, relation: choices_from_association(klass))
|
25
|
+
]
|
26
|
+
}.to_h
|
27
|
+
end
|
28
|
+
build_choice_mapper(collection)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def associated_classes
|
33
|
+
Plutonium.eager_load_rails!
|
34
|
+
|
35
|
+
associated_classes = []
|
36
|
+
ActiveRecord::Base.descendants.each do |model_klass|
|
37
|
+
next if !model_klass.table_exists? || model_klass.abstract_class?
|
38
|
+
|
39
|
+
(model_klass.reflect_on_all_associations(:has_many) + model_klass.reflect_on_all_associations(:has_one)).each do |association|
|
40
|
+
if association.options[:as] == association_reflection.name
|
41
|
+
associated_classes << model_klass
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
associated_classes
|
46
|
+
end
|
47
|
+
|
48
|
+
def render_add_button
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -91,7 +91,6 @@ module Plutonium
|
|
91
91
|
# @param [Symbol] name The name of the nested resource field
|
92
92
|
# @raise [ArgumentError] if the nested input definition is missing required configuration
|
93
93
|
def render_nested_resource_field(name)
|
94
|
-
# debugger if $extracting_input
|
95
94
|
context = NestedFieldContext.new(
|
96
95
|
name: name,
|
97
96
|
definition: build_nested_fields_definition(name),
|
@@ -51,7 +51,18 @@ module Plutonium
|
|
51
51
|
uppy: :file,
|
52
52
|
valid_uppy: :valid_file,
|
53
53
|
invalid_uppy: :invalid_file,
|
54
|
-
neutral_uppy: :neutral_file
|
54
|
+
neutral_uppy: :neutral_file,
|
55
|
+
|
56
|
+
association: :select,
|
57
|
+
valid_association: :valid_select,
|
58
|
+
invalid_association: :invalid_select,
|
59
|
+
neutral_association: :neutral_select,
|
60
|
+
|
61
|
+
polymorpic_association: :association,
|
62
|
+
valid_polymorpic_association: :valid_association,
|
63
|
+
invalid_polymorpic_association: :invalid_association,
|
64
|
+
neutral_polymorpic_association: :neutral_association
|
65
|
+
|
55
66
|
})
|
56
67
|
end
|
57
68
|
end
|
@@ -40,7 +40,7 @@ module Plutonium
|
|
40
40
|
|
41
41
|
def render_actions
|
42
42
|
@actions.each do |action|
|
43
|
-
url = resource_url_for(resource_record || resource_class, *action.route_options.url_args, **action.route_options.url_options)
|
43
|
+
url = resource_url_for(resource_record? || resource_class, *action.route_options.url_args, **action.route_options.url_options)
|
44
44
|
ActionButton(action, url:)
|
45
45
|
end
|
46
46
|
end
|
data/lib/plutonium/version.rb
CHANGED
data/package-lock.json
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"name": "@radioactive-labs/plutonium",
|
3
|
-
"version": "0.3.
|
3
|
+
"version": "0.3.2",
|
4
4
|
"lockfileVersion": 3,
|
5
5
|
"requires": true,
|
6
6
|
"packages": {
|
7
7
|
"": {
|
8
8
|
"name": "@radioactive-labs/plutonium",
|
9
|
-
"version": "0.3.
|
9
|
+
"version": "0.3.2",
|
10
10
|
"license": "MIT",
|
11
11
|
"dependencies": {
|
12
12
|
"@hotwired/stimulus": "^3.2.2",
|
data/package.json
CHANGED
@@ -16,6 +16,8 @@ export default class extends Controller {
|
|
16
16
|
|
17
17
|
reconnect() {
|
18
18
|
this.disconnect()
|
19
|
-
this.
|
19
|
+
// dispatch this on the next frame.
|
20
|
+
// there's some funny issue where my elements get removed from the DOM
|
21
|
+
setTimeout(() => this.connect(), 10)
|
20
22
|
}
|
21
23
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plutonium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.18.
|
4
|
+
version: 0.18.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Froelich
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-01-
|
11
|
+
date: 2025-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|
@@ -603,6 +603,8 @@ files:
|
|
603
603
|
- lib/generators/pu/lib/plutonium_generators/concerns/actions.rb
|
604
604
|
- lib/generators/pu/lib/plutonium_generators/concerns/config.rb
|
605
605
|
- lib/generators/pu/lib/plutonium_generators/concerns/logger.rb
|
606
|
+
- lib/generators/pu/lib/plutonium_generators/concerns/package_selector.rb
|
607
|
+
- lib/generators/pu/lib/plutonium_generators/concerns/resource_selector.rb
|
606
608
|
- lib/generators/pu/lib/plutonium_generators/concerns/serializer.rb
|
607
609
|
- lib/generators/pu/lib/plutonium_generators/generator.rb
|
608
610
|
- lib/generators/pu/lib/plutonium_generators/installer.rb
|
@@ -786,6 +788,11 @@ files:
|
|
786
788
|
- lib/plutonium/resource/policy.rb
|
787
789
|
- lib/plutonium/resource/query_object.rb
|
788
790
|
- lib/plutonium/resource/record.rb
|
791
|
+
- lib/plutonium/resource/record/associated_with.rb
|
792
|
+
- lib/plutonium/resource/record/associations.rb
|
793
|
+
- lib/plutonium/resource/record/field_names.rb
|
794
|
+
- lib/plutonium/resource/record/labeling.rb
|
795
|
+
- lib/plutonium/resource/record/routes.rb
|
789
796
|
- lib/plutonium/resource/register.rb
|
790
797
|
- lib/plutonium/rodauth/controller_methods.rb
|
791
798
|
- lib/plutonium/routing/mapper_extensions.rb
|
@@ -813,11 +820,11 @@ files:
|
|
813
820
|
- lib/plutonium/ui/dyna_frame/host.rb
|
814
821
|
- lib/plutonium/ui/empty_card.rb
|
815
822
|
- lib/plutonium/ui/form/base.rb
|
816
|
-
- lib/plutonium/ui/form/components/belongs_to.rb
|
817
823
|
- lib/plutonium/ui/form/components/easymde.rb
|
818
824
|
- lib/plutonium/ui/form/components/flatpickr.rb
|
819
|
-
- lib/plutonium/ui/form/components/has_many.rb
|
820
825
|
- lib/plutonium/ui/form/components/intl_tel_input.rb
|
826
|
+
- lib/plutonium/ui/form/components/secure_association.rb
|
827
|
+
- lib/plutonium/ui/form/components/secure_polymorphic_association.rb
|
821
828
|
- lib/plutonium/ui/form/components/uppy.rb
|
822
829
|
- lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb
|
823
830
|
- lib/plutonium/ui/form/interaction.rb
|
@@ -1,66 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Plutonium
|
4
|
-
module UI
|
5
|
-
module Form
|
6
|
-
module Components
|
7
|
-
class BelongsTo < Phlexi::Form::Components::BelongsTo
|
8
|
-
include Plutonium::UI::Component::Methods
|
9
|
-
|
10
|
-
def view_template
|
11
|
-
div(class: "flex space-x-1") do
|
12
|
-
super
|
13
|
-
render_add_button
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def add_url
|
20
|
-
@add_url ||= begin
|
21
|
-
return unless @skip_authorization || allowed_to?(:create?, association_reflection.klass)
|
22
|
-
|
23
|
-
url = @add_action || resource_url_for(association_reflection.klass, action: :new, parent: nil)
|
24
|
-
return unless url
|
25
|
-
|
26
|
-
uri = URI(url)
|
27
|
-
uri.query = URI.encode_www_form({return_to: request.original_url})
|
28
|
-
uri.to_s
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def render_add_button
|
33
|
-
return if @add_action == false || add_url.nil?
|
34
|
-
|
35
|
-
a(
|
36
|
-
href: add_url,
|
37
|
-
class:
|
38
|
-
"bg-gray-100 dark:bg-gray-600 dark:hover:bg-gray-700 dark:border-gray-500 hover:bg-gray-200 border border-gray-300 rounded-lg p-3 focus:ring-gray-100 dark:focus:ring-gray-700 focus:ring-2 focus:outline-none dark:text-white"
|
39
|
-
) do
|
40
|
-
render Phlex::TablerIcons::Plus.new(class: "w-3 h-3")
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def choices
|
45
|
-
@choices ||= begin
|
46
|
-
collection = if @provided_choices || @skip_authorization
|
47
|
-
@choice_collection
|
48
|
-
else
|
49
|
-
authorized_resource_scope(association_reflection.klass, relation: @choice_collection)
|
50
|
-
end
|
51
|
-
Phlexi::Form::ChoicesMapper.new(collection, label_method: @label_method, value_method: @value_method)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def build_attributes
|
56
|
-
@provided_choices = !attributes[:choices].nil?
|
57
|
-
@skip_authorization = attributes.delete(:skip_authorization)
|
58
|
-
@add_action = attributes.delete(:add_action)
|
59
|
-
|
60
|
-
super
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Plutonium
|
4
|
-
module UI
|
5
|
-
module Form
|
6
|
-
module Components
|
7
|
-
class HasMany < Phlexi::Form::Components::HasMany
|
8
|
-
include Plutonium::UI::Component::Methods
|
9
|
-
|
10
|
-
def view_template
|
11
|
-
div(class: "flex space-x-1") do
|
12
|
-
super
|
13
|
-
render_add_button
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def add_url
|
20
|
-
@add_url ||= begin
|
21
|
-
return unless @skip_authorization || allowed_to?(:create?, association_reflection.klass)
|
22
|
-
|
23
|
-
url = @add_action || resource_url_for(association_reflection.klass, action: :new, parent: nil)
|
24
|
-
return unless url
|
25
|
-
|
26
|
-
uri = URI(url)
|
27
|
-
uri.query = URI.encode_www_form({return_to: request.original_url})
|
28
|
-
uri.to_s
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def render_add_button
|
33
|
-
return if @add_action == false || add_url.nil?
|
34
|
-
|
35
|
-
a(
|
36
|
-
href: add_url,
|
37
|
-
class:
|
38
|
-
"bg-gray-100 dark:bg-gray-600 dark:hover:bg-gray-700 dark:border-gray-500 hover:bg-gray-200 border border-gray-300 rounded-lg p-3 focus:ring-gray-100 dark:focus:ring-gray-700 focus:ring-2 focus:outline-none dark:text-white"
|
39
|
-
) do
|
40
|
-
render Phlex::TablerIcons::Plus.new(class: "w-3 h-3")
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def choices
|
45
|
-
@choices ||= begin
|
46
|
-
collection = if @provided_choices || @skip_authorization
|
47
|
-
@choice_collection
|
48
|
-
else
|
49
|
-
authorized_resource_scope(association_reflection.klass, relation: @choice_collection)
|
50
|
-
end
|
51
|
-
Phlexi::Form::ChoicesMapper.new(collection, label_method: @label_method, value_method: @value_method)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def build_attributes
|
56
|
-
@provided_choices = !attributes[:choices].nil?
|
57
|
-
@skip_authorization = attributes.delete(:skip_authorization)
|
58
|
-
@add_action = attributes.delete(:add_action)
|
59
|
-
|
60
|
-
super
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|