- 51 fix agents covered every dirty batch from the round-1 verifiers: helper-function labels (roles, statuses, relative time), constant label maps (SETTINGS_SECTIONS, PROVIDER_INFO, EVENT_TYPE_LABELS), TUI help overlay + tab labels, toasts, placeholders, aria-labels - Inline markup flattened by round 1 restored with <Trans> (DbCorruptionBanner storage-docs link, UpdateAvailableBanner code chip) - Catalogs merged: +527 en keys across 5 locales; CLI bundles + app locale tree regenerated (6 locales) - All 23 sweep-caused test regressions fixed: delta vs the clean-main baseline is now zero (remaining 4 local failures reproduce identically on origin/main; CI-green upstream) - typecheck/lint clean; TUI 82/82, core locale 9/9 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
82 lines
3.2 KiB
TypeScript
82 lines
3.2 KiB
TypeScript
import { AlertTriangle, RefreshCw } from "lucide-react";
|
|
import { Trans, useTranslation } from "react-i18next";
|
|
|
|
import "./DbCorruptionBanner.css";
|
|
|
|
interface DbCorruptionBannerProps {
|
|
errors: string[];
|
|
lastCheckedAt: string | null;
|
|
onRefresh: () => void | Promise<void>;
|
|
refreshing: boolean;
|
|
refreshError: string | null;
|
|
}
|
|
|
|
export function DbCorruptionBanner({
|
|
errors,
|
|
lastCheckedAt,
|
|
onRefresh,
|
|
refreshing,
|
|
refreshError,
|
|
}: DbCorruptionBannerProps) {
|
|
const { t } = useTranslation("app");
|
|
if (errors.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
const visibleErrors = errors.slice(0, 5);
|
|
const checkedAtLabel = lastCheckedAt ? new Date(lastCheckedAt).toLocaleString() : null;
|
|
|
|
return (
|
|
<section className="db-corruption-banner" role="alert" aria-live="assertive">
|
|
<div className="db-corruption-banner__header">
|
|
<div className="db-corruption-banner__headline-wrap">
|
|
<span className="status-dot status-dot--error" aria-hidden="true" />
|
|
<AlertTriangle aria-hidden="true" />
|
|
<div className="db-corruption-banner__headline-copy">
|
|
<h2 className="db-corruption-banner__headline">{t("dbBanner.title", "Database corruption detected")}</h2>
|
|
{checkedAtLabel ? (
|
|
<p className="db-corruption-banner__meta">{t("dbBanner.lastChecked", "Last checked: {{checkedAtLabel}}", { checkedAtLabel })}</p>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
<button
|
|
type="button"
|
|
className="btn btn-sm db-corruption-banner__refresh"
|
|
onClick={() => {
|
|
void onRefresh();
|
|
}}
|
|
disabled={refreshing}
|
|
>
|
|
<RefreshCw className={refreshing ? "db-corruption-banner__refresh-icon db-corruption-banner__refresh-icon--spinning" : "db-corruption-banner__refresh-icon"} aria-hidden="true" />
|
|
{refreshing ? t("dbBanner.refreshing", "Refreshing…") : t("dbBanner.refreshHealth", "Refresh health")}
|
|
</button>
|
|
</div>
|
|
|
|
<p className="db-corruption-banner__body">
|
|
{t("dbBanner.body", "Fusion's background SQLite integrity check reported corruption. Review the failing objects below before continuing critical operations.")}
|
|
</p>
|
|
|
|
<ul className="db-corruption-banner__list">
|
|
{visibleErrors.map((error, index) => (
|
|
<li key={`${index}:${error}`} className="db-corruption-banner__item">
|
|
<code className="db-corruption-banner__error-code">{error}</code>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
|
|
<p className="db-corruption-banner__footer">
|
|
<strong className="db-corruption-banner__footer-label">{t("dbBanner.whatToDo", "What to do:")}</strong>{" "}
|
|
<Trans
|
|
i18nKey="app:dbBanner.instructions"
|
|
defaults="Back up the project, try <cmd>fn db --vacuum</cmd> if the database still opens cleanly, and restore from a known-good backup if corruption persists. See <docsLink>docs/storage.md</docsLink> for the storage layout and recovery guidance."
|
|
components={{
|
|
cmd: <code />,
|
|
docsLink: <a href="docs/storage.md" />,
|
|
}}
|
|
/>
|
|
</p>
|
|
{refreshError ? <p className="db-corruption-banner__error">{refreshError}</p> : null}
|
|
</section>
|
|
);
|
|
}
|