plutonium 0.10.3 → 0.11.1

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -2
  3. data/app/assets/application.js.bk +31419 -0
  4. data/app/assets/plutonium-original.png +0 -0
  5. data/app/assets/plutonium-white.png +0 -0
  6. data/app/assets/plutonium.css +1 -0
  7. data/app/assets/plutonium.ico +0 -0
  8. data/app/assets/plutonium.js +12416 -0
  9. data/app/assets/plutonium.js.map +7 -0
  10. data/app/assets/plutonium.min.js +39 -0
  11. data/app/assets/plutonium.min.js.map +7 -0
  12. data/app/assets/plutonium.png +0 -0
  13. data/app/views/application/_flash_alerts.html.erb +2 -2
  14. data/app/views/application/_resource_header.html.erb +261 -697
  15. data/app/views/application/_resource_sidebar.html.erb +14 -12
  16. data/app/views/components/action_button/action_button_component.rb +3 -3
  17. data/app/views/components/attributes.rb +184 -0
  18. data/app/views/components/base.rb +19 -40
  19. data/app/views/components/block/block_component.html.erb +1 -1
  20. data/app/views/components/block/block_component.rb +11 -7
  21. data/app/views/components/breadcrumbs/breadcrumbs_component.rb +3 -3
  22. data/app/views/components/button/button_component.html.erb +2 -2
  23. data/app/views/components/button/button_component.rb +10 -5
  24. data/app/views/components/dyna_frame_content/dyna_frame_content_component.html.erb +1 -0
  25. data/app/views/components/dyna_frame_content/dyna_frame_content_component.rb +3 -3
  26. data/app/views/components/dyna_frame_host/dyna_frame_host_component.html.erb +1 -2
  27. data/app/views/components/dyna_frame_host/dyna_frame_host_component.rb +12 -5
  28. data/app/views/components/empty_card/empty_card_component.rb +3 -3
  29. data/app/views/components/form/form_builder.rb +1 -1
  30. data/app/views/components/form/form_component.rb +3 -3
  31. data/app/views/components/has_many_panel/has_many_panel_component.html.erb +25 -0
  32. data/app/views/components/has_many_panel/has_many_panel_component.rb +16 -0
  33. data/app/views/components/header/header_component.rb +3 -3
  34. data/app/views/components/interactive_action_form/interactive_action_form_component.rb +3 -3
  35. data/app/views/components/nav_grid_menu/nav_grid_menu_component.html.erb +24 -0
  36. data/app/views/components/nav_grid_menu/nav_grid_menu_component.rb +23 -0
  37. data/app/views/components/nav_grid_menu_item/nav_grid_menu_item_component.html.erb +4 -0
  38. data/app/views/components/nav_grid_menu_item/nav_grid_menu_item_component.rb +20 -0
  39. data/app/views/components/nav_user/nav_user_component.html.erb +50 -0
  40. data/app/views/components/nav_user/nav_user_component.rb +32 -0
  41. data/app/views/components/nav_user_link/nav_user_link_component.html.erb +7 -0
  42. data/app/views/components/nav_user_link/nav_user_link_component.rb +23 -0
  43. data/app/views/components/nav_user_section/nav_user_section_component.html.erb +7 -0
  44. data/app/views/components/nav_user_section/nav_user_section_component.rb +18 -0
  45. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.html.erb +1 -3
  46. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.rb +11 -5
  47. data/app/views/components/pagination/pagination_component.html.erb +1 -1
  48. data/app/views/components/pagination/pagination_component.rb +10 -7
  49. data/app/views/components/panel/panel_component.html.erb +13 -6
  50. data/app/views/components/panel/panel_component.rb +11 -5
  51. data/app/views/components/resource_header/resource_header_component.html.erb +83 -0
  52. data/app/views/components/resource_header/resource_header_component.rb +30 -0
  53. data/app/views/components/resource_layout/resource_layout_component.html.erb +49 -0
  54. data/app/views/components/resource_layout/resource_layout_component.rb +41 -0
  55. data/app/views/components/sidebar/sidebar_component.html.erb +3 -33
  56. data/app/views/components/sidebar/sidebar_component.rb +3 -3
  57. data/app/views/components/sidebar_menu/sidebar_menu_component.html.erb +4 -2
  58. data/app/views/components/sidebar_menu/sidebar_menu_component.rb +10 -6
  59. data/app/views/components/sidebar_menu_item/sidebar_menu_item_component.html.erb +63 -71
  60. data/app/views/components/sidebar_menu_item/sidebar_menu_item_component.rb +27 -8
  61. data/app/views/components/skeleton/table/table_component.html.erb +1 -1
  62. data/app/views/components/skeleton/table/table_component.rb +3 -3
  63. data/app/views/components/table/table_component.html.erb +40 -89
  64. data/app/views/components/table/table_component.rb +124 -28
  65. data/app/views/components/table_search_input/table_search_input_component.html.erb +1 -1
  66. data/app/views/components/table_search_input/table_search_input_component.rb +11 -6
  67. data/app/views/components/table_toolbar/table_toolbar_component.html.erb +1 -1
  68. data/app/views/components/table_toolbar/table_toolbar_component.rb +11 -3
  69. data/app/views/components/toolbar/toolbar_component.html.erb +2 -2
  70. data/app/views/components/toolbar/toolbar_component.rb +16 -8
  71. data/app/views/layouts/resource.html.erb +12 -45
  72. data/app/views/layouts/rodauth.html.erb +20 -36
  73. data/app/views/resource/_interactive_resource_action_form.html.erb +1 -1
  74. data/app/views/resource/_resource_details.html.erb +8 -5
  75. data/app/views/resource/_resource_table.html.erb +70 -1
  76. data/app/views/resource/interactive_resource_collection_action.html.erb +1 -0
  77. data/app/views/resource/interactive_resource_record_action.html.erb +1 -0
  78. data/app/views/resource/interactive_resource_recordless_action.html.erb +1 -0
  79. data/app/views/resource/new.html.erb +1 -0
  80. data/config/initializers/simple_form.rb +22 -2
  81. data/esbuild.config.js +35 -31
  82. data/lib/generators/pu/core/assets/assets_generator.rb +44 -0
  83. data/lib/generators/pu/core/assets/templates/tailwind.config.js +18 -0
  84. data/lib/generators/pu/core/install/install_generator.rb +4 -1
  85. data/lib/generators/pu/gem/dotenv/templates/config/initializers/001_ensure_required_env.rb +6 -0
  86. data/lib/generators/pu/gen/component/component_generator.rb +13 -10
  87. data/lib/generators/pu/gen/component/templates/component.html.erb.tt +1 -1
  88. data/lib/generators/pu/gen/component/templates/component.rb.tt +10 -4
  89. data/lib/generators/pu/pkg/app/app_generator.rb +4 -4
  90. data/lib/generators/pu/pkg/app/templates/app/controllers/concerns/controller.rb.tt +28 -0
  91. data/lib/generators/pu/pkg/app/templates/app/controllers/controller.rb.tt +5 -0
  92. data/lib/generators/pu/pkg/app/templates/app/controllers/dashboard_controller.rb.tt +1 -1
  93. data/lib/generators/pu/res/conn/conn_generator.rb +4 -4
  94. data/lib/generators/pu/res/conn/templates/app/controllers/resource_controller.rb.tt +1 -1
  95. data/lib/generators/pu/res/model/model_generator.rb +3 -3
  96. data/lib/generators/pu/res/scaffold/templates/policy.rb.tt +6 -0
  97. data/lib/generators/pu/service/sidekiq/sidekiq_generator.rb +0 -5
  98. data/lib/generators/pu/service/sidekiq/templates/app/sidekiq/sidekiq_job.rb +0 -2
  99. data/lib/plutonium/config.rb +2 -14
  100. data/lib/plutonium/core/associations/renderers/basic_renderer.rb +28 -0
  101. data/lib/plutonium/core/associations/renderers/factory.rb +36 -0
  102. data/lib/plutonium/core/associations/renderers/has_many_renderer.rb +16 -0
  103. data/lib/plutonium/core/autodiscovery/association_renderer_discoverer.rb +31 -0
  104. data/lib/plutonium/core/controllers/authorizable.rb +13 -17
  105. data/lib/plutonium/core/controllers/base.rb +3 -7
  106. data/lib/plutonium/core/controllers/presentable.rb +6 -1
  107. data/lib/plutonium/core/definers/association_renderer_definer.rb +33 -0
  108. data/lib/plutonium/core/fields/inputs/checkbox_input.rb +13 -0
  109. data/lib/plutonium/core/fields/inputs/factory.rb +1 -0
  110. data/lib/plutonium/core/fields/inputs/polymorphic_belongs_to_association_input.rb +1 -1
  111. data/lib/plutonium/core/ui/detail.rb +1 -0
  112. data/lib/plutonium/helpers/application_helper.rb +8 -9
  113. data/lib/plutonium/helpers/assets_helper.rb +41 -0
  114. data/lib/plutonium/helpers/display_helper.rb +13 -0
  115. data/lib/plutonium/helpers/form_helper.rb +1 -1
  116. data/lib/plutonium/helpers.rb +1 -0
  117. data/lib/plutonium/icons.rb +12 -5
  118. data/lib/plutonium/pkg/app.rb +10 -0
  119. data/lib/plutonium/pundit/context.rb +18 -0
  120. data/lib/plutonium/pundit/policy_finder.rb +25 -0
  121. data/lib/plutonium/railtie.rb +26 -8
  122. data/lib/plutonium/reloader.rb +18 -7
  123. data/lib/plutonium/resource/controller.rb +4 -0
  124. data/lib/plutonium/resource/policy.rb +69 -47
  125. data/lib/plutonium/resource/presenter.rb +1 -0
  126. data/lib/plutonium/resource/query_object.rb +139 -130
  127. data/lib/plutonium/rodauth/controller_methods.rb +7 -3
  128. data/lib/plutonium/version.rb +1 -1
  129. data/lib/plutonium.rb +9 -57
  130. data/package-lock.json +782 -17
  131. data/package.json +31 -8
  132. data/postcss.config.js +17 -7
  133. data/src/.npmignore +2 -0
  134. data/src/js/controllers/color_mode_controller.js +41 -0
  135. data/src/js/controllers/frame_navigator_controller.js +99 -0
  136. data/src/js/controllers/has_many_panel_controller.js +8 -0
  137. data/src/js/controllers/nav_grid_menu_controller.js +8 -0
  138. data/src/js/controllers/nav_grid_menu_item_controller.js +8 -0
  139. data/{app/views/components/tab_bar/tab_bar_controller.js → src/js/controllers/nav_user_controller.js} +2 -2
  140. data/src/js/controllers/nav_user_link_controller.js +8 -0
  141. data/src/js/controllers/nav_user_section_controller.js +8 -0
  142. data/src/js/controllers/register_controllers.js +45 -0
  143. data/{app/assets/javascripts → src/js}/controllers/resource_dismiss_controller.js +2 -0
  144. data/{app/assets/javascripts → src/js}/controllers/resource_drop_down_controller.js +2 -0
  145. data/src/js/controllers/resource_header_controller.js +8 -0
  146. data/src/js/controllers/resource_layout_controller.js +8 -0
  147. data/src/js/controllers/sidebar_menu_controller.js +8 -0
  148. data/src/js/controllers/sidebar_menu_item_controller.js +8 -0
  149. data/src/js/core.js +4 -0
  150. data/{app/assets/javascripts/plutonium-app.js → src/js/plutonium.js} +1 -1
  151. data/{app/assets/javascripts → src/js}/turbo/turbo_debug.js +2 -4
  152. data/tailwind.config.js +85 -84
  153. metadata +73 -39
  154. data/app/assets/build/plutonium.js +0 -5122
  155. data/app/assets/javascripts/controllers/index.js +0 -34
  156. data/app/assets/javascripts/plutonium.js +0 -1
  157. data/app/views/application/_color_modes.html.erb +0 -57
  158. data/app/views/components/tab_bar/tab_bar_component.html.erb +0 -11
  159. data/app/views/components/tab_bar/tab_bar_component.rb +0 -9
  160. data/app/views/resource/_nav_user.html.erb +0 -4
  161. data/app/views/resource/_tab_menu.html.erb +0 -13
  162. data/css.manifest +0 -3
  163. data/js.manifest +0 -4
  164. data/lib/generators/pu/pkg/app/templates/app/controllers/app_controller.rb.tt +0 -5
  165. data/lib/generators/pu/pkg/app/templates/app/controllers/package_controller.rb.tt +0 -26
  166. data/public/plutonium-assets/application.css +0 -25086
  167. data/public/plutonium-assets/plutonium-app-36KN5FVJ.js +0 -6
  168. data/public/plutonium-assets/plutonium-app-36KN5FVJ.js.map +0 -7
  169. data/public/plutonium-assets/plutonium-app-6WILQCTT.js +0 -39
  170. data/public/plutonium-assets/plutonium-app-6WILQCTT.js.map +0 -7
  171. data/public/plutonium-assets/plutonium.2d4f0c333cd000051d3b.css +0 -3424
  172. data/public/plutonium-assets/plutonium.50232e35b5495f5ad90d.css +0 -3415
  173. data/public/plutonium-assets/plutonium.8bee7a8482988b0360e3.css +0 -3420
  174. /data/{app/assets/build → lib/generators/pu/core/assets/templates}/.keep +0 -0
  175. /data/{app/assets/stylesheets → src/css}/plutonium.css +0 -0
  176. /data/{app/views/components/form → src/js/controllers}/form_controller.js +0 -0
  177. /data/{app/views/components/interactive_action_form → src/js/controllers}/interactive_action_form_controller.js +0 -0
  178. /data/{app/views/components/nested_resource_form_fields → src/js/controllers}/nested_resource_form_fields_controller.js +0 -0
  179. /data/{app/views/components/table → src/js/controllers}/table_controller.js +0 -0
  180. /data/{app/views/components/table_search_input → src/js/controllers}/table_search_input_controller.js +0 -0
  181. /data/{app/views/components/table_toolbar → src/js/controllers}/table_toolbar_controller.js +0 -0
  182. /data/{app/views/components/toolbar → src/js/controllers}/toolbar_controller.js +0 -0
  183. /data/{app/assets/javascripts → src/js}/turbo/index.js +0 -0
  184. /data/{app/assets/javascripts → src/js}/turbo/turbo_actions.js +0 -0
  185. /data/{app/assets/javascripts → src/js}/turbo/turbo_frame_monkey_patch.js +0 -0
