mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-23 06:10:32 +00:00
fix(subgraph): trust persisted previewExposures, stop re-auto-exposing on load
Auto-exposed previews would reappear after reload even when the user had explicitly hidden them. The host's `properties.previewExposures` already captures user intent, but `LGraph.configure` was unconditionally running `autoExposeKnownPreviewNodes` after hydration, second-guessing the serialized state. - Gate `autoExposeKnownPreviewNodes` on `properties.previewExposures` being undefined. A node that has never been saved (or comes from a pre-PR workflow with no `previewExposures` property) still gets the convenience auto-expose pass; once the property exists in any form, including an empty array, the serialized state is authoritative. - Always serialize `previewExposures` (including as `[]` when empty) so "user cleared everything" is distinguishable from "never touched". Amp-Thread-ID: https://ampcode.com/threads/T-019e4671-bc67-7039-b6c6-9f5b11a07e42 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -28,6 +28,7 @@ vi.mock('@/services/litegraphService', () => ({
|
||||
|
||||
import {
|
||||
CANVAS_IMAGE_PREVIEW_WIDGET,
|
||||
autoExposeKnownPreviewNodes,
|
||||
demoteWidget,
|
||||
getPromotableWidgets,
|
||||
hasUnpromotedWidgets,
|
||||
@@ -341,6 +342,74 @@ describe('promoteRecommendedWidgets', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('autoExposeKnownPreviewNodes', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
updatePreviewsMock.mockReset()
|
||||
})
|
||||
|
||||
it('auto-exposes previews when host has no persisted previewExposures property', () => {
|
||||
const subgraph = createTestSubgraph()
|
||||
const subgraphNode = createTestSubgraphNode(subgraph)
|
||||
const glslNode = new LGraphNode('GLSLShader')
|
||||
glslNode.type = 'GLSLShader'
|
||||
subgraph.add(glslNode)
|
||||
|
||||
autoExposeKnownPreviewNodes(subgraphNode)
|
||||
|
||||
expect(
|
||||
usePreviewExposureStore().getExposures(
|
||||
subgraphNode.rootGraph.id,
|
||||
String(subgraphNode.id)
|
||||
)
|
||||
).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('does not auto-expose when host has empty persisted previewExposures (user cleared)', () => {
|
||||
const subgraph = createTestSubgraph()
|
||||
const subgraphNode = createTestSubgraphNode(subgraph)
|
||||
subgraphNode.properties.previewExposures = []
|
||||
const glslNode = new LGraphNode('GLSLShader')
|
||||
glslNode.type = 'GLSLShader'
|
||||
subgraph.add(glslNode)
|
||||
|
||||
autoExposeKnownPreviewNodes(subgraphNode)
|
||||
|
||||
expect(
|
||||
usePreviewExposureStore().getExposures(
|
||||
subgraphNode.rootGraph.id,
|
||||
String(subgraphNode.id)
|
||||
)
|
||||
).toEqual([])
|
||||
})
|
||||
|
||||
it('does not auto-expose when host has non-empty persisted previewExposures', () => {
|
||||
const subgraph = createTestSubgraph()
|
||||
const subgraphNode = createTestSubgraphNode(subgraph)
|
||||
const glslNode = new LGraphNode('GLSLShader')
|
||||
glslNode.type = 'GLSLShader'
|
||||
subgraph.add(glslNode)
|
||||
const otherNode = new LGraphNode('OtherShader')
|
||||
otherNode.type = 'GLSLShader'
|
||||
subgraph.add(otherNode)
|
||||
subgraphNode.properties.previewExposures = [
|
||||
{
|
||||
name: CANVAS_IMAGE_PREVIEW_WIDGET,
|
||||
sourceNodeId: String(otherNode.id),
|
||||
sourcePreviewName: CANVAS_IMAGE_PREVIEW_WIDGET
|
||||
}
|
||||
]
|
||||
|
||||
autoExposeKnownPreviewNodes(subgraphNode)
|
||||
|
||||
expect(
|
||||
usePreviewExposureStore()
|
||||
.getExposures(subgraphNode.rootGraph.id, String(subgraphNode.id))
|
||||
.map((e) => e.sourceNodeId)
|
||||
).not.toContain(String(glslNode.id))
|
||||
})
|
||||
})
|
||||
|
||||
describe('hasUnpromotedWidgets', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
|
||||
@@ -470,6 +470,7 @@ function nodeWidgets(n: LGraphNode): WidgetItem[] {
|
||||
}
|
||||
|
||||
export function autoExposeKnownPreviewNodes(subgraphNode: SubgraphNode): void {
|
||||
if (subgraphNode.properties.previewExposures !== undefined) return
|
||||
const { updatePreviews } = useLitegraphService()
|
||||
const interiorNodes = subgraphNode.subgraph.nodes
|
||||
for (const node of interiorNodes) {
|
||||
|
||||
@@ -1031,13 +1031,9 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
|
||||
rootGraphId,
|
||||
hostLocator
|
||||
)
|
||||
if (previewExposures.length > 0) {
|
||||
serializedProperties.previewExposures = previewExposures.map((entry) => ({
|
||||
...entry
|
||||
}))
|
||||
} else {
|
||||
delete serializedProperties.previewExposures
|
||||
}
|
||||
serializedProperties.previewExposures = previewExposures.map((entry) => ({
|
||||
...entry
|
||||
}))
|
||||
|
||||
const quarantine = parseProxyWidgetErrorQuarantine(
|
||||
this.properties.proxyWidgetErrorQuarantine
|
||||
|
||||
@@ -1175,12 +1175,12 @@ describe('SubgraphWidgetPromotion', () => {
|
||||
expected: [named12, named14]
|
||||
},
|
||||
{
|
||||
name: 'omits previewExposures when the store has no entries for the host',
|
||||
name: 'writes empty previewExposures when the store has no entries for the host',
|
||||
addExposures: [],
|
||||
staleProperty: [
|
||||
{ name: 'stale', sourceNodeId: '0', sourcePreviewName: CANVAS }
|
||||
],
|
||||
expected: undefined,
|
||||
expected: [],
|
||||
expectLiveUnchanged: true
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user