plutonium 0.15.6 → 0.15.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/plutonium.css +1 -1
  3. data/app/assets/plutonium.js +25 -11
  4. data/app/assets/plutonium.js.map +2 -2
  5. data/app/assets/plutonium.min.js +4 -4
  6. data/app/assets/plutonium.min.js.map +3 -3
  7. data/app/views/layouts/rodauth.html.erb +2 -2
  8. data/docs/guide/getting-started/installation.md +2 -1
  9. data/docs/guide/getting-started/resources.md +8 -12
  10. data/docs/public/templates/plutonium.rb +8 -0
  11. data/lib/generators/pu/core/assets/assets_generator.rb +1 -1
  12. data/lib/generators/pu/eject/layout/layout_generator.rb +3 -3
  13. data/lib/generators/pu/eject/shell/shell_generator.rb +3 -3
  14. data/lib/generators/pu/gem/dotenv/dotenv_generator.rb +1 -1
  15. data/lib/generators/pu/gem/letter_opener/letter_opener_generator.rb +21 -0
  16. data/lib/generators/pu/gem/redis/redis_generator.rb +0 -2
  17. data/lib/generators/pu/gem/standard/standard_generator.rb +19 -0
  18. data/lib/generators/pu/lib/plutonium_generators/generator.rb +1 -1
  19. data/lib/generators/pu/res/conn/conn_generator.rb +1 -1
  20. data/lib/plutonium/definition/actions.rb +6 -2
  21. data/lib/plutonium/definition/base.rb +1 -0
  22. data/lib/plutonium/definition/nested_inputs.rb +19 -0
  23. data/lib/plutonium/resource/controller.rb +1 -1
  24. data/lib/plutonium/resource/controllers/interactive_actions.rb +1 -1
  25. data/lib/plutonium/resource/controllers/presentable.rb +1 -5
  26. data/lib/plutonium/ui/block.rb +13 -0
  27. data/lib/plutonium/ui/component/kit.rb +10 -0
  28. data/lib/plutonium/ui/display/resource.rb +29 -11
  29. data/lib/plutonium/ui/display/theme.rb +1 -1
  30. data/lib/plutonium/ui/dyna_frame/content.rb +2 -2
  31. data/lib/plutonium/ui/dyna_frame/host.rb +20 -0
  32. data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +282 -0
  33. data/lib/plutonium/ui/form/resource.rb +39 -29
  34. data/lib/plutonium/ui/form/theme.rb +1 -1
  35. data/lib/plutonium/ui/frame_navigator_panel.rb +53 -0
  36. data/lib/plutonium/ui/panel.rb +63 -0
  37. data/lib/plutonium/ui/skeleton_table.rb +29 -0
  38. data/lib/plutonium/ui/table/resource.rb +1 -1
  39. data/lib/plutonium/version.rb +1 -1
  40. data/src/js/controllers/frame_navigator_controller.js +25 -8
  41. data/src/js/controllers/nested_resource_form_fields_controller.js +2 -2
  42. metadata +11 -3
  43. data/lib/generators/pu/gem/redis/templates/.keep +0 -0
@@ -12,8 +12,8 @@
12
12
  <%= yield %>
13
13
  </div>
14
14
  </div>
15
- <div class="mt-4 flex items-center font-medium text-blue-600 dark:text-blue-500 hover:underline">
15
+ <div class="mt-4 flex items-center font-medium text-secondary-600 dark:text-secondary-400 hover:underline">
16
16
  <%= render_icon "outline/home" %>
17
- <%= link_to "Home", root_path, class: "font-medium text-blue-600 dark:text-blue-500" %>
17
+ <%= link_to "Home", root_path, class: "font-medium text-secondary-600 dark:text-secondary-400" %>
18
18
  </div>
19
19
  <% end %>
@@ -3,6 +3,7 @@
3
3
  ::: tip VERSION REQUIREMENTS
4
4
  - Ruby 3.2.2 or higher
5
5
  - Rails 7.1 or higher