@@ -17,7 +17,7 @@ module Pu
17
17
  source_feature = select_feature
18
18
  source_module = (source_feature == "main_app") ? "ResourceRecord" : "#{source_feature.classify}::ResourceRecord"
19
19
 
20
- Rails.application.eager_load!
20
+ Plutonium.eager_load_rails!
21
21
  available_resources = source_module.constantize.descendants.map(&:to_s)
22
22
  selected_resources = prompt.multi_select("Select resources", available_resources)
23
23
 
@@ -27,9 +27,9 @@ module Pu
27
27
  @resource_class = resource
28
28
 
29
29
  template "app/controllers/resource_controller.rb", "packages/#{package_namespace}/app/controllers/#{package_namespace}/#{resource.pluralize.underscore}_controller.rb"
30
- template "app/policies/resource_policy.rb", "packages/#{package_namespace}/app/policies/#{package_namespace}/#{resource.underscore}_policy.rb"
31
- template "app/presenters/resource_presenter.rb", "packages/#{package_namespace}/app/presenters/#{package_namespace}/#{resource.underscore}_presenter.rb"
32
- template "app/query_objects/resource_query_object.rb", "packages/#{package_namespace}/app/query_objects/#{package_namespace}/#{resource.underscore}_query_object.rb"
30
+ # template "app/policies/resource_policy.rb", "packages/#{package_namespace}/app/policies/#{package_namespace}/#{resource.underscore}_policy.rb"
31
+ # template "app/presenters/resource_presenter.rb", "packages/#{package_namespace}/app/presenters/#{package_namespace}/#{resource.underscore}_presenter.rb"
32
+ # template "app/query_objects/resource_query_object.rb", "packages/#{package_namespace}/app/query_objects/#{package_namespace}/#{resource.underscore}_query_object.rb"
33
33
 
