From 1b5a806963ed2d8ba24a99665ab1d64e617262d8 Mon Sep 17 00:00:00 2001 From: Monica Khoury <99693443+monicakh@users.noreply.github.com> Date: Mon, 28 Sep 2026 18:21:34 +0300 Subject: [PATCH] fix: show support contact message if Studio fails to load (FE-4460) (#50872) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Adds a fallback message ("Taking longer than expected?... contact support@supabase.io") shown after 7s if Studio fails to fully load, for the Next.js runtime — mirrors the existing TanStack-only `ShellFallback`, which had no Next.js equivalent - Fixes the support email in the existing TanStack `ShellFallback` (was `support@supabase.com`, should be `support@supabase.io`) - Extracts the shared copy (message, email, delay) into one file so both fallbacks stay in sync ## Why Linear FE-4460: users reported the Dashboard going completely blank with no way to reach support when a JS chunk failed to load. The Next.js runtime (the current default) had no fallback at all for this case. ## Test plan - [ ] Normal page load: fallback never appears - [ ] Simulated stuck boot (mount signal disabled): fallback appears after 7s with correct copy/email, no layout bugs - [ ] Same two checks on the TanStack runtime (`STUDIO_FRAMEWORK=tanstack`) - [ ] `pnpm --filter studio run typecheck` / `lint:ratchet` pass ## Summary by CodeRabbit * **New Features** * Added a loading fallback that appears if the app takes too long to load, with guidance to clear browser cookies and reload. * On self-hosted platforms, the fallback includes a support contact link. * The fallback is automatically hidden once the app loads. --- .../interfaces/App/ShellFallback.tsx | 13 +++- .../BootTimeoutFallback.tsx | 75 +++++++++++++++++++ apps/studio/lib/boot-fallback-copy.ts | 6 ++ apps/studio/pages/_app.tsx | 5 ++ apps/studio/pages/_document.tsx | 2 + 5 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 apps/studio/components/ui/BootTimeoutFallback/BootTimeoutFallback.tsx create mode 100644 apps/studio/lib/boot-fallback-copy.ts diff --git a/apps/studio/components/interfaces/App/ShellFallback.tsx b/apps/studio/components/interfaces/App/ShellFallback.tsx index ff6a1666af7..24722a22998 100644 --- a/apps/studio/components/interfaces/App/ShellFallback.tsx +++ b/apps/studio/components/interfaces/App/ShellFallback.tsx @@ -1,5 +1,10 @@ import { LogoLoader } from 'ui' +import { + BOOT_FALLBACK_MESSAGE, + BOOT_FALLBACK_REVEAL_DELAY_SECONDS, + BOOT_FALLBACK_SUPPORT_EMAIL, +} from '@/lib/boot-fallback-copy' import { IS_PLATFORM } from '@/lib/constants' // Baked into the prerendered SPA shell (_shell.html) — this is the static HTML @@ -15,7 +20,7 @@ export function ShellFallback() { #studio-shell-help { visibility: hidden; opacity: 0; - animation: studio-shell-help-reveal 0.3s ease-out 7s forwards; + animation: studio-shell-help-reveal 0.3s ease-out ${BOOT_FALLBACK_REVEAL_DELAY_SECONDS}s forwards; } @keyframes studio-shell-help-reveal { to { @@ -40,13 +45,13 @@ export function ShellFallback() { data-nosnippet="" className="max-w-md text-center text-sm text-foreground-light" > - Taking longer than expected? Try clearing your browser cookies and reloading the page. + {BOOT_FALLBACK_MESSAGE} {IS_PLATFORM && ( <> {' '} If the problem persists, contact{' '} - - support@supabase.com + + {BOOT_FALLBACK_SUPPORT_EMAIL} . > diff --git a/apps/studio/components/ui/BootTimeoutFallback/BootTimeoutFallback.tsx b/apps/studio/components/ui/BootTimeoutFallback/BootTimeoutFallback.tsx new file mode 100644 index 00000000000..5ac98fe7087 --- /dev/null +++ b/apps/studio/components/ui/BootTimeoutFallback/BootTimeoutFallback.tsx @@ -0,0 +1,75 @@ +import { + BOOT_FALLBACK_MESSAGE, + BOOT_FALLBACK_REVEAL_DELAY_SECONDS, + BOOT_FALLBACK_SUPPORT_EMAIL, +} from '@/lib/boot-fallback-copy' +import { IS_PLATFORM } from '@/lib/constants' + +const FALLBACK_ID = 'studio-boot-fallback' + +// Next.js equivalent of the TanStack build's ShellFallback (see +// components/interfaces/App/ShellFallback.tsx): a safety net for a stuck +// chunk load (FE-4460). Next always server-renders real page content into +// , so — unlike TanStack's ClientOnly fallback, which shows nothing +// until hydration — this can't be a full-screen overlay shown by default; it +// has to reveal itself only once it's clear the page is actually stuck. +// +// The reveal is pure CSS (a delayed animation), not a JS timer, so it still +// fires even if every JS chunk fails to load. Hiding it on a successful +// mount necessarily needs JS — see `clearBootTimeoutFallback` — but a +// missed hide is harmless: the reveal only starts after +// BOOT_FALLBACK_REVEAL_DELAY_SECONDS, by which point a successful mount has +// long since hidden it. +export function BootTimeoutFallback() { + return ( + <> + +
+ {BOOT_FALLBACK_MESSAGE} + {IS_PLATFORM && ( + <> + {' '} + If the problem persists, contact{' '} + {BOOT_FALLBACK_SUPPORT_EMAIL}. + > + )} +
+