refactor(desktop): loop-proof route redirects and contain content crashes
Stacked on #6353. That PR fixes the specific SUPER-1814 crash; this one makes the whole crash class unreachable so it can't come back at a different site.
Background
TanStack's <Navigate> re-navigates whenever its props object identity changes (confirmed in the installed source and upstream main: if (previousPropsRef.current !== props)). Rendered inline, it re-navigates on every parent re-render and loops into React error #185 — which unmounts the tree. The codebase had been defending this by hoisting each <Navigate> element by hand (#5729), which is whack-a-mole: the six un-hoisted sites I found were all latent instances of the same bug.
What this does
1. A loop-proof Redirect component (renderer/components/Redirect) — re-navigates only when the resolved target href changes, not on props identity. Safe to render inline with dynamic params/search.
2. Bans <Navigate> in the renderer via Biome noRestrictedImports (importNames: ["Navigate"]), pointing offenders at Redirect or beforeLoad. CI already fails on Biome warnings, so this is binding — mutation-tested with a canary file that the rule correctly rejected.
3. Migrates all sites:
- Reactive redirects (root index, sign-in, create-org, onboarding, authenticated layout ×3, dashboard versionMismatch, cloud gates ×2) →
Redirect. - Static/legacy redirects (settings index, presets→terminal, tasks
?type=prs, tasks PR detail) →beforeLoad: () => { throw redirect(...) }, so no navigation happens at render time at all.
4. Fixes a latent cloud-settings bug — the CLOUD_ACCESS flag reads undefined while loading, which the old gates treated as "no access" and bounced entitled users out. Now renders nothing until the flag resolves.
5. Adds a CatchBoundary around the dashboard Outlet — a crashing content route now shows a contained error pane with the sidebar and terminals still alive, instead of bubbling to the root boundary and unmounting the whole app (which is what made SUPER-1814 present as "Superset restarted itself").
Verification (CDP, dev desktop from this worktree)
- All four migrated redirect targets resolve correctly (
/workspace/$id→/new-workspace,/tasks?type=prs→/pull-requests,/settings→/settings/account,/settings/presets→/settings/terminal) with zero #185 signals and the layout surviving every transition. - Forced a render throw in a dashboard route (
/automations): the content-error pane rendered with the sidebar fully intact and the root "Something went wrong" page not shown — screenshot confirms containment. Reverted the probe after. Redirectvs an equivalent directnavigate({search})produce identical router state — no behavioral change beyond loop-proofing.- typecheck clean, lint clean, 1454 renderer tests pass.
Follow-ups (not in this PR)
- Renderer Sentry didn't capture Jose's crash despite
ErrorPagecallingcaptureException;render-process-gonein main only logs locally. Telemetry PR worth doing so this class is visible in monitoring. - A
Redirectunit test would need a router test harness the repo doesn't have yet.
Summary by cubic
Hardened renderer navigation to stop React #185 redirect loops and contain dashboard content crashes (SUPER-1814). Adds a loop‑proof Redirect for @tanstack/react-router, enforces it repo‑wide, moves static redirects to beforeLoad, and proves it with a renderer test.
-
Bug Fixes
- Stop infinite re-navigation: replace inline
<Navigate>with loop‑proofRedirect; move static redirects tobeforeLoadso nothing navigates during render. - Contain dashboard content-route crashes with a catch boundary that resets on full location
href; keep sidebar/terminals mounted, report to Sentry, log reporting failures, and wrap long messages. - Fix cloud settings gate: wait for
CLOUD_ACCESSto resolve instead of treatingundefinedas no access. - Handle failed navigations:
Redirectcatches errors, logs them, and clears its marker so later renders can retry.
- Stop infinite re-navigation: replace inline
-
Refactors
- Add
renderer/components/Redirectthat navigates only when the resolvedhrefchanges. - Ban
Navigatein the renderer via BiomenoRestrictedImports; useRedirectorbeforeLoad+redirect(...). - Migrate routes (root, sign-in, create-org, onboarding, authenticated layout, dashboard version mismatch, tasks legacy PR routes, settings index, presets→terminal) to the new patterns.
- Add a renderer unit test using
@testing-library/reactand@happy-dom/global-registratorto verify single navigation across re-renders.
- Add
Summary by CodeRabbit
-
New Features
- Added reliable redirect handling across authentication, onboarding, settings, dashboard, and legacy routes.
- Preserved relevant URL parameters during legacy route redirects.
- Added dashboard error recovery with error details, Go Home, and Reload App actions.
-
Bug Fixes
- Prevented repeated navigation and improved retry behavior when redirects fail.
- Prevented dashboard content errors from escaping the dashboard layout.
-
Tests
- Added comprehensive coverage for redirect behavior, including navigation updates and loop prevention.