{Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => (
-
+
@@ -17,7 +17,7 @@ export default function TablesLoading() {
-
+
@@ -26,7 +26,7 @@ export default function TablesLoading() {
-
+
|
|
@@ -39,7 +39,7 @@ export default function TablesLoading() {
{Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => (
-
+
|
|
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
index 59e56a16b6c..374340af825 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
@@ -201,8 +201,6 @@ const edgeTypes: EdgeTypes = {
const defaultEdgeOptions = { type: 'custom' }
const reactFlowStyles = [
- '[&_.react-flow__edges]:!z-0',
- '[&_.react-flow__node]:z-[21]',
'[&_.react-flow__handle]:!z-[30]',
'[&_.react-flow__edge-labels]:!z-[1001]',
'[&_.react-flow__pane]:select-none',
@@ -2478,6 +2476,7 @@ const WorkflowContent = React.memo(
// Local state for nodes - allows smooth drag without store updates on every frame
const [displayNodes, setDisplayNodes] = useState([])
+ const [lastInteractedNodeId, setLastInteractedNodeId] = useState(null)
const selectedNodeIds = useMemo(
() => displayNodes.filter((node) => node.selected).map((node) => node.id),
@@ -2489,6 +2488,14 @@ const WorkflowContent = React.memo(
syncPanelWithSelection(selectedNodeIds)
}, [selectedNodeIdsKey])
+ // Keep the most recently selected block on top even after deselection, so a
+ // dragged block doesn't suddenly drop behind other overlapping blocks.
+ useEffect(() => {
+ if (selectedNodeIds.length > 0) {
+ setLastInteractedNodeId(selectedNodeIds[selectedNodeIds.length - 1])
+ }
+ }, [selectedNodeIdsKey])
+
useEffect(() => {
// Check for pending selection (from paste/duplicate), otherwise preserve existing selection
if (pendingSelection && pendingSelection.length > 0) {
@@ -3723,18 +3730,58 @@ const WorkflowContent = React.memo(
[removeEdge, edges, blocks, addNotification, activeWorkflowId]
)
+ // Elevate nodes using React Flow's native zIndex so selected/recent blocks
+ // always sit above edges and other blocks.
+ //
+ // Z-index layers (regular blocks):
+ // 21 — default
+ // 22 — last interacted (dragged/selected, now deselected) so it stays on
+ // top of siblings until another block is touched
+ // 31 — currently selected (above connected edges at z-22 and handles at z-30)
+ //
+ // Subflow container nodes are skipped — they use depth-based zIndex for
+ // correct parent/child layering and must not be bumped.
+ // Child blocks inside containers already carry zIndex 1000 and are bumped by
+ // +10 when selected so they stay above their sibling child blocks.
+ const nodesForRender = useMemo(() => {
+ return displayNodes.map((node) => {
+ if (node.type === 'subflowNode') return node
+ const base = node.zIndex ?? 21
+ const target = node.selected
+ ? base + 10
+ : node.id === lastInteractedNodeId
+ ? Math.max(base + 1, 22)
+ : base
+ if (target === (node.zIndex ?? 21)) return node
+ return { ...node, zIndex: target }
+ })
+ }, [displayNodes, lastInteractedNodeId])
+
/** Transforms edges to include selection state and delete handlers. Memoized to prevent re-renders. */
const edgesWithSelection = useMemo(() => {
const nodeMap = new Map(displayNodes.map((n) => [n.id, n]))
+ const elevatedNodeIdSet = new Set(
+ lastInteractedNodeId ? [...selectedNodeIds, lastInteractedNodeId] : selectedNodeIds
+ )
return edgesForDisplay.map((edge) => {
const sourceNode = nodeMap.get(edge.source)
const targetNode = nodeMap.get(edge.target)
const parentLoopId = sourceNode?.parentId || targetNode?.parentId
const edgeContextId = `${edge.id}${parentLoopId ? `-${parentLoopId}` : ''}`
+ const connectedToElevated =
+ elevatedNodeIdSet.has(edge.source) || elevatedNodeIdSet.has(edge.target)
+ // Derive elevated z-index from connected nodes so edges inside subflows
+ // (child nodes at z-1000) stay above their sibling child blocks.
+ const elevatedZIndex = Math.max(
+ 22,
+ (sourceNode?.zIndex ?? 21) + 1,
+ (targetNode?.zIndex ?? 21) + 1
+ )
return {
...edge,
+ zIndex: connectedToElevated ? elevatedZIndex : 0,
data: {
...edge.data,
isSelected: selectedEdges.has(edgeContextId),
@@ -3745,7 +3792,14 @@ const WorkflowContent = React.memo(
},
}
})
- }, [edgesForDisplay, displayNodes, selectedEdges, handleEdgeDelete])
+ }, [
+ edgesForDisplay,
+ displayNodes,
+ selectedNodeIds,
+ selectedEdges,
+ handleEdgeDelete,
+ lastInteractedNodeId,
+ ])
/** Handles Delete/Backspace to remove selected edges or blocks. */
useEffect(() => {
@@ -3885,7 +3939,7 @@ const WorkflowContent = React.memo(
{showTrainingModal && }
|