From c4e5fc8dbfcba331c7440967e11900025fa8c638 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Fri, 30 Jan 2026 16:49:57 -0800 Subject: [PATCH] fix: update reactive ref after merge in imagePreviewStore (#8479) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fix for COM-14110: Preview image does not display new outputs in vue-nodes. ## Problem The merge logic in `setOutputsByLocatorId` updated `app.nodeOutputs` but returned early without updating the reactive `nodeOutputs.value` ref. This caused Vue components to never receive merged output updates because only the non-reactive `app.nodeOutputs` was being updated. ## Solution Added `nodeOutputs.value[nodeLocatorId] = existingOutput` after the merge loop, before the return statement. ## Testing - Added 2 unit tests covering the merge behavior - All 4076 existing unit tests pass - Typechecks pass - Lint passes ## Notes - Related open PRs touching same files: #8143, #8366 - potential minor conflicts possible Fixes COM-14110 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8479-fix-update-reactive-ref-after-merge-in-imagePreviewStore-2f86d73d365081f1a145fa5a9782515f) by [Unito](https://www.unito.io) Co-authored-by: Amp --- src/stores/imagePreviewStore.test.ts | 60 +++++++++++++++++++++++++++- src/stores/imagePreviewStore.ts | 1 + 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/stores/imagePreviewStore.test.ts b/src/stores/imagePreviewStore.test.ts index 4b796e479..b9a4ce240 100644 --- a/src/stores/imagePreviewStore.test.ts +++ b/src/stores/imagePreviewStore.test.ts @@ -14,7 +14,9 @@ vi.mock('@/utils/litegraphUtil', () => ({ vi.mock('@/scripts/app', () => ({ app: { - getPreviewFormatParam: vi.fn(() => '&format=test_webp') + getPreviewFormatParam: vi.fn(() => '&format=test_webp'), + nodeOutputs: {} as Record, + nodePreviewImages: {} as Record } })) @@ -29,6 +31,62 @@ const createMockOutputs = ( images?: ExecutedWsMessage['output']['images'] ): ExecutedWsMessage['output'] => ({ images }) +vi.mock('@/stores/executionStore', () => ({ + useExecutionStore: vi.fn(() => ({ + executionIdToNodeLocatorId: vi.fn((id: string) => id) + })) +})) + +vi.mock('@/platform/workflow/management/stores/workflowStore', () => ({ + useWorkflowStore: vi.fn(() => ({ + nodeIdToNodeLocatorId: vi.fn((id: string | number) => String(id)), + nodeToNodeLocatorId: vi.fn((node: { id: number }) => String(node.id)) + })) +})) + +describe('imagePreviewStore setNodeOutputsByExecutionId with merge', () => { + beforeEach(() => { + setActivePinia(createTestingPinia({ stubActions: false })) + vi.clearAllMocks() + app.nodeOutputs = {} + app.nodePreviewImages = {} + }) + + it('should update reactive nodeOutputs.value when merging outputs', () => { + const store = useNodeOutputStore() + const executionId = '1' + + const initialOutput = createMockOutputs([{ filename: 'a.png' }]) + store.setNodeOutputsByExecutionId(executionId, initialOutput) + + expect(app.nodeOutputs[executionId]?.images).toHaveLength(1) + expect(store.nodeOutputs[executionId]?.images).toHaveLength(1) + + const newOutput = createMockOutputs([{ filename: 'b.png' }]) + store.setNodeOutputsByExecutionId(executionId, newOutput, { merge: true }) + + expect(app.nodeOutputs[executionId]?.images).toHaveLength(2) + expect(store.nodeOutputs[executionId]?.images).toHaveLength(2) + }) + + it('should assign to reactive ref after merge for Vue reactivity', () => { + const store = useNodeOutputStore() + const executionId = '1' + + const initialOutput = createMockOutputs([{ filename: 'a.png' }]) + store.setNodeOutputsByExecutionId(executionId, initialOutput) + + const newOutput = createMockOutputs([{ filename: 'b.png' }]) + + store.setNodeOutputsByExecutionId(executionId, newOutput, { merge: true }) + + expect(store.nodeOutputs[executionId]).toStrictEqual( + app.nodeOutputs[executionId] + ) + expect(store.nodeOutputs[executionId]?.images).toHaveLength(2) + }) +}) + describe('imagePreviewStore getPreviewParam', () => { beforeEach(() => { setActivePinia(createTestingPinia({ stubActions: false })) diff --git a/src/stores/imagePreviewStore.ts b/src/stores/imagePreviewStore.ts index db2c9abaa..d2aa2d4e0 100644 --- a/src/stores/imagePreviewStore.ts +++ b/src/stores/imagePreviewStore.ts @@ -148,6 +148,7 @@ export const useNodeOutputStore = defineStore('nodeOutput', () => { existingOutput[k] = newValue } } + nodeOutputs.value[nodeLocatorId] = existingOutput return } }