mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-02 20:22:08 +00:00
feat: auto-resolve simple validation errors on widget change and slot connection (#9464)
## Summary Automatically clears transient validation errors (`value_bigger_than_max`, `value_smaller_than_min`, `value_not_in_list`, `required_input_missing`) when the user modifies a widget value or connects an input slot, so resolved errors don't linger in the error panel. Also clears missing model state when the user changes a combo widget value. ## Changes - **`useNodeErrorAutoResolve` composable**: watches widget changes and slot connections, clears matching errors via `executionErrorStore` - **`executionErrorStore`**: adds `clearSimpleNodeErrors` and `clearSimpleWidgetErrorIfValid` with granular per-slot error removal - **`executionErrorUtil`**: adds `isValueStillOutOfRange` to prevent premature clearing when a new value still violates the constraint - **`graphTraversalUtil`**: adds `getExecutionIdFromNodeData` for subgraph-aware execution ID resolution - **`GraphCanvas.vue`**: fixes subgraph error key lookup by using `getExecutionIdByNode` instead of raw `node.id` - **`NodeWidgets.vue`**: wires up the new composable to the widget layer - **`missingModelStore`**: adds `removeMissingModelByWidget` to clear missing model state on widget value change - **`useGraphNodeManager`**: registers composable per node - **Tests**: 126 new unit tests covering error clearing, range validation, and graph traversal edge cases ## Screenshots https://github.com/user-attachments/assets/515ea811-ff84-482a-a866-a17e5c779c39 https://github.com/user-attachments/assets/a2b30f02-4929-4537-952c-a0febe20f02e ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9464-feat-auto-resolve-simple-validation-errors-on-widget-change-and-slot-connection-31b6d73d3650816b8afdc34f4b40295a) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -388,6 +388,32 @@ describe('scanAllModelCandidates', () => {
|
||||
expect(result[0].isAssetSupported).toBe(true)
|
||||
expect(result[1].widgetName).toBe('vae_name')
|
||||
})
|
||||
|
||||
it('skips subgraph container nodes whose promoted widgets are already scanned via interior nodes', () => {
|
||||
const containerNode = {
|
||||
id: 65,
|
||||
type: 'abc-def-uuid',
|
||||
widgets: [makeComboWidget('ckpt_name', 'model.safetensors', [])],
|
||||
isSubgraphNode: () => true,
|
||||
_testExecutionId: '65'
|
||||
} as unknown as LGraphNode
|
||||
|
||||
const interiorNode = makeNode(
|
||||
42,
|
||||
'CheckpointLoaderSimple',
|
||||
[
|
||||
makeComboWidget('ckpt_name', 'model.safetensors', ['model.safetensors'])
|
||||
],
|
||||
'65:42'
|
||||
)
|
||||
|
||||
const graph = makeGraph([containerNode, interiorNode])
|
||||
const result = scanAllModelCandidates(graph, noAssetSupport)
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0].nodeId).toBe('65:42')
|
||||
expect(result[0].nodeType).toBe('CheckpointLoaderSimple')
|
||||
})
|
||||
})
|
||||
|
||||
function makeCandidate(
|
||||
|
||||
Reference in New Issue
Block a user