fix(apps): drop iframe auto-retry, add reopen hint to stuck overlay

This commit is contained in:
Gagan 2026-07-06 21:00:45 +05:30
parent f2bc01ffa9
commit 5a7fd1506c

View file

@ -1,5 +1,5 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { ArrowLeft, BadgeCheck, ExternalLink, Info, Loader2, RotateCw, UploadCloud } from 'lucide-react' import { ArrowLeft, BadgeCheck, ExternalLink, Info, RotateCw, UploadCloud } from 'lucide-react'
import type { rowboatApp } from '@x/shared' import type { rowboatApp } from '@x/shared'
import { appOpened } from '@/lib/analytics' import { appOpened } from '@/lib/analytics'
import { AppDetail } from '@/components/apps/app-detail' import { AppDetail } from '@/components/apps/app-detail'
@ -36,10 +36,10 @@ export function AppFrame({ app, onBack }: { app: rowboatApp.AppSummary; onBack:
return () => window.clearTimeout(timer) return () => window.clearTimeout(timer)
}, [watchKey]) }, [watchKey])
// Stuck recovery: the usual cause is the apps server not being reachable yet // Stuck diagnosis: the usual cause is the apps server not being reachable
// (it starts with the main process; on a fresh launch or a quick relaunch the // yet (it starts with the main process; on a fresh launch or a quick
// first iframe load can beat it). Auto-retry instead of demanding a manual // relaunch the first iframe load can beat it). Say when the server itself
// click, and say when the server itself is the problem. // is the problem.
const [serverDown, setServerDown] = useState(false) const [serverDown, setServerDown] = useState(false)
useEffect(() => { useEffect(() => {
if (loadState !== 'stuck') return if (loadState !== 'stuck') return
@ -47,11 +47,7 @@ export function AppFrame({ app, onBack }: { app: rowboatApp.AppSummary; onBack:
void window.ipc.invoke('apps:serverStatus', {}).then((s) => { void window.ipc.invoke('apps:serverStatus', {}).then((s) => {
if (!cancelled) setServerDown(!s.running) if (!cancelled) setServerDown(!s.running)
}).catch(() => { /* status probe is best-effort */ }) }).catch(() => { /* status probe is best-effort */ })
const timer = window.setTimeout(() => setReloadNonce((n) => n + 1), 4000) return () => { cancelled = true }
return () => {
cancelled = true
window.clearTimeout(timer)
}
}, [loadState]) }, [loadState])
return ( return (
@ -126,16 +122,16 @@ export function AppFrame({ app, onBack }: { app: rowboatApp.AppSummary; onBack:
<div className="text-muted-foreground"> <div className="text-muted-foreground">
{serverDown ? 'The Rowboat apps server is still starting up.' : 'This app is taking too long to load.'} {serverDown ? 'The Rowboat apps server is still starting up.' : 'This app is taking too long to load.'}
</div> </div>
<div className="flex items-center gap-2 text-xs text-muted-foreground">
<Loader2 className="size-3.5 animate-spin" /> Retrying automatically
</div>
<button <button
type="button" type="button"
onClick={() => setReloadNonce((n) => n + 1)} onClick={() => setReloadNonce((n) => n + 1)}
className="rounded-md border border-border px-3 py-1.5 font-medium hover:bg-accent" className="rounded-md border border-border px-3 py-1.5 font-medium hover:bg-accent"
> >
Retry now Retry
</button> </button>
<div className="max-w-xs text-center text-xs text-muted-foreground">
If it still doesn&apos;t load, go back to Apps and open it again.
</div>
<div className="font-mono text-xs text-muted-foreground">{app.origin}</div> <div className="font-mono text-xs text-muted-foreground">{app.origin}</div>
</div> </div>
)} )}