feat: add delete functionality for condition branches in node forms and improve edge filtering in workflow normalization

This commit is contained in:
mlogclub
2026-06-28 10:07:00 +08:00
parent 325a860fee
commit 33c6647375
3 changed files with 50 additions and 12 deletions
@@ -1,5 +1,5 @@
import { Field, type WorkflowNodeRegistry } from "@flowgram.ai/free-layout-editor"
import { PlusIcon } from "lucide-react"
import { PlusIcon, XIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import type { AIWorkflowNodeSpec } from "@/lib/api/admin"
@@ -99,6 +99,9 @@ function ConditionNodeForm({ fallbackTitle }: { fallbackTitle: string }) {
branches: ensureConditionBranches(nextBranches),
})
}
const deleteBranch = (branchId: string) => {
updateBranches(branches.filter((branch) => branch.id !== branchId))
}
return (
<div className="px-4 py-3">
@@ -114,6 +117,19 @@ function ConditionNodeForm({ fallbackTitle }: { fallbackTitle: string }) {
<span className="shrink-0 rounded-sm bg-[#e7e9f3] px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground">
{branch.default ? "else" : index === 0 ? "if" : "elseif"}
</span>
{branch.default ? null : (
<button
type="button"
className="flex size-5 shrink-0 items-center justify-center rounded-sm text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive"
aria-label={`删除条件 ${branch.name || branch.id}`}
onClick={(event) => {
event.stopPropagation()
deleteBranch(branch.id)
}}
>
<XIcon className="size-3.5" />
</button>
)}
<span
data-port-id={branch.id}
data-port-type="output"
@@ -274,15 +274,17 @@ function ConditionBranchesEditor({
className="h-8"
onChange={(event) => onChange({ ...branch, name: event.target.value })}
/>
<Button
type="button"
variant="ghost"
size="sm"
className="h-8 px-2 text-xs text-muted-foreground hover:text-destructive"
onClick={() => onDelete(branch.id)}
>
</Button>
{branch.default ? null : (
<Button
type="button"
variant="ghost"
size="sm"
className="h-8 px-2 text-xs text-muted-foreground hover:text-destructive"
onClick={() => onDelete(branch.id)}
>
</Button>
)}
</div>
<div className="space-y-1.5">
@@ -241,18 +241,32 @@ export function deleteConditionBranch(
return definition
}
const config = normalizeNodeConfig(node.data?.config)
return updateWorkflowNodeData(definition, nodeId, {
const nextDefinition = updateWorkflowNodeData(definition, nodeId, {
...(node.data ?? {}),
config: {
...config,
branches: (config.branches ?? []).filter((branch) => branch.id !== branchId),
},
})
return {
...nextDefinition,
edges: nextDefinition.edges.filter((edge) => !(edge.sourceNodeID === nodeId && edge.sourcePortID === branchId)),
}
}
export function normalizeConditionPortsForFlowgram(
definition: AIWorkflowDefinition
): AIWorkflowDefinition {
const branchIdsByNodeId = new Map<string, Set<string>>()
for (const node of definition.nodes) {
if (node.type !== "condition") {
continue
}
const config = normalizeNodeConfig(node.data?.config)
const branches = ensureConditionBranches(config.branches ?? [])
branchIdsByNodeId.set(node.id, new Set(branches.map((branch) => branch.id)))
}
return {
...definition,
nodes: definition.nodes.map((node) => {
@@ -271,7 +285,13 @@ export function normalizeConditionPortsForFlowgram(
},
}
}),
edges: definition.edges.map((edge) => {
edges: definition.edges.filter((edge) => {
if (!edge.sourcePortID) {
return true
}
const branchIds = branchIdsByNodeId.get(edge.sourceNodeID)
return !branchIds || branchIds.has(edge.sourcePortID)
}).map((edge) => {
const source = definition.nodes.find((node) => node.id === edge.sourceNodeID)
if (!source || source.type !== "condition" || edge.sourcePortID) {
return edge