Skip to content

Migrate custom reports forms to Ant Design#7865

Merged
gilluminate merged 4 commits intomainfrom
gill/ENG-3183/datamap-report-templates-antd
Apr 9, 2026
Merged

Migrate custom reports forms to Ant Design#7865
gilluminate merged 4 commits intomainfrom
gill/ENG-3183/datamap-report-templates-antd

Conversation

@gilluminate
Copy link
Copy Markdown
Contributor

Ticket ENG-3183

Description Of Changes

Migrates the custom reports forms (CustomReportCreationModal and CustomReportTemplates) from Chakra/Formik to Ant Design, continuing the ongoing antd migration effort.

Key changes:

  • Replaced Formik + Yup validation with antd Form + rules-based validation in the report creation modal
  • Replaced Formik form wrapper with native antd Form in the report templates popover
  • Replaced Chakra useDisclosure with useState for popover/modal state management
  • Replaced ConfirmationModal (Chakra) with antd useModal().confirm() for delete confirmation
  • Deleted the now-unused CustomInput component and its InputType type
  • Updated Cypress tests to use getAntFormError helper instead of getByTestId("error-...")

Code Changes

  • Migrated CustomReportCreationModal.tsx from Formik/Yup to antd Form with rules-based validation
  • Migrated CustomReportTemplates.tsx from Formik/Chakra disclosure to antd Form and useState
  • Deleted clients/admin-ui/src/features/common/custom-fields/form/CustomInput.tsx (unused after migration)
  • Deleted clients/admin-ui/src/features/common/custom-fields/form/types.ts (unused after migration)
  • Updated clients/admin-ui/cypress/e2e/datamap-report.cy.ts to use getAntFormError for validation assertions

Steps to Confirm

  1. Navigate to the Data Map Report page
  2. Click the saved reports popover button - verify the popover opens and lists any existing reports
  3. Click "Create report template" - verify the creation modal opens
  4. Test validation: submit empty form (should show required error), enter a duplicate name (should show "already exists" error), enter a name > 80 chars (should show max length error)
  5. Create a new report - verify it appears in the list
  6. Delete a report - verify the antd confirmation dialog appears and works correctly
  7. Apply/reset report templates - verify they still work as expected

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

gilluminate and others added 2 commits April 8, 2026 15:12
- Update Cypress tests to use getAntFormError helper for antd form errors
- Delete dead code custom-fields/form/ directory (unused CustomInput + types)
- Add loading spinner to report creation submit button
- Replace ConfirmationModal with imperative Modal.confirm via useModal
- Remove redundant delete state management (deleteIsOpen, reportToDelete, useEffect)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 8, 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 Apr 8, 2026 9:42pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
fides-privacy-center Ignored Ignored Apr 8, 2026 9:42pm

Request Review

gilluminate and others added 2 commits April 8, 2026 15:33
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 8, 2026

Title Lines Statements Branches Functions
admin-ui Coverage: 7%
5.88% (2547/43288) 4.89% (1199/24479) 3.95% (508/12829)
fides-js Coverage: 78%
78.98% (1962/2484) 65.55% (1214/1852) 72.57% (336/463)
privacy-center Coverage: 88%
85.93% (330/384) 81.1% (176/217) 78.87% (56/71)

@gilluminate gilluminate changed the title ENG-3183: Migrate custom reports forms to Ant Design Migrate custom reports forms to Ant Design Apr 8, 2026
@gilluminate gilluminate marked this pull request as ready for review April 9, 2026 15:02
@gilluminate gilluminate requested a review from a team as a code owner April 9, 2026 15:02
@gilluminate gilluminate requested review from kruulik and removed request for a team April 9, 2026 15:02
@gilluminate gilluminate added this pull request to the merge queue Apr 9, 2026
@gilluminate gilluminate removed the request for review from kruulik April 9, 2026 15:02
Copy link
Copy Markdown
Contributor

@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: Custom Reports Forms — Chakra/Formik → Ant Design Migration

Overall this is a clean migration. The form logic is clearer with Form.useForm, the delete confirmation flow is improved with useModal, and removing Chakra useDisclosure in favor of plain useState simplifies the state management. The Cypress test updates correctly reflect the new component structure.

Must Fix

