mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-28 18:22:40 +00:00
feat: optimize empty search to use cached /nodes endpoint (#8159)
## Summary Optimizes the Manager dialog to use the cached `GET /nodes` endpoint instead of `GET /nodes/search` for empty search queries (when the dialog first opens). This significantly reduces Algolia usage since empty searches account for the majority of search requests. ## Changes - **registrySearchProvider.ts**: Modified `searchPacks()` to detect empty queries and route them to `listAllPacks()` instead of `search()` - **registrySearchProvider.test.ts**: Added 5 new test cases covering empty query behavior - Cache clearing now clears both `search` and `listAllPacks` caches ## Technical Details **Empty Query Flow (NEW):** - Query: `""` or whitespace - Endpoint: `GET /nodes?limit=X&page=Y` - Cache: Server-side cached (via omitting `latest` parameter) - Result: Fast, cached node pack list **Non-Empty Query Flow (UNCHANGED):** - Query: Any non-empty string - Endpoint: `GET /nodes/search?search=X` or `comfy_node_search=X` - Result: Search results as before ## Testing ```bash pnpm test:unit -- src/services/providers/registrySearchProvider.test.ts pnpm typecheck ```
This commit is contained in:
committed by
GitHub
parent
b0d7a7f0f4
commit
0d0576faab
@@ -11,6 +11,8 @@ vi.mock('@/stores/comfyRegistryStore', () => ({
|
|||||||
describe('useComfyRegistrySearchProvider', () => {
|
describe('useComfyRegistrySearchProvider', () => {
|
||||||
const mockSearchCall = vi.fn()
|
const mockSearchCall = vi.fn()
|
||||||
const mockSearchClear = vi.fn()
|
const mockSearchClear = vi.fn()
|
||||||
|
const mockListAllPacksCall = vi.fn()
|
||||||
|
const mockListAllPacksClear = vi.fn()
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks()
|
vi.clearAllMocks()
|
||||||
@@ -20,6 +22,10 @@ describe('useComfyRegistrySearchProvider', () => {
|
|||||||
search: {
|
search: {
|
||||||
call: mockSearchCall,
|
call: mockSearchCall,
|
||||||
clear: mockSearchClear
|
clear: mockSearchClear
|
||||||
|
},
|
||||||
|
listAllPacks: {
|
||||||
|
call: mockListAllPacksCall,
|
||||||
|
clear: mockListAllPacksClear
|
||||||
}
|
}
|
||||||
} as any)
|
} as any)
|
||||||
})
|
})
|
||||||
@@ -111,14 +117,85 @@ describe('useComfyRegistrySearchProvider', () => {
|
|||||||
expect(result.nodePacks).toEqual([])
|
expect(result.nodePacks).toEqual([])
|
||||||
expect(result.querySuggestions).toEqual([])
|
expect(result.querySuggestions).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should use listAllPacks for empty query', async () => {
|
||||||
|
const mockResults = {
|
||||||
|
nodes: [
|
||||||
|
{ id: '1', name: 'Pack 1' },
|
||||||
|
{ id: '2', name: 'Pack 2' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
mockListAllPacksCall.mockResolvedValue(mockResults)
|
||||||
|
|
||||||
|
const provider = useComfyRegistrySearchProvider()
|
||||||
|
const result = await provider.searchPacks('', {
|
||||||
|
pageSize: 20,
|
||||||
|
pageNumber: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(mockListAllPacksCall).toHaveBeenCalledWith({
|
||||||
|
limit: 20,
|
||||||
|
page: 1
|
||||||
|
})
|
||||||
|
expect(mockSearchCall).not.toHaveBeenCalled()
|
||||||
|
expect(result.nodePacks).toEqual(mockResults.nodes)
|
||||||
|
expect(result.querySuggestions).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should use listAllPacks for whitespace-only query', async () => {
|
||||||
|
const mockResults = {
|
||||||
|
nodes: [{ id: '1', name: 'Pack 1' }]
|
||||||
|
}
|
||||||
|
mockListAllPacksCall.mockResolvedValue(mockResults)
|
||||||
|
|
||||||
|
const provider = useComfyRegistrySearchProvider()
|
||||||
|
const result = await provider.searchPacks(' ', {
|
||||||
|
pageSize: 10,
|
||||||
|
pageNumber: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(mockListAllPacksCall).toHaveBeenCalledWith({
|
||||||
|
limit: 10,
|
||||||
|
page: 1
|
||||||
|
})
|
||||||
|
expect(mockSearchCall).not.toHaveBeenCalled()
|
||||||
|
expect(result.nodePacks).toEqual(mockResults.nodes)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle empty results from listAllPacks', async () => {
|
||||||
|
mockListAllPacksCall.mockResolvedValue({ nodes: [] })
|
||||||
|
|
||||||
|
const provider = useComfyRegistrySearchProvider()
|
||||||
|
const result = await provider.searchPacks('', {
|
||||||
|
pageSize: 10,
|
||||||
|
pageNumber: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.nodePacks).toEqual([])
|
||||||
|
expect(result.querySuggestions).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle null results from listAllPacks', async () => {
|
||||||
|
mockListAllPacksCall.mockResolvedValue(null)
|
||||||
|
|
||||||
|
const provider = useComfyRegistrySearchProvider()
|
||||||
|
const result = await provider.searchPacks('', {
|
||||||
|
pageSize: 10,
|
||||||
|
pageNumber: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.nodePacks).toEqual([])
|
||||||
|
expect(result.querySuggestions).toEqual([])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('clearSearchCache', () => {
|
describe('clearSearchCache', () => {
|
||||||
it('should delegate to store search.clear', () => {
|
it('should clear both search and listAllPacks caches', () => {
|
||||||
const provider = useComfyRegistrySearchProvider()
|
const provider = useComfyRegistrySearchProvider()
|
||||||
provider.clearSearchCache()
|
provider.clearSearchCache()
|
||||||
|
|
||||||
expect(mockSearchClear).toHaveBeenCalled()
|
expect(mockSearchClear).toHaveBeenCalled()
|
||||||
|
expect(mockListAllPacksClear).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -25,33 +25,45 @@ export const useComfyRegistrySearchProvider = (): NodePackSearchProvider => {
|
|||||||
): Promise<SearchPacksResult> => {
|
): Promise<SearchPacksResult> => {
|
||||||
const { pageSize, pageNumber, restrictSearchableAttributes } = params
|
const { pageSize, pageNumber, restrictSearchableAttributes } = params
|
||||||
|
|
||||||
// Determine search mode based on searchable attributes
|
// For empty queries, use the cached listAllPacks endpoint instead of search
|
||||||
|
if (!query || query.trim() === '') {
|
||||||
|
const listParams = {
|
||||||
|
limit: pageSize,
|
||||||
|
page: pageNumber + 1 // Registry API uses 1-based pagination
|
||||||
|
// Note: omitting 'latest' parameter defaults to cached result
|
||||||
|
}
|
||||||
|
|
||||||
|
const listResult = await registryStore.listAllPacks.call(listParams)
|
||||||
|
const nodePacks = listResult?.nodes ?? []
|
||||||
|
|
||||||
|
return {
|
||||||
|
nodePacks,
|
||||||
|
querySuggestions: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-empty queries, use the search endpoint
|
||||||
const isNodeSearch = restrictSearchableAttributes?.includes('comfy_nodes')
|
const isNodeSearch = restrictSearchableAttributes?.includes('comfy_nodes')
|
||||||
|
|
||||||
const searchParams = {
|
const searchParams = {
|
||||||
search: isNodeSearch ? undefined : query,
|
search: isNodeSearch ? undefined : query,
|
||||||
comfy_node_search: isNodeSearch ? query : undefined,
|
comfy_node_search: isNodeSearch ? query : undefined,
|
||||||
limit: pageSize,
|
limit: pageSize,
|
||||||
page: pageNumber + 1 // Registry API uses 1-based pagination
|
page: pageNumber + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchResult = await registryStore.search.call(searchParams)
|
const searchResult = await registryStore.search.call(searchParams)
|
||||||
|
const nodePacks = searchResult?.nodes ?? []
|
||||||
if (!searchResult || !searchResult.nodes) {
|
|
||||||
return {
|
|
||||||
nodePacks: [],
|
|
||||||
querySuggestions: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nodePacks: searchResult.nodes,
|
nodePacks,
|
||||||
querySuggestions: [] // Registry doesn't support query suggestions
|
querySuggestions: [] // Registry doesn't support query suggestions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearSearchCache = () => {
|
const clearSearchCache = () => {
|
||||||
registryStore.search.clear()
|
registryStore.search.clear()
|
||||||
|
registryStore.listAllPacks.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSortValue = (
|
const getSortValue = (
|
||||||
|
|||||||
Reference in New Issue
Block a user