plutonium 0.65.0 → 0.66.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 +43 -43
- data/.claude/skills/plutonium-app/SKILL.md +101 -59
- data/.claude/skills/plutonium-async-interactions/SKILL.md +19 -19
- data/.claude/skills/plutonium-auth/SKILL.md +119 -53
- data/.claude/skills/plutonium-behavior/SKILL.md +110 -78
- data/.claude/skills/plutonium-dashboard/SKILL.md +11 -4
- data/.claude/skills/plutonium-kanban/SKILL.md +81 -49
- data/.claude/skills/plutonium-resource/SKILL.md +144 -133
- data/.claude/skills/plutonium-tenancy/SKILL.md +104 -55
- data/.claude/skills/plutonium-testing/SKILL.md +130 -33
- data/.claude/skills/plutonium-ui/SKILL.md +151 -96
- data/.claude/skills/plutonium-wizard/SKILL.md +93 -82
- data/CHANGELOG.md +21 -0
- data/README.md +9 -9
- data/SECURITY.md +1 -1
- data/app/assets/plutonium.css +1 -1
- data/docs/.vitepress/sync-skills.mjs +6 -3
- data/docs/blog/introducing-plutonium-dashboards.md +4 -5
- data/docs/blog/introducing-plutonium-i18n.md +4 -5
- data/docs/getting-started/installation.md +5 -5
- data/docs/getting-started/tutorial/02-first-resource.md +3 -3
- data/docs/getting-started/tutorial/03-authentication.md +7 -7
- data/docs/getting-started/tutorial/04-authorization.md +21 -4
- data/docs/getting-started/tutorial/05-custom-actions.md +2 -2
- data/docs/getting-started/tutorial/06-nested-resources.md +5 -2
- data/docs/getting-started/tutorial/07-author-portal.md +2 -2
- data/docs/getting-started/tutorial/08-customizing-ui.md +45 -30
- data/docs/getting-started/tutorial/index.md +1 -1
- data/docs/guides/adding-resources.md +10 -7
- data/docs/guides/authentication.md +25 -25
- data/docs/guides/authorization.md +24 -24
- data/docs/guides/creating-packages.md +17 -17
- data/docs/guides/custom-actions.md +32 -32
- data/docs/guides/customizing-ui.md +29 -26
- data/docs/guides/dashboards.md +1 -1
- data/docs/guides/index.md +3 -3
- data/docs/guides/kanban.md +55 -55
- data/docs/guides/multi-tenancy.md +35 -22
- data/docs/guides/nested-resources.md +21 -21
- data/docs/guides/performance.md +3 -3
- data/docs/guides/search-filtering.md +13 -13
- data/docs/guides/testing.md +16 -12
- data/docs/guides/theming.md +32 -17
- data/docs/guides/troubleshooting.md +2 -2
- data/docs/guides/user-invites.md +17 -17
- data/docs/guides/user-profile.md +51 -24
- data/docs/guides/wizards.md +55 -55
- data/docs/reference/app/generators.md +22 -22
- data/docs/reference/app/index.md +15 -18
- data/docs/reference/app/packages.md +8 -8
- data/docs/reference/app/portals.md +75 -29
- data/docs/reference/auth/accounts.md +15 -15
- data/docs/reference/auth/index.md +12 -12
- data/docs/reference/auth/profile.md +67 -29
- data/docs/reference/behavior/async-interactions.md +24 -24
- data/docs/reference/behavior/controllers.md +28 -28
- data/docs/reference/behavior/index.md +5 -5
- data/docs/reference/behavior/interactions.md +44 -44
- data/docs/reference/behavior/policies.md +48 -28
- data/docs/reference/configuration.md +6 -6
- data/docs/reference/dashboard/dsl.md +2 -2
- data/docs/reference/dashboard/index.md +1 -1
- data/docs/reference/generators/lite.md +7 -7
- data/docs/reference/i18n.md +23 -0
- data/docs/reference/index.md +1 -1
- data/docs/reference/kanban/authorization.md +9 -9
- data/docs/reference/kanban/dsl.md +32 -32
- data/docs/reference/kanban/index.md +1 -1
- data/docs/reference/kanban/positioning.md +17 -15
- data/docs/reference/resource/actions.md +51 -51
- data/docs/reference/resource/definition.md +73 -73
- data/docs/reference/resource/export.md +6 -6
- data/docs/reference/resource/index.md +16 -16
- data/docs/reference/resource/model.md +24 -24
- data/docs/reference/resource/positioning.md +78 -76
- data/docs/reference/resource/query.md +13 -13
- data/docs/reference/tenancy/entity-scoping.md +65 -35
- data/docs/reference/tenancy/index.md +11 -11
- data/docs/reference/tenancy/invites.md +20 -20
- data/docs/reference/tenancy/nested-resources.md +13 -13
- data/docs/reference/testing/index.md +116 -22
- data/docs/reference/ui/assets.md +57 -25
- data/docs/reference/ui/components.md +20 -20
- data/docs/reference/ui/displays.md +14 -14
- data/docs/reference/ui/forms.md +35 -35
- data/docs/reference/ui/index.md +17 -15
- data/docs/reference/ui/layouts.md +21 -21
- data/docs/reference/ui/pages.md +22 -22
- data/docs/reference/ui/tables.md +7 -7
- data/docs/reference/wizard/anchoring-resume.md +33 -32
- data/docs/reference/wizard/dsl.md +44 -44
- data/docs/reference/wizard/index.md +6 -6
- data/docs/reference/wizard/one-time.md +18 -18
- data/docs/reference/wizard/registration-launch.md +32 -32
- data/docs/reference/wizard/storage-config.md +23 -23
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/generators/pu/profile/conn_generator.rb +6 -0
- data/lib/plutonium/resource/record/associated_with.rb +23 -2
- data/lib/plutonium/ui/form/concerns/typeahead_attributes.rb +7 -1
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- data/src/css/components.css +10 -10
- metadata +2 -2
|
@@ -11,25 +11,25 @@ All resource models inherit from `ResourceRecord` (created by `pu:core:install`)
|
|
|
11
11
|
class Post < ResourceRecord
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
# Inside a feature package
|
|
14
|
+
# Inside a feature package: uses the package's ResourceRecord
|
|
15
15
|
module Blogging
|
|
16
16
|
class Post < Blogging::ResourceRecord
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
`ResourceRecord` is abstract and inherits from `ApplicationRecord`. Standard ActiveRecord features (associations, validations, scopes, callbacks, attribute macros) all work
|
|
21
|
+
`ResourceRecord` is abstract and inherits from `ApplicationRecord`. Standard ActiveRecord features (associations, validations, scopes, callbacks, attribute macros) all work; Plutonium adds capabilities on top.
|
|
22
22
|
|
|
23
23
|
## What `Plutonium::Resource::Record` adds
|
|
24
24
|
|
|
25
25
|
| Module | Purpose | Section |
|
|
26
26
|
|---|---|---|
|
|
27
|
-
| `HasCents` | Money handling
|
|
27
|
+
| `HasCents` | Money handling: cents column ↔ decimal accessor | [has_cents](#has-cents) |
|
|
28
28
|
| `Routes` | URL parameter customization (slugs, dynamic params) | [URL routing](#url-routing) |
|
|
29
29
|
| `Labeling` | `to_label` for human-readable record names | [Labeling](#labeling) |
|
|
30
30
|
| `FieldNames` | Field introspection by category | [Field introspection](#field-introspection) |
|
|
31
31
|
| `Associations` | Auto-generated SGID accessors on every association | [SGID accessors](#sgid-accessors) |
|
|
32
|
-
| `AssociatedWith` | Multi-tenant scoping
|
|
32
|
+
| `AssociatedWith` | Multi-tenant scoping: `Model.associated_with(entity)` | [Tenancy](/reference/tenancy/entity-scoping) |
|
|
33
33
|
|
|
34
34
|
## Section layout
|
|
35
35
|
|
|
@@ -89,7 +89,7 @@ end
|
|
|
89
89
|
|
|
90
90
|
## `has_cents`
|
|
91
91
|
|
|
92
|
-
Stores monetary values as integer cents and exposes a decimal virtual accessor. Use this for money
|
|
92
|
+
Stores monetary values as integer cents and exposes a decimal virtual accessor. Use this for money; never store decimals directly.
|
|
93
93
|
|
|
94
94
|
```ruby
|
|
95
95
|
class Product < ResourceRecord
|
|
@@ -112,16 +112,16 @@ product.price = 10.999
|
|
|
112
112
|
product.price_cents # => 1099
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
**Currency symbol (`unit:`)
|
|
115
|
+
**Currency symbol (`unit:`).** A `String` is used verbatim (`unit: "£"`); a `Symbol`
|
|
116
116
|
names a method read off the record for per-row currencies (`unit: :currency_symbol`
|
|
117
117
|
→ `record.currency_symbol`); `false` explicitly renders no symbol. This unit is picked
|
|
118
|
-
up automatically anywhere the value renders as currency
|
|
119
|
-
grid/kanban cards
|
|
118
|
+
up automatically anywhere the value renders as currency (show pages, tables, and
|
|
119
|
+
grid/kanban cards), so you configure it once on the model. A per-display
|
|
120
120
|
`display :price, as: :currency, unit: …` overrides it for that display.
|
|
121
121
|
|
|
122
122
|
A `has_cents` field also **infers the currency input** on forms: a bare `input :price`
|
|
123
123
|
renders the [currency input](../ui/forms#currency-fields) (number field + unit prefix),
|
|
124
|
-
no `as: :currency` needed
|
|
124
|
+
no `as: :currency` needed, matching the display side.
|
|
125
125
|
|
|
126
126
|
Resolution is `display unit → has_cents unit → config default`, where `nil` means
|
|
127
127
|
"not set, keep looking" and `false` means "stop, no symbol". When nothing is set, it
|
|
@@ -148,7 +148,7 @@ end
|
|
|
148
148
|
field :price, as: :decimal # ✅ virtual name
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
-
Generators sometimes emit the `_cents` name in the policy
|
|
151
|
+
Generators sometimes emit the `_cents` name in the policy; fix by hand (and verify `has_cents` is declared on the model).
|
|
152
152
|
:::
|
|
153
153
|
|
|
154
154
|
### Options
|
|
@@ -176,7 +176,7 @@ product.errors[:price_cents] # => ["must be greater than 0"]
|
|
|
176
176
|
product.errors[:price] # => ["is invalid"]
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
-
The framework adds an `after_validation` hook that copies `:invalid` from `price_cents` → `price` automatically
|
|
179
|
+
The framework adds an `after_validation` hook that copies `:invalid` from `price_cents` → `price` automatically, no manual wiring needed.
|
|
180
180
|
|
|
181
181
|
### Introspection
|
|
182
182
|
|
|
@@ -196,7 +196,7 @@ post.to_param # => "1" (numeric id)
|
|
|
196
196
|
# URL: /posts/1
|
|
197
197
|
```
|
|
198
198
|
|
|
199
|
-
### `path_parameter
|
|
199
|
+
### `path_parameter`: use a stable column
|
|
200
200
|
|
|
201
201
|
Use a column that's unique and human-readable instead of the numeric id:
|
|
202
202
|
|
|
@@ -212,9 +212,9 @@ user.to_param # => "john_doe"
|
|
|
212
212
|
User.from_path_param("john_doe") # finds by username
|
|
213
213
|
```
|
|
214
214
|
|
|
215
|
-
`path_parameter` is a class-level macro (private class method). The column you pass MUST be unique
|
|
215
|
+
`path_parameter` is a class-level macro (private class method). The column you pass MUST be unique; Plutonium uses it for lookup.
|
|
216
216
|
|
|
217
|
-
### `dynamic_path_parameter
|
|
217
|
+
### `dynamic_path_parameter`: SEO-friendly id + slug
|
|
218
218
|
|
|
219
219
|
Combines the id (for stable lookup) with a slug from another column (for SEO):
|
|
220
220
|
|
|
@@ -230,7 +230,7 @@ article.to_param # => "42-hello-world"
|
|
|
230
230
|
Article.from_path_param("42-hello-world") # extracts "42", finds by id
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
The slug is informational
|
|
233
|
+
The slug is informational: only the id portion is used for lookup, so changing the title doesn't break old URLs.
|
|
234
234
|
|
|
235
235
|
## Labeling
|
|
236
236
|
|
|
@@ -262,7 +262,7 @@ end
|
|
|
262
262
|
|
|
263
263
|
## SGID accessors
|
|
264
264
|
|
|
265
|
-
Every association on a resource model gets Signed Global ID accessors automatically
|
|
265
|
+
Every association on a resource model gets Signed Global ID accessors automatically, for secure form submission, API payloads, and hidden fields without exposing database ids.
|
|
266
266
|
|
|
267
267
|
### Singular associations (`belongs_to`, `has_one`)
|
|
268
268
|
|
|
@@ -292,7 +292,7 @@ user.add_post_sgid(sgid) # append
|
|
|
292
292
|
user.remove_post_sgid(sgid) # remove
|
|
293
293
|
```
|
|
294
294
|
|
|
295
|
-
These are what `secure_association_tag` uses in forms
|
|
295
|
+
These are what `secure_association_tag` uses in forms; see [UI › Forms](/reference/ui/forms).
|
|
296
296
|
|
|
297
297
|
## Field introspection
|
|
298
298
|
|
|
@@ -335,11 +335,11 @@ Resolution order, association path requirements, three model shapes, and custom
|
|
|
335
335
|
|
|
336
336
|
## Standard ActiveRecord features
|
|
337
337
|
|
|
338
|
-
Everything you'd expect works
|
|
338
|
+
Everything you'd expect works: associations, validations, scopes, callbacks, delegations, `has_rich_text`, `has_secure_token`, `has_one_attached`, etc. Where Plutonium adds twists:
|
|
339
339
|
|
|
340
|
-
- **Section ordering** is by convention, not enforcement
|
|
341
|
-
- **Compound uniqueness for tenant-scoped resources:** `validates :code, uniqueness: {scope: :organization_id}
|
|
342
|
-
- **Keep models thin
|
|
340
|
+
- **Section ordering** is by convention, not enforcement: pick the right slot in the [layout above](#section-layout) so the file stays scannable.
|
|
341
|
+
- **Compound uniqueness for tenant-scoped resources:** `validates :code, uniqueness: {scope: :organization_id}`, without the scope, uniqueness leaks across tenants.
|
|
342
|
+
- **Keep models thin**: business logic that touches multiple records or has multi-step state changes belongs in [interactions](/reference/behavior/interactions), not model methods.
|
|
343
343
|
|
|
344
344
|
## Nested resources
|
|
345
345
|
|
|
@@ -369,6 +369,6 @@ Override with `self.table_name = "posts"` if you need a shared table.
|
|
|
369
369
|
|
|
370
370
|
## Related
|
|
371
371
|
|
|
372
|
-
- [Definition](./definition)
|
|
373
|
-
- [Tenancy › Entity scoping](/reference/tenancy/entity-scoping)
|
|
374
|
-
- [App › Generators](/reference/app/generators)
|
|
372
|
+
- [Definition](./definition): controls how the model's fields render
|
|
373
|
+
- [Tenancy › Entity scoping](/reference/tenancy/entity-scoping): `associated_with`, three model shapes
|
|
374
|
+
- [App › Generators](/reference/app/generators): `pu:res:scaffold` field syntax
|