Merge pull request #67 from StableLlama/fix_64

release 2.2.1; Fix dynamic node inputs lost when loading workflows from images/videos
This commit is contained in:
StableLlama
2026-11-03 23:42:19 +01:00
committed by GitHub
3 changed files with 41 additions and 2 deletions
+16
View File
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.2.1] - 2026-11-03
Fixed:
- Dynamic input nodes (e.g. "create DICT"): clearing a key/value pair could
leave the node with input names and widget names out of sync. The prompt was
then built from the stale widget names, so the container was created empty
and the connection was drawn next to the wrong row. Removed widgets are now
also removed from ComfyUI's widget value store, which keeps both in sync.
- Dynamic input nodes (e.g. "create DICT" and "create LIST") lost their extra
key/value pairs when the workflow was recreated by dragging a produced image
or video back into ComfyUI: the workflow that ComfyUI embeds into those files
drops unconnected widget inputs, and for these nodes that slot is what keeps
a pair alive, so the values ended up on the wrong rows and the container was
created with only its first entry. The dynamic inputs are now kept in that
embedded workflow, also for workflows that were saved before this fix.
## [2.2.0] - 2026-10-16
Added:
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "basic_data_handling"
version = "2.2.0"
version = "2.2.1"
description = """Basic Python functions for manipulating data that every programmer is used to, lightweight with no additional dependencies.
Supported data types:
+24 -1
View File
@@ -266,6 +266,11 @@ app.registerExtension({
if (isWidgetFlag) {
addStandardWidget.call(this, name, widgetGuiType, widgetDefaultVal, widgetConfOpts);
this.addInput(name, comfyInputType, { shape, widget: { name } });
// ComfyUI drops widget inputs that are not connected from the workflow it
// embeds into saved images/videos (compressWidgetInputSlots) unless the slot
// carries a label. For dynamic inputs the slot is what keeps the whole
// key/value pair alive, so label it with its own name to survive the round trip.
this.inputs[this.inputs.length - 1].label = name;
} else {
this.addInput(name, comfyInputType, { shape });
}
@@ -312,10 +317,12 @@ app.registerExtension({
const widget = this.widgets.find(w => w.name === widgetName);
if (widget) {
widget.name = newName;
if (widget.label) widget.label = newName;
}
if (inputRef.widget) inputRef.widget.name = newName;
}
inputRef.name = newName;
if (inputRef.label) inputRef.label = newName;
}
updateSlotIndices(this);
};
@@ -500,7 +507,7 @@ app.registerExtension({
this.setDirtyCanvas(true, true);
};
// --- Event Handlers (onConnectionsChange, onConnectInput, onRemoved, onWidgetChanged) ---
// --- Event Handlers (onConnectionsChange, onConnectInput, onConfigure, onRemoved, onWidgetChanged) ---
const onConnectionsChange = nodeType.prototype.onConnectionsChange;
nodeType.prototype.onConnectionsChange = function (type, slotIndex, isConnected, link, ioSlot) {
const originalReturn = onConnectionsChange?.apply(this, arguments);
@@ -532,6 +539,22 @@ app.registerExtension({
return result;
}
const onConfigure = nodeType.prototype.onConfigure;
nodeType.prototype.onConfigure = function () {
const originalReturn = onConfigure?.apply(this, arguments);
// Inputs restored from a workflow may not carry the label yet, e.g. when the
// workflow was saved before it was introduced. Without the label ComfyUI
// drops the slot again when the workflow is embedded into an image/video, so
// stamp it here for every dynamic widget input.
for (const input of this.inputs ?? []) {
if (!input.widget || input.label || !isDynamicInput(input.name)) continue;
input.label = input.name;
const widget = this.widgets?.find((w) => w.name === input.widget.name);
if (widget && !widget.label) widget.label = input.name;
}
return originalReturn;
};
const onRemoved = nodeType.prototype.onRemoved;
nodeType.prototype.onRemoved = function () {
if(!isProcessingConnection){