From 546c2cb4d4d2bedb974817c00adb56fae97dd355 Mon Sep 17 00:00:00 2001 From: DrJKL Date: Thu, 7 May 2026 22:36:01 -0700 Subject: [PATCH] refactor(subgraph): remove promotion store use Amp-Thread-ID: https://ampcode.com/threads/T-019e05c3-bed1-706a-a7a7-27733a6ab1e4 Co-authored-by: Amp --- .../parameters/SectionWidgets.vue | 8 +- .../parameters/TabSubgraphInputs.vue | 88 ++-- .../parameters/WidgetActions.vue | 33 +- .../subgraph/SubgraphEditor.vue | 91 ++-- .../node/usePromotedPreviews.test.ts | 86 +--- src/composables/node/usePromotedPreviews.ts | 25 +- .../migration/classifyProxyEntry.test.ts | 45 +- .../subgraph/migration/classifyProxyEntry.ts | 5 +- .../migration/migratePreviewExposure.test.ts | 28 ++ .../migration/migratePreviewExposure.ts | 9 + .../migration/repairValueWidget.test.ts | 47 +- .../subgraph/migration/repairValueWidget.ts | 10 +- .../graph/subgraph/promotionUtils.test.ts | 162 +++++-- src/core/graph/subgraph/promotionUtils.ts | 258 ++++++++--- src/lib/litegraph/src/LGraph.test.ts | 15 +- src/lib/litegraph/src/LGraph.ts | 84 +--- src/lib/litegraph/src/LiteGraphGlobal.ts | 1 - .../src/__snapshots__/litegraph.test.ts.snap | 1 - .../subgraph/SubgraphNode.serialize.test.ts | 27 ++ .../litegraph/src/subgraph/SubgraphNode.ts | 432 +----------------- src/lib/litegraph/src/widgets/BaseWidget.ts | 14 +- .../composables/useProcessedWidgets.test.ts | 29 +- .../composables/useProcessedWidgets.ts | 20 +- src/scripts/domWidget.test.ts | 42 +- src/scripts/domWidget.ts | 26 -- src/services/litegraphService.ts | 15 +- 26 files changed, 676 insertions(+), 925 deletions(-) diff --git a/src/components/rightSidePanel/parameters/SectionWidgets.vue b/src/components/rightSidePanel/parameters/SectionWidgets.vue index 4613346701..eb6c905e57 100644 --- a/src/components/rightSidePanel/parameters/SectionWidgets.vue +++ b/src/components/rightSidePanel/parameters/SectionWidgets.vue @@ -3,10 +3,10 @@ import { computed, inject, provide, ref, shallowRef, watchEffect } from 'vue' import { useI18n } from 'vue-i18n' import Button from '@/components/ui/button/Button.vue' +import { isWidgetPromotedOnSubgraphNode } from '@/core/graph/subgraph/promotionUtils' import { isPromotedWidgetView } from '@/core/graph/subgraph/promotedWidgetTypes' import type { LGraphGroup, LGraphNode } from '@/lib/litegraph/src/litegraph' import { SubgraphNode } from '@/lib/litegraph/src/litegraph' -import { usePromotionStore } from '@/stores/promotionStore' import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets' import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import { useExecutionErrorStore } from '@/stores/executionErrorStore' @@ -70,8 +70,6 @@ const { t } = useI18n() const getNodeParentGroup = inject(GetNodeParentGroupKey, null) -const promotionStore = usePromotionStore() - function isWidgetShownOnParents( widgetNode: LGraphNode, widget: IBaseWidget @@ -83,13 +81,13 @@ function isWidgetShownOnParents( ? widget.sourceNodeId : String(widgetNode.id) - return promotionStore.isPromoted(parent.rootGraph.id, parent.id, { + return isWidgetPromotedOnSubgraphNode(parent, { sourceNodeId: interiorNodeId, sourceWidgetName: widget.sourceWidgetName, disambiguatingSourceNodeId: widget.disambiguatingSourceNodeId }) } - return promotionStore.isPromoted(parent.rootGraph.id, parent.id, { + return isWidgetPromotedOnSubgraphNode(parent, { sourceNodeId: String(widgetNode.id), sourceWidgetName: widget.name }) diff --git a/src/components/rightSidePanel/parameters/TabSubgraphInputs.vue b/src/components/rightSidePanel/parameters/TabSubgraphInputs.vue index 8bce407ae0..03f4962e4d 100644 --- a/src/components/rightSidePanel/parameters/TabSubgraphInputs.vue +++ b/src/components/rightSidePanel/parameters/TabSubgraphInputs.vue @@ -14,13 +14,16 @@ import { import { useI18n } from 'vue-i18n' import { isPromotedWidgetView } from '@/core/graph/subgraph/promotedWidgetTypes' -import { getWidgetName } from '@/core/graph/subgraph/promotionUtils' +import { + getWidgetName, + isWidgetPromotedOnSubgraphNode +} from '@/core/graph/subgraph/promotionUtils' import type { SubgraphNode } from '@/lib/litegraph/src/subgraph/SubgraphNode' +import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets' import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import FormSearchInput from '@/renderer/extensions/vueNodes/widgets/components/form/FormSearchInput.vue' import CollapseToggleButton from '@/components/rightSidePanel/layout/CollapseToggleButton.vue' import { DraggableList } from '@/scripts/ui/draggableList' -import { usePromotionStore } from '@/stores/promotionStore' import { useRightSidePanelStore } from '@/stores/workspace/rightSidePanelStore' import { searchWidgets } from '../shared' @@ -33,7 +36,6 @@ const { node } = defineProps<{ const { t } = useI18n() const canvasStore = useCanvasStore() -const promotionStore = usePromotionStore() const rightSidePanelStore = useRightSidePanelStore() const { focusedSection, searchQuery } = storeToRefs(rightSidePanelStore) @@ -55,9 +57,32 @@ const draggableList = ref(undefined) const sectionWidgetsRef = useTemplateRef('sectionWidgetsRef') const advancedInputsSectionRef = useTemplateRef('advancedInputsSectionRef') -const promotionEntries = computed(() => - promotionStore.getPromotions(node.rootGraph.id, node.id) -) +function isSamePromotedWidget(a: IBaseWidget, b: IBaseWidget): boolean { + return ( + isPromotedWidgetView(a) && + isPromotedWidgetView(b) && + a.sourceNodeId === b.sourceNodeId && + a.sourceWidgetName === b.sourceWidgetName && + a.disambiguatingSourceNodeId === b.disambiguatingSourceNodeId + ) +} + +function getPromotedWidgets(): IBaseWidget[] { + const inputWidgets = node.inputs + .map((input) => input._widget) + .filter((widget): widget is IBaseWidget => + Boolean(widget && isPromotedWidgetView(widget)) + ) + const extraWidgets = (node.widgets ?? []).filter( + (widget) => + isPromotedWidgetView(widget) && + !inputWidgets.some((inputWidget) => + isSamePromotedWidget(inputWidget, widget) + ) + ) + + return [...inputWidgets, ...extraWidgets] +} watch( focusedSection, @@ -81,37 +106,7 @@ watch( ) const widgetsList = computed((): NodeWidgetsList => { - const entries = promotionEntries.value - const { widgets = [] } = node - - const result: NodeWidgetsList = [] - for (const { - sourceNodeId: entryNodeId, - sourceWidgetName, - disambiguatingSourceNodeId - } of entries) { - const widget = widgets.find((w) => { - if (isPromotedWidgetView(w)) { - if ( - String(w.sourceNodeId) !== entryNodeId || - w.sourceWidgetName !== sourceWidgetName - ) - return false - - if (!disambiguatingSourceNodeId) return true - - return ( - (w.disambiguatingSourceNodeId ?? w.sourceNodeId) === - disambiguatingSourceNodeId - ) - } - return w.name === sourceWidgetName - }) - if (widget) { - result.push({ node, widget }) - } - } - return result + return getPromotedWidgets().map((widget) => ({ node, widget })) }) const advancedInputsWidgets = computed((): NodeWidgetsList => { @@ -126,7 +121,7 @@ const advancedInputsWidgets = computed((): NodeWidgetsList => { return allInteriorWidgets.filter( ({ node: interiorNode, widget }) => - !promotionStore.isPromoted(node.rootGraph.id, node.id, { + !isWidgetPromotedOnSubgraphNode(node, { sourceNodeId: String(interiorNode.id), sourceWidgetName: getWidgetName(widget), disambiguatingSourceNodeId: isPromotedWidgetView(widget) @@ -190,12 +185,19 @@ function setDraggableState() { this.draggableItem as HTMLElement ) - promotionStore.movePromotion( - node.rootGraph.id, - node.id, - oldPosition, - newPosition + const subgraphInputs = node.subgraph.inputs + const hostInputs = node.inputs + + if ( + oldPosition >= subgraphInputs.length || + newPosition >= subgraphInputs.length ) + return + + const [input] = subgraphInputs.splice(oldPosition, 1) + if (input) subgraphInputs.splice(newPosition, 0, input) + const [nodeInput] = hostInputs.splice(oldPosition, 1) + if (nodeInput) hostInputs.splice(newPosition, 0, nodeInput) canvasStore.canvas?.setDirty(true, true) } } diff --git a/src/components/rightSidePanel/parameters/WidgetActions.vue b/src/components/rightSidePanel/parameters/WidgetActions.vue index 039065e4f0..f27654d7df 100644 --- a/src/components/rightSidePanel/parameters/WidgetActions.vue +++ b/src/components/rightSidePanel/parameters/WidgetActions.vue @@ -5,7 +5,6 @@ import { useI18n } from 'vue-i18n' import MoreButton from '@/components/button/MoreButton.vue' import Button from '@/components/ui/button/Button.vue' -import type { PromotedWidgetSource } from '@/core/graph/subgraph/promotedWidgetTypes' import { isPromotedWidgetView } from '@/core/graph/subgraph/promotedWidgetTypes' import { demoteWidget, @@ -17,7 +16,6 @@ import type { SubgraphNode } from '@/lib/litegraph/src/subgraph/SubgraphNode' import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets' import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import { useNodeDefStore } from '@/stores/nodeDefStore' -import { usePromotionStore } from '@/stores/promotionStore' import { useFavoritedWidgetsStore } from '@/stores/workspace/favoritedWidgetsStore' import { getWidgetDefaultValue, promptWidgetLabel } from '@/utils/widgetUtil' import type { WidgetValue } from '@/utils/widgetUtil' @@ -43,13 +41,17 @@ const label = defineModel('label', { required: true }) const canvasStore = useCanvasStore() const favoritedWidgetsStore = useFavoritedWidgetsStore() const nodeDefStore = useNodeDefStore() -const promotionStore = usePromotionStore() const { t } = useI18n() const hasParents = computed(() => parents?.length > 0) const isLinked = computed(() => { if (!node.isSubgraphNode() || !isPromotedWidgetView(widget)) return false - return isLinkedPromotion(node, widget.sourceNodeId, widget.sourceWidgetName) + return isLinkedPromotion( + node, + widget.sourceNodeId, + widget.sourceWidgetName, + widget.disambiguatingSourceNodeId + ) }) const canToggleVisibility = computed(() => hasParents.value && !isLinked.value) const favoriteNode = computed(() => @@ -82,16 +84,19 @@ function handleHideInput() { if (isPromotedWidgetView(widget)) { for (const parent of parents) { - const source: PromotedWidgetSource = { - sourceNodeId: - String(node.id) === String(parent.id) - ? widget.sourceNodeId - : String(node.id), - sourceWidgetName: widget.sourceWidgetName, - disambiguatingSourceNodeId: widget.disambiguatingSourceNodeId - } - promotionStore.demote(parent.rootGraph.id, parent.id, source) - parent.computeSize(parent.size) + const sourceNodeId = + String(node.id) === String(parent.id) + ? widget.sourceNodeId + : String(node.id) + demoteWidget( + { + id: sourceNodeId, + title: node.title, + type: node.type + }, + widget, + [parent] + ) } canvasStore.canvas?.setDirty(true, true) } else { diff --git a/src/components/rightSidePanel/subgraph/SubgraphEditor.vue b/src/components/rightSidePanel/subgraph/SubgraphEditor.vue index 47c3873c1c..6b45671698 100644 --- a/src/components/rightSidePanel/subgraph/SubgraphEditor.vue +++ b/src/components/rightSidePanel/subgraph/SubgraphEditor.vue @@ -1,7 +1,6 @@