From 3687415c601bb470a7f38121120786e7bce34d50 Mon Sep 17 00:00:00 2001 From: Nat Budin Date: Fri, 7 Aug 2026 18:59:25 -0700 Subject: [PATCH] Deprecate and remove remaining bucket key-based GraphQL/Liquid surface (#11896) Most of the fields this issue targets were already deprecation_reason-marked (the four Signup-family types' bucketKey/requestedBucketKey, and all six mutations' bucket_key/requested_bucket_key arguments) -- so the actual work here is narrower than the issue's own background section: - Remove BucketKeyMappingInputType#from_key entirely (not just deprecate -- a removed bucket is always a persisted row with a real id already, unlike to_key's bucket, which may be newly created in the same edit and have no id yet). This required converting BucketKeyRemappingModal.tsx/ useBucketKeyRemapping.tsx to submit from_bucket_id instead, since they previously always sent from_key. - Deprecate RegistrationPolicyBucketType#key (the one field the issue flagged as not yet deprecated). This surfaces new @graphql-eslint/no-deprecated warnings on the many places that still legitimately read key for editing/remapping -- expected, not something this issue addresses. - Remove RegistrationPolicy::BucketDrop#key's delegate (confirmed zero real-world Liquid usage). - Delete the dead RegistrationPolicyInputType/RegistrationPolicyBucketInputType (referenced by nothing, not even present in the generated schema). Deliberately not removing the already-deprecated bucketKey/requestedBucketKey fields or mutation arguments yet -- the issue calls for that to wait on a deprecation window passing, which is a timing/process decision rather than something to execute in this PR. Co-Authored-By: Claude Sonnet 4.6 --- app/graphql/mutations/update_event.rb | 8 +++---- .../types/bucket_key_mapping_input_type.rb | 6 ----- .../registration_policy_bucket_input_type.rb | 13 ---------- .../types/registration_policy_bucket_type.rb | 6 ++++- .../types/registration_policy_input_type.rb | 5 ---- .../EventAdmin/BucketKeyRemappingModal.tsx | 24 +++++++++++-------- .../EventAdmin/mutations.generated.ts | 5 ---- .../EventAdmin/useBucketKeyRemapping.tsx | 23 +++++++++++------- .../mutations.generated.ts | 5 ---- app/javascript/graphqlTypes.generated.ts | 10 ++++---- .../registration_policy/bucket_drop.rb | 3 --- schema.graphql | 7 +----- schema.json | 16 ++----------- .../BucketKeyRemappingModal.test.tsx | 14 +++++------ 14 files changed, 52 insertions(+), 93 deletions(-) delete mode 100644 app/graphql/types/registration_policy_bucket_input_type.rb delete mode 100644 app/graphql/types/registration_policy_input_type.rb diff --git a/app/graphql/mutations/update_event.rb b/app/graphql/mutations/update_event.rb index 44303883832..a66672af6bd 100644 --- a/app/graphql/mutations/update_event.rb +++ b/app/graphql/mutations/update_event.rb @@ -39,16 +39,16 @@ def apply_registration_policy(event, registration_policy_attributes, bucket_key_ end # EventChangeRegistrationPolicyService still works entirely in terms of from_key/to_key (see the - # comment on that service). This resolves incoming from_bucket_id/to_bucket_id args (only usable - # when the destination bucket already exists, since a bucket being newly created in this same - # edit has no id yet) down to that shape. + # comment on that service). This resolves incoming from_bucket_id/to_bucket_id args down to that + # shape -- to_bucket_id is only usable when the destination bucket already exists, since a + # bucket being newly created in this same edit has no id yet, so to_key is still accepted too. def resolve_bucket_key_mappings(event, bucket_key_mappings) (bucket_key_mappings || []).map { |mapping| resolve_bucket_key_mapping(event, mapping.to_h) } end def resolve_bucket_key_mapping(event, mapping) { - from_key: mapping[:from_key] || bucket_key_for_id(event, mapping[:from_bucket_id]), + from_key: bucket_key_for_id(event, mapping[:from_bucket_id]), to_key: mapping[:to_key] || bucket_key_for_id(event, mapping[:to_bucket_id]) } end diff --git a/app/graphql/types/bucket_key_mapping_input_type.rb b/app/graphql/types/bucket_key_mapping_input_type.rb index fa5690b21b3..02da6024059 100644 --- a/app/graphql/types/bucket_key_mapping_input_type.rb +++ b/app/graphql/types/bucket_key_mapping_input_type.rb @@ -7,12 +7,6 @@ class Types::BucketKeyMappingInputType < Types::BaseInputObject required: false, camelize: true, description: "The id of the old bucket being removed or changed" - argument :from_key, - String, - required: false, - camelize: false, - deprecation_reason: "Use from_bucket_id instead", - description: "The old bucket key being removed or changed" argument :to_bucket_id, ID, required: false, camelize: true, description: <<~MARKDOWN The id of the new bucket to map to (nil means no preference). Only usable when mapping to a bucket that already exists -- mapping to a bucket being newly created in the same diff --git a/app/graphql/types/registration_policy_bucket_input_type.rb b/app/graphql/types/registration_policy_bucket_input_type.rb deleted file mode 100644 index e91077a4ee1..00000000000 --- a/app/graphql/types/registration_policy_bucket_input_type.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true -class Types::RegistrationPolicyBucketInputType < Types::BaseInputObject - argument :anything, Boolean, required: false - argument :description, String, required: false - argument :expose_attendees, Boolean, required: false, camelize: false - argument :key, String, required: true - argument :minimum_slots, Integer, required: false, camelize: false - argument :name, String, required: false - argument :not_counted, Boolean, required: false, camelize: false - argument :preferred_slots, Integer, required: false, camelize: false - argument :slots_limited, Boolean, required: false, camelize: false - argument :total_slots, Integer, required: false, camelize: false -end diff --git a/app/graphql/types/registration_policy_bucket_type.rb b/app/graphql/types/registration_policy_bucket_type.rb index c65f4584ee9..2493a761315 100644 --- a/app/graphql/types/registration_policy_bucket_type.rb +++ b/app/graphql/types/registration_policy_bucket_type.rb @@ -4,7 +4,11 @@ class Types::RegistrationPolicyBucketType < Types::BaseObject field :description, String, null: true, description: "A long-form description for the bucket" field :id, ID, null: false, description: "The ID of this bucket" - field :key, String, null: false, description: "The unique string identifier for this bucket" + field :key, + String, + null: false, + deprecation_reason: "Use id instead", + description: "The unique string identifier for this bucket" field :minimum_slots, Integer, null: true, description: "The minimum number of attendees needed for this bucket" field :name, String, null: false, description: "The name of this bucket" field :preferred_slots, Integer, null: true, description: "The preferred number of attendees for this bucket" diff --git a/app/graphql/types/registration_policy_input_type.rb b/app/graphql/types/registration_policy_input_type.rb deleted file mode 100644 index 6ac3864d5ba..00000000000 --- a/app/graphql/types/registration_policy_input_type.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true -class Types::RegistrationPolicyInputType < Types::BaseInputObject - argument :buckets, [Types::RegistrationPolicyBucketInputType], required: false - argument :prevent_no_preference_signups, Boolean, required: false, camelize: false -end diff --git a/app/javascript/EventAdmin/BucketKeyRemappingModal.tsx b/app/javascript/EventAdmin/BucketKeyRemappingModal.tsx index 27b40623cf3..2c5aeecae2c 100644 --- a/app/javascript/EventAdmin/BucketKeyRemappingModal.tsx +++ b/app/javascript/EventAdmin/BucketKeyRemappingModal.tsx @@ -10,9 +10,13 @@ type BucketOption = { name?: string | null; }; +// A removed bucket is always a persisted row, so it always has a real id -- unlike a bucket in +// newPolicyBuckets, which might have been added in the current, not-yet-saved edit. +type RemovedBucketOption = BucketOption & { id: string }; + export type BucketKeyRemappingModalProps = { visible: boolean; - removedBuckets: BucketOption[]; + removedBuckets: RemovedBucketOption[]; newPolicyBuckets: BucketOption[]; preventNoPreferenceSignups: boolean; onConfirm: (mappings: BucketKeyMappingInput[]) => Promise; @@ -42,22 +46,22 @@ function BucketKeyRemappingModal({ const [prevRemovedBuckets, setPrevRemovedBuckets] = useState(removedBuckets); if (prevRemovedBuckets !== removedBuckets) { setPrevRemovedBuckets(removedBuckets); - setMappings(Object.fromEntries(removedBuckets.map((bucket) => [bucket.key, null]))); + setMappings(Object.fromEntries(removedBuckets.map((bucket) => [bucket.id, null]))); } - const setMapping = (fromKey: string, toKey: string | null) => { - setMappings((prev) => ({ ...prev, [fromKey]: toKey })); + const setMapping = (fromBucketId: string, toKey: string | null) => { + setMappings((prev) => ({ ...prev, [fromBucketId]: toKey })); }; // When the new policy disallows no-preference signups, mapping a removed bucket to "no // preference" would leave affected signups/requests with a null requested_bucket_id that the // policy no longer permits new signups to have -- so every row needs an explicit bucket chosen // before this can be confirmed. - const canConfirm = !preventNoPreferenceSignups || removedBuckets.every((bucket) => mappings[bucket.key]); + const canConfirm = !preventNoPreferenceSignups || removedBuckets.every((bucket) => mappings[bucket.id]); const handleConfirm = async () => { - const bucketKeyMappings: BucketKeyMappingInput[] = Object.entries(mappings).map(([fromKey, toKey]) => ({ - from_key: fromKey, + const bucketKeyMappings: BucketKeyMappingInput[] = Object.entries(mappings).map(([fromBucketId, toKey]) => ({ + from_bucket_id: fromBucketId, to_key: toKey ?? undefined, })); setIsSubmitting(true); @@ -90,13 +94,13 @@ function BucketKeyRemappingModal({ {removedBuckets.map((bucket) => ( - + {bucket.name}