plutonium 0.56.0 → 0.56.2

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/skills/plutonium/SKILL.md +1 -1
  3. data/.claude/skills/plutonium-app/SKILL.md +1 -1
  4. data/.claude/skills/plutonium-auth/SKILL.md +1 -1
  5. data/.claude/skills/plutonium-resource/SKILL.md +35 -1
  6. data/CHANGELOG.md +19 -0
  7. data/CONTRIBUTING.md +1 -1
  8. data/README.md +38 -16
  9. data/app/assets/plutonium.css +1 -1
  10. data/docs/getting-started/installation.md +2 -2
  11. data/docs/getting-started/tutorial/02-first-resource.md +1 -1
  12. data/docs/getting-started/tutorial/03-authentication.md +3 -3
  13. data/docs/guides/adding-resources.md +1 -1
  14. data/docs/guides/authentication.md +1 -1
  15. data/docs/guides/creating-packages.md +1 -1
  16. data/docs/guides/multi-tenancy.md +1 -1
  17. data/docs/guides/nested-resources.md +1 -1
  18. data/docs/guides/user-invites.md +1 -1
  19. data/docs/guides/user-profile.md +1 -1
  20. data/docs/reference/app/generators.md +3 -3
  21. data/docs/reference/app/index.md +1 -1
  22. data/docs/reference/app/portals.md +1 -1
  23. data/docs/reference/auth/profile.md +1 -1
  24. data/docs/reference/resource/actions.md +55 -0
  25. data/docs/reference/resource/index.md +1 -1
  26. data/docs/reference/tenancy/invites.md +1 -1
  27. data/gemfiles/rails_7.gemfile.lock +1 -1
  28. data/gemfiles/rails_8.0.gemfile.lock +1 -1
  29. data/gemfiles/rails_8.1.gemfile.lock +1 -1
  30. data/lib/generators/pu/core/typespec/typespec_generator.rb +1 -1
  31. data/lib/generators/pu/core/update/update_generator.rb +10 -1
  32. data/lib/generators/pu/saas/welcome_generator.rb +1 -1
  33. data/lib/plutonium/action/base.rb +19 -2
  34. data/lib/plutonium/action/condition_context.rb +33 -0
  35. data/lib/plutonium/ui/grid/card.rb +3 -2
  36. data/lib/plutonium/ui/page/index.rb +1 -1
  37. data/lib/plutonium/ui/page/show.rb +1 -1
  38. data/lib/plutonium/ui/table/components/pagy_pagination.rb +3 -3
  39. data/lib/plutonium/ui/table/resource.rb +2 -2
  40. data/lib/plutonium/version.rb +1 -1
  41. data/package.json +1 -1
  42. metadata +2 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fdb3a70cfc50828cc986040543d72e8e576497deffb3304aac601b113c507370
4
- data.tar.gz: 7901dd81e5a9f11519224695071e1fe76c3121e8d311d1b1d6d7445fb2179667
3
+ metadata.gz: 7932a8a7af49201798eaf8727c03857ab7b7b3490a7ce049acd89cf8efeeda38
4
+ data.tar.gz: 4a268a9cd14ae441ca664c249a3b602f2509aa63f38b9e76a4fd06b0d56fc3a3
5
5
  SHA512:
6
- metadata.gz: 3d89dc0f91a27bb0e0e1ac5503cb11059d35309767fa006c200216819e0c123d6d2a558a03ac162964527b992fabc974184d5f357f3b0389405f2c63a13bdfed
7
- data.tar.gz: 584146030273aeac56b898049f4f9e6a05f364c1b334bdca4ef2e044288548f1277c4d419cf7051504d36e0fd32ffbe48a4540c03f7b80f08405f43b4a0313ab
6
+ metadata.gz: eea920321f823c316c2ba4aa226e56e614fc0fc39790ee6ac9dd1893fc2a028d4165782823aab2bb8b4285bdbe868fbb43c68553df2eff74784ce04a6de98bff
7
+ data.tar.gz: 713961bf18c70042aa361e948a72caa918d67e0636f2b632715809f7e48c1d4aa41efe77e4517469d0e6ab8c13270965b9558a59d27e98264149646c5b757ea0
@@ -127,7 +127,7 @@ Meta-generators (`pu:saas:setup`) propagate flags to the generators they chain.
127
127
 
