Skip to content

ENG-699: Migrate privacy experiences table to Ant Design#7789

Open
jpople wants to merge 9 commits intomainfrom
jpople/eng-699/privacy-experiences-table-migration
Open

ENG-699: Migrate privacy experiences table to Ant Design#7789
jpople wants to merge 9 commits intomainfrom
jpople/eng-699/privacy-experiences-table-migration

Conversation

@jpople
Copy link
Copy Markdown
Contributor

@jpople jpople commented Mar 30, 2026

Ticket ENG-699

Description Of Changes

Migrates the Privacy Experiences table from the legacy FidesTableV2 (TanStack-based) component to the new Ant Design table infrastructure, consistent with other recently migrated tables in the admin UI.

Code Changes

  • Extracted table logic into usePrivacyExperiencesTable hook, returning tableProps and columns for use with the Ant <Table> component
  • Replaced FidesTableV2 row/cell rendering with Ant Design column definitions in the hook
  • Removed PRIVACY_NOTICE_REGION_MAP (Map) from privacy-notice-regions.ts in favor of direct PRIVACY_NOTICE_REGION_RECORD lookup
  • Updated Cypress tests to use row content selectors instead of data-testid="row-${index}" (which was specific to the old table), and added data-testid="empty-state" to the empty state component
  • Fixed stuck loading spinner in EnablePrivacyExperienceCell by wrapping the mutation in try/finally

Steps to Confirm

  1. Navigate to PrivacyExperiences
  2. Verify the table renders with columns: Title, Component, Locations, Properties, Last update, Enable
  3. Click a row → should navigate to the experience detail page
  4. Toggle the enable switch on an active experience → confirm the disable warning modal appears
  5. Navigate to an empty environment or intercept the API to return no items → confirm the empty state renders with a "Create new experience" button

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
Copy Markdown
Contributor

vercel bot commented Mar 30, 2026

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

Project Deployment Actions Updated (UTC)
fides-plus-nightly Ready Ready Preview, Comment Mar 31, 2026 6:34pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
fides-privacy-center Ignored Ignored Mar 31, 2026 6:34pm

Request Review

@jpople jpople force-pushed the jpople/eng-699/privacy-experiences-table-migration branch from 15f7a98 to 3bfe23e Compare March 30, 2026 21:29
@jpople jpople marked this pull request as ready for review March 30, 2026 21:34
@jpople jpople requested a review from a team as a code owner March 30, 2026 21:34
@jpople jpople requested review from kruulik and removed request for a team March 30, 2026 21:34
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Code Review: Privacy Experiences Table → Ant Design Migration

This is a clean, well-structured migration. The extraction of table logic into usePrivacyExperiencesTable is a clear improvement in separation of concerns, and the new getRegionValues using flatMap is more readable than the old forEach+push pattern. The try/finally fix in EnablePrivacyExperienceCell is a nice correctness improvement.

Issues

Bug (medium): Empty state button ignores permissions
The EmptyTableExperience component always renders the "Create new experience" button regardless of the user's PRIVACY_EXPERIENCE_UPDATE scope. In the main component the action bar is correctly gated behind userCanUpdate, but the empty-state path bypasses this check. See inline comment.

Nit: Duplicate keys in Properties column
Properties are keyed by p.name. If two properties share a name, React will warn about duplicate keys. See inline comment.

Nit: JSX element in memoized config
Minor referential stability concern with <EmptyTableExperience /> inside the antTableConfig memo. Not a blocker. See inline comment.

Other observations

  • PRIVACY_NOTICE_REGION_MAP removal is safe — it was only consumed in the now-replaced getRegions helper.
  • ComponentCell removal from cells.tsx exports is clean — it was only used inside PrivacyExperiencesTable itself.
  • The Cypress test update from data-testid="row-N" to cy.get("table").contains("tr", item.name) is the right approach for Ant Design tables.
  • updated_at rendered via new Date(updated_at).toDateString() is consistent with the prior implementation, so no regression there.

iconPosition="end"
>
Create new experience
</Button>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The "Create new experience" button inside EmptyTableExperience is always rendered regardless of the user's permissions. In the main component, the action bar (including the equivalent button) is gated behind userCanUpdate. A user without PRIVACY_EXPERIENCE_UPDATE scope will see this button in the empty state and be able to click it, even though they shouldn't be able to create experiences.

Consider passing userCanUpdate as a prop to EmptyTableExperience (or moving the component definition inside the hook where that value is available) and either hiding the button or rendering a permission-aware version:

const EmptyTableExperience = ({ canCreate }: { canCreate: boolean }) => {
  ...
  {canCreate && (
    <Button onClick={...} ...>
      Create new experience
    </Button>
  )}
  ...
};

columnState={{ isExpanded: isPropertiesExpanded }}
/>
),
menu: {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Properties are keyed by p.name, which means two properties with the same name will produce duplicate React keys and a console warning. Consider using a stable unique identifier (e.g. p.id if available) as the key, or a composite like ${p.id}-${p.name} as a fallback:

values={(properties ?? []).map((p) => ({
  label: p.name,
  key: p.id ?? p.name,
}))}

]);

const tableState = useTableState({
pagination: {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

antTableConfig is memoized but <EmptyTableExperience /> is created as a new JSX element on every render. While EmptyTableExperience itself is stable (module-level), the element is re-created whenever the memo re-runs. This is low-impact but if you want strict referential stability you can define it once outside the memo:

const emptyText = useMemo(() => <EmptyTableExperience />, []);

const antTableConfig = useMemo(
  () => ({
    ...
    customTableProps: { locale: { emptyText } },
  }),
  [dataSource, totalRows, isLoading, isFetching, emptyText],
);

(Not a blocker — just a nit if consistency with the rest of the memo pattern matters.)

@github-actions
Copy link
Copy Markdown

Title Lines Statements Branches Functions
admin-ui Coverage: 7%
5.66% (2384/42070) 4.6% (1094/23759) 3.81% (477/12504)
fides-js Coverage: 78%
78.98% (1962/2484) 65.55% (1214/1852) 72.57% (336/463)
privacy-center Coverage: 86%
83.18% (287/345) 77.15% (152/197) 75% (48/64)

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.

1 participant