From cf45911b69275db59d28a2b47aa2c4a515a0f235 Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Thu, 30 Jul 2026 23:54:12 +0200 Subject: [PATCH] Web upgrade: Next 16 + React 19 + MSAL v4 (#114) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(web): bump to next 16, react 19, msal-browser 4, msal-react 3 react 19.2 aligns the declared dependency with the React the app router has been running all along (Next-vendored 19 canary). msal-react 3.0.29 is the React-19-compatible bridge that only needs msal-browser 4 — deliberately NOT msal v5, whose COOP redirect bridge requires new bridge pages per origin plus app-registration changes (separate project). The react-leaflet peer overrides are gone: react 19 satisfies react-leaflet 5 natively. Co-Authored-By: Claude Fable 5 * fix(web): react 19 / msal v4 / next 16 code adaptations - msalConfig: allowNativeBroker -> allowPlatformBroker (v4 rename); storeAuthStateInCookie stays (deprecated in v4, removed only in v5) - zero-arg useRef() removed in @types/react 19: GlobalSearch (2x), dashboard autoLoadTimerRef - React.MutableRefObject -> React.RefObject in 5 session/progress hooks (all refs are mutable in 19 types) - layout: data-scroll-behavior="smooth" opt-in so route changes keep jumping instead of animating (Next 16 stopped suppressing CSS smooth-scroll during navigation) - next.config: analyzer comment - Turbopack default build skips the webpack-only analyzer, use --webpack for ANALYZE runs Co-Authored-By: Claude Fable 5 * chore(web): untrack Next-managed next-env.d.ts, generate types in CI Next 16 rewrites next-env.d.ts on every dev/build run and the routes import inside flips between .next/types and .next/dev/types (vercel/ next.js#86001) - official guidance is to gitignore it. CI now runs `next typegen` before tsc so the type stubs exist on a fresh checkout. Co-Authored-By: Claude Fable 5 * chore(web): migrate lint script to eslint CLI (next lint removed in 16) Minimal flat config from eslint-config-next@16 (core-web-vitals + typescript) with build-output ignores. Lint stays out of CI as before; the 264 pre-existing findings are untouched. Co-Authored-By: Claude Fable 5 --------- Co-authored-by: Claude Fable 5 --- .github/workflows/ci.yml | 5 + .gitignore | 3 + .../app/dashboard/page.tsx | 2 +- src/Web/autopilot-monitor-web/app/layout.tsx | 5 +- .../app/progress/hooks/useProgressEvents.ts | 2 +- .../app/progress/hooks/useProgressSignalR.ts | 2 +- .../app/sessions/hooks/useSessionDetail.ts | 4 +- .../app/sessions/hooks/useSessionEvents.ts | 2 +- .../app/sessions/hooks/useSessionSignalR.ts | 4 +- .../components/GlobalSearch.tsx | 4 +- .../autopilot-monitor-web/eslint.config.mjs | 21 + .../autopilot-monitor-web/lib/msalConfig.ts | 4 +- src/Web/autopilot-monitor-web/next-env.d.ts | 6 - src/Web/autopilot-monitor-web/next.config.ts | 6 +- .../autopilot-monitor-web/package-lock.json | 837 +++++++++++++----- src/Web/autopilot-monitor-web/package.json | 28 +- src/Web/autopilot-monitor-web/tsconfig.json | 5 +- .../utils/page-lastmod.generated.ts | 8 +- 18 files changed, 691 insertions(+), 257 deletions(-) create mode 100644 src/Web/autopilot-monitor-web/eslint.config.mjs delete mode 100644 src/Web/autopilot-monitor-web/next-env.d.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 436fedcc..68875a83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,11 @@ jobs: - run: npm ci + # next-env.d.ts + .next type stubs are gitignored (Next-managed since + # v16); typegen generates them so tsc sees the same types as a build. + - name: Generate Next.js types + run: npx next typegen + - name: Typecheck run: npx tsc --noEmit diff --git a/.gitignore b/.gitignore index f2096cff..9e790e58 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,9 @@ __azurite_db*__.json node_modules/ .next/ out/ +# Managed by Next.js since v16 (regenerated by next dev/build/typegen; path +# inside flips between .next/types and .next/dev/types) — must not be tracked. +next-env.d.ts build/ dist/ !rules/dist/ diff --git a/src/Web/autopilot-monitor-web/app/dashboard/page.tsx b/src/Web/autopilot-monitor-web/app/dashboard/page.tsx index be27a68c..8cb42912 100644 --- a/src/Web/autopilot-monitor-web/app/dashboard/page.tsx +++ b/src/Web/autopilot-monitor-web/app/dashboard/page.tsx @@ -232,7 +232,7 @@ function HomeContent() { // Auto-load ALL remaining sessions when search is active and local results are insufficient. // Uses a 500ms debounce so rapid typing doesn't trigger unnecessary loads. - const autoLoadTimerRef = useRef>(); + const autoLoadTimerRef = useRef | undefined>(undefined); useEffect(() => { if (autoLoadTimerRef.current) clearTimeout(autoLoadTimerRef.current); diff --git a/src/Web/autopilot-monitor-web/app/layout.tsx b/src/Web/autopilot-monitor-web/app/layout.tsx index 748150c1..c6139019 100644 --- a/src/Web/autopilot-monitor-web/app/layout.tsx +++ b/src/Web/autopilot-monitor-web/app/layout.tsx @@ -113,8 +113,11 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode; }>) { + // data-scroll-behavior: Next 16 no longer auto-suppresses CSS smooth-scroll + // during route navigation; without the opt-in, globals.css's + // `scroll-behavior: smooth` would animate every route change to top. return ( - +