refactor: move node.imgs sync from component to store

Move syncNodeImgs logic from ImagePreview.vue to imagePreviewStore.ts
for proper separation of concerns. Store handles backwards compatibility
sync when setting node outputs.
This commit is contained in:
bymyself
2025-12-12 22:09:14 -08:00
parent 9ffced4b30
commit 9a9b3f286b
3 changed files with 23 additions and 53 deletions

View File

@@ -125,7 +125,6 @@ import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { downloadFile } from '@/base/common/downloadUtil' import { downloadFile } from '@/base/common/downloadUtil'
import { app } from '@/scripts/app'
import { useCommandStore } from '@/stores/commandStore' import { useCommandStore } from '@/stores/commandStore'
import { useNodeOutputStore } from '@/stores/imagePreviewStore' import { useNodeOutputStore } from '@/stores/imagePreviewStore'
@@ -188,17 +187,6 @@ watch(
{ deep: true, immediate: true } { deep: true, immediate: true }
) )
/**
* Sync node.imgs for backwards compatibility with legacy systems (e.g., Copy Image).
*/
const syncNodeImgs = () => {
if (!props.nodeId || !currentImageEl.value) return
const node = app.rootGraph?.getNodeById(props.nodeId)
if (!node) return
node.imgs = [currentImageEl.value]
node.imageIndex = currentIndex.value
}
// Event handlers // Event handlers
const handleImageLoad = (event: Event) => { const handleImageLoad = (event: Event) => {
if (!event.target || !(event.target instanceof HTMLImageElement)) return if (!event.target || !(event.target instanceof HTMLImageElement)) return
@@ -209,7 +197,6 @@ const handleImageLoad = (event: Event) => {
if (img.naturalWidth && img.naturalHeight) { if (img.naturalWidth && img.naturalHeight) {
actualDimensions.value = `${img.naturalWidth} x ${img.naturalHeight}` actualDimensions.value = `${img.naturalWidth} x ${img.naturalHeight}`
} }
syncNodeImgs()
} }
const handleImageError = () => { const handleImageError = () => {

View File

@@ -37,7 +37,8 @@ interface SetOutputOptions {
} }
export const useNodeOutputStore = defineStore('nodeOutput', () => { export const useNodeOutputStore = defineStore('nodeOutput', () => {
const { nodeIdToNodeLocatorId, nodeToNodeLocatorId } = useWorkflowStore() const { nodeIdToNodeLocatorId, nodeToNodeLocatorId, nodeLocatorIdToNodeId } =
useWorkflowStore()
const { executionIdToNodeLocatorId } = useExecutionStore() const { executionIdToNodeLocatorId } = useExecutionStore()
const scheduledRevoke: Record<NodeLocatorId, { stop: () => void }> = {} const scheduledRevoke: Record<NodeLocatorId, { stop: () => void }> = {}
const latestOutput = ref<string[]>([]) const latestOutput = ref<string[]>([])
@@ -156,6 +157,26 @@ export const useNodeOutputStore = defineStore('nodeOutput', () => {
}) ?? [] }) ?? []
app.nodeOutputs[nodeLocatorId] = outputs app.nodeOutputs[nodeLocatorId] = outputs
nodeOutputs.value[nodeLocatorId] = outputs nodeOutputs.value[nodeLocatorId] = outputs
syncNodeImgs(nodeLocatorId, latestOutput.value)
}
/**
* Sync node.imgs for backwards compatibility with legacy systems (e.g., Copy Image).
*/
function syncNodeImgs(nodeLocatorId: NodeLocatorId, imageUrls: string[]) {
if (!imageUrls.length) return
const nodeId = nodeLocatorIdToNodeId(nodeLocatorId)
if (nodeId === null) return
const node = app.canvas?.graph?.getNodeById(nodeId)
if (!node) return
const img = new Image()
img.onload = () => {
node.imgs = [img]
node.imageIndex = 0
}
img.src = imageUrls[0]
} }
function setNodeOutputs( function setNodeOutputs(

View File

@@ -1,7 +1,7 @@
import { createTestingPinia } from '@pinia/testing' import { createTestingPinia } from '@pinia/testing'
import type { VueWrapper } from '@vue/test-utils' import type { VueWrapper } from '@vue/test-utils'
import { mount } from '@vue/test-utils' import { mount } from '@vue/test-utils'
import { beforeEach, describe, expect, it, vi } from 'vitest' import { describe, expect, it, vi } from 'vitest'
import { nextTick } from 'vue' import { nextTick } from 'vue'
import { createI18n } from 'vue-i18n' import { createI18n } from 'vue-i18n'
@@ -13,22 +13,6 @@ vi.mock('@/base/common/downloadUtil', () => ({
downloadFile: vi.fn() downloadFile: vi.fn()
})) }))
// Mock app for node.imgs sync tests
const mockNode: {
imgs?: HTMLImageElement[] | undefined
imageIndex?: number | null
} = {}
vi.mock('@/scripts/app', () => ({
app: {
rootGraph: {
getNodeById: vi.fn(() => mockNode)
},
canvas: {
select: vi.fn()
}
}
}))
const i18n = createI18n({ const i18n = createI18n({
legacy: false, legacy: false,
locale: 'en', locale: 'en',
@@ -60,11 +44,6 @@ describe('ImagePreview', () => {
} }
const wrapperRegistry = new Set<VueWrapper>() const wrapperRegistry = new Set<VueWrapper>()
beforeEach(() => {
delete mockNode.imgs
delete mockNode.imageIndex
})
const mountImagePreview = (props = {}) => { const mountImagePreview = (props = {}) => {
const wrapper = mount(ImagePreview, { const wrapper = mount(ImagePreview, {
props: { ...defaultProps, ...props }, props: { ...defaultProps, ...props },
@@ -329,21 +308,4 @@ describe('ImagePreview', () => {
expect(imgElement.exists()).toBe(true) expect(imgElement.exists()).toBe(true)
expect(imgElement.attributes('alt')).toBe('Node output 2') expect(imgElement.attributes('alt')).toBe('Node output 2')
}) })
it('syncs node.imgs on image load for legacy compatibility', async () => {
const wrapper = mountImagePreview({
imageUrls: [defaultProps.imageUrls[0]],
nodeId: 'test-node-123'
})
const img = wrapper.find('img')
expect(img.exists()).toBe(true)
await img.trigger('load')
await nextTick()
expect(mockNode.imgs).toHaveLength(1)
expect(mockNode.imgs?.[0]).toBe(img.element)
expect(mockNode.imageIndex).toBe(0)
})
}) })