plutonium 0.33.0 → 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 (145) 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 +36 -0
  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/controllers/crud_actions.rb +21 -18
  102. data/lib/plutonium/resource/controllers/interactive_actions.rb +21 -25
  103. data/lib/plutonium/resource/query_object.rb +38 -8
  104. data/lib/plutonium/ui/table/components/scopes_bar.rb +39 -34
  105. data/lib/plutonium/version.rb +1 -1
  106. data/lib/tasks/release.rake +19 -4
  107. data/package.json +1 -1
  108. metadata +76 -39
  109. data/brakeman.ignore +0 -28
  110. data/docs/api-examples.md +0 -49
  111. data/docs/guide/claude-code-guide.md +0 -74
  112. data/docs/guide/deep-dive/authorization.md +0 -189
  113. data/docs/guide/deep-dive/multitenancy.md +0 -256
  114. data/docs/guide/deep-dive/resources.md +0 -390
  115. data/docs/guide/getting-started/01-installation.md +0 -165
  116. data/docs/guide/index.md +0 -28
  117. data/docs/guide/introduction/01-what-is-plutonium.md +0 -211
  118. data/docs/guide/introduction/02-core-concepts.md +0 -440
  119. data/docs/guide/tutorial/01-project-setup.md +0 -75
  120. data/docs/guide/tutorial/02-creating-a-feature-package.md +0 -45
  121. data/docs/guide/tutorial/03-defining-resources.md +0 -90
  122. data/docs/guide/tutorial/04-creating-a-portal.md +0 -101
  123. data/docs/guide/tutorial/05-customizing-the-ui.md +0 -128
  124. data/docs/guide/tutorial/06-adding-custom-actions.md +0 -101
  125. data/docs/guide/tutorial/07-implementing-authorization.md +0 -90
  126. data/docs/markdown-examples.md +0 -85
  127. data/docs/modules/action.md +0 -244
  128. data/docs/modules/authentication.md +0 -236
  129. data/docs/modules/configuration.md +0 -599
  130. data/docs/modules/controller.md +0 -443
  131. data/docs/modules/core.md +0 -316
  132. data/docs/modules/definition.md +0 -1308
  133. data/docs/modules/display.md +0 -759
  134. data/docs/modules/form.md +0 -495
  135. data/docs/modules/generator.md +0 -400
  136. data/docs/modules/index.md +0 -167
  137. data/docs/modules/interaction.md +0 -642
  138. data/docs/modules/package.md +0 -151
  139. data/docs/modules/policy.md +0 -176
  140. data/docs/modules/portal.md +0 -710
  141. data/docs/modules/query.md +0 -297
  142. data/docs/modules/resource_record.md +0 -618
  143. data/docs/modules/routing.md +0 -690
  144. data/docs/modules/table.md +0 -301
  145. data/docs/modules/ui.md +0 -631
@@ -28,9 +28,9 @@ module Plutonium
28
28
  build_interactive_record_action_interaction
29
29
 
30
30
  if helpers.current_turbo_frame == "remote_modal"
31
- render layout: false
31
+ render layout: false, formats: [:html]
32
32
  else
33
- render :interactive_record_action
33
+ render :interactive_record_action, formats: [:html]
34
34
  end
35
35
  end
36
36
 
@@ -39,11 +39,7 @@ module Plutonium
39
39
  build_interactive_record_action_interaction
40
40
 
41
41
  if params[:pre_submit]
42
- respond_to do |format|
43
- format.html do
44
- render :interactive_record_action, status: :unprocessable_content
45
- end
46
- end
42
+ render :interactive_record_action, formats: [:html], status: :unprocessable_content
47
43
  return
48
44
  end
49
45
 
@@ -54,8 +50,6 @@ module Plutonium
54
50
  if outcome.success?
55
51
  return_url = redirect_url_after_action_on(resource_record!)
56
52
 
57
- format.any { redirect_to return_url, status: :see_other }
58
-
59
53
  if helpers.current_turbo_frame == "remote_modal"
60
54
  format.turbo_stream do
61
55
  render turbo_stream: [
@@ -63,16 +57,16 @@ module Plutonium
63
57
  ]
64
58
  end
65
59
  end
60
+
61
+ format.any { redirect_to return_url, status: :see_other }
66
62
  else
67
- format.html do
68
- render :interactive_record_action, status: :unprocessable_content
63
+ format.any(:html, :turbo_stream) do
64
+ render :interactive_record_action, formats: [:html], status: :unprocessable_content
69
65
  end
70
-
71
66
  format.any do
72
67
  @errors = @interaction.errors
73
68
  render "errors", status: :unprocessable_content
74
69
  end
75
-
76
70
  end
77
71
  end
78
72
  end
@@ -83,10 +77,14 @@ module Plutonium
83
77
  skip_verify_current_authorized_scope!
84
78
  build_interactive_resource_action_interaction
85
79
 
86
- if helpers.current_turbo_frame == "remote_modal"
87
- render layout: false
88
- else
89
- render :interactive_resource_action
80
+ respond_to do |format|
81
+ format.any(:html, :turbo_stream) do
82
+ if helpers.current_turbo_frame == "remote_modal"
83
+ render layout: false, formats: [:html]
84
+ else
85
+ render :interactive_resource_action, formats: [:html]
86
+ end
87
+ end
90
88
  end
91
89
  end
92
90
 
@@ -97,8 +95,8 @@ module Plutonium
97
95
 
98
96
  if params[:pre_submit]
99
97
  respond_to do |format|
100
- format.html do
101
- render :interactive_resource_action, status: :unprocessable_content
98
+ format.any(:html, :turbo_stream) do
99
+ render :interactive_resource_action, formats: [:html], status: :unprocessable_content
102
100
  end
