diff --git a/src/components/searchbox/v2/NodeSearchCategorySidebar.test.ts b/src/components/searchbox/v2/NodeSearchCategorySidebar.test.ts index 156170c1783..4dcc243c0b3 100644 --- a/src/components/searchbox/v2/NodeSearchCategorySidebar.test.ts +++ b/src/components/searchbox/v2/NodeSearchCategorySidebar.test.ts @@ -51,6 +51,11 @@ describe('NodeSearchCategorySidebar', () => { createMockNodeDef({ name: 'EssentialNode', essentials_category: 'basic' + }), + createMockNodeDef({ + name: 'ApiNode', + display_name: 'API Node', + api_node: true }) ]) await nextTick() @@ -60,6 +65,7 @@ describe('NodeSearchCategorySidebar', () => { expect(wrapper.text()).toContain('Most relevant') expect(wrapper.text()).toContain('Favorites') expect(wrapper.text()).toContain('Essentials') + expect(wrapper.text()).toContain('API Nodes') expect(wrapper.text()).toContain('Custom') }) diff --git a/src/components/searchbox/v2/NodeSearchCategorySidebar.vue b/src/components/searchbox/v2/NodeSearchCategorySidebar.vue index fad96faf613..79667ad594e 100644 --- a/src/components/searchbox/v2/NodeSearchCategorySidebar.vue +++ b/src/components/searchbox/v2/NodeSearchCategorySidebar.vue @@ -79,11 +79,18 @@ const hasEssentialNodes = computed(() => ) ) +const hasApiNodes = computed(() => + nodeDefStore.visibleNodeDefs.some((n) => n.api_node) +) + const sourceCategories = computed(() => { const categories = [] if (flags.nodeLibraryEssentialsEnabled && hasEssentialNodes.value) { categories.push({ id: 'essentials', label: t('g.essentials') }) } + if (hasApiNodes.value) { + categories.push({ id: 'api', label: t('g.API Nodes') }) + } categories.push({ id: 'custom', label: t('g.custom') }) return categories }) diff --git a/src/components/searchbox/v2/NodeSearchContent.test.ts b/src/components/searchbox/v2/NodeSearchContent.test.ts index 5559aa8c14d..01404ec96f9 100644 --- a/src/components/searchbox/v2/NodeSearchContent.test.ts +++ b/src/components/searchbox/v2/NodeSearchContent.test.ts @@ -163,6 +163,32 @@ describe('NodeSearchContent', () => { expect(items[0].text()).toContain('Custom Node') }) + it('should show only API nodes when API Nodes is selected', async () => { + useNodeDefStore().updateNodeDefs([ + createMockNodeDef({ + name: 'ApiNode', + display_name: 'API Node', + python_module: 'comfy_api_nodes.provider', + api_node: true + }), + createMockNodeDef({ + name: 'CoreNode', + display_name: 'Core Node', + python_module: 'nodes', + api_node: false + }) + ]) + await nextTick() + + const wrapper = await createWrapper() + await wrapper.find('[data-testid="category-api"]').trigger('click') + await nextTick() + + const items = getNodeItems(wrapper) + expect(items).toHaveLength(1) + expect(items[0].text()).toContain('API Node') + }) + it('should hide Essentials category when no essential nodes exist', async () => { useNodeDefStore().updateNodeDefs([ createMockNodeDef({ diff --git a/src/components/searchbox/v2/NodeSearchContent.vue b/src/components/searchbox/v2/NodeSearchContent.vue index 49bc9230dff..e5122a11aae 100644 --- a/src/components/searchbox/v2/NodeSearchContent.vue +++ b/src/components/searchbox/v2/NodeSearchContent.vue @@ -212,6 +212,9 @@ const displayedResults = computed(() => { (n) => n.nodeSource.type === NodeSourceType.Essentials ) break + case 'api': + results = allNodes.filter((n) => n.api_node) + break case 'custom': results = allNodes.filter( (n) => diff --git a/src/components/searchbox/v2/__test__/testUtils.ts b/src/components/searchbox/v2/__test__/testUtils.ts index 23eb2a6424e..b937db69452 100644 --- a/src/components/searchbox/v2/__test__/testUtils.ts +++ b/src/components/searchbox/v2/__test__/testUtils.ts @@ -39,6 +39,7 @@ export const testI18n = createI18n({ mostRelevant: 'Most relevant', favorites: 'Favorites', essentials: 'Essentials', + 'API Nodes': 'API Nodes', custom: 'Custom', noResults: 'No results', filterByType: 'Filter by {type}...',