34
34
  insert_into_file "packages/#{package_namespace}/lib/engine.rb",
35
35
  indent("register_resource ::#{resource}\n", 6),
@@ -1,3 +1,3 @@
1
1
  class <%= app_namespace %>::<%= resource_class.pluralize %>Controller < ::<%= resource_class.pluralize %>Controller
2
- include <%= app_namespace %>::<%= app_namespace %>Controller
2
+ include <%= app_namespace %>::Concerns::Controller
3
3
  end
@@ -14,9 +14,9 @@ module Pu
14
14
  def run_create_model
15
15
  model_class = class_name.safe_constantize
16
16
  if model_class.present? && !model_class.include?(Plutonium::Resource::Record)
17
- insert_into_file File.join("app/models", class_path, "#{file_name}.rb"),
18
- indent("include Plutonium::Resource::Record\n", 2),
19
- after: /.*class .*\n/
17
+ gsub_file File.join("app/models", class_path, "#{file_name}.rb"),
18
+ "< ApplicationRecord",
19
+ "< ResourceRecord"
20
20
  end
21
21
 
22
22
  create_model_file if create_files?
@@ -19,5 +19,11 @@ class <%= class_name %>Policy < <%= [feature_package_name, "ResourcePolicy"].joi
19
19
  def permitted_attributes_for_read
