mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 02:32:18 +00:00
Track subgraph open history for breadcrumbs
This commit is contained in:
@@ -20,22 +20,24 @@ import type { MenuItem, MenuItemCommandEvent } from 'primevue/menuitem'
|
|||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import { useCanvasStore } from '@/stores/graphStore'
|
import { useCanvasStore } from '@/stores/graphStore'
|
||||||
|
import { useSubgraphNavigationStore } from '@/stores/subgraphNavigationStore'
|
||||||
import { useWorkflowStore } from '@/stores/workflowStore'
|
import { useWorkflowStore } from '@/stores/workflowStore'
|
||||||
|
|
||||||
const workflowStore = useWorkflowStore()
|
const workflowStore = useWorkflowStore()
|
||||||
|
const navigationStore = useSubgraphNavigationStore()
|
||||||
|
|
||||||
const workflowName = computed(() => workflowStore.activeWorkflow?.filename)
|
const workflowName = computed(() => workflowStore.activeWorkflow?.filename)
|
||||||
|
|
||||||
const items = computed(() => {
|
const items = computed(() => {
|
||||||
if (!workflowStore.subgraphNamePath.length) return []
|
if (!navigationStore.navigationStack.length) return []
|
||||||
|
|
||||||
return workflowStore.subgraphNamePath.map<MenuItem>((name, index) => ({
|
return navigationStore.navigationStack.map<MenuItem>((subgraph) => ({
|
||||||
label: name,
|
label: subgraph.name,
|
||||||
command: async () => {
|
command: async () => {
|
||||||
const canvas = useCanvasStore().getCanvas()
|
const canvas = useCanvasStore().getCanvas()
|
||||||
if (!canvas.graph) throw new TypeError('Canvas has no graph')
|
if (!canvas.graph) throw new TypeError('Canvas has no graph')
|
||||||
|
|
||||||
canvas.setGraph(canvas.graph.pathToRootGraph[index + 1])
|
canvas.setGraph(subgraph)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|||||||
71
src/stores/subgraphNavigationStore.ts
Normal file
71
src/stores/subgraphNavigationStore.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import type { Subgraph } from '@comfyorg/litegraph'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { defineStore } from 'pinia'
|
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 { ComfyWorkflowJSON } from '@/schemas/comfyWorkflowSchema'
|
||||||
import { api } from '@/scripts/api'
|
import { api } from '@/scripts/api'
|
||||||
@@ -156,10 +157,9 @@ export interface WorkflowStore {
|
|||||||
syncWorkflows: (dir?: string) => Promise<void>
|
syncWorkflows: (dir?: string) => Promise<void>
|
||||||
reorderWorkflows: (from: number, to: number) => 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. */
|
/** `true` if any subgraph is currently being viewed. */
|
||||||
isSubgraphActive: boolean
|
isSubgraphActive: boolean
|
||||||
|
activeSubgraph: Subgraph | undefined
|
||||||
/** Updates the {@link subgraphNamePath} and {@link isSubgraphActive} values. */
|
/** Updates the {@link subgraphNamePath} and {@link isSubgraphActive} values. */
|
||||||
updateActiveGraph: () => void
|
updateActiveGraph: () => void
|
||||||
}
|
}
|
||||||
@@ -427,25 +427,19 @@ export const useWorkflowStore = defineStore('workflow', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see WorkflowStore.subgraphNamePath */
|
|
||||||
const subgraphNamePath = ref<string[]>([])
|
|
||||||
/** @see WorkflowStore.isSubgraphActive */
|
/** @see WorkflowStore.isSubgraphActive */
|
||||||
const isSubgraphActive = ref(false)
|
const isSubgraphActive = ref(false)
|
||||||
|
|
||||||
|
/** @see WorkflowStore.activeSubgraph */
|
||||||
|
const activeSubgraph = shallowRef<Subgraph>()
|
||||||
|
|
||||||
/** @see WorkflowStore.updateActiveGraph */
|
/** @see WorkflowStore.updateActiveGraph */
|
||||||
const updateActiveGraph = () => {
|
const updateActiveGraph = () => {
|
||||||
|
activeSubgraph.value = comfyApp.canvas?.subgraph
|
||||||
if (!comfyApp.canvas) return
|
if (!comfyApp.canvas) return
|
||||||
|
|
||||||
const { subgraph } = comfyApp.canvas
|
const { subgraph } = comfyApp.canvas
|
||||||
isSubgraphActive.value = isSubgraph(subgraph)
|
isSubgraphActive.value = isSubgraph(subgraph)
|
||||||
|
|
||||||
if (subgraph) {
|
|
||||||
const [, ...pathFromRoot] = subgraph.pathToRootGraph
|
|
||||||
|
|
||||||
subgraphNamePath.value = pathFromRoot.map((subgraph) => subgraph.name)
|
|
||||||
} else {
|
|
||||||
subgraphNamePath.value = []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(activeWorkflow, updateActiveGraph)
|
watch(activeWorkflow, updateActiveGraph)
|
||||||
@@ -473,8 +467,8 @@ export const useWorkflowStore = defineStore('workflow', () => {
|
|||||||
getWorkflowByPath,
|
getWorkflowByPath,
|
||||||
syncWorkflows,
|
syncWorkflows,
|
||||||
|
|
||||||
subgraphNamePath,
|
|
||||||
isSubgraphActive,
|
isSubgraphActive,
|
||||||
|
activeSubgraph,
|
||||||
updateActiveGraph
|
updateActiveGraph
|
||||||
}
|
}
|
||||||
}) satisfies () => WorkflowStore
|
}) satisfies () => WorkflowStore
|
||||||
|
|||||||
@@ -21,3 +21,9 @@ export const isAbortError = (
|
|||||||
export const isSubgraph = (
|
export const isSubgraph = (
|
||||||
item: LGraph | Subgraph | undefined | null
|
item: LGraph | Subgraph | undefined | null
|
||||||
): item is Subgraph => item?.isRootGraph === false
|
): 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
|
||||||
|
|||||||
Reference in New Issue
Block a user