128
128
  1. **Load the bootstrap bundle** (or the targeted skill from the router table).
129
129
  2. **Generate** — `rails g pu:res:scaffold Model field:type ... --dest=main_app`.
130
- 3. **Migrate** — `rails db:migrate`.
130
+ 3. **Migrate** — `rails db:prepare`.
131
131
  4. **Connect** — `rails g pu:res:conn Model --dest=portal_name`.
132
132
  5. **Customize** — edit definition / policy as needed.
133
133
  6. **Verify** — hit the route in the browser.
@@ -62,7 +62,7 @@ rails generate pu:pkg:portal admin --auth=user
62
62
 
63
63
  # 4. First resource
64
64
  rails generate pu:res:scaffold Post user:belongs_to title:string 'content:text?' --dest=main_app
65
- rails db:migrate
65
+ rails db:prepare
66
66
 
67
67
  # 5. Connect resource to portal
68
68
  rails generate pu:res:conn Post --dest=admin_portal
@@ -279,7 +279,7 @@ rails g pu:profile:setup date_of_birth:date bio:text \
279
279
  rails generate pu:profile:install bio:text avatar:attachment 'timezone:string?' \
280
280
  --dest=customer
281
281
 
282
- rails db:migrate
282
+ rails db:prepare
283
283
 
284
284
  rails generate pu:profile:conn --dest=customer_portal
285
285
  ```
@@ -29,7 +29,7 @@ For tenancy / `associated_with` / `relation_scope`, load [[plutonium-tenancy]].
29
29
  1. Pick destination: `--dest=main_app` or `--dest=package_name`.
30
30
  2. Run `rails g pu:res:scaffold ResourceName field:type ... --dest=<dest>`.
31
31
  3. Review the generated migration — add cascade deletes, composite indexes, defaults.
32
- 4. `rails db:migrate`.
32
+ 4. `rails db:prepare`.
33
33
  5. `rails g pu:res:conn ResourceName --dest=<portal_name>`.
34
34
  6. Customize the policy's `permitted_attributes_for_*` as needed.
35
35
  7. Open the portal route in the browser.
@@ -1050,6 +1050,10 @@ action :name,
1050
1050
  collection_record_action: true,
1051
1051
  bulk_action: true,
1052
1052
 
1053
+ # Conditional visibility — display-only toggle, NOT authorization (see below).
1054
+ # `-> { false }` keeps the route live but hides the button (e.g. API-only).
1055
+ condition: -> { params[:beta] == "1" },
1056
+
1053
1057
  # Grouping
1054
1058
  category: :primary, # :primary, :secondary, :danger
1055
1059
  position: 50,
@@ -1062,6 +1066,36 @@ action :name,
1062
1066
  size: :lg # :sm / :md / :lg / :xl / :auto / :full — overrides definition's modal size
1063
1067
  ```
1064
1068
 