20
20
  <%= attributes.select{ |a| !a.rich_text? && !a.password_digest? && !a.token? }.map(&:name).map(&:to_sym).inspect %>
21
21
  end
22
+
23
+ # Associations
24
+
25
+ def permitted_associations
26
+ %i[]
27
+ end
22
28
  end
23
29
  <% end -%>
@@ -13,14 +13,9 @@ module Pu
13
13
 
14
14
  def start
15
15
  bundle "sidekiq"
16
- bundle "sidekiq-failures"
17
16
  directory "app"
18
17
  directory "config"
19
18
 
20
- in_root do
21
- insert_into_file "app/jobs/application_job.rb", "\n sidekiq_options failures: :exhausted\n", before: /^end/
22
- end
23
-
24
19
  add_compose_env :REDIS_QUEUE_URL, "redis://redis-queue/0"
25
20
  add_required_env_vars :REDIS_QUEUE_URL
26
21
  add_compose_dependency redis_service
@@ -1,5 +1,3 @@
1
1
  class SidekiqJob
2
2
  include Sidekiq::Job
3
-
4
- sidekiq_options failures: :exhausted
5
3
  end
@@ -3,19 +3,7 @@ require "active_model"
3
3
 
4
4
  module Plutonium
5
5
  module Config
6
- mattr_accessor :stylesheet_tag
7
- @@stylesheet_tag = ->(view_context) {
8
- "<link rel=\"stylesheet\" href=\"#{Plutonium.stylesheet_link}\" data-turbo-track=\"reload\" />".html_safe
9
- }
10
-
11
- mattr_accessor :script_tag
12
- @@script_tag = ->(view_context) {
13
- "<script src=\"#{Plutonium.script_link}\" data-turbo-track=\"reload\"></script>".html_safe
14
- }
15
-
16
- mattr_accessor :favicon_tag
17
- @@favicon_tag = ->(view_context) {
18
- "<link rel=\"icon\" type=\"image/x-icon\" href=\"#{Plutonium.favicon_link}\">".html_safe
19
- }
6
+ mattr_accessor :logo
7
+ @@logo = "plutonium-logo.png"
20
8
  end
