feat: expand intelligent investigation workspace
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import { ChevronLeft, ChevronRight, Radio } from "lucide-react";
|
||||
import { Button } from "@/shared/ui/button";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/shared/ui/select";
|
||||
import type { PresentationHistoryControls } from "../utils/presentation-view-history";
|
||||
|
||||
const statusLabels = { running: "进行中", completed: "完成", error: "未完成", cancelled: "已取消" };
|
||||
|
||||
export function PresentationHistorySwitcher({
|
||||
entries,
|
||||
currentEntryId,
|
||||
selectedId,
|
||||
onSelect
|
||||
}: PresentationHistoryControls) {
|
||||
const currentEntry = entries.find((entry) => entry.id === currentEntryId);
|
||||
const available = entries.filter(
|
||||
(entry) => entry.status !== "running" && entry.id !== currentEntryId
|
||||
);
|
||||
const index =
|
||||
selectedId === null
|
||||
? available.length
|
||||
: available.findIndex((entry) => entry.id === selectedId);
|
||||
return (
|
||||
<div className="mt-2 flex min-w-0 items-center gap-1" role="group" aria-label="展示动作历史">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
className="size-8 shrink-0"
|
||||
aria-label="上一个动作"
|
||||
disabled={index <= 0}
|
||||
onClick={() => onSelect(available[index - 1].id)}
|
||||
>
|
||||
<ChevronLeft size={14} aria-hidden />
|
||||
</Button>
|
||||
<Select
|
||||
value={selectedId === null ? "current" : String(selectedId)}
|
||||
onValueChange={(value) => onSelect(value === "current" ? null : Number(value))}
|
||||
>
|
||||
<SelectTrigger
|
||||
aria-label="切换展示动作"
|
||||
className="h-8 min-w-0 flex-1 px-2 text-xs [&>span]:truncate"
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent
|
||||
position="popper"
|
||||
sideOffset={4}
|
||||
className="workbench-shadcn-surface z-[90] max-w-[calc(100vw-24px)]"
|
||||
>
|
||||
<SelectItem value="current" className="text-xs">
|
||||
当前(最新)
|
||||
{currentEntry ? ` · ${entries.indexOf(currentEntry) + 1}. ${currentEntry.label}` : ""} ·{" "}
|
||||
{entries.length} 个动作
|
||||
</SelectItem>
|
||||
{entries
|
||||
.slice()
|
||||
.reverse()
|
||||
.map((entry, position) =>
|
||||
entry.id === currentEntryId ? null : (
|
||||
<SelectItem
|
||||
key={entry.id}
|
||||
value={String(entry.id)}
|
||||
disabled={entry.status === "running"}
|
||||
className="whitespace-normal text-xs [&>span:last-child]:break-words"
|
||||
>
|
||||
{entries.length - position}. {entry.label} · {statusLabels[entry.status]}
|
||||
</SelectItem>
|
||||
)
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
className="size-8 shrink-0"
|
||||
aria-label="下一个动作"
|
||||
disabled={selectedId === null}
|
||||
onClick={() => onSelect(index + 1 < available.length ? available[index + 1].id : null)}
|
||||
>
|
||||
<ChevronRight size={14} aria-hidden />
|
||||
</Button>
|
||||
{selectedId !== null ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
className="h-8 shrink-0 gap-1 px-2 text-[11px]"
|
||||
onClick={() => onSelect(null)}
|
||||
>
|
||||
<Radio size={12} aria-hidden />
|
||||
回到当前
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user