Prevent partial copy of custom widgets when performing linked promotion on subgraphs (#6079)

The `toConcrete` call creates a restricted view of a widget that extends
from `BaseWidget`. A copy of the widget created by `createCopyForNode`
will also inherit this restricted view. This creates two problems
- Some widget properties (like `displayValue`) have been judged unsafe
and are explicitly blacklisted from being copied
- The widget now extends from `BaseWidget`. This results in the widget
being processed differently in some logic, such as `#processWidgetClick`
- Because `LegacyWidget` provides an implementation for `onClick`, the
presence of click handlers can not be used to determine which should be
used.

As a proposed, minimal workaround. Widgets which do not already extend
from BaseWidget are no longer cloned through `createCopyForNode`.

Because this PR involves side-stepping properties which have been
explicitly blacklisted. I'd recommend waiting to merge/backport until
after the release of 1.28.7

Resolves Kosinkadink/ComfyUI-VideoHelperSuite#569

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6079-Prevent-partial-copy-of-custom-widgets-when-performing-linked-promotion-on-subgraphs-28d6d73d36508198950efd401186ddef)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
AustinMroz
2026-01-27 18:45:48 -08:00
committed by GitHub
parent e3bad033ed
commit 803062bccd

View File

@@ -28,8 +28,8 @@ import type {
} from '@/lib/litegraph/src/types/serialisation'
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
import type { UUID } from '@/lib/litegraph/src/utils/uuid'
import { BaseWidget } from '@/lib/litegraph/src/widgets/BaseWidget'
import { AssetWidget } from '@/lib/litegraph/src/widgets/AssetWidget'
import { toConcreteWidget } from '@/lib/litegraph/src/widgets/widgetMap'
import { ExecutableNodeDTO } from './ExecutableNodeDTO'
import type { ExecutableLGraphNode, ExecutionId } from './ExecutableNodeDTO'
@@ -331,9 +331,10 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
inputWidget: IWidgetLocator | undefined
) {
// Use the first matching widget
const promotedWidget = toConcreteWidget(widget, this).createCopyForNode(
this
)
const promotedWidget =
widget instanceof BaseWidget
? widget.createCopyForNode(this)
: { ...widget, node: this }
if (widget instanceof AssetWidget)
promotedWidget.options.nodeType ??= widget.node.type