Files
fusion/packages/dashboard/app/components/DataBoundary.tsx
gsxdsm 1e49494bac feat(i18n): full-sweep string migration — 5,930 keys across 5 locales (#1352)
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>
2026-06-03 19:06:53 -07:00

68 lines
1.9 KiB
TypeScript

import { AlertCircle } from "lucide-react";
import type { ReactNode } from "react";
import { useTranslation } from "react-i18next";
import { getErrorMessage } from "@fusion/core";
import { AgentEmptyState } from "./AgentEmptyState";
import { ProjectGridSkeleton } from "./ProjectGridSkeleton";
export interface DataBoundaryProps {
isEmpty: boolean;
isLoading?: boolean;
hasFetched?: boolean;
error?: unknown;
loadingFallback?: ReactNode;
emptyFallback?: ReactNode;
errorFallback?: ReactNode;
children: ReactNode;
}
function DefaultErrorFallback({ error }: { error: unknown }) {
const { t } = useTranslation("app");
return (
<div className="agent-empty" data-testid="data-boundary-error">
<AlertCircle className="agent-empty-state__icon" size={48} opacity={0.3} />
<p className="agent-empty-state__title">{t("common.unableToLoadData", "Unable to load data")}</p>
<p className="agent-empty-state__description text-secondary">
{getErrorMessage(error) || t("common.somethingWentWrong", "Something went wrong while loading this view.")}
</p>
</div>
);
}
export function DataBoundary({
isEmpty,
isLoading = false,
hasFetched = false,
error,
loadingFallback,
emptyFallback,
errorFallback,
children,
}: DataBoundaryProps) {
const { t } = useTranslation("app");
if (error) {
return <>{errorFallback ?? <DefaultErrorFallback error={error} />}</>;
}
const shouldShowLoading = isLoading || (!hasFetched && !error);
if (shouldShowLoading) {
return <>{loadingFallback ?? <ProjectGridSkeleton />}</>;
}
if (hasFetched && isEmpty) {
return (
<>
{emptyFallback ?? (
<AgentEmptyState
title={t("common.noDataAvailable", "No data available")}
description={t("common.nothingToShow", "There is nothing to show yet.")}
ctaLabel=""
/>
)}
</>
);
}
return <>{children}</>;
}