remove dead subflow-specific ops

This commit is contained in:
waleed
2026-01-08 19:30:12 -08:00
parent a8fb76b450
commit 0568704c69
7 changed files with 54 additions and 124 deletions

View File

@@ -425,7 +425,8 @@ export function useUndoRedo() {
break
}
case 'batch-add-blocks': {
const batchAddOp = entry.operation as BatchAddBlocksOperation
// Undoing a removal: inverse is batch-add-blocks, use entry.inverse for data
const batchAddOp = entry.inverse as BatchAddBlocksOperation
const { blockSnapshots, edgeSnapshots, subBlockValues } = batchAddOp.data
const blocksToAdd = blockSnapshots.filter((b) => !workflowStore.blocks[b.id])

View File

@@ -13,11 +13,11 @@
import {
createAddBlockEntry,
createAddEdgeEntry,
createBatchRemoveEdgesEntry,
createBlock,
createMockStorage,
createMoveBlockEntry,
createRemoveBlockEntry,
createRemoveEdgeEntry,
createUpdateParentEntry,
} from '@sim/testing'
import { beforeEach, describe, expect, it } from 'vitest'
@@ -603,16 +603,17 @@ describe('useUndoRedoStore', () => {
expect(getStackSizes(workflowId, userId).undoSize).toBe(2)
})
it('should handle remove-edge operations', () => {
it('should handle batch-remove-edges operations', () => {
const { push, undo, getStackSizes } = useUndoRedoStore.getState()
push(workflowId, userId, createRemoveEdgeEntry('edge-1', null, { workflowId, userId }))
const edgeSnapshot = { id: 'edge-1', source: 'block-1', target: 'block-2' }
push(workflowId, userId, createBatchRemoveEdgesEntry([edgeSnapshot], { workflowId, userId }))
expect(getStackSizes(workflowId, userId).undoSize).toBe(1)
const entry = undo(workflowId, userId)
expect(entry?.operation.type).toBe('remove-edge')
expect(entry?.inverse.type).toBe('add-edge')
expect(entry?.operation.type).toBe('batch-remove-edges')
expect(entry?.inverse.type).toBe('batch-add-edges')
})
})
@@ -672,8 +673,10 @@ describe('useUndoRedoStore', () => {
it('should remove entries for non-existent edges', () => {
const { push, pruneInvalidEntries, getStackSizes } = useUndoRedoStore.getState()
push(workflowId, userId, createRemoveEdgeEntry('edge-1', null, { workflowId, userId }))
push(workflowId, userId, createRemoveEdgeEntry('edge-2', null, { workflowId, userId }))
const edge1 = { id: 'edge-1', source: 'a', target: 'b' }
const edge2 = { id: 'edge-2', source: 'c', target: 'd' }
push(workflowId, userId, createBatchRemoveEdgesEntry([edge1], { workflowId, userId }))
push(workflowId, userId, createBatchRemoveEdgesEntry([edge2], { workflowId, userId }))
expect(getStackSizes(workflowId, userId).undoSize).toBe(2)
@@ -686,6 +689,8 @@ describe('useUndoRedoStore', () => {
pruneInvalidEntries(workflowId, userId, graph as any)
// edge-1 exists in graph, so we can't undo its removal (can't add it back) → pruned
// edge-2 doesn't exist, so we can undo its removal (can add it back) → kept
expect(getStackSizes(workflowId, userId).undoSize).toBe(1)
})
})

View File

@@ -4,6 +4,7 @@ import { create } from 'zustand'
import { createJSONStorage, persist } from 'zustand/middleware'
import type {
BatchAddBlocksOperation,
BatchAddEdgesOperation,
BatchMoveBlocksOperation,
BatchRemoveBlocksOperation,
BatchRemoveEdgesOperation,
@@ -104,17 +105,14 @@ function isOperationApplicable(
const op = operation as BatchRemoveEdgesOperation
return op.data.edgeSnapshots.every((edge) => Boolean(graph.edgesById[edge.id]))
}
case 'batch-add-edges': {
const op = operation as BatchAddEdgesOperation
return op.data.edgeSnapshots.every((edge) => !graph.edgesById[edge.id])
}
case 'add-edge': {
const edgeId = operation.data.edgeId
return !graph.edgesById[edgeId]
}
case 'add-subflow':
case 'remove-subflow': {
const subflowId = operation.data.subflowId
return operation.type === 'remove-subflow'
? Boolean(graph.blocksById[subflowId])
: !graph.blocksById[subflowId]
}
default:
return true
}

View File

@@ -7,10 +7,7 @@ export type OperationType =
| 'add-edge'
| 'batch-add-edges'
| 'batch-remove-edges'
| 'add-subflow'
| 'remove-subflow'
| 'batch-move-blocks'
| 'move-subflow'
| 'update-parent'
| 'batch-toggle-enabled'
| 'batch-toggle-handles'
@@ -65,21 +62,6 @@ export interface BatchRemoveEdgesOperation extends BaseOperation {
}
}
export interface AddSubflowOperation extends BaseOperation {
type: 'add-subflow'
data: {
subflowId: string
}
}
export interface RemoveSubflowOperation extends BaseOperation {
type: 'remove-subflow'
data: {
subflowId: string
subflowSnapshot: BlockState | null
}
}
export interface BatchMoveBlocksOperation extends BaseOperation {
type: 'batch-move-blocks'
data: {
@@ -91,21 +73,6 @@ export interface BatchMoveBlocksOperation extends BaseOperation {
}
}
export interface MoveSubflowOperation extends BaseOperation {
type: 'move-subflow'
data: {
subflowId: string
before: {
x: number
y: number
}
after: {
x: number
y: number
}
}
}
export interface UpdateParentOperation extends BaseOperation {
type: 'update-parent'
data: {
@@ -169,10 +136,7 @@ export type Operation =
| AddEdgeOperation
| BatchAddEdgesOperation
| BatchRemoveEdgesOperation
| AddSubflowOperation
| RemoveSubflowOperation
| BatchMoveBlocksOperation
| MoveSubflowOperation
| UpdateParentOperation
| BatchToggleEnabledOperation
| BatchToggleHandlesOperation

View File

@@ -79,25 +79,6 @@ export function createInverseOperation(operation: Operation): Operation {
} as BatchAddEdgesOperation
}
case 'add-subflow':
return {
...operation,
type: 'remove-subflow',
data: {
subflowId: operation.data.subflowId,
subflowSnapshot: null,
},
}
case 'remove-subflow':
return {
...operation,
type: 'add-subflow',
data: {
subflowId: operation.data.subflowId,
},
}
case 'batch-move-blocks': {
const op = operation as BatchMoveBlocksOperation
return {
@@ -113,16 +94,6 @@ export function createInverseOperation(operation: Operation): Operation {
} as BatchMoveBlocksOperation
}
case 'move-subflow':
return {
...operation,
data: {
subflowId: operation.data.subflowId,
before: operation.data.after,
after: operation.data.before,
},
}
case 'update-parent':
return {
...operation,
@@ -256,20 +227,6 @@ export function operationToCollaborativePayload(operation: Operation): {
}
}
case 'add-subflow':
return {
operation: 'add',
target: 'subflow',
payload: { id: operation.data.subflowId },
}
case 'remove-subflow':
return {
operation: 'remove',
target: 'subflow',
payload: { id: operation.data.subflowId },
}
case 'batch-move-blocks': {
const op = operation as BatchMoveBlocksOperation
return {
@@ -286,17 +243,6 @@ export function operationToCollaborativePayload(operation: Operation): {
}
}
case 'move-subflow':
return {
operation: 'update-position',
target: 'subflow',
payload: {
id: operation.data.subflowId,
x: operation.data.after.x,
y: operation.data.after.y,
},
}
case 'update-parent':
return {
operation: 'update-parent',

View File

@@ -123,18 +123,19 @@ export {
type AddEdgeOperation,
type BaseOperation,
type BatchAddBlocksOperation,
type BatchAddEdgesOperation,
type BatchMoveBlocksOperation,
type BatchRemoveBlocksOperation,
type BatchRemoveEdgesOperation,
createAddBlockEntry,
createAddEdgeEntry,
createBatchRemoveEdgesEntry,
createMoveBlockEntry,
createRemoveBlockEntry,
createRemoveEdgeEntry,
createUpdateParentEntry,
type Operation,
type OperationEntry,
type OperationType,
type RemoveEdgeOperation,
type UpdateParentOperation,
} from './undo-redo.factory'
// User/workspace factories

View File

@@ -9,7 +9,8 @@ export type OperationType =
| 'batch-add-blocks'
| 'batch-remove-blocks'
| 'add-edge'
| 'remove-edge'
| 'batch-add-edges'
| 'batch-remove-edges'
| 'batch-move-blocks'
| 'update-parent'
@@ -71,11 +72,19 @@ export interface AddEdgeOperation extends BaseOperation {
}
/**
* Remove edge operation data.
* Batch add edges operation data.
*/
export interface RemoveEdgeOperation extends BaseOperation {
type: 'remove-edge'
data: { edgeId: string; edgeSnapshot: any }
export interface BatchAddEdgesOperation extends BaseOperation {
type: 'batch-add-edges'
data: { edgeSnapshots: any[] }
}
/**
* Batch remove edges operation data.
*/
export interface BatchRemoveEdgesOperation extends BaseOperation {
type: 'batch-remove-edges'
data: { edgeSnapshots: any[] }
}
/**
@@ -96,7 +105,8 @@ export type Operation =
| BatchAddBlocksOperation
| BatchRemoveBlocksOperation
| AddEdgeOperation
| RemoveEdgeOperation
| BatchAddEdgesOperation
| BatchRemoveEdgesOperation
| BatchMoveBlocksOperation
| UpdateParentOperation
@@ -212,10 +222,16 @@ export function createRemoveBlockEntry(
/**
* Creates a mock add-edge operation entry.
*/
export function createAddEdgeEntry(edgeId: string, options: OperationEntryOptions = {}): any {
export function createAddEdgeEntry(
edgeId: string,
edgeSnapshot: any = null,
options: OperationEntryOptions = {}
): any {
const { id = nanoid(8), workflowId = 'wf-1', userId = 'user-1', createdAt = Date.now() } = options
const timestamp = Date.now()
const snapshot = edgeSnapshot || { id: edgeId, source: 'block-1', target: 'block-2' }
return {
id,
createdAt,
@@ -229,21 +245,20 @@ export function createAddEdgeEntry(edgeId: string, options: OperationEntryOption
},
inverse: {
id: nanoid(8),
type: 'remove-edge',
type: 'batch-remove-edges',
timestamp,
workflowId,
userId,
data: { edgeId, edgeSnapshot: null },
data: { edgeSnapshots: [snapshot] },
},
}
}
/**
* Creates a mock remove-edge operation entry.
* Creates a mock batch-remove-edges operation entry.
*/
export function createRemoveEdgeEntry(
edgeId: string,
edgeSnapshot: any = null,
export function createBatchRemoveEdgesEntry(
edgeSnapshots: any[],
options: OperationEntryOptions = {}
): any {
const { id = nanoid(8), workflowId = 'wf-1', userId = 'user-1', createdAt = Date.now() } = options
@@ -254,19 +269,19 @@ export function createRemoveEdgeEntry(
createdAt,
operation: {
id: nanoid(8),
type: 'remove-edge',
type: 'batch-remove-edges',
timestamp,
workflowId,
userId,
data: { edgeId, edgeSnapshot },
data: { edgeSnapshots },
},
inverse: {
id: nanoid(8),
type: 'add-edge',
type: 'batch-add-edges',
timestamp,
workflowId,
userId,
data: { edgeId },
data: { edgeSnapshots },
},
}
}