plutonium 0.43.2 → 0.44.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/Rakefile +24 -6
  4. data/app/assets/plutonium.css +1 -1
  5. data/config/initializers/pagy.rb +1 -4
  6. data/gemfiles/rails_7.gemfile.lock +10 -5
  7. data/gemfiles/rails_8.0.gemfile.lock +9 -5
  8. data/gemfiles/rails_8.1.gemfile.lock +9 -5
  9. data/lib/generators/pu/invites/install_generator.rb +69 -11
  10. data/lib/generators/pu/invites/templates/INSTRUCTIONS +4 -1
  11. data/lib/generators/pu/invites/templates/app/interactions/invite_user_interaction.rb.tt +1 -1
  12. data/lib/generators/pu/invites/templates/app/interactions/user_invite_user_interaction.rb.tt +1 -1
  13. data/lib/generators/pu/invites/templates/packages/invites/app/controllers/invites/user_invitations_controller.rb.tt +5 -1
  14. data/lib/generators/pu/invites/templates/packages/invites/app/controllers/invites/welcome_controller.rb.tt +14 -24
  15. data/lib/generators/pu/invites/templates/packages/invites/app/mailers/invites/user_invite_mailer.rb.tt +2 -0
  16. data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/show.html.erb.tt +3 -2
  17. data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/welcome/pending_invitation.html.erb.tt +3 -2
  18. data/lib/generators/pu/lib/plutonium_generators/concerns/logger.rb +2 -0
  19. data/lib/generators/pu/lib/plutonium_generators/concerns/package_selector.rb +4 -6
  20. data/lib/generators/pu/lib/plutonium_generators/concerns/rodauth_redirects.rb +41 -0
  21. data/lib/generators/pu/lib/plutonium_generators/generator.rb +5 -1
  22. data/lib/generators/pu/lib/plutonium_generators/non_interactive_prompt.rb +27 -0
  23. data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +4 -0
  24. data/lib/generators/pu/saas/entity_generator.rb +16 -0
  25. data/lib/generators/pu/saas/membership_generator.rb +4 -3
  26. data/lib/generators/pu/saas/portal/USAGE +15 -0
  27. data/lib/generators/pu/saas/portal_generator.rb +122 -0
  28. data/lib/generators/pu/saas/setup/USAGE +17 -22
  29. data/lib/generators/pu/saas/setup_generator.rb +62 -9
  30. data/lib/generators/pu/saas/welcome/USAGE +27 -0
  31. data/lib/generators/pu/saas/welcome/templates/app/controllers/authenticated_controller.rb.tt +18 -0
  32. data/lib/generators/pu/saas/welcome/templates/app/controllers/welcome_controller.rb.tt +69 -0
  33. data/lib/generators/pu/saas/welcome/templates/app/views/layouts/welcome.html.erb.tt +33 -0
  34. data/lib/generators/pu/saas/welcome/templates/app/views/welcome/onboarding.html.erb.tt +51 -0
  35. data/lib/generators/pu/saas/welcome/templates/app/views/welcome/select_entity.html.erb.tt +22 -0
  36. data/lib/generators/pu/saas/welcome_generator.rb +197 -0
  37. data/lib/plutonium/auth/sequel_adapter.rb +1 -2
  38. data/lib/plutonium/core/controller.rb +18 -8
  39. data/lib/plutonium/core/controllers/association_resolver.rb +19 -6
  40. data/lib/plutonium/invites/concerns/cancel_invite.rb +3 -1
  41. data/lib/plutonium/invites/concerns/invite_user.rb +1 -1
  42. data/lib/plutonium/railtie.rb +1 -1
  43. data/lib/plutonium/resource/controller.rb +2 -3
  44. data/lib/plutonium/resource/controllers/crud_actions/index_action.rb +1 -1
  45. data/lib/plutonium/resource/controllers/presentable.rb +2 -0
  46. data/lib/plutonium/ui/form/components/resource_select.rb +1 -1
  47. data/lib/plutonium/ui/form/components/secure_association.rb +2 -2
  48. data/lib/plutonium/ui/form/components/secure_polymorphic_association.rb +6 -11
  49. data/lib/plutonium/ui/table/components/pagy_info.rb +1 -7
  50. data/lib/plutonium/ui/table/components/pagy_pagination.rb +4 -6
  51. data/lib/plutonium/version.rb +1 -1
  52. data/package.json +1 -1
  53. data/plutonium.gemspec +2 -2
  54. metadata +18 -10
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+ require_relative "../lib/plutonium_generators"
5
+
6
+ module Pu
7
+ module Saas
8
+ class WelcomeGenerator < ::Rails::Generators::Base
9
+ include PlutoniumGenerators::Generator
10
+ include PlutoniumGenerators::Concerns::RodauthRedirects
11
+
12
+ source_root File.expand_path("welcome/templates", __dir__)
13
+
14
+ desc "Generate a post-login welcome flow with onboarding and entity selection"
15
+
16
+ class_option :user_model, type: :string, required: true,
17
+ desc: "The user model name (e.g., User)"
18
+
19
+ class_option :entity_model, type: :string, required: true,
20
+ desc: "The entity model name (e.g., Organization)"
21
+
22
+ class_option :portal, type: :string, required: true,
23
+ desc: "The portal engine name (e.g., CustomerPortal)"
24
+
25
+ class_option :membership_model, type: :string,
26
+ desc: "The membership model name (defaults to <Entity><User>)"
27
+
28
+ class_option :rodauth, type: :string, default: "user",
29
+ desc: "Rodauth configuration name"
30
+
31
+ class_option :profile, type: :boolean, default: false,
32
+ desc: "Include profile setup in onboarding"
33
+
34
+ def start
35
+ validate_requirements
36
+ create_authenticated_controller
37
+ create_welcome_controller
38
+ create_views
39
+ add_routes
40
+ configure_rodauth
41
+ show_instructions
42
+ rescue => e
43
+ exception "#{self.class} failed:", e
44
+ end
45
+
46
+ private
47
+
48
+ def validate_requirements
49
+ errors = []
50
+
51
+ unless File.exist?(user_model_path)
52
+ errors << "User model not found: #{user_model_path.relative_path_from(Rails.root)}"
53
+ end
54
+
55
+ unless File.exist?(entity_model_path)
56
+ errors << "Entity model not found: #{entity_model_path.relative_path_from(Rails.root)}"
57
+ end
58
+
59
+ if File.exist?(user_model_path)
60
+ user_content = File.read(user_model_path)
61
+ unless user_content.include?("has_many :#{entity_table.pluralize}")
62
+ errors << "User model missing 'has_many :#{entity_table.pluralize}' — run the membership generator first"
63
+ end
64
+ end
65
+
66
+ if errors.any?
67
+ errors.each { |e| say_status :error, e, :red }
68
+ raise Thor::Error, "Required files missing:\n - #{errors.join("\n - ")}"
69
+ end
70
+ end
71
+
72
+ def create_authenticated_controller
73
+ template "app/controllers/authenticated_controller.rb",
74
+ "app/controllers/authenticated_controller.rb"
75
+ end
76
+
77
+ def create_welcome_controller
78
+ template "app/controllers/welcome_controller.rb",
79
+ "app/controllers/welcome_controller.rb"
80
+ end
81
+
82
+ def create_views
83
+ template "app/views/layouts/welcome.html.erb",
84
+ "app/views/layouts/welcome.html.erb"
85
+
86
+ template "app/views/welcome/select_entity.html.erb",
87
+ "app/views/welcome/select_entity.html.erb"
88
+
89
+ template "app/views/welcome/onboarding.html.erb",
90
+ "app/views/welcome/onboarding.html.erb"
91
+ end
92
+
93
+ def add_routes
94
+ routes_file = "config/routes.rb"
95
+ routes_content = File.read(Rails.root.join(routes_file))
96
+
97
+ if routes_content.include?("# Welcome & onboarding")
98
+ say_status :skip, "Welcome routes already present", :yellow
99
+ return
100
+ end
101
+
102
+ route_code = <<-RUBY
103
+
104
+ # Welcome & onboarding
105
+ get "welcome", to: "welcome#index"
106
+ get "welcome/onboard", to: "welcome#new_entity", as: :welcome_onboard
107
+ post "welcome/onboard", to: "welcome#onboard"
108
+ RUBY
109
+
110
+ # Remove the standalone invites welcome route if it exists,
111
+ # since the main WelcomeController now handles /welcome
112
+ if routes_content.include?('get "welcome", to: "invites/welcome#index"')
113
+ gsub_file routes_file,
114
+ /\n\s*# Welcome route \(handled by invites.*\n\s*get "welcome", to: "invites\/welcome#index"\n/,
115
+ "\n"
116
+ end
117
+
118
+ inject_into_file routes_file,
119
+ route_code,
120
+ before: /^end\s*\z/
121
+ end
122
+
123
+ def configure_rodauth
124
+ return unless rodauth?
125
+
126
+ update_rodauth_redirects("app/rodauth/#{rodauth_config}_rodauth_plugin.rb")
127
+ end
128
+
129
+ def show_instructions
130
+ say "\n"
131
+ say "=" * 79
132
+ say "\n"
133
+ say "Welcome flow installed successfully!"
134
+ say "\n"
135
+ say "Next steps:"
136
+ say "\n"
137
+ say "1. Run migrations (if you haven't already):"
138
+ say " rails db:migrate"
139
+ say "\n"
140
+ say "2. Customize the onboarding view to match your app:"
141
+ say " app/views/welcome/onboarding.html.erb"
142
+ say "\n"
143
+ if profile?
144
+ say "3. Ensure your User model has a `profile` association:"
145
+ say " has_one :profile"
146
+ say "\n"
147
+ end
148
+ say "=" * 79
149
+ say "\n"
150
+ end
151
+
152
+ def user_model
153
+ options[:user_model].camelize
154
+ end
155
+
156
+ def user_table
157
+ options[:user_model].underscore
158
+ end
159
+
160
+ def entity_model
161
+ options[:entity_model].camelize
162
+ end
163
+
164
+ def entity_table
165
+ options[:entity_model].underscore
166
+ end
167
+
168
+ def portal_engine
169
+ options[:portal].camelize
170
+ end
171
+
172
+ def membership_model
173
+ options[:membership_model] || "#{entity_model}#{user_model}"
174
+ end
175
+
176
+ def rodauth_config
177
+ options[:rodauth]
178
+ end
179
+
180
+ def rodauth?
181
+ rodauth_config.present?
182
+ end
183
+
184
+ def profile?
185
+ options[:profile]
186
+ end
187
+
188
+ def entity_model_path
189
+ Rails.root.join("app/models/#{entity_table}.rb")
190
+ end
191
+
192
+ def user_model_path
193
+ Rails.root.join("app/models/#{user_table}.rb")
194
+ end
195
+ end
196
+ end
197
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "sequel/core"
4
-
5
3
  module Plutonium