21
9
  end
@@ -0,0 +1,28 @@
1
+ module Plutonium
2
+ module Core
3
+ module Associations
4
+ module Renderers
5
+ class BasicRenderer
6
+ attr_reader :name, :label, :reflection, :user_options
7
+
8
+ def initialize(name, label:, reflection:, **user_options)
9
+ @name = name
10
+ @label = label
11
+ @reflection = reflection
12
+ @user_options = user_options
13
+ end
14
+
15
+ def render(view_context, record)
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def options = @options ||= renderer_options.deep_merge(@user_options)
20
+
21
+ private
22
+
23
+ def renderer_options = {}
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ require "simple_form/map_type"
2
+
3
+ module Plutonium
4
+ module Core
5
+ module Associations
6
+ module Renderers
7
+ class Factory
8
+ extend ::SimpleForm::MapType
9
+
10
+ map_type :has_many, to: Plutonium::Core::Associations::Renderers::HasManyRenderer
11
+
12
+ def self.build(name, type:, **)
13
+ mapping = mappings[type]
14
+ raise ArgumentError, "Unknown association renderer type #{type}" unless mapping.present?
15
+
16
+ mapping.new(name, **)
17
+ end
18
+
19
+ def self.for_resource_association(resource_class, attr_name, **options)
20
+ options[:label] ||= resource_class.human_attribute_name(attr_name)
21
+
22
+ association = resource_class.try(:reflect_on_association, attr_name)
23
+ raise ArgumentError, "#{attr_name} is not a valid association of #{resource_class}" unless association.present?
24
+ raise ArgumentError, "#{association.klass} does is not a resource record" unless association.klass.include?(Plutonium::Resource::Record)
25
+
26
+ type = association.macro
27
+ raise NotImplementedError, "#{macro} associations are currently not supported." unless type == :has_many
28
+
29
+ options[:reflection] = association
30
+ build(attr_name, type:, **options)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ module Plutonium
2
+ module Core
3
+ module Associations
4
+ module Renderers
5
+ class HasManyRenderer < BasicRenderer
6
+ def render(view_context, record)
7
+ view_context.render_component :has_many_panel,
8
+ title: label,
9
+ src: view_context.resource_url_for(reflection.klass, parent: record),
10
+ **options
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,31 @@
1
+ module Plutonium
2
+ module Core
3
+ module Autodiscovery
4
+ module AssociationRendererDiscoverer
5
+ extend ActiveSupport::Concern
6
+ include Discoverer
7
+
8
+ class_methods do
9
+ def autodiscovery_association_renderer_cache = @autodiscovery_association_renderer_cache ||= {}
10
+ end
11
+
12
+ private
13
+
14
+ # If cache_discovery is enabled, use the class level cache that persists
15
+ # between requests, otherwise use the instance one.
16
+ def autodiscovery_association_renderer_cache
17
+ if Rails.application.config.plutonium.cache_discovery
18
+ self.class.autodiscovery_association_renderer_cache
19
+ else
20
+ @autodiscovery_association_renderer_cache ||= {}
21
+ end
22
+ end
23
+
24
+ def autodiscover_association_renderer(name)
25
+ autodiscovery_association_renderer_cache[name] ||=
26
+ Plutonium::Core::Associations::Renderers::Factory.for_resource_association(resource_class, name)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -5,22 +5,17 @@ module Plutonium
5
5
  module Controllers
