Migration (multi-agent sweep over 216 files, 60 batches):
- Every user-visible dashboard + TUI string moved to t() with the exact
English inline default (en rendering byte-identical)
- Catalogs merged from per-batch fragments: en/zh-CN/zh-TW/fr/es now
carry ~5,930 keys each across common/app/errors/cli namespaces;
CLI bundles regenerated (6 locales incl. ko)
Integration fixes:
- 18 type errors: reserved {{count}} interpolations renamed, malformed
plural call, hand-rolled t-param types replaced with TFunction<"app">
- 23 lint errors: superseded label constants/helpers removed
- ExecutorStatusBar hook-order violation (keyboard-open early return
moved below hooks)
- TUI tests wrapped in I18nextProvider (uninitialized fallback renders
literal {{placeholders}}); dashboard vitest.setup boots a minimal en
i18next instance for the same reason
Known WIP (next commits): ~457 residual strings across 50 batches,
Korean drafts for swept keys, and a dashboard test-suite pass that is
still being stabilized (~283 failures under investigation — fake-timer
waitFor interaction, likely stale node_modules vs merged lockfile).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
import "./BackendConnectionErrorPage.css";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
interface BackendConnectionErrorPageProps {
|
|
errorMessage: string;
|
|
isRetrying: boolean;
|
|
onRetry: () => void;
|
|
onManageConnection?: () => void;
|
|
}
|
|
|
|
function isDesktopShell(): boolean {
|
|
if (typeof window === "undefined") return false;
|
|
return typeof window.fusionShell?.resetDesktopMode === "function";
|
|
}
|
|
|
|
async function changeLaunchMode(): Promise<void> {
|
|
const shell = typeof window !== "undefined" ? window.fusionShell : undefined;
|
|
try {
|
|
await shell?.resetDesktopMode?.();
|
|
} catch {
|
|
// Best-effort; still strip query params and reload.
|
|
}
|
|
const url = new URL(window.location.href);
|
|
url.searchParams.delete("serverBaseUrl");
|
|
url.searchParams.delete("shellMode");
|
|
window.location.replace(url.toString());
|
|
}
|
|
|
|
export function BackendConnectionErrorPage({
|
|
errorMessage,
|
|
isRetrying,
|
|
onRetry,
|
|
onManageConnection,
|
|
}: BackendConnectionErrorPageProps) {
|
|
const { t } = useTranslation("app");
|
|
const showChangeLaunchMode = isDesktopShell();
|
|
return (
|
|
<div className="project-overview-empty" role="alert" aria-live="polite">
|
|
<h2>{t("backend.connectionError", "Can't reach the Fusion backend")}</h2>
|
|
<p className="settings-muted">
|
|
{t("backend.couldNotLoad", "Fusion couldn't load your projects right now. Please make sure the backend is running and try again.")}
|
|
</p>
|
|
<p className="settings-muted">{t("backend.error", "Error: {{error}}", { error: errorMessage })}</p>
|
|
<div className="modal-actions">
|
|
<button type="button" className="btn btn-primary" onClick={onRetry} disabled={isRetrying}>
|
|
{isRetrying ? t("backend.retrying", "Retrying…") : t("backend.retryConnection", "Retry Connection")}
|
|
</button>
|
|
{showChangeLaunchMode && (
|
|
<button type="button" className="btn" onClick={() => void changeLaunchMode()}>
|
|
{t("backend.changeLaunchMode", "Change Launch Mode…")}
|
|
</button>
|
|
)}
|
|
{onManageConnection && (
|
|
<button type="button" className="btn" onClick={onManageConnection}>
|
|
{t("backend.manageConnection", "Manage Connection")}
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|