activeadmin-graphql 0.3.1 → 0.3.3

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/app/controllers/active_admin/graphql_controller.rb +19 -4
  4. data/docs/changelogs/20261010091415_graphql-resource-enabled-default.md +34 -0
  5. data/docs/changelogs/20261010101500_nonconventional-id-fields.md +16 -2
  6. data/docs/changelogs/20261010103800_release-0-3-1.md +9 -2
  7. data/docs/changelogs/20261010110600_graphql-identity-dsl.md +34 -0
  8. data/docs/changelogs/20261010111800_release-0-3-2.md +46 -0
  9. data/docs/changelogs/20261012050051_graphql-surface-toggles.md +40 -0
  10. data/docs/changelogs/20261012064500_graphql-capabilities.md +35 -0
  11. data/docs/changelogs/20261012113500_release-0-3-3.md +45 -0
  12. data/docs/graphql-api.md +166 -20
  13. data/docs/issues/20261010111159_rails-composite-primary-keys-alignment.md +81 -0
  14. data/docs/issues/20261010111300_partitions-and-shards-support.md +55 -0
  15. data/docs/issues/20261010111500_graphql-federation-support.md +46 -0
  16. data/lib/active_admin/graphql/capability.rb +35 -0
  17. data/lib/active_admin/graphql/capability_definition_dsl.rb +64 -0
  18. data/lib/active_admin/graphql/integration.rb +19 -1
  19. data/lib/active_admin/graphql/policy_adapter.rb +94 -0
  20. data/lib/active_admin/graphql/policy_set_cache.rb +18 -9
  21. data/lib/active_admin/graphql/resource_capability_dsl.rb +31 -0
  22. data/lib/active_admin/graphql/resource_capability_maps.rb +59 -0
  23. data/lib/active_admin/graphql/resource_config.rb +23 -2
  24. data/lib/active_admin/graphql/resource_definition_dsl.rb +12 -2
  25. data/lib/active_admin/graphql/resource_identity.rb +98 -0
  26. data/lib/active_admin/graphql/resource_methods.rb +8 -2
  27. data/lib/active_admin/graphql/resource_query_proxy/identity.rb +4 -4
  28. data/lib/active_admin/graphql/resource_query_proxy.rb +5 -4
  29. data/lib/active_admin/graphql/resource_surface_dsl.rb +48 -0
  30. data/lib/active_admin/graphql/schema_builder/build.rb +52 -3
  31. data/lib/active_admin/graphql/schema_builder/mutation_batch.rb +7 -0
  32. data/lib/active_admin/graphql/schema_builder/mutation_collection.rb +8 -0
  33. data/lib/active_admin/graphql/schema_builder/mutation_create.rb +1 -0
  34. data/lib/active_admin/graphql/schema_builder/mutation_member.rb +8 -0
  35. data/lib/active_admin/graphql/schema_builder/mutation_type_builder.rb +15 -10
  36. data/lib/active_admin/graphql/schema_builder/mutation_update_destroy.rb +4 -2
  37. data/lib/active_admin/graphql/schema_builder/query_type.rb +2 -1
  38. data/lib/active_admin/graphql/schema_builder/query_type_collection.rb +3 -0
  39. data/lib/active_admin/graphql/schema_builder/query_type_member.rb +5 -2
  40. data/lib/active_admin/graphql/schema_builder/query_type_policies.rb +9 -63
  41. data/lib/active_admin/graphql/schema_builder/resources.rb +34 -0
  42. data/lib/active_admin/graphql/schema_builder/types_object.rb +27 -11
  43. data/lib/active_admin/graphql/schema_builder/visibility.rb +22 -7
  44. data/lib/active_admin/graphql/schema_builder/wire.rb +3 -1
  45. data/lib/active_admin/graphql/schema_field.rb +18 -2
  46. data/lib/active_admin/graphql/version.rb +1 -1
  47. data/lib/active_admin/graphql.rb +3 -0
  48. metadata +17 -1
