plutonium 0.49.1 → 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 (206) 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 +37 -0
  11. data/Rakefile +2 -1
  12. data/app/assets/plutonium.css +1 -11
  13. data/app/assets/plutonium.js +1323 -1184
  14. data/app/assets/plutonium.js.map +4 -4
  15. data/app/assets/plutonium.min.js +50 -49
  16. data/app/assets/plutonium.min.js.map +4 -4
  17. data/app/views/plutonium/_resource_header.html.erb +4 -4
  18. data/app/views/plutonium/_resource_sidebar.html.erb +9 -9
  19. data/app/views/resource/_resource_grid.html.erb +1 -0
  20. data/config/brakeman.ignore +25 -2
  21. data/docs/.vitepress/config.ts +37 -27
  22. data/docs/getting-started/index.md +22 -29
  23. data/docs/getting-started/installation.md +37 -80
  24. data/docs/getting-started/tutorial/index.md +4 -5
  25. data/docs/guides/adding-resources.md +66 -377
  26. data/docs/guides/authentication.md +94 -463
  27. data/docs/guides/authorization.md +124 -370
  28. data/docs/guides/creating-packages.md +94 -296
  29. data/docs/guides/custom-actions.md +121 -441
  30. data/docs/guides/index.md +22 -42
  31. data/docs/guides/multi-tenancy.md +116 -187
  32. data/docs/guides/nested-resources.md +103 -431
  33. data/docs/guides/search-filtering.md +123 -240
  34. data/docs/guides/testing.md +5 -4
  35. data/docs/guides/theming.md +157 -407
  36. data/docs/guides/troubleshooting.md +5 -3
  37. data/docs/guides/user-invites.md +106 -425
  38. data/docs/guides/user-profile.md +76 -243
  39. data/docs/index.md +1 -1
  40. data/docs/reference/app/generators.md +517 -0
  41. data/docs/reference/app/index.md +158 -0
  42. data/docs/reference/app/packages.md +146 -0
  43. data/docs/reference/app/portals.md +377 -0
  44. data/docs/reference/auth/accounts.md +230 -0
  45. data/docs/reference/auth/index.md +88 -0
  46. data/docs/reference/auth/profile.md +185 -0
  47. data/docs/reference/behavior/controllers.md +395 -0
  48. data/docs/reference/behavior/index.md +22 -0
  49. data/docs/reference/behavior/interactions.md +341 -0
  50. data/docs/reference/behavior/policies.md +417 -0
  51. data/docs/reference/index.md +56 -49
  52. data/docs/reference/resource/actions.md +423 -0
  53. data/docs/reference/resource/definition.md +508 -0
  54. data/docs/reference/resource/index.md +50 -0
  55. data/docs/reference/resource/model.md +348 -0
  56. data/docs/reference/resource/query.md +305 -0
  57. data/docs/reference/tenancy/entity-scoping.md +361 -0
  58. data/docs/reference/tenancy/index.md +36 -0
  59. data/docs/reference/tenancy/invites.md +393 -0
  60. data/docs/reference/tenancy/nested-resources.md +267 -0
  61. data/docs/reference/testing/index.md +287 -0
  62. data/docs/reference/ui/assets.md +400 -0
  63. data/docs/reference/ui/components.md +165 -0
  64. data/docs/reference/ui/displays.md +104 -0
  65. data/docs/reference/ui/forms.md +284 -0
  66. data/docs/reference/ui/index.md +30 -0
  67. data/docs/reference/ui/layouts.md +106 -0
  68. data/docs/reference/ui/pages.md +189 -0
  69. data/docs/reference/ui/tables.md +117 -0
  70. data/docs/superpowers/plans/2026-05-07-ui-layout-overhaul.md +841 -0
  71. data/docs/superpowers/plans/2026-05-07-ui-layout-overhaul.md.tasks.json +103 -0
  72. data/docs/superpowers/specs/2026-05-07-ui-layout-overhaul-design.md +270 -0
  73. data/docs/superpowers/specs/2026-05-09-typeahead-endpoint-design.md +203 -0
  74. data/docs/superpowers/specs/2026-05-12-skill-compaction-design.md +99 -0
  75. data/docs/superpowers/specs/2026-05-13-docs-restructure-design.md +186 -0
  76. data/gemfiles/rails_7.gemfile.lock +1 -1
  77. data/gemfiles/rails_8.0.gemfile.lock +1 -1
  78. data/gemfiles/rails_8.1.gemfile.lock +1 -1
  79. data/lib/generators/pu/core/install/templates/config/initializers/plutonium.rb +1 -0
  80. data/lib/generators/pu/invites/install_generator.rb +1 -0
  81. data/lib/generators/pu/lite/rails_pulse/rails_pulse_generator.rb +54 -5
  82. data/lib/plutonium/action/base.rb +44 -1
  83. data/lib/plutonium/action/interactive.rb +1 -1
  84. data/lib/plutonium/configuration.rb +4 -0
  85. data/lib/plutonium/definition/actions.rb +3 -0
  86. data/lib/plutonium/definition/base.rb +8 -0
  87. data/lib/plutonium/definition/index_views.rb +95 -0
  88. data/lib/plutonium/definition/metadata.rb +40 -0
  89. data/lib/plutonium/helpers/turbo_helper.rb +12 -1
  90. data/lib/plutonium/helpers/turbo_stream_actions_helper.rb +14 -0
  91. data/lib/plutonium/interaction/response/redirect.rb +1 -1
  92. data/lib/plutonium/query/base.rb +8 -0
  93. data/lib/plutonium/query/filters/association.rb +30 -8
  94. data/lib/plutonium/query/filters/boolean.rb +5 -0
  95. data/lib/plutonium/resource/controller.rb +1 -0
  96. data/lib/plutonium/resource/controllers/crud_actions.rb +19 -1
  97. data/lib/plutonium/resource/controllers/presentable.rb +11 -2
  98. data/lib/plutonium/resource/controllers/typeahead.rb +180 -0
  99. data/lib/plutonium/resource/definition.rb +42 -0
  100. data/lib/plutonium/resource/policy.rb +7 -0
  101. data/lib/plutonium/resource/query_object.rb +64 -6
  102. data/lib/plutonium/routing/mapper_extensions.rb +15 -0
  103. data/lib/plutonium/testing/resource_definition.rb +2 -2
  104. data/lib/plutonium/ui/action_button.rb +4 -2
  105. data/lib/plutonium/ui/component/kit.rb +12 -0
  106. data/lib/plutonium/ui/component/methods.rb +4 -0
  107. data/lib/plutonium/ui/display/base.rb +3 -1
  108. data/lib/plutonium/ui/display/resource.rb +109 -25
  109. data/lib/plutonium/ui/display/theme.rb +2 -1
  110. data/lib/plutonium/ui/dyna_frame/content.rb +8 -14
  111. data/lib/plutonium/ui/empty_card.rb +1 -1
  112. data/lib/plutonium/ui/form/base.rb +35 -3
  113. data/lib/plutonium/ui/form/components/hidden_wrapper.rb +25 -0
  114. data/lib/plutonium/ui/form/components/json.rb +58 -0
  115. data/lib/plutonium/ui/form/components/resource_select.rb +133 -1
  116. data/lib/plutonium/ui/form/components/secure_association.rb +105 -24
  117. data/lib/plutonium/ui/form/components/sticky_footer.rb +17 -0
  118. data/lib/plutonium/ui/form/concerns/typeahead_attributes.rb +83 -0
  119. data/lib/plutonium/ui/form/resource.rb +45 -10
  120. data/lib/plutonium/ui/form/theme.rb +1 -1
  121. data/lib/plutonium/ui/frame_navigator_panel.rb +7 -4
  122. data/lib/plutonium/ui/grid/card.rb +235 -0
  123. data/lib/plutonium/ui/grid/resource.rb +149 -0
  124. data/lib/plutonium/ui/layout/base.rb +38 -1
  125. data/lib/plutonium/ui/layout/header.rb +1 -2
  126. data/lib/plutonium/ui/layout/icon_rail.rb +212 -0
  127. data/lib/plutonium/ui/layout/resource_layout.rb +10 -3
  128. data/lib/plutonium/ui/layout/sidebar.rb +12 -24
  129. data/lib/plutonium/ui/layout/topbar.rb +100 -0
  130. data/lib/plutonium/ui/modal/base.rb +109 -0
  131. data/lib/plutonium/ui/modal/centered.rb +21 -0
  132. data/lib/plutonium/ui/modal/slideover.rb +26 -0
  133. data/lib/plutonium/ui/page/base.rb +18 -6
  134. data/lib/plutonium/ui/page/edit.rb +13 -1
  135. data/lib/plutonium/ui/page/index.rb +40 -1
  136. data/lib/plutonium/ui/page/interactive_action.rb +8 -39
  137. data/lib/plutonium/ui/page/new.rb +13 -1
  138. data/lib/plutonium/ui/page/show.rb +8 -1
  139. data/lib/plutonium/ui/page_header.rb +8 -13
  140. data/lib/plutonium/ui/panel.rb +10 -19
  141. data/lib/plutonium/ui/sidebar_menu.rb +2 -25
  142. data/lib/plutonium/ui/tab_list.rb +29 -7
  143. data/lib/plutonium/ui/table/base.rb +106 -0
  144. data/lib/plutonium/ui/table/components/bulk_actions_toolbar.rb +12 -4
  145. data/lib/plutonium/ui/table/components/filter_form.rb +171 -0
  146. data/lib/plutonium/ui/table/components/filter_pills.rb +89 -0
  147. data/lib/plutonium/ui/table/components/row_actions_dropdown.rb +13 -12
  148. data/lib/plutonium/ui/table/components/scopes_pills.rb +67 -0
  149. data/lib/plutonium/ui/table/components/selection_column.rb +2 -11
  150. data/lib/plutonium/ui/table/components/toolbar.rb +104 -0
  151. data/lib/plutonium/ui/table/components/view_switcher.rb +81 -0
  152. data/lib/plutonium/ui/table/resource.rb +158 -89
  153. data/lib/plutonium/ui/table/theme.rb +14 -5
  154. data/lib/plutonium/version.rb +1 -1
  155. data/lib/plutonium.rb +14 -0
  156. data/lib/tasks/release.rake +15 -1
  157. data/package.json +10 -10
  158. data/src/css/components.css +304 -131
  159. data/src/css/slim_select.css +4 -0
  160. data/src/css/tokens.css +101 -85
  161. data/src/js/controllers/autosubmit_controller.js +24 -0
  162. data/src/js/controllers/bulk_actions_controller.js +15 -16
  163. data/src/js/controllers/capture_url_controller.js +14 -0
  164. data/src/js/controllers/filter_panel_controller.js +77 -19
  165. data/src/js/controllers/frame_navigator_controller.js +34 -6
  166. data/src/js/controllers/icon_rail_controller.js +22 -0
  167. data/src/js/controllers/icon_rail_flyout_controller.js +128 -0
  168. data/src/js/controllers/register_controllers.js +16 -0
  169. data/src/js/controllers/resource_tab_list_controller.js +56 -3
  170. data/src/js/controllers/row_click_controller.js +21 -0
  171. data/src/js/controllers/slim_select_controller.js +61 -0
  172. data/src/js/controllers/table_column_menu_controller.js +43 -0
  173. data/src/js/controllers/table_header_controller.js +16 -0
  174. data/src/js/controllers/view_switcher_controller.js +29 -0
  175. data/src/js/turbo/turbo_actions.js +33 -0
  176. data/yarn.lock +553 -543
  177. metadata +71 -32
  178. data/.claude/skills/plutonium-assets/SKILL.md +0 -512
  179. data/.claude/skills/plutonium-controller/SKILL.md +0 -396
  180. data/.claude/skills/plutonium-create-resource/SKILL.md +0 -303
  181. data/.claude/skills/plutonium-definition/SKILL.md +0 -1138
  182. data/.claude/skills/plutonium-entity-scoping/SKILL.md +0 -317
  183. data/.claude/skills/plutonium-forms/SKILL.md +0 -465
  184. data/.claude/skills/plutonium-installation/SKILL.md +0 -325
  185. data/.claude/skills/plutonium-interaction/SKILL.md +0 -413
  186. data/.claude/skills/plutonium-invites/SKILL.md +0 -408
  187. data/.claude/skills/plutonium-model/SKILL.md +0 -440
  188. data/.claude/skills/plutonium-nested-resources/SKILL.md +0 -360
  189. data/.claude/skills/plutonium-package/SKILL.md +0 -198
  190. data/.claude/skills/plutonium-policy/SKILL.md +0 -456
  191. data/.claude/skills/plutonium-portal/SKILL.md +0 -410
  192. data/.claude/skills/plutonium-views/SKILL.md +0 -592
  193. data/docs/reference/assets/index.md +0 -496
  194. data/docs/reference/controller/index.md +0 -412
  195. data/docs/reference/definition/actions.md +0 -449
  196. data/docs/reference/definition/fields.md +0 -383
  197. data/docs/reference/definition/index.md +0 -268
  198. data/docs/reference/definition/query.md +0 -351
  199. data/docs/reference/generators/index.md +0 -648
  200. data/docs/reference/interaction/index.md +0 -449
  201. data/docs/reference/model/features.md +0 -248
  202. data/docs/reference/model/index.md +0 -218
  203. data/docs/reference/policy/index.md +0 -456
  204. data/docs/reference/portal/index.md +0 -379
  205. data/docs/reference/views/forms.md +0 -411
  206. data/docs/reference/views/index.md +0 -501
