Skip to content

Conversation

@erosselli
Copy link
Contributor

@erosselli erosselli commented Nov 16, 2025

Ticket ENG-1923

Description Of Changes

In ENG-1923 we changed the override_children query param in the consent v3 API to override_mode (with values descendants , ancestors and all) . This PR updates the privacy notice sandbox to use this new query param instead of override_children.

Steps to Confirm

  1. Enable FIDESPLUS__EXPERIMENTAL__CONSENT_V3_ENABLED=true
  2. Create an Email Marketing opt out notice with some children notices; make sure the notices are enabled
  3. Add the notices to an experience and enable the experience (more details on setup in https://ethyca.atlassian.net/wiki/x/IoDm8)
  4. Enable the alpha flag for the privacy notice sandbox
  5. Go to <admin_ui_url>/sandbox/privacy-notices and play around with the new override mode dropdown

Pre-Merge Checklist

  • Issue requirements met
  • All CI pipelines succeeded
  • CHANGELOG.md updated
    • Add a db-migration This indicates that a change includes a database migration label to the entry if your change includes a DB migration
    • Add a high-risk This issue suggests changes that have a high-probability of breaking existing code label to the entry if your change includes a high-risk change (i.e. potential for performance impact or unexpected regression) that should be flagged
    • Updates unreleased work already in Changelog, no new entry necessary
  • UX feedback:
    • All UX related changes have been reviewed by a designer
    • No UX review needed
  • Followup issues:
    • Followup issues created
    • No followup issues
  • Database migrations:
    • Ensure that your downrev is up to date with the latest revision on main
    • Ensure that your downgrade() migration is correct and works
      • If a downgrade migration is not possible for this change, please call this out in the PR description!
    • No migrations
  • Documentation:
    • Documentation complete, PR opened in fidesdocs
    • Documentation issue created in fidesdocs
    • If there are any new client scopes created as part of the pull request, remember to update public-facing documentation that references our scope registry
    • No documentation updates required

@vercel
Copy link

vercel bot commented Nov 16, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
fides-plus-nightly Ready Ready Preview Comment Nov 17, 2025 3:39pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
fides-privacy-center Ignored Ignored Nov 17, 2025 3:39pm

placeholder="No override"
allowClear
options={options}
aria-labelledby="override-mode-select-label"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why but if I didn't add aria-labelledby I got an jsx-a11y error about components needing labels, even when having the <label> tag with htmlFor

@erosselli erosselli marked this pull request as ready for review November 17, 2025 13:30
@erosselli erosselli requested a review from a team as a code owner November 17, 2025 13:30
@erosselli erosselli requested review from gilluminate and removed request for a team November 17, 2025 13:30
const [overrideMode, setOverrideMode] = useState<OverrideMode | null>(null);
const [checkedKeys, setCheckedKeys] = useState<Key[]>([]);
const [fetchedCheckedKeys, setFetchedCheckedKeys] = useState<Key[]>([]);
const [explicitlyChangedKeys, setExplicitlyChangedKeys] = useState<Key[]>([]);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this new state is needed to track the keys the user has explicitly checked/unchecked, separate from checkedKeys which includes cascading logic (e.g when override_mode is descendants, if I opt in to the parent notice checked keys will include both parent and children, but for the API call I want just the explicitly opted in parent to be sent)

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Nov 17, 2025

Greptile Summary

  • Replaced boolean override_children query parameter with override_mode enum supporting ancestors, descendants, and all values
  • Implemented ancestor cascade logic and explicit key tracking to ensure only user-clicked preferences are sent to API
  • Added new dropdown component replacing toggle switch for granular override mode selection

Confidence Score: 4/5

  • This PR is safe to merge with minor cleanup recommended
  • The core API parameter migration from override_children to override_mode is straightforward and correctly implemented across all components. The new cascade logic properly tracks explicitly changed keys for API submission. One style issue noted: unused childToParentMap computation that could be cleaned up. The complex state management for explicit key tracking is sound but adds complexity to what is a sandbox/testing feature.
  • No files require special attention

Important Files Changed

Filename Overview
clients/admin-ui/src/features/poc/privacy-notices-sandbox/components/SavePreferencesSection.tsx Complex logic changes to use explicitlyChangedKeys for API submission instead of filtering by cascade logic, updated to use new override mode
clients/admin-ui/src/features/poc/privacy-notices-sandbox/components/PrivacyNoticesTree.tsx Added ancestor cascade logic, ancestorsMap building, and onExplicitChange callback to track user-clicked nodes for API submission

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (1)

  1. clients/admin-ui/src/features/poc/privacy-notices-sandbox/PrivacyNoticeSandboxRealData.tsx, line 66-103 (link)

    style: childToParentMap is computed but no longer used - it's not passed to SavePreferencesSection and the only other usage is in mergePreferencesWithExisting. Consider removing it from the memo return value or documenting why it's kept

7 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile
React with 👍 or 👎 to share your feedback on this new summary format

Comment on lines +112 to +116
// Use the explicitly changed keys (the ones the user actually clicked)
// Filter to only include keys that are actually in the changed set
const keysToSend = explicitlyChangedKeys.filter((key) =>
changedKeys.includes(String(key)),
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: if user manually edits checked state without clicking (e.g., by programmatically calling setCheckedKeys), explicitlyChangedKeys would be empty and no preferences would be sent

Suggested change
// Use the explicitly changed keys (the ones the user actually clicked)
// Filter to only include keys that are actually in the changed set
const keysToSend = explicitlyChangedKeys.filter((key) =>
changedKeys.includes(String(key)),
);
// Use the explicitly changed keys (the ones the user actually clicked)
// Filter to only include keys that are actually in the changed set
const keysToSend = explicitlyChangedKeys.length > 0
? explicitlyChangedKeys.filter((key) =>
changedKeys.includes(String(key)),
)
: changedKeys;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 does this even make sense? how would the user prorammatically call setCheckedKeys?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You raise a good point! Looking at this code, the concern about programmatic calls to setCheckedKeys might not be as realistic as I initially thought.

In this component, onCheckedKeysChange (which would be setCheckedKeys) is only called from:

  1. The PrivacyNoticesTree component when users interact with checkboxes
  2. The onFetchedKeysChange call after a successful save (line 153)

The second case is internal to this component and would still have explicitlyChangedKeys populated from the user's actions before saving.

For a truly programmatic call from outside this component to bypass the explicit tracking, someone would need to call the onCheckedKeysChange prop directly without going through the tree component's click handlers. While technically possible, it's not a likely scenario in normal usage.

However, there is still a potential edge case: if the preferences are reset or synchronized from an external source, explicitlyChangedKeys could indeed be empty while changedKeys has values. In that case, falling back to changedKeys would be the correct behavior.

So the suggestion is still valid as defensive programming, but you're right to question whether it addresses a realistic scenario. The fallback ensures the component works correctly even in edge cases where the explicit tracking gets out of sync.

Copy link
Contributor

@gilluminate gilluminate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I'll keep digging on the jsx-a11y issue, we may just need to define the custom select component in that config.

@erosselli erosselli added this pull request to the merge queue Nov 17, 2025
Merged via the queue into main with commit ffe77c7 Nov 17, 2025
47 checks passed
@erosselli erosselli deleted the ENG-1923-sandbox-changes branch November 17, 2025 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants