plutonium 0.38.0 → 0.39.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-controller/SKILL.md +13 -0
- data/.claude/skills/plutonium-definition-actions/SKILL.md +13 -0
- data/.claude/skills/plutonium-nested-resources/SKILL.md +6 -4
- data/CHANGELOG.md +7 -1
- data/docs/guides/custom-actions.md +14 -0
- data/docs/guides/nested-resources.md +7 -3
- data/docs/og-image.html +84 -0
- data/docs/public/og-image.png +0 -0
- data/docs/reference/controller/index.md +5 -1
- data/docs/reference/definition/actions.md +14 -0
- data/gemfiles/rails_7.gemfile.lock +5 -5
- data/gemfiles/rails_8.0.gemfile.lock +5 -5
- data/gemfiles/rails_8.1.gemfile.lock +5 -5
- data/lib/generators/pu/rodauth/install_generator.rb +7 -11
- data/lib/generators/pu/rodauth/templates/app/rodauth/rodauth_plugin.rb.tt +3 -5
- data/lib/plutonium/auth/sequel_adapter.rb +76 -0
- data/lib/plutonium/core/controller.rb +2 -3
- data/lib/plutonium/resource/controller.rb +3 -2
- data/lib/plutonium/resource/controllers/presentable.rb +4 -2
- data/lib/plutonium/routing/mapper_extensions.rb +9 -6
- data/lib/plutonium/ui/action_button.rb +72 -11
- data/lib/plutonium/ui/actions_dropdown.rb +3 -25
- data/lib/plutonium/ui/breadcrumbs.rb +2 -2
- data/lib/plutonium/ui/component/methods.rb +10 -3
- data/lib/plutonium/ui/form/base.rb +1 -1
- data/lib/plutonium/ui/form/interaction.rb +5 -5
- data/lib/plutonium/ui/form/query.rb +1 -1
- data/lib/plutonium/ui/form/resource.rb +1 -1
- data/lib/plutonium/ui/layout/base.rb +1 -1
- data/lib/plutonium/ui/layout/basic_layout.rb +2 -2
- data/lib/plutonium/ui/layout/resource_layout.rb +2 -2
- data/lib/plutonium/ui/layout/rodauth_layout.rb +2 -2
- data/lib/plutonium/ui/page/index.rb +1 -1
- data/lib/plutonium/ui/page/interactive_action.rb +1 -1
- data/lib/plutonium/ui/table/components/row_actions_dropdown.rb +3 -25
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- data/plutonium.gemspec +2 -2
- metadata +8 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7c8fc50a1fe8c28ef9db4c7bef8b632c2b3c15524be2572085433e7185ed6923
|
|
4
|
+
data.tar.gz: 3dacb628155eeb439002f145c16fac47237ce55f1dc2d90c0253df36ec7f70a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '03919fed054eca767c0904b360c575af0b217b90acabec6688622e17fdfeabccbf024fd6343e8cc51ea0497ac53a37eb483e567063ec08a7a499eeaa86a5e96a'
|
|
7
|
+
data.tar.gz: e810b4a35375822961f4aad503603d3970a4c6217d65f4a9394f5b4952bc860b519bb405c0319dcef4418aa13711c5b04f2a5a0918070a6ad6f6b6cbeacf557b
|
|
@@ -151,6 +151,19 @@ class PostsController < ::ResourceController
|
|
|
151
151
|
end
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
+
**Important:** When adding custom routes, always use the `as:` option to name them:
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
# config/routes.rb or portal routes
|
|
158
|
+
resources :posts do
|
|
159
|
+
member do
|
|
160
|
+
post :publish, as: :publish # Named route required!
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
This ensures `resource_url_for` can generate correct URLs, especially for nested resources.
|
|
166
|
+
|
|
154
167
|
Note: For most custom operations, use Interactive Actions in definitions instead.
|
|
155
168
|
|
|
156
169
|
## Key Methods
|
|
@@ -37,6 +37,19 @@ class PostDefinition < ResourceDefinition
|
|
|
37
37
|
end
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
**Important:** When adding custom routes for actions, always use the `as:` option to name them:
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
# In your portal routes or config/routes.rb
|
|
44
|
+
resources :posts do
|
|
45
|
+
collection do
|
|
46
|
+
get :reports, as: :reports # Named route required!
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This ensures `resource_url_for` can generate correct URLs, especially for nested resources.
|
|
52
|
+
|
|
40
53
|
**Note:** For custom operations with business logic, use **Interactive Actions** with an Interaction class instead. That's the recommended approach for most custom actions.
|
|
41
54
|
|
|
42
55
|
## Interactive Actions (with Interaction)
|
|
@@ -316,15 +316,17 @@ Add custom member/collection routes to nested resources:
|
|
|
316
316
|
```ruby
|
|
317
317
|
register_resource ::Property do
|
|
318
318
|
member do
|
|
319
|
-
get :analytics
|
|
320
|
-
post :archive
|
|
319
|
+
get :analytics, as: :analytics
|
|
320
|
+
post :archive, as: :archive
|
|
321
321
|
end
|
|
322
322
|
end
|
|
323
323
|
```
|
|
324
324
|
|
|
325
|
+
**Important:** Always use the `as:` option to name custom routes. This ensures `resource_url_for` can generate correct URLs for nested resources. Without named routes, URL generation will fail.
|
|
326
|
+
|
|
325
327
|
Generates nested routes:
|
|
326
|
-
- `/companies/:company_id/
|
|
327
|
-
- `/companies/:company_id/
|
|
328
|
+
- `/companies/:company_id/nested_properties/:id/analytics`
|
|
329
|
+
- `/companies/:company_id/nested_properties/:id/archive`
|
|
328
330
|
|
|
329
331
|
## Related Skills
|
|
330
332
|
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
## [0.
|
|
1
|
+
## [0.39.0] - 2026-01-26
|
|
2
2
|
|
|
3
3
|
### 🚀 Features
|
|
4
4
|
|
|
@@ -14,9 +14,14 @@
|
|
|
14
14
|
- Remove duplicate kv store controller and move improvements into original
|
|
15
15
|
- *(filters)* Improve association filter class resolution
|
|
16
16
|
- *(ui)* Improve dropdown positioning with viewport boundary
|
|
17
|
+
- *(auth)* Dynamically detect database adapter for Rodauth (#51)
|
|
17
18
|
- *(crud)* Use correct action attributes for form re-rendering on errors
|
|
18
19
|
- *(form)* Distinguish empty vs not-submitted key-value store fields
|
|
19
20
|
- *(controller)* Use existing record context for form param extraction
|
|
21
|
+
- *(controller)* Prevent UrlGenerationError when extracting params for nested resource update
|
|
22
|
+
- *(routing)* Correct URL generation for interactive actions on nested resources
|
|
23
|
+
- *(ui)* Replace deprecated phlex-rails `helpers` method with `view_context`
|
|
24
|
+
- *(routing)* Add named routes for commit actions and document route naming requirement
|
|
20
25
|
|
|
21
26
|
### 📚 Documentation
|
|
22
27
|
|
|
@@ -34,6 +39,7 @@
|
|
|
34
39
|
- Use chokidar to fix dev build cyclic dependency issues
|
|
35
40
|
- Warn when running tests without Appraisal
|
|
36
41
|
- Switch to yarn
|
|
42
|
+
- Update og image
|
|
37
43
|
## [0.37.0] - 2026-01-21
|
|
38
44
|
|
|
39
45
|
### 🚀 Features
|
|
@@ -39,6 +39,20 @@ class PostDefinition < ResourceDefinition
|
|
|
39
39
|
end
|
|
40
40
|
```
|
|
41
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
|
+
|
|
42
56
|
**Note:** For custom operations with business logic, use Interactive Actions with an Interaction class.
|
|
43
57
|
|
|
44
58
|
## Interactive Actions with Interactions
|
|
@@ -388,15 +388,19 @@ Add member/collection routes:
|
|
|
388
388
|
```ruby
|
|
389
389
|
register_resource ::Comment do
|
|
390
390
|
member do
|
|
391
|
-
post :approve
|
|
392
|
-
post :flag
|
|
391
|
+
post :approve, as: :approve
|
|
392
|
+
post :flag, as: :flag
|
|
393
393
|
end
|
|
394
394
|
collection do
|
|
395
|
-
get :pending
|
|
395
|
+
get :pending, as: :pending
|
|
396
396
|
end
|
|
397
397
|
end
|
|
398
398
|
```
|
|
399
399
|
|
|
400
|
+
::: warning Always Name Custom Routes
|
|
401
|
+
Always use the `as:` option when defining custom routes. This ensures `resource_url_for` can generate correct URLs. Without named routes, URL generation will fail for nested resources.
|
|
402
|
+
:::
|
|
403
|
+
|
|
400
404
|
Generates nested routes:
|
|
401
405
|
- `POST /posts/:post_id/nested_comments/:id/approve`
|
|
402
406
|
- `POST /posts/:post_id/nested_comments/:id/flag`
|
data/docs/og-image.html
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<style>
|
|
6
|
+
* {
|
|
7
|
+
margin: 0;
|
|
8
|
+
padding: 0;
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
body {
|
|
13
|
+
width: 1200px;
|
|
14
|
+
height: 630px;
|
|
15
|
+
background: #1e2330;
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.container {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: row;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 60px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.logo {
|
|
30
|
+
width: 260px;
|
|
31
|
+
height: 260px;
|
|
32
|
+
object-fit: contain;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.content {
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
gap: 16px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.title {
|
|
42
|
+
font-size: 88px;
|
|
43
|
+
font-weight: 700;
|
|
44
|
+
color: #ffffff;
|
|
45
|
+
letter-spacing: -1px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.tagline {
|
|
49
|
+
font-size: 40px;
|
|
50
|
+
color: #b8bcc8;
|
|
51
|
+
font-weight: 400;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.features {
|
|
55
|
+
display: flex;
|
|
56
|
+
gap: 24px;
|
|
57
|
+
margin-top: 12px;
|
|
58
|
+
font-size: 26px;
|
|
59
|
+
color: #e07c5a;
|
|
60
|
+
font-weight: 500;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.features span:not(:last-child)::after {
|
|
64
|
+
content: '·';
|
|
65
|
+
margin-left: 24px;
|
|
66
|
+
color: #e07c5a;
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
69
|
+
</head>
|
|
70
|
+
<body>
|
|
71
|
+
<div class="container">
|
|
72
|
+
<img src="public/plutonium.png" alt="Plutonium" class="logo">
|
|
73
|
+
<div class="content">
|
|
74
|
+
<div class="title">Plutonium</div>
|
|
75
|
+
<div class="tagline">Build Rails Apps in Minutes, Not Days</div>
|
|
76
|
+
<div class="features">
|
|
77
|
+
<span>Convention-driven</span>
|
|
78
|
+
<span>AI-ready</span>
|
|
79
|
+
<span>Fully customizable</span>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</body>
|
|
84
|
+
</html>
|
data/docs/public/og-image.png
CHANGED
|
Binary file
|
|
@@ -219,11 +219,15 @@ end
|
|
|
219
219
|
# In portal routes or config/routes.rb
|
|
220
220
|
register_resource Post do
|
|
221
221
|
member do
|
|
222
|
-
post :publish
|
|
222
|
+
post :publish, as: :publish # Always use as: option!
|
|
223
223
|
end
|
|
224
224
|
end
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
+
::: warning Always Name Custom Routes
|
|
228
|
+
Always use the `as:` option when defining custom routes. This ensures `resource_url_for` can generate correct URLs, especially for nested resources.
|
|
229
|
+
:::
|
|
230
|
+
|
|
227
231
|
## Authorization
|
|
228
232
|
|
|
229
233
|
### Automatic Authorization
|
|
@@ -39,6 +39,20 @@ class PostDefinition < Plutonium::Resource::Definition
|
|
|
39
39
|
end
|
|
40
40
|
```
|
|
41
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
|
+
|
|
42
56
|
**Note:** For custom operations with business logic, use **Interactive Actions** with an Interaction class.
|
|
43
57
|
|
|
44
58
|
## Interactive Actions
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
plutonium (0.
|
|
4
|
+
plutonium (0.38.0)
|
|
5
5
|
action_policy (~> 0.7.0)
|
|
6
6
|
listen (~> 3.8)
|
|
7
7
|
pagy (~> 9.0)
|
|
@@ -11,8 +11,8 @@ PATH
|
|
|
11
11
|
phlex-tabler_icons
|
|
12
12
|
phlexi-display (>= 0.2.0)
|
|
13
13
|
phlexi-field (>= 0.2.0)
|
|
14
|
-
phlexi-form (>= 0.14.
|
|
15
|
-
phlexi-menu (>= 0.4.
|
|
14
|
+
phlexi-form (>= 0.14.1)
|
|
15
|
+
phlexi-menu (>= 0.4.1)
|
|
16
16
|
phlexi-table (>= 0.2.0)
|
|
17
17
|
rabl (~> 0.16.1)
|
|
18
18
|
rails (>= 7.2)
|
|
@@ -230,12 +230,12 @@ GEM
|
|
|
230
230
|
fiber-local
|
|
231
231
|
phlex (~> 2.0)
|
|
232
232
|
zeitwerk
|
|
233
|
-
phlexi-form (0.14.
|
|
233
|
+
phlexi-form (0.14.1)
|
|
234
234
|
activesupport
|
|
235
235
|
phlex (~> 2.0)
|
|
236
236
|
phlexi-field (~> 0.2.0)
|
|
237
237
|
zeitwerk
|
|
238
|
-
phlexi-menu (0.4.
|
|
238
|
+
phlexi-menu (0.4.1)
|
|
239
239
|
phlex (~> 2.0)
|
|
240
240
|
phlexi-field (~> 0.2.0)
|
|
241
241
|
zeitwerk
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
plutonium (0.
|
|
4
|
+
plutonium (0.38.0)
|
|
5
5
|
action_policy (~> 0.7.0)
|
|
6
6
|
listen (~> 3.8)
|
|
7
7
|
pagy (~> 9.0)
|
|
@@ -11,8 +11,8 @@ PATH
|
|
|
11
11
|
phlex-tabler_icons
|
|
12
12
|
phlexi-display (>= 0.2.0)
|
|
13
13
|
phlexi-field (>= 0.2.0)
|
|
14
|
-
phlexi-form (>= 0.14.
|
|
15
|
-
phlexi-menu (>= 0.4.
|
|
14
|
+
phlexi-form (>= 0.14.1)
|
|
15
|
+
phlexi-menu (>= 0.4.1)
|
|
16
16
|
phlexi-table (>= 0.2.0)
|
|
17
17
|
rabl (~> 0.16.1)
|
|
18
18
|
rails (>= 7.2)
|
|
@@ -209,12 +209,12 @@ GEM
|
|
|
209
209
|
fiber-local
|
|
210
210
|
phlex (~> 2.0)
|
|
211
211
|
zeitwerk
|
|
212
|
-
phlexi-form (0.14.
|
|
212
|
+
phlexi-form (0.14.1)
|
|
213
213
|
activesupport
|
|
214
214
|
phlex (~> 2.0)
|
|
215
215
|
phlexi-field (~> 0.2.0)
|
|
216
216
|
zeitwerk
|
|
217
|
-
phlexi-menu (0.4.
|
|
217
|
+
phlexi-menu (0.4.1)
|
|
218
218
|
phlex (~> 2.0)
|
|
219
219
|
phlexi-field (~> 0.2.0)
|
|
220
220
|
zeitwerk
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
plutonium (0.
|
|
4
|
+
plutonium (0.38.0)
|
|
5
5
|
action_policy (~> 0.7.0)
|
|
6
6
|
listen (~> 3.8)
|
|
7
7
|
pagy (~> 9.0)
|
|
@@ -11,8 +11,8 @@ PATH
|
|
|
11
11
|
phlex-tabler_icons
|
|
12
12
|
phlexi-display (>= 0.2.0)
|
|
13
13
|
phlexi-field (>= 0.2.0)
|
|
14
|
-
phlexi-form (>= 0.14.
|
|
15
|
-
phlexi-menu (>= 0.4.
|
|
14
|
+
phlexi-form (>= 0.14.1)
|
|
15
|
+
phlexi-menu (>= 0.4.1)
|
|
16
16
|
phlexi-table (>= 0.2.0)
|
|
17
17
|
rabl (~> 0.16.1)
|
|
18
18
|
rails (>= 7.2)
|
|
@@ -211,12 +211,12 @@ GEM
|
|
|
211
211
|
fiber-local
|
|
212
212
|
phlex (~> 2.0)
|
|
213
213
|
zeitwerk
|
|
214
|
-
phlexi-form (0.14.
|
|
214
|
+
phlexi-form (0.14.1)
|
|
215
215
|
activesupport
|
|
216
216
|
phlex (~> 2.0)
|
|
217
217
|
phlexi-field (~> 0.2.0)
|
|
218
218
|
zeitwerk
|
|
219
|
-
phlexi-menu (0.4.
|
|
219
|
+
phlexi-menu (0.4.1)
|
|
220
220
|
phlex (~> 2.0)
|
|
221
221
|
phlexi-field (~> 0.2.0)
|
|
222
222
|
zeitwerk
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
require "rails/generators/base"
|
|
2
2
|
require "rails/generators/active_record/migration"
|
|
3
3
|
require "securerandom"
|
|
4
|
+
require "plutonium/auth/sequel_adapter"
|
|
4
5
|
|
|
5
6
|
module Pu
|
|
6
7
|
module Rodauth
|
|
7
8
|
class InstallGenerator < ::Rails::Generators::Base
|
|
8
9
|
include ::ActiveRecord::Generators::Migration
|
|
9
10
|
|
|
10
|
-
SEQUEL_ADAPTERS = {
|
|
11
|
-
"postgresql" => (RUBY_ENGINE == "jruby") ? "postgresql" : "postgres",
|
|
12
|
-
"mysql2" => (RUBY_ENGINE == "jruby") ? "mysql" : "mysql2",
|
|
13
|
-
"sqlite3" => "sqlite",
|
|
14
|
-
"oracle_enhanced" => "oracle",
|
|
15
|
-
"sqlserver" => (RUBY_ENGINE == "jruby") ? "mssql" : "tinytds"
|
|
16
|
-
}
|
|
17
|
-
|
|
18
11
|
source_root "#{__dir__}/templates"
|
|
19
12
|
|
|
20
13
|
desc "Install rodauth-rails"
|
|
@@ -61,15 +54,18 @@ module Pu
|
|
|
61
54
|
|
|
62
55
|
private
|
|
63
56
|
|
|
57
|
+
# Delegates to the SequelAdapter module to avoid code duplication.
|
|
64
58
|
def sequel_adapter
|
|
65
|
-
|
|
59
|
+
Plutonium::Auth::SequelAdapter.sequel_adapter
|
|
66
60
|
end
|
|
67
61
|
|
|
62
|
+
# Delegates to the SequelAdapter module's internal ActiveRecord adapter detection.
|
|
63
|
+
# We still provide this method for use in create_install_migration.
|
|
68
64
|
def activerecord_adapter
|
|
69
65
|
if ActiveRecord::Base.respond_to?(:connection_db_config)
|
|
70
|
-
ActiveRecord::Base.connection_db_config
|
|
66
|
+
ActiveRecord::Base.connection_db_config&.adapter
|
|
71
67
|
else
|
|
72
|
-
ActiveRecord::Base.connection_config
|
|
68
|
+
ActiveRecord::Base.connection_config&.fetch(:adapter, nil)
|
|
73
69
|
end
|
|
74
70
|
end
|
|
75
71
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "sequel/core"
|
|
2
|
+
require "plutonium/auth/sequel_adapter"
|
|
2
3
|
|
|
3
4
|
class RodauthPlugin < Rodauth::Rails::Auth
|
|
4
5
|
attr_accessor :url_options
|
|
@@ -17,11 +18,8 @@ class RodauthPlugin < Rodauth::Rails::Auth
|
|
|
17
18
|
# ==> General
|
|
18
19
|
|
|
19
20
|
# Initialize Sequel and have it reuse Active Record's database connection.
|
|
20
|
-
|
|
21
|
-
db
|
|
22
|
-
<% else -%>
|
|
23
|
-
db Sequel.<%= sequel_adapter %>(extensions: :activerecord_connection, keep_reference: false)
|
|
24
|
-
<% end -%>
|
|
21
|
+
# The adapter is detected dynamically at runtime to support database changes.
|
|
22
|
+
db Plutonium::Auth::SequelAdapter.db
|
|
25
23
|
|
|
26
24
|
# Change prefix of table and foreign key column names from default "account"
|
|
27
25
|
# accounts_table :users
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "sequel/core"
|
|
4
|
+
|
|
5
|
+
module Plutonium
|
|
6
|
+
module Auth
|
|
7
|
+
# Provides runtime detection of the database adapter for Sequel configuration.
|
|
8
|
+
# This module dynamically detects the ActiveRecord adapter and returns the
|
|
9
|
+
# corresponding Sequel adapter, allowing users to change their database
|
|
10
|
+
# without needing to regenerate rodauth files.
|
|
11
|
+
module SequelAdapter
|
|
12
|
+
# Maps ActiveRecord adapter names to their corresponding Sequel adapter names.
|
|
13
|
+
# JRuby uses JDBC adapters which have different naming conventions.
|
|
14
|
+
SEQUEL_ADAPTERS = {
|
|
15
|
+
"postgresql" => (RUBY_ENGINE == "jruby") ? "postgresql" : "postgres",
|
|
16
|
+
"mysql2" => (RUBY_ENGINE == "jruby") ? "mysql" : "mysql2",
|
|
17
|
+
"sqlite3" => "sqlite",
|
|
18
|
+
"oracle_enhanced" => "oracle",
|
|
19
|
+
"sqlserver" => (RUBY_ENGINE == "jruby") ? "mssql" : "tinytds"
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
# Returns a Sequel database connection that reuses ActiveRecord's connection.
|
|
24
|
+
# Automatically detects the correct adapter based on the current ActiveRecord config.
|
|
25
|
+
#
|
|
26
|
+
# @return [Sequel::Database] configured Sequel database connection
|
|
27
|
+
# @raise [RuntimeError] if the Sequel adapter initialization fails
|
|
28
|
+
def db
|
|
29
|
+
adapter = sequel_adapter
|
|
30
|
+
begin
|
|
31
|
+
if RUBY_ENGINE == "jruby"
|
|
32
|
+
Sequel.connect("jdbc:#{adapter}://", extensions: :activerecord_connection, keep_reference: false)
|
|
33
|
+
else
|
|
34
|
+
Sequel.public_send(adapter, extensions: :activerecord_connection, keep_reference: false)
|
|
35
|
+
end
|
|
36
|
+
rescue => e
|
|
37
|
+
raise "Failed to initialize Sequel with adapter '#{adapter}'. " \
|
|
38
|
+
"Please ensure your database configuration is correct and the required " \
|
|
39
|
+
"database gems are installed. Original error: #{e.message}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns the Sequel adapter name based on the current ActiveRecord adapter.
|
|
44
|
+
# If the ActiveRecord adapter is not in the SEQUEL_ADAPTERS mapping, the
|
|
45
|
+
# ActiveRecord adapter name is returned as-is, which may work for adapters
|
|
46
|
+
# where the names match between ActiveRecord and Sequel.
|
|
47
|
+
#
|
|
48
|
+
# @return [String] the Sequel adapter name
|
|
49
|
+
def sequel_adapter
|
|
50
|
+
SEQUEL_ADAPTERS[activerecord_adapter] || activerecord_adapter
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
# Returns the current ActiveRecord adapter name.
|
|
56
|
+
#
|
|
57
|
+
# @return [String] the ActiveRecord adapter name
|
|
58
|
+
# @raise [RuntimeError] if the ActiveRecord adapter cannot be determined
|
|
59
|
+
def activerecord_adapter
|
|
60
|
+
adapter = if ActiveRecord::Base.respond_to?(:connection_db_config)
|
|
61
|
+
ActiveRecord::Base.connection_db_config&.adapter
|
|
62
|
+
else
|
|
63
|
+
ActiveRecord::Base.connection_config&.fetch(:adapter, nil)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
unless adapter
|
|
67
|
+
raise "Unable to determine the ActiveRecord database adapter. " \
|
|
68
|
+
"Please ensure ActiveRecord is properly configured with a database connection."
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
adapter
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -135,8 +135,9 @@ module Plutonium
|
|
|
135
135
|
# @return [Hash] The submitted resource parameters
|
|
136
136
|
def submitted_resource_params
|
|
137
137
|
# Use existing record (cloned) for context during param extraction, or new instance for create
|
|
138
|
+
# Pass form_action: false to prevent form from trying to generate URL (cloned record has id: nil)
|
|
138
139
|
extraction_record = resource_record?&.dup || resource_class.new
|
|
139
|
-
@submitted_resource_params ||= build_form(extraction_record).extract_input(params, view_context:)[resource_param_key.to_sym].compact
|
|
140
|
+
@submitted_resource_params ||= build_form(extraction_record, form_action: false).extract_input(params, view_context:)[resource_param_key.to_sym].compact
|
|
140
141
|
end
|
|
141
142
|
|
|
142
143
|
# Returns the resource parameters, including scoped and parent parameters
|
|
@@ -273,7 +274,7 @@ module Plutonium
|
|
|
273
274
|
def resource_url_args_for(*, **kwargs)
|
|
274
275
|
kwargs[:parent] = current_parent unless kwargs.key?(:parent)
|
|
275
276
|
# Pass the current association when in a nested context
|
|
276
|
-
if
|
|
277
|
+
if kwargs[:parent] && !kwargs.key?(:association) && current_nested_association
|
|
277
278
|
kwargs[:association] = current_nested_association
|
|
278
279
|
end
|
|
279
280
|
super
|
|
@@ -46,8 +46,10 @@ module Plutonium
|
|
|
46
46
|
current_definition.detail_class.new(resource_record!, resource_fields: presentable_attributes, resource_associations: permitted_associations, resource_definition: current_definition)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
def build_form(record = resource_record!, action: action_name)
|
|
50
|
-
|
|
49
|
+
def build_form(record = resource_record!, action: action_name, form_action: nil, **)
|
|
50
|
+
form_options = {resource_fields: submittable_attributes_for(action), resource_definition: current_definition, **}
|
|
51
|
+
form_options[:action] = form_action unless form_action.nil?
|
|
52
|
+
current_definition.form_class.new(record, **form_options)
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
def present_parent? = false
|
|
@@ -127,8 +127,9 @@ module Plutonium
|
|
|
127
127
|
def define_member_interactive_actions
|
|
128
128
|
member do
|
|
129
129
|
get "record_actions/:interactive_action", action: :interactive_record_action,
|
|
130
|
-
as: :
|
|
131
|
-
post "record_actions/:interactive_action", action: :commit_interactive_record_action
|
|
130
|
+
as: :interactive_record_action
|
|
131
|
+
post "record_actions/:interactive_action", action: :commit_interactive_record_action,
|
|
132
|
+
as: :commit_interactive_record_action
|
|
132
133
|
end
|
|
133
134
|
end
|
|
134
135
|
|
|
@@ -138,12 +139,14 @@ module Plutonium
|
|
|
138
139
|
def define_collection_interactive_actions
|
|
139
140
|
collection do
|
|
140
141
|
get "bulk_actions/:interactive_action", action: :interactive_bulk_action,
|
|
141
|
-
as: :
|
|
142
|
-
post "bulk_actions/:interactive_action", action: :commit_interactive_bulk_action
|
|
142
|
+
as: :interactive_bulk_action
|
|
143
|
+
post "bulk_actions/:interactive_action", action: :commit_interactive_bulk_action,
|
|
144
|
+
as: :commit_interactive_bulk_action
|
|
143
145
|
|
|
144
146
|
get "resource_actions/:interactive_action", action: :interactive_resource_action,
|
|
145
|
-
as: :
|
|
146
|
-
post "resource_actions/:interactive_action", action: :commit_interactive_resource_action
|
|
147
|
+
as: :interactive_resource_action
|
|
148
|
+
post "resource_actions/:interactive_action", action: :commit_interactive_resource_action,
|
|
149
|
+
as: :commit_interactive_resource_action
|
|
147
150
|
end
|
|
148
151
|
end
|
|
149
152
|
|
|
@@ -17,6 +17,13 @@ module Plutonium
|
|
|
17
17
|
secondary: {default: "pu-btn-secondary", soft: "pu-btn-soft-secondary"}
|
|
18
18
|
}.freeze
|
|
19
19
|
|
|
20
|
+
# Color to CSS class mapping for dropdown item variants
|
|
21
|
+
DROPDOWN_COLOR_CLASSES = {
|
|
22
|
+
danger: "text-danger-600 dark:text-danger-400 hover:bg-danger-50 dark:hover:bg-danger-900/30"
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
DROPDOWN_DEFAULT_COLOR = "text-[var(--pu-text)] hover:bg-[var(--pu-surface-alt)]"
|
|
26
|
+
|
|
20
27
|
def initialize(action, url:, variant: :default)
|
|
21
28
|
@action = action
|
|
22
29
|
@url = url
|
|
@@ -24,24 +31,23 @@ module Plutonium
|
|
|
24
31
|
end
|
|
25
32
|
|
|
26
33
|
def view_template
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
case @variant
|
|
35
|
+
when :dropdown, :row_dropdown
|
|
36
|
+
render_dropdown_item
|
|
29
37
|
else
|
|
30
|
-
|
|
38
|
+
if @action.route_options.method == :get
|
|
39
|
+
render_link
|
|
40
|
+
else
|
|
41
|
+
render_button
|
|
42
|
+
end
|
|
31
43
|
end
|
|
32
44
|
end
|
|
33
45
|
|
|
34
46
|
private
|
|
35
47
|
|
|
36
48
|
def render_link
|
|
37
|
-
uri = URI.parse(@url)
|
|
38
|
-
params = Rack::Utils.parse_nested_query(uri.query)
|
|
39
|
-
params["return_to"] = @action.return_to.nil? ? request.original_url : @action.return_to
|
|
40
|
-
uri.query = params.to_query
|
|
41
|
-
uri.to_s
|
|
42
|
-
|
|
43
49
|
link_to(
|
|
44
|
-
|
|
50
|
+
url_with_return_to,
|
|
45
51
|
class: button_classes,
|
|
46
52
|
data: {turbo_frame: @action.turbo_frame}
|
|
47
53
|
) do
|
|
@@ -53,7 +59,7 @@ module Plutonium
|
|
|
53
59
|
button_to(
|
|
54
60
|
@url,
|
|
55
61
|
method: @action.route_options.method,
|
|
56
|
-
name: :return_to, value:
|
|
62
|
+
name: :return_to, value: return_to_url,
|
|
57
63
|
class: "inline-block",
|
|
58
64
|
form: {
|
|
59
65
|
data: {
|
|
@@ -69,6 +75,28 @@ module Plutonium
|
|
|
69
75
|
end
|
|
70
76
|
end
|
|
71
77
|
|
|
78
|
+
def render_dropdown_item
|
|
79
|
+
link_attrs = {
|
|
80
|
+
href: url_with_return_to,
|
|
81
|
+
class: dropdown_item_classes
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Add turbo frame if specified
|
|
85
|
+
link_attrs[:data] = {turbo_frame: @action.turbo_frame} if @action.turbo_frame
|
|
86
|
+
|
|
87
|
+
# Add confirmation and method for non-GET requests
|
|
88
|
+
if @action.confirmation || @action.route_options.method != :get
|
|
89
|
+
link_attrs[:data] ||= {}
|
|
90
|
+
link_attrs[:data][:turbo_method] = @action.route_options.method if @action.route_options.method != :get
|
|
91
|
+
link_attrs[:data][:turbo_confirm] = @action.confirmation if @action.confirmation
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
a(**link_attrs) do
|
|
95
|
+
render @action.icon.new(class: "w-4 h-4") if @action.icon
|
|
96
|
+
span { @action.label }
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
72
100
|
def render_button_content
|
|
73
101
|
if @action.icon
|
|
74
102
|
render @action.icon.new(class: icon_classes)
|
|
@@ -100,6 +128,39 @@ module Plutonium
|
|
|
100
128
|
# Table variant uses soft (tinted) buttons, default uses solid buttons
|
|
101
129
|
(@variant == :table) ? color_mapping[:soft] : color_mapping[:default]
|
|
102
130
|
end
|
|
131
|
+
|
|
132
|
+
def dropdown_item_classes
|
|
133
|
+
base_classes = "flex items-center gap-2 text-sm transition-colors"
|
|
134
|
+
size_classes = (@variant == :row_dropdown) ? "px-3 py-1.5" : "px-4 py-2"
|
|
135
|
+
|
|
136
|
+
# Use same color determination as buttons: color || category
|
|
137
|
+
color_key = (@action.color || @action.category)&.to_sym
|
|
138
|
+
color_classes = DROPDOWN_COLOR_CLASSES[color_key] || DROPDOWN_DEFAULT_COLOR
|
|
139
|
+
|
|
140
|
+
"#{base_classes} #{size_classes} #{color_classes}"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def url_with_return_to
|
|
144
|
+
uri = URI.parse(@url)
|
|
145
|
+
params = Rack::Utils.parse_nested_query(uri.query)
|
|
146
|
+
params["return_to"] = return_to_url
|
|
147
|
+
uri.query = params.to_query
|
|
148
|
+
uri.to_s
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def default_return_to
|
|
152
|
+
# When in a turbo frame with a parent, return to parent's show page
|
|
153
|
+
# instead of the frame's URL (which would be the nested index)
|
|
154
|
+
if current_turbo_frame && current_parent
|
|
155
|
+
resource_url_for(current_parent, parent: nil)
|
|
156
|
+
else
|
|
157
|
+
request.original_url
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def return_to_url
|
|
162
|
+
@action.return_to.nil? ? default_return_to : @action.return_to
|
|
163
|
+
end
|
|
103
164
|
end
|
|
104
165
|
end
|
|
105
166
|
end
|
|
@@ -56,35 +56,13 @@ module Plutonium
|
|
|
56
56
|
|
|
57
57
|
def render_danger_actions
|
|
58
58
|
div(class: "py-1") do
|
|
59
|
-
danger_actions.each { |action| render_action_item(action
|
|
59
|
+
danger_actions.each { |action| render_action_item(action) }
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
def render_action_item(action
|
|
63
|
+
def render_action_item(action)
|
|
64
64
|
url = route_options_to_url(action.route_options, @subject)
|
|
65
|
-
|
|
66
|
-
link_attrs = {
|
|
67
|
-
href: url,
|
|
68
|
-
class: tokens(
|
|
69
|
-
"flex items-center gap-2 px-4 py-2 text-sm transition-colors",
|
|
70
|
-
danger ? "text-danger-600 dark:text-danger-400 hover:bg-danger-50 dark:hover:bg-danger-900/30" : "text-[var(--pu-text)] hover:bg-[var(--pu-surface-alt)]"
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
# Add turbo frame if specified
|
|
75
|
-
link_attrs[:data] = {turbo_frame: action.turbo_frame} if action.turbo_frame
|
|
76
|
-
|
|
77
|
-
# Add confirmation if specified
|
|
78
|
-
if action.confirmation
|
|
79
|
-
link_attrs[:data] ||= {}
|
|
80
|
-
link_attrs[:data][:turbo_method] = :delete if action.route_options.method == :delete
|
|
81
|
-
link_attrs[:data][:turbo_confirm] = action.confirmation
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
a(**link_attrs) do
|
|
85
|
-
render action.icon.new(class: "w-4 h-4") if action.icon
|
|
86
|
-
span { action.label }
|
|
87
|
-
end
|
|
65
|
+
render ActionButton.new(action, url: url, variant: :dropdown)
|
|
88
66
|
end
|
|
89
67
|
|
|
90
68
|
def secondary_actions
|
|
@@ -15,7 +15,7 @@ module Plutonium
|
|
|
15
15
|
# Dashboard
|
|
16
16
|
li(class: "inline-flex items-center") do
|
|
17
17
|
a(
|
|
18
|
-
href:
|
|
18
|
+
href: root_path,
|
|
19
19
|
class: "inline-flex items-center text-sm font-medium text-[var(--pu-text-muted)] hover:text-primary-600 transition-colors"
|
|
20
20
|
) do
|
|
21
21
|
svg(
|
|
@@ -101,7 +101,7 @@ module Plutonium
|
|
|
101
101
|
d: "m1 9 4-4-4-4"
|
|
102
102
|
)
|
|
103
103
|
end
|
|
104
|
-
link_to
|
|
104
|
+
link_to nestable_resource_name_plural(resource_class),
|
|
105
105
|
resource_url_for(resource_class),
|
|
106
106
|
class: "ms-1 text-sm font-medium text-[var(--pu-text-muted)] hover:text-primary-600 md:ms-2 transition-colors"
|
|
107
107
|
end
|
|
@@ -11,15 +11,19 @@ module Plutonium
|
|
|
11
11
|
private
|
|
12
12
|
|
|
13
13
|
def params
|
|
14
|
-
|
|
14
|
+
view_context.controller.params
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def request
|
|
18
|
-
|
|
18
|
+
view_context.controller.request
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def pagy_instance
|
|
22
|
-
|
|
22
|
+
view_context.controller.instance_variable_get(:@pagy)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def controller
|
|
26
|
+
view_context.controller
|
|
23
27
|
end
|
|
24
28
|
|
|
25
29
|
delegate \
|
|
@@ -29,6 +33,7 @@ module Plutonium
|
|
|
29
33
|
:resource_record?,
|
|
30
34
|
:resource_name,
|
|
31
35
|
:resource_name_plural,
|
|
36
|
+
:nestable_resource_name_plural,
|
|
32
37
|
:display_name_of,
|
|
33
38
|
:resource_url_for,
|
|
34
39
|
:route_options_to_url,
|
|
@@ -46,6 +51,8 @@ module Plutonium
|
|
|
46
51
|
:allowed_to?,
|
|
47
52
|
:registered_resources,
|
|
48
53
|
:root_path,
|
|
54
|
+
:make_page_title,
|
|
55
|
+
:resource_logo_tag,
|
|
49
56
|
to: :view_context
|
|
50
57
|
end
|
|
51
58
|
end
|
|
@@ -109,7 +109,7 @@ module Plutonium
|
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
def form_action
|
|
112
|
-
return @form_action unless object.present? && @form_action != false &&
|
|
112
|
+
return @form_action unless object.present? && @form_action != false && view_context.present?
|
|
113
113
|
|
|
114
114
|
@form_action ||= url_for(object, action: object.new_record? ? :create : :update)
|
|
115
115
|
end
|
|
@@ -16,7 +16,7 @@ module Plutonium
|
|
|
16
16
|
|
|
17
17
|
def form_action
|
|
18
18
|
# Build the correct commit URL for the interactive action
|
|
19
|
-
action =
|
|
19
|
+
action = current_interactive_action
|
|
20
20
|
return nil unless action
|
|
21
21
|
|
|
22
22
|
# Create route options for the commit action (convert GET to POST action)
|
|
@@ -28,8 +28,8 @@ module Plutonium
|
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
# Use existing infrastructure to build the URL
|
|
31
|
-
subject = action.record_action? ?
|
|
32
|
-
|
|
31
|
+
subject = action.record_action? ? resource_record! : resource_class
|
|
32
|
+
route_options_to_url(commit_route_options, subject)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def commit_action_name(action_name)
|
|
@@ -52,10 +52,10 @@ module Plutonium
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def render_bulk_action_ids
|
|
55
|
-
action =
|
|
55
|
+
action = current_interactive_action
|
|
56
56
|
return unless action&.bulk_action?
|
|
57
57
|
|
|
58
|
-
ids = Array(
|
|
58
|
+
ids = Array(params[:ids])
|
|
59
59
|
ids.each do |id|
|
|
60
60
|
input(type: :hidden, name: "ids[]", value: id)
|
|
61
61
|
end
|
|
@@ -207,7 +207,7 @@ module Plutonium
|
|
|
207
207
|
def count_active_filters
|
|
208
208
|
count = 0
|
|
209
209
|
query_object.filter_definitions.each do |filter_name, _|
|
|
210
|
-
filter_params =
|
|
210
|
+
filter_params = params.dig(:q, filter_name)
|
|
211
211
|
next unless filter_params.is_a?(Hash) || filter_params.is_a?(ActionController::Parameters)
|
|
212
212
|
|
|
213
213
|
filter_params.each_value do |v|
|
|
@@ -58,7 +58,7 @@ module Plutonium
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def form_action
|
|
61
|
-
return @form_action unless object.present? && @form_action != false &&
|
|
61
|
+
return @form_action unless object.present? && @form_action != false && view_context.present?
|
|
62
62
|
|
|
63
63
|
@form_action ||= resource_url_for(object, action: object.new_record? ? :create : :update)
|
|
64
64
|
end
|
|
@@ -22,7 +22,7 @@ module Plutonium
|
|
|
22
22
|
|
|
23
23
|
def lang = nil
|
|
24
24
|
|
|
25
|
-
def page_title =
|
|
25
|
+
def page_title = view_context.controller.instance_variable_get(:@page_title)
|
|
26
26
|
|
|
27
27
|
def html_attributes = {lang:, data_controller: "color-mode"}
|
|
28
28
|
|
|
@@ -7,7 +7,7 @@ module Plutonium
|
|
|
7
7
|
private
|
|
8
8
|
|
|
9
9
|
def page_title
|
|
10
|
-
|
|
10
|
+
controller.instance_variable_get(:@page_title)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def main_attributes = mix(super, {
|
|
@@ -26,7 +26,7 @@ module Plutonium
|
|
|
26
26
|
|
|
27
27
|
def render_logo
|
|
28
28
|
link_to root_path, class: "flex items-center text-2xl font-semibold text-[var(--pu-text)] mb-2" do
|
|
29
|
-
|
|
29
|
+
resource_logo_tag classname: "w-24 h-24 mr-2 rounded-[var(--pu-radius-md)]"
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -7,7 +7,7 @@ module Plutonium
|
|
|
7
7
|
private
|
|
8
8
|
|
|
9
9
|
def page_title
|
|
10
|
-
super || current_definition.index_page_title ||
|
|
10
|
+
super || current_definition.index_page_title || nestable_resource_name_plural(resource_class)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def page_description
|
|
@@ -56,35 +56,13 @@ module Plutonium
|
|
|
56
56
|
|
|
57
57
|
def render_danger_actions
|
|
58
58
|
div(class: "py-1") do
|
|
59
|
-
danger_actions.each { |action| render_action_item(action
|
|
59
|
+
danger_actions.each { |action| render_action_item(action) }
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
def render_action_item(action
|
|
63
|
+
def render_action_item(action)
|
|
64
64
|
url = route_options_to_url(action.route_options, @record)
|
|
65
|
-
|
|
66
|
-
link_attrs = {
|
|
67
|
-
href: url,
|
|
68
|
-
class: tokens(
|
|
69
|
-
"flex items-center gap-2 px-3 py-1.5 text-sm transition-colors",
|
|
70
|
-
danger ? "text-danger-600 dark:text-danger-400 hover:bg-danger-50 dark:hover:bg-danger-900/30" : "text-[var(--pu-text)] hover:bg-[var(--pu-surface-alt)]"
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
# Add turbo frame if specified
|
|
75
|
-
link_attrs[:data] = {turbo_frame: action.turbo_frame} if action.turbo_frame
|
|
76
|
-
|
|
77
|
-
# Add confirmation if specified
|
|
78
|
-
if action.confirmation
|
|
79
|
-
link_attrs[:data] ||= {}
|
|
80
|
-
link_attrs[:data][:turbo_method] = action.route_options.method if action.route_options.method
|
|
81
|
-
link_attrs[:data][:turbo_confirm] = action.confirmation
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
a(**link_attrs) do
|
|
85
|
-
render action.icon.new(class: "w-4 h-4") if action.icon
|
|
86
|
-
span { action.label }
|
|
87
|
-
end
|
|
65
|
+
render Plutonium::UI::ActionButton.new(action, url: url, variant: :row_dropdown)
|
|
88
66
|
end
|
|
89
67
|
|
|
90
68
|
def secondary_actions
|
data/lib/plutonium/version.rb
CHANGED
data/package.json
CHANGED
data/plutonium.gemspec
CHANGED
|
@@ -44,10 +44,10 @@ Gem::Specification.new do |spec|
|
|
|
44
44
|
spec.add_dependency "phlex-rails"
|
|
45
45
|
spec.add_dependency "phlex-tabler_icons"
|
|
46
46
|
spec.add_dependency "phlexi-field", ">= 0.2.0"
|
|
47
|
-
spec.add_dependency "phlexi-form", ">= 0.14.
|
|
47
|
+
spec.add_dependency "phlexi-form", ">= 0.14.1"
|
|
48
48
|
spec.add_dependency "phlexi-table", ">= 0.2.0"
|
|
49
49
|
spec.add_dependency "phlexi-display", ">= 0.2.0"
|
|
50
|
-
spec.add_dependency "phlexi-menu", ">= 0.4.
|
|
50
|
+
spec.add_dependency "phlexi-menu", ">= 0.4.1"
|
|
51
51
|
spec.add_dependency "tailwind_merge"
|
|
52
52
|
spec.add_dependency "phlex-slotable", ">= 1.0.0"
|
|
53
53
|
spec.add_dependency "redcarpet"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: plutonium
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.39.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stefan Froelich
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-01-
|
|
11
|
+
date: 2026-01-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: zeitwerk
|
|
@@ -184,14 +184,14 @@ dependencies:
|
|
|
184
184
|
requirements:
|
|
185
185
|
- - ">="
|
|
186
186
|
- !ruby/object:Gem::Version
|
|
187
|
-
version: 0.14.
|
|
187
|
+
version: 0.14.1
|
|
188
188
|
type: :runtime
|
|
189
189
|
prerelease: false
|
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
|
191
191
|
requirements:
|
|
192
192
|
- - ">="
|
|
193
193
|
- !ruby/object:Gem::Version
|
|
194
|
-
version: 0.14.
|
|
194
|
+
version: 0.14.1
|
|
195
195
|
- !ruby/object:Gem::Dependency
|
|
196
196
|
name: phlexi-table
|
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -226,14 +226,14 @@ dependencies:
|
|
|
226
226
|
requirements:
|
|
227
227
|
- - ">="
|
|
228
228
|
- !ruby/object:Gem::Version
|
|
229
|
-
version: 0.4.
|
|
229
|
+
version: 0.4.1
|
|
230
230
|
type: :runtime
|
|
231
231
|
prerelease: false
|
|
232
232
|
version_requirements: !ruby/object:Gem::Requirement
|
|
233
233
|
requirements:
|
|
234
234
|
- - ">="
|
|
235
235
|
- !ruby/object:Gem::Version
|
|
236
|
-
version: 0.4.
|
|
236
|
+
version: 0.4.1
|
|
237
237
|
- !ruby/object:Gem::Dependency
|
|
238
238
|
name: tailwind_merge
|
|
239
239
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -542,6 +542,7 @@ files:
|
|
|
542
542
|
- docs/guides/theming.md
|
|
543
543
|
- docs/guides/troubleshooting.md
|
|
544
544
|
- docs/index.md
|
|
545
|
+
- docs/og-image.html
|
|
545
546
|
- docs/public/android-chrome-192x192.png
|
|
546
547
|
- docs/public/android-chrome-512x512.png
|
|
547
548
|
- docs/public/apple-touch-icon.png
|
|
@@ -776,6 +777,7 @@ files:
|
|
|
776
777
|
- lib/plutonium/auth.rb
|
|
777
778
|
- lib/plutonium/auth/public.rb
|
|
778
779
|
- lib/plutonium/auth/rodauth.rb
|
|
780
|
+
- lib/plutonium/auth/sequel_adapter.rb
|
|
779
781
|
- lib/plutonium/configuration.rb
|
|
780
782
|
- lib/plutonium/core/.DS_Store
|
|
781
783
|
- lib/plutonium/core/controller.rb
|