Skip to content

ENG-2987: Upgrade Admin UI Next.js from 14 to 16#7907

Merged
gilluminate merged 17 commits intomainfrom
gill/ENG-2987/upgrade-nextjs-14-to-16
Apr 15, 2026
Merged

ENG-2987: Upgrade Admin UI Next.js from 14 to 16#7907
gilluminate merged 17 commits intomainfrom
gill/ENG-2987/upgrade-nextjs-14-to-16

Conversation

@gilluminate
Copy link
Copy Markdown
Contributor

@gilluminate gilluminate commented Apr 13, 2026

Ticket ENG-2987

Description Of Changes

Upgrades the Admin UI from Next.js 14.2.35 to Next.js 16.x (and React 18 to React 19, which Next 15+ requires). Next.js upgrades had been suppressed in Dependabot because earlier attempts broke the output: "export" static build and conflicted with Chakra v2's portal/focus-trap system under React 19. With the Chakra → Ant Design migration far enough along, this upgrade is now unblocked.

Code Changes

  • Bumped next 14 → 16, react/react-dom 18 → 19, and eslint-config-next / @next/bundle-analyzer to match across admin-ui, fidesui, and sample-app
  • Replaced next-transpile-modules with Next's built-in transpilePackages in next.config.js
  • Added --webpack flag to next dev / next build to keep webpack as the bundler (Turbopack is now Next 16's default)
  • Replaced next lint (removed in Next 16) with direct eslint CLI; added .eslintignore
  • Removed the reactStrictMode: false workaround that was there for Chakra modal bugs
  • Deleted pages/api/auth/[...nextauth].ts (static export cannot host API routes; this was dead on the exported build anyway)
  • Renamed src/features/common/table/hooks/types.d.tstypes.ts and tightened a few call sites where React 19's stricter types flagged issues (useCountUp, CustomList, SystemDataGroup, a few modal/form components, Popup, etc.)
  • Added app-env.d.ts and updated next-env.d.ts / tsconfig.json for the new Next 16 type surface

Steps to Confirm

  1. cd clients/admin-ui && npm i at the repo root, then run the dev server — verify the app boots and the dashboard renders
  2. Navigate through a few key flows (Systems, Integrations, Privacy Requests, Consent, Settings) and confirm no console errors or broken modals/drawers/menus
  3. Run npm run prod-export — verify output: "export" still produces a working static bundle (see https://ethyca.atlassian.net/wiki/spaces/EN/pages/3986849842/Testing+Next.js+Static+Export+Locally)

Pre-Merge Checklist

  • Issue requirements met
  • All CI pipelines succeeded
  • CHANGELOG.md updated (via changelog/7907-upgrade-nextjs-14-to-16.yaml)
    • 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 Apr 13, 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 14, 2026 9:32pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
fides-privacy-center Ignored Ignored Apr 14, 2026 9:32pm

Request Review

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 13, 2026

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
See the Details below.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 7a2df9d.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

  • clients/admin-ui/package.json
  • clients/fidesui/package.json
  • clients/package-lock.json
  • clients/privacy-center/package.json
  • clients/sample-app/package.json

@gilluminate gilluminate force-pushed the gill/ENG-2987/upgrade-nextjs-14-to-16 branch from 5a73dde to c2541d6 Compare April 13, 2026 21:05
@gilluminate gilluminate force-pushed the gill/ENG-2987/upgrade-nextjs-14-to-16 branch from c2541d6 to 68283c5 Compare April 13, 2026 21:11
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 13, 2026

Title Lines Statements Branches Functions
admin-ui Coverage: 8%
6.1% (2663/43647) 5.22% (1293/24752) 4.19% (542/12916)
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)

`form.validateFields({ validateOnly: true })` was unreliable on mount in
edit mode under antd v6 / React 19 — the Promise didn't resolve in time,
so `submittable` stayed false and the Next button remained disabled.

Since `name` is the only required field, gate `submittable` on its
presence directly, falling back to `monitor?.name` for the initial
render before `useWatch` emits.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gilluminate gilluminate force-pushed the gill/ENG-2987/upgrade-nextjs-14-to-16 branch from 3228de5 to 50b1730 Compare April 13, 2026 22:35
"analyze:server": "cross-env BUNDLE_ANALYZE=server next build --webpack",
"build": "next build --webpack",
"build:test": "NODE_ENV=test next build --webpack",
"build:vercel": "(cd ../fides-js && npm run build) & (cd ../admin-ui && next build --webpack && node -e \"require('fs').writeFileSync('.next/routes-manifest-deterministic.json', '{}')\" && node -e \"if(process.env.VERCEL){const fs=require('fs'),path=require('path');const src='/vercel/path0/clients',dst='/vercel/path0';for(const e of fs.readdirSync(src)){try{fs.symlinkSync(path.join(src,e),path.join(dst,e),'dir')}catch(err){if(err.code!=='EEXIST')throw err}}}\") & wait",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This big ugly command is due to a bug in Vercel CLI where the post-build validation drops intermediate path segments from multi-segment Root Directory. I have a bug report submitted here: vercel/vercel#15937

@gilluminate gilluminate marked this pull request as ready for review April 13, 2026 23:51
@gilluminate gilluminate requested a review from a team as a code owner April 13, 2026 23:51
@gilluminate gilluminate requested review from jpople and removed request for a team April 13, 2026 23:51
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: ENG-2987 — Next.js 14 → 16 / React 18 → 19 Upgrade

This is a well-scoped and carefully executed major dependency upgrade. The PR description is detailed, the migration rationale is clear, and the author has methodically addressed each React 19 type-strictness breakage across the codebase. Overall the change is in good shape.

Summary of findings

One item to verify before merge:

  • gcm.ts gtag pattern (inline comment): Replacing dataLayer.push(arguments) with datalay.push(args) pushes an Array instead of an IArguments object. The canonical GTM snippet relies on arguments specifically. This may work fine in practice, but should be validated against a live GTM/gtag setup — or use // eslint-disable-next-line prefer-rest-params to keep the original pattern.

Suggestions / low-risk items:

  • next-env.d.ts: The import "./.next/dev/types/routes.d.ts" line references a build artifact that won't exist on a fresh checkout. Investigate whether TypeScript errors occur before the first next dev run, and whether this file should be in .gitignore (Next.js typically owns and regenerates it).
  • build:vercel script: The inline Node.js for Vercel symlinks is hard to maintain and has limited error handling. Worth extracting to a dedicated script file soon.
  • ConfigureMonitorForm.tsx: The submittable simplification is pragmatic and the comment explains the reasoning well — just consider adding a note warning future contributors to update the guard if new required fields are added.
  • app-env.d.ts: The global JSX shim is correct; ElementChildrenAttribute is technically deprecated in React 19 but poses no immediate risk.
  • next.config.js: Enabling reactStrictMode: true is the right call. Watch for double-invocation side-effects in remaining Chakra components during dev-mode testing post-merge.

Positives

  • Removing next-transpile-modules in favour of built-in transpilePackages is the correct upgrade path.
  • The --webpack flag rationale (Turbopack + Lightning CSS breaking fidesui's :export pseudo-class) is well-documented in package.json with a reference to ENG-3410.
  • All @reduxjs/toolkit/dist/query@reduxjs/toolkit/query import fixes are correct — dist/ subpaths are non-public API.
  • useCountUp.ts useRef initialisation with explicit undefined and useRef<number | undefined> is the correct React 19 pattern.
  • The local FidesGlobal interface in Preview.tsx (with TODO ENG-3409) is a clean short-term fix for the moduleResolution: bundler constraint.
  • fidesui peer dep ranges accepting ^18 || ^19 are correctly set for backward compatibility.

🔬 Codegraph: unavailable


💡 Write /code-review in a comment to re-run this review.

Comment thread clients/fides-js/src/integrations/gcm.ts Outdated
Comment thread clients/admin-ui/next-env.d.ts
Comment thread clients/admin-ui/package.json
Comment thread clients/admin-ui/app-env.d.ts
Comment thread clients/admin-ui/next.config.js
Copy link
Copy Markdown

@rayharnett rayharnett 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 for PR 7907

Branch: gill/ENG-2987/upgrade-nextjs-14-to-16
Focus: Upgrade Next.js from 14 to 16 and React from 18 to 19, including related UI component migrations from Formik to Ant Design (via fidesui).


🚨 Critical Issues (Must Fix)

No critical security or functional breaking issues were identified in the provided diff.


⚠️ Warnings (Should Fix)

1. Potential mismatch in AuthenticateOktaForm error handling

File: clients/admin-ui/src/features/config-wizard/AuthenticateOktaForm.tsx

Description:
The transition from Formik's submission pattern to Ant Design's (via fidesui) uses a new onFinish handler and manually manages the submittable state using an useEffect with form.validateFields({ validateOnly: true }). While this works, it adds complexity.

Rationale:
The current implementation of checkValidity is called on every change via allValues. While functional, if the form becomes very large, frequent validation calls might impact performance slightly, though unlikely for this specific small form. More importantly, ensure that any asynchronous custom validators in rules are properly handled by the Ant Design form instance.

Suggested Solution:
Ensure that all custom validators (like the JSON parse check for the private key) are robust and don't cause infinite loops or unnecessary re-renders. The current implementation looks okay, but keep an eye on performance if more fields are added.


💡 Suggestions (Nitpicks/Improvements)

1. Cleanup of commented out code in [...nextauth].ts

File: clients/admin-ui/src/pages/api/auth/[...nextauth].ts

Description:
The file was deleted, but it contains a large block of commented-out code.

Suggestion:
Since this is a public repository (as per project guidelines), even commented-out code that might contain business logic or old patterns should be cleaned up to keep the codebase professional and avoid cluttering history if not strictly necessary for future reference.

2. Explicitly handle console.error in login.tsx

File: clients/admin-ui/src/pages/login.tsx

Description:
A lint suppression (// eslint-disable-next-line no-console) was added to handle an error log.

Suggestion:
Instead of just suppressing the lint warning, consider using a proper logging utility if one exists in the project (e.g., a service that sends errors to a monitoring tool like Sentry), which would be more consistent with production-grade applications.

3. Webpack flag documentation in package.json

File: clients/admin-ui/package.json

Description:
A comment was added explaining the need for the --webpack flag to avoid Turbopack issues with Lightning CSS.

Suggestion:
This is excellent practice. Documenting "why" a workaround exists (especially one that limits performance like pinning to Webpack) is very helpful for future maintainers.


✅ Good Practices

  • Dependency Upgrades: The upgrade from Next.js 14 -> 16 and React 18 -> 19 is handled cleanly, including the necessary @types updates.
  • UI Component Migration: Moving from Formik to Ant Design/fidesui simplifies the component tree by removing the nested function children pattern required by Formik, making the JSX much flatter and easier to read.
  • Testability Improvements: Adding data-testid attributes (e.g., input-orgUrl, submit-btn) during the migration is a great move for maintaining/improving E2E and unit test stability.
  • Documentation of Workarounds: The comment in package.json regarding the Webpack flag is a perfect example of good technical documentation within code.

@gilluminate
Copy link
Copy Markdown
Contributor Author

gilluminate commented Apr 14, 2026

@rayharnett Thanks for the thorough review! A few notes:

  • AuthenticateOktaForm - Good callout. This is a small form (3 fields) so perf shouldn't be an issue, but I'll keep an eye on it. The Ant Design validateFields({ validateOnly: true }) pattern is what their docs recommend for this use case.
  • [...nextauth].ts - This file was fully deleted in this PR, so no commented code to worry about.
  • login.tsx console.error - Fair point. We don't have a structured logging utility on the frontend yet, so console.error is our current pattern. Could be a follow-up.
  • Appreciate the callout on the webpack flag docs!

gilluminate and others added 2 commits April 14, 2026 10:29
Restores `dataLayer.push(arguments)` instead of rest-params to maintain
the IArguments object that GTM's dataLayer processor expects.

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

@jpople jpople left a comment

Choose a reason for hiding this comment

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

Did a bunch of smoke testing, everything's looking good.

@gilluminate gilluminate added this pull request to the merge queue Apr 15, 2026
Merged via the queue into main with commit 4527dbe Apr 15, 2026
52 of 55 checks passed
@gilluminate gilluminate deleted the gill/ENG-2987/upgrade-nextjs-14-to-16 branch April 15, 2026 16:48
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