mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 11:11:53 +00:00
[feat] sync subgraph node titles with breadcrumb renaming (#4565)
This commit is contained in:
@@ -42,6 +42,7 @@ import { useOverflowObserver } from '@/composables/element/useOverflowObserver'
|
|||||||
import { useCanvasStore } from '@/stores/graphStore'
|
import { useCanvasStore } from '@/stores/graphStore'
|
||||||
import { useSubgraphNavigationStore } from '@/stores/subgraphNavigationStore'
|
import { useSubgraphNavigationStore } from '@/stores/subgraphNavigationStore'
|
||||||
import { useWorkflowStore } from '@/stores/workflowStore'
|
import { useWorkflowStore } from '@/stores/workflowStore'
|
||||||
|
import { forEachSubgraphNode } from '@/utils/graphTraversalUtil'
|
||||||
|
|
||||||
const MIN_WIDTH = 28
|
const MIN_WIDTH = 28
|
||||||
const ITEM_GAP = 8
|
const ITEM_GAP = 8
|
||||||
@@ -71,6 +72,14 @@ const items = computed(() => {
|
|||||||
if (!canvas.graph) throw new TypeError('Canvas has no graph')
|
if (!canvas.graph) throw new TypeError('Canvas has no graph')
|
||||||
|
|
||||||
canvas.setGraph(subgraph)
|
canvas.setGraph(subgraph)
|
||||||
|
},
|
||||||
|
updateTitle: (title: string) => {
|
||||||
|
const rootGraph = useCanvasStore().getCanvas().graph?.rootGraph
|
||||||
|
if (!rootGraph) return
|
||||||
|
|
||||||
|
forEachSubgraphNode(rootGraph, subgraph.id, (node) => {
|
||||||
|
node.title = title
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ const rename = async (
|
|||||||
initialName: string
|
initialName: string
|
||||||
) => {
|
) => {
|
||||||
if (newName && newName !== initialName) {
|
if (newName && newName !== initialName) {
|
||||||
|
// Synchronize the node titles with the new name
|
||||||
|
props.item.updateTitle?.(newName)
|
||||||
|
|
||||||
if (workflowStore.activeSubgraph) {
|
if (workflowStore.activeSubgraph) {
|
||||||
workflowStore.activeSubgraph.name = newName
|
workflowStore.activeSubgraph.name = newName
|
||||||
} else if (workflowStore.activeWorkflow) {
|
} else if (workflowStore.activeWorkflow) {
|
||||||
|
|||||||
@@ -86,13 +86,7 @@ export function triggerCallbackOnAllNodes(
|
|||||||
graph: LGraph | Subgraph,
|
graph: LGraph | Subgraph,
|
||||||
callbackProperty: keyof LGraphNode
|
callbackProperty: keyof LGraphNode
|
||||||
): void {
|
): void {
|
||||||
visitGraphNodes(graph, (node) => {
|
forEachNode(graph, (node) => {
|
||||||
// Recursively process subgraphs first
|
|
||||||
if (node.isSubgraphNode?.() && node.subgraph) {
|
|
||||||
triggerCallbackOnAllNodes(node.subgraph, callbackProperty)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke callback if it exists on the node
|
|
||||||
const callback = node[callbackProperty]
|
const callback = node[callbackProperty]
|
||||||
if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
callback.call(node)
|
callback.call(node)
|
||||||
@@ -100,6 +94,58 @@ export function triggerCallbackOnAllNodes(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a function over all nodes in a graph hierarchy (including subgraphs).
|
||||||
|
* This is a pure functional traversal that doesn't mutate the graph.
|
||||||
|
*
|
||||||
|
* @param graph - The root graph to traverse
|
||||||
|
* @param mapFn - Function to apply to each node
|
||||||
|
* @returns Array of mapped results (excluding undefined values)
|
||||||
|
*/
|
||||||
|
export function mapAllNodes<T>(
|
||||||
|
graph: LGraph | Subgraph,
|
||||||
|
mapFn: (node: LGraphNode) => T | undefined
|
||||||
|
): T[] {
|
||||||
|
const results: T[] = []
|
||||||
|
|
||||||
|
visitGraphNodes(graph, (node) => {
|
||||||
|
// Recursively map over subgraphs first
|
||||||
|
if (node.isSubgraphNode?.() && node.subgraph) {
|
||||||
|
results.push(...mapAllNodes(node.subgraph, mapFn))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply map function to current node
|
||||||
|
const result = mapFn(node)
|
||||||
|
if (result !== undefined) {
|
||||||
|
results.push(result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a side-effect function on all nodes in a graph hierarchy.
|
||||||
|
* This is for operations that modify nodes or perform side effects.
|
||||||
|
*
|
||||||
|
* @param graph - The root graph to traverse
|
||||||
|
* @param fn - Function to execute on each node
|
||||||
|
*/
|
||||||
|
export function forEachNode(
|
||||||
|
graph: LGraph | Subgraph,
|
||||||
|
fn: (node: LGraphNode) => void
|
||||||
|
): void {
|
||||||
|
visitGraphNodes(graph, (node) => {
|
||||||
|
// Recursively process subgraphs first
|
||||||
|
if (node.isSubgraphNode?.() && node.subgraph) {
|
||||||
|
forEachNode(node.subgraph, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute function on current node
|
||||||
|
fn(node)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collects all nodes in a graph hierarchy (including subgraphs) into a flat array.
|
* Collects all nodes in a graph hierarchy (including subgraphs) into a flat array.
|
||||||
*
|
*
|
||||||
@@ -111,21 +157,12 @@ export function collectAllNodes(
|
|||||||
graph: LGraph | Subgraph,
|
graph: LGraph | Subgraph,
|
||||||
filter?: (node: LGraphNode) => boolean
|
filter?: (node: LGraphNode) => boolean
|
||||||
): LGraphNode[] {
|
): LGraphNode[] {
|
||||||
const nodes: LGraphNode[] = []
|
return mapAllNodes(graph, (node) => {
|
||||||
|
|
||||||
visitGraphNodes(graph, (node) => {
|
|
||||||
// Recursively collect from subgraphs
|
|
||||||
if (node.isSubgraphNode?.() && node.subgraph) {
|
|
||||||
nodes.push(...collectAllNodes(node.subgraph, filter))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add node if it passes the filter (or no filter provided)
|
|
||||||
if (!filter || filter(node)) {
|
if (!filter || filter(node)) {
|
||||||
nodes.push(node)
|
return node
|
||||||
}
|
}
|
||||||
|
return undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
return nodes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -241,3 +278,63 @@ export function getNodeByLocatorId(
|
|||||||
|
|
||||||
return targetSubgraph.getNodeById(localNodeId) || null
|
return targetSubgraph.getNodeById(localNodeId) || null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the root graph from any graph in the hierarchy.
|
||||||
|
*
|
||||||
|
* @param graph - Any graph or subgraph in the hierarchy
|
||||||
|
* @returns The root graph
|
||||||
|
*/
|
||||||
|
export function getRootGraph(graph: LGraph | Subgraph): LGraph | Subgraph {
|
||||||
|
let current: LGraph | Subgraph = graph
|
||||||
|
while ('rootGraph' in current && current.rootGraph) {
|
||||||
|
current = current.rootGraph
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a function to all nodes whose type matches a subgraph ID.
|
||||||
|
* Operates on the entire graph hierarchy starting from the root.
|
||||||
|
*
|
||||||
|
* @param rootGraph - The root graph to search in
|
||||||
|
* @param subgraphId - The ID/type of the subgraph to match nodes against
|
||||||
|
* @param fn - Function to apply to each matching node
|
||||||
|
*/
|
||||||
|
export function forEachSubgraphNode(
|
||||||
|
rootGraph: LGraph | Subgraph | null | undefined,
|
||||||
|
subgraphId: string | null | undefined,
|
||||||
|
fn: (node: LGraphNode) => void
|
||||||
|
): void {
|
||||||
|
if (!rootGraph || !subgraphId) return
|
||||||
|
|
||||||
|
forEachNode(rootGraph, (node) => {
|
||||||
|
if (node.type === subgraphId) {
|
||||||
|
fn(node)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a function over all nodes whose type matches a subgraph ID.
|
||||||
|
* Operates on the entire graph hierarchy starting from the root.
|
||||||
|
*
|
||||||
|
* @param rootGraph - The root graph to search in
|
||||||
|
* @param subgraphId - The ID/type of the subgraph to match nodes against
|
||||||
|
* @param mapFn - Function to apply to each matching node
|
||||||
|
* @returns Array of mapped results
|
||||||
|
*/
|
||||||
|
export function mapSubgraphNodes<T>(
|
||||||
|
rootGraph: LGraph | Subgraph | null | undefined,
|
||||||
|
subgraphId: string | null | undefined,
|
||||||
|
mapFn: (node: LGraphNode) => T
|
||||||
|
): T[] {
|
||||||
|
if (!rootGraph || !subgraphId) return []
|
||||||
|
|
||||||
|
return mapAllNodes(rootGraph, (node) => {
|
||||||
|
if (node.type === subgraphId) {
|
||||||
|
return mapFn(node)
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,10 +5,15 @@ import {
|
|||||||
collectAllNodes,
|
collectAllNodes,
|
||||||
findNodeInHierarchy,
|
findNodeInHierarchy,
|
||||||
findSubgraphByUuid,
|
findSubgraphByUuid,
|
||||||
|
forEachNode,
|
||||||
|
forEachSubgraphNode,
|
||||||
getLocalNodeIdFromExecutionId,
|
getLocalNodeIdFromExecutionId,
|
||||||
getNodeByExecutionId,
|
getNodeByExecutionId,
|
||||||
getNodeByLocatorId,
|
getNodeByLocatorId,
|
||||||
|
getRootGraph,
|
||||||
getSubgraphPathFromExecutionId,
|
getSubgraphPathFromExecutionId,
|
||||||
|
mapAllNodes,
|
||||||
|
mapSubgraphNodes,
|
||||||
parseExecutionId,
|
parseExecutionId,
|
||||||
traverseSubgraphPath,
|
traverseSubgraphPath,
|
||||||
triggerCallbackOnAllNodes,
|
triggerCallbackOnAllNodes,
|
||||||
@@ -283,6 +288,141 @@ describe('graphTraversalUtil', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('mapAllNodes', () => {
|
||||||
|
it('should map over all nodes in a flat graph', () => {
|
||||||
|
const nodes = [createMockNode(1), createMockNode(2), createMockNode(3)]
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
|
||||||
|
const results = mapAllNodes(graph, (node) => node.id)
|
||||||
|
|
||||||
|
expect(results).toEqual([1, 2, 3])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should map over nodes in subgraphs', () => {
|
||||||
|
const subNode = createMockNode(100)
|
||||||
|
const subgraph = createMockSubgraph('sub-uuid', [subNode])
|
||||||
|
|
||||||
|
const nodes = [
|
||||||
|
createMockNode(1),
|
||||||
|
createMockNode(2, { isSubgraph: true, subgraph })
|
||||||
|
]
|
||||||
|
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
const results = mapAllNodes(graph, (node) => node.id)
|
||||||
|
|
||||||
|
expect(results).toHaveLength(3)
|
||||||
|
expect(results).toContain(100)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should exclude undefined results', () => {
|
||||||
|
const nodes = [createMockNode(1), createMockNode(2), createMockNode(3)]
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
|
||||||
|
const results = mapAllNodes(graph, (node) => {
|
||||||
|
return Number(node.id) > 1 ? node.id : undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(results).toEqual([2, 3])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle deeply nested structures', () => {
|
||||||
|
const deepNode = createMockNode(300)
|
||||||
|
const deepSubgraph = createMockSubgraph('deep-uuid', [deepNode])
|
||||||
|
|
||||||
|
const midNode = createMockNode(200)
|
||||||
|
const midSubgraphNode = createMockNode(201, {
|
||||||
|
isSubgraph: true,
|
||||||
|
subgraph: deepSubgraph
|
||||||
|
})
|
||||||
|
const midSubgraph = createMockSubgraph('mid-uuid', [
|
||||||
|
midNode,
|
||||||
|
midSubgraphNode
|
||||||
|
])
|
||||||
|
|
||||||
|
const nodes = [
|
||||||
|
createMockNode(1),
|
||||||
|
createMockNode(2, { isSubgraph: true, subgraph: midSubgraph })
|
||||||
|
]
|
||||||
|
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
const results = mapAllNodes(graph, (node) => `node-${node.id}`)
|
||||||
|
|
||||||
|
expect(results).toHaveLength(5)
|
||||||
|
expect(results).toContain('node-300')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('forEachNode', () => {
|
||||||
|
it('should execute function on all nodes in a flat graph', () => {
|
||||||
|
const nodes = [createMockNode(1), createMockNode(2), createMockNode(3)]
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
|
||||||
|
const visited: number[] = []
|
||||||
|
forEachNode(graph, (node) => {
|
||||||
|
visited.push(node.id as number)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(visited).toHaveLength(3)
|
||||||
|
expect(visited).toContain(1)
|
||||||
|
expect(visited).toContain(2)
|
||||||
|
expect(visited).toContain(3)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should execute function on nodes in subgraphs', () => {
|
||||||
|
const subNode = createMockNode(100)
|
||||||
|
const subgraph = createMockSubgraph('sub-uuid', [subNode])
|
||||||
|
|
||||||
|
const nodes = [
|
||||||
|
createMockNode(1),
|
||||||
|
createMockNode(2, { isSubgraph: true, subgraph })
|
||||||
|
]
|
||||||
|
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
|
||||||
|
const visited: number[] = []
|
||||||
|
forEachNode(graph, (node) => {
|
||||||
|
visited.push(node.id as number)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(visited).toHaveLength(3)
|
||||||
|
expect(visited).toContain(100)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should allow node mutations', () => {
|
||||||
|
const nodes = [createMockNode(1), createMockNode(2), createMockNode(3)]
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
|
||||||
|
// Add a title property to each node
|
||||||
|
forEachNode(graph, (node) => {
|
||||||
|
;(node as any).title = `Node ${node.id}`
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(nodes[0]).toHaveProperty('title', 'Node 1')
|
||||||
|
expect(nodes[1]).toHaveProperty('title', 'Node 2')
|
||||||
|
expect(nodes[2]).toHaveProperty('title', 'Node 3')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle node type matching for subgraph references', () => {
|
||||||
|
const subgraphId = 'my-subgraph-123'
|
||||||
|
const nodes = [
|
||||||
|
createMockNode(1),
|
||||||
|
{ ...createMockNode(2), type: subgraphId } as LGraphNode,
|
||||||
|
createMockNode(3),
|
||||||
|
{ ...createMockNode(4), type: subgraphId } as LGraphNode
|
||||||
|
]
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
|
||||||
|
const matchingNodes: number[] = []
|
||||||
|
forEachNode(graph, (node) => {
|
||||||
|
if (node.type === subgraphId) {
|
||||||
|
matchingNodes.push(node.id as number)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(matchingNodes).toEqual([2, 4])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('findNodeInHierarchy', () => {
|
describe('findNodeInHierarchy', () => {
|
||||||
it('should find node in root graph', () => {
|
it('should find node in root graph', () => {
|
||||||
const nodes = [createMockNode(1), createMockNode(2), createMockNode(3)]
|
const nodes = [createMockNode(1), createMockNode(2), createMockNode(3)]
|
||||||
@@ -482,5 +622,140 @@ describe('graphTraversalUtil', () => {
|
|||||||
expect(found).toBeNull()
|
expect(found).toBeNull()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('getRootGraph', () => {
|
||||||
|
it('should return the same graph if it is already root', () => {
|
||||||
|
const graph = createMockGraph([])
|
||||||
|
expect(getRootGraph(graph)).toBe(graph)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return root graph from subgraph', () => {
|
||||||
|
const rootGraph = createMockGraph([])
|
||||||
|
const subgraph = createMockSubgraph('sub-uuid', [])
|
||||||
|
;(subgraph as any).rootGraph = rootGraph
|
||||||
|
|
||||||
|
expect(getRootGraph(subgraph)).toBe(rootGraph)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return root graph from deeply nested subgraph', () => {
|
||||||
|
const rootGraph = createMockGraph([])
|
||||||
|
const midSubgraph = createMockSubgraph('mid-uuid', [])
|
||||||
|
const deepSubgraph = createMockSubgraph('deep-uuid', [])
|
||||||
|
|
||||||
|
;(midSubgraph as any).rootGraph = rootGraph
|
||||||
|
;(deepSubgraph as any).rootGraph = midSubgraph
|
||||||
|
|
||||||
|
expect(getRootGraph(deepSubgraph)).toBe(rootGraph)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('forEachSubgraphNode', () => {
|
||||||
|
it('should apply function to all nodes matching subgraph type', () => {
|
||||||
|
const subgraphId = 'my-subgraph-123'
|
||||||
|
const nodes = [
|
||||||
|
createMockNode(1),
|
||||||
|
{ ...createMockNode(2), type: subgraphId } as LGraphNode,
|
||||||
|
createMockNode(3),
|
||||||
|
{ ...createMockNode(4), type: subgraphId } as LGraphNode
|
||||||
|
]
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
|
||||||
|
const matchingIds: number[] = []
|
||||||
|
forEachSubgraphNode(graph, subgraphId, (node) => {
|
||||||
|
matchingIds.push(node.id as number)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(matchingIds).toEqual([2, 4])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should work with root graph directly', () => {
|
||||||
|
const subgraphId = 'target-subgraph'
|
||||||
|
const rootNodes = [
|
||||||
|
{ ...createMockNode(1), type: subgraphId } as LGraphNode,
|
||||||
|
createMockNode(2),
|
||||||
|
{ ...createMockNode(3), type: subgraphId } as LGraphNode
|
||||||
|
]
|
||||||
|
const rootGraph = createMockGraph(rootNodes)
|
||||||
|
|
||||||
|
const matchingIds: number[] = []
|
||||||
|
forEachSubgraphNode(rootGraph, subgraphId, (node) => {
|
||||||
|
matchingIds.push(node.id as number)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(matchingIds).toEqual([1, 3])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle null inputs gracefully', () => {
|
||||||
|
const fn = vi.fn()
|
||||||
|
|
||||||
|
forEachSubgraphNode(null, 'id', fn)
|
||||||
|
forEachSubgraphNode(createMockGraph([]), null, fn)
|
||||||
|
forEachSubgraphNode(null, null, fn)
|
||||||
|
|
||||||
|
expect(fn).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should allow node mutations like title updates', () => {
|
||||||
|
const subgraphId = 'my-subgraph'
|
||||||
|
const nodes = [
|
||||||
|
{ ...createMockNode(1), type: subgraphId } as LGraphNode,
|
||||||
|
{ ...createMockNode(2), type: subgraphId } as LGraphNode,
|
||||||
|
createMockNode(3)
|
||||||
|
]
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
|
||||||
|
forEachSubgraphNode(graph, subgraphId, (node) => {
|
||||||
|
;(node as any).title = 'Updated Title'
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(nodes[0]).toHaveProperty('title', 'Updated Title')
|
||||||
|
expect(nodes[1]).toHaveProperty('title', 'Updated Title')
|
||||||
|
expect(nodes[2]).not.toHaveProperty('title', 'Updated Title')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('mapSubgraphNodes', () => {
|
||||||
|
it('should map over nodes matching subgraph type', () => {
|
||||||
|
const subgraphId = 'my-subgraph-123'
|
||||||
|
const nodes = [
|
||||||
|
createMockNode(1),
|
||||||
|
{ ...createMockNode(2), type: subgraphId } as LGraphNode,
|
||||||
|
createMockNode(3),
|
||||||
|
{ ...createMockNode(4), type: subgraphId } as LGraphNode
|
||||||
|
]
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
|
||||||
|
const results = mapSubgraphNodes(graph, subgraphId, (node) => node.id)
|
||||||
|
|
||||||
|
expect(results).toEqual([2, 4])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return empty array for null inputs', () => {
|
||||||
|
expect(mapSubgraphNodes(null, 'id', (n) => n.id)).toEqual([])
|
||||||
|
expect(
|
||||||
|
mapSubgraphNodes(createMockGraph([]), null, (n) => n.id)
|
||||||
|
).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should work with complex transformations', () => {
|
||||||
|
const subgraphId = 'target'
|
||||||
|
const nodes = [
|
||||||
|
{ ...createMockNode(1), type: subgraphId } as LGraphNode,
|
||||||
|
{ ...createMockNode(2), type: 'other' } as LGraphNode,
|
||||||
|
{ ...createMockNode(3), type: subgraphId } as LGraphNode
|
||||||
|
]
|
||||||
|
const graph = createMockGraph(nodes)
|
||||||
|
|
||||||
|
const results = mapSubgraphNodes(graph, subgraphId, (node) => ({
|
||||||
|
id: node.id,
|
||||||
|
isTarget: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
expect(results).toEqual([
|
||||||
|
{ id: 1, isTarget: true },
|
||||||
|
{ id: 3, isTarget: true }
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user