Track subgraph open history for breadcrumbs

This commit is contained in:
filtered
2025-05-14 15:42:45 +10:00
parent 6918aa830b
commit b65440e1c2
4 changed files with 91 additions and 18 deletions

View File

@@ -20,22 +20,24 @@ import type { MenuItem, MenuItemCommandEvent } from 'primevue/menuitem'
import { computed } from 'vue'
import { useCanvasStore } from '@/stores/graphStore'
import { useSubgraphNavigationStore } from '@/stores/subgraphNavigationStore'
import { useWorkflowStore } from '@/stores/workflowStore'
const workflowStore = useWorkflowStore()
const navigationStore = useSubgraphNavigationStore()
const workflowName = computed(() => workflowStore.activeWorkflow?.filename)
const items = computed(() => {
if (!workflowStore.subgraphNamePath.length) return []
if (!navigationStore.navigationStack.length) return []
return workflowStore.subgraphNamePath.map<MenuItem>((name, index) => ({
label: name,
return navigationStore.navigationStack.map<MenuItem>((subgraph) => ({
label: subgraph.name,
command: async () => {
const canvas = useCanvasStore().getCanvas()
if (!canvas.graph) throw new TypeError('Canvas has no graph')
canvas.setGraph(canvas.graph.pathToRootGraph[index + 1])
canvas.setGraph(subgraph)
}
}))
})

View File

@@ -0,0 +1,71 @@
import type { Subgraph } from '@comfyorg/litegraph'
import { defineStore } from 'pinia'
import { computed, shallowReactive, shallowRef, watch } from 'vue'
import { isNonNullish } from '@/utils/typeGuardUtil'
import { useCanvasStore } from './graphStore'
import { useWorkflowStore } from './workflowStore'
/**
* Stores the current subgraph navigation state; a stack representing subgraph
* navigation history from the root graph to the subgraph that is currently
* open.
*/
export const useSubgraphNavigationStore = defineStore(
'subgraphNavigation',
() => {
const workflowStore = useWorkflowStore()
const canvasStore = useCanvasStore()
/** The currently opened subgraph. */
const activeSubgraph = shallowRef<Subgraph>()
/** The stack of subgraph IDs from the root graph to the currently opened subgraph. */
const subgraphIdStack = shallowReactive<string[]>([])
/**
* A stack representing subgraph navigation history from the root graph to
* the current opened subgraph.
*/
const navigationStack = computed(() =>
subgraphIdStack
.map((id) => canvasStore.getCanvas().graph?.subgraphs.get(id))
.filter(isNonNullish)
)
// Reset on workflow change
watch(
() => workflowStore.activeWorkflow,
() => (subgraphIdStack.length = 0)
)
// Update navigation stack when opened subgraph changes
watch(
() => workflowStore.activeSubgraph,
(subgraph) => {
// Navigated back to the root graph
if (!subgraph) {
subgraphIdStack.length = 0
return
}
const index = subgraphIdStack.lastIndexOf(subgraph.id)
const lastIndex = subgraphIdStack.length - 1
if (index === -1) {
// Opened a new subgraph
subgraphIdStack.push(subgraph.id)
} else if (index !== lastIndex) {
// Navigated to a different subgraph
subgraphIdStack.splice(index + 1, lastIndex - index)
}
}
)
return {
activeSubgraph,
navigationStack
}
}
)

View File

@@ -1,6 +1,7 @@
import type { Subgraph } from '@comfyorg/litegraph'
import _ from 'lodash'
import { defineStore } from 'pinia'
import { computed, markRaw, ref, watch } from 'vue'
import { computed, markRaw, ref, shallowRef, watch } from 'vue'
import { ComfyWorkflowJSON } from '@/schemas/comfyWorkflowSchema'
import { api } from '@/scripts/api'
@@ -156,10 +157,9 @@ export interface WorkflowStore {
syncWorkflows: (dir?: string) => Promise<void>
reorderWorkflows: (from: number, to: number) => void
/** An ordered list of all parent subgraphs, ending with the current subgraph. */
subgraphNamePath: string[]
/** `true` if any subgraph is currently being viewed. */
isSubgraphActive: boolean
activeSubgraph: Subgraph | undefined
/** Updates the {@link subgraphNamePath} and {@link isSubgraphActive} values. */
updateActiveGraph: () => void
}
@@ -427,25 +427,19 @@ export const useWorkflowStore = defineStore('workflow', () => {
}
}
/** @see WorkflowStore.subgraphNamePath */
const subgraphNamePath = ref<string[]>([])
/** @see WorkflowStore.isSubgraphActive */
const isSubgraphActive = ref(false)
/** @see WorkflowStore.activeSubgraph */
const activeSubgraph = shallowRef<Subgraph>()
/** @see WorkflowStore.updateActiveGraph */
const updateActiveGraph = () => {
activeSubgraph.value = comfyApp.canvas?.subgraph
if (!comfyApp.canvas) return
const { subgraph } = comfyApp.canvas
isSubgraphActive.value = isSubgraph(subgraph)
if (subgraph) {
const [, ...pathFromRoot] = subgraph.pathToRootGraph
subgraphNamePath.value = pathFromRoot.map((subgraph) => subgraph.name)
} else {
subgraphNamePath.value = []
}
}
watch(activeWorkflow, updateActiveGraph)
@@ -473,8 +467,8 @@ export const useWorkflowStore = defineStore('workflow', () => {
getWorkflowByPath,
syncWorkflows,
subgraphNamePath,
isSubgraphActive,
activeSubgraph,
updateActiveGraph
}
}) satisfies () => WorkflowStore

View File

@@ -21,3 +21,9 @@ export const isAbortError = (
export const isSubgraph = (
item: LGraph | Subgraph | undefined | null
): item is Subgraph => item?.isRootGraph === false
/**
* Check if an item is non-nullish.
*/
export const isNonNullish = <T>(item: T | undefined | null): item is T =>
item != null