diff --git a/src/stores/layoutStore.ts b/src/stores/layoutStore.ts index 94350467e..039ee1c95 100644 --- a/src/stores/layoutStore.ts +++ b/src/stores/layoutStore.ts @@ -11,16 +11,12 @@ import * as Y from 'yjs' import { ACTOR_CONFIG, DEBUG_CONFIG } from '@/constants/layout' import { SpatialIndexManager } from '@/services/spatialIndexManager' import type { - BatchUpdateSlotsOperation, CreateNodeOperation, - CreateSlotOperation, DeleteNodeOperation, - DeleteSlotOperation, LayoutOperation, MoveNodeOperation, ResizeNodeOperation, - SetNodeZIndexOperation, - UpdateSlotOperation + SetNodeZIndexOperation } from '@/types/layoutOperations' import type { Bounds, @@ -28,9 +24,7 @@ import type { LayoutStore, NodeId, NodeLayout, - Point, - SlotId, - SlotLayout + Point } from '@/types/layoutTypes' // Create logger for layout store @@ -44,7 +38,6 @@ class LayoutStoreImpl implements LayoutStore { // Yjs document and shared data structures private ydoc = new Y.Doc() private ynodes: Y.Map> // Maps nodeId -> Y.Map containing NodeLayout data - private yslots: Y.Map> // Maps slotId -> Y.Map containing SlotLayout data private yoperations: Y.Array // Operation log // Vue reactivity layer @@ -61,8 +54,6 @@ class LayoutStoreImpl implements LayoutStore { // CustomRef cache and trigger functions private nodeRefs = new Map>() private nodeTriggers = new Map void>() - private slotRefs = new Map>() - private slotTriggers = new Map void>() // Spatial index manager private spatialIndex: SpatialIndexManager @@ -70,7 +61,6 @@ class LayoutStoreImpl implements LayoutStore { constructor() { // Initialize Yjs data structures this.ynodes = this.ydoc.getMap('nodes') - this.yslots = this.ydoc.getMap('slots') this.yoperations = this.ydoc.getArray('operations') // Initialize spatial index manager @@ -90,20 +80,6 @@ class LayoutStoreImpl implements LayoutStore { }) }) - // Listen for slot changes - this.yslots.observe((event) => { - this.version++ - - // Trigger all affected slot refs - event.changes.keys.forEach((_change, key) => { - const trigger = this.slotTriggers.get(key) - if (trigger) { - logger.debug(`Yjs change detected for slot ${key}, triggering ref`) - trigger() - } - }) - }) - // Debug: Log layout operations if (localStorage.getItem(DEBUG_CONFIG.LAYOUT_DEBUG_KEY) === 'true') { this.yoperations.observe((event) => { @@ -272,140 +248,6 @@ class LayoutStoreImpl implements LayoutStore { }) } - /** - * Get or create a customRef for a slot layout - */ - getSlotLayoutRef(slotId: SlotId): Ref { - let slotRef = this.slotRefs.get(slotId) - - if (!slotRef) { - logger.debug(`Creating new layout ref for slot ${slotId}`) - - slotRef = customRef((track, trigger) => { - // Store the trigger so we can call it when Yjs changes - this.slotTriggers.set(slotId, trigger) - - return { - get: () => { - track() - const yslot = this.yslots.get(slotId) - const layout = yslot ? this.ySlotToLayout(yslot) : null - logger.debug(`Layout ref GET for slot ${slotId}:`, { - position: layout?.position, - hasYslot: !!yslot, - version: this.version - }) - return layout - }, - set: (newLayout: SlotLayout | null) => { - if (newLayout === null) { - // Delete operation - const existing = this.yslots.get(slotId) - if (existing) { - this.applyOperation({ - type: 'deleteSlot', - slotId, - timestamp: Date.now(), - source: this.currentSource, - actor: this.currentActor, - previousLayout: this.ySlotToLayout(existing) - }) - } - } else { - // Update or create operation - const existing = this.yslots.get(slotId) - if (!existing) { - // Create operation - this.applyOperation({ - type: 'createSlot', - slotId, - layout: newLayout, - timestamp: Date.now(), - source: this.currentSource, - actor: this.currentActor - }) - } else { - const existingLayout = this.ySlotToLayout(existing) - // Update position if changed - if ( - existingLayout.position.x !== newLayout.position.x || - existingLayout.position.y !== newLayout.position.y - ) { - this.applyOperation({ - type: 'updateSlot', - slotId, - position: newLayout.position, - previousPosition: existingLayout.position, - timestamp: Date.now(), - source: this.currentSource, - actor: this.currentActor - }) - } - } - } - logger.debug(`Layout ref SET triggering for slot ${slotId}`) - trigger() - } - } - }) - - this.slotRefs.set(slotId, slotRef) - } - - return slotRef - } - - /** - * Get slots for a specific node (reactive) - */ - getNodeSlots(nodeId: NodeId): ComputedRef { - return computed(() => { - // Touch version for reactivity - void this.version - - const result: SlotLayout[] = [] - for (const [slotId] of this.yslots) { - const yslot = this.yslots.get(slotId) - if (yslot) { - const layout = this.ySlotToLayout(yslot) - if (layout && layout.nodeId === nodeId) { - result.push(layout) - } - } - } - // Sort by type and index - result.sort((a, b) => { - if (a.type !== b.type) { - return a.type === 'input' ? -1 : 1 - } - return a.index - b.index - }) - return result - }) - } - - /** - * Get all slots as a reactive map - */ - getAllSlots(): ComputedRef> { - return computed(() => { - // Touch version for reactivity - void this.version - - const result = new Map() - for (const [slotId] of this.yslots) { - const yslot = this.yslots.get(slotId) - if (yslot) { - const layout = this.ySlotToLayout(yslot) - if (layout) { - result.set(slotId, layout) - } - } - } - return result - }) - } - /** * Get current version for change detection */ @@ -448,54 +290,13 @@ class LayoutStoreImpl implements LayoutStore { return this.spatialIndex.query(bounds) } - /** - * Query slot at point (non-reactive for performance) - */ - querySlotAtPoint(point: Point): SlotId | null { - // First find the node at the point - const nodeId = this.queryNodeAtPoint(point) - if (!nodeId) return null - - // Then check slots for that node - for (const [slotId] of this.yslots) { - const yslot = this.yslots.get(slotId) - if (yslot) { - const slot = this.ySlotToLayout(yslot) - if (slot && slot.nodeId === nodeId) { - const ynode = this.ynodes.get(nodeId) - if (ynode) { - const node = this.yNodeToLayout(ynode) - // Convert slot relative position to absolute - const absoluteX = node.position.x + slot.position.x - const absoluteY = node.position.y + slot.position.y - // Check if point is within slot radius (typically 10-15 pixels) - const slotRadius = 15 - const dx = point.x - absoluteX - const dy = point.y - absoluteY - if (dx * dx + dy * dy <= slotRadius * slotRadius) { - return slotId - } - } - } - } - } - return null - } - /** * Apply a layout operation using Yjs transactions */ applyOperation(operation: LayoutOperation): void { - const entityId = - 'nodeId' in operation - ? operation.nodeId - : 'slotId' in operation - ? (operation as any).slotId - : 'unknown' - logger.debug(`applyOperation called:`, { type: operation.type, - entityId, + nodeId: operation.nodeId, operation }) @@ -544,21 +345,6 @@ class LayoutStoreImpl implements LayoutStore { case 'deleteNode': this.handleDeleteNode(operation as DeleteNodeOperation, change) break - case 'createSlot': - this.handleCreateSlot(operation as CreateSlotOperation, change) - break - case 'updateSlot': - this.handleUpdateSlot(operation as UpdateSlotOperation, change) - break - case 'deleteSlot': - this.handleDeleteSlot(operation as DeleteSlotOperation, change) - break - case 'batchUpdateSlots': - this.handleBatchUpdateSlots( - operation as BatchUpdateSlotsOperation, - change - ) - break } } @@ -762,87 +548,6 @@ class LayoutStoreImpl implements LayoutStore { change.nodeIds.push(operation.nodeId) } - // Slot operation handlers - private handleCreateSlot( - operation: CreateSlotOperation, - change: LayoutChange - ): void { - const yslot = this.layoutToYSlot(operation.layout) - this.yslots.set(operation.slotId, yslot) - - change.type = 'create' - // Track the affected node - change.nodeIds.push(operation.layout.nodeId) - } - - private handleUpdateSlot( - operation: UpdateSlotOperation, - change: LayoutChange - ): void { - const yslot = this.yslots.get(operation.slotId) - if (!yslot) { - logger.warn(`No yslot found for ${operation.slotId}`) - return - } - - logger.debug(`Updating slot ${operation.slotId}`, operation.position) - yslot.set('position', operation.position) - - // Track the affected node - const nodeId = yslot.get('nodeId') as string - if (nodeId) { - change.nodeIds.push(nodeId) - } - } - - private handleDeleteSlot( - operation: DeleteSlotOperation, - change: LayoutChange - ): void { - const yslot = this.yslots.get(operation.slotId) - if (!yslot) return - - // Track the affected node before deletion - const nodeId = yslot.get('nodeId') as string - - this.yslots.delete(operation.slotId) - this.slotRefs.delete(operation.slotId) - this.slotTriggers.delete(operation.slotId) - - change.type = 'delete' - if (nodeId) { - change.nodeIds.push(nodeId) - } - } - - private handleBatchUpdateSlots( - operation: BatchUpdateSlotsOperation, - change: LayoutChange - ): void { - // Delete all existing slots for this node - const slotsToDelete: string[] = [] - for (const [slotId] of this.yslots) { - const yslot = this.yslots.get(slotId) - if (yslot && yslot.get('nodeId') === operation.nodeId) { - slotsToDelete.push(slotId) - } - } - - slotsToDelete.forEach((slotId) => { - this.yslots.delete(slotId) - this.slotRefs.delete(slotId) - this.slotTriggers.delete(slotId) - }) - - // Add new slots - operation.slots.forEach((slotLayout) => { - const yslot = this.layoutToYSlot(slotLayout) - this.yslots.set(slotLayout.id, yslot) - }) - - change.nodeIds.push(operation.nodeId) - } - /** * Update node bounds helper */ @@ -882,26 +587,6 @@ class LayoutStoreImpl implements LayoutStore { } } - private layoutToYSlot(layout: SlotLayout): Y.Map { - const yslot = new Y.Map() - yslot.set('id', layout.id) - yslot.set('nodeId', layout.nodeId) - yslot.set('position', layout.position) - yslot.set('type', layout.type) - yslot.set('index', layout.index) - return yslot - } - - private ySlotToLayout(yslot: Y.Map): SlotLayout { - return { - id: yslot.get('id') as string, - nodeId: yslot.get('nodeId') as string, - position: yslot.get('position') as Point, - type: yslot.get('type') as 'input' | 'output', - index: yslot.get('index') as number - } - } - private notifyChange(change: LayoutChange): void { this.changeListeners.forEach((listener) => { try { diff --git a/src/types/layoutOperations.ts b/src/types/layoutOperations.ts index 2073d2320..23fe18158 100644 --- a/src/types/layoutOperations.ts +++ b/src/types/layoutOperations.ts @@ -8,13 +8,7 @@ * - Conflict resolution (CRDT) * - Debugging (actor, timestamp, source) */ -import type { - NodeId, - NodeLayout, - Point, - SlotId, - SlotLayout -} from './layoutTypes' +import type { NodeId, NodeLayout, Point } from './layoutTypes' /** * Base operation interface that all operations extend @@ -43,10 +37,6 @@ export type OperationType = | 'deleteNode' | 'setNodeVisibility' | 'batchUpdate' - | 'createSlot' - | 'updateSlot' - | 'deleteSlot' - | 'batchUpdateSlots' /** * Move node operation @@ -109,56 +99,6 @@ export interface BatchUpdateOperation extends BaseOperation { previousValues: Partial } -/** - * Base slot operation interface - */ -export interface BaseSlotOperation { - /** Unique operation ID for deduplication */ - id?: string - /** Timestamp for ordering operations */ - timestamp: number - /** Actor who performed the operation (for CRDT) */ - actor: string - /** Source system that initiated the operation */ - source: 'canvas' | 'vue' | 'external' - /** Slot this operation affects */ - slotId: SlotId -} - -/** - * Create slot operation - */ -export interface CreateSlotOperation extends BaseSlotOperation { - type: 'createSlot' - layout: SlotLayout -} - -/** - * Update slot position operation - */ -export interface UpdateSlotOperation extends BaseSlotOperation { - type: 'updateSlot' - position: Point - previousPosition: Point -} - -/** - * Delete slot operation - */ -export interface DeleteSlotOperation extends BaseSlotOperation { - type: 'deleteSlot' - previousLayout: SlotLayout -} - -/** - * Batch update slots operation for a node - */ -export interface BatchUpdateSlotsOperation extends BaseOperation { - type: 'batchUpdateSlots' - slots: SlotLayout[] - previousSlots: SlotLayout[] -} - /** * Union of all operation types */ @@ -170,10 +110,6 @@ export type LayoutOperation = | DeleteNodeOperation | SetNodeVisibilityOperation | BatchUpdateOperation - | CreateSlotOperation - | UpdateSlotOperation - | DeleteSlotOperation - | BatchUpdateSlotsOperation /** * Type guards for operations @@ -205,22 +141,6 @@ export const isDeleteNodeOperation = ( op: LayoutOperation ): op is DeleteNodeOperation => op.type === 'deleteNode' -export const isCreateSlotOperation = ( - op: LayoutOperation -): op is CreateSlotOperation => op.type === 'createSlot' - -export const isUpdateSlotOperation = ( - op: LayoutOperation -): op is UpdateSlotOperation => op.type === 'updateSlot' - -export const isDeleteSlotOperation = ( - op: LayoutOperation -): op is DeleteSlotOperation => op.type === 'deleteSlot' - -export const isBatchUpdateSlotsOperation = ( - op: LayoutOperation -): op is BatchUpdateSlotsOperation => op.type === 'batchUpdateSlots' - /** * Operation application interface */ diff --git a/src/types/layoutTypes.ts b/src/types/layoutTypes.ts index 3ed3bbc10..541874bb9 100644 --- a/src/types/layoutTypes.ts +++ b/src/types/layoutTypes.ts @@ -131,23 +131,15 @@ export interface LayoutChange { // Store interfaces export interface LayoutStore { - // Node accessors + // CustomRef accessors for shared write access getNodeLayoutRef(nodeId: NodeId): Ref getNodesInBounds(bounds: Bounds): ComputedRef getAllNodes(): ComputedRef> - - // Slot accessors - getSlotLayoutRef(slotId: SlotId): Ref - getNodeSlots(nodeId: NodeId): ComputedRef - getAllSlots(): ComputedRef> - - // Version tracking getVersion(): ComputedRef // Spatial queries (non-reactive) queryNodeAtPoint(point: Point): NodeId | null queryNodesInBounds(bounds: Bounds): NodeId[] - querySlotAtPoint(point: Point): SlotId | null // Direct mutation API (CRDT-ready) applyOperation(operation: LayoutOperation): void @@ -171,7 +163,6 @@ export interface LayoutStore { export type { LayoutOperation as AnyLayoutOperation, BaseOperation, - BaseSlotOperation, MoveNodeOperation, ResizeNodeOperation, SetNodeZIndexOperation, @@ -179,10 +170,6 @@ export type { DeleteNodeOperation, SetNodeVisibilityOperation, BatchUpdateOperation, - CreateSlotOperation, - UpdateSlotOperation, - DeleteSlotOperation, - BatchUpdateSlotsOperation, OperationType, OperationApplicator, OperationSerializer,