plutonium 0.33.1 → 0.34.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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/# Plutonium: The pre-alpha demo.md +4 -2
  3. data/.claude/skills/assets/SKILL.md +416 -0
  4. data/.claude/skills/connect-resource/SKILL.md +112 -0
  5. data/.claude/skills/controller/SKILL.md +302 -0
  6. data/.claude/skills/create-resource/SKILL.md +240 -0
  7. data/.claude/skills/definition/SKILL.md +218 -0
  8. data/.claude/skills/definition-actions/SKILL.md +386 -0
  9. data/.claude/skills/definition-fields/SKILL.md +474 -0
  10. data/.claude/skills/definition-query/SKILL.md +334 -0
  11. data/.claude/skills/forms/SKILL.md +439 -0
  12. data/.claude/skills/installation/SKILL.md +300 -0
  13. data/.claude/skills/interaction/SKILL.md +382 -0
  14. data/.claude/skills/model/SKILL.md +267 -0
  15. data/.claude/skills/model-features/SKILL.md +286 -0
  16. data/.claude/skills/nested-resources/SKILL.md +274 -0
  17. data/.claude/skills/package/SKILL.md +191 -0
  18. data/.claude/skills/policy/SKILL.md +352 -0
  19. data/.claude/skills/portal/SKILL.md +400 -0
  20. data/.claude/skills/resource/SKILL.md +281 -0
  21. data/.claude/skills/rodauth/SKILL.md +452 -0
  22. data/.claude/skills/views/SKILL.md +563 -0
  23. data/Appraisals +46 -4
  24. data/CHANGELOG.md +32 -1
  25. data/app/assets/plutonium.css +2 -2
  26. data/config/brakeman.ignore +239 -0
  27. data/config/initializers/action_policy.rb +1 -1
  28. data/docs/.vitepress/config.ts +132 -47
  29. data/docs/concepts/architecture.md +226 -0
  30. data/docs/concepts/auto-detection.md +254 -0
  31. data/docs/concepts/index.md +61 -0
  32. data/docs/concepts/packages-portals.md +304 -0
  33. data/docs/concepts/resources.md +224 -0
  34. data/docs/cookbook/blog.md +412 -0
  35. data/docs/cookbook/index.md +289 -0
  36. data/docs/cookbook/saas.md +481 -0
  37. data/docs/getting-started/index.md +56 -0
  38. data/docs/getting-started/installation.md +146 -0
  39. data/docs/getting-started/tutorial/01-setup.md +118 -0
  40. data/docs/getting-started/tutorial/02-first-resource.md +180 -0
  41. data/docs/getting-started/tutorial/03-authentication.md +246 -0
  42. data/docs/getting-started/tutorial/04-authorization.md +170 -0
  43. data/docs/getting-started/tutorial/05-custom-actions.md +202 -0
  44. data/docs/getting-started/tutorial/06-nested-resources.md +147 -0
  45. data/docs/getting-started/tutorial/07-customizing-ui.md +254 -0
  46. data/docs/getting-started/tutorial/index.md +64 -0
  47. data/docs/guides/adding-resources.md +420 -0
  48. data/docs/guides/authentication.md +551 -0
  49. data/docs/guides/authorization.md +468 -0
  50. data/docs/guides/creating-packages.md +380 -0
  51. data/docs/guides/custom-actions.md +523 -0
  52. data/docs/guides/index.md +45 -0
  53. data/docs/guides/multi-tenancy.md +302 -0
  54. data/docs/guides/nested-resources.md +411 -0
  55. data/docs/guides/search-filtering.md +266 -0
  56. data/docs/guides/theming.md +321 -0
  57. data/docs/index.md +67 -26
  58. data/docs/public/CLAUDE.md +64 -21
  59. data/docs/reference/assets/index.md +496 -0
  60. data/docs/reference/controller/index.md +363 -0
  61. data/docs/reference/definition/actions.md +400 -0
  62. data/docs/reference/definition/fields.md +350 -0
  63. data/docs/reference/definition/index.md +252 -0
  64. data/docs/reference/definition/query.md +342 -0
  65. data/docs/reference/generators/index.md +469 -0
  66. data/docs/reference/index.md +49 -0
  67. data/docs/reference/interaction/index.md +445 -0
  68. data/docs/reference/model/features.md +248 -0
  69. data/docs/reference/model/index.md +219 -0
  70. data/docs/reference/policy/index.md +385 -0
  71. data/docs/reference/portal/index.md +382 -0
  72. data/docs/reference/views/forms.md +396 -0
  73. data/docs/reference/views/index.md +479 -0
  74. data/gemfiles/rails_7.gemfile +9 -2
  75. data/gemfiles/rails_7.gemfile.lock +146 -111
  76. data/gemfiles/rails_8.0.gemfile +20 -0
  77. data/gemfiles/rails_8.0.gemfile.lock +417 -0
  78. data/gemfiles/rails_8.1.gemfile +20 -0
  79. data/gemfiles/rails_8.1.gemfile.lock +419 -0
  80. data/lib/generators/pu/gem/dotenv/templates/.env +2 -0
  81. data/lib/generators/pu/gem/dotenv/templates/config/initializers/001_ensure_required_env.rb +3 -1
  82. data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +13 -16
  83. data/lib/generators/pu/pkg/portal/USAGE +65 -0
  84. data/lib/generators/pu/pkg/portal/portal_generator.rb +22 -9
  85. data/lib/generators/pu/res/conn/USAGE +71 -0
  86. data/lib/generators/pu/res/model/USAGE +106 -110
  87. data/lib/generators/pu/res/model/templates/model.rb.tt +6 -2
  88. data/lib/generators/pu/res/scaffold/USAGE +85 -0
  89. data/lib/generators/pu/rodauth/install_generator.rb +2 -6
  90. data/lib/generators/pu/rodauth/templates/config/initializers/url_options.rb +17 -0
  91. data/lib/generators/pu/skills/sync/USAGE +14 -0
  92. data/lib/generators/pu/skills/sync/sync_generator.rb +66 -0
  93. data/lib/plutonium/action_policy/sti_policy_lookup.rb +1 -1
  94. data/lib/plutonium/core/controller.rb +2 -2
  95. data/lib/plutonium/interaction/base.rb +1 -0
  96. data/lib/plutonium/package/engine.rb +2 -2
  97. data/lib/plutonium/query/adhoc_block.rb +6 -2
  98. data/lib/plutonium/query/model_scope.rb +1 -1
  99. data/lib/plutonium/railtie.rb +4 -0
  100. data/lib/plutonium/resource/controllers/crud_actions/index_action.rb +1 -1
  101. data/lib/plutonium/resource/query_object.rb +38 -8
  102. data/lib/plutonium/ui/table/components/scopes_bar.rb +39 -34
  103. data/lib/plutonium/version.rb +1 -1
  104. data/lib/tasks/release.rake +19 -4
  105. data/package.json +1 -1
  106. metadata +76 -39
  107. data/brakeman.ignore +0 -28
  108. data/docs/api-examples.md +0 -49
  109. data/docs/guide/claude-code-guide.md +0 -74
  110. data/docs/guide/deep-dive/authorization.md +0 -189
  111. data/docs/guide/deep-dive/multitenancy.md +0 -256
  112. data/docs/guide/deep-dive/resources.md +0 -390
  113. data/docs/guide/getting-started/01-installation.md +0 -165
  114. data/docs/guide/index.md +0 -28
  115. data/docs/guide/introduction/01-what-is-plutonium.md +0 -211
  116. data/docs/guide/introduction/02-core-concepts.md +0 -440
  117. data/docs/guide/tutorial/01-project-setup.md +0 -75
  118. data/docs/guide/tutorial/02-creating-a-feature-package.md +0 -45
  119. data/docs/guide/tutorial/03-defining-resources.md +0 -90
  120. data/docs/guide/tutorial/04-creating-a-portal.md +0 -101
  121. data/docs/guide/tutorial/05-customizing-the-ui.md +0 -128
  122. data/docs/guide/tutorial/06-adding-custom-actions.md +0 -101
  123. data/docs/guide/tutorial/07-implementing-authorization.md +0 -90
  124. data/docs/markdown-examples.md +0 -85
  125. data/docs/modules/action.md +0 -244
  126. data/docs/modules/authentication.md +0 -236
  127. data/docs/modules/configuration.md +0 -599
  128. data/docs/modules/controller.md +0 -443
  129. data/docs/modules/core.md +0 -316
  130. data/docs/modules/definition.md +0 -1308
  131. data/docs/modules/display.md +0 -759
  132. data/docs/modules/form.md +0 -495
  133. data/docs/modules/generator.md +0 -400
  134. data/docs/modules/index.md +0 -167
  135. data/docs/modules/interaction.md +0 -642
  136. data/docs/modules/package.md +0 -151
  137. data/docs/modules/policy.md +0 -176
  138. data/docs/modules/portal.md +0 -710
  139. data/docs/modules/query.md +0 -297
  140. data/docs/modules/resource_record.md +0 -618
  141. data/docs/modules/routing.md +0 -690
  142. data/docs/modules/table.md +0 -301
  143. data/docs/modules/ui.md +0 -631
