diff options
Diffstat (limited to 'frontend/src/store')
| -rw-r--r-- | frontend/src/store/flowStore.ts | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/frontend/src/store/flowStore.ts b/frontend/src/store/flowStore.ts index 6083a36..d2114aa 100644 --- a/frontend/src/store/flowStore.ts +++ b/frontend/src/store/flowStore.ts @@ -68,6 +68,11 @@ interface FlowState { getActiveContext: (nodeId: string) => Message[]; + // Actions + deleteEdge: (edgeId: string) => void; + deleteNode: (nodeId: string) => void; + deleteBranch: (startNodeId?: string, startEdgeId?: string) => void; + propagateTraces: () => void; } @@ -196,6 +201,79 @@ const useFlowStore = create<FlowState>((set, get) => ({ return contextMessages; }, + deleteEdge: (edgeId: string) => { + set({ + edges: get().edges.filter(e => e.id !== edgeId) + }); + get().propagateTraces(); + }, + + deleteNode: (nodeId: string) => { + set({ + nodes: get().nodes.filter(n => n.id !== nodeId), + edges: get().edges.filter(e => e.source !== nodeId && e.target !== nodeId) + }); + get().propagateTraces(); + }, + + deleteBranch: (startNodeId?: string, startEdgeId?: string) => { + const { edges, nodes } = get(); + // We ONLY delete edges, NOT nodes. + const edgesToDelete = new Set<string>(); + + // Helper to traverse downstream EDGES based on Trace Dependency + const traverse = (currentEdge: Edge) => { + if (edgesToDelete.has(currentEdge.id)) return; + edgesToDelete.add(currentEdge.id); + + const targetNodeId = currentEdge.target; + // Identify the trace ID carried by this edge + const traceId = currentEdge.sourceHandle?.replace('trace-', ''); + if (!traceId) return; + + // Look for outgoing edges from the target node that carry the EVOLUTION of this trace. + // Our logic generates next trace ID as: `${traceId}_${targetNodeId}` + const expectedNextTraceId = `${traceId}_${targetNodeId}`; + + const outgoing = edges.filter(e => e.source === targetNodeId); + outgoing.forEach(nextEdge => { + // If the outgoing edge carries the evolved trace, delete it too + if (nextEdge.sourceHandle === `trace-${expectedNextTraceId}`) { + traverse(nextEdge); + } + }); + }; + + if (startNodeId) { + // If deleting a node, we delete ALL outgoing edges recursively. + // Because all traces passing through this node are broken. + // But we can't use `traverse` directly because we don't have a single start edge. + // We just start traverse on ALL outgoing edges of this node. + const initialOutgoing = edges.filter(e => e.source === startNodeId); + initialOutgoing.forEach(e => traverse(e)); + + // Also delete incoming to this node + const incomingToNode = edges.filter(e => e.target === startNodeId); + incomingToNode.forEach(e => edgesToDelete.add(e.id)); + + set({ + nodes: nodes.filter(n => n.id !== startNodeId), + edges: edges.filter(e => !edgesToDelete.has(e.id)) + }); + } else if (startEdgeId) { + const startEdge = edges.find(e => e.id === startEdgeId); + if (startEdge) { + traverse(startEdge); + } + + set({ + edges: edges.filter(e => !edgesToDelete.has(e.id)) + }); + } + + get().propagateTraces(); + }, + propagateTraces: () => { const { nodes, edges } = get(); |
