mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-14 17:37:46 +00:00
fix: emit layout change for batch node bounds (#5939)
## Summary Fixes issue where node size changes are not serialized by routing DOM-driven node bounds updates through a single CRDT operation so Vue node geometry stays synchronized with LiteGraph. ## Changes - **What**: Added `BatchUpdateBoundsOperation` to the layout store, applied it via the existing Yjs pipeline, notified link sync to recompute touched nodes, and covered the path with a regression test ## Review Focus Correctness of the new batch operation when multiple nodes update simultaneously, especially remote replay/undo scenarios and link geometry recomputation. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5939-fix-emit-layout-change-for-batch-node-bounds-2846d73d365081db8f8cca5bf7b85308) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
|
||||
import {
|
||||
@@ -165,10 +165,11 @@ describe('layoutStore CRDT operations', () => {
|
||||
actor: layoutStore.getCurrentActor()
|
||||
})
|
||||
|
||||
// Wait for async notification
|
||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||
// Wait for onChange callback to be called (uses setTimeout internally)
|
||||
await vi.waitFor(() => {
|
||||
expect(changes.length).toBeGreaterThanOrEqual(1)
|
||||
})
|
||||
|
||||
expect(changes.length).toBeGreaterThanOrEqual(1)
|
||||
const lastChange = changes[changes.length - 1]
|
||||
expect(lastChange.source).toBe('vue')
|
||||
expect(lastChange.operation.actor).toBe('user-123')
|
||||
@@ -176,6 +177,48 @@ describe('layoutStore CRDT operations', () => {
|
||||
unsubscribe()
|
||||
})
|
||||
|
||||
it('should emit change when batch updating node bounds', async () => {
|
||||
const nodeId = 'test-node-6'
|
||||
const layout = createTestNode(nodeId)
|
||||
|
||||
layoutStore.applyOperation({
|
||||
type: 'createNode',
|
||||
entity: 'node',
|
||||
nodeId,
|
||||
layout,
|
||||
timestamp: Date.now(),
|
||||
source: LayoutSource.External,
|
||||
actor: 'test'
|
||||
})
|
||||
|
||||
const changes: LayoutChange[] = []
|
||||
const unsubscribe = layoutStore.onChange((change) => {
|
||||
changes.push(change)
|
||||
})
|
||||
|
||||
const newBounds = { x: 40, y: 60, width: 220, height: 120 }
|
||||
layoutStore.batchUpdateNodeBounds([{ nodeId, bounds: newBounds }])
|
||||
|
||||
// Wait for onChange callback to be called (uses setTimeout internally)
|
||||
await vi.waitFor(() => {
|
||||
expect(changes.length).toBeGreaterThan(0)
|
||||
const lastChange = changes[changes.length - 1]
|
||||
expect(lastChange.operation.type).toBe('batchUpdateBounds')
|
||||
})
|
||||
|
||||
const lastChange = changes[changes.length - 1]
|
||||
if (lastChange.operation.type === 'batchUpdateBounds') {
|
||||
expect(lastChange.nodeIds).toContain(nodeId)
|
||||
expect(lastChange.operation.bounds[nodeId]?.bounds).toEqual(newBounds)
|
||||
}
|
||||
|
||||
const nodeRef = layoutStore.getNodeLayoutRef(nodeId)
|
||||
expect(nodeRef.value?.position).toEqual({ x: 40, y: 60 })
|
||||
expect(nodeRef.value?.size).toEqual({ width: 220, height: 120 })
|
||||
|
||||
unsubscribe()
|
||||
})
|
||||
|
||||
it('should query nodes by spatial bounds', () => {
|
||||
const nodes = [
|
||||
{ id: 'node-a', position: { x: 0, y: 0 } },
|
||||
|
||||
Reference in New Issue
Block a user