Expand test case fixed-input editor and batch case detail split view.
Unify multi-turn behaviors (reply/tool), overall expectation, and input-mode picker while keeping non-text modes as coming soon; batch completed/running use a half-and-half detail panel below the top bar. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* 批量测试用例详情抽屉。
|
||||
* 批量测试用例详情面板。
|
||||
* 与 prompt mode DebugDrawer overlay 相同:作为右侧 flex 半屏,无遮罩/模糊。
|
||||
* 当前展示前端 mock 数据,后续可直接替换为真实执行事件与校验结果。
|
||||
*/
|
||||
|
||||
@@ -12,21 +13,15 @@ import {
|
||||
MessageSquareText,
|
||||
Target,
|
||||
TriangleAlert,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
|
||||
import { BatchCaseStatusBadge } from "@/components/batch-test/batch-case-status";
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from "@/components/ui/sheet";
|
||||
import type { BatchRunCase } from "@/data/batch-run";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type BatchCaseDetailDrawerProps = {
|
||||
item: BatchRunCase | null;
|
||||
item: BatchRunCase;
|
||||
assistantName: string;
|
||||
onClose: () => void;
|
||||
};
|
||||
@@ -37,80 +32,72 @@ export function BatchCaseDetailDrawer({
|
||||
onClose,
|
||||
}: BatchCaseDetailDrawerProps) {
|
||||
return (
|
||||
<Sheet
|
||||
open={Boolean(item)}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) onClose();
|
||||
}}
|
||||
>
|
||||
<SheetContent
|
||||
side="right"
|
||||
className="w-[min(92vw,620px)] border-hairline bg-card p-0 sm:max-w-[620px]"
|
||||
>
|
||||
{item && (
|
||||
<>
|
||||
<SheetHeader className="border-b border-hairline px-6 py-5 pr-16">
|
||||
<p className="text-xs font-medium tracking-[0.08em] text-muted-soft uppercase">
|
||||
用例详情
|
||||
</p>
|
||||
<SheetTitle className="text-lg leading-7">
|
||||
{item.name}
|
||||
</SheetTitle>
|
||||
<SheetDescription>
|
||||
被测助手:{assistantName} · 当前为前端 Mock 结果
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<aside className="flex h-full min-w-0 flex-1 flex-col overflow-hidden border-l border-hairline bg-card">
|
||||
<div className="flex min-h-14 shrink-0 items-center gap-3 border-b border-hairline px-4 py-3">
|
||||
<button
|
||||
type="button"
|
||||
aria-label="关闭用例详情"
|
||||
title="关闭"
|
||||
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-hairline-strong bg-card text-muted-foreground shadow-sm transition-colors hover:text-foreground"
|
||||
onClick={onClose}
|
||||
>
|
||||
<X size={16} />
|
||||
</button>
|
||||
<div className="min-w-0 flex-1">
|
||||
<h2 className="truncate text-sm font-medium text-foreground">
|
||||
{item.name}
|
||||
</h2>
|
||||
<p className="truncate text-xs text-muted-soft">
|
||||
被测助手:{assistantName} · Mock 结果
|
||||
</p>
|
||||
</div>
|
||||
<BatchCaseStatusBadge status={item.status} />
|
||||
</div>
|
||||
|
||||
<div className="min-h-0 flex-1 overflow-y-auto px-6 py-6">
|
||||
<div className="space-y-6">
|
||||
<section className="flex items-center justify-between rounded-2xl border border-hairline bg-canvas-soft px-4 py-3.5">
|
||||
<div>
|
||||
<p className="text-xs text-muted-soft">当前状态</p>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
{statusDescription(item)}
|
||||
</p>
|
||||
</div>
|
||||
<BatchCaseStatusBadge status={item.status} />
|
||||
</section>
|
||||
<div className="min-h-0 flex-1 overflow-y-auto px-5 py-5">
|
||||
<div className="space-y-5">
|
||||
<section className="rounded-2xl border border-hairline bg-canvas-soft px-4 py-3.5">
|
||||
<p className="text-xs text-muted-soft">当前状态</p>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
{statusDescription(item)}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<DetailSection
|
||||
icon={<Target size={16} />}
|
||||
title="预期结果"
|
||||
value={item.expected}
|
||||
/>
|
||||
<DetailSection
|
||||
icon={<Target size={16} />}
|
||||
title="预期结果"
|
||||
value={item.expected}
|
||||
/>
|
||||
|
||||
{(item.status === "waiting" || item.status === "running") && (
|
||||
<ExecutionTimeline status={item.status} />
|
||||
)}
|
||||
{(item.status === "waiting" || item.status === "running") && (
|
||||
<ExecutionTimeline status={item.status} />
|
||||
)}
|
||||
|
||||
{(item.status === "pass" || item.status === "fail") && (
|
||||
<DetailSection
|
||||
icon={<MessageSquareText size={16} />}
|
||||
title="实际回复"
|
||||
value={item.actual}
|
||||
/>
|
||||
)}
|
||||
{(item.status === "pass" || item.status === "fail") && (
|
||||
<DetailSection
|
||||
icon={<MessageSquareText size={16} />}
|
||||
title="实际回复"
|
||||
value={item.actual}
|
||||
/>
|
||||
)}
|
||||
|
||||
{item.status === "fail" && item.failReason && (
|
||||
<DetailSection
|
||||
icon={<TriangleAlert size={16} />}
|
||||
title="失败原因(LLM 判断)"
|
||||
value={item.failReason}
|
||||
tone="destructive"
|
||||
/>
|
||||
)}
|
||||
{item.status === "fail" && item.failReason && (
|
||||
<DetailSection
|
||||
icon={<TriangleAlert size={16} />}
|
||||
title="失败原因(LLM 判断)"
|
||||
value={item.failReason}
|
||||
tone="destructive"
|
||||
/>
|
||||
)}
|
||||
|
||||
{item.status === "skipped" && (
|
||||
<div className="rounded-2xl border border-dashed border-hairline-strong px-4 py-4 text-sm leading-6 text-muted-foreground">
|
||||
该用例未执行,因此没有实际回复与判断结果。
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{item.status === "skipped" && (
|
||||
<div className="rounded-2xl border border-dashed border-hairline-strong px-4 py-4 text-sm leading-6 text-muted-foreground">
|
||||
该用例未执行,因此没有实际回复与判断结果。
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user