6
4
  module Auth
7
5
  # Provides runtime detection of the database adapter for Sequel configuration.
@@ -26,6 +24,7 @@ module Plutonium
26
24
  # @return [Sequel::Database] configured Sequel database connection
27
25
  # @raise [RuntimeError] if the Sequel adapter initialization fails
28
26
  def db
27
+ require "sequel/core"
29
28
  adapter = sequel_adapter
30
29
  begin
31
30
  if RUBY_ENGINE == "jruby"
@@ -145,7 +145,10 @@ module Plutonium
145
145
  end
146
146
 
147
147
  # Build the named helper: e.g., "blogging_post_nested_post_metadata_path"
148
- parent_singular = parent.model_name.singular
148
+ # For plural parent resources (resources :posts), nested routes use the singular member name (post_nested_...)
149
+ # For singular parent resources (resource :entities), nested routes use the route name as-is (entities_nested_...)
150
+ parent_is_singular_route = current_engine.routes.singular_resource_route?(parent.model_name.plural)
151
+ parent_prefix = parent_is_singular_route ? parent.model_name.plural : parent.model_name.singular
149
152
  nested_resource_name = "#{prefix}#{association_name}"
150
153
 
151
154
  # Determine if this is a collection action (no specific record)
@@ -158,12 +161,10 @@ module Plutonium
158
161
  # - :new action uses singular (new_blogging_post_nested_comment)
