feat(workflow): edit node names in drawer header
This commit is contained in:
@@ -90,9 +90,15 @@ export function AssistantIdentity({ assistantId }: { assistantId: string | null
|
|||||||
export function EditableTitle({
|
export function EditableTitle({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
|
placeholder = "未命名助手",
|
||||||
|
editLabel = "助手名称",
|
||||||
|
variant = "page",
|
||||||
}: {
|
}: {
|
||||||
value: string;
|
value: string;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
|
placeholder?: string;
|
||||||
|
editLabel?: string;
|
||||||
|
variant?: "page" | "panel";
|
||||||
}) {
|
}) {
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
const [draft, setDraft] = useState(value);
|
const [draft, setDraft] = useState(value);
|
||||||
@@ -134,7 +140,12 @@ export function EditableTitle({
|
|||||||
setEditing(false);
|
setEditing(false);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="font-display display-sm w-[min(60vw,420px)] border-b border-primary bg-transparent text-ink outline-none"
|
aria-label={`修改${editLabel}`}
|
||||||
|
className={
|
||||||
|
variant === "panel"
|
||||||
|
? "min-w-0 flex-1 border-b border-primary bg-transparent px-3 py-1.5 text-sm font-medium text-foreground outline-none"
|
||||||
|
: "font-display display-sm w-[min(60vw,420px)] border-b border-primary bg-transparent text-ink outline-none"
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -143,14 +154,24 @@ export function EditableTitle({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={startEdit}
|
onClick={startEdit}
|
||||||
title="点击修改助手名称"
|
title={`点击修改${editLabel}`}
|
||||||
className="group -mx-2 flex min-w-0 items-center gap-2 rounded-lg px-2 py-1 text-left transition-colors hover:bg-surface-strong"
|
className={
|
||||||
|
variant === "panel"
|
||||||
|
? "group flex min-w-0 items-center gap-2 rounded-lg px-3 py-1.5 text-left transition-colors hover:bg-surface-strong"
|
||||||
|
: "group -mx-2 flex min-w-0 items-center gap-2 rounded-lg px-2 py-1 text-left transition-colors hover:bg-surface-strong"
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<span className="font-display display-sm truncate text-ink">
|
<span
|
||||||
{value || "未命名助手"}
|
className={
|
||||||
|
variant === "panel"
|
||||||
|
? "truncate text-sm font-medium text-foreground"
|
||||||
|
: "font-display display-sm truncate text-ink"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{value || placeholder}
|
||||||
</span>
|
</span>
|
||||||
<Pencil
|
<Pencil
|
||||||
size={16}
|
size={variant === "panel" ? 14 : 16}
|
||||||
className="shrink-0 text-muted-soft opacity-0 transition-opacity group-hover:opacity-100"
|
className="shrink-0 text-muted-soft opacity-0 transition-opacity group-hover:opacity-100"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
|
import { EditableTitle } from "@/components/assistant-editor/editor-controls";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
@@ -680,7 +681,22 @@ export function WorkflowCanvas({
|
|||||||
? "工作流设置"
|
? "工作流设置"
|
||||||
: editingEdge
|
: editingEdge
|
||||||
? "编辑连接条件"
|
? "编辑连接条件"
|
||||||
: `编辑${editingSpec?.displayName ?? "节点"}`
|
: editingNode && editingSpec
|
||||||
|
? (
|
||||||
|
<EditableTitle
|
||||||
|
value={
|
||||||
|
(editingNode.data as WorkflowNodeData).name ??
|
||||||
|
""
|
||||||
|
}
|
||||||
|
placeholder={editingSpec.displayName}
|
||||||
|
editLabel="节点名称"
|
||||||
|
variant="panel"
|
||||||
|
onChange={(name) =>
|
||||||
|
updateNodeData(editingNode.id, { name })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: "编辑节点"
|
||||||
}
|
}
|
||||||
closeLabel={
|
closeLabel={
|
||||||
dynamicVariablesOpen
|
dynamicVariablesOpen
|
||||||
@@ -719,7 +735,7 @@ export function WorkflowCanvas({
|
|||||||
/>
|
/>
|
||||||
) : editingNode && editingSpec ? (
|
) : editingNode && editingSpec ? (
|
||||||
<NodeSettingsPanel
|
<NodeSettingsPanel
|
||||||
key={editingNode.id}
|
key={`${editingNode.id}:${(editingNode.data as WorkflowNodeData).name ?? ""}`}
|
||||||
panel
|
panel
|
||||||
spec={editingSpec}
|
spec={editingSpec}
|
||||||
data={editingNode.data as WorkflowNodeData}
|
data={editingNode.data as WorkflowNodeData}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export function WorkflowSidePanel({
|
|||||||
onClose,
|
onClose,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
title?: string;
|
title?: ReactNode;
|
||||||
closeLabel?: string;
|
closeLabel?: string;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -27,7 +27,7 @@ export function WorkflowSidePanel({
|
|||||||
>
|
>
|
||||||
<X size={16} />
|
<X size={16} />
|
||||||
</button>
|
</button>
|
||||||
<h2 className="min-w-0 truncate text-sm font-medium text-foreground">
|
<h2 className="min-w-0 flex-1 truncate text-sm font-medium text-foreground">
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
MessageSquareText,
|
MessageSquareText,
|
||||||
Settings2,
|
Settings2,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
Tag,
|
|
||||||
Wrench,
|
Wrench,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
@@ -15,7 +14,6 @@ import { KnowledgeRetrievalConfigDialog } from "@/components/editor/knowledge-re
|
|||||||
import { SectionCard } from "@/components/editor/section-card";
|
import { SectionCard } from "@/components/editor/section-card";
|
||||||
import { VisionConfigSection } from "@/components/editor/vision-config-section";
|
import { VisionConfigSection } from "@/components/editor/vision-config-section";
|
||||||
import { TurnConfigEditor } from "@/components/turn-config-editor";
|
import { TurnConfigEditor } from "@/components/turn-config-editor";
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import type { KnowledgeRetrievalConfig } from "@/lib/api";
|
import type { KnowledgeRetrievalConfig } from "@/lib/api";
|
||||||
@@ -102,21 +100,6 @@ export function AgentNodePanel({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<SectionCard
|
|
||||||
icon={<Tag size={15} />}
|
|
||||||
title="节点信息"
|
|
||||||
description="节点在画布上显示的名称"
|
|
||||||
>
|
|
||||||
<label className="block">
|
|
||||||
<div className="mb-1.5 text-sm font-medium text-foreground">节点名称</div>
|
|
||||||
<Input
|
|
||||||
value={draft.name ?? ""}
|
|
||||||
onChange={(event) => set("name", event.target.value)}
|
|
||||||
className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</SectionCard>
|
|
||||||
|
|
||||||
<SectionCard
|
<SectionCard
|
||||||
icon={<Settings2 size={15} />}
|
icon={<Settings2 size={15} />}
|
||||||
title="配置范围"
|
title="配置范围"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Flag, PhoneForwarded, Tag } from "lucide-react";
|
import { Flag, PhoneForwarded } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { SectionCard } from "@/components/editor/section-card";
|
import { SectionCard } from "@/components/editor/section-card";
|
||||||
@@ -297,23 +297,6 @@ function WorkflowNodePanelForm({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<SectionCard
|
|
||||||
icon={<Tag size={15} />}
|
|
||||||
title="节点信息"
|
|
||||||
description="节点在画布上显示的名称"
|
|
||||||
>
|
|
||||||
<label className="block">
|
|
||||||
<div className="mb-1.5 text-sm font-medium text-foreground">
|
|
||||||
节点名称
|
|
||||||
</div>
|
|
||||||
<Input
|
|
||||||
value={draft.name ?? ""}
|
|
||||||
onChange={(event) => set("name", event.target.value)}
|
|
||||||
className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</SectionCard>
|
|
||||||
|
|
||||||
{spec.type === "action" && (
|
{spec.type === "action" && (
|
||||||
<ActionNodePanel
|
<ActionNodePanel
|
||||||
draft={draft}
|
draft={draft}
|
||||||
|
|||||||
Reference in New Issue
Block a user