From ecb13a58d6cfff0e789ed750bf5eb24eb7b11456 Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 31 Jan 2026 19:02:03 -0800 Subject: [PATCH] fix(lock): ensure consistent behavior across all UIs Block Menu, Editor, Action Bar now all have identical behavior: - Enable/Disable: disabled when locked OR parent locked - Flip Handles: disabled when locked OR parent locked - Delete: disabled when locked OR parent locked - Remove from Subflow: disabled when locked OR parent locked - Lock: always available for admins - Unlock: disabled when parent is locked (unlock parent first) Co-Authored-By: Claude Opus 4.5 --- .../components/action-bar/action-bar.tsx | 12 ++++++------ .../components/block-menu/block-menu.tsx | 12 +++++++++--- .../w/[workflowId]/hooks/use-canvas-context-menu.ts | 4 +++- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx index a0e17dc16..7c044c5a4 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx @@ -200,18 +200,18 @@ export const ActionBar = memo( variant='ghost' onClick={(e) => { e.stopPropagation() - if (!disabled && !isLocked) { + if (!disabled && !isLocked && !isParentLocked) { collaborativeBatchToggleBlockEnabled([blockId]) } }} className={ACTION_BUTTON_STYLES} - disabled={disabled || isLocked} + disabled={disabled || isLocked || isParentLocked} > {isEnabled ? : } - {isLocked + {isLocked || isParentLocked ? 'Block is locked' : getTooltipMessage(isEnabled ? 'Disable Block' : 'Enable Block')} @@ -274,12 +274,12 @@ export const ActionBar = memo( variant='ghost' onClick={(e) => { e.stopPropagation() - if (!disabled && !isLocked) { + if (!disabled && !isLocked && !isParentLocked) { collaborativeBatchToggleBlockHandles([blockId]) } }} className={ACTION_BUTTON_STYLES} - disabled={disabled || isLocked} + disabled={disabled || isLocked || isParentLocked} > {horizontalHandles ? ( @@ -289,7 +289,7 @@ export const ActionBar = memo( - {isLocked + {isLocked || isParentLocked ? 'Block is locked' : getTooltipMessage(horizontalHandles ? 'Vertical Ports' : 'Horizontal Ports')} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/block-menu/block-menu.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/block-menu/block-menu.tsx index 65c0a65d2..e8c5861b8 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/block-menu/block-menu.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/block-menu/block-menu.tsx @@ -21,6 +21,7 @@ export interface BlockInfo { parentId?: string parentType?: string locked?: boolean + isParentLocked?: boolean } /** @@ -98,6 +99,8 @@ export function BlockMenu({ const allDisabled = selectedBlocks.every((b) => !b.enabled) const allLocked = selectedBlocks.every((b) => b.locked) const allUnlocked = selectedBlocks.every((b) => !b.locked) + // Can't unlock blocks that have locked parents + const hasBlockWithLockedParent = selectedBlocks.some((b) => b.locked && b.isParentLocked) const hasSingletonBlock = selectedBlocks.some( (b) => @@ -216,12 +219,15 @@ export function BlockMenu({ )} {canAdmin && onToggleLocked && ( { - onToggleLocked() - onClose() + if (!hasBlockWithLockedParent) { + onToggleLocked() + onClose() + } }} > - {getToggleLockedLabel()} + {hasBlockWithLockedParent ? 'Parent is locked' : getToggleLockedLabel()} )} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-canvas-context-menu.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-canvas-context-menu.ts index 334e473f8..c95e97563 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-canvas-context-menu.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-canvas-context-menu.ts @@ -31,7 +31,8 @@ export function useCanvasContextMenu({ blocks, getNodes, setNodes }: UseCanvasCo nodes.map((n) => { const block = blocks[n.id] const parentId = block?.data?.parentId - const parentType = parentId ? blocks[parentId]?.type : undefined + const parentBlock = parentId ? blocks[parentId] : undefined + const parentType = parentBlock?.type return { id: n.id, type: block?.type || '', @@ -40,6 +41,7 @@ export function useCanvasContextMenu({ blocks, getNodes, setNodes }: UseCanvasCo parentId, parentType, locked: block?.locked ?? false, + isParentLocked: parentBlock?.locked ?? false, } }), [blocks]