plutonium 0.50.0 → 0.51.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 (132) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/skills/plutonium/SKILL.md +85 -102
  3. data/.claude/skills/plutonium-app/SKILL.md +572 -0
  4. data/.claude/skills/plutonium-auth/SKILL.md +163 -300
  5. data/.claude/skills/plutonium-behavior/SKILL.md +838 -0
  6. data/.claude/skills/plutonium-resource/SKILL.md +1176 -0
  7. data/.claude/skills/plutonium-tenancy/SKILL.md +655 -0
  8. data/.claude/skills/plutonium-testing/SKILL.md +6 -5
  9. data/.claude/skills/plutonium-ui/SKILL.md +900 -0
  10. data/CHANGELOG.md +27 -2
  11. data/Rakefile +2 -1
  12. data/app/assets/plutonium.css +1 -11
  13. data/app/assets/plutonium.js +1009 -1214
  14. data/app/assets/plutonium.js.map +3 -3
  15. data/app/assets/plutonium.min.js +52 -51
  16. data/app/assets/plutonium.min.js.map +3 -3
  17. data/docs/.vitepress/config.ts +37 -27
  18. data/docs/getting-started/index.md +22 -29
  19. data/docs/getting-started/installation.md +37 -80
  20. data/docs/getting-started/tutorial/index.md +4 -5
  21. data/docs/guides/adding-resources.md +66 -377
  22. data/docs/guides/authentication.md +94 -463
  23. data/docs/guides/authorization.md +124 -370
  24. data/docs/guides/creating-packages.md +94 -296
  25. data/docs/guides/custom-actions.md +121 -441
  26. data/docs/guides/index.md +22 -42
  27. data/docs/guides/multi-tenancy.md +116 -187
  28. data/docs/guides/nested-resources.md +103 -431
  29. data/docs/guides/search-filtering.md +123 -240
  30. data/docs/guides/testing.md +5 -4
  31. data/docs/guides/theming.md +157 -407
  32. data/docs/guides/troubleshooting.md +5 -3
  33. data/docs/guides/user-invites.md +106 -425
  34. data/docs/guides/user-profile.md +76 -243
  35. data/docs/index.md +1 -1
  36. data/docs/reference/app/generators.md +517 -0
  37. data/docs/reference/app/index.md +158 -0
  38. data/docs/reference/app/packages.md +146 -0
  39. data/docs/reference/app/portals.md +377 -0
  40. data/docs/reference/auth/accounts.md +230 -0
  41. data/docs/reference/auth/index.md +88 -0
  42. data/docs/reference/auth/profile.md +185 -0
  43. data/docs/reference/behavior/controllers.md +395 -0
  44. data/docs/reference/behavior/index.md +22 -0
  45. data/docs/reference/behavior/interactions.md +341 -0
  46. data/docs/reference/behavior/policies.md +417 -0
  47. data/docs/reference/index.md +56 -49
  48. data/docs/reference/resource/actions.md +423 -0
  49. data/docs/reference/resource/definition.md +508 -0
  50. data/docs/reference/resource/index.md +50 -0
  51. data/docs/reference/resource/model.md +348 -0
  52. data/docs/reference/resource/query.md +305 -0
  53. data/docs/reference/tenancy/entity-scoping.md +361 -0
  54. data/docs/reference/tenancy/index.md +36 -0
  55. data/docs/reference/tenancy/invites.md +393 -0
  56. data/docs/reference/tenancy/nested-resources.md +267 -0
  57. data/docs/reference/testing/index.md +287 -0
  58. data/docs/reference/ui/assets.md +400 -0
  59. data/docs/reference/ui/components.md +165 -0
  60. data/docs/reference/ui/displays.md +104 -0
  61. data/docs/reference/ui/forms.md +284 -0
  62. data/docs/reference/ui/index.md +30 -0
  63. data/docs/reference/ui/layouts.md +106 -0
  64. data/docs/reference/ui/pages.md +189 -0
  65. data/docs/reference/ui/tables.md +117 -0
  66. data/docs/superpowers/specs/2026-05-09-typeahead-endpoint-design.md +203 -0
  67. data/docs/superpowers/specs/2026-05-12-skill-compaction-design.md +99 -0
  68. data/docs/superpowers/specs/2026-05-13-docs-restructure-design.md +186 -0
  69. data/gemfiles/rails_7.gemfile.lock +1 -1
  70. data/gemfiles/rails_8.0.gemfile.lock +1 -1
  71. data/gemfiles/rails_8.1.gemfile.lock +1 -1
  72. data/lib/generators/pu/core/update/update_generator.rb +0 -20
  73. data/lib/generators/pu/invites/install_generator.rb +1 -0
  74. data/lib/plutonium/definition/base.rb +1 -1
  75. data/lib/plutonium/definition/{views.rb → index_views.rb} +21 -20
  76. data/lib/plutonium/helpers/turbo_helper.rb +11 -0
  77. data/lib/plutonium/helpers/turbo_stream_actions_helper.rb +14 -0
  78. data/lib/plutonium/resource/controller.rb +1 -0
  79. data/lib/plutonium/resource/controllers/crud_actions.rb +19 -1
  80. data/lib/plutonium/resource/controllers/typeahead.rb +180 -0
  81. data/lib/plutonium/resource/policy.rb +7 -0
  82. data/lib/plutonium/routing/mapper_extensions.rb +15 -0
  83. data/lib/plutonium/ui/component/methods.rb +4 -0
  84. data/lib/plutonium/ui/form/base.rb +6 -2
  85. data/lib/plutonium/ui/form/components/json.rb +58 -0
  86. data/lib/plutonium/ui/form/components/resource_select.rb +62 -8
  87. data/lib/plutonium/ui/form/components/secure_association.rb +98 -22
  88. data/lib/plutonium/ui/form/concerns/typeahead_attributes.rb +83 -0
  89. data/lib/plutonium/ui/form/resource.rb +0 -4
  90. data/lib/plutonium/ui/grid/resource.rb +1 -1
  91. data/lib/plutonium/ui/layout/base.rb +1 -0
  92. data/lib/plutonium/ui/page/base.rb +0 -7
  93. data/lib/plutonium/ui/page/index.rb +4 -4
  94. data/lib/plutonium/ui/table/resource.rb +1 -1
  95. data/lib/plutonium/version.rb +1 -1
  96. data/lib/plutonium.rb +8 -0
  97. data/lib/tasks/release.rake +15 -1
  98. data/package.json +10 -10
  99. data/src/css/slim_select.css +4 -0
  100. data/src/js/controllers/slim_select_controller.js +61 -0
  101. data/src/js/turbo/turbo_actions.js +33 -0
  102. data/yarn.lock +553 -543
  103. metadata +44 -33
  104. data/.claude/skills/plutonium-assets/SKILL.md +0 -512
  105. data/.claude/skills/plutonium-controller/SKILL.md +0 -396
  106. data/.claude/skills/plutonium-create-resource/SKILL.md +0 -303
  107. data/.claude/skills/plutonium-definition/SKILL.md +0 -1223
  108. data/.claude/skills/plutonium-entity-scoping/SKILL.md +0 -317
  109. data/.claude/skills/plutonium-forms/SKILL.md +0 -465
  110. data/.claude/skills/plutonium-installation/SKILL.md +0 -331
  111. data/.claude/skills/plutonium-interaction/SKILL.md +0 -413
  112. data/.claude/skills/plutonium-invites/SKILL.md +0 -408
  113. data/.claude/skills/plutonium-model/SKILL.md +0 -440
  114. data/.claude/skills/plutonium-nested-resources/SKILL.md +0 -360
  115. data/.claude/skills/plutonium-package/SKILL.md +0 -198
  116. data/.claude/skills/plutonium-policy/SKILL.md +0 -456
  117. data/.claude/skills/plutonium-portal/SKILL.md +0 -410
  118. data/.claude/skills/plutonium-views/SKILL.md +0 -651
  119. data/docs/reference/assets/index.md +0 -496
  120. data/docs/reference/controller/index.md +0 -412
  121. data/docs/reference/definition/actions.md +0 -462
  122. data/docs/reference/definition/fields.md +0 -383
  123. data/docs/reference/definition/index.md +0 -326
  124. data/docs/reference/definition/query.md +0 -351
  125. data/docs/reference/generators/index.md +0 -648
  126. data/docs/reference/interaction/index.md +0 -449
  127. data/docs/reference/model/features.md +0 -248
  128. data/docs/reference/model/index.md +0 -218
  129. data/docs/reference/policy/index.md +0 -456
  130. data/docs/reference/portal/index.md +0 -379
  131. data/docs/reference/views/forms.md +0 -411
  132. data/docs/reference/views/index.md +0 -544