103
101
  end
104
102
  return
@@ -111,8 +109,6 @@ module Plutonium
111
109
  if outcome.success?
112
110
  return_url = redirect_url_after_action_on(resource_class)
113
111
 
114
- format.any { redirect_to return_url, status: :see_other }
115
-
116
112
  if helpers.current_turbo_frame == "remote_modal"
117
113
  format.turbo_stream do
118
114
  render turbo_stream: [
@@ -120,16 +116,16 @@ module Plutonium
120
116
  ]
121
117
  end
122
118
  end
119
+
120
+ format.any { redirect_to return_url, status: :see_other }
123
121
  else
124
- format.html do
125
- render :interactive_resource_action, status: :unprocessable_content
122
+ format.any(:html, :turbo_stream) do
123
+ render :interactive_resource_action, formats: [:html], status: :unprocessable_content
126
124
  end
127
-
128
125
  format.any do
129
126
  @errors = @interaction.errors
130
127
  render "errors", status: :unprocessable_content
131
128
  end
132
-
133
129
  end
134
130
  end
135
131
  end
@@ -1,7 +1,7 @@
1
1
  module Plutonium
2
2
  module Resource
3
3
  class QueryObject
4
- attr_reader :search_filter, :search_query
4
+ attr_reader :search_filter, :search_query, :default_scope_name
5
5
  attr_accessor :default_sort_config
6
6
 
7
7
  # Initializes a QueryObject with the given resource_class and parameters.
@@ -31,9 +31,11 @@ module Plutonium
31
31
  #
32
32
  # @param name [Symbol] The name of the scope.
33
33
  # @param body [Proc, nil] The body of the scope.
34
- def define_scope(name, body = nil)
34
+ # @param default [Boolean] Whether this scope is the default.
35
+ def define_scope(name, body = nil, default: false, **)
35
36
  body ||= name
36
37
  scope_definitions[name] = build_query(body)
38
+ @default_scope_name = name.to_s if default
37
39
  end
38
40
 
39
41
  # Defines a sort with the given name and body.
@@ -68,31 +70,53 @@ module Plutonium
68
70
  q = {}
69
71
 
70
72
  q[:search] = options.key?(:search) ? options[:search].presence : search_query
71
- q[:scope] = options.key?(:scope) ? options[:scope].presence : selected_scope_filter
73
+ q[:scope] = if options.key?(:scope)
74
+ options[:scope].presence
75
+ else
76
+ selected_scope_filter
77
+ end
72
78
 
73
79
  q[:sort_directions] = selected_sort_directions.dup
74
80
  q[:sort_fields] = selected_sort_fields.dup
75
81
  handle_sort_options!(q, options)
76
82
 
77
83
  q.merge! params.slice(*filter_definitions.keys)
78
- query_params = deep_compact({q: q}).to_param
84
+ compacted = deep_compact({q: q})
85
+
86
+ # Preserve explicit "All" selection (scope: nil in options means show all)
87
+ if options.key?(:scope) && options[:scope].nil?
88
+ compacted[:q] ||= {}
89
+ compacted[:q][:scope] = ""
90
+ end
91
+
92
+ query_params = compacted.to_param
79
93
  "#{@request_path}?#{query_params}"
80
94
  end
81
95
 
82
96
  # Applies the defined filters and sorts to the given scope.
83
97
  #
84
98
  # @param scope [Object] The initial scope to which filters and sorts are applied.
99
+ # @param params [Hash] The query parameters.
100
+ # @param context [Object] Optional context (e.g., controller) for executing scope blocks.
85
101
  # @return [Object] The modified scope.
86
- def apply(scope, params)
102
+ def apply(scope, params, context: nil)
87
103
  params = deep_compact(params.with_indifferent_access)
88
104
  scope = search_filter.apply(scope, search: params[:search]) if search_filter && params[:search]
89
- scope = scope_definitions[params[:scope]].apply(scope, **{}) if scope_definitions[params[:scope]]
105
+ # Use selected_scope which includes the default when no explicit selection
106
+ effective_scope = @selected_scope_filter
107
+ scope = scope_definitions[effective_scope].apply(scope, context:) if effective_scope && scope_definitions[effective_scope]
90
108
  scope = apply_sorts(scope, params)
91
109
  apply_filters(scope, params)
92
110
  end
93
111
 
94
112
  def scope_definitions = @scope_definitions ||= {}.with_indifferent_access
95
113
 
114
+ # Returns true if user explicitly selected "All" scope (no filtering)
115
+ def all_scope_selected? = @all_scope_selected
116
+
117
+ # Returns the currently selected scope (may be default if none explicitly selected)
118
+ def selected_scope = @selected_scope_filter
119
+
96
120
  def filter_definitions = @filter_definitions ||= {}.with_indifferent_access
97
121
 
98
122
  def sort_definitions = @sort_definitions ||= {}.with_indifferent_access
@@ -125,8 +149,14 @@ module Plutonium
125
149
  #
126
150
  # @param params [Hash] The parameters to extract.
127
151
  def extract_filter_params
128
- @search_query = params[:search]
129
- @selected_scope_filter = params[:scope]
152
+ @search_query = params[:search].presence&.strip
153
+ # Track if user explicitly selected "all" (scope param present but blank)
154
+ @all_scope_selected = params.key?(:scope) && params[:scope].blank?
155
+ @selected_scope_filter = if @all_scope_selected
156
+ nil # User clicked "All"
157
+ else
158
+ params[:scope].presence || default_scope_name
159
+ end
130
160
  end
131
161
 
132
162
  # Extracts sort parameters from the given params.
@@ -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.0"
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.0",
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.0
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-12 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).