@@ -1,449 +0,0 @@
1
- # Definition Actions
2
-
3
- Complete reference for custom actions in definitions.
4
-
5
- ## Overview
6
-
7
- Actions add buttons beyond standard CRUD operations. Two types:
8
-
9
- 1. **Simple Actions** - Navigate to URLs
10
- 2. **Interactive Actions** - Execute Interactions with optional user input
11
-
12
- ## Action Types
13
-
14
- | Type | Shows In | Use Case |
15
- |------|----------|----------|
16
- | `resource_action` | Index page | Import, Export, Create |
17
- | `record_action` | Show page | Edit, Delete, Archive |
18
- | `collection_record_action` | Table rows | Quick actions per row |
19
- | `bulk_action` | Selected records | Bulk operations |
20
-
21
- ## Simple Actions
22
-
23
- Simple actions link to existing routes. The target route must already exist.
24
-
25
- ```ruby
26
- class PostDefinition < Plutonium::Resource::Definition
27
- # Link to external URL
28
- action :documentation,
29
- label: "Documentation",
30
- route_options: {url: "https://docs.example.com"},
31
- icon: Phlex::TablerIcons::Book,
32
- resource_action: true
33
-
34
- # Link to custom controller action
35
- action :reports,
36
- route_options: {action: :reports},
37
- icon: Phlex::TablerIcons::ChartBar,
38
- resource_action: true
39
- end
40
- ```
41
-
42
- ::: warning Always Name Custom Routes
43
- When adding custom routes for actions, always use the `as:` option:
44
-
45
- ```ruby
46
- resources :posts do
47
- collection do
48
- get :reports, as: :reports # Named route required!
49
- end
50
- end
51
- ```
52
-
53
- This ensures `resource_url_for` can generate correct URLs, especially for nested resources.
54
- :::
55
-
56
- **Note:** For custom operations with business logic, use **Interactive Actions** with an Interaction class.
57
-
58
- ## Interactive Actions
59
-
60
- ```ruby
61
- class PostDefinition < Plutonium::Resource::Definition
62
- action :publish,
63
- interaction: PublishInteraction,
64
- icon: Phlex::TablerIcons::Send
65
-
66
- action :archive,
67
- interaction: ArchiveInteraction,
68
- color: :danger,
69
- category: :danger,
70
- position: 1000,
71
- confirmation: "Are you sure?"
72
- end
73
- ```
74
-
75
- ## Action Options
76
-
77
- ```ruby
78
- action :name,
79
- # Display
80
- label: "Custom Label", # Button text (default: name.titleize)
81
- description: "What it does", # Tooltip/description
82
- icon: Phlex::TablerIcons::Star, # Icon component
83
-
84
- # Styling
85
- color: :danger, # :primary, :secondary, :danger
86
-
87
- # Visibility (boolean flags)
88
- resource_action: true, # Show on index page
89
- record_action: true, # Show on show page
90
- collection_record_action: true, # Show in table rows
91
- bulk_action: true, # For selected records
92
-
93
- # Grouping
94
- category: :primary, # :primary, :secondary, :danger
95
- position: 50, # Order (lower = first)
96
-
97
- # Behavior
98
- confirmation: "Are you sure?", # Confirmation dialog
99
- turbo_frame: "_top", # Turbo frame target
100
- return_to: "/custom/path", # Override return URL
101
- route_options: {action: :foo} # Route configuration
102
- ```
103
-
104
- ## Route Options
105
-
106
- Configure how the action's URL is generated:
107
-
108
- ```ruby
109
- # Simple route to controller action
110
- action :preview,
111
- route_options: {action: :preview},
112
- record_action: true
113
-
114
- # With HTTP method
115
- action :archive,
116
- route_options: {method: :post, action: :archive},
117
- record_action: true
118
-
119
- # External URL
120
- action :docs,
121
- route_options: {url: "https://docs.example.com"},
122
- resource_action: true
123
-
124
- # Custom URL resolver
125
- action :create_deployment,
126
- route_options: Plutonium::Action::RouteOptions.new(
127
- url_resolver: ->(subject) {
128
- resource_url_for(Deployment, action: :new, parent: subject)
129
- }
130
- ),
131
- record_action: true
132
- ```
133
-
134
- ## Built-in CRUD Actions
135
-
136
- These are defined by default:
137
-
138
- ```ruby
139
- action :new,
140
- route_options: {action: :new},
141
- resource_action: true,
142
- category: :primary,
143
- icon: Phlex::TablerIcons::Plus,
144
- position: 10
145
-
146
- action :show,
147
- route_options: {action: :show},
148
- collection_record_action: true,
149
- icon: Phlex::TablerIcons::Eye,
150
- position: 10
151
-
152
- action :edit,
153
- route_options: {action: :edit},
154
- record_action: true,
155
- collection_record_action: true,
156
- icon: Phlex::TablerIcons::Edit,
157
- position: 20
158
-
159
- action :destroy,
160
- route_options: {method: :delete},
161
- record_action: true,
162
- collection_record_action: true,
163
- category: :danger,
164
- icon: Phlex::TablerIcons::Trash,
165
- position: 100,
166
- confirmation: "Are you sure?",
167
- turbo_frame: "_top"
168
- ```
169
-
170
- ### Customizing Built-in Actions
171
-
172
- Override in your definition:
173
-
174
- ```ruby
175
- class PostDefinition < Plutonium::Resource::Definition
176
- # Customize delete confirmation
177
- action :destroy,
178
- confirmation: "This will permanently delete the post and all comments.",
179
- route_options: {method: :delete},
180
- record_action: true,
181
- collection_record_action: true,
182
- category: :danger,
183
- icon: Phlex::TablerIcons::Trash,
184
- position: 100,
185
- turbo_frame: "_top"
186
- end
187
- ```
188
-
189
- ## Authorization
190
-
191
- Actions are authorized via policies:
192
-
193
- ```ruby
194
- # app/policies/post_policy.rb
195
- class PostPolicy < Plutonium::Resource::Policy
196
- def publish?
197
- user.admin? || record.author == user
198
- end
199
-
200
- def archive?
201
- user.admin?
202
- end
203
- end
204
- ```
205
-
206
- The action only appears if the policy method returns `true`.
207
-
208
- ## Immediate vs Form Actions
209
-
210
- **Immediate** - Executes without showing a form (when interaction has no extra inputs):
211
-
212
- ```ruby
213
- class ArchiveInteraction < Plutonium::Resource::Interaction
214
- attribute :resource # Only resource, no other inputs
215
- # No input declarations
216
-
217
- def execute
218
- resource.archived!
219
- succeed(resource)
220
- end
221
- end
222
- ```
223
-
224
- **Form** - Shows a form first (when interaction has additional inputs):
225
-
226
- ```ruby
227
- class InviteUserInteraction < Plutonium::Resource::Interaction
228
- attribute :resource
229
- attribute :email
230
- attribute :role
231
-
232
- input :email
233
- input :role, as: :select, choices: %w[admin member]
234
- # Has inputs = shows form first
235
- end
236
- ```
237
-
238
- ## Interaction Reference
239
-
240
- ### Basic Structure
241
-
242
- ```ruby
243
- class PublishInteraction < Plutonium::Resource::Interaction
244
- presents label: "Publish",
245
- icon: Phlex::TablerIcons::Send,
246
- description: "Make this post public"
247
-
248
- attribute :resource # The record being acted upon
249
-
250
- private
251
-
252
- def execute
253
- resource.update!(published: true, published_at: Time.current)
254
- succeed(resource).with_message("Published!")
255
- rescue ActiveRecord::RecordInvalid => e
256
- failed(e.record.errors)
257
- end
258
- end
259
- ```
260
-
261
- ### With User Input
262
-
263
- ```ruby
264
- class InviteUserInteraction < Plutonium::Resource::Interaction
265
- presents label: "Invite User", icon: Phlex::TablerIcons::Mail
266
-
267
- attribute :resource # The company
268
- attribute :email
269
- attribute :role
270
-
271
- input :email, as: :email
272
- input :role, as: :select, choices: %w[admin member viewer]
273
-
274
- validates :email, presence: true, format: {with: URI::MailTo::EMAIL_REGEXP}
275
- validates :role, presence: true
276
-
277
- private
278
-
279
- def execute
280
- UserInvite.create!(
281
- company: resource,
282
- email: email,
283
- role: role
284
- )
285
- succeed(resource).with_message("Invitation sent to #{email}.")
286
- rescue ActiveRecord::RecordInvalid => e
287
- failed(e.record.errors)
288
- end
289
- end
290
- ```
291
-
292
- ### Bulk Action
293
-
294
- Bulk actions operate on multiple selected records. When registered, the resource table automatically shows:
295
- - **Selection checkboxes** in each row
296
- - **Bulk actions toolbar** that appears when records are selected
297
-
298
- ```ruby
299
- class BulkArchiveInteraction < Plutonium::Resource::Interaction
300
- presents label: "Archive Selected", icon: Phlex::TablerIcons::Archive
301
-
302
- attribute :resources # Array of records (note: plural)
303
-
304
- private
305
-
306
- def execute
307
- count = 0
308
- resources.each do |record|
309
- record.archived!
310
- count += 1
311
- end
312
- succeed(resources).with_message("#{count} records archived.")
313
- end
314
- end
315
- ```
316
-
317
- Register in definition:
318
-
319
- ```ruby
320
- class PostDefinition < ResourceDefinition
321
- action :bulk_archive, interaction: BulkArchiveInteraction
322
- # bulk_action: true is automatically inferred from `resources` attribute
323
- end
324
- ```
325
-
326
- Add the policy method (checked per-record):
327
-
328
- ```ruby
329
- class PostPolicy < ResourcePolicy
330
- def bulk_archive?
331
- # Can use record attributes - checked for each selected record
332
- user.admin? || record.author == user
333
- end
334
- end
335
- ```
336
-
337
- ::: tip Bulk Action Authorization
338
- Bulk actions use **per-record authorization**:
339
- - Policy method (e.g., `bulk_archive?`) is checked for **each selected record** - you can use `record` attributes
340
- - Backend rejects the entire request if any record fails authorization
341
- - UI only shows actions that **all** selected records support
342
- :::
343
-
344
- ### Resource Action (No Record)
345
-
346
- ```ruby
347
- class ImportInteraction < Plutonium::Resource::Interaction
348
- presents label: "Import CSV", icon: Phlex::TablerIcons::Upload
349
-
350
- # No :resource or :resources = resource action
351
- attribute :file
352
-
353
- input :file, as: :file
354
-
355
- validates :file, presence: true
356
-
357
- private
358
-
359
- def execute
360
- # Import logic...
361
- succeed(nil).with_message("Import completed.")
362
- end
363
- end
364
- ```
365
-
366
- ## Interaction Responses
367
-
368
- ```ruby
369
- def execute
370
- # Success with message (redirects to resource automatically)
371
- succeed(resource).with_message("Done!")
372
-
373
- # Success with custom redirect (only if different from default)
374
- succeed(resource)
375
- .with_redirect_response(custom_dashboard_path)
376
- .with_message("Redirecting...")
377
-
378
- # Failure with field errors
379
- failed(resource.errors)
380
-
381
- # Failure with custom message
382
- failed("Something went wrong")
383
- end
384
- ```
385
-
386
- ::: tip Automatic Redirect
387
- Redirect is automatic on success. You can use `with_redirect_response` for a different destination.
388
- :::
389
-
390
- ## Inherited Actions
391
-
392
- Actions defined in `ResourceDefinition` are inherited by all definitions:
393
-
394
- ```ruby
395
- # app/definitions/resource_definition.rb
396
- class ResourceDefinition < Plutonium::Resource::Definition
397
- action :archive,
398
- interaction: ArchiveInteraction,
399
- color: :danger,
400
- position: 1000
401
- end
402
-
403
- # All definitions inherit the archive action automatically
404
- class PostDefinition < ResourceDefinition
405
- end
406
- ```
407
-
408
- ## Portal-Specific Actions
409
-
410
- Override actions for a specific portal:
411
-
412
- ```ruby
413
- # packages/admin_portal/app/definitions/admin_portal/post_definition.rb
414
- class AdminPortal::PostDefinition < ::PostDefinition
415
- # Add admin-only actions
416
- action :feature, interaction: FeaturePostInteraction
417
- action :bulk_publish, interaction: BulkPublishInteraction
418
- end
419
- ```
420
-
421
- ## Common Patterns
422
-
423
- ### Archive/Restore
424
-
425
- ```ruby
426
- action :archive,
427
- interaction: ArchiveInteraction,
428
- record_action: true,
429
- color: :danger
430
-
431
- action :restore,
432
- interaction: RestoreInteraction,
433
- record_action: true
434
- ```
435
-
436
- ### Export
437
-
438
- ```ruby
439
- action :export,
440
- interaction: ExportInteraction,
441
- resource_action: true,
442
- icon: Phlex::TablerIcons::Download
443
- ```
444
-
445
- ## Related
446
-
447
- - [Definition Reference](./index)
448
- - [Fields Reference](./fields)
449
- - [Query Reference](./query)