1069
+ ### Conditional Actions (`condition:`)
1070
+
1071
+ Like `condition:` on inputs/displays/columns — define an action but render its **button** only when a runtime proc is truthy. The action and its route stay live either way; `condition:` only toggles the UI.
1072
+
1073
+ Headline use case: **expose an action's endpoint without a button** — one you call from the API, a webhook, or another service. Hide it with an always-falsy condition; the route still works:
1074
+
1075
+ ```ruby
1076
+ # Defined and callable (API / programmatic), but no button anywhere:
1077
+ action :sync_inventory, interaction: SyncInventoryInteraction, condition: -> { false }
1078
+
1079
+ # Per-record display state — object is the row/shown record:
1080
+ action :reopen, interaction: ReopenInteraction, condition: -> { object.closed? }
1081
+
1082
+ # View/request-level toggle (feature flag, beta mode):
1083
+ action :preview, interaction: PreviewInteraction, condition: -> { params[:beta] == "1" }
1084
+ ```
1085
+
1086
+ Inside the proc, `object`/`record` is the contextual record — the row/shown record for **record** and **collection-record** actions, **nil** for **resource** and **bulk** actions (guard with `object&.…` if shared). Every other call delegates to the **view context**: `current_user`, `current_parent`, `params`, `request`, `allowed_to?`, `resource_record!`, etc. `object` is evaluated per row in tables/grids, so per-record show/hide works there.
1087
+
1088
+ 🚨 **`condition:` is NOT authorization — it only hides the button.** A hidden action still has a live route; anyone with the URL can trigger it. "Who may run this" belongs in the policy:
1089
+
1090
+ ```ruby
1091
+ # 🚫 WRONG — does not stop non-admins; the route is live.
1092
+ action :wipe, interaction: WipeInteraction, condition: -> { current_user.admin? }
1093
+ # ✅ RIGHT — authorization in the policy, enforced regardless of condition:
1094
+ def wipe? = current_user.admin?
1095
+ ```
1096
+
1097
+ The two compose: an action's button shows only when the policy permits **and** the condition is truthy; execution is gated by the policy alone. Use `object` in `condition:` for per-record *display*; use the policy for per-record *authorization*.
1098
+
1065
1099
  `Action#with(...)` — actions are frozen value objects; clone with overrides:
1066
1100
 
1067
1101
  ```ruby
data/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ ## [0.56.2] - 2026-06-05
2
+
3
+ ### 🐛 Bug Fixes
4
+
5
+ - *(generators/update)* Run skills sync in unbundled env
6
+ - *(ui/pagination)* Prevent large page numbers from overflowing buttons
7
+ ## [0.56.1] - 2026-06-05
8
+
9
+ ### 🚀 Features
10
+
11
+ - *(actions)* Add display-only condition: to actions
12
+
13
+ ### 🐛 Bug Fixes
14
+
15
+ - *(dummy)* Version-adapt kitchen_sinks migration
16
+
17
+ ### 📚 Documentation
18
+
19
+ - Recommend db:prepare, firm up README, document conditional actions
1
20
  ## [0.56.0] - 2026-06-05
2
21
 
3
22
  ### 🚀 Features
data/CONTRIBUTING.md CHANGED
@@ -153,7 +153,7 @@ Use the dummy app:
153
153
  ```bash
154
154
  cd test/dummy
155
155
  rails g pu:res:scaffold TestModel name:string --dest=main_app
156
- rails db:migrate
156
+ rails db:prepare
157
157
  bin/dev
158
158
  ```
159
159
 
data/README.md CHANGED
@@ -2,8 +2,11 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/plutonium.svg)](https://badge.fury.io/rb/plutonium)
4
4
  [![Ruby](https://github.com/radioactive-labs/plutonium-core/actions/workflows/main.yml/badge.svg)](https://github.com/radioactive-labs/plutonium-core/actions/workflows/main.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE.txt)
5
6
 
6
- Build production-ready Rails apps in minutes, not days. Convention-driven, fully customizable, and AI-ready. Plutonium picks up where Rails left off, adding application-level concepts that make building complex apps faster.
7
+ **The Rails framework for things you should never write again.**
8
+
9
+ Convention over configuration, extended to everything you keep rebuilding: **CRUD. Auth. Authorization. Multi-tenancy. Admin portals. Search, filters, bulk actions.** All generated. All customizable. All Rails.
7
10
 
8
11
  ## Quick Start
9
12
 
@@ -12,20 +15,36 @@ rails new myapp -a propshaft -j esbuild -c tailwind \
12
15
  -m https://radioactive-labs.github.io/plutonium-core/templates/plutonium.rb
13
16
  ```
14
17
 
15
- Then create your first resource:
18
+ Then scaffold a resource, create a portal, and connect them:
16
19
 
