From c012e49d536a688dab0bf9bb9f70f2209e1be863 Mon Sep 17 00:00:00 2001 From: bymyself Date: Fri, 15 Aug 2025 12:55:37 -0700 Subject: [PATCH] fix: improve minimap subgraph navigation with graph UUID callback tracking - Replace single callback storage with Map using graph UUIDs as keys - Fix minimap not updating when navigating between subgraphs - Add proper cleanup and error handling for callback management - Switch from app.canvas.graph to reactive workflowStore.activeSubgraph - Prevent callback wrapping recursion by tracking setup state per graph --- src/composables/useMinimap.ts | 53 +++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/src/composables/useMinimap.ts b/src/composables/useMinimap.ts index 499d068b8e..2aa3c124fe 100644 --- a/src/composables/useMinimap.ts +++ b/src/composables/useMinimap.ts @@ -5,9 +5,9 @@ import { useCanvasTransformSync } from '@/composables/canvas/useCanvasTransformS import { LGraphEventMode, LGraphNode } from '@/lib/litegraph/src/litegraph' import type { NodeId } from '@/schemas/comfyWorkflowSchema' import { api } from '@/scripts/api' -import { app } from '@/scripts/app' import { useCanvasStore } from '@/stores/graphStore' import { useSettingStore } from '@/stores/settingStore' +import { useWorkflowStore } from '@/stores/workflowStore' import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore' import { adjustColor } from '@/utils/colorUtil' @@ -27,6 +27,7 @@ export type MinimapOptionKey = export function useMinimap() { const settingStore = useSettingStore() const canvasStore = useCanvasStore() + const workflowStore = useWorkflowStore() const colorPaletteStore = useColorPaletteStore() const containerRef = ref() @@ -147,7 +148,11 @@ export function useMinimap() { } const canvas = computed(() => canvasStore.canvas) - const graph = ref(app.canvas?.graph) + const graph = computed(() => { + // If we're in a subgraph, use that; otherwise use the canvas graph + const activeSubgraph = workflowStore.activeSubgraph + return activeSubgraph || canvas.value?.graph + }) const containerStyles = computed(() => ({ width: `${width}px`, @@ -627,7 +632,8 @@ export function useMinimap() { c.setDirty(true, true) } - let originalCallbacks: GraphCallbacks = {} + // Map to store original callbacks per graph ID + const originalCallbacksMap = new Map() const handleGraphChanged = useThrottleFn(() => { needsFullRedraw.value = true @@ -641,11 +647,18 @@ export function useMinimap() { const g = graph.value if (!g) return - originalCallbacks = { + // Check if we've already wrapped this graph's callbacks + if (originalCallbacksMap.has(g.id)) { + return + } + + // Store the original callbacks for this graph + const originalCallbacks: GraphCallbacks = { onNodeAdded: g.onNodeAdded, onNodeRemoved: g.onNodeRemoved, onConnectionChange: g.onConnectionChange } + originalCallbacksMap.set(g.id, originalCallbacks) g.onNodeAdded = function (node) { originalCallbacks.onNodeAdded?.call(this, node) @@ -670,15 +683,18 @@ export function useMinimap() { const g = graph.value if (!g) return - if (originalCallbacks.onNodeAdded !== undefined) { - g.onNodeAdded = originalCallbacks.onNodeAdded - } - if (originalCallbacks.onNodeRemoved !== undefined) { - g.onNodeRemoved = originalCallbacks.onNodeRemoved - } - if (originalCallbacks.onConnectionChange !== undefined) { - g.onConnectionChange = originalCallbacks.onConnectionChange + const originalCallbacks = originalCallbacksMap.get(g.id) + if (!originalCallbacks) { + throw new Error( + 'Attempted to cleanup event listeners for graph that was never set up' + ) } + + g.onNodeAdded = originalCallbacks.onNodeAdded + g.onNodeRemoved = originalCallbacks.onNodeRemoved + g.onConnectionChange = originalCallbacks.onConnectionChange + + originalCallbacksMap.delete(g.id) } const init = async () => { @@ -751,6 +767,19 @@ export function useMinimap() { { immediate: true, flush: 'post' } ) + // Watch for graph changes (e.g., when navigating to/from subgraphs) + watch(graph, (newGraph, oldGraph) => { + if (newGraph && newGraph !== oldGraph) { + cleanupEventListeners() + setupEventListeners() + needsFullRedraw.value = true + updateFlags.value.bounds = true + updateFlags.value.nodes = true + updateFlags.value.connections = true + updateMinimap() + } + }) + watch(visible, async (isVisible) => { if (isVisible) { if (containerRef.value) {