@@ -14,39 +14,9 @@ module Plutonium
14
14
  "flex flex-wrap justify-between items-center gap-4 mb-4"
15
15
  ) do
16
16
  div(class: "flex flex-wrap items-center gap-2") do
17
- name = "all"
18
- if current_scope.blank?
19
- a(
20
- id: "#{name}-scope",
21
- href: current_query_object.build_url(scope: nil),
22
- class:
23
- "px-4 py-2 text-sm font-medium text-white bg-primary-700 border border-primary-700 rounded-lg hover:bg-primary-800 focus:z-10 focus:ring-2 focus:ring-primary-700 focus:text-white dark:bg-primary-600 dark:border-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
24
- ) { name.humanize }
25
- else
26
- a(
27
- id: "#{name}-scope",
28
- href: current_query_object.build_url(scope: nil),
29
- class:
30
- "px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-100 hover:text-gray-700 focus:z-10 focus:ring-2 focus:ring-gray-300 focus:text-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:focus:text-white"
31
- ) { name.humanize }
32
- end
33
-
34
- current_query_object.scope_definitions.each do |name, definition|
35
- if name == current_scope
36
- a(
37
- id: "#{name}-scope",
38
- href: current_query_object.build_url(scope: name),
39
- class:
40
- "px-4 py-2 text-sm font-medium text-white bg-primary-700 border border-primary-700 rounded-lg hover:bg-primary-800 focus:z-10 focus:ring-2 focus:ring-primary-700 focus:text-white dark:bg-primary-600 dark:border-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
41
- ) { name.humanize }
42
- else
43
- a(
44
- id: "#{name}-scope",
45
- href: current_query_object.build_url(scope: name),
46
- class:
47
- "px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-100 hover:text-gray-700 focus:z-10 focus:ring-2 focus:ring-gray-300 focus:text-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:focus:text-white"
48
- ) { name.humanize }
49
- end
17
+ render_all_scope_button
18
+ current_query_object.scope_definitions.each_key do |name|
19
+ render_scope_button(name)
50
20
  end
