Compare commits

...

2 Commits

Author SHA1 Message Date
bymyself
4d19bd2f32 add browser test 2025-04-05 10:42:21 -07:00
bymyself
323db0e049 filter unserialized widgets values 2025-04-05 10:35:49 -07:00
3 changed files with 61 additions and 2 deletions

View File

@@ -192,3 +192,19 @@ test.describe('Load audio widget', () => {
await expect(comfyPage.canvas).toHaveScreenshot('load_audio_widget.png')
})
})
test.describe('Unserialized widgets', () => {
test('Unserialized widgets values do not mark graph as modified', async ({
comfyPage
}) => {
// Add workflow w/ LoadImage node, which contains file upload and image preview widgets (not serialized)
await comfyPage.loadWorkflow('widgets/load_image_widget')
// Move mouse and click to trigger the `graphEqual` check in `changeTracker.ts`
await comfyPage.page.mouse.move(10, 10)
await comfyPage.page.mouse.click(10, 10)
// Expect the graph to not be modified
expect(await comfyPage.isCurrentWorkflowModified()).toBe(false)
})
})

View File

@@ -8,6 +8,7 @@ import type { ExecutedWsMessage } from '@/schemas/apiSchema'
import type { ComfyWorkflowJSON } from '@/schemas/comfyWorkflowSchema'
import { useExecutionStore } from '@/stores/executionStore'
import { ComfyWorkflow, useWorkflowStore } from '@/stores/workflowStore'
import { filterSerializedWidgetValues } from '@/utils/litegraphUtil'
import { api } from './api'
import type { ComfyApp } from './app'
@@ -385,7 +386,10 @@ export class ChangeTracker {
if (
!_.isEqualWith(a.nodes, b.nodes, (arrA, arrB) => {
if (Array.isArray(arrA) && Array.isArray(arrB)) {
return _.isEqual(new Set(arrA), new Set(arrB))
// Filter non-serializable widget values before comparison
const filteredArrA = filterSerializedWidgetValues(arrA, app.graph)
const filteredArrB = filterSerializedWidgetValues(arrB, app.graph)
return _.isEqual(new Set(filteredArrA), new Set(filteredArrB))
}
})
) {

View File

@@ -1,8 +1,10 @@
import type { ColorOption } from '@comfyorg/litegraph'
import type { ColorOption, LGraph } from '@comfyorg/litegraph'
import { LGraphGroup, LGraphNode, isColorable } from '@comfyorg/litegraph'
import type { IComboWidget } from '@comfyorg/litegraph/dist/types/widgets'
import _ from 'lodash'
import type { ComfyNode } from '@/schemas/comfyWorkflowSchema'
type ImageNode = LGraphNode & { imgs: HTMLImageElement[] | undefined }
type VideoNode = LGraphNode & {
videoContainer: HTMLElement | undefined
@@ -70,3 +72,40 @@ export function executeWidgetsCallback(
}
}
}
/**
* Creates a copy of the nodes with non-serialized widget values removed
*/
export function filterSerializedWidgetValues(
nodes: ComfyNode[],
graph: LGraph
): ComfyNode[] {
if (!graph) return nodes
return nodes.map((node) => {
if (!node.widgets_values) return node
const graphNode = graph.getNodeById(node.id)
if (!graphNode?.widgets) return node
const filteredNode = { ...node }
const serializedValues = []
for (let i = 0; i < graphNode.widgets.length; i++) {
const widget = graphNode.widgets[i]
// Skip if widget is not serialized
if (!widget.options || widget.options.serialize !== false) {
const value = Array.isArray(node.widgets_values)
? node.widgets_values[i]
: node.widgets_values[widget.name || i.toString()]
serializedValues.push(
typeof value === 'object' && value !== null ? value.value : value
)
}
}
filteredNode.widgets_values = serializedValues
return filteredNode
})
}