返回 DeepSeek-Reasonix
ToolRow.tsx
1 // Adapted from DeepSeek Harness c291e7961a, ui-tool/components/ToolRow.tsx (MIT).
2 // Reasonix provides authorized content and inspection through slots, without Cordis.
3 import { useState, type ReactNode } from "react";
4 import { ScanSearch } from "lucide-react";
5 import { useT } from "../../lib/i18n";
6 import { presentError } from "../../lib/errorPresentation";
7 import { DisclosureRow } from "./DisclosureRow";
8 import { StateDot, type StateDotState } from "./StateDot";
9 import css from "./ToolRow.styles";
10
11 export function ToolRow({ icon, title, summary, state, dot, statusLabel, errorSummary, children, inspectLabel, inspect, beforeToggle }: {
12 dot?: StateDotState;
13 icon: ReactNode; title: string; summary: string; state: "running" | "done" | "error" | "stopped" | "unknown";
14 statusLabel: string; errorSummary?: string; children: ReactNode;
15 inspectLabel: string; inspect: (trigger: HTMLElement) => void; beforeToggle: () => void;
16 }) {
17 const [open, setOpen] = useState(false);
18 const t = useT();
19 const failureLine = state === "error" && errorSummary ? presentError(errorSummary, t).summary : undefined;
20 const leading = dot ? <StateDot state={dot} /> : state === "error" || state === "stopped"
21 ? <StateDot state={state === "error" ? "error" : "warning"} /> : icon;
22 return <div className={`${css.root} chat-tool`} data-state={state}>
23 {state !== "done" && <span className="sr-only">{statusLabel}</span>}
24 <DisclosureRow icon={leading} title={title} open={open} expandable expandOnRowClick keepContentWhenOpen
25 rowClassName={css.row} leadingClassName={css.leading} titleClassName={css.title} chevronClassName={css.chevron}
26 onToggle={() => { beforeToggle(); setOpen(value => !value); }}
27 collapsedContent={(failureLine || summary) && <><span className={css.sep} aria-hidden />
28 <span className={`${css.summary}${failureLine ? ` ${css.errorSummary}` : ""}`}>{failureLine || summary}</span></>}>
29 <div className={css.bodyWrap}>
30 {children}
31 <button className={css.inspectButton} type="button" onClick={event => inspect(event.currentTarget)}><ScanSearch size={12} />{inspectLabel}</button>
32 </div>
33 </DisclosureRow>
34 </div>;
35 }
36
36 lines Plain Text