6
+ - Node.js and Yarn
6
7
  :::
7
8
 
8
9
  ## Quick Start
@@ -151,7 +152,7 @@ bin/importmap pin @radioactive-labs/plutonium
151
152
  ```
152
153
 
153
154
  ```bash [esbuild]
154
- npm install @radioactive-labs/plutonium
155
+ yarn add @radioactive-labs/plutonium
155
156
  ```
156
157
  :::
157
158
 
@@ -17,7 +17,8 @@ Resources are the core building blocks of a Plutonium application. A resource re
17
17
  The fastest way to create a resource is using the scaffold generator:
18
18
 
19
19
  ```bash
20
- rails generate pu:res:scaffold Blog user:belongs_to title:string content:text state:string published_at:datetime?
20
+ rails generate pu:res:scaffold Blog user:belongs_to \
21
+ title:string content:text 'published_at:datetime?'
21
22
  ```
22
23
 
23
24
  This generates several files, including:
@@ -40,11 +41,11 @@ class BlogPolicy < Plutonium::Resource::Policy
40
41
  end
41
42
 
42
43
  def permitted_attributes_for_create
43
- %i[user title content state published_at]
44
+ %i[user title content published_at]
44
45
  end
45
46
 
46
47
  def permitted_attributes_for_read
47
- %i[user title content state published_at]
48
+ %i[user title content published_at]
48
49
  end
49
50
  end
50
51
  ```
@@ -83,12 +84,12 @@ end
83
84
  class BlogDefinition < Plutonium::Resource::Definition
84
85
  # Customize how fields are displayed
85
86
  display :title, class: "col-span-full"
86
- display :content do |f|
87
+ display :content, class: "col-span-full" do |f|
87
88
  f.text_tag class: "prose dark:prose-invert"
88
89
  end
89
90
 
90
91
  # Custom column display in tables
91
- column :state, align: :right
92
+ column :published_at, align: :end
92
93
  end
