@@ -49,6 +49,31 @@ interface DbBlockRef {
4949 data : unknown
5050}
5151
52+ export function filterBatchAddBlocksByProtection (
53+ blocks : Array < Record < string , unknown > > ,
54+ existingBlocks : Array < { id : string ; locked ?: boolean | null ; data : unknown } >
55+ ) : Array < Record < string , unknown > > {
56+ const blocksById : Record < string , DbBlockRef > = Object . fromEntries (
57+ existingBlocks . map ( ( block ) => [ block . id , block ] )
58+ )
59+
60+ for ( const block of blocks ) {
61+ const id = block . id as string | undefined
62+ if ( ! id ) continue
63+
64+ blocksById [ id ] = {
65+ id,
66+ locked : ( block . locked as boolean | null | undefined ) ?? false ,
67+ data : ( block . data as Record < string , unknown > | null | undefined ) ?? { } ,
68+ }
69+ }
70+
71+ return blocks . filter ( ( block ) => {
72+ const id = block . id as string | undefined
73+ return id !== undefined && ! isDbBlockProtected ( id , blocksById )
74+ } )
75+ }
76+
5277/**
5378 * Checks if a block is protected (locked or inside a locked ancestor).
5479 * Works with raw DB records.
@@ -127,6 +152,15 @@ function getParentTransitionKey(
127152 return JSON . stringify ( [ oldParentId ?? null , newParentId ?? null ] )
128153}
129154
155+ export function getBatchUpdateParentCoMovingKey (
156+ oldParentId : string | null | undefined ,
157+ newParentId : string | null | undefined
158+ ) : string {
159+ return newParentId
160+ ? JSON . stringify ( [ 'destination' , newParentId ] )
161+ : getParentTransitionKey ( oldParentId , newParentId )
162+ }
163+
130164/**
131165 * Remove cross-boundary edges when a block is reparented into or out of a container.
132166 *
@@ -1099,29 +1133,25 @@ async function handleBlocksOperationTx(
10991133 if ( blocks && blocks . length > 0 ) {
11001134 // Fetch existing blocks to check for locked parents
11011135 const existingBlocks = await tx
1102- . select ( { id : workflowBlocks . id , locked : workflowBlocks . locked } )
1136+ . select ( {
1137+ id : workflowBlocks . id ,
1138+ locked : workflowBlocks . locked ,
1139+ data : workflowBlocks . data ,
1140+ } )
11031141 . from ( workflowBlocks )
11041142 . where ( eq ( workflowBlocks . workflowId , workflowId ) )
11051143
11061144 type ExistingBlockRecord = ( typeof existingBlocks ) [ number ]
11071145 existingBlockIds = new Set ( existingBlocks . map ( ( block : ExistingBlockRecord ) => block . id ) )
1108- const lockedParentIds = new Set (
1146+ allowedBlocks = filterBatchAddBlocksByProtection (
1147+ blocks as Array < Record < string , unknown > > ,
11091148 existingBlocks
1110- . filter ( ( b : ExistingBlockRecord ) => b . locked )
1111- . map ( ( b : ExistingBlockRecord ) => b . id )
11121149 )
11131150
1114- // Filter out blocks being added to locked parents
1115- allowedBlocks = ( blocks as Array < Record < string , unknown > > ) . filter ( ( block ) => {
1116- const parentId = ( block . data as Record < string , unknown > | null ) ?. parentId as
1117- | string
1118- | undefined
1119- if ( parentId && lockedParentIds . has ( parentId ) ) {
1120- logger . info ( `Skipping block ${ block . id } - parent ${ parentId } is locked` )
1121- return false
1122- }
1123- return true
1124- } )
1151+ const skippedBlockCount = blocks . length - allowedBlocks . length
1152+ if ( skippedBlockCount > 0 ) {
1153+ logger . info ( `Filtered out ${ skippedBlockCount } batch-added block(s) due to protection` )
1154+ }
11251155
11261156 if ( allowedBlocks . length === 0 ) {
11271157 logger . info ( 'All blocks filtered out due to locked parents, skipping add' )
@@ -1683,7 +1713,7 @@ async function handleBlocksOperationTx(
16831713 const allRemovedEdgeIds : string [ ] = [ ]
16841714 const allAddedEdges : NonNullable < OperationResult [ 'addedEdges' ] > = [ ]
16851715 const applicableUpdates : Array < ( typeof updates ) [ number ] > = [ ]
1686- const coMovingBlockIdsByTransition = new Map < string , Set < string > > ( )
1716+ const coMovingBlockIdsByDestination = new Map < string , Set < string > > ( )
16871717
16881718 for ( const update of updates ) {
16891719 const { id, parentId, position } = update
@@ -1714,11 +1744,10 @@ async function handleBlocksOperationTx(
17141744 const existingParentId = ( existing . data as Record < string , unknown > | null ) ?. parentId as
17151745 | string
17161746 | undefined
1717- const transitionKey = getParentTransitionKey ( existingParentId , parentId )
1718- const coMovingBlockIds =
1719- coMovingBlockIdsByTransition . get ( transitionKey ) ?? new Set < string > ( )
1747+ const coMovingKey = getBatchUpdateParentCoMovingKey ( existingParentId , parentId )
1748+ const coMovingBlockIds = coMovingBlockIdsByDestination . get ( coMovingKey ) ?? new Set < string > ( )
17201749 coMovingBlockIds . add ( id )
1721- coMovingBlockIdsByTransition . set ( transitionKey , coMovingBlockIds )
1750+ coMovingBlockIdsByDestination . set ( coMovingKey , coMovingBlockIds )
17221751 }
17231752
17241753 for ( const update of applicableUpdates ) {
@@ -1769,7 +1798,9 @@ async function handleBlocksOperationTx(
17691798 id ,
17701799 parentId ?? null ,
17711800 existingParentId ?? null ,
1772- coMovingBlockIdsByTransition . get ( getParentTransitionKey ( existingParentId , parentId ) )
1801+ coMovingBlockIdsByDestination . get (
1802+ getBatchUpdateParentCoMovingKey ( existingParentId , parentId )
1803+ )
17731804 )
17741805 allRemovedEdgeIds . push ( ...removedEdgeIds )
17751806
0 commit comments