plutonium 0.37.0 → 0.38.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 +25 -2
- data/.claude/skills/plutonium-definition-fields/SKILL.md +33 -0
- data/.claude/skills/plutonium-nested-resources/SKILL.md +79 -19
- data/.claude/skills/plutonium-policy/SKILL.md +93 -6
- data/CHANGELOG.md +36 -0
- data/CLAUDE.md +8 -10
- data/CONTRIBUTING.md +6 -8
- data/Rakefile +16 -1
- data/app/assets/plutonium.css +1 -1
- data/app/assets/plutonium.js +9371 -11492
- data/app/assets/plutonium.js.map +4 -4
- data/app/assets/plutonium.min.js +55 -55
- data/app/assets/plutonium.min.js.map +4 -4
- data/docs/guides/index.md +5 -0
- data/docs/guides/nested-resources.md +132 -29
- data/docs/guides/troubleshooting.md +82 -0
- data/docs/reference/controller/index.md +1 -1
- data/docs/reference/definition/fields.md +33 -0
- data/docs/reference/model/index.md +1 -1
- data/docs/reference/policy/index.md +77 -6
- data/gemfiles/rails_7.gemfile.lock +3 -3
- data/gemfiles/rails_8.0.gemfile.lock +3 -3
- data/gemfiles/rails_8.1.gemfile.lock +3 -3
- data/lib/plutonium/core/controller.rb +144 -19
- data/lib/plutonium/core/controllers/association_resolver.rb +86 -0
- data/lib/plutonium/helpers/display_helper.rb +12 -0
- data/lib/plutonium/query/filters/association.rb +25 -3
- data/lib/plutonium/resource/controller.rb +90 -9
- data/lib/plutonium/resource/controllers/authorizable.rb +17 -4
- data/lib/plutonium/resource/controllers/crud_actions.rb +7 -5
- data/lib/plutonium/resource/controllers/interactive_actions.rb +9 -0
- data/lib/plutonium/resource/controllers/presentable.rb +13 -11
- data/lib/plutonium/resource/policy.rb +85 -2
- data/lib/plutonium/resource/record/routes.rb +31 -1
- data/lib/plutonium/routing/mapper_extensions.rb +40 -4
- data/lib/plutonium/routing/route_set_extensions.rb +3 -0
- data/lib/plutonium/ui/breadcrumbs.rb +1 -1
- data/lib/plutonium/ui/display/resource.rb +5 -2
- data/lib/plutonium/ui/form/components/key_value_store.rb +17 -5
- data/lib/plutonium/ui/page/index.rb +1 -1
- data/lib/plutonium/version.rb +1 -1
- data/lib/tasks/release.rake +1 -1
- data/package.json +6 -5
- data/plutonium.gemspec +1 -1
- data/src/js/controllers/key_value_store_controller.js +6 -0
- data/src/js/controllers/resource_drop_down_controller.js +3 -3
- data/yarn.lock +1465 -693
- metadata +6 -5
- data/app/javascript/controllers/key_value_store_controller.js +0 -119
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.38.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-25 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.
|
|
187
|
+
version: 0.14.0
|
|
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.
|
|
194
|
+
version: 0.14.0
|
|
195
195
|
- !ruby/object:Gem::Dependency
|
|
196
196
|
name: phlexi-table
|
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -444,7 +444,6 @@ files:
|
|
|
444
444
|
- app/assets/plutonium.min.js
|
|
445
445
|
- app/assets/plutonium.min.js.map
|
|
446
446
|
- app/assets/plutonium.png
|
|
447
|
-
- app/javascript/controllers/key_value_store_controller.js
|
|
448
447
|
- app/views/layouts/resource.html.erb
|
|
449
448
|
- app/views/layouts/rodauth.html.erb
|
|
450
449
|
- app/views/plutonium/_flash.html.erb
|
|
@@ -541,6 +540,7 @@ files:
|
|
|
541
540
|
- docs/guides/nested-resources.md
|
|
542
541
|
- docs/guides/search-filtering.md
|
|
543
542
|
- docs/guides/theming.md
|
|
543
|
+
- docs/guides/troubleshooting.md
|
|
544
544
|
- docs/index.md
|
|
545
545
|
- docs/public/android-chrome-192x192.png
|
|
546
546
|
- docs/public/android-chrome-512x512.png
|
|
@@ -779,6 +779,7 @@ files:
|
|
|
779
779
|
- lib/plutonium/configuration.rb
|
|
780
780
|
- lib/plutonium/core/.DS_Store
|
|
781
781
|
- lib/plutonium/core/controller.rb
|
|
782
|
+
- lib/plutonium/core/controllers/association_resolver.rb
|
|
782
783
|
- lib/plutonium/core/controllers/authorizable.rb
|
|
783
784
|
- lib/plutonium/core/controllers/bootable.rb
|
|
784
785
|
- lib/plutonium/core/controllers/entity_scoping.rb
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { Controller } from "@hotwired/stimulus"
|
|
2
|
-
|
|
3
|
-
// Connects to data-controller="key-value-store"
|
|
4
|
-
export default class extends Controller {
|
|
5
|
-
static targets = ["container", "pair", "template", "addButton", "keyInput", "valueInput"]
|
|
6
|
-
static values = { limit: Number }
|
|
7
|
-
|
|
8
|
-
connect() {
|
|
9
|
-
this.updateIndices()
|
|
10
|
-
this.updateAddButtonState()
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
addPair(event) {
|
|
14
|
-
event.preventDefault()
|
|
15
|
-
|
|
16
|
-
if (this.pairTargets.length >= this.limitValue) {
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const template = this.templateTarget
|
|
21
|
-
const newPair = template.content.cloneNode(true)
|
|
22
|
-
const index = this.pairTargets.length
|
|
23
|
-
|
|
24
|
-
// Update the template placeholders with actual indices
|
|
25
|
-
this.updatePairIndices(newPair, index)
|
|
26
|
-
|
|
27
|
-
this.containerTarget.appendChild(newPair)
|
|
28
|
-
this.updateIndices()
|
|
29
|
-
this.updateAddButtonState()
|
|
30
|
-
|
|
31
|
-
// Focus on the key input of the new pair
|
|
32
|
-
const newKeyInput = this.containerTarget.lastElementChild.querySelector('[data-key-value-store-target="keyInput"]')
|
|
33
|
-
if (newKeyInput) {
|
|
34
|
-
newKeyInput.focus()
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
removePair(event) {
|
|
39
|
-
event.preventDefault()
|
|
40
|
-
|
|
41
|
-
const pair = event.target.closest('[data-key-value-store-target="pair"]')
|
|
42
|
-
if (pair) {
|
|
43
|
-
pair.remove()
|
|
44
|
-
this.updateIndices()
|
|
45
|
-
this.updateAddButtonState()
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
updateIndices() {
|
|
50
|
-
this.pairTargets.forEach((pair, index) => {
|
|
51
|
-
const keyInput = pair.querySelector('[data-key-value-store-target="keyInput"]')
|
|
52
|
-
const valueInput = pair.querySelector('[data-key-value-store-target="valueInput"]')
|
|
53
|
-
|
|
54
|
-
if (keyInput) {
|
|
55
|
-
// Update name attribute
|
|
56
|
-
keyInput.name = keyInput.name.replace(/\[\d+\]/, `[${index}]`)
|
|
57
|
-
// Update id attribute for Turbo compatibility
|
|
58
|
-
keyInput.id = keyInput.id.replace(/_\d+_/, `_${index}_`)
|
|
59
|
-
}
|
|
60
|
-
if (valueInput) {
|
|
61
|
-
// Update name attribute
|
|
62
|
-
valueInput.name = valueInput.name.replace(/\[\d+\]/, `[${index}]`)
|
|
63
|
-
// Update id attribute for Turbo compatibility
|
|
64
|
-
valueInput.id = valueInput.id.replace(/_\d+_/, `_${index}_`)
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
updatePairIndices(element, index) {
|
|
70
|
-
const inputs = element.querySelectorAll('input')
|
|
71
|
-
inputs.forEach(input => {
|
|
72
|
-
if (input.name) {
|
|
73
|
-
input.name = input.name.replace('__INDEX__', index)
|
|
74
|
-
}
|
|
75
|
-
if (input.id) {
|
|
76
|
-
input.id = input.id.replace('___INDEX___', `_${index}_`)
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
updateAddButtonState() {
|
|
82
|
-
const addButton = this.addButtonTarget
|
|
83
|
-
if (this.pairTargets.length >= this.limitValue) {
|
|
84
|
-
addButton.disabled = true
|
|
85
|
-
addButton.classList.add('opacity-50', 'cursor-not-allowed')
|
|
86
|
-
} else {
|
|
87
|
-
addButton.disabled = false
|
|
88
|
-
addButton.classList.remove('opacity-50', 'cursor-not-allowed')
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Serialize the current key-value pairs to JSON
|
|
93
|
-
toJSON() {
|
|
94
|
-
const pairs = {}
|
|
95
|
-
this.pairTargets.forEach(pair => {
|
|
96
|
-
const keyInput = pair.querySelector('[data-key-value-store-target="keyInput"]')
|
|
97
|
-
const valueInput = pair.querySelector('[data-key-value-store-target="valueInput"]')
|
|
98
|
-
|
|
99
|
-
if (keyInput && valueInput && keyInput.value.trim()) {
|
|
100
|
-
pairs[keyInput.value.trim()] = valueInput.value
|
|
101
|
-
}
|
|
102
|
-
})
|
|
103
|
-
return JSON.stringify(pairs)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Get the current key-value pairs as an object
|
|
107
|
-
toObject() {
|
|
108
|
-
const pairs = {}
|
|
109
|
-
this.pairTargets.forEach(pair => {
|
|
110
|
-
const keyInput = pair.querySelector('[data-key-value-store-target="keyInput"]')
|
|
111
|
-
const valueInput = pair.querySelector('[data-key-value-store-target="valueInput"]')
|
|
112
|
-
|
|
113
|
-
if (keyInput && valueInput && keyInput.value.trim()) {
|
|
114
|
-
pairs[keyInput.value.trim()] = valueInput.value
|
|
115
|
-
}
|
|
116
|
-
})
|
|
117
|
-
return pairs
|
|
118
|
-
}
|
|
119
|
-
}
|