返回 DeepSeek-Reasonix
ErrorMessage.tsx
根目录 / desktop / frontend / src / components / ErrorMessage.tsx
1 import { useId, useState } from "react";
2 import { useI18n } from "../lib/i18n";
3 import { presentError } from "../lib/errorPresentation";
4 import type { WireEvent } from "../lib/types";
5
6 /** Inline-safe error surface, including inside paragraphs and existing banners. */
7 export function ErrorMessage({ error, summary, diagnostic, onInspect }: { error: unknown; summary?: string; diagnostic?: WireEvent["diagnostic"]; onInspect?: () => void }) {
8 const { t, locale } = useI18n();
9 const id = useId();
10 const [expandedError, setExpandedError] = useState<{ error: unknown } | null>(null);
11 const presentation = presentError(error, t, locale, diagnostic);
12 const expanded = expandedError !== null && expandedError.error === error;
13 const title = summary || presentation.summary;
14 const detail = error == null || error === "" ? "" : presentation.detail || (summary ? presentation.summary : "");
15 if ((error == null || error === "") && !summary) return null;
16 return <span className="user-error">
17 <span className="user-error__summary">{title}</span>
18 {detail && detail !== title && <>
19 <button type="button" className="user-error__toggle" aria-expanded={expanded} aria-controls={id}
20 onClick={(event) => { event.stopPropagation(); onInspect?.(); setExpandedError(expanded ? null : { error }); }}>
21 {t(expanded ? "error.hideDetails" : "error.details")}
22 </button>
23 {expanded && <span id={id} className="user-error__detail" onClick={event => event.stopPropagation()}>{detail}</span>}
24 </>}
25 </span>;
26 }
27
27 lines Plain Text