6
6
  module Authorizable
7
7
  extend ActiveSupport::Concern
8
- include Pundit::Authorization
8
+ include ::Pundit::Authorization
9
9
 
10
10
  included do
11
11
  after_action :verify_authorized
12
12
  after_action :verify_policy_scoped, except: %i[new create]
13
13
 
14
- helper_method :permitted_attributes
15
- helper_method :current_policy
14
+ helper_method :current_policy, :permitted_attributes
16
15
  end
17
16
 
18
17
  private
19
18
 
20
- def policy_namespace(scope)
21
- [current_package.to_s.underscore.to_sym, scope]
22
- end
23
-
24
19
  def policy_context
25
20
  raise NotImplementedError, "policy_context"
26
21
  end
@@ -29,22 +24,23 @@ module Plutonium
29
24
  policy_context
30
25
  end
31
26
 
32
- def policy(scope)
33
- super(policy_namespace(scope))
34
- end
35
-
36
- def policy_scope(scope)
37
- super(policy_namespace(scope))
38
- end
39
-
40
- def authorize(record, query = nil)
41
- super(policy_namespace(record), query)
27
+ # @return [Plutonium::Pundit::Context] a new instance of {Plutonium::Pundit::Context} with the current user and package
28
+ def pundit
29
+ @pundit ||= Plutonium::Pundit::Context.new(
30
+ package: current_package.to_s.underscore.to_sym,
31
+ user: pundit_user,
32
+ policy_cache: ::Pundit::CacheStore::LegacyStore.new(policies)
33
+ )
42
34
  end
43
35
 
44
36
  def permitted_attributes
45
37
  @permitted_attributes ||= current_policy.send_with_report :"permitted_attributes_for_#{action_name}"
46
38
  end
47
39
 
40
+ def permitted_associations
41
+ @permitted_associations ||= current_policy.permitted_associations
42
+ end
43
+
48
44
  def current_policy
49
45
  @current_policy ||= begin
50
46
  policy_subject = resource_record || resource_class
@@ -18,7 +18,7 @@ module Plutonium
18
18
  end
19
19
 
20
20
  helper Plutonium::Helpers
21
- helper_method :page_title, :resource_url_for, :resource_url_args_for, :root_path, :application_name
21
+ helper_method :make_page_title, :resource_url_for, :resource_url_args_for, :root_path
22
22
 
23
23
  append_view_path File.expand_path("app/views", Plutonium.root)
24
24
  layout -> { turbo_frame_request? ? false : "resource" }
@@ -30,12 +30,8 @@ module Plutonium
30
30
  @page_title = nil
31
31
  end
32
32
 
33
- def page_title(title)
34
- [title.presence, application_name].compact.join(" | ")
35
- end
36
-
37
- def application_name
38
- Plutonium.application_name
33
+ def make_page_title(title)
34
+ [title.presence, helpers.application_name].compact.join(" | ")
39
35
  end
40
36
 
41
37
  #
@@ -5,7 +5,7 @@ module Plutonium
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- helper_method :presentable_attributes
8
+ helper_method :presentable_attributes, :present_associations?
9
9
  end
10
10
 
11
11
  private
@@ -44,6 +44,7 @@ module Plutonium
44
44
  resource_class:,
45
45
  record: resource_record,
46
46
  fields: current_presenter.defined_renderers_for(*presentable_attributes),
47
+ associations: current_presenter.defined_association_renderers_for(*permitted_associations),
47
48
  actions: current_presenter.actions
48
49
  )
49
50
  end
@@ -54,6 +55,10 @@ module Plutonium
54
55
  inputs: current_presenter.defined_inputs_for(*presentable_attributes)
55
56
  )
56
57
  end
58
+
59
+ def present_associations?
60
+ current_parent.nil?
61
+ end
57
62
  end
58
63
  end
59
64
  end
@@ -0,0 +1,33 @@
1
+ module Plutonium
2
+ module Core
3
+ module Definers
4
+ module AssociationRendererDefiner
5
+ extend ActiveSupport::Concern
6
+ include Plutonium::Core::Autodiscovery::AssociationRendererDiscoverer
7
+
8
+ def defined_association_renderers_for(*names)
9
+ (names - association_renderer_definitions.keys).each do |name|
10
+ define_association_renderer(name, renderer: autodiscover_association_renderer(name))
11
+ end
12
+ association_renderer_definitions.slice(*names)
13
+ end
14
+
15
+ private
16
+
17
+ def association_renderer_definitions = @association_renderer_definitions ||= {}
18
+
19
+ def define_association_renderer(name, renderer: nil, **options)
20
+ association_renderer_definitions[name] = if renderer.present?
21
+ renderer
22
+ else
23
+ autodiscover_association_renderer(name)
24
+ end
25
+ end
26
+
27
+ def association_renderer_defined?(name)
28
+ association_renderer_definitions.key? name
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Inputs
5
+ class CheckboxInput < SimpleFormInput
6
+ private
7
+
8
+ def input_options = {wrapper: :resource_checkbox}
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -14,6 +14,7 @@ module Plutonium
14
14
  map_type :attachment, to: Plutonium::Core::Fields::Inputs::AttachmentInput