93
94
  ```
94
95
  :::
@@ -140,7 +141,6 @@ module Blogs
140
141
 
141
142
  def execute
142
143
  if resource.update(
143
- state: "published",
144
144
  published_at: publish_date
145
145
  )
146
146
  succeed(resource)
@@ -175,20 +175,16 @@ class BlogDefinition < Plutonium::Resource::Definition
175
175
  end
176
176
 
177
177
  # Add filters
178
- filter :state,
179
- with: SelectFilter,
180
- choices: %w[draft published]
181
-
182
178
  filter :published_at,
183
179
  with: DateFilter,
184
180
  predicate: :gteq
185
181
 
186
182
  # Add scopes
187
183
  scope :published do |scope|
188
- where(state: "published")
184
+ scope.where.not(published_at: nil)
189
185
  end
190
186
  scope :draft do |scope|
191
- where(state: "draft")
187
+ scope.where(published_at: nil)
192
188
  end
193
189
 
194
190
  # Configure sorting
@@ -15,6 +15,14 @@ after_bundle do
15
15
  git add: "."
16
16
  git commit: %( -m 'add annotate' )
17
17
 
18
+ generate "pu:gem:standard"
19
+ git add: "."
20
+ git commit: %( -m 'add standardrb' )
21
+
22
+ generate "pu:gem:letter_opener"
23
+ git add: "."
24
+ git commit: %( -m 'add letter_opener' )
25
+
18
26
  generate "pu:core:assets"
19
27
  git add: "."
20
28
  git commit: %( -m 'integrate assets' )
@@ -26,7 +26,7 @@ module Pu
26
26
  end
27
27
 
28
28
  def install_dependencies
29
- run "npm install @radioactive-labs/plutonium flowbite @tailwindcss/forms"
29
+ run "yarn add @radioactive-labs/plutonium flowbite @tailwindcss/forms"
30
30
  end
31
31
 
32
32
  def configure_application
@@ -15,7 +15,7 @@ module Pu
15
15
  class_option :rodauth, type: :boolean
16
16
 
17
17
  def start
18
- destination_dir = (destination_app == "main_app") ? "app/views/" : "packages/#{destination_app}/app/views/"
18
+ destination_dir = (destination_portal == "main_app") ? "app/views/" : "packages/#{destination_portal}/app/views/"
19
19
  [
20
20
  "layouts/resource.html.erb"
21
21
  ].each do |file|
@@ -27,8 +27,8 @@ module Pu
27
27
 
28
28
  private
29
29
 
30
- def destination_app
31
- @destination_app || select_app(options[:dest], msg: "Select destination app")
30
+ def destination_portal
31
+ @destination_portal || select_portal(options[:dest], msg: "Select destination portal")
32
32
  end
33
33
 
34
34
  def copy_file(source_path, destination_path)
@@ -14,7 +14,7 @@ module Pu
14
14
  class_option :dest, type: :string
15
15
 
16
16
  def start
17
- destination_dir = (destination_app == "main_app") ? "app/views/" : "packages/#{destination_app}/app/views"
17
+ destination_dir = (destination_portal == "main_app") ? "app/views/" : "packages/#{destination_portal}/app/views"
18
18
  [
19
19
  "plutonium/_resource_header.html.erb",
20
20
  "plutonium/_resource_sidebar.html.erb"
@@ -27,8 +27,8 @@ module Pu
27
27
 
28
28
  private
29
29
 
30
- def destination_app
31
- @destination_app || select_app(options[:dest], msg: "Select destination app")
30
+ def destination_portal
31
+ @destination_portal || select_portal(options[:dest], msg: "Select destination portal")
32
32
  end
33
33
 
34
34
  def copy_file(source_path, destination_path)
@@ -21,7 +21,7 @@ module Pu
21
21
 
22
22
  gitignore "!/.env.template", "!/.env.local.template", "!/.env"
23
23
 
24
- insert_into_file "Gemfile", "\ngem \"dotenv\", :groups => [:development, :test]\n", after: /^gem ["']rails["'].*\n/
24
+ insert_into_file "Gemfile", "\ngem \"dotenv\", groups: %i[development test]\n", after: /^gem ["']rails["'].*\n/
25
25
  bundle!
26
26
  end
27
27
  rescue => e
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../lib/plutonium_generators"
4
+
5
+ module Pu
6
+ module Gem
7
+ class LetterOpenerGenerator < Rails::Generators::Base
8
+ include PlutoniumGenerators::Generator
9
+
10
+ desc "Set up letter_opener"
11
+
12
+ def start
13
+ bundle "letter_opener", group: :development
14
+ environment "config.action_mailer.delivery_method = :letter_opener", env: :development
15
+ environment "config.action_mailer.perform_deliveries = true", env: :development
16
+ rescue => e
17
+ exception "#{self.class} failed:", e
18
+ end
19
+ end
20
+ end
21
+ end
@@ -7,8 +7,6 @@ module Pu
7
7
  class RedisGenerator < Rails::Generators::Base
8
8
  include PlutoniumGenerators::Generator
9
9
 
10
- source_root File.expand_path("templates", __dir__)
11
-
12
10
  desc "Set up redis"
13
11
 
14
12
  def start
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../lib/plutonium_generators"
4
+
5
+ module Pu
6
+ module Gem
7
+ class StandardGenerator < Rails::Generators::Base
8
+ include PlutoniumGenerators::Generator
9
+
10
+ desc "Set up standardrb"
11
+
12
+ def start
13
+ bundle "standardrb"
14
+ rescue => e
15
+ exception "#{self.class} failed:", e
16
+ end
17
+ end
18
+ end
19
+ end
@@ -52,7 +52,7 @@ module PlutoniumGenerators
52
52
  end
53
53
  end
54
54
 
55
- def select_app(selected_package = nil, msg: "Select app")
55
+ def select_portal(selected_package = nil, msg: "Select portal")
56
56
  select_package(selected_package, msg: msg, pkgs: available_apps)
57
57
  end
58
58
 
@@ -22,7 +22,7 @@ module Pu
22
22
  error "No resources found" if available_resources.blank?
23
23
  selected_resources = prompt.multi_select("Select resources", available_resources)
24
24
 
25
- @app_namespace = select_app.camelize
25
+ @app_namespace = select_portal.camelize
26
26
 
27
27
  selected_resources.each do |resource|
28
28
  @resource_class = resource
@@ -14,8 +14,12 @@ module Plutonium
14
14
  end
15
15
  end
16
16
 
17
- def action(name, **)
18
- instance_defined_actions[name] = Plutonium::Action::Simple.new(name, **)
17
+ def action(name, interaction: nil, **)
18
+ instance_defined_actions[name] = if interaction
19
+ Plutonium::Action::Interactive::Factory.create(name, interaction:, **)
20
+ else
21
+ Plutonium::Action::Simple.new(name, **)
22
+ end
19
23
  end
20
24
 
21
25
  def defined_actions
@@ -29,6 +29,7 @@ module Plutonium
29
29
  include Actions
30
30
  include Sorting
31
31
  include Search
32
+ include NestedInputs
32
33
 
33
34
  class IndexPage < Plutonium::UI::Page::Index; end
34
35
 
@@ -0,0 +1,19 @@
1
+ module Plutonium
2
+ module Definition
3
+ module NestedInputs
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ defineable_prop :nested_input
8
+
9
+ # def self.nested_input(name, with: nil, **)
10
+ # defined_nested_inputs[name] = {}
11
+ # end
12
+
13
+ # def nested_input(name, with: nil, **)
14
+ # instance_defined_nested_inputs[name] = {}
15
+ # end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -59,7 +59,7 @@ module Plutonium
59
59
  # Returns the submitted resource parameters
60
60
  # @return [Hash] The submitted resource parameters
61
61
  def submitted_resource_params
62
- @submitted_resource_params ||= build_form(resource_class.new).extract_input(params)[resource_param_key.to_sym]
62
+ @submitted_resource_params ||= build_form(resource_class.new).extract_input(params, view_context:)[resource_param_key.to_sym]
63
63
  end
64
64
 
65
65
  # Returns the resource parameters, including scoped and parent parameters
@@ -232,7 +232,7 @@ module Plutonium
232
232
  @submitted_interaction_params ||= current_interactive_action
233
233
  .interaction
234
234
  .build_form(nil)
235
- .extract_input(params)[:interaction]
235
+ .extract_input(params, view_context:)[:interaction]
236
236
  end
237
237
 
238
238
  def redirect_url_after_action_on(resource_record_or_resource_class)
@@ -5,7 +5,7 @@ module Plutonium
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- helper_method :presentable_attributes, :present_associations?
8
+ helper_method :presentable_attributes
9
9
  helper_method :build_form, :build_detail, :build_collection
10
10
  end
11
11
 
@@ -31,10 +31,6 @@ module Plutonium
31
31
  def build_form(record = resource_record)
32
32
  current_definition.form_class.new(record, resource_fields: presentable_attributes, resource_definition: current_definition)
33
33
  end
34
-
35
- def present_associations?
36
- current_parent.nil?
37
- end
38
34
  end
39
35
  end
40
36
  end
@@ -0,0 +1,13 @@
1
+ module Plutonium
2
+ module UI
3
+ class Block < Plutonium::UI::Component::Base
4
+ def view_template(&)
5
+ raise ArgumentError, "Block requires a content block" unless block_given?
6
+
7
+ div class: "relative bg-white dark:bg-gray-800 shadow-md sm:rounded-lg my-3" do
8
+ yield
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -10,6 +10,16 @@ module Plutonium
10
10
 
11
11
  def Breadcrumbs(...) = render Plutonium::UI::Breadcrumbs.new(...)
12
12
 
13
+ def SkeletonTable(...) = render Plutonium::UI::SkeletonTable.new(...)
14
+
15
+ def Block(...) = render Plutonium::UI::Block.new(...)
16
+
17
+ def Panel(...) = render Plutonium::UI::Panel.new(...)
18
+
19
+ def FrameNavigatorPanel(...) = render Plutonium::UI::FrameNavigatorPanel.new(...)
20
+
21
+ def DynaFrameHost(...) = render Plutonium::UI::DynaFrame::Host.new(...)
22
+
13
23
  def DynaFrameContent(...) = render Plutonium::UI::DynaFrame::Content.new(...)
14
24
 
15
25
  def PageHeader(...) = render Plutonium::UI::PageHeader.new(...)
@@ -21,19 +21,37 @@ module Plutonium
21
21
  private
22
22
 
23
23
  def render_fields
24
- fields_wrapper {
25
- resource_fields.each { |name|
26
- render_resource_field name
27
- }
28
- }
24
+ Block do
25
+ fields_wrapper do
26
+ resource_fields.each do |name|
27
+ render_resource_field name
28
+ end
29
+ end
30
+ end
29
31
  end
30
32
 
31
33
  def render_associations
32
- nil
33
- # TODO
34
- # resource_associations.each do |name, renderer|
35
- # # <%= render renderer.with(record: details.record) %>
36
- # end
34
+ resource_associations.each do |name|
35
+ reflection = object.class.reflect_on_association name
36
+
37
+ if !reflection
38
+ raise ArgumentError,
39
+ "unknown association #{object.class}##{name} defined in #permitted_associations"
40
+ elsif !registered_resources.include?(reflection.klass)
41
+ raise ArgumentError,
42
+ "#{object.class}##{name} defined in #permitted_associations, but #{reflection.klass} is not a registered resource"
43
+ end
44
+
45
+ title = object.class.human_attribute_name(name)
46
+ src = case reflection.macro
47
+ when :belongs_to
48
+ associated = object.public_send name
49
+ resource_url_for(associated, parent: nil) if associated
50
+ when :has_many
51
+ resource_url_for(reflection.klass, parent: object)
52
+ end
53
+ FrameNavigatorPanel(title:, src:) if src
54
+ end
37
55
  end
38
56
 
39
57
  def render_resource_field(name)
@@ -73,7 +91,7 @@ module Plutonium
73
91
  end
74
92
 
75
93
  def present_associations?
76
- current_parent.nil?
94
+ current_turbo_frame.nil?
77
95
  end
78
96
  end
79
97
  end
@@ -6,7 +6,7 @@ module Plutonium
6
6
  class Theme < Phlexi::Display::Theme
7
7
  def self.theme
8
8
  super.merge({
9
- base: "relative bg-white dark:bg-gray-800 shadow-md sm:rounded-lg my-3",
9
+ base: "",
10
10
  value_wrapper: "max-h-[300px] overflow-y-auto",
11
11
  fields_wrapper: "p-6 grid grid-cols-1 md:grid-cols-2 2xl:grid-cols-4 gap-6 gap-y-10 grid-flow-row-dense",
12
12
  label: "text-base font-bold text-gray-500 dark:text-gray-400 mb-1",
@@ -6,10 +6,10 @@ module Plutonium
6
6
 
7
7
  def view_template
8
8
  if current_turbo_frame.present?
9
- render turbo_frame_tag(current_turbo_frame) {
9
+ turbo_frame_tag(current_turbo_frame) do
10
10
  render "flash"
11
11
  yield
12
- }
12
+ end
13
13
  else
14
14
  yield
15
15
  end
@@ -0,0 +1,20 @@
1
+ module Plutonium
2
+ module UI
3
+ module DynaFrame
4
+ class Host < Plutonium::UI::Component::Base
5
+ include Phlex::Rails::Helpers::TurboFrameTag
6
+
7
+ def initialize(src:, loading:, id: SecureRandom.hex, **attributes)
8
+ @id = id
9
+ @src = src
10
+ @loading = loading
11
+ @attributes = attributes
12
+ end
13
+
14
+ def view_template(&)
15
+ turbo_frame_tag(@id, src: @src, loading: @loading, **@attributes, &)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end