159
162
  # - member actions (show/edit/update/destroy) use singular (blogging_post_nested_comment)
160
163
  is_collection_action = action == :index || action == :create || (no_record && action != :new)
161
- helper_base = if is_singular
162
- "#{parent_singular}_#{nested_resource_name}"
163
- elsif is_collection_action
164
- "#{parent_singular}_#{nested_resource_name}"
164
+ helper_base = if is_singular || is_collection_action
165
+ "#{parent_prefix}_#{nested_resource_name}"
165
166
  else
166
- "#{parent_singular}_#{nested_resource_name.to_s.singularize}"
167
+ "#{parent_prefix}_#{nested_resource_name.to_s.singularize}"
167
168
  end
168
169
 
169
170
  # Only add helper prefix for actions that have named route helpers (new, edit)
@@ -173,10 +174,19 @@ module Plutonium
173
174
  else "#{action}_"
174
175
  end
175
176
 
176
- helper_name = :"#{helper_suffix}#{helper_base}_path"
177
+ # Add entity scope prefix for path-based entity scoping
178
+ entity_prefix = if scoped_to_entity? && scoped_entity_strategy == :path
179
+ "#{scoped_entity_param_key}_"
180
+ end
181
+
182
+ helper_name = :"#{helper_suffix}#{entity_prefix}#{helper_base}_path"
177
183
 
