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>
98 lines
3.8 KiB
TypeScript
98 lines
3.8 KiB
TypeScript
import { useTranslation } from "react-i18next";
|
|
import type { Task } from "@fusion/core";
|
|
|
|
interface MergeDetailsProps {
|
|
task: Task;
|
|
}
|
|
|
|
function shortSha(sha?: string, t?: (key: string, defaultValue: string) => string): string {
|
|
if (!sha) return t ? t("merge.unknown", "Unknown") : "Unknown";
|
|
return sha.slice(0, 7);
|
|
}
|
|
|
|
export function MergeDetails({ task }: MergeDetailsProps) {
|
|
const { t } = useTranslation("app");
|
|
if (task.column !== "done" || !task.mergeDetails) {
|
|
return null;
|
|
}
|
|
|
|
const details = task.mergeDetails;
|
|
|
|
return (
|
|
<div className="detail-section">
|
|
<h4>{t("merge.title", "Merge Details")}</h4>
|
|
<div className="pr-card merge-details-card">
|
|
<div className="detail-log-entry">
|
|
<div className="detail-log-header">
|
|
<span className="detail-log-action">{t("merge.status", "Status")}</span>
|
|
<span className="detail-log-outcome">{details.mergeConfirmed === false ? t("merge.recordedNoConfirm", "Recorded without local merge confirmation") : t("merge.mergedSuccess", "Merged successfully")}</span>
|
|
</div>
|
|
</div>
|
|
<div className="detail-log-entry">
|
|
<div className="detail-log-header">
|
|
<span className="detail-log-action">{t("merge.commit", "Commit")}</span>
|
|
<span className="detail-log-outcome">{shortSha(details.commitSha, t)}</span>
|
|
</div>
|
|
</div>
|
|
<div className="detail-log-entry">
|
|
<div className="detail-log-header">
|
|
<span
|
|
className="detail-log-action"
|
|
title={t("merge.shortstatTitle", "Final commit shortstat; for the full landed diff across all task commits, see the Changes tab.")}
|
|
>
|
|
{t("merge.filesChanged", "Files in merge commit")}
|
|
</span>
|
|
<span className="detail-log-outcome">{details.filesChanged ?? 0}</span>
|
|
</div>
|
|
</div>
|
|
<div className="detail-log-entry">
|
|
<div className="detail-log-header">
|
|
<span
|
|
className="detail-log-action"
|
|
title={t("merge.shortstatTitle", "Final commit shortstat; for the full landed diff across all task commits, see the Changes tab.")}
|
|
>
|
|
{t("merge.insertionsDeletions", "Merge-commit insertions / deletions")}
|
|
</span>
|
|
<span className="detail-log-outcome">+{details.insertions ?? 0} / -{details.deletions ?? 0}</span>
|
|
</div>
|
|
</div>
|
|
{details.mergedAt ? (
|
|
<div className="detail-log-entry">
|
|
<div className="detail-log-header">
|
|
<span className="detail-log-action">{t("merge.mergedAt", "Merged at")}</span>
|
|
<span className="detail-log-outcome">{new Date(details.mergedAt).toLocaleString()}</span>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
{details.prNumber ? (
|
|
<div className="detail-log-entry">
|
|
<div className="detail-log-header">
|
|
<span className="detail-log-action">{t("merge.pr", "PR")}</span>
|
|
{task.prInfo?.url ? (
|
|
<a
|
|
className="detail-source-link detail-log-outcome"
|
|
href={task.prInfo.url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
#{details.prNumber}
|
|
</a>
|
|
) : (
|
|
<span className="detail-log-outcome">#{details.prNumber}</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
{details.mergeCommitMessage ? (
|
|
<div className="detail-log-entry">
|
|
<div className="detail-log-header">
|
|
<span className="detail-log-action">{t("merge.message", "Message")}</span>
|
|
</div>
|
|
<div className="detail-log-outcome">{details.mergeCommitMessage}</div>
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|