feat: centralize API error localization
Replace the err instanceof ApiError ? err.message : t(fallback) anti-
pattern -- which showed raw English backend text for the common case and
only used the localized fallback for the rare network-failure case -- at
all 13 call sites across 7 files.
New frontend/src/api/errorMessages.ts (describeApiError) resolves a
caught error to a localized {title, explanation, nextStep?, technical}
by checking the 32 known AppError codes first, then known HTTP statuses
(401/403/404/409/422/500), then a fully generic fallback. New
ApiErrorNotice (PageChrome.tsx) renders title/explanation/nextStep with
the raw text demoted to a "Technical details"/"Details techniques"
disclosure -- never shown as the primary message.
ApiError itself is split out of client.ts into a standalone
api/apiError.ts with no import.meta.env dependency, so errorMessages.ts
(and its tests) can be loaded outside a Vite/browser context.
This commit is contained in:
@@ -67,6 +67,26 @@ export function ErrorState({ message }: { message: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
// Shared rendering for describeApiError()'s output: a localized title + explanation +
|
||||
// optional next step, with the raw backend/network text demoted to a "Technical
|
||||
// details" disclosure -- never shown as the primary message. See
|
||||
// frontend/src/api/errorMessages.ts and docs/fleet-ops-final-localization/audit.md.
|
||||
export function ApiErrorNotice({ error }: { error: import("../api/errorMessages").ApiErrorInfo | null }) {
|
||||
const { t } = useTranslation("common");
|
||||
if (!error) return null;
|
||||
return (
|
||||
<div className="error api-error-notice" role="alert">
|
||||
<strong>{error.title}</strong>
|
||||
<p>{error.explanation}</p>
|
||||
{error.nextStep && <p className="api-error-next-step">{error.nextStep}</p>}
|
||||
<details className="evidence-disclosure">
|
||||
<summary>{t("actions.technicalDetails")}</summary>
|
||||
<pre className="evidence-block">{error.technical}</pre>
|
||||
</details>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function EmptyState({
|
||||
icon = "check",
|
||||
title,
|
||||
|
||||
Reference in New Issue
Block a user