Skip to content

Commit b72d323

Browse files
jtydhr88christian-byrne
authored andcommitted
fix mask editor bug under vueNodes (#5953)
## Summary fix mask editor issues on vueNodes ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5953-fix-mask-editor-bug-under-vueNodes-2856d73d3650810aa8a2e1a94c4d97a6) by [Unito](https://www.unito.io)
1 parent 6a62322 commit b72d323

File tree

4 files changed

+46
-4
lines changed

4 files changed

+46
-4
lines changed

src/renderer/extensions/vueNodes/components/ImagePreview.vue

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<!-- Main Image -->
3333
<img
3434
v-else
35+
ref="currentImageEl"
3536
:src="currentImageUrl"
3637
:alt="imageAltText"
3738
class="block size-full object-contain"
@@ -118,6 +119,7 @@ import { computed, ref, watch } from 'vue'
118119
import { useI18n } from 'vue-i18n'
119120
120121
import { downloadFile } from '@/base/common/downloadUtil'
122+
import { app } from '@/scripts/app'
121123
import { useCommandStore } from '@/stores/commandStore'
122124
import { useNodeOutputStore } from '@/stores/imagePreviewStore'
123125
@@ -143,6 +145,8 @@ const actualDimensions = ref<string | null>(null)
143145
const imageError = ref(false)
144146
const isLoading = ref(false)
145147
148+
const currentImageEl = ref<HTMLImageElement>()
149+
146150
// Computed values
147151
const currentImageUrl = computed(() => props.imageUrls[currentIndex.value])
148152
const hasMultipleImages = computed(() => props.imageUrls.length > 1)
@@ -182,7 +186,18 @@ const handleImageError = () => {
182186
actualDimensions.value = null
183187
}
184188
189+
// In vueNodes mode, we need to set them manually before opening the mask editor.
190+
const setupNodeForMaskEditor = () => {
191+
if (!props.nodeId || !currentImageEl.value) return
192+
const node = app.rootGraph?.getNodeById(props.nodeId)
193+
if (!node) return
194+
node.imageIndex = currentIndex.value
195+
node.imgs = [currentImageEl.value]
196+
app.canvas?.select(node)
197+
}
198+
185199
const handleEditMask = () => {
200+
setupNodeForMaskEditor()
186201
void commandStore.execute('Comfy.MaskEditor.OpenMaskEditor')
187202
}
188203

src/scripts/app.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,11 +380,15 @@ export class ComfyApp {
380380
const paintedIndex = selectedIndex + 1
381381
const combinedIndex = selectedIndex + 2
382382

383+
// for vueNodes mode
384+
const images =
385+
node.images ?? useNodeOutputStore().getNodeOutputs(node)?.images
386+
383387
ComfyApp.clipspace = {
384388
widgets: widgets,
385389
imgs: imgs,
386390
original_imgs: orig_imgs,
387-
images: node.images,
391+
images: images,
388392
selectedIndex: selectedIndex,
389393
img_paste_mode: 'selected', // reset to default im_paste_mode state on copy action
390394
paintedIndex: paintedIndex,
@@ -411,7 +415,8 @@ export class ComfyApp {
411415
ComfyApp.clipspace.imgs[ComfyApp.clipspace.combinedIndex].src
412416
}
413417
if (ComfyApp.clipspace.imgs && node.imgs) {
414-
if (node.images && ComfyApp.clipspace.images) {
418+
// Update node.images even if it's initially undefined (vueNodes mode)
419+
if (ComfyApp.clipspace.images) {
415420
if (ComfyApp.clipspace['img_paste_mode'] == 'selected') {
416421
node.images = [
417422
ComfyApp.clipspace.images[ComfyApp.clipspace['selectedIndex']]
@@ -513,6 +518,8 @@ export class ComfyApp {
513518
}
514519

515520
app.graph.setDirtyCanvas(true)
521+
522+
useNodeOutputStore().updateNodeImages(node)
516523
}
517524
}
518525

src/stores/imagePreviewStore.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,26 @@ export const useNodeOutputStore = defineStore('nodeOutput', () => {
331331
nodeOutputs.value = outputs
332332
}
333333

334+
function updateNodeImages(node: LGraphNode) {
335+
if (!node.images?.length) return
336+
337+
const nodeLocatorId = nodeIdToNodeLocatorId(node.id)
338+
339+
if (nodeLocatorId) {
340+
const existingOutputs = app.nodeOutputs[nodeLocatorId]
341+
342+
if (existingOutputs) {
343+
const updatedOutputs = {
344+
...existingOutputs,
345+
images: node.images
346+
}
347+
348+
app.nodeOutputs[nodeLocatorId] = updatedOutputs
349+
nodeOutputs.value[nodeLocatorId] = updatedOutputs
350+
}
351+
}
352+
}
353+
334354
function resetAllOutputsAndPreviews() {
335355
app.nodeOutputs = {}
336356
nodeOutputs.value = {}
@@ -349,6 +369,7 @@ export const useNodeOutputStore = defineStore('nodeOutput', () => {
349369
setNodeOutputsByExecutionId,
350370
setNodePreviewsByExecutionId,
351371
setNodePreviewsByNodeId,
372+
updateNodeImages,
352373

353374
// Cleanup
354375
revokePreviewsByExecutionId,

tests-ui/tests/renderer/extensions/vueNodes/components/ImagePreview.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,8 @@ describe('ImagePreview', () => {
203203
await navigationDots[1].trigger('click')
204204
await nextTick()
205205

206-
// After clicking, component shows loading state (Skeleton), not img
206+
// After clicking, component shows loading state (Skeleton)
207207
expect(wrapper.find('skeleton-stub').exists()).toBe(true)
208-
expect(wrapper.find('img').exists()).toBe(false)
209208

210209
// Simulate image load event to clear loading state
211210
const component = wrapper.vm as any

0 commit comments

Comments
 (0)