51
21
  end
52
22
 
@@ -124,7 +94,42 @@ module Plutonium
124
94
 
125
95
  private
126
96
 
127
- def current_scope = raw_resource_query_params[:scope]
97
+ def render_all_scope_button
98
+ active = all_scope_active?
99
+ a(
100
+ id: "all-scope",
101
+ href: current_query_object.build_url(scope: nil),
102
+ class: active ? active_scope_class : inactive_scope_class
103
+ ) { "All" }
104
+ end
105
+
106
+ def render_scope_button(name)
107
+ active = name.to_s == current_scope
108
+ a(
109
+ id: "#{name}-scope",
110
+ href: current_query_object.build_url(scope: name),
111
+ class: active ? active_scope_class : inactive_scope_class
112
+ ) { name.to_s.humanize }
113
+ end
114
+
115
+ def current_scope
116
+ # Use the effective scope (includes default when no selection)
117
+ current_query_object.selected_scope
118
+ end
119
+
120
+ def all_scope_active?
121
+ # Active if user explicitly selected "All" OR no scope param and no default
122
+ current_query_object.all_scope_selected? ||
123
+ (!raw_resource_query_params.key?(:scope) && current_query_object.default_scope_name.blank?)
124
+ end
125
+
126
+ def active_scope_class
127
+ "px-4 py-2 text-sm font-medium text-white bg-primary-700 border border-primary-700 rounded-lg hover:bg-primary-800 focus:z-10 focus:ring-2 focus:ring-primary-700 focus:text-white dark:bg-primary-600 dark:border-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
128
+ end
129
+
130
+ def inactive_scope_class
131
+ "px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-100 hover:text-gray-700 focus:z-10 focus:ring-2 focus:ring-gray-300 focus:text-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:focus:text-white"
132
+ end
128
133
 
129
134
  def render?
130
135
  current_query_object.scope_definitions.present?
@@ -1,5 +1,5 @@
1
1
  module Plutonium
