From 4c05ae1f34d730a612b27d1eadf44a0c5f73c39f Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 31 Jan 2026 19:56:00 -0800 Subject: [PATCH] fix(lock): address review comments for lock feature 1. Store batchToggleEnabled now uses continue to skip locked blocks entirely, matching database operation behavior 2. Copilot add operation now checks if parent container is locked before adding nested nodes (defensive check for consistency) 3. Remove unused filterUnprotectedEdges function Co-Authored-By: Claude Opus 4.5 --- .../w/[workflowId]/utils/block-protection-utils.ts | 14 -------------- .../copilot/tools/server/workflow/edit-workflow.ts | 13 +++++++++++++ apps/sim/stores/workflows/workflow/store.ts | 10 +++++----- 3 files changed, 18 insertions(+), 19 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 8380dd985..797c7f2c9 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 @@ -71,20 +71,6 @@ export function filterProtectedBlocks( } } -/** - * Filters edges to only include those that are not protected. - * - * @param edges - Array of edges to filter - * @param blocks - Record of all blocks in the workflow - * @returns Array of edges that can be modified (not protected) - */ -export function filterUnprotectedEdges( - edges: T[], - blocks: Record -): T[] { - return edges.filter((edge) => !isEdgeProtected(edge, blocks)) -} - /** * Checks if any blocks in the selection are protected. * Useful for determining if edit actions should be disabled. diff --git a/apps/sim/lib/copilot/tools/server/workflow/edit-workflow.ts b/apps/sim/lib/copilot/tools/server/workflow/edit-workflow.ts index d4fe120cf..54080236d 100644 --- a/apps/sim/lib/copilot/tools/server/workflow/edit-workflow.ts +++ b/apps/sim/lib/copilot/tools/server/workflow/edit-workflow.ts @@ -2146,6 +2146,19 @@ function applyOperationsToWorkflowState( // Handle nested nodes (for loops/parallels created from scratch) if (params.nestedNodes) { + // Defensive check: verify parent is not locked before adding children + // (Parent was just created with locked: false, but check for consistency) + const parentBlock = modifiedState.blocks[block_id] + if (parentBlock?.locked) { + logSkippedItem(skippedItems, { + type: 'block_locked', + operationType: 'add_nested_nodes', + blockId: block_id, + reason: `Container "${block_id}" is locked - cannot add nested nodes`, + }) + break + } + Object.entries(params.nestedNodes).forEach(([childId, childBlock]: [string, any]) => { // Validate childId is a valid string if (!isValidKey(childId)) { diff --git a/apps/sim/stores/workflows/workflow/store.ts b/apps/sim/stores/workflows/workflow/store.ts index 3e28d717b..e58228ff3 100644 --- a/apps/sim/stores/workflows/workflow/store.ts +++ b/apps/sim/stores/workflows/workflow/store.ts @@ -373,16 +373,16 @@ export const useWorkflowStore = create()( const newBlocks = { ...currentBlocks } const blocksToToggle = new Set() - // For each ID, collect blocks to toggle (skip locked blocks) + // For each ID, collect blocks to toggle (skip locked blocks entirely) // If it's a container, also include non-locked children for (const id of ids) { const block = currentBlocks[id] if (!block) continue - // Skip locked blocks - if (!block.locked) { - blocksToToggle.add(id) - } + // Skip locked blocks entirely (including their children) + if (block.locked) continue + + blocksToToggle.add(id) // If it's a loop or parallel, also include non-locked children if (block.type === 'loop' || block.type === 'parallel') {