From 0ee52df5a73aa923daa29a7a5c1404c2cb8bbea7 Mon Sep 17 00:00:00 2001 From: Emir Karabeg <78010029+emir-karabeg@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:16:17 -0800 Subject: [PATCH] feat(canvas): allow locked block outbound connections (#3229) * Allow outbound connections from locked blocks to be modified - Modified isEdgeProtected to only check target block protection - Outbound connections (from locked blocks) can now be added/removed - Inbound connections (to locked blocks) remain protected - Updated notification messages and comments to reflect the change Co-authored-by: Emir Karabeg * update notif msg --------- Co-authored-by: Cursor Agent Co-authored-by: Emir Karabeg Co-authored-by: waleed --- .../w/[workflowId]/utils/block-protection-utils.ts | 7 ++++--- .../[workspaceId]/w/[workflowId]/workflow.tsx | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-protection-utils.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-protection-utils.ts index eb76077fc..d86f1b3dc 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-protection-utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-protection-utils.ts @@ -36,17 +36,18 @@ export function isBlockProtected(blockId: string, blocks: Record ): boolean { - return isBlockProtected(edge.source, blocks) || isBlockProtected(edge.target, blocks) + return isBlockProtected(edge.target, blocks) } /** diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx index 66fa0ee16..5b8b66f2b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx @@ -2523,7 +2523,7 @@ const WorkflowContent = React.memo(() => { .filter((change: any) => change.type === 'remove') .map((change: any) => change.id) .filter((edgeId: string) => { - // Prevent removing edges connected to protected blocks + // Prevent removing edges targeting protected blocks const edge = edges.find((e) => e.id === edgeId) if (!edge) return true return !isEdgeProtected(edge, blocks) @@ -2595,7 +2595,7 @@ const WorkflowContent = React.memo(() => { if (!sourceNode || !targetNode) return - // Prevent connections to/from protected blocks + // Prevent connections to protected blocks (outbound from locked blocks is allowed) if (isEdgeProtected(connection, blocks)) { addNotification({ level: 'info', @@ -3357,12 +3357,12 @@ const WorkflowContent = React.memo(() => { /** Stable delete handler to avoid creating new function references per edge. */ const handleEdgeDelete = useCallback( (edgeId: string) => { - // Prevent removing edges connected to protected blocks + // Prevent removing edges targeting protected blocks const edge = edges.find((e) => e.id === edgeId) if (edge && isEdgeProtected(edge, blocks)) { addNotification({ level: 'info', - message: 'Cannot remove connections from locked blocks', + message: 'Cannot remove connections to locked blocks', workflowId: activeWorkflowId || undefined, }) return @@ -3420,7 +3420,7 @@ const WorkflowContent = React.memo(() => { // Handle edge deletion first (edges take priority if selected) if (selectedEdges.size > 0) { - // Get all selected edge IDs and filter out edges connected to protected blocks + // Get all selected edge IDs and filter out edges targeting protected blocks const edgeIds = Array.from(selectedEdges.values()).filter((edgeId) => { const edge = edges.find((e) => e.id === edgeId) if (!edge) return true