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