[refactor] Remove parentSubgraphNode property from widgets (#1145)

This commit is contained in:
Christian Byrne
2025-07-21 11:26:03 -07:00
committed by GitHub
parent efdb8080ae
commit def6010d72
4 changed files with 4 additions and 55 deletions

View File

@@ -190,9 +190,6 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
// Use the first matching widget
const promotedWidget = toConcreteWidget(widget, this).createCopyForNode(this)
// Set parentSubgraphNode for all promoted widgets to track their origin
promotedWidget.parentSubgraphNode = this
Object.assign(promotedWidget, {
get name() {
return subgraphInput.name
@@ -332,7 +329,6 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
override onRemoved(): void {
// Clean up all promoted widgets
for (const widget of this.widgets) {
widget.parentSubgraphNode = undefined
this.subgraph.events.dispatch("widget-demoted", { widget, subgraphNode: this })
}

View File

@@ -1,7 +1,6 @@
import type { CanvasColour, Point, RequiredProps, Size } from "../interfaces"
import type { CanvasPointer, LGraphCanvas, LGraphNode } from "../litegraph"
import type { CanvasPointerEvent } from "./events"
import type { NodeLike } from "./NodeLike"
export interface IWidgetOptions<TValues = unknown[]> {
on?: string
@@ -202,14 +201,6 @@ export interface IBaseWidget<
tooltip?: string
/**
* Reference to the subgraph container node when this widget is promoted from a subgraph.
* This allows the widget to know which SubgraphNode it belongs to in the parent graph.
* @remarks This property is a runtime reference and should not be serialized.
* It will be undefined after deserialization and needs to be reconstructed.
*/
parentSubgraphNode?: NodeLike
// TODO: Confirm this format
callback?(
value: any,

View File

@@ -1,7 +1,6 @@
import type { Point } from "@/interfaces"
import type { CanvasPointer, LGraphCanvas, LGraphNode, Size } from "@/litegraph"
import type { CanvasPointerEvent } from "@/types/events"
import type { NodeLike } from "@/types/NodeLike"
import type { IBaseWidget } from "@/types/widgets"
import { drawTextInArea } from "@/draw"
@@ -57,12 +56,6 @@ export abstract class BaseWidget<TWidget extends IBaseWidget = IBaseWidget> impl
return this.#node
}
/**
* Reference to the subgraph container node when this widget is promoted from a subgraph.
* This allows the widget to know which SubgraphNode it belongs to in the parent graph.
*/
parentSubgraphNode?: NodeLike
linkedWidgets?: IBaseWidget[]
name: string
options: TWidget["options"]

View File

@@ -55,10 +55,9 @@ describe("SubgraphWidgetPromotion", () => {
expect(subgraphNode.widgets[0].name).toBe("value") // Uses subgraph input name
expect(subgraphNode.widgets[0].type).toBe("number")
expect(subgraphNode.widgets[0].value).toBe(42)
expect(subgraphNode.widgets[0].parentSubgraphNode).toBe(subgraphNode)
})
it("should set parentSubgraphNode for all promoted widget types", () => {
it("should promote all widget types", () => {
const subgraph = createTestSubgraph({
inputs: [
{ name: "numberInput", type: "number" },
@@ -83,13 +82,9 @@ describe("SubgraphWidgetPromotion", () => {
const subgraphNode = createTestSubgraphNode(subgraph)
// All widgets should be promoted with parentSubgraphNode set
// All widgets should be promoted
expect(subgraphNode.widgets).toHaveLength(3)
for (const widget of subgraphNode.widgets) {
expect(widget.parentSubgraphNode).toBe(subgraphNode)
}
// Check specific widget values
expect(subgraphNode.widgets[0].value).toBe(100)
expect(subgraphNode.widgets[1].value).toBe("test")
@@ -113,7 +108,6 @@ describe("SubgraphWidgetPromotion", () => {
const promotedEvents = eventCapture.getEventsByType("widget-promoted")
expect(promotedEvents).toHaveLength(1)
expect(promotedEvents[0].detail.widget).toBeDefined()
expect(promotedEvents[0].detail.widget.parentSubgraphNode).toBe(subgraphNode)
expect(promotedEvents[0].detail.subgraphNode).toBe(subgraphNode)
eventCapture.cleanup()
@@ -192,32 +186,26 @@ describe("SubgraphWidgetPromotion", () => {
expect(subgraphNode.widgets).toHaveLength(2)
expect(subgraphNode.widgets[0].name).toBe("input1")
expect(subgraphNode.widgets[0].value).toBe(10)
expect(subgraphNode.widgets[0].parentSubgraphNode).toBe(subgraphNode)
expect(subgraphNode.widgets[1].name).toBe("input2")
expect(subgraphNode.widgets[1].value).toBe("hello")
expect(subgraphNode.widgets[1].parentSubgraphNode).toBe(subgraphNode)
})
it("should clean up parentSubgraphNode on node removal", () => {
it("should fire widget-demoted events when node is removed", () => {
const subgraph = createTestSubgraph({
inputs: [{ name: "input", type: "number" }],
})
const { node } = createNodeWithWidget("Test Node")
const subgraphNode = setupPromotedWidget(subgraph, node)
const promotedWidget = subgraphNode.widgets[0]
expect(promotedWidget.parentSubgraphNode).toBe(subgraphNode)
expect(subgraphNode.widgets).toHaveLength(1)
const eventCapture = createEventCapture(subgraph.events, ["widget-demoted"])
// Remove the subgraph node
subgraphNode.onRemoved()
// parentSubgraphNode should be cleared
expect(promotedWidget.parentSubgraphNode).toBeUndefined()
// Should fire demoted events for all widgets
const demotedEvents = eventCapture.getEventsByType("widget-demoted")
expect(demotedEvents).toHaveLength(1)
@@ -225,25 +213,6 @@ describe("SubgraphWidgetPromotion", () => {
eventCapture.cleanup()
})
it("should handle DOM widgets with parentSubgraphNode", () => {
const subgraph = createTestSubgraph({
inputs: [{ name: "domInput", type: "custom" }],
})
const { node, widget } = createNodeWithWidget("DOM Node", "custom", "custom value", "custom")
// Make it a DOM widget
widget.element = document.createElement("div")
const subgraphNode = setupPromotedWidget(subgraph, node)
// DOM widget should be promoted with parentSubgraphNode
expect(subgraphNode.widgets).toHaveLength(1)
const promotedWidget = subgraphNode.widgets[0]
expect(promotedWidget.parentSubgraphNode).toBe(subgraphNode)
expect(promotedWidget.name).toBe("domInput")
})
it("should not promote widget if input is not connected", () => {
const subgraph = createTestSubgraph({
inputs: [{ name: "input", type: "number" }],