Files
supabase/apps/studio/components/interfaces/App/ShellFallback.tsx
T
Monica Khoury 1b5a806963 fix: show support contact message if Studio fails to load (FE-4460) (#50872)
## 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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## 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.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-28 18:21:34 +03:00

79 lines
2.7 KiB
TypeScript

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
// shown on every cold load until the JS bundle hydrates, so nothing here can
// rely on JS: the loader animation, the 7s stuck-load help reveal, and the
// noscript message are all pure CSS/HTML.
export function ShellFallback() {
return (
<>
<style>{`
/* visibility (not just opacity) so the text is also hidden from
screen readers until the reveal. */
#studio-shell-help {
visibility: hidden;
opacity: 0;
animation: studio-shell-help-reveal 0.3s ease-out ${BOOT_FALLBACK_REVEAL_DELAY_SECONDS}s forwards;
}
@keyframes studio-shell-help-reveal {
to {
visibility: visible;
opacity: 1;
}
}
`}</style>
<div
id="studio-shell-loader"
className="fixed inset-0 flex flex-col items-center justify-center gap-8 p-4"
>
{/* LogoLoader fills its parent, so give it a fixed-height box — otherwise
it stretches to the full column and pushes the help text offscreen. */}
<div className="h-[62px] w-full">
<LogoLoader />
</div>
{/* data-nosnippet keeps Google from surfacing this boilerplate as the
search snippet for dashboard URLs (the shell serves every route). */}
<p
id="studio-shell-help"
data-nosnippet=""
className="max-w-md text-center text-sm text-foreground-light"
>
{BOOT_FALLBACK_MESSAGE}
{IS_PLATFORM && (
<>
{' '}
If the problem persists, contact{' '}
<a href={`mailto:${BOOT_FALLBACK_SUPPORT_EMAIL}`} className="underline">
{BOOT_FALLBACK_SUPPORT_EMAIL}
</a>
.
</>
)}
</p>
</div>
{/* dangerouslySetInnerHTML keeps React hydration from diffing noscript
children, which the server renders as real markup but the client
treats as raw text. */}
<noscript
dangerouslySetInnerHTML={{
__html: `
<style>#studio-shell-loader{display:none}</style>
<div data-nosnippet class="fixed inset-0 flex items-center justify-center p-4">
<p class="text-sm text-foreground-light text-center">
Supabase Studio requires JavaScript. Enable JavaScript in your browser settings and reload the page.
</p>
</div>
`,
}}
/>
</>
)
}