From 8ccf4548a65e6f71023ec37f242d3959574f9b8e Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Tue, 13 Jan 2026 18:14:39 -0800 Subject: [PATCH 1/2] fix(sockets): redrawing edges should not lead to socket ops --- apps/sim/hooks/use-collaborative-workflow.ts | 38 +++++++++++++++++-- .../stores/workflows/workflow/store.test.ts | 13 +------ apps/sim/stores/workflows/workflow/store.ts | 11 ------ 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/apps/sim/hooks/use-collaborative-workflow.ts b/apps/sim/hooks/use-collaborative-workflow.ts index c2fa032d86..de70ce55fa 100644 --- a/apps/sim/hooks/use-collaborative-workflow.ts +++ b/apps/sim/hooks/use-collaborative-workflow.ts @@ -242,7 +242,20 @@ export function useCollaborativeWorkflow() { case EDGES_OPERATIONS.BATCH_ADD_EDGES: { const { edges } = payload if (Array.isArray(edges) && edges.length > 0) { - workflowStore.batchAddEdges(edges) + const currentEdges = workflowStore.edges + const newEdges = edges.filter((edge: Edge) => { + if (edge.source === edge.target) return false + return !currentEdges.some( + (e) => + e.source === edge.source && + e.sourceHandle === edge.sourceHandle && + e.target === edge.target && + e.targetHandle === edge.targetHandle + ) + }) + if (newEdges.length > 0) { + workflowStore.batchAddEdges(newEdges) + } } break } @@ -976,6 +989,23 @@ export function useCollaborativeWorkflow() { if (edges.length === 0) return false + const currentEdges = workflowStore.edges + const newEdges = edges.filter((edge) => { + if (edge.source === edge.target) return false + return !currentEdges.some( + (e) => + e.source === edge.source && + e.sourceHandle === edge.sourceHandle && + e.target === edge.target && + e.targetHandle === edge.targetHandle + ) + }) + + if (newEdges.length === 0) { + logger.debug('Skipping batch add edges - all edges already exist') + return false + } + const operationId = crypto.randomUUID() addToQueue({ @@ -983,16 +1013,16 @@ export function useCollaborativeWorkflow() { operation: { operation: EDGES_OPERATIONS.BATCH_ADD_EDGES, target: OPERATION_TARGETS.EDGES, - payload: { edges }, + payload: { edges: newEdges }, }, workflowId: activeWorkflowId || '', userId: session?.user?.id || 'unknown', }) - workflowStore.batchAddEdges(edges) + workflowStore.batchAddEdges(newEdges) if (!options?.skipUndoRedo) { - edges.forEach((edge) => undoRedo.recordAddEdge(edge.id)) + newEdges.forEach((edge) => undoRedo.recordAddEdge(edge.id)) } return true diff --git a/apps/sim/stores/workflows/workflow/store.test.ts b/apps/sim/stores/workflows/workflow/store.test.ts index f1fef5bef7..1ed122c238 100644 --- a/apps/sim/stores/workflows/workflow/store.test.ts +++ b/apps/sim/stores/workflows/workflow/store.test.ts @@ -297,7 +297,7 @@ describe('workflow store', () => { expectEdgeConnects(edges, 'block-1', 'block-2') }) - it('should not add duplicate edges', () => { + it('should not add duplicate connections', () => { const { addBlock, batchAddEdges } = useWorkflowStore.getState() addBlock('block-1', 'starter', 'Start', { x: 0, y: 0 }) @@ -309,17 +309,6 @@ describe('workflow store', () => { const state = useWorkflowStore.getState() expectEdgeCount(state, 1) }) - - it('should prevent self-referencing edges', () => { - const { addBlock, batchAddEdges } = useWorkflowStore.getState() - - addBlock('block-1', 'function', 'Self', { x: 0, y: 0 }) - - batchAddEdges([{ id: 'e1', source: 'block-1', target: 'block-1' }]) - - const state = useWorkflowStore.getState() - expectEdgeCount(state, 0) - }) }) describe('batchRemoveEdges', () => { diff --git a/apps/sim/stores/workflows/workflow/store.ts b/apps/sim/stores/workflows/workflow/store.ts index 9f46b0de6f..f5a265b64f 100644 --- a/apps/sim/stores/workflows/workflow/store.ts +++ b/apps/sim/stores/workflows/workflow/store.ts @@ -497,16 +497,8 @@ export const useWorkflowStore = create()( batchAddEdges: (edges: Edge[]) => { const currentEdges = get().edges const newEdges = [...currentEdges] - const existingEdgeIds = new Set(currentEdges.map((e) => e.id)) for (const edge of edges) { - // Skip if edge ID already exists - if (existingEdgeIds.has(edge.id)) continue - - // Skip self-referencing edges - if (edge.source === edge.target) continue - - // Skip if identical connection already exists (same ports) const connectionExists = newEdges.some( (e) => e.source === edge.source && @@ -515,8 +507,6 @@ export const useWorkflowStore = create()( e.targetHandle === edge.targetHandle ) if (connectionExists) continue - - // Skip if would create a cycle if (wouldCreateCycle([...newEdges], edge.source, edge.target)) continue newEdges.push({ @@ -528,7 +518,6 @@ export const useWorkflowStore = create()( type: edge.type || 'default', data: edge.data || {}, }) - existingEdgeIds.add(edge.id) } const blocks = get().blocks From 42fa5b219856a846a4116be99b3f5623fe23035d Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Tue, 13 Jan 2026 18:27:32 -0800 Subject: [PATCH 2/2] consolidate --- apps/sim/hooks/use-collaborative-workflow.ts | 32 +++----------------- apps/sim/stores/workflows/utils.ts | 14 +++++++++ apps/sim/stores/workflows/workflow/store.ts | 19 +++++------- 3 files changed, 26 insertions(+), 39 deletions(-) diff --git a/apps/sim/hooks/use-collaborative-workflow.ts b/apps/sim/hooks/use-collaborative-workflow.ts index de70ce55fa..bdfbbae43b 100644 --- a/apps/sim/hooks/use-collaborative-workflow.ts +++ b/apps/sim/hooks/use-collaborative-workflow.ts @@ -22,7 +22,7 @@ import { useUndoRedoStore } from '@/stores/undo-redo' import { useWorkflowDiffStore } from '@/stores/workflow-diff/store' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useSubBlockStore } from '@/stores/workflows/subblock/store' -import { mergeSubblockState, normalizeName } from '@/stores/workflows/utils' +import { filterNewEdges, mergeSubblockState, normalizeName } from '@/stores/workflows/utils' import { useWorkflowStore } from '@/stores/workflows/workflow/store' import type { BlockState, Loop, Parallel, Position } from '@/stores/workflows/workflow/types' @@ -242,17 +242,7 @@ export function useCollaborativeWorkflow() { case EDGES_OPERATIONS.BATCH_ADD_EDGES: { const { edges } = payload if (Array.isArray(edges) && edges.length > 0) { - const currentEdges = workflowStore.edges - const newEdges = edges.filter((edge: Edge) => { - if (edge.source === edge.target) return false - return !currentEdges.some( - (e) => - e.source === edge.source && - e.sourceHandle === edge.sourceHandle && - e.target === edge.target && - e.targetHandle === edge.targetHandle - ) - }) + const newEdges = filterNewEdges(edges, workflowStore.edges) if (newEdges.length > 0) { workflowStore.batchAddEdges(newEdges) } @@ -989,22 +979,8 @@ export function useCollaborativeWorkflow() { if (edges.length === 0) return false - const currentEdges = workflowStore.edges - const newEdges = edges.filter((edge) => { - if (edge.source === edge.target) return false - return !currentEdges.some( - (e) => - e.source === edge.source && - e.sourceHandle === edge.sourceHandle && - e.target === edge.target && - e.targetHandle === edge.targetHandle - ) - }) - - if (newEdges.length === 0) { - logger.debug('Skipping batch add edges - all edges already exist') - return false - } + const newEdges = filterNewEdges(edges, workflowStore.edges) + if (newEdges.length === 0) return false const operationId = crypto.randomUUID() diff --git a/apps/sim/stores/workflows/utils.ts b/apps/sim/stores/workflows/utils.ts index 2caadeea1a..c0b3f3a9a4 100644 --- a/apps/sim/stores/workflows/utils.ts +++ b/apps/sim/stores/workflows/utils.ts @@ -1,5 +1,19 @@ import type { Edge } from 'reactflow' import { v4 as uuidv4 } from 'uuid' + +export function filterNewEdges(edgesToAdd: Edge[], currentEdges: Edge[]): Edge[] { + return edgesToAdd.filter((edge) => { + if (edge.source === edge.target) return false + return !currentEdges.some( + (e) => + e.source === edge.source && + e.sourceHandle === edge.sourceHandle && + e.target === edge.target && + e.targetHandle === edge.targetHandle + ) + }) +} + import { getBlockOutputs } from '@/lib/workflows/blocks/block-outputs' import { getBlock } from '@/blocks' import { normalizeName } from '@/executor/constants' diff --git a/apps/sim/stores/workflows/workflow/store.ts b/apps/sim/stores/workflows/workflow/store.ts index f5a265b64f..789e83695e 100644 --- a/apps/sim/stores/workflows/workflow/store.ts +++ b/apps/sim/stores/workflows/workflow/store.ts @@ -9,7 +9,12 @@ import { getBlock } from '@/blocks' import type { SubBlockConfig } from '@/blocks/types' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useSubBlockStore } from '@/stores/workflows/subblock/store' -import { getUniqueBlockName, mergeSubblockState, normalizeName } from '@/stores/workflows/utils' +import { + filterNewEdges, + getUniqueBlockName, + mergeSubblockState, + normalizeName, +} from '@/stores/workflows/utils' import type { Position, SubBlockState, @@ -496,19 +501,11 @@ export const useWorkflowStore = create()( batchAddEdges: (edges: Edge[]) => { const currentEdges = get().edges + const filtered = filterNewEdges(edges, currentEdges) const newEdges = [...currentEdges] - for (const edge of edges) { - const connectionExists = newEdges.some( - (e) => - e.source === edge.source && - e.sourceHandle === edge.sourceHandle && - e.target === edge.target && - e.targetHandle === edge.targetHandle - ) - if (connectionExists) continue + for (const edge of filtered) { if (wouldCreateCycle([...newEdges], edge.source, edge.target)) continue - newEdges.push({ id: edge.id || crypto.randomUUID(), source: edge.source,