Skip to content

Commit 9cea546

Browse files
authored
Pin reroute on link release searchbox (#469)
* Correctly handle wildcard type * Add test * nit * Pin reroute on link release search * Connect wildcard * nit
1 parent d171597 commit 9cea546

File tree

7 files changed

+43
-12
lines changed

7 files changed

+43
-12
lines changed

browser_tests/ComfyPage.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,20 @@ class ComfyNodeSearchBox {
2626
)
2727
}
2828

29-
async fillAndSelectFirstNode(nodeName: string) {
29+
async fillAndSelectFirstNode(
30+
nodeName: string,
31+
options?: { suggestionIndex: number }
32+
) {
3033
await this.input.waitFor({ state: 'visible' })
3134
await this.input.fill(nodeName)
3235
await this.dropdown.waitFor({ state: 'visible' })
3336
// Wait for some time for the auto complete list to update.
3437
// The auto complete list is debounced and may take some time to update.
3538
await this.page.waitForTimeout(500)
36-
await this.dropdown.locator('li').nth(0).click()
39+
await this.dropdown
40+
.locator('li')
41+
.nth(options?.suggestionIndex || 0)
42+
.click()
3743
}
3844
}
3945

browser_tests/nodeSearchBox.spec.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ test.describe('Node search box', () => {
3535

3636
test('Can auto link node', async ({ comfyPage }) => {
3737
await comfyPage.disconnectEdge()
38-
await comfyPage.searchBox.fillAndSelectFirstNode('CLIPTextEncode')
38+
// Select the second item as the first item is always reroute
39+
await comfyPage.searchBox.fillAndSelectFirstNode('CLIPTextEncode', {
40+
suggestionIndex: 1
41+
})
3942
await expect(comfyPage.canvas).toHaveScreenshot('auto-linked-node.png')
4043
})
4144

@@ -54,7 +57,10 @@ test.describe('Node search box', () => {
5457
await comfyPage.dragAndDrop(outputSlot1Pos, emptySpacePos)
5558
await comfyPage.page.keyboard.up('Shift')
5659

57-
await comfyPage.searchBox.fillAndSelectFirstNode('Load Checkpoint')
60+
// Select the second item as the first item is always reroute
61+
await comfyPage.searchBox.fillAndSelectFirstNode('Load Checkpoint', {
62+
suggestionIndex: 1
63+
})
5864
await expect(comfyPage.canvas).toHaveScreenshot(
5965
'auto-linked-node-batch.png'
6066
)

src/components/searchbox/NodeSearchBox.vue

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ const props = defineProps({
7878
searchLimit: {
7979
type: Number,
8080
default: 64
81+
},
82+
// TODO: Find a more flexible mechanism to add pinned nodes
83+
includeReroute: {
84+
type: Boolean,
85+
default: false
8186
}
8287
})
8388
@@ -91,13 +96,14 @@ const placeholder = computed(() => {
9196
9297
const search = (query: string) => {
9398
currentQuery.value = query
94-
suggestions.value = useNodeDefStore().nodeSearchService.searchNode(
95-
query,
96-
props.filters,
97-
{
99+
suggestions.value = [
100+
...(props.includeReroute
101+
? [useNodeDefStore().nodeDefsByName['Reroute']]
102+
: []),
103+
...useNodeDefStore().nodeSearchService.searchNode(query, props.filters, {
98104
limit: props.searchLimit
99-
}
100-
)
105+
})
106+
]
101107
}
102108
103109
const highlightQuery = (text: string, query: string) => {

src/components/searchbox/NodeSearchBoxPopover.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<template #container>
2121
<NodeSearchBox
2222
:filters="nodeFilters"
23+
:includeReroute="includeReroute"
2324
@add-filter="addFilter"
2425
@remove-filter="removeFilter"
2526
@add-node="addNode"
@@ -61,6 +62,7 @@ const getNewNodeLocation = (): [number, number] => {
6162
return [originalEvent.canvasX, originalEvent.canvasY]
6263
}
6364
const nodeFilters = reactive([])
65+
const includeReroute = ref(false)
6466
const addFilter = (filter: FilterAndValue) => {
6567
nodeFilters.push(filter)
6668
}
@@ -100,6 +102,7 @@ const linkReleaseTriggerMode = computed(() => {
100102
})
101103
102104
const canvasEventHandler = (e: LiteGraphCanvasEvent) => {
105+
includeReroute.value = false
103106
const shiftPressed = (e.detail.originalEvent as KeyboardEvent).shiftKey
104107
105108
if (e.detail.subType === 'empty-release') {
@@ -123,6 +126,7 @@ const canvasEventHandler = (e: LiteGraphCanvasEvent) => {
123126
)
124127
const dataType = firstLink.type
125128
addFilter([filter, dataType])
129+
includeReroute.value = true
126130
}
127131
triggerEvent.value = e
128132
visible.value = true

src/services/nodeSearchService.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,13 @@ export abstract class NodeFilter<FilterOptionT = string> {
5757
public abstract getNodeOptions(node: ComfyNodeDefImpl): FilterOptionT[]
5858

5959
public matches(node: ComfyNodeDefImpl, value: FilterOptionT): boolean {
60-
return this.getNodeOptions(node).includes(value)
60+
if (value === '*') {
61+
return true
62+
}
63+
const options = this.getNodeOptions(node)
64+
return (
65+
options.includes(value) || _.some(options, (option) => option === '*')
66+
)
6167
}
6268
}
6369

src/types/litegraphTypes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ export class ConnectingLinkImpl implements ConnectingLink {
5555
const newNodeSlots =
5656
this.releaseSlotType === 'output' ? newNode.outputs : newNode.inputs
5757
const newNodeSlot = newNodeSlots.findIndex(
58-
(slot: INodeSlot) => slot.type === this.type
58+
(slot: INodeSlot) =>
59+
slot.type === this.type || slot.type === '*' || this.type === '*'
5960
)
6061

6162
if (newNodeSlot === -1) {

tests-ui/tests/nodeSearchService.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ describe('nodeSearchService', () => {
5858
const service = new NodeSearchService(EXAMPLE_NODE_DEFS)
5959
const inputFilter = service.getFilterById('input')
6060
expect(service.searchNode('L', [[inputFilter, 'LATENT']])).toHaveLength(1)
61+
// Wildcard should match all.
62+
expect(service.searchNode('L', [[inputFilter, '*']])).toHaveLength(2)
6163
expect(service.searchNode('L')).toHaveLength(2)
6264
})
6365
})

0 commit comments

Comments
 (0)