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,383 +0,0 @@
|
|
|
1
|
-
# Definition Fields
|
|
2
|
-
|
|
3
|
-
Complete reference for field configuration in definitions.
|
|
4
|
-
|
|
5
|
-
## Core Methods
|
|
6
|
-
|
|
7
|
-
| Method | Applies To | Use When |
|
|
8
|
-
|--------|-----------|----------|
|
|
9
|
-
| `field` | Forms + Show + Table | Universal type override |
|
|
10
|
-
| `input` | Forms only | Form-specific options |
|
|
11
|
-
| `display` | Show page only | Display-specific options |
|
|
12
|
-
| `column` | Table only | Table-specific options |
|
|
13
|
-
|
|
14
|
-
## Basic Usage
|
|
15
|
-
|
|
16
|
-
```ruby
|
|
17
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
18
|
-
# field - changes type everywhere
|
|
19
|
-
field :content, as: :markdown
|
|
20
|
-
|
|
21
|
-
# input - form-specific
|
|
22
|
-
input :title,
|
|
23
|
-
label: "Article Title",
|
|
24
|
-
hint: "Enter a descriptive title",
|
|
25
|
-
placeholder: "e.g. Getting Started"
|
|
26
|
-
|
|
27
|
-
# display - show page specific
|
|
28
|
-
display :content,
|
|
29
|
-
as: :markdown,
|
|
30
|
-
description: "Published content",
|
|
31
|
-
wrapper: {class: "col-span-full"}
|
|
32
|
-
|
|
33
|
-
# column - table specific
|
|
34
|
-
column :title, label: "Article", align: :center
|
|
35
|
-
column :view_count, align: :end
|
|
36
|
-
end
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Available Field Types
|
|
40
|
-
|
|
41
|
-
### Input Types (Forms)
|
|
42
|
-
|
|
43
|
-
| Category | Types |
|
|
44
|
-
|----------|-------|
|
|
45
|
-
| **Text** | `:string`, `:text`, `:email`, `:url`, `:tel`, `:password` |
|
|
46
|
-
| **Rich Text** | `:markdown` (uses EasyMDE editor) |
|
|
47
|
-
| **Numeric** | `:number`, `:integer`, `:decimal`, `:range` |
|
|
48
|
-
| **Boolean** | `:boolean` |
|
|
49
|
-
| **Date/Time** | `:date`, `:time`, `:datetime` |
|
|
50
|
-
| **Selection** | `:select`, `:slim_select`, `:radio_buttons`, `:check_boxes` |
|
|
51
|
-
| **Files** | `:file`, `:uppy`, `:attachment` |
|
|
52
|
-
| **Associations** | `:association`, `:secure_association`, `:belongs_to`, `:has_many`, `:has_one` |
|
|
53
|
-
| **Special** | `:hidden`, `:color`, `:phone` |
|
|
54
|
-
|
|
55
|
-
### Display Types (Show/Index)
|
|
56
|
-
|
|
57
|
-
`:string`, `:text`, `:email`, `:url`, `:phone`, `:markdown`, `:number`, `:integer`, `:decimal`, `:boolean`, `:date`, `:time`, `:datetime`, `:association`, `:attachment`
|
|
58
|
-
|
|
59
|
-
## Field Options
|
|
60
|
-
|
|
61
|
-
### Common Options
|
|
62
|
-
|
|
63
|
-
```ruby
|
|
64
|
-
input :title,
|
|
65
|
-
label: "Custom Label", # Custom label text
|
|
66
|
-
hint: "Help text for forms", # Form help text
|
|
67
|
-
placeholder: "Enter value", # Input placeholder
|
|
68
|
-
description: "For displays" # Display description
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### HTML Attributes
|
|
72
|
-
|
|
73
|
-
```ruby
|
|
74
|
-
input :title,
|
|
75
|
-
class: "custom-class", # CSS class
|
|
76
|
-
data: {controller: "custom"}, # Data attributes
|
|
77
|
-
required: true, # HTML required
|
|
78
|
-
readonly: true, # HTML readonly
|
|
79
|
-
disabled: true # HTML disabled
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Wrapper Options
|
|
83
|
-
|
|
84
|
-
```ruby
|
|
85
|
-
display :content, wrapper: {class: "col-span-full"}
|
|
86
|
-
input :notes, wrapper: {class: "bg-gray-50"}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Select/Choices
|
|
90
|
-
|
|
91
|
-
### Static Choices
|
|
92
|
-
|
|
93
|
-
```ruby
|
|
94
|
-
input :category, as: :select, choices: %w[Tech Business Lifestyle]
|
|
95
|
-
input :status, as: :select, choices: Post.statuses.keys
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Dynamic Choices (requires block)
|
|
99
|
-
|
|
100
|
-
```ruby
|
|
101
|
-
# Basic dynamic
|
|
102
|
-
input :author do |f|
|
|
103
|
-
choices = User.active.pluck(:name, :id)
|
|
104
|
-
f.select_tag choices: choices
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# With context access
|
|
108
|
-
input :team_members do |f|
|
|
109
|
-
choices = current_user.organization.users.pluck(:name, :id)
|
|
110
|
-
f.select_tag choices: choices
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# Based on object state
|
|
114
|
-
input :related_posts do |f|
|
|
115
|
-
choices = if object.persisted?
|
|
116
|
-
Post.where.not(id: object.id).published.pluck(:title, :id)
|
|
117
|
-
else
|
|
118
|
-
[]
|
|
119
|
-
end
|
|
120
|
-
f.select_tag choices: choices
|
|
121
|
-
end
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Conditional Rendering
|
|
125
|
-
|
|
126
|
-
```ruby
|
|
127
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
128
|
-
# Show based on object state
|
|
129
|
-
display :published_at, condition: -> { object.published? }
|
|
130
|
-
display :rejection_reason, condition: -> { object.rejected? }
|
|
131
|
-
|
|
132
|
-
# Show based on environment
|
|
133
|
-
field :debug_info, condition: -> { Rails.env.development? }
|
|
134
|
-
end
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
**Note:** Use `condition` for UI state logic. Use **policies** for authorization.
|
|
138
|
-
|
|
139
|
-
## Dynamic Forms (pre_submit)
|
|
140
|
-
|
|
141
|
-
Use `pre_submit: true` to create forms that dynamically show/hide fields based on other field values.
|
|
142
|
-
|
|
143
|
-
### Basic Pattern
|
|
144
|
-
|
|
145
|
-
```ruby
|
|
146
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
147
|
-
# Trigger field - causes form to re-render on change
|
|
148
|
-
input :send_notifications, pre_submit: true
|
|
149
|
-
|
|
150
|
-
# Dependent field - only shown when condition is true
|
|
151
|
-
input :notification_channel,
|
|
152
|
-
as: :select,
|
|
153
|
-
choices: %w[Email SMS],
|
|
154
|
-
condition: -> { object.send_notifications? }
|
|
155
|
-
end
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### How It Works
|
|
159
|
-
|
|
160
|
-
1. User changes a `pre_submit: true` field
|
|
161
|
-
2. Form submits via Turbo (no page reload)
|
|
162
|
-
3. Server re-renders the form with updated `object` state
|
|
163
|
-
4. Fields with `condition` procs are re-evaluated
|
|
164
|
-
5. Newly visible fields appear, hidden fields disappear
|
|
165
|
-
|
|
166
|
-
## Custom Rendering
|
|
167
|
-
|
|
168
|
-
### Block Syntax
|
|
169
|
-
|
|
170
|
-
**For Display (can return any component):**
|
|
171
|
-
|
|
172
|
-
```ruby
|
|
173
|
-
display :status do |field|
|
|
174
|
-
StatusBadgeComponent.new(value: field.value, class: field.dom.css_class)
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
display :metrics do |field|
|
|
178
|
-
if field.value.present?
|
|
179
|
-
MetricsChartComponent.new(data: field.value)
|
|
180
|
-
else
|
|
181
|
-
EmptyStateComponent.new(message: "No metrics")
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
**For Input (must use form builder methods):**
|
|
187
|
-
|
|
188
|
-
```ruby
|
|
189
|
-
input :birth_date do |f|
|
|
190
|
-
case object.age_category
|
|
191
|
-
when 'adult'
|
|
192
|
-
f.date_tag(min: 18.years.ago.to_date)
|
|
193
|
-
when 'minor'
|
|
194
|
-
f.date_tag(max: 18.years.ago.to_date)
|
|
195
|
-
else
|
|
196
|
-
f.date_tag
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### phlexi_tag (Advanced Display)
|
|
202
|
-
|
|
203
|
-
```ruby
|
|
204
|
-
# With component class
|
|
205
|
-
display :status, as: :phlexi_tag, with: StatusBadgeComponent
|
|
206
|
-
|
|
207
|
-
# With inline proc
|
|
208
|
-
display :priority, as: :phlexi_tag, with: ->(value, attrs) {
|
|
209
|
-
case value
|
|
210
|
-
when 'high'
|
|
211
|
-
span(class: "badge badge-danger") { "High" }
|
|
212
|
-
when 'medium'
|
|
213
|
-
span(class: "badge badge-warning") { "Medium" }
|
|
214
|
-
else
|
|
215
|
-
span(class: "badge badge-info") { "Low" }
|
|
216
|
-
end
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### Custom Component Class
|
|
221
|
-
|
|
222
|
-
```ruby
|
|
223
|
-
input :color_picker, as: ColorPickerComponent
|
|
224
|
-
display :chart, as: ChartComponent
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
## Column Alignment
|
|
228
|
-
|
|
229
|
-
```ruby
|
|
230
|
-
column :title, align: :start # Left (default)
|
|
231
|
-
column :status, align: :center # Center
|
|
232
|
-
column :amount, align: :end # Right
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
## Value Formatting
|
|
236
|
-
|
|
237
|
-
Use `formatter` for simple value transformations without a full block:
|
|
238
|
-
|
|
239
|
-
```ruby
|
|
240
|
-
# Truncate long text
|
|
241
|
-
column :description, formatter: ->(value) { value&.truncate(30) }
|
|
242
|
-
|
|
243
|
-
# Format numbers
|
|
244
|
-
column :price, formatter: ->(value) { "$%.2f" % value if value }
|
|
245
|
-
|
|
246
|
-
# Transform values
|
|
247
|
-
column :status, formatter: ->(value) { value&.humanize&.upcase }
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
The `formatter` option:
|
|
251
|
-
- Receives the field value as its argument
|
|
252
|
-
- Returns the transformed value for display
|
|
253
|
-
- Works with `column` and `display` declarations
|
|
254
|
-
- Is simpler than block syntax when you only need to transform the value
|
|
255
|
-
|
|
256
|
-
**formatter vs block:** Use `formatter` when you only need the value. Use a block when you need access to the full record:
|
|
257
|
-
|
|
258
|
-
```ruby
|
|
259
|
-
# formatter - receives just the value
|
|
260
|
-
column :name, formatter: ->(value) { value&.titleize }
|
|
261
|
-
|
|
262
|
-
# block - receives the full record
|
|
263
|
-
column :full_name do |record|
|
|
264
|
-
"#{record.first_name} #{record.last_name}"
|
|
265
|
-
end
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
## Nested Inputs
|
|
269
|
-
|
|
270
|
-
Render inline forms for associated records. Requires `accepts_nested_attributes_for` on the model.
|
|
271
|
-
|
|
272
|
-
### Model Setup
|
|
273
|
-
|
|
274
|
-
```ruby
|
|
275
|
-
class Post < ResourceRecord
|
|
276
|
-
has_many :comments
|
|
277
|
-
has_one :metadata
|
|
278
|
-
|
|
279
|
-
accepts_nested_attributes_for :comments, allow_destroy: true, limit: 10
|
|
280
|
-
accepts_nested_attributes_for :metadata, update_only: true
|
|
281
|
-
end
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### Basic Declaration
|
|
285
|
-
|
|
286
|
-
```ruby
|
|
287
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
288
|
-
# Block syntax
|
|
289
|
-
nested_input :comments do |n|
|
|
290
|
-
n.input :body, as: :text
|
|
291
|
-
n.input :author_name
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
# Using another definition
|
|
295
|
-
nested_input :metadata, using: PostMetadataDefinition, fields: %i[seo_title seo_description]
|
|
296
|
-
end
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### Options
|
|
300
|
-
|
|
301
|
-
| Option | Description |
|
|
302
|
-
|--------|-------------|
|
|
303
|
-
| `limit` | Max records (auto-detected from model, default: 10) |
|
|
304
|
-
| `allow_destroy` | Show delete checkbox (auto-detected from model) |
|
|
305
|
-
| `update_only` | Hide "Add" button, only edit existing |
|
|
306
|
-
| `description` | Help text above the section |
|
|
307
|
-
| `condition` | Proc to show/hide section |
|
|
308
|
-
| `using` | Reference another Definition class |
|
|
309
|
-
| `fields` | Which fields to render from the definition |
|
|
310
|
-
|
|
311
|
-
```ruby
|
|
312
|
-
nested_input :amenities,
|
|
313
|
-
allow_destroy: true,
|
|
314
|
-
limit: 20,
|
|
315
|
-
description: "Add property amenities" do |n|
|
|
316
|
-
n.input :name
|
|
317
|
-
n.input :icon, as: :select, choices: ICONS
|
|
318
|
-
end
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
## File Uploads
|
|
322
|
-
|
|
323
|
-
```ruby
|
|
324
|
-
input :avatar, as: :file
|
|
325
|
-
input :avatar, as: :uppy
|
|
326
|
-
|
|
327
|
-
input :documents, as: :file, multiple: true
|
|
328
|
-
input :documents, as: :uppy,
|
|
329
|
-
allowed_file_types: ['.pdf', '.doc'],
|
|
330
|
-
max_file_size: 5.megabytes
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
## Common Patterns
|
|
334
|
-
|
|
335
|
-
### Rich Text Content
|
|
336
|
-
|
|
337
|
-
```ruby
|
|
338
|
-
field :content, as: :markdown # Form: EasyMDE editor
|
|
339
|
-
display :content, as: :markdown # Show: rendered markdown
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
### Money Fields
|
|
343
|
-
|
|
344
|
-
```ruby
|
|
345
|
-
input :price, as: :decimal, class: "font-mono"
|
|
346
|
-
display :price, class: "font-bold text-green-600"
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
### Status Badges
|
|
350
|
-
|
|
351
|
-
```ruby
|
|
352
|
-
display :status do |field|
|
|
353
|
-
color = case field.value
|
|
354
|
-
when 'active' then 'green'
|
|
355
|
-
when 'pending' then 'yellow'
|
|
356
|
-
else 'gray'
|
|
357
|
-
end
|
|
358
|
-
span(class: "badge badge-#{color}") { field.value.humanize }
|
|
359
|
-
end
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
### Hidden Fields
|
|
363
|
-
|
|
364
|
-
```ruby
|
|
365
|
-
field :author_id, as: :hidden
|
|
366
|
-
input :tenant_id, as: :hidden
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
## Context in Blocks
|
|
370
|
-
|
|
371
|
-
Inside `condition` procs and `input` blocks:
|
|
372
|
-
- `object` - The record being edited/displayed
|
|
373
|
-
- `current_user` - The authenticated user
|
|
374
|
-
- `current_parent` - Parent record for nested resources
|
|
375
|
-
- `request`, `params` - Request information
|
|
376
|
-
- All helper methods
|
|
377
|
-
|
|
378
|
-
## Related
|
|
379
|
-
|
|
380
|
-
- [Definition Reference](./index)
|
|
381
|
-
- [Actions Reference](./actions)
|
|
382
|
-
- [Query Reference](./query)
|
|
383
|
-
- [Forms Reference](/reference/views/forms)
|
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
# Definition Reference
|
|
2
|
-
|
|
3
|
-
Complete reference for resource definitions.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
Definitions control how resources render - which fields appear in forms, how tables display data, what actions are available.
|
|
8
|
-
|
|
9
|
-
```ruby
|
|
10
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
11
|
-
# Field configuration
|
|
12
|
-
field :title
|
|
13
|
-
field :body, as: :markdown
|
|
14
|
-
|
|
15
|
-
# Form-specific
|
|
16
|
-
input :title, placeholder: "Enter title"
|
|
17
|
-
|
|
18
|
-
# Display-specific
|
|
19
|
-
display :body, as: :markdown
|
|
20
|
-
|
|
21
|
-
# Table columns
|
|
22
|
-
column :title
|
|
23
|
-
|
|
24
|
-
# Custom actions
|
|
25
|
-
action :publish, interaction: PublishPost
|
|
26
|
-
|
|
27
|
-
# Search
|
|
28
|
-
search do |scope, query|
|
|
29
|
-
scope.where("title ILIKE ?", "%#{query}%")
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Sorting
|
|
33
|
-
sort :title
|
|
34
|
-
sort :created_at
|
|
35
|
-
default_sort :created_at, :desc
|
|
36
|
-
end
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Definition Files
|
|
40
|
-
|
|
41
|
-
### Location
|
|
42
|
-
|
|
43
|
-
```
|
|
44
|
-
app/definitions/post_definition.rb
|
|
45
|
-
packages/blogging/app/definitions/blogging/post_definition.rb
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Naming Convention
|
|
49
|
-
|
|
50
|
-
| Model | Definition |
|
|
51
|
-
|-------|------------|
|
|
52
|
-
| `Post` | `PostDefinition` |
|
|
53
|
-
| `Blogging::Post` | `Blogging::PostDefinition` |
|
|
54
|
-
|
|
55
|
-
### Portal-Specific
|
|
56
|
-
|
|
57
|
-
Override for specific portals:
|
|
58
|
-
|
|
59
|
-
```ruby
|
|
60
|
-
# packages/admin_portal/app/definitions/admin_portal/post_definition.rb
|
|
61
|
-
module AdminPortal
|
|
62
|
-
class PostDefinition < ::PostDefinition
|
|
63
|
-
# Admin-specific customizations
|
|
64
|
-
field :internal_notes
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Auto-Detection
|
|
70
|
-
|
|
71
|
-
By default, Plutonium auto-detects fields from the model:
|
|
72
|
-
|
|
73
|
-
```ruby
|
|
74
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
75
|
-
# Empty definition = all fields auto-detected
|
|
76
|
-
end
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Override selectively:
|
|
80
|
-
|
|
81
|
-
```ruby
|
|
82
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
83
|
-
# Override just body field
|
|
84
|
-
field :body, as: :markdown
|
|
85
|
-
|
|
86
|
-
# Other fields still auto-detected
|
|
87
|
-
end
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Core Methods
|
|
91
|
-
|
|
92
|
-
### Field Declaration
|
|
93
|
-
|
|
94
|
-
| Method | Purpose |
|
|
95
|
-
|--------|---------|
|
|
96
|
-
| `field` | Universal type/options for forms, displays, tables |
|
|
97
|
-
| `input` | Form-specific configuration |
|
|
98
|
-
| `display` | Show page configuration |
|
|
99
|
-
| `column` | Table configuration |
|
|
100
|
-
|
|
101
|
-
### Query Configuration
|
|
102
|
-
|
|
103
|
-
| Method | Purpose |
|
|
104
|
-
|--------|---------|
|
|
105
|
-
| `search` | Full-text search block |
|
|
106
|
-
| `filter` | Sidebar filter inputs |
|
|
107
|
-
| `scope` | Quick filter buttons |
|
|
108
|
-
| `sort` / `sorts` | Sortable columns |
|
|
109
|
-
| `default_sort` | Default sort order |
|
|
110
|
-
|
|
111
|
-
### Actions
|
|
112
|
-
|
|
113
|
-
| Method | Purpose |
|
|
114
|
-
|--------|---------|
|
|
115
|
-
| `action` | Define custom actions |
|
|
116
|
-
| `nested_input` | Nested forms for associations |
|
|
117
|
-
|
|
118
|
-
## Page Configuration
|
|
119
|
-
|
|
120
|
-
Configure page titles and descriptions:
|
|
121
|
-
|
|
122
|
-
```ruby
|
|
123
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
124
|
-
index_page_title "All Posts"
|
|
125
|
-
index_page_description "Manage your blog posts"
|
|
126
|
-
|
|
127
|
-
new_page_title "Create Post"
|
|
128
|
-
new_page_description "Add a new blog post"
|
|
129
|
-
|
|
130
|
-
show_page_title { |record| record.title }
|
|
131
|
-
show_page_description "View post details"
|
|
132
|
-
|
|
133
|
-
edit_page_title { |record| "Edit: #{record.title}" }
|
|
134
|
-
edit_page_description "Update post content"
|
|
135
|
-
end
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## Breadcrumbs
|
|
139
|
-
|
|
140
|
-
Control breadcrumb display:
|
|
141
|
-
|
|
142
|
-
```ruby
|
|
143
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
144
|
-
# Disable breadcrumbs globally
|
|
145
|
-
breadcrumbs false
|
|
146
|
-
|
|
147
|
-
# Or per-page
|
|
148
|
-
index_page_breadcrumbs true
|
|
149
|
-
new_page_breadcrumbs true
|
|
150
|
-
show_page_breadcrumbs true
|
|
151
|
-
edit_page_breadcrumbs true
|
|
152
|
-
interactive_action_page_breadcrumbs true
|
|
153
|
-
end
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
## Form Configuration
|
|
157
|
-
|
|
158
|
-
Control form behavior:
|
|
159
|
-
|
|
160
|
-
```ruby
|
|
161
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
162
|
-
# Controls "Save and add another" / "Update and continue editing" buttons
|
|
163
|
-
# nil (default) = auto-detect (hidden for singular resources, shown for plural)
|
|
164
|
-
# true = always show
|
|
165
|
-
# false = always hide
|
|
166
|
-
submit_and_continue false
|
|
167
|
-
|
|
168
|
-
# How `:new` / `:edit` render. Default is :slideover.
|
|
169
|
-
# :slideover — slide-in panel from the right (default)
|
|
170
|
-
# :centered — centered modal dialog
|
|
171
|
-
# false — full standalone pages (no modal)
|
|
172
|
-
modal :centered
|
|
173
|
-
end
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Singular resources (e.g., `resource :profile` routes or `has_one` nested) auto-hide the secondary submit button since creating "another" doesn't make sense.
|
|
177
|
-
|
|
178
|
-
The `modal` setting only retargets the framework-provided `:new` / `:edit` actions. Custom interactive actions render in their own dialog whose chrome is set on the action via the per-action `modal:` option (`:centered` default, or `:slideover`) — see [Actions](./actions#action-options).
|
|
179
|
-
|
|
180
|
-
## Show Page Metadata Panel
|
|
181
|
-
|
|
182
|
-
The `metadata` DSL declares a list of fields that render in a right-side aside on the show page as label/value rows, leaving the main card focused on the record's substance.
|
|
183
|
-
|
|
184
|
-
```ruby
|
|
185
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
186
|
-
metadata :author, :state, :created_at, :updated_at
|
|
187
|
-
end
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
- **Opt-in.** Without a `metadata` call, the show page renders full-width with no aside.
|
|
191
|
-
- **Policy-aware.** Fields are intersected with the policy's permitted attributes. The panel auto-hides when nothing is permitted.
|
|
192
|
-
- **Deduplicated.** Fields listed in `metadata` are removed from the main card so values aren't shown twice.
|
|
193
|
-
- **Responsive.** Side-by-side at `lg+`, stacked single-column below.
|
|
194
|
-
|
|
195
|
-
Field formatting (label, `as:`, blocks) is shared with the main card — declare once via `field` / `display` and the metadata panel inherits it.
|
|
196
|
-
|
|
197
|
-
## Index Views (Table & Grid)
|
|
198
|
-
|
|
199
|
-
Resources can opt into a card-based **Grid** view alongside the default **Table** view. The user can switch between them via the toolbar; the choice is persisted per-resource via cookie.
|
|
200
|
-
|
|
201
|
-
```ruby
|
|
202
|
-
class UserDefinition < Plutonium::Resource::Definition
|
|
203
|
-
views :table, :grid # enable both
|
|
204
|
-
default_view :grid # initial view if no cookie
|
|
205
|
-
|
|
206
|
-
grid_fields(
|
|
207
|
-
image: :avatar, # ActiveStorage attachment, Shrine, or URL string
|
|
208
|
-
header: :name, # falls back to record.to_label
|
|
209
|
-
subheader: :email,
|
|
210
|
-
body: :bio,
|
|
211
|
-
meta: [:role, :status], # rendered as small pills
|
|
212
|
-
footer: :last_seen_at # falls back to :created_at
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
grid_layout :media # :compact (default) or :media
|
|
216
|
-
grid_columns 3 # pin to 3 cols on lg+; default is 1/2/3/4 responsive
|
|
217
|
-
end
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
| Method | Purpose |
|
|
221
|
-
|--------|---------|
|
|
222
|
-
| `views :table, :grid` | Which views are available. Default `[:table]`. |
|
|
223
|
-
| `default_view :grid` | Initial view when no cookie. Falls back to first declared view. |
|
|
224
|
-
| `grid_fields(...)` | Maps card slots to fields. **Implicitly enables `:grid`** if not already declared. |
|
|
225
|
-
| `grid_layout :media` | `:compact` (image left of content) or `:media` (full-width image on top). |
|
|
226
|
-
| `grid_columns 3` | Override responsive column count on `lg+`. Default is 1 / 2 / 3 / 4 at sm/md/lg/xl. |
|
|
227
|
-
|
|
228
|
-
Grid slots — `:image`, `:header`, `:subheader`, `:body`, `:meta`, `:footer` — are all optional. `:meta` accepts an array; the rest are single fields. Slots that point at fields not permitted by the user's policy collapse silently.
|
|
229
|
-
|
|
230
|
-
## Custom Page Classes
|
|
231
|
-
|
|
232
|
-
Override default page components:
|
|
233
|
-
|
|
234
|
-
```ruby
|
|
235
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
236
|
-
# Custom page classes
|
|
237
|
-
class IndexPage < Plutonium::UI::Page::Index
|
|
238
|
-
def render_header
|
|
239
|
-
# Custom header
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
class Form < Plutonium::UI::Form::Resource
|
|
244
|
-
# Custom form behavior
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
class Table < Plutonium::UI::Table::Resource
|
|
248
|
-
# Custom table behavior
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
class Display < Plutonium::UI::Display::Resource
|
|
252
|
-
# Custom display behavior
|
|
253
|
-
end
|
|
254
|
-
end
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
## Inheritance
|
|
258
|
-
|
|
259
|
-
Definitions inherit from each other:
|
|
260
|
-
|
|
261
|
-
```ruby
|
|
262
|
-
# Base definition
|
|
263
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
264
|
-
field :title
|
|
265
|
-
field :body
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
# Extended definition
|
|
269
|
-
class AdminPortal::PostDefinition < ::PostDefinition
|
|
270
|
-
field :internal_notes
|
|
271
|
-
field :moderation_status
|
|
272
|
-
end
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
## Customization Hooks
|
|
276
|
-
|
|
277
|
-
Override customization methods for dynamic configuration:
|
|
278
|
-
|
|
279
|
-
```ruby
|
|
280
|
-
class PostDefinition < Plutonium::Resource::Definition
|
|
281
|
-
def customize_fields
|
|
282
|
-
field :dynamic_field if some_condition?
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
def customize_inputs
|
|
286
|
-
input :special_input, as: :text
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
def customize_displays
|
|
290
|
-
display :computed_value
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
def customize_columns
|
|
294
|
-
column :extra_column
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
def customize_filters
|
|
298
|
-
filter :status, with: Plutonium::Query::Filters::Text, predicate: :eq
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
def customize_scopes
|
|
302
|
-
scope :active
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
def customize_sorts
|
|
306
|
-
sort :custom_field
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
def customize_actions
|
|
310
|
-
action :dynamic_action, interaction: SomeInteraction
|
|
311
|
-
end
|
|
312
|
-
end
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
## Sections
|
|
316
|
-
|
|
317
|
-
- [Fields](./fields) - Form and display field configuration
|
|
318
|
-
- [Actions](./actions) - Custom actions and buttons
|
|
319
|
-
- [Query](./query) - Search, filters, scopes, and sorting
|
|
320
|
-
|
|
321
|
-
## Related
|
|
322
|
-
|
|
323
|
-
- [Fields](./fields) - Field configuration
|
|
324
|
-
- [Actions](./actions) - Custom actions
|
|
325
|
-
- [Query](./query) - Search, filters, scopes
|
|
326
|
-
- [Views Reference](/reference/views/)
|