fix: painter widget preserves mask reference across WidgetPainter remount

The painter's serializeValue closure captured hasStrokes and isDirty as
local variables that reset on every WidgetPainter.vue mount. After a
remount (e.g. NodeWidgets re-render driven by useProcessedWidgets, added
in #10966), serializeValue saw isCanvasEmpty()=true and returned '' even
when modelValue still held a valid mask reference from a workflow load
or a prior upload — backend then received an empty mask, and on cloud
this surfaced as ImageDownloadError.

Reorder the short-circuits so a non-dirty painter returns its existing
modelValue.value before the canvas-empty guard, and fall back to the
prior modelValue.value if the canvas element is no longer mounted.
This commit is contained in:
bymyself
2026-05-05 20:37:50 -07:00
parent e46667b33f
commit 1521e6956f
2 changed files with 6 additions and 7 deletions

View File

@@ -359,15 +359,14 @@ describe('usePainter', () => {
expect(result).toBe('')
})
it('returns empty string when canvas has no strokes even if modelValue is set', async () => {
it('returns existing modelValue when not dirty (regression: WidgetPainter remount must not blank a workflow-restored mask reference)', async () => {
const maskWidget = makeWidget('mask', '')
mockWidgets.push(maskWidget)
const { modelValue } = mountPainter()
modelValue.value = 'painter/existing.png [temp]'
mountPainter('test-node', 'painter/existing.png [temp]')
const result = await maskWidget.serializeValue!({} as LGraphNode, 0)
expect(result).toBe('')
expect(result).toBe('painter/existing.png [temp]')
})
})

View File

@@ -624,13 +624,13 @@ export function usePainter(nodeId: string, options: UsePainterOptions) {
}
async function serializeValue(): Promise<string> {
if (!isDirty.value) return modelValue.value
const el = canvasEl.value
if (!el) return ''
if (!el) return modelValue.value
if (isCanvasEmpty()) return ''
if (!isDirty.value) return modelValue.value
const blob = await new Promise<Blob | null>((resolve) =>
el.toBlob(resolve, 'image/png')
)