@@ -82,14 +82,20 @@ module ActiveAdmin
82
82
  define_singleton_method(:activeadmin_graphql_resource) { aa_res }
83
83
  end
84
84
 
85
- pk_cols = ActiveAdmin::PrimaryKey.columns(model)
85
+ pk_cols = ActiveAdmin::GraphQL::ResourceIdentity.columns(aa_res)
86
86
  if pk_cols.empty?
87
87
  raise ArgumentError,
88
- "#{model.name} has no primary key for GraphQL `id`; set self.primary_key on the model"
88
+ "#{model.name} has no primary key for GraphQL `id`; set self.primary_key on the model " \
89
+ "or graphql { identity ... }"
89
90
  end
90
91
 
91
92
  type_class.field :id, ::GraphQL::Types::ID, null: false, authorize: false
92
- type_class.define_method(:id) { ActiveAdmin::PrimaryKey.graphql_id_value(object) }
93
+ type_class.define_method(:id) do
94
+ ActiveAdmin::GraphQL::ResourceIdentity.graphql_id_value(
95
+ self.class.activeadmin_graphql_resource,
96
+ object
97
+ )
98
+ end
93
99
 
94
100
  # ActiveAdmin omits a single-column primary key from resource_attributes; still expose
95
101
  # non-id key columns as scalars (composite keys already remain in attributes).
@@ -107,18 +113,28 @@ module ActiveAdmin
107
113
  next unless col
108
114
 
109
115
  gql_t = graphql_scalar_for_column(aa_res, model, col)
110
- type_class.field(name.to_sym, gql_t, null: true, camelize: false, authorize: false)
116
+ type_class.field(
117
+ name.to_sym,
118
+ gql_t,
119
+ null: true,
120
+ camelize: false,
121
+ authorize: false,
122
+ capability: aa_res.graphql_config.capability_for_field(name)
123
+ )
111
124
 
112
125
  type_class.define_method(name.to_sym) { object.public_send(name) }
113
126
  end
114
127
 
115
- type_class.field :activeadmin_policies, policy_set_type, null: false, camelize: false, authorize: false
116
- type_class.define_method(:activeadmin_policies) do
117
- ActiveAdmin::GraphQL::PolicySetCache.fetch(
118
- context,
119
- subject_owner: aa_res,
120
- subject: object
121
- )
128
+ adapter = policy_adapter
129
+ if adapter&.include_resource?(aa_res)
130
+ type_class.field :activeadmin_policies, policy_set_type, null: false, camelize: false, authorize: false
131
+ type_class.define_method(:activeadmin_policies) do
132
+ ActiveAdmin::GraphQL::PolicySetCache.fetch(
133
+ context,
134
+ subject_owner: aa_res,
135
+ subject: object
136
+ )
137
+ end
122
138
  end
123
139
 
124
140
  if (ext = aa_res.graphql_config.extension_block)
@@ -10,14 +10,29 @@ module ActiveAdmin
10
10
  vis = @namespace.graphql_visibility
11
11
  return if vis.nil?
12
12
 
13
- if vis == true
14
- schema.use(::GraphQL::Schema::Visibility)
15
- elsif vis.is_a?(Hash)
16
- schema.use(::GraphQL::Schema::Visibility, **vis.symbolize_keys)
17
- else
18
- raise ActiveAdmin::DependencyError,
19
- "namespace graphql_visibility must be nil, true, or a Hash of GraphQL::Schema::Visibility options"
13
+ options =
14
+ case vis
15
+ when true
16
+ {}
17
+ when Hash
18
+ vis.symbolize_keys
19
+ else
20
+ raise ActiveAdmin::DependencyError,
21
+ "namespace graphql_visibility must be nil, true, or a Hash of GraphQL::Schema::Visibility options"
22
+ end
23
+
24
+ if @namespace.graphql_capabilities.respond_to?(:call)
25
+ profiles = options[:profiles]
26
+ if profiles.respond_to?(:any?) && profiles.any?
27
+ raise ActiveAdmin::DependencyError,
28
+ "graphql_capabilities cannot be combined with named GraphQL visibility profiles " \
29
+ "(named profiles cache a fixed context and ignore per-request capabilities). " \
30
+ "Omit profiles: and use dynamic visibility, or drop graphql_capabilities."
31
+ end
32
+ options = options.merge(dynamic: true)
20
33
  end
