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.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/skills/plutonium/skill.md +53 -0
  3. data/.claude/skills/{assets → plutonium-assets}/SKILL.md +13 -8
  4. data/.claude/skills/{connect-resource → plutonium-connect-resource}/SKILL.md +1 -1
  5. data/.claude/skills/{controller → plutonium-controller}/SKILL.md +27 -13
  6. data/.claude/skills/{create-resource → plutonium-create-resource}/SKILL.md +1 -1
  7. data/.claude/skills/{definition → plutonium-definition}/SKILL.md +10 -10
  8. data/.claude/skills/{definition-actions → plutonium-definition-actions}/SKILL.md +34 -9
  9. data/.claude/skills/{definition-fields → plutonium-definition-fields}/SKILL.md +38 -10
  10. data/.claude/skills/plutonium-definition-query/SKILL.md +356 -0
  11. data/.claude/skills/{forms → plutonium-forms}/SKILL.md +6 -6
  12. data/.claude/skills/{installation → plutonium-installation}/SKILL.md +9 -9
  13. data/.claude/skills/{interaction → plutonium-interaction}/SKILL.md +20 -19
  14. data/.claude/skills/{model → plutonium-model}/SKILL.md +3 -3
  15. data/.claude/skills/{model-features → plutonium-model-features}/SKILL.md +3 -3
  16. data/.claude/skills/{nested-resources → plutonium-nested-resources}/SKILL.md +5 -5
  17. data/.claude/skills/{package → plutonium-package}/SKILL.md +7 -8
  18. data/.claude/skills/{policy → plutonium-policy}/SKILL.md +26 -4
  19. data/.claude/skills/{portal → plutonium-portal}/SKILL.md +33 -31
  20. data/.claude/skills/{resource → plutonium-resource}/SKILL.md +27 -27
  21. data/.claude/skills/{rodauth → plutonium-rodauth}/SKILL.md +5 -5
  22. data/.claude/skills/plutonium-theming/SKILL.md +424 -0
  23. data/.claude/skills/{views → plutonium-views}/SKILL.md +7 -7
  24. data/CHANGELOG.md +52 -0
  25. data/CLAUDE.md +215 -0
  26. data/CONTRIBUTING.md +72 -18
  27. data/README.md +100 -19
  28. data/app/assets/plutonium.css +1 -11
  29. data/app/assets/plutonium.js +1685 -1146
  30. data/app/assets/plutonium.js.map +4 -4
  31. data/app/assets/plutonium.min.js +70 -70
  32. data/app/assets/plutonium.min.js.map +4 -4
  33. data/app/views/resource/interactive_bulk_action.html.erb +1 -5
  34. data/app/views/rodauth/_email_auth_request_form.html.erb +1 -1
  35. data/app/views/rodauth/_login_form.html.erb +15 -55
  36. data/app/views/rodauth/_login_form_footer.html.erb +2 -2
  37. data/app/views/rodauth/_password_visibility.html.erb +2 -8
  38. data/app/views/rodauth/add_recovery_codes.html.erb +2 -2
  39. data/app/views/rodauth/change_login.html.erb +36 -19
  40. data/app/views/rodauth/change_password.html.erb +34 -10
  41. data/app/views/rodauth/close_account.html.erb +12 -4
  42. data/app/views/rodauth/confirm_password.html.erb +19 -17
  43. data/app/views/rodauth/create_account.html.erb +30 -109
  44. data/app/views/rodauth/email_auth.html.erb +1 -1
  45. data/app/views/rodauth/logout.html.erb +4 -4
  46. data/app/views/rodauth/otp_auth.html.erb +13 -4
  47. data/app/views/rodauth/otp_disable.html.erb +12 -4
  48. data/app/views/rodauth/otp_setup.html.erb +29 -12
  49. data/app/views/rodauth/otp_unlock.html.erb +19 -10
  50. data/app/views/rodauth/otp_unlock_not_available.html.erb +7 -7
  51. data/app/views/rodauth/recovery_auth.html.erb +12 -4
  52. data/app/views/rodauth/recovery_codes.html.erb +12 -4
  53. data/app/views/rodauth/remember.html.erb +7 -7
  54. data/app/views/rodauth/reset_password.html.erb +23 -7
  55. data/app/views/rodauth/reset_password_request.html.erb +14 -10
  56. data/app/views/rodauth/sms_auth.html.erb +13 -4
  57. data/app/views/rodauth/sms_confirm.html.erb +13 -4
  58. data/app/views/rodauth/sms_disable.html.erb +12 -4
  59. data/app/views/rodauth/sms_request.html.erb +1 -1
  60. data/app/views/rodauth/sms_setup.html.erb +23 -7
  61. data/app/views/rodauth/two_factor_auth.html.erb +2 -2
  62. data/app/views/rodauth/two_factor_disable.html.erb +12 -4
  63. data/app/views/rodauth/two_factor_manage.html.erb +7 -7
  64. data/app/views/rodauth/unlock_account.html.erb +13 -5
  65. data/app/views/rodauth/unlock_account_request.html.erb +2 -2
  66. data/app/views/rodauth/verify_account.html.erb +25 -7
  67. data/app/views/rodauth/verify_account_resend.html.erb +14 -10
  68. data/app/views/rodauth/verify_login_change.html.erb +1 -1
  69. data/app/views/rodauth/webauthn_auth.html.erb +1 -1
  70. data/app/views/rodauth/webauthn_remove.html.erb +18 -8
  71. data/app/views/rodauth/webauthn_setup.html.erb +12 -4
  72. data/docs/.vitepress/config.ts +15 -26
  73. data/docs/.vitepress/theme/custom.css +388 -29
  74. data/docs/getting-started/index.md +1 -1
  75. data/docs/getting-started/tutorial/02-first-resource.md +9 -0
  76. data/docs/getting-started/tutorial/06-nested-resources.md +2 -2
  77. data/docs/getting-started/tutorial/07-author-portal.md +191 -0
  78. data/docs/getting-started/tutorial/{07-customizing-ui.md → 08-customizing-ui.md} +7 -7
  79. data/docs/getting-started/tutorial/index.md +5 -2
  80. data/docs/guides/authorization.md +33 -0
  81. data/docs/guides/creating-packages.md +12 -16
  82. data/docs/guides/custom-actions.md +36 -0
  83. data/docs/guides/search-filtering.md +121 -42
  84. data/docs/guides/theming.md +232 -36
  85. data/docs/index.md +203 -57
  86. data/docs/public/og-image.png +0 -0
  87. data/docs/reference/controller/index.md +14 -16
  88. data/docs/reference/definition/actions.md +38 -3
  89. data/docs/reference/definition/fields.md +3 -3
  90. data/docs/reference/definition/index.md +2 -2
  91. data/docs/reference/generators/index.md +0 -1
  92. data/docs/reference/interaction/index.md +14 -10
  93. data/docs/reference/model/index.md +0 -1
  94. data/docs/reference/portal/index.md +13 -27
  95. data/gemfiles/rails_7.gemfile.lock +1 -1
  96. data/gemfiles/rails_8.0.gemfile.lock +1 -1
  97. data/gemfiles/rails_8.1.gemfile.lock +1 -1
  98. data/lib/generators/pu/pkg/portal/portal_generator.rb +0 -2
  99. data/lib/generators/pu/pkg/portal/templates/app/views/package/dashboard/index.html.erb +28 -72
  100. data/lib/plutonium/action/interactive.rb +2 -2
  101. data/lib/plutonium/core/controller.rb +2 -1
  102. data/lib/plutonium/definition/actions.rb +2 -2
  103. data/lib/plutonium/lib/deep_freezer.rb +3 -7
  104. data/lib/plutonium/query/filter.rb +14 -0
  105. data/lib/plutonium/query/filters/association.rb +49 -0
  106. data/lib/plutonium/query/filters/boolean.rb +35 -0
  107. data/lib/plutonium/query/filters/date.rb +97 -0
  108. data/lib/plutonium/query/filters/date_range.rb +58 -0
  109. data/lib/plutonium/query/filters/select.rb +55 -0
  110. data/lib/plutonium/resource/controllers/crud_actions.rb +24 -6
  111. data/lib/plutonium/resource/controllers/interactive_actions.rb +76 -58
  112. data/lib/plutonium/resource/controllers/queryable.rb +4 -2
  113. data/lib/plutonium/resource/query_object.rb +1 -1
  114. data/lib/plutonium/ui/action_button.rb +23 -65
  115. data/lib/plutonium/ui/actions_dropdown.rb +103 -0
  116. data/lib/plutonium/ui/block.rb +1 -1
  117. data/lib/plutonium/ui/breadcrumbs.rb +12 -19
  118. data/lib/plutonium/ui/color_mode_selector.rb +1 -1
  119. data/lib/plutonium/ui/component/kit.rb +6 -0
  120. data/lib/plutonium/ui/component_classes.rb +102 -0
  121. data/lib/plutonium/ui/display/base.rb +15 -0
  122. data/lib/plutonium/ui/display/components/attachment.rb +6 -5
  123. data/lib/plutonium/ui/display/components/boolean.rb +23 -0
  124. data/lib/plutonium/ui/display/components/color.rb +23 -0
  125. data/lib/plutonium/ui/display/resource.rb +1 -1
  126. data/lib/plutonium/ui/display/theme.rb +29 -15
  127. data/lib/plutonium/ui/empty_card.rb +3 -3
  128. data/lib/plutonium/ui/form/base.rb +20 -0
  129. data/lib/plutonium/ui/form/components/key_value_store.rb +11 -11
  130. data/lib/plutonium/ui/form/components/resource_select.rb +31 -0
  131. data/lib/plutonium/ui/form/components/secure_association.rb +1 -2
  132. data/lib/plutonium/ui/form/components/uppy.rb +5 -4
  133. data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +4 -4
  134. data/lib/plutonium/ui/form/interaction.rb +17 -1
  135. data/lib/plutonium/ui/form/query.rb +133 -80
  136. data/lib/plutonium/ui/form/theme.rb +50 -35
  137. data/lib/plutonium/ui/frame_navigator_panel.rb +2 -2
  138. data/lib/plutonium/ui/layout/base.rb +1 -1
  139. data/lib/plutonium/ui/layout/header.rb +4 -7
  140. data/lib/plutonium/ui/layout/rodauth_layout.rb +7 -7
  141. data/lib/plutonium/ui/layout/sidebar.rb +1 -1
  142. data/lib/plutonium/ui/nav_grid_menu.rb +7 -6
  143. data/lib/plutonium/ui/nav_user.rb +9 -8
  144. data/lib/plutonium/ui/page/interactive_action.rb +5 -5
  145. data/lib/plutonium/ui/page_header.rb +29 -10
  146. data/lib/plutonium/ui/panel.rb +4 -4
  147. data/lib/plutonium/ui/sidebar_menu.rb +8 -8
  148. data/lib/plutonium/ui/skeleton_table.rb +7 -8
  149. data/lib/plutonium/ui/tab_list.rb +5 -5
  150. data/lib/plutonium/ui/table/base.rb +3 -0
  151. data/lib/plutonium/ui/table/components/attachment.rb +4 -3
  152. data/lib/plutonium/ui/table/components/bulk_actions_toolbar.rb +82 -0
  153. data/lib/plutonium/ui/table/components/pagy_info.rb +2 -2
  154. data/lib/plutonium/ui/table/components/pagy_pagination.rb +13 -8
  155. data/lib/plutonium/ui/table/components/row_actions_dropdown.rb +101 -0
  156. data/lib/plutonium/ui/table/components/scopes_bar.rb +2 -2
  157. data/lib/plutonium/ui/table/components/selection_column.rb +100 -0
  158. data/lib/plutonium/ui/table/display_theme.rb +6 -6
  159. data/lib/plutonium/ui/table/resource.rb +93 -52
  160. data/lib/plutonium/ui/table/theme.rb +28 -15
  161. data/lib/plutonium/version.rb +1 -1
  162. data/package.json +2 -2
  163. data/plutonium.gemspec +5 -4
  164. data/src/css/components.css +471 -0
  165. data/src/css/intl_tel_input.css +2 -2
  166. data/src/css/plutonium.css +2 -0
  167. data/src/css/tokens.css +149 -0
  168. data/src/js/controllers/bulk_actions_controller.js +109 -0
  169. data/src/js/controllers/filter_panel_controller.js +35 -0
  170. data/src/js/controllers/register_controllers.js +5 -1
  171. data/src/js/controllers/resource_drop_down_controller.js +25 -1
  172. data/src/js/controllers/slim_select_controller.js +6 -2
  173. data/src/js/turbo/turbo_actions.js +1 -1
  174. metadata +52 -39
  175. data/.claude/skills/definition-query/SKILL.md +0 -334
  176. data/docs/concepts/architecture.md +0 -226
  177. data/docs/concepts/auto-detection.md +0 -254
  178. data/docs/concepts/index.md +0 -61
  179. data/docs/concepts/packages-portals.md +0 -304
  180. data/docs/concepts/resources.md +0 -224
  181. data/docs/cookbook/blog.md +0 -411
  182. data/docs/cookbook/index.md +0 -289
  183. data/docs/cookbook/saas.md +0 -481
  184. data/docs/public/CLAUDE.md +0 -578
  185. data/lib/generators/pu/pkg/portal/templates/app/controllers/resource_controller.rb.tt +0 -5
@@ -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