feat(ui): add traffic and tool detail drawers
This commit is contained in:
1 parent
fd2ddbc9d7
commit
af3149901e
6 files changed
+436
-271
No files matched your search
@@ -23,6 +23,7 @@ import {
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { Markdown } from "@/components/markdown";
|
||||
import { api } from "@/lib/api";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { Agent, AgentDetail, AgentTrigger, MCPServer, PromptVar, PromptVersion, Settings, SkillItem, Tool } from "@/lib/types";
|
||||
@@ -397,9 +398,9 @@ export function AgentEditor({ agentKey, onSaved }: { agentKey: string; onSaved?:
|
||||
<DialogTitle>渲染预览</DialogTitle>
|
||||
<DialogDescription>所有 {`{{.Var}}`} 已由后端用示例值替换。</DialogDescription>
|
||||
</DialogHeader>
|
||||
<pre className="bg-muted max-h-[60vh] overflow-auto whitespace-pre-wrap rounded-md p-3 font-mono text-xs">
|
||||
{preview}
|
||||
</pre>
|
||||
<div className="max-h-[60vh] overflow-auto rounded-md border bg-muted/30 p-3">
|
||||
<Markdown text={preview} />
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<Button size="sm" onClick={savePrompt}>
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
|
||||
import { CheckIcon, CopyIcon } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn, copyText } from "@/lib/utils";
|
||||
|
||||
type CopyButtonProps = {
|
||||
// 要复制的文本;为空则按钮禁用。
|
||||
text: string | null | undefined;
|
||||
// 复制成功后的 toast 文案,默认「已复制」。
|
||||
successMessage?: string;
|
||||
label?: React.ReactNode;
|
||||
size?: React.ComponentProps<typeof Button>["size"];
|
||||
variant?: React.ComponentProps<typeof Button>["variant"];
|
||||
className?: string;
|
||||
};
|
||||
|
||||
// CopyButton 统一的「复制到剪贴板」按钮:内置成功/失败反馈,并在 HTTP 非安全上下文
|
||||
// 下自动降级(见 copyText)。
|
||||
export function CopyButton({
|
||||
text,
|
||||
successMessage = "已复制",
|
||||
label = "复制",
|
||||
size = "sm",
|
||||
variant = "outline",
|
||||
className,
|
||||
}: CopyButtonProps) {
|
||||
const [copied, setCopied] = React.useState(false);
|
||||
const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
if (timer.current) clearTimeout(timer.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
async function handleCopy() {
|
||||
if (!text) return;
|
||||
const ok = await copyText(text);
|
||||
if (ok) {
|
||||
setCopied(true);
|
||||
toast.success(successMessage);
|
||||
if (timer.current) clearTimeout(timer.current);
|
||||
timer.current = setTimeout(() => setCopied(false), 1500);
|
||||
} else {
|
||||
toast.error("复制失败,请手动选择文本复制");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
size={size}
|
||||
variant={variant}
|
||||
className={cn(className)}
|
||||
disabled={!text}
|
||||
onClick={handleCopy}
|
||||
>
|
||||
{copied ? <CheckIcon /> : <CopyIcon />}
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
import { toast } from "sonner";
|
||||
import { api } from "@/lib/api";
|
||||
import { Markdown } from "@/components/markdown";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import type { Activity } from "@/lib/types";
|
||||
|
||||
@@ -208,7 +209,7 @@ function InterceptCard({
|
||||
}, [pendingId]);
|
||||
|
||||
async function decide(decision: "allowed" | "denied") {
|
||||
if (!pendingId || deciding) return;
|
||||
if (step.inherited || !pendingId || deciding) return;
|
||||
setDeciding(true);
|
||||
try {
|
||||
await api.interceptDecide(pendingId, decision);
|
||||
@@ -246,7 +247,9 @@ function InterceptCard({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{decided ? (
|
||||
{step.inherited ? (
|
||||
<Badge variant="outline">历史记录 · 只读</Badge>
|
||||
) : decided ? (
|
||||
<span className={
|
||||
"shrink-0 rounded px-2 py-0.5 text-[11px] font-medium " +
|
||||
(decided === "allowed"
|
||||
|
||||
Reference in new issue
Block a user