@@ -1,411 +0,0 @@
1
- # Forms Reference
2
-
3
- Complete reference for form customization using Phlexi::Form.
4
-
5
- ## Overview
6
-
7
- Plutonium forms are built on [Phlexi::Form](https://github.com/radioactive-labs/phlexi-form), providing a Ruby-first approach to form building.
8
-
9
- ## Form Class Hierarchy
10
-
11
- ```
12
- Phlexi::Form::Base
13
- └── Plutonium::UI::Form::Base # Base with Plutonium components
14
- ├── Plutonium::UI::Form::Resource # Resource CRUD forms
15
- │ └── Plutonium::UI::Form::Interaction # Interactive action forms
16
- └── Plutonium::UI::Form::Query # Search/filter forms
17
- ```
18
-
19
- ## Custom Form Template
20
-
21
- Override form rendering in your definition:
22
-
23
- ```ruby
24
- class PostDefinition < ResourceDefinition
25
- class Form < Form
26
- def form_template
27
- # Your custom layout
28
- render_fields
29
- render_actions
30
- end
31
- end
32
- end
33
- ```
34
-
35
- ### Form Template Methods
36
-
37
- | Method | Description |
38
- |--------|-------------|
39
- | `form_template` | Main template method to override |
40
- | `render_fields` | Render all permitted fields |
41
- | `render_resource_field(name)` | Render a single field by name |
42
- | `render_actions` | Render submit buttons |
43
- | `fields_wrapper { }` | Wrapper div for field grid |
44
- | `actions_wrapper { }` | Wrapper div for buttons |
45
-
46
- ### Form Attributes
47
-
48
- | Attribute | Description |
49
- |-----------|-------------|
50
- | `object` / `record` | The form object being edited |
51
- | `resource_fields` | Array of permitted field names |
52
- | `resource_definition` | The definition instance |
53
-
54
- ## Custom Layouts
55
-
56
- ### Sectioned Form
57
-
58
- ```ruby
59
- class PostDefinition < ResourceDefinition
60
- class Form < Form
61
- def form_template
62
- section("Basic Information") {
63
- render_resource_field :title
64
- render_resource_field :slug
65
- }
66
-
67
- section("Content") {
68
- render_resource_field :content
69
- render_resource_field :excerpt
70
- }
71
-
72
- render_actions
73
- end
74
-
75
- private
76
-
77
- def section(title, &)
78
- div(class: "mb-8") {
79
- h3(class: "text-lg font-semibold mb-4") { title }
80
- fields_wrapper(&)
81
- }
82
- end
83
- end
84
- end
85
- ```
86
-
87
- ### Two-Column Layout
88
-
89
- ```ruby
90
- class Form < Form
91
- def form_template
92
- div(class: "grid grid-cols-1 lg:grid-cols-3 gap-6") {
93
- # Main content - 2 columns
94
- div(class: "lg:col-span-2") {
95
- fields_wrapper {
96
- render_resource_field :title
97
- render_resource_field :content
98
- }
99
- }
100
-
101
- # Sidebar - 1 column
102
- div(class: "space-y-4") {
103
- Panel {
104
- h4(class: "font-medium mb-2") { "Settings" }
105
- render_resource_field :status
106
- render_resource_field :visibility
107
- }
108
- }
109
- }
110
-
111
- render_actions
112
- end
113
- end
114
- ```
115
-
116
- ## Field Builder
117
-
118
- When using `render_resource_field`, Plutonium applies definition configuration. For custom rendering, use the `field` method directly.
119
-
120
- ### Basic Field Usage
121
-
122
- ```ruby
123
- def form_template
124
- # Using field builder directly
125
- render field(:title).wrapped { |f| f.input_tag }
126
- render field(:content).wrapped { |f| f.easymde_tag }
127
- render field(:published).wrapped { |f| f.checkbox_tag }
128
-
129
- render_actions
130
- end
131
- ```
132
-
133
- ### Standard Tag Methods
134
-
135
- | Method | Input Type |
136
- |--------|------------|
137
- | `f.input_tag` | Text input (auto-detects type) |
138
- | `f.string_tag` | Text input |
139
- | `f.text_tag` | Textarea |
140
- | `f.number_tag` | Number input |
141
- | `f.email_tag` | Email input |
142
- | `f.password_tag` | Password input |
143
- | `f.url_tag` | URL input |
144
- | `f.phone_tag` | Telephone input |
145
- | `f.hidden_tag` | Hidden input |
146
- | `f.date_tag` | Date input |
147
- | `f.time_tag` | Time input |
148
- | `f.datetime_tag` | Datetime input |
149
- | `f.checkbox_tag` | Checkbox |
150
- | `f.boolean_tag` | Checkbox (themed as boolean) |
151
- | `f.select_tag` | Select dropdown |
152
- | `f.radio_button_tag` | Radio button |
153
- | `f.collection_radio_buttons_tag` | Radio button collection |
154
- | `f.collection_checkboxes_tag` | Checkbox collection |
155
- | `f.range_tag` | Range slider |
156
- | `f.file_input_tag` | File input |
157
-
158
- ### Plutonium-Enhanced Tags
159
-
160
- Plutonium extends the form builder with additional tags. See the [Form::Base::Builder source](https://github.com/radioactive-labs/plutonium-core/blob/master/lib/plutonium/ui/form/base.rb) for the current list.
161
-
162
- Common ones include:
163
- - `f.easymde_tag` / `f.markdown_tag` - Markdown editor
164
- - `f.slim_select_tag` - Enhanced select
165
- - `f.flatpickr_tag` - Date/time picker
166
- - `f.uppy_tag` / `f.file_tag` - File upload
167
- - `f.secure_association_tag` - Association with SGID
168
-
169
- ### Field with Options
170
-
171
- ```ruby
172
- # Select with choices
173
- render field(:status).wrapped { |f|
174
- f.select_tag(choices: %w[draft published archived])
175
- }
176
-
177
- # Date picker with options
178
- render field(:published_at).wrapped { |f|
179
- f.flatpickr_tag(min_date: Date.today, enable_time: true)
180
- }
181
-
182
- # File upload with restrictions
183
- render field(:avatar).wrapped { |f|
184
- f.uppy_tag(
185
- allowed_file_types: %w[.jpg .png .gif],
186
- max_file_size: 5.megabytes
187
- )
188
- }
189
- ```
190
-
191
- ### Wrapped vs Unwrapped
192
-
193
- ```ruby
194
- # Wrapped - includes label, hint, errors
195
- render field(:title).wrapped { |f| f.input_tag }
196
-
197
- # Unwrapped - just the input element
198
- render field(:title).input_tag
199
-
200
- # Custom wrapper options
201
- render field(:title).wrapped(class: "col-span-full") { |f|
202
- f.input_tag
203
- }
204
- ```
205
-
206
- ## Input Configuration in Definitions
207
-
208
- Define inputs in the definition, render them in the form:
209
-
210
- ```ruby
211
- class PostDefinition < ResourceDefinition
212
- # Configure inputs
213
- input :title, hint: "Be descriptive", placeholder: "Enter title"
214
- input :content, as: :markdown
215
- input :status, as: :select, choices: %w[draft published]
216
- input :published_at, as: :flatpickr
217
-
218
- # Custom input with block
219
- input :category do |f|
220
- choices = Category.active.pluck(:name, :id)
221
- f.select_tag(choices: choices)
222
- end
223
-
224
- class Form < Form
225
- def form_template
226
- # render_resource_field uses the input configuration
227
- render_resource_field :title
228
- render_resource_field :content
229
- render_resource_field :status
230
- render_resource_field :published_at
231
- render_resource_field :category
232
-
233
- render_actions
234
- end
235
- end
236
- end
237
- ```
238
-
239
- ## Nested Forms
240
-
241
- For `has_many` / `has_one` associations with `accepts_nested_attributes_for`:
242
-
243
- ### Model Setup
244
-
245
- ```ruby
246
- class Post < ResourceRecord
247
- has_many :comments
248
- accepts_nested_attributes_for :comments, allow_destroy: true
249
- end
250
- ```
251
-
252
- ### Definition Setup
253
-
254
- ```ruby
255
- class PostDefinition < ResourceDefinition
256
- nested_input :comments do |n|
257
- n.input :author_name
258
- n.input :body, as: :text
259
- end
260
-
261
- # Or reference another definition
262
- nested_input :comments, using: CommentDefinition, fields: %i[author_name body]
263
- end
264
- ```
265
-
266
- ### Rendering
267
-
268
- ```ruby
269
- class Form < Form
270
- def form_template
271
- render_resource_field :title
272
- render_resource_field :content
273
-
274
- # Nested fields are automatically handled
275
- render_resource_field :comments
276
-
277
- render_actions
278
- end
279
- end
280
- ```
281
-
282
- ## Dynamic Forms (pre_submit)
283
-
284
- Fields with `pre_submit: true` trigger form re-rendering on change:
285
-
286
- ```ruby
287
- class PostDefinition < ResourceDefinition
288
- input :post_type, as: :select,
289
- choices: %w[article video podcast],
290
- pre_submit: true
291
-
292
- input :video_url,
293
- condition: -> { object.post_type == "video" }
294
-
295
- input :podcast_url,
296
- condition: -> { object.post_type == "podcast" }
297
- end
298
- ```
299
-
300
- When `post_type` changes, the form re-renders via Turbo and shows/hides conditional fields.
301
-
302
- ## Form Actions
303
-
304
- ### Submit and Continue Button
305
-
306
- Forms include a secondary button ("Create and add another" for new records, "Update and continue editing" for existing). Control this in your definition:
307
-
308
- ```ruby
309
- class PostDefinition < ResourceDefinition
310
- # nil (default) = auto-detect (hidden for singular resources, shown for plural)
311
- # true = always show
312
- # false = always hide
313
- submit_and_continue false
314
- end
315
- ```
316
-
317
- Singular resources (e.g., `resource :profile` routes or `has_one` nested) auto-hide this button.
318
-
319
- ### Default Actions
320
-
321
- ```ruby
322
- def render_actions
323
- actions_wrapper {
324
- render submit_button
325
- }
326
- end
327
- ```
328
-
329
- ### Custom Actions
330
-
331
- ```ruby
332
- def render_actions
333
- actions_wrapper {
334
- # Cancel link
335
- a(href: resource_url_for(resource_class), class: "btn btn-secondary") {
336
- "Cancel"
337
- }
338
-
339
- # Save as draft
340
- button(type: :submit, name: "draft", value: "1", class: "btn") {
341
- "Save Draft"
342
- }
343
-
344
- # Primary submit
345
- render submit_button
346
- }
347
- end
348
- ```
349
-
350
- ## Form Context
351
-
352
- Inside form templates:
353
-
354
- ```ruby
355
- class Form < Form
356
- def form_template
357
- # Form object
358
- object # The record
359
- record # Alias for object
360
- object.new_record? # Check if creating
361
-
362
- # Request context
363
- current_user
364
- current_parent
365
- request
366
- params
367
-
368
- # Definition
369
- resource_definition
370
- resource_fields # Permitted fields
371
-
372
- # URL helpers
373
- resource_url_for(object)
374
- resource_url_for(Post, action: :new)
375
-
376
- # Rails helpers
377
- helpers.link_to(...)
378
- end
379
- end
380
- ```
381
-
382
- ## Interaction Forms
383
-
384
- Forms for interactive actions:
385
-
386
- ```ruby
387
- class PublishPostInteraction < ResourceInteraction
388
- attribute :publish_date, :date
389
- attribute :notify_subscribers, :boolean, default: true
390
-
391
- input :publish_date, as: :flatpickr
392
- input :notify_subscribers
393
-
394
- # Custom form (optional)
395
- class Form < Plutonium::UI::Form::Interaction
396
- def form_template
397
- div(class: "space-y-4") {
398
- render_resource_field :publish_date
399
- render_resource_field :notify_subscribers
400
- }
401
- render_actions
402
- end
403
- end
404
- end
405
- ```
406
-
407
- ## Related
408
-
409
- - [Fields Reference](/reference/definition/fields) - Input configuration
410
- - [Views Reference](./index) - Custom page classes
411
- - [Theming Guide](/guides/theming) - TailwindCSS and styling