| 83 | } |
| 84 | |
| 85 | function isOperationApplicable( |
| 86 | operation: Operation, |
| 87 | graph: { blocksById: Record<string, BlockState>; edgesById: Record<string, Edge> } |
| 88 | ): boolean { |
| 89 | switch (operation.type) { |
| 90 | case UNDO_REDO_OPERATIONS.BATCH_REMOVE_BLOCKS: { |
| 91 | const op = operation as BatchRemoveBlocksOperation |
| 92 | return op.data.blockSnapshots.every((block) => Boolean(graph.blocksById[block.id])) |
| 93 | } |
| 94 | case UNDO_REDO_OPERATIONS.BATCH_ADD_BLOCKS: { |
| 95 | const op = operation as BatchAddBlocksOperation |
| 96 | return op.data.blockSnapshots.every((block) => !graph.blocksById[block.id]) |
| 97 | } |
| 98 | case UNDO_REDO_OPERATIONS.BATCH_MOVE_BLOCKS: { |
| 99 | const op = operation as BatchMoveBlocksOperation |
| 100 | return op.data.moves.every((move) => Boolean(graph.blocksById[move.blockId])) |
| 101 | } |
| 102 | case UNDO_REDO_OPERATIONS.UPDATE_PARENT: { |
| 103 | const blockId = operation.data.blockId |
| 104 | return Boolean(graph.blocksById[blockId]) |
| 105 | } |
| 106 | case UNDO_REDO_OPERATIONS.BATCH_UPDATE_PARENT: { |
| 107 | const op = operation as BatchUpdateParentOperation |
| 108 | return op.data.updates.every((u) => Boolean(graph.blocksById[u.blockId])) |
| 109 | } |
| 110 | case UNDO_REDO_OPERATIONS.BATCH_REMOVE_EDGES: { |
| 111 | const op = operation as BatchRemoveEdgesOperation |
| 112 | return op.data.edgeSnapshots.every((edge) => Boolean(graph.edgesById[edge.id])) |
| 113 | } |
| 114 | case UNDO_REDO_OPERATIONS.BATCH_ADD_EDGES: { |
| 115 | const op = operation as BatchAddEdgesOperation |
| 116 | return op.data.edgeSnapshots.every((edge) => !graph.edgesById[edge.id]) |
| 117 | } |
| 118 | default: |
| 119 | return true |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | export const useUndoRedoStore = create<UndoRedoState>()( |
| 124 | persist( |