15
15
  map_type :datetime, :date, :time, to: Plutonium::Core::Fields::Inputs::DateTimeInput
16
16
  map_type :phone, to: Plutonium::Core::Fields::Inputs::PhoneInput
17
+ map_type :boolean, to: Plutonium::Core::Fields::Inputs::CheckboxInput
17
18
  # map_type :text, :string, to: Plutonium::Core::Fields::Inputs::SimpleFormInput
18
19
 
19
20
  def self.build(name, type:, **options)
@@ -27,7 +27,7 @@ module Plutonium
27
27
  end
28
28
 
29
29
  def associated_classes
30
- Rails.application.eager_load! unless Rails.application.config.eager_load
30
+ Plutonium.eager_load_rails!
31
31
 
32
32
  associated_classes = []
33
33
  ActiveRecord::Base.descendants.each do |model|
@@ -7,6 +7,7 @@ module Plutonium
7
7
  option :resource_class
8
8
  option :record, optional: true
9
9
  option :fields, default: proc { {} }
10
+ option :associations, default: proc { {} }
10
11
  option :actions, default: proc { Plutonium::Core::Actions::Collection.new }
11
12
  end
12
13
  end
@@ -1,17 +1,16 @@
1
1
  module Plutonium
2
2
  module Helpers
3
3
  module ApplicationHelper
4
- # def tooltip(text)
5
- # text = sanitize text
6
- # "title=\"#{text}\" data-controller=\"tooltip\" data-bs-title=\"#{text}\"".html_safe
7
- # end
8
-
9
- def resource_name(resource_class, count = 1)
10
- resource_class.model_name.human.pluralize(count)
4
+ def application_name
5
+ Plutonium.application_name
11
6
  end
12
7
 
13
- def resource_name_plural(resource_class)
14
- resource_name resource_class, 2
8
+ # Renders an icon using the Plutonium Icons library.
9
+ #
10
+ # @param icon [Symbol, String] The name or identifier of the icon to render.
11
+ # @return [String] The HTML-safe string for the rendered icon.
12
+ def render_icon(icon, **)
13
+ Plutonium::Icons.render(icon, **)
15
14
  end
16
15
  end
17
16
  end
@@ -0,0 +1,41 @@
1
+ module Plutonium
2
+ module Helpers
3
+ module AssetsHelper
4
+ def resource_stylesheet_tag
5
+ url = if Plutonium.development?
6
+ filename = JSON.parse(File.read(Plutonium.root.join("src", "build", "css.manifest")))["plutonium.css"]
7
+ "/build/#{filename}"
8
+ else
9
+ resource_stylesheet_asset
10
+ end
11
+ stylesheet_link_tag url, "data-turbo-track": "reload"
12
+ end
13
+
14
+ def resource_script_tag
15
+ url = if Plutonium.development?
16
+ filename = JSON.parse(File.read(Plutonium.root.join("src", "build", "js.manifest")))["plutonium.js"]
17
+ "/build/#{filename}"
18
+ else
19
+ resource_script_asset
20
+ end
21
+ javascript_include_tag url, "data-turbo-track": "reload", type: "module"
22
+ end
23
+
24
+ def resource_favicon_tag
25
+ favicon_link_tag resource_favicon_asset
26
+ end
27
+
28
+ def resource_logo_tag(classname:)
29
+ image_tag resource_logo_asset, class: classname
30
+ end
31
+
32
+ def resource_logo_asset = Rails.application.config.plutonium.assets.logo
33
+
34
+ def resource_stylesheet_asset = Rails.application.config.plutonium.assets.stylesheet
35
+
36
+ def resource_script_asset = Rails.application.config.plutonium.assets.script
37
+
38
+ def resource_favicon_asset = Rails.application.config.plutonium.assets.favicon
39
+ end
40
+ end
41
+ end
@@ -1,6 +1,19 @@
1
1
  module Plutonium
2
2
  module Helpers
3
3
  module DisplayHelper