178
184
  # Build the arguments for the helper
179
- helper_args = [parent.to_param]
185
+ helper_args = []
186
+ # Add entity scope param for path-based entity scoping
187
+ helper_args << current_scoped_entity.to_param if entity_prefix
188
+ # Singular parent resources (resource :entity) have no :id param in the route
189
+ helper_args << parent.to_param unless parent_is_singular_route
180
190
  # Include element ID for plural routes (has_many) when we have a record instance
181
191
  # Skip ID for collection actions (:index, :create) which don't need a member ID
182
192
  unless is_singular || no_record || is_collection_action
@@ -61,21 +61,34 @@ module Plutonium
61
61
  #
62
62
  # For Blogging::Comment, returns [:blogging_comments, :comments]
63
63
  # For Comment, returns [:comments]
64
+ # For Blogging::PostDetail, returns [:blogging_post_details, :post_details, :blogging_post_detail, :post_detail]
65
+ #
66
+ # Tries both plural (has_many) and singular (has_one) forms.
64
67
  #
65
68
  # @param klass [Class] The target class
66
69
  # @return [Array<Symbol>] Candidate association names in priority order
67
70
  def association_candidates_for(klass)
68
71
  candidates = []
69
72
 
70
- # Full namespaced name: Blogging::Comment => :blogging_comments
71
- full_name = klass.model_name.plural.to_sym
72
- candidates << full_name
73
+ # Full namespaced name (plural): Blogging::Comment => :blogging_comments
74
+ full_plural = klass.model_name.plural.to_sym
75
+ candidates << full_plural
73
76
 
74
- # Demodulized name: Blogging::Comment => :comments
77
+ # Demodulized name (plural): Blogging::Comment => :comments
75
78
  demodulized = klass.name.demodulize
76
79
  if demodulized != klass.name
77
- short_name = demodulized.underscore.pluralize.to_sym
78
- candidates << short_name unless candidates.include?(short_name)
80
+ short_plural = demodulized.underscore.pluralize.to_sym
81
+ candidates << short_plural unless candidates.include?(short_plural)
82
+ end
83
+
84
+ # Full namespaced name (singular): Blogging::PostDetail => :blogging_post_detail
85
+ full_singular = klass.model_name.singular.to_sym
86
+ candidates << full_singular unless candidates.include?(full_singular)
87
+
88
+ # Demodulized name (singular): Blogging::PostDetail => :post_detail
89
+ if demodulized != klass.name
90
+ short_singular = demodulized.underscore.to_sym
91
+ candidates << short_singular unless candidates.include?(short_singular)
79
92
  end
80
93
 
81
94
  candidates
@@ -17,7 +17,9 @@ module Plutonium
17
17
  extend ActiveSupport::Concern
18
18
 
19
19
  included do
20
- presents label: "Cancel Invitation", icon: "outline/x-circle"
20
+ presents label: "Cancel Invitation", icon: Phlex::TablerIcons::CircleX
21
+
22
+ attribute :resource
21
23
  end
22
24
 
23
25
  def execute
@@ -57,7 +57,7 @@ module Plutonium
57
57
  # Override to specify the invite model class
58
58
  # @return [Class]
59
59
  def invite_class
60
- Invites::UserInvite
60
+ ::Invites::UserInvite
61
61
  end
