fix(configs): PUT existing scope config when adding a new slice#167
Merged
Conversation
ESP enforces one config per scope (any combination of rsvp / locales /
customAttributes slices), but the UI treated each tab as its own config
keyed on a legacy `type` discriminator. When a scope already had a
config (e.g. customAttributes), saving from the Locales tab POSTed and
returned 409 because the "no locales-typed config found" check missed
the existing customAttributes-typed one.
This change unifies the model: a scope has a single ScopeConfig with
optional slice fields. Slices are detected by field presence, and saves
PUT to the existing config (merging slices, dropping legacy `type`) or
POST a fresh one only when the scope owns none.
## Summary
- New unified `ScopeConfig` with optional slice fields + `hasRsvpSlice`
/ `hasLocalesSlice` / `hasAttributesSlice` guards
- `getConfigsForScope(scopeId, type)` filters by slice-field presence
so reads still work on configs written by newer PUTs that omit `type`
- ConfigManagement save handlers (RSVP / Locales / Attributes) PUT into
`scopeConfig.configId` when the scope owns a config; POST otherwise
- New `buildPutBody()` strips legacy `type` while preserving sibling
slices on every PUT path
- Slice-level deletes (`deleteSlice`, `handleDeleteAttr`) clear only the
removed slice via PUT when other slices remain; full DELETE only when
the slice was the last one
- EventForm consumers (EventInfo, CustomAttributes, RegistrationFields)
switched from `c.type === ...` to slice-presence helpers
## Test plan
- [ ] On a scope that already has a customAttributes config, go to the
Locale Mapping tab, click Create Locales Config, fill in en-US,
and save — expect a PUT 200 (not POST 409), and after refresh both
the locales table and the existing custom attributes are visible
- [ ] On a fresh scope (no config), Create Locales Config — expect a
POST 201 with no `type` field in the body
- [ ] On a scope with locales + attributes, delete the locales config —
expect a PUT 200 that drops localeNames/localeUrlCodes; attributes
remain on refresh
- [ ] On the same scope, delete the last custom attribute — expect a
PUT 200 that drops `attributes`; locales remain
- [ ] On a scope with only locales, delete locales — expect a DELETE 204
- [ ] Repeat the same scenarios for the RSVP slice (Create/Edit field,
Edit options, Delete field, Delete RSVP Config)
- [ ] Open EventForm on a scope whose config was PUT without `type` —
locale picker, custom attributes, and RSVP fields all populate
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Only Locale Mapping is in scope; the other two tabs are disabled and the default landing tab switches to `locales` so the page doesn't open onto a disabled tab. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Collaborator
Author
|
Note: The locales structure might get updated in the next PR based on latest BE changes getting discussed |
qiyundai
approved these changes
May 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ESP enforces one config per scope (any combination of rsvp / locales / customAttributes slices), but the UI treated each tab as its own config keyed on a legacy
typediscriminator. When a scope already had a config (e.g. customAttributes), saving from the Locales tab POSTed and returned 409 because the "no locales-typed config found" check missed the existing customAttributes-typed one.This change unifies the model: a scope has a single
ScopeConfigwith optional slice fields. Slices are detected by field presence, and saves PUT to the existing config (merging slices, dropping legacytype) or POST a fresh one only when the scope owns none.What is a "slice"?
A slice is one tab's chunk of fields inside the single scope config:
rsvpFormFields,localizationslocaleNames,localeUrlCodesattributesdeleteSliceis triggered from the Delete button in each tab — the ButtonGroup next to Edit on the RSVP/Locales tabs (ConfigManagement.tsx:1482for RSVP,:1557for Locales). It flows: button → confirmationAlertDialog→deleteSlice(config, 'rsvp' | 'locales', label).Why not just call
DELETE /configs/{configId}? Because the config now possibly carries other tabs' data. If a scope has both locales and custom attributes on the same config, hitting Delete on the Locales tab used to wipe attributes too. Now it strips only that tab's fields and PUTs the rest back. The full DELETE only fires when removing this slice empties the config entirely.For Custom Attributes there's no separate "delete the whole attributes section" button — the equivalent slice-clearing path is inside
handleDeleteAttr(:855): when you delete the last attribute row, it removes theattributesfield. Same PUT-vs-DELETE branch lives there.Changes deployed here: https://14257-emc-sharmeeb.adobeio-static.net/
Summary
ScopeConfigwith optional slice fields +hasRsvpSlice/hasLocalesSlice/hasAttributesSliceguardsgetConfigsForScope(scopeId, type)filters by slice-field presence so reads still work on configs written by newer PUTs that omittypescopeConfig.configIdwhen the scope owns a config; POST otherwisebuildPutBody()strips legacytypewhile preserving sibling slices on every PUT pathdeleteSlice,handleDeleteAttr) clear only the removed slice via PUT when other slices remain; full DELETE only when the slice was the last onec.type === ...to slice-presence helperslocalesso the page doesn't open onto a disabled tabTest plan
typefield in the bodyattributes; locales remaintype— locale picker, custom attributes, and RSVP fields all populate