34
+
35
+ schema.use(::GraphQL::Schema::Visibility, **options)
21
36
  end
22
37
 
23
38
  def attach_registered_resource_union_visibility!(union_class)
@@ -20,7 +20,9 @@ module ActiveAdmin
20
20
  field_name = ref.name.to_sym
21
21
  fk = ref.foreign_key.to_s
22
22
 
23
- type_class.field field_name, @object_types[target], null: true, camelize: false
23
+ type_class.field field_name, @object_types[target], null: true, camelize: false,
24
+ authorize: false,
25
+ capability: aa_res.graphql_config.capability_for_field(field_name)
24
26
 
25
27
  type_class.define_method(field_name) do
26
28
  fk_val = object.public_send(fk)
@@ -8,9 +8,17 @@ module ActiveAdmin
8
8
  # +graphql_schema_visible+ (second argument) when {GraphQL::Schema::Visibility} is enabled.
9
9
  # That hook runs from {#visible?}; it does not replace graphql-ruby's visibility system—it
10
10
  # composes with +super+ like any custom +Field+ class.
11
+ #
12
+ # +capability:+ (RFC 0008) gates +visible?+ and +authorized?+ via +context[:capabilities]+.
11
13
  class SchemaField < ::GraphQL::Schema::Field
12
- def initialize(visibility: nil, authorize: nil, authorize_action: nil, **kwargs, &block)
13
- @visibility = visibility
14
+ def initialize(visibility: nil, authorize: nil, authorize_action: nil, capability: nil, **kwargs, &block)
15
+ @capability = capability&.to_sym
16
+ @visibility =
17
+ if @capability && visibility.is_a?(Hash) && !visibility.key?(:capability)
18
+ visibility.merge(capability: @capability)
19
+ else
20
+ visibility
21
+ end
14
22
  @authorize = authorize
15
23
  @authorize_action = authorize_action
16
24
  super(**kwargs, &block)
@@ -19,6 +27,13 @@ module ActiveAdmin
19
27
  def visible?(ctx)
20
28
  return false unless super
21
29
 
30
+ # Gate introspection only when Schema::Visibility is enabled; otherwise
31
+ # capability is enforced in +authorized?+ so hosts without the plugin
32
+ # do not trip graphql-ruby's legacy Warden +visible?+ path.
33
+ if ctx[:namespace]&.graphql_visibility && !Capability.granted?(ctx, @capability)
34
+ return false
35
+ end
36
+
22
37
  return true unless @visibility
23
38
 
24
39
  hook = ctx[:namespace]&.graphql_schema_visible
@@ -29,6 +44,7 @@ module ActiveAdmin
29
44
 
30
45
  def authorized?(object, args, ctx)
31
46
  return false unless super
47
+ return false unless Capability.granted?(ctx, @capability)
32
48
 
33
49
  owner = self.owner
34
50
  aa_resource = owner.respond_to?(:activeadmin_graphql_resource) ? owner.activeadmin_graphql_resource : nil
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveAdmin
4
4
  module GraphQL
5
- VERSION = "0.3.1"
5
+ VERSION = "0.3.3"
6
6
  end
7
7
  end
@@ -68,14 +68,17 @@ module ActiveAdmin
68
68
  def require_active_admin_graphql_components!