1. Fire-and-forget delete (see inline on CustomReportTemplates.tsx:151)
deleteCustomReportMutationTrigger(id) is not awaited and has no error handler. If the request fails, the UI resets as if delete succeeded while the report still exists on the server. The mutation must use .unwrap() in a try/catch, and the local state reset should only run on success.

2. catch (error: any) (see inline on CustomReportCreationModal.tsx:110)
Use unknown (or omit the annotation entirely — TypeScript 4.4+ defaults to unknown in catch clauses). getErrorMessage already accepts unknown.

3. <Space orientation="vertical"> is not a valid prop (see inline on CustomReportTemplates.tsx:280)
The correct Ant Design prop is direction, not orientation. The incorrect prop is silently ignored and the list renders horizontally.

4. onOpenChange applies template on Cancel (see inline on CustomReportTemplates.tsx:353)
The else branch of onOpenChange calls handleApplyTemplate() unconditionally on every close, including when the user clicks the Cancel button or clicks outside the popover. This is unintended application of a template selection on cancel.

Suggestions

  • style={{ width: "100%" }} on Radio.Group (inline on line 278): Replace with className="w-full" for consistency.
  • zIndex={1400} // below chakra modals (inline on line 361): The comment references Chakra, which is being removed. Track this for cleanup once Chakra is fully gone.
  • useCallback for handleSelection/handleReset: Lines 190 and 200 suppress react-hooks/exhaustive-deps because these functions are not memoized. Wrapping them in useCallback would allow the suppressions to be removed.
  • Missing barrel index.ts: features/common/custom-reports/ has no index.ts, causing sibling features to import with deep paths. Adding a barrel would make imports stable across future refactors.

@@ -164,11 +151,27 @@ export const CustomReportTemplates = ({
deleteCustomReportMutationTrigger(id);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: fire-and-forget delete — errors are silently dropped

deleteCustomReportMutationTrigger(id) is not awaited, and there's no error handler. If the DELETE request fails (network error, 403, 404), onSavedReportDeleted() has already been called and local state has already been reset — the UI shows a success state, but the report still exists on the server.

const handleDeleteReport = async (id: string) => {
  try {
    await deleteCustomReportMutationTrigger(id).unwrap();
    if (id === fetchedReport?.id) {
      handleReset();
      onSavedReportDeleted();
    }
  } catch (error) {
    message.error(getErrorMessage(error, "A problem occurred while deleting the report."));
  }
};

Note: the early state reset should move inside the try block so it only runs on success.

value={selectedReportId}
style={{ width: "100%" }}
>
<Space orientation="vertical" className="w-full" size="small">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Invalid orientation prop on <Space> — layout will default to horizontal

<Space> does not have an orientation prop; the correct prop is direction. Because extra props are spread silently, TypeScript won't catch this, but the list will render horizontally instead of vertically:

<Space direction="vertical" className="w-full" size="small">

popoverOnOpen();
setPopoverIsOpen(true);
} else {
handleApplyTemplate();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

onOpenChange calls handleApplyTemplate unconditionally on every close — including when the user clicks Cancel

When the user clicks the Cancel button, handleCancel calls setPopoverIsOpen(false), which triggers onOpenChange(false), which then calls handleApplyTemplate(). This means cancelling silently applies whatever template was selected. The same issue occurs when the popover is dismissed by clicking outside.

One fix: track whether the user explicitly cancelled via a ref, and check it in onOpenChange:

const cancelledRef = useRef(false);

// In handleCancel:
cancelledRef.current = true;
setPopoverIsOpen(false);

// In onOpenChange:
onOpenChange={(open) => {
  if (open) {
    setPopoverIsOpen(true);
  } else if (!cancelledRef.current) {
    handleApplyTemplate();
  } else {
    cancelledRef.current = false;
  }
}}

<Radio.Group
onChange={(e) => handleSelection(e.target.value)}
value={selectedReportId}
style={{ width: "100%" }}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Inline style on Radio.Group — use Tailwind utility instead

<Radio.Group
  onChange={(e) => handleSelection(e.target.value)}
  value={selectedReportId}
  className="w-full"
>

style={{ width: "100%" }} can be replaced with the existing w-full Tailwind class, keeping styles consistent with the rest of the file.

Merged via the queue into main with commit f34bd93 Apr 9, 2026
52 checks passed
@gilluminate gilluminate deleted the gill/ENG-3183/datamap-report-templates-antd branch April 9, 2026 15:09
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.

2 participants