17
20
  ```bash
18
21
  cd myapp
19
- rails g pu:res:scaffold Post title:string body:text --dest=main_app
20
- rails db:migrate
22
+
23
+ # Scaffold a resource — model, migration, definition, policy
24
+ rails g pu:res:scaffold Post title:string body:text published_at:datetime --dest=main_app
25
+ rails db:prepare
26
+
27
+ # Create a portal (web interface) and connect the resource to it
28
+ rails g pu:pkg:portal app --public
29
+ rails g pu:res:conn Post --dest=app_portal
30
+
21
31
  bin/dev
22
32
  ```
23
33
 
24
- Visit `http://localhost:3000` - you have a complete CRUD interface.
34
+ Visit `http://localhost:3000/app/posts` you have a complete CRUD interface.
25
35
 
26
- ## What You Get
36
+ ## What You Stop Writing
27
37
 
28
- **Resource-oriented architecture** - Models, policies, definitions, and controllers that work together:
38
+ Same scaffold command you already know. A very different surface area.
39
+
40
+ ```bash
41
+ rails g scaffold Post ... # Rails: just CRUD
42
+ rails g pu:res:scaffold Post ... # Plutonium: full CRUD + search + filters + bulk actions
43
+ ```
44
+
45
+ And it doesn't stop at scaffolds:
46
+
47
+ **Resource-oriented architecture** — models, policies, definitions, and controllers that work together:
29
48
 
30
49
  ```ruby
31
50
  # Policy controls WHO can do WHAT
@@ -47,7 +66,7 @@ class PostDefinition < ResourceDefinition
47
66
  end
48
67
  ```
49
68
 
50
- **Packages for organization** - Split your app into feature packages and portals:
69
+ **Packages and portals** split your app into feature engines and themed web interfaces:
51
70
 
52
71
  ```bash
53
72
  rails g pu:pkg:package blogging # Business logic
@@ -65,7 +84,7 @@ rails g pu:rodauth:account user
65
84
  **Multi-tenancy** with entity scoping:
66
85
 
67
86
  ```ruby
68
- # In portal engine
87
+ # In a portal engine
69
88
  scope_to_entity Organization, strategy: :path
70
89
  # Routes become /organizations/:organization_id/posts
71
90
  ```
@@ -86,6 +105,13 @@ class PublishInteraction < ResourceInteraction
86
105
  end
87
106
  ```
88
107
 
108
+ ## Why Plutonium
109
+
110
+ - **Convention over configuration** — extended to resources, policies, portals, and tenancy, not just routes and views.
111
+ - **It's just Rails** — generated code lives in your repo. Edit it, override it, delete it. The "magic" is regular Ruby mixins you can read.
112
+ - **Multi-tenant ready** — path or domain tenancy, scoped relations, invites and memberships out of the box.
113
+ - **AI-readable** — predictable file layout and naming, plus built-in [Claude Code skills](.claude/skills) that teach AI assistants the patterns.
114
+
89
115
  ## Documentation
90
116
 
91
117
  Full documentation at **[radioactive-labs.github.io/plutonium-core](https://radioactive-labs.github.io/plutonium-core/)**
@@ -97,18 +123,14 @@ Full documentation at **[radioactive-labs.github.io/plutonium-core](https://radi
97
123
 
98
124
  ## Requirements
99
125
 
100
- - Ruby 3.2+
101
- - Rails 7.1+ (Rails 8 recommended)
126
+ - Ruby 3.2.2+
127
+ - Rails 7.2+ (Rails 8 recommended)
102
128
  - Node.js 18+
103
129
 
104
130
  ## Contributing
105
131
 
106
132
  See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
107
133
 
108
- ## Status
109
-
110
- Plutonium is used in production but still evolving. APIs may change between minor versions. Pin your version in Gemfile.
111
-
112
134
  ## License
113
135
 
114
- MIT License - see [LICENSE](LICENSE).
136
+ MIT License see [LICENSE.txt](LICENSE.txt).