From 96f40b71600d5f59e946a1ce9aa5693e0514b0d4 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 4 Mar 2026 11:41:56 -0800 Subject: [PATCH 1/8] fix(subflows): recurse into all descendants for lock, enable, and protection checks --- .../panel/components/editor/editor.tsx | 21 +- .../components/subflows/subflow-node.tsx | 118 ++++++------ .../utils/block-protection-utils.ts | 25 +-- .../[workspaceId]/w/[workflowId]/workflow.tsx | 10 +- apps/sim/hooks/use-collaborative-workflow.ts | 32 +--- apps/sim/socket/database/operations.ts | 179 +++++++----------- apps/sim/stores/workflows/workflow/store.ts | 34 ++-- apps/sim/stores/workflows/workflow/utils.ts | 41 ++-- 8 files changed, 196 insertions(+), 264 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx index 42e88b22a50..597f8213438 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx @@ -40,6 +40,7 @@ import { LoopTool } from '@/app/workspace/[workspaceId]/w/[workflowId]/component import { ParallelTool } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/parallel/parallel-config' import { getSubBlockStableKey } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/utils' import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks' +import { isBlockProtected } from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/block-protection-utils' import { PreviewWorkflow } from '@/app/workspace/[workspaceId]/w/components/preview' import { getBlock } from '@/blocks/registry' import type { SubBlockType } from '@/blocks/types' @@ -107,12 +108,11 @@ export function Editor() { const userPermissions = useUserPermissionsContext() - // Check if block is locked (or inside a locked container) and compute edit permission + // Check if block is locked (or inside a locked ancestor) and compute edit permission // Locked blocks cannot be edited by anyone (admins can only lock/unlock) const blocks = useWorkflowStore((state) => state.blocks) - const parentId = currentBlock?.data?.parentId as string | undefined - const isParentLocked = parentId ? (blocks[parentId]?.locked ?? false) : false - const isLocked = (currentBlock?.locked ?? false) || isParentLocked + const isLocked = currentBlockId ? isBlockProtected(currentBlockId, blocks) : false + const isAncestorLocked = isLocked && !(currentBlock?.locked ?? false) const canEditBlock = userPermissions.canEdit && !isLocked const activeWorkflowId = useWorkflowRegistry((state) => state.activeWorkflowId) @@ -247,10 +247,7 @@ export function Editor() { const block = blocks[blockId] if (!block) return - const parentId = block.data?.parentId as string | undefined - const isParentLocked = parentId ? (blocks[parentId]?.locked ?? false) : false - const isLocked = (block.locked ?? false) || isParentLocked - if (!userPermissions.canEdit || isLocked) return + if (!userPermissions.canEdit || isBlockProtected(blockId, blocks)) return renamingBlockIdRef.current = blockId setEditedName(block.name || '') @@ -364,11 +361,11 @@ export function Editor() { )}
- {/* Locked indicator - clickable to unlock if user has admin permissions, block is locked, and parent is not locked */} + {/* Locked indicator - clickable to unlock if user has admin permissions, block is locked directly, and not locked by an ancestor */} {isLocked && currentBlock && ( - {userPermissions.canAdmin && currentBlock.locked && !isParentLocked ? ( + {userPermissions.canAdmin && currentBlock.locked && !isAncestorLocked ? (