plutonium 0.34.1 → 0.35.0
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/.claude/skills/plutonium/skill.md +53 -0
- data/.claude/skills/{assets → plutonium-assets}/SKILL.md +13 -8
- data/.claude/skills/{connect-resource → plutonium-connect-resource}/SKILL.md +1 -1
- data/.claude/skills/{controller → plutonium-controller}/SKILL.md +27 -13
- data/.claude/skills/{create-resource → plutonium-create-resource}/SKILL.md +1 -1
- data/.claude/skills/{definition → plutonium-definition}/SKILL.md +10 -10
- data/.claude/skills/{definition-actions → plutonium-definition-actions}/SKILL.md +34 -9
- data/.claude/skills/{definition-fields → plutonium-definition-fields}/SKILL.md +38 -10
- data/.claude/skills/plutonium-definition-query/SKILL.md +356 -0
- data/.claude/skills/{forms → plutonium-forms}/SKILL.md +6 -6
- data/.claude/skills/{installation → plutonium-installation}/SKILL.md +9 -9
- data/.claude/skills/{interaction → plutonium-interaction}/SKILL.md +20 -19
- data/.claude/skills/{model → plutonium-model}/SKILL.md +3 -3
- data/.claude/skills/{model-features → plutonium-model-features}/SKILL.md +3 -3
- data/.claude/skills/{nested-resources → plutonium-nested-resources}/SKILL.md +5 -5
- data/.claude/skills/{package → plutonium-package}/SKILL.md +7 -8
- data/.claude/skills/{policy → plutonium-policy}/SKILL.md +26 -4
- data/.claude/skills/{portal → plutonium-portal}/SKILL.md +33 -31
- data/.claude/skills/{resource → plutonium-resource}/SKILL.md +27 -27
- data/.claude/skills/{rodauth → plutonium-rodauth}/SKILL.md +5 -5
- data/.claude/skills/plutonium-theming/SKILL.md +424 -0
- data/.claude/skills/{views → plutonium-views}/SKILL.md +7 -7
- data/CHANGELOG.md +52 -0
- data/CLAUDE.md +215 -0
- data/CONTRIBUTING.md +72 -18
- data/README.md +100 -19
- data/app/assets/plutonium.css +1 -11
- data/app/assets/plutonium.js +1685 -1146
- data/app/assets/plutonium.js.map +4 -4
- data/app/assets/plutonium.min.js +70 -70
- data/app/assets/plutonium.min.js.map +4 -4
- data/app/views/resource/interactive_bulk_action.html.erb +1 -5
- data/app/views/rodauth/_email_auth_request_form.html.erb +1 -1
- data/app/views/rodauth/_login_form.html.erb +15 -55
- data/app/views/rodauth/_login_form_footer.html.erb +2 -2
- data/app/views/rodauth/_password_visibility.html.erb +2 -8
- data/app/views/rodauth/add_recovery_codes.html.erb +2 -2
- data/app/views/rodauth/change_login.html.erb +36 -19
- data/app/views/rodauth/change_password.html.erb +34 -10
- data/app/views/rodauth/close_account.html.erb +12 -4
- data/app/views/rodauth/confirm_password.html.erb +19 -17
- data/app/views/rodauth/create_account.html.erb +30 -109
- data/app/views/rodauth/email_auth.html.erb +1 -1
- data/app/views/rodauth/logout.html.erb +4 -4
- data/app/views/rodauth/otp_auth.html.erb +13 -4
- data/app/views/rodauth/otp_disable.html.erb +12 -4
- data/app/views/rodauth/otp_setup.html.erb +29 -12
- data/app/views/rodauth/otp_unlock.html.erb +19 -10
- data/app/views/rodauth/otp_unlock_not_available.html.erb +7 -7
- data/app/views/rodauth/recovery_auth.html.erb +12 -4
- data/app/views/rodauth/recovery_codes.html.erb +12 -4
- data/app/views/rodauth/remember.html.erb +7 -7
- data/app/views/rodauth/reset_password.html.erb +23 -7
- data/app/views/rodauth/reset_password_request.html.erb +14 -10
- data/app/views/rodauth/sms_auth.html.erb +13 -4
- data/app/views/rodauth/sms_confirm.html.erb +13 -4
- data/app/views/rodauth/sms_disable.html.erb +12 -4
- data/app/views/rodauth/sms_request.html.erb +1 -1
- data/app/views/rodauth/sms_setup.html.erb +23 -7
- data/app/views/rodauth/two_factor_auth.html.erb +2 -2
- data/app/views/rodauth/two_factor_disable.html.erb +12 -4
- data/app/views/rodauth/two_factor_manage.html.erb +7 -7
- data/app/views/rodauth/unlock_account.html.erb +13 -5
- data/app/views/rodauth/unlock_account_request.html.erb +2 -2
- data/app/views/rodauth/verify_account.html.erb +25 -7
- data/app/views/rodauth/verify_account_resend.html.erb +14 -10
- data/app/views/rodauth/verify_login_change.html.erb +1 -1
- data/app/views/rodauth/webauthn_auth.html.erb +1 -1
- data/app/views/rodauth/webauthn_remove.html.erb +18 -8
- data/app/views/rodauth/webauthn_setup.html.erb +12 -4
- data/docs/.vitepress/config.ts +15 -26
- data/docs/.vitepress/theme/custom.css +388 -29
- data/docs/getting-started/index.md +1 -1
- data/docs/getting-started/tutorial/02-first-resource.md +9 -0
- data/docs/getting-started/tutorial/06-nested-resources.md +2 -2
- data/docs/getting-started/tutorial/07-author-portal.md +191 -0
- data/docs/getting-started/tutorial/{07-customizing-ui.md → 08-customizing-ui.md} +7 -7
- data/docs/getting-started/tutorial/index.md +5 -2
- data/docs/guides/authorization.md +33 -0
- data/docs/guides/creating-packages.md +12 -16
- data/docs/guides/custom-actions.md +36 -0
- data/docs/guides/search-filtering.md +121 -42
- data/docs/guides/theming.md +232 -36
- data/docs/index.md +203 -57
- data/docs/public/og-image.png +0 -0
- data/docs/reference/controller/index.md +14 -16
- data/docs/reference/definition/actions.md +38 -3
- data/docs/reference/definition/fields.md +3 -3
- data/docs/reference/definition/index.md +2 -2
- data/docs/reference/generators/index.md +0 -1
- data/docs/reference/interaction/index.md +14 -10
- data/docs/reference/model/index.md +0 -1
- data/docs/reference/portal/index.md +13 -27
- data/gemfiles/rails_7.gemfile.lock +1 -1
- data/gemfiles/rails_8.0.gemfile.lock +1 -1
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/generators/pu/pkg/portal/portal_generator.rb +0 -2
- data/lib/generators/pu/pkg/portal/templates/app/views/package/dashboard/index.html.erb +28 -72
- data/lib/plutonium/action/interactive.rb +2 -2
- data/lib/plutonium/core/controller.rb +2 -1
- data/lib/plutonium/definition/actions.rb +2 -2
- data/lib/plutonium/lib/deep_freezer.rb +3 -7
- data/lib/plutonium/query/filter.rb +14 -0
- data/lib/plutonium/query/filters/association.rb +49 -0
- data/lib/plutonium/query/filters/boolean.rb +35 -0
- data/lib/plutonium/query/filters/date.rb +97 -0
- data/lib/plutonium/query/filters/date_range.rb +58 -0
- data/lib/plutonium/query/filters/select.rb +55 -0
- data/lib/plutonium/resource/controllers/crud_actions.rb +24 -6
- data/lib/plutonium/resource/controllers/interactive_actions.rb +76 -58
- data/lib/plutonium/resource/controllers/queryable.rb +4 -2
- data/lib/plutonium/resource/query_object.rb +1 -1
- data/lib/plutonium/ui/action_button.rb +23 -65
- data/lib/plutonium/ui/actions_dropdown.rb +103 -0
- data/lib/plutonium/ui/block.rb +1 -1
- data/lib/plutonium/ui/breadcrumbs.rb +12 -19
- data/lib/plutonium/ui/color_mode_selector.rb +1 -1
- data/lib/plutonium/ui/component/kit.rb +6 -0
- data/lib/plutonium/ui/component_classes.rb +102 -0
- data/lib/plutonium/ui/display/base.rb +15 -0
- data/lib/plutonium/ui/display/components/attachment.rb +6 -5
- data/lib/plutonium/ui/display/components/boolean.rb +23 -0
- data/lib/plutonium/ui/display/components/color.rb +23 -0
- data/lib/plutonium/ui/display/resource.rb +1 -1
- data/lib/plutonium/ui/display/theme.rb +29 -15
- data/lib/plutonium/ui/empty_card.rb +3 -3
- data/lib/plutonium/ui/form/base.rb +20 -0
- data/lib/plutonium/ui/form/components/key_value_store.rb +11 -11
- data/lib/plutonium/ui/form/components/resource_select.rb +31 -0
- data/lib/plutonium/ui/form/components/secure_association.rb +1 -2
- data/lib/plutonium/ui/form/components/uppy.rb +5 -4
- data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +4 -4
- data/lib/plutonium/ui/form/interaction.rb +17 -1
- data/lib/plutonium/ui/form/query.rb +133 -80
- data/lib/plutonium/ui/form/theme.rb +50 -35
- data/lib/plutonium/ui/frame_navigator_panel.rb +2 -2
- data/lib/plutonium/ui/layout/base.rb +1 -1
- data/lib/plutonium/ui/layout/header.rb +4 -7
- data/lib/plutonium/ui/layout/rodauth_layout.rb +7 -7
- data/lib/plutonium/ui/layout/sidebar.rb +1 -1
- data/lib/plutonium/ui/nav_grid_menu.rb +7 -6
- data/lib/plutonium/ui/nav_user.rb +9 -8
- data/lib/plutonium/ui/page/interactive_action.rb +5 -5
- data/lib/plutonium/ui/page_header.rb +29 -10
- data/lib/plutonium/ui/panel.rb +4 -4
- data/lib/plutonium/ui/sidebar_menu.rb +8 -8
- data/lib/plutonium/ui/skeleton_table.rb +7 -8
- data/lib/plutonium/ui/tab_list.rb +5 -5
- data/lib/plutonium/ui/table/base.rb +3 -0
- data/lib/plutonium/ui/table/components/attachment.rb +4 -3
- data/lib/plutonium/ui/table/components/bulk_actions_toolbar.rb +82 -0
- data/lib/plutonium/ui/table/components/pagy_info.rb +2 -2
- data/lib/plutonium/ui/table/components/pagy_pagination.rb +13 -8
- data/lib/plutonium/ui/table/components/row_actions_dropdown.rb +101 -0
- data/lib/plutonium/ui/table/components/scopes_bar.rb +2 -2
- data/lib/plutonium/ui/table/components/selection_column.rb +100 -0
- data/lib/plutonium/ui/table/display_theme.rb +6 -6
- data/lib/plutonium/ui/table/resource.rb +93 -52
- data/lib/plutonium/ui/table/theme.rb +28 -15
- data/lib/plutonium/version.rb +1 -1
- data/package.json +2 -2
- data/plutonium.gemspec +5 -4
- data/src/css/components.css +471 -0
- data/src/css/intl_tel_input.css +2 -2
- data/src/css/plutonium.css +2 -0
- data/src/css/tokens.css +149 -0
- data/src/js/controllers/bulk_actions_controller.js +109 -0
- data/src/js/controllers/filter_panel_controller.js +35 -0
- data/src/js/controllers/register_controllers.js +5 -1
- data/src/js/controllers/resource_drop_down_controller.js +25 -1
- data/src/js/controllers/slim_select_controller.js +6 -2
- data/src/js/turbo/turbo_actions.js +1 -1
- metadata +52 -39
- data/.claude/skills/definition-query/SKILL.md +0 -334
- data/docs/concepts/architecture.md +0 -226
- data/docs/concepts/auto-detection.md +0 -254
- data/docs/concepts/index.md +0 -61
- data/docs/concepts/packages-portals.md +0 -304
- data/docs/concepts/resources.md +0 -224
- data/docs/cookbook/blog.md +0 -411
- data/docs/cookbook/index.md +0 -289
- data/docs/cookbook/saas.md +0 -481
- data/docs/public/CLAUDE.md +0 -578
- data/lib/generators/pu/pkg/portal/templates/app/controllers/resource_controller.rb.tt +0 -5
data/docs/cookbook/index.md
DELETED
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
# Cookbook
|
|
2
|
-
|
|
3
|
-
Real-world recipes and patterns for building applications with Plutonium.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
These recipes show complete implementations of common application patterns. Each recipe includes:
|
|
8
|
-
- Architecture decisions
|
|
9
|
-
- Code examples
|
|
10
|
-
- Best practices
|
|
11
|
-
|
|
12
|
-
## Recipes
|
|
13
|
-
|
|
14
|
-
### [Blog Application](./blog)
|
|
15
|
-
A content management system with posts, comments, categories, and multi-user support.
|
|
16
|
-
|
|
17
|
-
### [SaaS Application](./saas)
|
|
18
|
-
Multi-tenant application with organizations, team management, and subscription handling.
|
|
19
|
-
|
|
20
|
-
## Quick Patterns
|
|
21
|
-
|
|
22
|
-
### Basic CRUD with Authorization
|
|
23
|
-
|
|
24
|
-
```ruby
|
|
25
|
-
# Model
|
|
26
|
-
class Article < ResourceRecord
|
|
27
|
-
belongs_to :author, class_name: 'User'
|
|
28
|
-
validates :title, :body, presence: true
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Definition
|
|
32
|
-
class ArticleDefinition < Plutonium::Resource::Definition
|
|
33
|
-
field :title
|
|
34
|
-
field :body, as: :rich_text
|
|
35
|
-
field :published, as: :switch
|
|
36
|
-
|
|
37
|
-
column :title, sortable: true
|
|
38
|
-
column :author
|
|
39
|
-
column :published
|
|
40
|
-
column :created_at, sortable: true
|
|
41
|
-
|
|
42
|
-
search { |scope, q| scope.where("title ILIKE ?", "%#{q}%") }
|
|
43
|
-
scope :all, default: true
|
|
44
|
-
scope :published, -> { where(published: true) }
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Policy
|
|
48
|
-
class ArticlePolicy < Plutonium::Resource::Policy
|
|
49
|
-
def update?
|
|
50
|
-
owner? || admin?
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def destroy?
|
|
54
|
-
owner? || admin?
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
private
|
|
58
|
-
|
|
59
|
-
def owner?
|
|
60
|
-
record.author_id == user.id
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Nested Resource Pattern
|
|
66
|
-
|
|
67
|
-
```ruby
|
|
68
|
-
# Parent
|
|
69
|
-
class Project < ResourceRecord
|
|
70
|
-
has_many :tasks, dependent: :destroy
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Child
|
|
74
|
-
class Task < ResourceRecord
|
|
75
|
-
belongs_to :project
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Parent policy enables association panel
|
|
79
|
-
class ProjectPolicy < Plutonium::Resource::Policy
|
|
80
|
-
def permitted_associations
|
|
81
|
-
%i[tasks]
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Custom Action Pattern
|
|
87
|
-
|
|
88
|
-
```ruby
|
|
89
|
-
# Interaction
|
|
90
|
-
class CompleteTask < Plutonium::Interaction::Base
|
|
91
|
-
presents model_class: Task
|
|
92
|
-
presents label: "Mark Complete"
|
|
93
|
-
|
|
94
|
-
attribute :completion_notes, :text
|
|
95
|
-
|
|
96
|
-
def execute
|
|
97
|
-
resource.update!(
|
|
98
|
-
completed: true,
|
|
99
|
-
completed_at: Time.current,
|
|
100
|
-
completion_notes: completion_notes
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
succeed(resource).with_message("Task completed!")
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# Register in definition
|
|
108
|
-
class TaskDefinition < Plutonium::Resource::Definition
|
|
109
|
-
action :complete,
|
|
110
|
-
interaction: CompleteTask,
|
|
111
|
-
condition: ->(task) { !task.completed? }
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# Authorize in policy
|
|
115
|
-
class TaskPolicy < Plutonium::Resource::Policy
|
|
116
|
-
def complete?
|
|
117
|
-
owner? && !record.completed?
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### Multi-Portal Pattern
|
|
123
|
-
|
|
124
|
-
```ruby
|
|
125
|
-
# Admin portal - full access
|
|
126
|
-
module AdminPortal
|
|
127
|
-
class TaskPolicy < ::TaskPolicy
|
|
128
|
-
def index?
|
|
129
|
-
true
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def destroy?
|
|
133
|
-
true
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def relation_scope(relation)
|
|
137
|
-
relation
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# User portal - limited access
|
|
143
|
-
module UserPortal
|
|
144
|
-
class TaskPolicy < ::TaskPolicy
|
|
145
|
-
def index?
|
|
146
|
-
true
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def destroy?
|
|
150
|
-
owner?
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def relation_scope(relation)
|
|
154
|
-
relation.where(user: user)
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## Architecture Patterns
|
|
161
|
-
|
|
162
|
-
### Feature Package Organization
|
|
163
|
-
|
|
164
|
-
```
|
|
165
|
-
packages/
|
|
166
|
-
├── core/ # Shared models (User, Organization)
|
|
167
|
-
├── projects/ # Project management feature
|
|
168
|
-
├── billing/ # Subscription & payments
|
|
169
|
-
├── notifications/ # Email & push notifications
|
|
170
|
-
├── admin_portal/ # Admin interface
|
|
171
|
-
└── customer_portal/ # Customer interface
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### Service Objects with Interactions
|
|
175
|
-
|
|
176
|
-
```ruby
|
|
177
|
-
# Complex operations go in Interactions
|
|
178
|
-
class CreateProjectWithTasks < Plutonium::Interaction::Base
|
|
179
|
-
presents model_class: Project
|
|
180
|
-
|
|
181
|
-
attribute :name, :string
|
|
182
|
-
attribute :tasks, :json # Array of task attributes
|
|
183
|
-
|
|
184
|
-
validates :name, presence: true
|
|
185
|
-
|
|
186
|
-
def execute
|
|
187
|
-
project = Project.create!(name: name, user: context[:user])
|
|
188
|
-
|
|
189
|
-
tasks.each do |task_attrs|
|
|
190
|
-
project.tasks.create!(task_attrs)
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
succeed(project).with_message("Project created with #{tasks.size} tasks")
|
|
194
|
-
rescue ActiveRecord::RecordInvalid => e
|
|
195
|
-
fail!(e.message)
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Event-Driven Updates
|
|
201
|
-
|
|
202
|
-
```ruby
|
|
203
|
-
class PublishArticle < Plutonium::Interaction::Base
|
|
204
|
-
presents model_class: Article
|
|
205
|
-
|
|
206
|
-
def execute
|
|
207
|
-
resource.update!(published: true, published_at: Time.current)
|
|
208
|
-
|
|
209
|
-
# Trigger downstream effects
|
|
210
|
-
ArticlePublishedJob.perform_later(resource.id)
|
|
211
|
-
NotifySubscribersJob.perform_later(resource.id)
|
|
212
|
-
UpdateSearchIndexJob.perform_later(resource.id)
|
|
213
|
-
|
|
214
|
-
succeed(resource)
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
## Common Customizations
|
|
220
|
-
|
|
221
|
-
### Custom Display Component
|
|
222
|
-
|
|
223
|
-
```ruby
|
|
224
|
-
class StatusBadge < Plutonium::UI::Component::Base
|
|
225
|
-
COLORS = {
|
|
226
|
-
'draft' => 'gray',
|
|
227
|
-
'pending' => 'yellow',
|
|
228
|
-
'approved' => 'green',
|
|
229
|
-
'rejected' => 'red'
|
|
230
|
-
}.freeze
|
|
231
|
-
|
|
232
|
-
def initialize(status:)
|
|
233
|
-
@status = status
|
|
234
|
-
@color = COLORS.fetch(status, 'gray')
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
def view_template
|
|
238
|
-
span(class: "px-2 py-1 text-xs rounded bg-#{@color}-100 text-#{@color}-800") do
|
|
239
|
-
@status.titleize
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
# Use in definition
|
|
245
|
-
column :status do |record|
|
|
246
|
-
render StatusBadge.new(status: record.status)
|
|
247
|
-
end
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### Custom Form Section
|
|
251
|
-
|
|
252
|
-
```ruby
|
|
253
|
-
class ProjectForm < Plutonium::UI::Form::Resource
|
|
254
|
-
def form_template
|
|
255
|
-
div(class: "space-y-8") do
|
|
256
|
-
section("Basic Information") do
|
|
257
|
-
render_field :name
|
|
258
|
-
render_field :description
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
section("Settings") do
|
|
262
|
-
render_field :visibility
|
|
263
|
-
render_field :notifications_enabled
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
section("Team") do
|
|
267
|
-
render_field :team_members, as: :nested
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
render_submit_button
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
private
|
|
275
|
-
|
|
276
|
-
def section(title, &block)
|
|
277
|
-
div(class: "bg-white rounded-lg shadow p-6") do
|
|
278
|
-
h3(class: "text-lg font-medium mb-4") { title }
|
|
279
|
-
yield
|
|
280
|
-
end
|
|
281
|
-
end
|
|
282
|
-
end
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
## Next Steps
|
|
286
|
-
|
|
287
|
-
- Explore the [Guides](/guides/) for detailed how-tos
|
|
288
|
-
- Check the [Reference](/reference/) for complete API documentation
|
|
289
|
-
- Visit our [GitHub](https://github.com/radioactive-labs/plutonium-core) for more examples
|