feat: add icon property to workflow node specifications and update related components

This commit is contained in:
mlogclub
2026-06-28 15:24:00 +08:00
parent 389291143a
commit 530cf145b2
12 changed files with 42 additions and 57 deletions
@@ -13,6 +13,7 @@ export function buildFlowgramNodeRegistries(nodeSpecs: AIWorkflowNodeSpec[]): Wo
type: "start",
title: "开始",
description: "流程入口",
icon: "PlayCircleIcon",
riskLevel: "low" as const,
interruptible: false,
requiresConfirmationPredecessor: false,
@@ -21,6 +22,7 @@ export function buildFlowgramNodeRegistries(nodeSpecs: AIWorkflowNodeSpec[]): Wo
type: "end",
title: "结束",
description: "流程结束",
icon: "FlagIcon",
riskLevel: "low" as const,
interruptible: false,
requiresConfirmationPredecessor: false,
@@ -47,9 +49,10 @@ export function buildFlowgramNodeRegistries(nodeSpecs: AIWorkflowNodeSpec[]): Wo
formMeta: {
render: () => (
<FlowgramNodeForm
nodeType={spec.type}
fallbackTitle={spec.title || spec.type}
/>
nodeType={spec.type}
fallbackTitle={spec.title || spec.type}
icon={spec.icon}
/>
),
},
}))
@@ -58,9 +61,11 @@ export function buildFlowgramNodeRegistries(nodeSpecs: AIWorkflowNodeSpec[]): Wo
function FlowgramNodeForm({
nodeType,
fallbackTitle,
icon,
}: {
nodeType: string
fallbackTitle: string
icon: string
}) {
const { node, selected } = useNodeRender()
const nodeId = String(node.id ?? "")
@@ -69,8 +74,8 @@ function FlowgramNodeForm({
<Field<string> name="title">
{({ field }) => (
<WorkflowNodeCard
nodeType={nodeType}
title={field.value || fallbackTitle}
icon={icon}
selected={selected}
width={nodeType === "condition" ? "wide" : "normal"}
>
@@ -4,14 +4,14 @@ import { cn } from "@/lib/utils"
import { WorkflowNodeIcon } from "./workflow-node-icon"
export function WorkflowNodeCard({
nodeType,
title,
icon,
selected,
width = "normal",
children,
}: {
nodeType: string
title: string
icon: string
selected: boolean
width?: "normal" | "wide"
children?: ReactNode
@@ -28,7 +28,7 @@ export function WorkflowNodeCard({
>
<div className="overflow-hidden rounded-lg border border-transparent bg-background">
<div className="flex items-center gap-2 px-3 pb-2 pt-3">
<WorkflowNodeIcon type={nodeType} />
<WorkflowNodeIcon icon={icon} />
<div className="min-w-0 flex-1">
<div className="truncate text-sm font-semibold leading-5 text-foreground">
{title}
@@ -1,17 +1,19 @@
import { cn } from "@/lib/utils"
import { getWorkflowNodeMeta } from "./workflow-node-meta"
import { FileTextIcon, type LucideIcon } from "lucide-react"
import * as LucideIcons from "lucide-react"
const lucideIconComponents = LucideIcons as unknown as Record<string, LucideIcon>
export function WorkflowNodeIcon({
type,
icon,
size = "md",
className,
}: {
type: string
icon?: string
size?: "sm" | "md"
className?: string
}) {
const meta = getWorkflowNodeMeta(type)
const Icon = meta.icon
const Icon = icon ? lucideIconComponents[icon] ?? FileTextIcon : FileTextIcon
return (
<span
@@ -1,43 +0,0 @@
import {
BookOpenIcon,
BotIcon,
ClipboardListIcon,
FileTextIcon,
FlagIcon,
GitBranchIcon,
HeadphonesIcon,
HelpCircleIcon,
MessageCircleIcon,
PlayCircleIcon,
SearchIcon,
SendIcon,
ShieldCheckIcon,
TicketIcon,
UserCheckIcon,
type LucideIcon,
} from "lucide-react"
export type WorkflowNodeMeta = {
icon: LucideIcon
}
const workflowNodeMetaByType: Record<string, WorkflowNodeMeta> = {
start: { icon: PlayCircleIcon },
conversation_understanding: { icon: MessageCircleIcon },
reply_policy: { icon: ShieldCheckIcon },
knowledge_retrieve: { icon: BookOpenIcon },
answerability_gate: { icon: HelpCircleIcon },
llm_reply: { icon: BotIcon },
condition: { icon: GitBranchIcon },
analyze_conversation: { icon: SearchIcon },
prepare_ticket_draft: { icon: ClipboardListIcon },
human_confirm: { icon: UserCheckIcon },
create_ticket: { icon: TicketIcon },
handoff_to_human: { icon: HeadphonesIcon },
send_reply: { icon: SendIcon },
end: { icon: FlagIcon },
}
export function getWorkflowNodeMeta(type: string): WorkflowNodeMeta {
return workflowNodeMetaByType[type] ?? { icon: FileTextIcon }
}
@@ -24,7 +24,7 @@ export function WorkflowNodePalette({
className="flex w-full items-start gap-2 rounded-md px-2 py-2 text-left text-sm transition-colors hover:bg-muted"
onClick={() => onAddNode(spec)}
>
<WorkflowNodeIcon type={spec.type} size="sm" className="mt-0.5" />
<WorkflowNodeIcon icon={spec.icon} size="sm" className="mt-0.5" />
<span className="min-w-0">
<span className="block truncate font-medium">{spec.title || spec.type}</span>
<span className="line-clamp-2 text-xs text-muted-foreground">{spec.description}</span>