69
69
  %w[
70
70
  graphql/resource_interface
71
+ graphql/capability
71
72
  graphql/schema_field
72
73
  graphql/auth_context
73
74
  graphql/record_source
75
+ graphql/resource_identity
74
76
  graphql/resource_query_proxy
75
77
  graphql/run_action_payload
76
78
  graphql/run_action_mutation_config
77
79
  graphql/run_action_mutation_dsl
78
80
  graphql/key_value_pair_input
81
+ graphql/policy_adapter
79
82
  graphql/policy_set_cache
80
83
  graphql/mutation_execution_error
81
84
  graphql/schema_builder
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeadmin-graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Makarov
@@ -374,8 +374,14 @@ files:
374
374
  - docs/changelogs/20260921111000_release-0-3-0.md
375
375
  - docs/changelogs/20260921112800_drop-standard-rubocop-direct.md
376
376
  - docs/changelogs/20260921120000_graphql-floor-and-activeadmin-4.md
377
+ - docs/changelogs/20261010091415_graphql-resource-enabled-default.md
377
378
  - docs/changelogs/20261010101500_nonconventional-id-fields.md
378
379
  - docs/changelogs/20261010103800_release-0-3-1.md
380
+ - docs/changelogs/20261010110600_graphql-identity-dsl.md
381
+ - docs/changelogs/20261010111800_release-0-3-2.md
382
+ - docs/changelogs/20261012050051_graphql-surface-toggles.md
383
+ - docs/changelogs/20261012064500_graphql-capabilities.md
384
+ - docs/changelogs/20261012113500_release-0-3-3.md
379
385
  - docs/dependencies/20260907141000_json-cve-2026-71847.md
380
386
  - docs/dependencies/20260907141000_sqlite3-ghsa-mwm8-39rw-8826.md
381
387
  - docs/dependencies/20260921114000_rails-json-parse-kwargs.md
@@ -388,25 +394,35 @@ files:
388
394
  - docs/issues/20260921104400_convention-alignment-audit.md
389
395
  - docs/issues/20260921114500_dependency-audit.md
390
396
  - docs/issues/20260921115500_file-length-metrics.md
397
+ - docs/issues/20261010111159_rails-composite-primary-keys-alignment.md
398
+ - docs/issues/20261010111300_partitions-and-shards-support.md
399
+ - docs/issues/20261010111500_graphql-federation-support.md
391
400
  - docs/plan/20260817201500_rfc-starter.md
392
401
  - lib/active_admin/graphql.rb
393
402
  - lib/active_admin/graphql/auth_context.rb
403
+ - lib/active_admin/graphql/capability.rb
404
+ - lib/active_admin/graphql/capability_definition_dsl.rb
394
405
  - lib/active_admin/graphql/engine.rb
395
406
  - lib/active_admin/graphql/integration.rb
396
407
  - lib/active_admin/graphql/key_value_pair_input.rb
397
408
  - lib/active_admin/graphql/mutation_execution_error.rb
398
409
  - lib/active_admin/graphql/mutation_input_config.rb
399
410
  - lib/active_admin/graphql/mutation_input_definition_dsl.rb
411
+ - lib/active_admin/graphql/policy_adapter.rb
400
412
  - lib/active_admin/graphql/policy_set_cache.rb
401
413
  - lib/active_admin/graphql/railtie.rb
402
414
  - lib/active_admin/graphql/record_source.rb
415
+ - lib/active_admin/graphql/resource_capability_dsl.rb
416
+ - lib/active_admin/graphql/resource_capability_maps.rb
403
417
  - lib/active_admin/graphql/resource_config.rb
404
418
  - lib/active_admin/graphql/resource_definition_dsl.rb
419
+ - lib/active_admin/graphql/resource_identity.rb
405
420
  - lib/active_admin/graphql/resource_interface.rb
406
421
  - lib/active_admin/graphql/resource_methods.rb
407
422
  - lib/active_admin/graphql/resource_query_proxy.rb
408
423
  - lib/active_admin/graphql/resource_query_proxy/controller.rb
409
424
  - lib/active_admin/graphql/resource_query_proxy/identity.rb
425
+ - lib/active_admin/graphql/resource_surface_dsl.rb
410
426
  - lib/active_admin/graphql/run_action_mutation_config.rb
411
427
  - lib/active_admin/graphql/run_action_mutation_dsl.rb
412
428
  - lib/active_admin/graphql/run_action_payload.rb