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}. + > + )} +
+