4
+ # def tooltip(text)
5
+ # text = sanitize text
6
+ # "title=\"#{text}\" data-controller=\"tooltip\" data-bs-title=\"#{text}\"".html_safe
7
+ # end
8
+
9
+ def resource_name(resource_class, count = 1)
10
+ resource_class.model_name.human.pluralize(count)
11
+ end
12
+
13
+ def resource_name_plural(resource_class)
14
+ resource_name resource_class, 2
15
+ end
16
+
4
17
  def display_field(value:, helper: nil, **options)
5
18
  return "-" unless value.present?
6
19
 
@@ -6,7 +6,7 @@ module Plutonium
6
6
  include ActionView::Helpers::FormHelper
7
7
 
8
8
  def resource_form_for(record, options = {}, &block)
9
- options[:builder] ||= Plutonium::Ui::FormBuilder
9
+ options[:builder] ||= PlutoniumUi::FormBuilder
10
10
  options[:wrapper] ||= :default_resource_form
11
11
  options[:html] ||= {}
12
12
  unless options[:html].key?(:novalidate)
@@ -12,6 +12,7 @@ module Plutonium
12
12
  include Plutonium::Helpers::TableHelper
13
13
  include Plutonium::Helpers::TurboHelper
14
14
  include Plutonium::Helpers::TurboStreamActionsHelper
15
+ include Plutonium::Helpers::AssetsHelper
15
16
  end
16
17
  end
17
18
  end
@@ -4,20 +4,27 @@ module Plutonium
4
4
  ICON_SIZES = {
5
5
  sm: "w-3 h-3",
6
6
  md: "w-4 h-4",
7
- lg: "w-6 h-6"
7
+ lg: "w-6 h-6",
8
+ xl: "w-8 h-8"
8
9
  }
9
10
 
10
11
  class << self
11
- def render(name, size: :md)
12
+ def render(name, size: :md, classname: nil)
13
+ size = ICON_SIZES.key?(size) ? size : :sm
14
+ classname = (Array(classname) + [ICON_SIZES[size]]).join(" ")
15
+
16
+ resolve(name).sub("<svg ", "<svg class=\"#{classname}\" ").html_safe
17
+ end
18
+
19
+ def resolve(name)
12
20
  # This is not threadsafe, but should not cause any issues
13
21
  # I believe adding a mutex would be overall more expensive than a few potential
14
22
  # concurrent disk accesses for a brief while after boot.
15
- size = ICON_SIZES.key?(size) ? size : :sm
16
- ICON_CACHE["#{name}:#{size}"] ||= begin
23
+ ICON_CACHE[name] ||= begin
17
24
  path = Plutonium.root.join "app/assets/icons/#{name}.svg"
18
25
  raise "Invalid icon: #{name}" unless File.exist?(path)
19
26
 
20
- File.read(path).sub("<svg ", "<svg class=\"#{ICON_SIZES[size]}\" ").html_safe
27
+ File.read(path)
21
28
  end
22
29
  end
23
30
  end
@@ -1,3 +1,5 @@
1
+ require "active_support/notifications"
2
+
1
3
  module Plutonium
2
4
  module Pkg
3
5
  module App
@@ -49,6 +51,14 @@ module Plutonium
49
51
  end
50
52
 
51
53
  def draw_resource_routes
54
+ ActiveSupport::Notifications.instrument("plutonium.app.draw_resource_routes", app: self.class.module_parent.to_s) do
55
+ draw_resource_routes_internal
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def draw_resource_routes_internal
52
62
  custom_routes_block = @custom_routes_block
53
63
  registered_resources = resource_register
54
64
  scoped_entity_param_key = self.scoped_entity_param_key if scoped_entity_strategy == :path
@@ -0,0 +1,18 @@
1
+ require "pundit"
2
+
3
+ module Plutonium
4
+ module Pundit
5
+ class Context < ::Pundit::Context
6
+ def initialize(*, package:, **)
7
+ super(*, **)
8
+ @package = package
9
+ end
10
+
11
+ private
12
+
13
+ def policy_finder(record)
14
+ PolicyFinder.new(record, package: @package)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ require "pundit"
2
+
3
+ module Plutonium
4
+ module Pundit
5
+ class PolicyFinder < ::Pundit::PolicyFinder
6
+ def initialize(*, package:)
7
+ super(*)
8
+ @package = package
9
+ end
10
+
11
+ attr_reader :package
12
+
13
+ def policy
14
+ policy_internal([package, object]) || policy_internal(object)
15
+ end
16
+
17
+ private
18
+
19
+ def policy_internal(object)
20
+ klass = find(object)
21
+ klass.is_a?(String) ? klass.safe_constantize : klass
22
+ end
23
+ end
24
+ end
25
+ end