62
62
 
63
63
  # Override to specify the membership model class
@@ -23,7 +23,7 @@ module Plutonium
23
23
  Rails.application.class.include Plutonium::Engine
24
24
  end
25
25
 
26
- initializer "plutonium.rescue_responses" do |app|
26
+ initializer "plutonium.rescue_responses", before: "action_dispatch.configure" do |app|
27
27
  app.config.action_dispatch.rescue_responses["ActionPolicy::Unauthorized"] = :forbidden
28
28
  end
29
29
 
@@ -7,7 +7,7 @@ module Plutonium
7
7
  # Controller module to handle resource actions and concerns
8
8
  module Controller
9
9
  extend ActiveSupport::Concern
10
- include Pagy::Backend
10
+ include Pagy::Method
11
11
  include Plutonium::Core::Controller
12
12
  include Plutonium::Resource::Controllers::Defineable
13
13
  include Plutonium::Resource::Controllers::Authorizable
@@ -17,8 +17,7 @@ module Plutonium
17
17
  include Plutonium::Resource::Controllers::InteractiveActions
18
18
 
19
19
  included do
20
- # https://github.com/ddnexus/pagy/blob/master/docs/extras/headers.md#headers
21
- after_action { pagy_headers_merge(@pagy) if @pagy }
20
+ after_action { response.headers.merge!(@pagy.headers_hash) if @pagy }
22
21
 
23
22
  helper_method :current_parent, :current_nested_association, :resource_record!, :resource_record?, :resource_param_key, :resource_class
24
23
 
@@ -8,7 +8,7 @@ module Plutonium
8
8
  private
9
9
 
10
10
  def setup_index_action!
11
- @pagy, @resource_records = pagy filtered_resource_collection
11
+ @pagy, @resource_records = pagy(:offset, filtered_resource_collection)
12
12
  end
13
13
 
14
14
  def filtered_resource_collection
@@ -59,6 +59,8 @@ module Plutonium
59
59
  return @scoped_entity_association if defined?(@scoped_entity_association)
60
60
 
61
61
  matching_assocs = resource_class.reflect_on_all_associations(:belongs_to).select do |assoc|
62
+ next false if assoc.polymorphic?
63
+
62
64
  assoc.klass.name == scoped_entity_class.name
63
65
  rescue NameError
64
66
  false
@@ -10,7 +10,7 @@ module Plutonium
10
10
 
11
11
  def choices
12
12
  @choices ||= begin
13
- collection = attributes.delete(:choices) || @association_class&.all || []
13
+ collection = @raw_choices || @association_class&.all || []
14
14
  build_choice_mapper(collection)
15
15
  end
16
16
  end
@@ -44,8 +44,8 @@ module Plutonium
44
44
 
45
45
  def choices
46
46
  @choices ||= begin
47
- collection = if (user_choices = attributes.delete(:choices))
48
- user_choices
47
+ collection = if @raw_choices
48
+ @raw_choices
49
49
  elsif @skip_authorization
50
50
  choices_from_association(association_reflection.klass)
51
51
  else
@@ -14,17 +14,12 @@ module Plutonium
14
14
 
15
15
  def choices
16
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
17
+ collection = @raw_choices || associated_classes.map { |klass|
18
+ [
19
+ klass.model_name.human.pluralize,
20
+ @skip_authorization ? choices_from_association(klass) : authorized_resource_scope(klass, relation: choices_from_association(klass))
21
+ ]
22
+ }.to_h
28
23
  build_choice_mapper(collection)
29
24
  end
30
25
  end
@@ -5,8 +5,6 @@ module Plutonium
5
5
  module Table
6
6
  module Components
7
7
  class PagyInfo < Plutonium::UI::Component::Base
8
- include Pagy::Frontend
9
-
10
8
  def initialize(pagy, per_page_options: [5, 10, 20, 50, 100])
11
9
  @pagy = pagy
12
10
  @per_page_options = (per_page_options + [@pagy.limit]).uniq.sort
@@ -57,11 +55,7 @@ module Plutonium
57
55
  end
58
56
 
59
57
  def page_url(limit)
60
- original_limit = @pagy.vars[:limit]
61
- @pagy.vars[:limit] = limit
62
- pagy_url_for(@pagy, @pagy.page)
63
- ensure
64
- @pagy.vars[:limit] = original_limit
58
+ @pagy.page_url(@pagy.page, limit: limit, client_max_limit: limit)
65
59
  end