2
- VERSION = "0.33.1"
2
+ VERSION = "0.34.0"
3
3
  NEXT_MAJOR_VERSION = VERSION.split(".").tap { |v|
4
4
  v[1] = v[1].to_i + 1
5
5
  v[2] = 0
@@ -6,10 +6,25 @@ namespace :release do
6
6
  current_version = Plutonium::VERSION
7
7
  puts "Current version: #{current_version}"
8
8
 
9
+ # Find the tag to compare against
10
+ version_tag = "v#{current_version}"
11
+ tag_exists = system("git rev-parse #{version_tag} >/dev/null 2>&1")
12
+
13
+ unless tag_exists
14
+ # Fall back to most recent tag
15
+ version_tag = `git describe --tags --abbrev=0 2>/dev/null`.strip
16
+ if version_tag.empty?
17
+ puts "No tags found, comparing against initial commit"
18
+ version_tag = `git rev-list --max-parents=0 HEAD`.strip
19
+ else
20
+ puts "Tag v#{current_version} not found, comparing against #{version_tag}"
21
+ end
22
+ end
23
+
9
24
  # Check for breaking changes, features, or fixes since last tag
10
- breaking = `git log v#{current_version}..HEAD --oneline | grep -i "BREAKING CHANGE"`.strip
11
- features = `git log v#{current_version}..HEAD --oneline | grep "^[a-f0-9]* feat"`.strip
12
- fixes = `git log v#{current_version}..HEAD --oneline | grep "^[a-f0-9]* fix"`.strip
25
+ breaking = `git log #{version_tag}..HEAD --oneline | grep -i "BREAKING CHANGE"`.strip
26
+ features = `git log #{version_tag}..HEAD --oneline | grep "^[a-f0-9]* feat"`.strip
27
+ fixes = `git log #{version_tag}..HEAD --oneline | grep "^[a-f0-9]* fix"`.strip
13
28
 
14
29
  major, minor, patch = current_version.split(".").map(&:to_i)
15
30
 
@@ -54,7 +69,7 @@ namespace :release do
54
69
  package_json_file = "package.json"
55
70
  if File.exist?(package_json_file)
56
71
  package_content = File.read(package_json_file)
57
- updated_package = package_content.gsub(/"version":\s*"[\d.]+"/, %{"version": "#{version}"})
72
+ updated_package = package_content.gsub(/"version":\s*"[\d.]+"/, %("version": "#{version}"))
58
73
  File.write(package_json_file, updated_package)
59
74
  puts "✓ Updated #{package_json_file}"
60
75
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radioactive-labs/plutonium",
3
- "version": "0.33.1",
3
+ "version": "0.34.0",
4
4
  "description": "Core assets for the Plutonium gem",
5
5
  "type": "module",
6
6
  "main": "src/js/core.js",
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.33.1
4
+ version: 0.34.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-14 00:00:00.000000000 Z
11
+ date: 2026-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -399,6 +399,26 @@ extensions: []
399
399
  extra_rdoc_files: []
400
400
  files:
401
401
  - "# Plutonium: The pre-alpha demo.md"
402
+ - ".claude/skills/assets/SKILL.md"
403
+ - ".claude/skills/connect-resource/SKILL.md"
404
+ - ".claude/skills/controller/SKILL.md"
405
+ - ".claude/skills/create-resource/SKILL.md"
406
+ - ".claude/skills/definition-actions/SKILL.md"
407
+ - ".claude/skills/definition-fields/SKILL.md"
408
+ - ".claude/skills/definition-query/SKILL.md"
409
+ - ".claude/skills/definition/SKILL.md"
410
+ - ".claude/skills/forms/SKILL.md"
411
+ - ".claude/skills/installation/SKILL.md"
412
+ - ".claude/skills/interaction/SKILL.md"
413
+ - ".claude/skills/model-features/SKILL.md"
414
+ - ".claude/skills/model/SKILL.md"
415
+ - ".claude/skills/nested-resources/SKILL.md"
416
+ - ".claude/skills/package/SKILL.md"
417
+ - ".claude/skills/policy/SKILL.md"
418
+ - ".claude/skills/portal/SKILL.md"
419
+ - ".claude/skills/resource/SKILL.md"
420
+ - ".claude/skills/rodauth/SKILL.md"
421
+ - ".claude/skills/views/SKILL.md"
402
422
  - ".cliff.toml"
403
423
  - ".node-version"
404
424
  - ".rspec"
@@ -486,8 +506,8 @@ files:
486
506
  - app/views/rodauth/webauthn_autofill.html.erb
487
507
  - app/views/rodauth/webauthn_remove.html.erb
488
508
  - app/views/rodauth/webauthn_setup.html.erb
489
- - brakeman.ignore
490
509
  - config.ru
510
+ - config/brakeman.ignore
491
511
  - config/initializers/action_policy.rb
492
512
  - config/initializers/hotwire_turbo_monkey_patches.rb
493
513
  - config/initializers/pagy.rb
@@ -496,43 +516,35 @@ files:
496
516
  - docs/.vitepress/config.ts
497
517
  - docs/.vitepress/theme/custom.css
498
518
  - docs/.vitepress/theme/index.ts
499
- - docs/api-examples.md
500
- - docs/guide/claude-code-guide.md
501
- - docs/guide/deep-dive/authorization.md
502
- - docs/guide/deep-dive/multitenancy.md
503
- - docs/guide/deep-dive/resources.md
504
- - docs/guide/getting-started/01-installation.md
505
- - docs/guide/index.md
506
- - docs/guide/introduction/01-what-is-plutonium.md
507
- - docs/guide/introduction/02-core-concepts.md
508
- - docs/guide/tutorial/01-project-setup.md
509
- - docs/guide/tutorial/02-creating-a-feature-package.md
510
- - docs/guide/tutorial/03-defining-resources.md
511
- - docs/guide/tutorial/04-creating-a-portal.md
512
- - docs/guide/tutorial/05-customizing-the-ui.md
513
- - docs/guide/tutorial/06-adding-custom-actions.md
514
- - docs/guide/tutorial/07-implementing-authorization.md
519
+ - docs/concepts/architecture.md
520
+ - docs/concepts/auto-detection.md
521
+ - docs/concepts/index.md
522
+ - docs/concepts/packages-portals.md
523
+ - docs/concepts/resources.md
524
+ - docs/cookbook/blog.md
525
+ - docs/cookbook/index.md
526
+ - docs/cookbook/saas.md
527
+ - docs/getting-started/index.md
528
+ - docs/getting-started/installation.md
529
+ - docs/getting-started/tutorial/01-setup.md
530
+ - docs/getting-started/tutorial/02-first-resource.md
531
+ - docs/getting-started/tutorial/03-authentication.md
532
+ - docs/getting-started/tutorial/04-authorization.md
533
+ - docs/getting-started/tutorial/05-custom-actions.md
534
+ - docs/getting-started/tutorial/06-nested-resources.md
535
+ - docs/getting-started/tutorial/07-customizing-ui.md
536
+ - docs/getting-started/tutorial/index.md
537
+ - docs/guides/adding-resources.md
538
+ - docs/guides/authentication.md
539
+ - docs/guides/authorization.md
540
+ - docs/guides/creating-packages.md
541
+ - docs/guides/custom-actions.md
542
+ - docs/guides/index.md
543
+ - docs/guides/multi-tenancy.md
544
+ - docs/guides/nested-resources.md
545
+ - docs/guides/search-filtering.md
546
+ - docs/guides/theming.md
515
547
  - docs/index.md
516
- - docs/markdown-examples.md
517
- - docs/modules/action.md
518
- - docs/modules/authentication.md
519
- - docs/modules/configuration.md
520
- - docs/modules/controller.md
521
- - docs/modules/core.md
522
- - docs/modules/definition.md
523
- - docs/modules/display.md
524
- - docs/modules/form.md
525
- - docs/modules/generator.md
526
- - docs/modules/index.md
527
- - docs/modules/interaction.md
528
- - docs/modules/package.md
529
- - docs/modules/policy.md
530
- - docs/modules/portal.md
531
- - docs/modules/query.md
532
- - docs/modules/resource_record.md
533
- - docs/modules/routing.md
534
- - docs/modules/table.md
535
- - docs/modules/ui.md
536
548
  - docs/public/CLAUDE.md
537
549
  - docs/public/android-chrome-192x192.png
538
550
  - docs/public/android-chrome-512x512.png
@@ -554,10 +566,29 @@ files:
554
566
  - docs/public/tutorial/plutonium-posts-detail-customized.png
555
567
  - docs/public/tutorial/plutonium-posts-detail.png
556
568
  - docs/public/tutorial/plutonium-publish-post.png
569
+ - docs/reference/assets/index.md
570
+ - docs/reference/controller/index.md
571
+ - docs/reference/definition/actions.md
572
+ - docs/reference/definition/fields.md
573
+ - docs/reference/definition/index.md
574
+ - docs/reference/definition/query.md
575
+ - docs/reference/generators/index.md
576
+ - docs/reference/index.md
577
+ - docs/reference/interaction/index.md
578
+ - docs/reference/model/features.md
579
+ - docs/reference/model/index.md
580
+ - docs/reference/policy/index.md
581
+ - docs/reference/portal/index.md
582
+ - docs/reference/views/forms.md
583
+ - docs/reference/views/index.md
557
584
  - esbuild.config.js
558
585
  - exe/pug
559
586
  - gemfiles/rails_7.gemfile
560
587
  - gemfiles/rails_7.gemfile.lock
588
+ - gemfiles/rails_8.0.gemfile
589
+ - gemfiles/rails_8.0.gemfile.lock
590
+ - gemfiles/rails_8.1.gemfile
591
+ - gemfiles/rails_8.1.gemfile.lock
561
592
  - lib/active_model/validations/array_validator.rb
562
593
  - lib/active_model/validations/attached_validator.rb
563
594
  - lib/active_model/validations/url_validator.rb
@@ -633,6 +664,7 @@ files:
633
664
  - lib/generators/pu/pkg/package/templates/app/presenters/resource_presenter.rb.tt
634
665
  - lib/generators/pu/pkg/package/templates/app/query_objects/resource_query_object.rb.tt
635
666
  - lib/generators/pu/pkg/package/templates/lib/engine.rb.tt
667
+ - lib/generators/pu/pkg/portal/USAGE
636
668
  - lib/generators/pu/pkg/portal/portal_generator.rb
637
669
  - lib/generators/pu/pkg/portal/templates/app/controllers/concerns/controller.rb.tt
638
670
  - lib/generators/pu/pkg/portal/templates/app/controllers/dashboard_controller.rb.tt
@@ -646,6 +678,7 @@ files:
646
678
  - lib/generators/pu/pkg/portal/templates/app/views/package/dashboard/index.html.erb
647
679
  - lib/generators/pu/pkg/portal/templates/config/routes.rb.tt
648
680
  - lib/generators/pu/pkg/portal/templates/lib/engine.rb.tt
681
+ - lib/generators/pu/res/conn/USAGE
649
682
  - lib/generators/pu/res/conn/conn_generator.rb
650
683
  - lib/generators/pu/res/conn/templates/.keep
651
684
  - lib/generators/pu/res/conn/templates/app/controllers/resource_controller.rb.tt
@@ -659,6 +692,7 @@ files:
659
692
  - lib/generators/pu/res/model/templates/create_table_migration.rb.tt
660
693
  - lib/generators/pu/res/model/templates/model.rb.tt
661
694
  - lib/generators/pu/res/model/templates/module.rb.tt
695
+ - lib/generators/pu/res/scaffold/USAGE
662
696
  - lib/generators/pu/res/scaffold/scaffold_generator.rb
663
697
  - lib/generators/pu/res/scaffold/templates/.keep
664
698
  - lib/generators/pu/res/scaffold/templates/controller.rb.tt
@@ -719,6 +753,7 @@ files:
719
753
  - lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/webauthn_authenticator_added.text.erb
720
754
  - lib/generators/pu/rodauth/templates/app/views/rodauth_mailer/webauthn_authenticator_removed.text.erb
721
755
  - lib/generators/pu/rodauth/templates/config/initializers/rodauth.rb.tt
756
+ - lib/generators/pu/rodauth/templates/config/initializers/url_options.rb
722
757
  - lib/generators/pu/rodauth/templates/db/migrate/create_rodauth.rb.tt
723
758
  - lib/generators/pu/rodauth/templates/db/migrate/install_rodauth.rb.tt
724
759
  - lib/generators/pu/rodauth/templates/lib/tasks/rodauth_admin.rake.tt
@@ -732,6 +767,8 @@ files:
732
767
  - lib/generators/pu/service/sidekiq/templates/app/sidekiq/sidekiq_job.rb
733
768
  - lib/generators/pu/service/sidekiq/templates/config/initializers/sidekiq.rb
734
769
  - lib/generators/pu/service/sidekiq/templates/config/sidekiq.yml
770
+ - lib/generators/pu/skills/sync/USAGE
771
+ - lib/generators/pu/skills/sync/sync_generator.rb
735
772
  - lib/plutonium.rb
736
773
  - lib/plutonium/action/README.md
737
774
  - lib/plutonium/action/base.rb
data/brakeman.ignore DELETED
@@ -1,28 +0,0 @@
1
- {
2
- "ignored_warnings": [
3
- {
4
- "warning_type": "Cross-Site Request Forgery",
5
- "warning_code": 7,
6
- "fingerprint": "1cb8570b8c91f38317cdf909e01e7016359846174f427e86011633c344d30fc3",
7
- "check_name": "ForgerySetting",
8
- "message": "`protect_from_forgery` should be called in `Plutonium::Resource::Controller`",
9
- "file": "lib/plutonium/resource/controller.rb",
10
- "line": 10,
11
- "link": "https://brakemanscanner.org/docs/warning_types/cross-site_request_forgery/",
12
- "code": null,
13
- "render_path": null,
14
- "location": {
15
- "type": "controller",
16
- "controller": "Plutonium::Resource::Controller"
17
- },
18
- "user_input": null,
19
- "confidence": "High",
20
- "cwe_id": [
21
- 352
22
- ],
23
- "note": "Tests confirm csrf tokens are being verified. False flag."
24
- }
25
- ],
26
- "updated": "2024-02-24 17:32:51 +0000",
27
- "brakeman_version": "6.1.2"
28
- }
data/docs/api-examples.md DELETED
@@ -1,49 +0,0 @@
1
- ---
2
- outline: deep
3
- ---
4
-
5
- # Runtime API Examples
6
-
7
- This page demonstrates usage of some of the runtime APIs provided by VitePress.
8
-
9
- The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files:
10
-
11
- ```md
12
- <script setup>
13
- import { useData } from 'vitepress'
14
-
15
- const { theme, page, frontmatter } = useData()
16
- </script>
17
-
18
- ## Results
19
-
20
- ### Theme Data
21
- <pre>{{ theme }}</pre>
22
-
23
- ### Page Data
24
- <pre>{{ page }}</pre>
25
-
26
- ### Page Frontmatter
27
- <pre>{{ frontmatter }}</pre>
28
- ```
29
-
30
- <script setup>
31
- import { useData } from 'vitepress'
32
-
33
- const { site, theme, page, frontmatter } = useData()
34
- </script>
35
-
36
- ## Results
37
-
38
- ### Theme Data
39
- <pre>{{ theme }}</pre>
40
-
41
- ### Page Data
42
- <pre>{{ page }}</pre>
43
-
44
- ### Page Frontmatter
45
- <pre>{{ frontmatter }}</pre>
46
-
47
- ## More
48
-
49
- Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata).
@@ -1,74 +0,0 @@
1
- ---
2
- title: Claude Code Guide for Plutonium Development
3
- ---
4
-
5
- <script setup>
6
- import { withBase } from 'vitepress'
7
- </script>
8
-
9
- # Claude Code Guide for Plutonium Development
10
-
11
- This page provides comprehensive development guidance for building Plutonium applications effectively. This guide is designed to help AI assistants and developers understand the framework's patterns and best practices.
12
-
13
- ## Quick Start
14
-
15
- **Download the CLAUDE.md File**: <a :href="withBase('/CLAUDE.md')" target="_blank">📄 CLAUDE.md</a>
16
-
17
- **Or download directly from your terminal**:
18
-
19
- ::: code-group
20
-
21
- ```bash [Unix/Linux/macOS/WSL]
22
- curl -o CLAUDE.md https://radioactive-labs.github.io/plutonium-core/CLAUDE.md
23
- ```
24
-
25
- ```cmd [Windows]
26
- curl -o CLAUDE.md https://radioactive-labs.github.io/plutonium-core/CLAUDE.md
27
- ```
28
-
29
- :::
30
-
31
- ## Using This Guide
32
-
33
- Claude Code uses CLAUDE.md files for project-specific context:
34
-
35
- 1. **Download the guide**: Right-click the link above and "Save As" to download the `CLAUDE.md` file
36
- 2. **Place in your project root** as `CLAUDE.md`
37
- 3. **Claude Code automatically loads** this file for project context
38
- 4. **Enhance with your own instructions** by adding project-specific details
39
-
40
- The guide provides comprehensive patterns and examples for building Plutonium applications with AI assistance.
41
-
42
- ## What's Included
43
-
44
- The CLAUDE.md guide contains comprehensive guidelines for:
45
-
46
- ### 🏗️ **Framework Architecture**
47
- - Resource-oriented development patterns
48
- - Package architecture (Feature & Portal packages)
49
- - Component-based UI with Phlex
50
- - Business logic through Interactions
51
-
52
- ### 📝 **Resource Development**
53
- - **Auto-detection philosophy** - Field types are automatically detected from models
54
- - **Definition patterns** - Only override when needed
55
- - **Policy-based authorization** - Fine-grained permissions
56
- - **Interaction-driven business logic** - Encapsulated operations
57
-
58
- ### 🔧 **Development Patterns**
59
- - **Generator commands** for scaffolding
60
- - **Authentication setup** with Rodauth
61
- - **Multi-tenancy** with entity scoping
62
- - **Query objects** for filtering and search
63
-
64
- ### 🎨 **UI Customization**
65
- - **Component architecture** with Phlex
66
- - **Custom display blocks** with `phlexi_tag`
67
- - **Conditional rendering** with context awareness
68
- - **Layout customization** patterns
69
-
70
- ### ⚡ **Best Practices**
71
- - **Performance optimization** techniques
72
- - **Security guidelines** and defaults
73
- - **Code organization** principles
74
- - **Development workflow** recommendations
@@ -1,189 +0,0 @@
1
- # Deep Dive: Authorization
2
-
3
- Plutonium provides a robust authorization system built on top of [Action Policy](https://actionpolicy.evilmartians.io/). It's designed to be secure by default while offering fine-grained control over every aspect of your application's access control.
4
-
5
- ## Core Principles
6
-
7
- Authorization in Plutonium is handled by **Policy** classes. Every resource should have a corresponding policy that inherits from `Plutonium::Resource::Policy`.
8
-
9
- A policy's primary job is to answer the question: "Can the current `user` perform this `action` on this `record`?"
10
-
11
- ```ruby
12
- class PostPolicy < Plutonium::Resource::Policy
13
- # Can the user see a list of posts?
14
- def index?
15
- true # Everyone can see the list
16
- end
17
-
18
- # Can the user update this specific post?
19
- def update?
20
- # `record` is the post instance.
21
- # `user` is the current authenticated user.
22
- record.author == user || user.admin?
23
- end
24
-
25
- # ... other permissions
26
- end
27
- ```
28
-
29
- ## Secure by Default: The Permission Chain
30
-
31
- Plutonium policies are secure by default. If a permission is not explicitly granted, it's denied. This is achieved through a clear inheritance chain.
32
-
33
- ::: code-group
34
- ```ruby [Core Permissions]
35
- # These are the base permissions.
36
- # They both default to `false`. You MUST override them.
37
- def create?
38
- false
39
- end
40
-
41
- def read?
42
- false
43
- end
44
- ```
45
- ```ruby [Derived Permissions]
46
- # These permissions inherit from the core ones.
47
- # You can override them for more granular control.
48
- def update?
49
- create?
50
- end
51
-
52
- def destroy?
53
- create?
54
- end
55
-
56
- def index?
57
- read?
58
- end
59
-
60
- def show?
61
- read?
62
- end
63
- ```
64
- :::
65
-
66
- ::: danger Always Define Core Permissions
67
- Because `create?` and `read?` default to `false`, you must define them in your policy to grant any access. If `create?` is `false`, then `update?` and `destroy?` will also be `false` unless you explicitly override them.
68
- :::
69
-
70
- ## Attribute & Association Permissions
71
-
72
- Beyond actions, policies also control access to a resource's data at a granular level.
73
-
74
- ### Attribute Permissions
75
-
76
- Attribute permissions control which fields a user can see or submit in a form. They follow a similar inheritance chain.
77
-
78
- ::: code-group
79
- ```ruby [Read Attributes]
80
- # Controls which fields are returned for `index` and `show` actions.
81
- def permitted_attributes_for_read
82
- # By default, auto-detects all columns in development,
83
- # but MUST be overridden for production.
84
- end
85
- ```
86
- ```ruby [Create/Update Attributes]
87
- # Controls which fields are allowed in `create` and `update` actions.
88
- def permitted_attributes_for_create
89
- # By default, auto-detects columns (minus some system ones)
90
- # in development, but MUST be overridden for production.
91
- end
92
-
93
- def permitted_attributes_for_update
94
- # Inherits from `permitted_attributes_for_create` by default.
95
- permitted_attributes_for_create
96
- end
97
- ```
98
- :::
99
-
100
- ::: warning Override in Production
101
- The default auto-detection for attributes only works in development to speed up initial scaffolding. You **must** override `permitted_attributes_for_create` and `permitted_attributes_for_read` in your policies for them to work in production.
102
- :::
103
-
104
- ### Association Permissions
105
-
106
- By default, no associations are permitted. You must explicitly list which related resources can be included.
107
-
108
- ```ruby
109
- class PostPolicy < Plutonium::Resource::Policy
110
- def permitted_associations
111
- [:comments, :author]
112
- end
113
- end
114
- ```
115
-
116
- ## Scoping: Filtering Collections
117
-
118
- A policy's `relation_scope` is used to filter down a collection of records to only what the current user should see. This is applied automatically on `index` pages.
119
-
120
- ::: code-group
121
- ```ruby [Simple Scope]
122
- class PostPolicy < Plutonium::Resource::Policy
123
- relation_scope do |relation|
124
- if user.admin?
125
- relation # Admins see all posts
126
- else
127
- # Others only see their own posts or published posts
128
- relation.where(author: user).or(relation.where(published: true))
129
- end
130
- end
131
- end
132
- ```
133
- ```ruby [Multi-Tenant Scope]
134
- class PostPolicy < Plutonium::Resource::Policy
135
- relation_scope do |relation|
136
- # `super` applies the portal's entity scoping first
137
- # e.g., `relation.associated_with(current_organization)`
138
- relation = super(relation)
139
-
140
- # Then, apply additional logic
141
- if user.admin?
142
- relation
143
- else
144
- relation.where(published: true)
145
- end
146
- end
147
- end
148
- ```
149
- :::
150
-
151
- ## Authorization Context
152
-
153
- Policies have access to a `context` object. By default, Plutonium provides two:
154
-
155
- - **`user`**: The current authenticated user. This is **required**.
156
- - **`entity_scope`**: The current portal's multi-tenancy record (e.g., the current `Organization`). This is optional.
157
-
158
- You can add your own custom context objects for more complex scenarios.
159
-
160
- ::: details Adding Custom Context
161
- Imagine you have a separate `Ability` system that you also want to check.
162
-
163
- **1. Define the context in the Policy:**
164
- ```ruby
165
- class PostPolicy < ResourcePolicy
166
- authorize :ability, allow_nil: true
167
-
168
- def promote?
169
- # You can now use `ability` in your permission checks
170
- user.admin? && ability&.can?(:promote, record)
171
- end
172
- end
173
- ```
174
-
175
- **2. Provide the context from the Controller:**
176
- ```ruby
177
- class PostsController < ResourceController
178
- # This tells the policy how to find the `ability` object.
179
- authorize :ability, through: :current_ability
180
-
181
- private
182
-
183
- def current_ability
184
- # Your custom logic to find the ability object
185
- Ability.new(user)
186
- end
187
- end
188
- ```
189
- :::