Add a production i18n lint baseline while replacing dashboard copy with translation keys. - Localize task, board, mailbox, report, graph, settings, and shared dashboard surfaces. - Regenerate locale catalogs and resource types for the migration keys. - Add the i18n lint-baseline regression test and contributor guidance. Files changed: .changeset/fn-013-i18n-lint-baseline.md | 7 + docs/i18n-contributing.md | 11 + .../dashboard/app/components/ActiveAgentsPanel.tsx | 2 +- .../dashboard/app/components/AgentDetailView.tsx | 2 +- packages/dashboard/app/components/Board.tsx | 19 +- packages/dashboard/app/components/ChatView.tsx | 2 +- .../dashboard/app/components/ComposeChatPanel.tsx | 14 +- packages/dashboard/app/components/DockTaskList.tsx | 16 +- .../dashboard/app/components/FloatingWindow.tsx | 6 +- .../dashboard/app/components/GitHubImportModal.tsx | 4 +- .../dashboard/app/components/KnowledgeGraphPanel.tsx | 21 +- packages/dashboard/app/components/ListView.tsx | 2 +- .../app/components/MailboxArtifactAttachment.tsx | 16 +- packages/dashboard/app/components/MailboxModal.tsx | 12 +- .../app/components/MailboxStructuralItem.tsx | 13 +- .../app/components/MailboxTaskProposal.tsx | 10 +- .../app/components/MailboxTaskRecommendations.tsx | 12 +- packages/dashboard/app/components/MailboxView.tsx | 14 +- packages/dashboard/app/components/MermaidDiagram.tsx | 4 +- packages/dashboard/app/components/MeshTopology.tsx | 6 +- .../dashboard/app/components/MessageComposer.tsx | 24 +- .../app/components/NativeStructurePreview.tsx | 14 +- packages/dashboard/app/components/ProviderLoginDialog.tsx | 24 +- packages/dashboard/app/components/ReportActionMenu.tsx | 6 +- packages/dashboard/app/components/ReportModal.tsx | 26 +- packages/dashboard/app/components/TaskChatTab.tsx | 10 +- packages/dashboard/app/components/TaskDetailModal.tsx | 28 +- .../app/components/TaskVerificationStatus.tsx | 10 +- .../dashboard/app/components/WhatsAppChatPairingPanel.tsx | 38 +- .../components/command-center/CommandCenter.tsx | 4 +- .../components/command-center/IdeationPanel.tsx | 12 +- .../components/settings/sections/McpServersCard.tsx | 2 +- .../components/settings/sections/MemorySection.tsx | 4 +- .../app/task-modal-touch-resize-e2e-fixture.tsx | 28 +- packages/i18n/locales/en/app.json | 247 +++++++- packages/i18n/locales/es/app.json | 256 +++++++- packages/i18n/locales/fr/app.json | 256 +++++++- packages/i18n/locales/ko/app.json | 256 +++++++- packages/i18n/locales/pt-BR/app.json | 705 ++++++++++++++++++++ packages/i18n/locales/zh-CN/app.json | 256 +++++++- packages/i18n/locales/zh-TW/app.json | 256 +++++++- .../i18n/src/__tests__/i18n-lint-baseline.test.ts | 31 + packages/i18n/src/resources.d.ts | 229 ++++++- 43 files changed, 2627 insertions(+), 288 deletions(-) Fusion-Task-Id: FN-013 Fusion-Task-Lineage: 846ac221-c7c3-4ff0-a30d-69479b614765 Co-authored-by: Fusion <noreply@runfusion.ai>
42 lines
2.4 KiB
TypeScript
42 lines
2.4 KiB
TypeScript
import type { TaskVerificationRequest } from "@fusion/core";
|
|
import { AlertCircle, CheckCircle2, Loader2 } from "lucide-react";
|
|
import { useTranslation } from "react-i18next";
|
|
import "./TaskVerificationStatus.css";
|
|
|
|
function formatDuration(durationMs: number | undefined): string | null {
|
|
if (typeof durationMs !== "number") return null;
|
|
return `${(durationMs / 1000).toFixed(1)}s`;
|
|
}
|
|
|
|
/**
|
|
* FNXC:TaskVerificationStatus 2026-07-30-00:00:
|
|
* FN-8296 exposes executor-owned verification as persisted state in every human
|
|
* surface. This component deliberately renders a record only; it never offers a
|
|
* command control or reimplements the chat/executor permission boundary.
|
|
*/
|
|
export function TaskVerificationStatus({ request, compact = false }: { request: TaskVerificationRequest | null; compact?: boolean }) {
|
|
const { t } = useTranslation("app");
|
|
if (!request) return null;
|
|
|
|
const running = request.status === "requested" || request.status === "running";
|
|
const failed = request.status === "failed" || request.status === "rejected";
|
|
const Icon = running ? Loader2 : failed ? AlertCircle : CheckCircle2;
|
|
const summary = request.status === "rejected"
|
|
? request.rejectionReason ?? t("taskVerification.requestRejected", "Request rejected")
|
|
: request.result
|
|
? `${request.result.success ? t("taskVerification.passed", "Passed") : t("taskVerification.failed", "Failed")}${formatDuration(request.result.durationMs) ? ` · ${formatDuration(request.result.durationMs)}` : ""}`
|
|
: request.status === "requested" ? t("taskVerification.queued", "Queued for the task executor") : t("taskVerification.running", "Running in the task worktree");
|
|
|
|
return (
|
|
<section className={`task-verification-status task-verification-status--${request.status}${compact ? " task-verification-status--compact" : ""}`} aria-live="polite" data-testid="task-verification-status">
|
|
<div className="task-verification-status__heading">
|
|
<Icon aria-hidden="true" className={running ? "task-verification-status__spinner" : undefined} />
|
|
<strong>{t("taskVerification.heading", "Verification · {{profile}}", { profile: request.profile })}</strong>
|
|
<span className="task-verification-status__state">{request.status}</span>
|
|
</div>
|
|
<p>{summary}</p>
|
|
{!compact && request.result?.stderrTail ? <pre className="task-verification-status__output">{request.result.stderrTail}</pre> : null}
|
|
</section>
|
|
);
|
|
}
|