66
60
  end
67
61
  end
@@ -5,8 +5,6 @@ module Plutonium
5
5
  module Table
6
6
  module Components
7
7
  class PagyPagination < Plutonium::UI::Component::Base
8
- include Pagy::Frontend
9
-
10
8
  def initialize(pagy)
11
9
  @pagy = pagy
12
10
  end
@@ -25,8 +23,8 @@ module Plutonium
25
23
 
26
24
  def prev_link
27
25
  li do
28
- if @pagy.prev
29
- a(href: page_url(@pagy.prev), class: link_classes(true)) {
26
+ if @pagy.previous
27
+ a(href: page_url(@pagy.previous), class: link_classes(true)) {
30
28
  render Phlex::TablerIcons::ChevronLeft.new
31
29
  }
32
30
  else
@@ -52,7 +50,7 @@ module Plutonium
52
50
  end
53
51
 
54
52
  def page_links
55
- @pagy.series.each do |item|
53
+ @pagy.send(:series).each do |item|
56
54
  li do
57
55
  case item
58
56
  when Integer
@@ -101,7 +99,7 @@ module Plutonium
101
99
  end
102
100
 
103
101
  def page_url(page)
104
- pagy_url_for(@pagy, page)
102
+ @pagy.page_url(page)
105
103
  end
106
104
  end
107
105
  end
@@ -1,5 +1,5 @@
1
1
  module Plutonium
2
- VERSION = "0.43.2"
2
+ VERSION = "0.44.1"
3
3
  NEXT_MAJOR_VERSION = VERSION.split(".").tap { |v|
4
4
  v[1] = v[1].to_i + 1
5
5
  v[2] = 0
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radioactive-labs/plutonium",
3
- "version": "0.43.2",
3
+ "version": "0.44.1",
4
4
  "description": "Build production-ready Rails apps in minutes, not days. Convention-driven, fully customizable, AI-ready.",
5
5
  "type": "module",
6
6
  "main": "src/js/core.js",
data/plutonium.gemspec CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
35
35
  spec.add_dependency "zeitwerk"
36
36
  spec.add_dependency "rails", ">= 7.2"
37
37
  spec.add_dependency "listen", "~> 3.8"
38
- spec.add_dependency "pagy", "~> 9.0"
38
+ spec.add_dependency "pagy", "~> 43.0"
39
39
  spec.add_dependency "rabl", "~> 0.17.0" # TODO: what to do with RABL
40
40
  spec.add_dependency "semantic_range", "~> 3.0"
41
41
  spec.add_dependency "tty-prompt", "~> 0.23.1"
@@ -44,7 +44,7 @@ Gem::Specification.new do |spec|
44
44
  spec.add_dependency "phlex-rails"
45
45
  spec.add_dependency "phlex-tabler_icons"
46
46
  spec.add_dependency "phlexi-field", ">= 0.2.0"
47
- spec.add_dependency "phlexi-form", ">= 0.14.1"
47
+ spec.add_dependency "phlexi-form", ">= 0.14.2"
48
48
  spec.add_dependency "phlexi-table", ">= 0.2.0"
49
49
  spec.add_dependency "phlexi-display", ">= 0.2.0"
50
50
  spec.add_dependency "phlexi-menu", ">= 0.4.1"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plutonium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.43.2
4
+ version: 0.44.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Froelich
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-03-13 00:00:00.000000000 Z
10
+ date: 2026-03-30 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: zeitwerk
@@ -58,14 +57,14 @@ dependencies:
58
57
  requirements:
59
58
  - - "~>"
60
59
  - !ruby/object:Gem::Version
61
- version: '9.0'
60
+ version: '43.0'
62
61
  type: :runtime
63
62
  prerelease: false
64
63
  version_requirements: !ruby/object:Gem::Requirement
65
64
  requirements:
66
65
  - - "~>"
67
66
  - !ruby/object:Gem::Version
68
- version: '9.0'
67
+ version: '43.0'
69
68
  - !ruby/object:Gem::Dependency
70
69
  name: rabl
71
70
  requirement: !ruby/object:Gem::Requirement
@@ -184,14 +183,14 @@ dependencies:
184
183
  requirements:
185
184
  - - ">="
186
185
  - !ruby/object:Gem::Version
187
- version: 0.14.1
186
+ version: 0.14.2
188
187
  type: :runtime
189
188
  prerelease: false
190
189
  version_requirements: !ruby/object:Gem::Requirement
191
190
  requirements:
192
191
  - - ">="
193
192
  - !ruby/object:Gem::Version
194
- version: 0.14.1
193
+ version: 0.14.2
195
194
  - !ruby/object:Gem::Dependency
196
195
  name: phlexi-table
197
196
  requirement: !ruby/object:Gem::Requirement
@@ -690,10 +689,12 @@ files:
690
689
  - lib/generators/pu/lib/plutonium_generators/concerns/mounts_engines.rb
691
690
  - lib/generators/pu/lib/plutonium_generators/concerns/package_selector.rb
692
691
  - lib/generators/pu/lib/plutonium_generators/concerns/resource_selector.rb
692
+ - lib/generators/pu/lib/plutonium_generators/concerns/rodauth_redirects.rb
693
693
  - lib/generators/pu/lib/plutonium_generators/concerns/serializer.rb
694
694
  - lib/generators/pu/lib/plutonium_generators/generator.rb
695
695
  - lib/generators/pu/lib/plutonium_generators/installer.rb
696
696
  - lib/generators/pu/lib/plutonium_generators/model_generator_base.rb
697
+ - lib/generators/pu/lib/plutonium_generators/non_interactive_prompt.rb
697
698
  - lib/generators/pu/lite/litestream/litestream_generator.rb
698
699
  - lib/generators/pu/lite/rails_pulse/rails_pulse_generator.rb
699
700
  - lib/generators/pu/lite/rails_pulse/templates/config/initializers/rails_pulse.rb.tt
@@ -822,10 +823,19 @@ files:
822
823
  - lib/generators/pu/saas/entity_generator.rb
823
824
  - lib/generators/pu/saas/membership/USAGE
824
825
  - lib/generators/pu/saas/membership_generator.rb
826
+ - lib/generators/pu/saas/portal/USAGE
827
+ - lib/generators/pu/saas/portal_generator.rb
825
828
  - lib/generators/pu/saas/setup/USAGE
826
829
  - lib/generators/pu/saas/setup_generator.rb
827
830
  - lib/generators/pu/saas/user/USAGE
828
831
  - lib/generators/pu/saas/user_generator.rb
832
+ - lib/generators/pu/saas/welcome/USAGE
833
+ - lib/generators/pu/saas/welcome/templates/app/controllers/authenticated_controller.rb.tt
834
+ - lib/generators/pu/saas/welcome/templates/app/controllers/welcome_controller.rb.tt
835
+ - lib/generators/pu/saas/welcome/templates/app/views/layouts/welcome.html.erb.tt
836
+ - lib/generators/pu/saas/welcome/templates/app/views/welcome/onboarding.html.erb.tt
837
+ - lib/generators/pu/saas/welcome/templates/app/views/welcome/select_entity.html.erb.tt
838
+ - lib/generators/pu/saas/welcome_generator.rb
829
839
  - lib/generators/pu/service/postgres/postgres_generator.rb
830
840
  - lib/generators/pu/service/postgres/templates/.keep
831
841
  - lib/generators/pu/service/postgres/templates/bin/initdb.d/create-multiple-postgresql-databases.sh
@@ -1087,7 +1097,6 @@ metadata:
1087
1097
  allowed_push_host: https://rubygems.org
1088
1098
  homepage_uri: https://radioactive-labs.github.io/plutonium-core/
1089
1099
  source_code_uri: https://github.com/radioactive-labs/plutonium-core
1090
- post_install_message:
1091
1100
  rdoc_options: []
1092
1101
  require_paths:
1093
1102
  - lib
@@ -1102,8 +1111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1102
1111
  - !ruby/object:Gem::Version
1103
1112
  version: '0'
1104
1113
  requirements: []
1105
- rubygems_version: 3.4.10
1106
- signing_key:
1114
+ rubygems_version: 3.6.2
1107
1115
  specification_version: 4
1108
1116
  summary: Build production-ready Rails apps in minutes, not days
1109
1117
  test_files: []