From 4810b5728a01b6368e4bd2b5e482db8c7947d0b7 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Sun, 2 Nov 2025 20:50:16 -0800 Subject: [PATCH] [feat] Add Partner Nodes virtual category and rename license filter (#6542) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a 'Partner Nodes' virtual category that filters templates where OpenSource === false, and renames the 'License' filter to 'Runs on' with values 'ComfyUI' and 'Partner API'. The implementation is backward compatible and works like the existing 'Basics' category - it filters templates from any category without duplication. The filter logic now uses the explicit OpenSource field instead of heuristic detection. This change coordinates with upcoming workflow_templates repo updates that will move API templates to GENERATION TYPE categories and add the OpenSource field to all API node templates. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6542-feat-Add-Partner-Nodes-virtual-category-and-rename-license-filter-29f6d73d36508111a85bdf5017f0a100) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude --- src/composables/useTemplateFiltering.ts | 13 ++++++----- src/locales/en/main.json | 6 ++++- .../repositories/workflowTemplatesStore.ts | 23 +++++++++++++++++++ .../workflow/templates/types/template.ts | 4 ++++ .../composables/useTemplateFiltering.test.ts | 3 ++- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/composables/useTemplateFiltering.ts b/src/composables/useTemplateFiltering.ts index 7c724e2d4..4d399e757 100644 --- a/src/composables/useTemplateFiltering.ts +++ b/src/composables/useTemplateFiltering.ts @@ -114,16 +114,17 @@ export function useTemplateFiltering( } return filteredByUseCases.value.filter((template) => { - // Check if template has API in its tags or name (indicating it runs on external/remote API) - const isApiTemplate = - template.tags?.includes('API') || - template.name?.toLowerCase().includes('api_') + // Use openSource field to determine where template runs + // openSource === false -> External/Remote API + // openSource !== false -> ComfyUI (includes true and undefined) + const isExternalAPI = template.openSource === false + const isComfyUI = template.openSource !== false return selectedRunsOn.value.some((selectedRunsOn) => { if (selectedRunsOn === 'External or Remote API') { - return isApiTemplate + return isExternalAPI } else if (selectedRunsOn === 'ComfyUI') { - return !isApiTemplate + return isComfyUI } return false }) diff --git a/src/locales/en/main.json b/src/locales/en/main.json index dc0c73ec6..b7e4c4b9a 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -754,7 +754,10 @@ "Image API": "Image API", "Video API": "Video API", "LLM API": "LLM API", - "All": "All Templates" + "All": "All Templates", + "Extensions": "Extensions", + "Partner Nodes": "Partner Nodes", + "Generation Type": "Generation Type" }, "categories": "Categories", "resetFilters": "Clear Filters", @@ -767,6 +770,7 @@ "modelsSelected": "{count} Models", "useCasesSelected": "{count} Use Cases", "runsOnSelected": "{count} Runs On", + "runsOnFilter": "Runs on", "resultsCount": "Showing {count} of {total} templates", "sort": { "recommended": "Recommended", diff --git a/src/platform/workflow/templates/repositories/workflowTemplatesStore.ts b/src/platform/workflow/templates/repositories/workflowTemplatesStore.ts index a1507f621..a1076c88d 100644 --- a/src/platform/workflow/templates/repositories/workflowTemplatesStore.ts +++ b/src/platform/workflow/templates/repositories/workflowTemplatesStore.ts @@ -22,6 +22,7 @@ interface EnhancedTemplate extends TemplateInfo { categoryType?: string categoryGroup?: string // 'GENERATION TYPE' or 'CLOSED SOURCE MODELS' isEssential?: boolean + isPartnerNode?: boolean // Computed from OpenSource === false searchableText?: string } @@ -202,6 +203,7 @@ export const useWorkflowTemplatesStore = defineStore( categoryType: category.type, categoryGroup: category.category, isEssential: category.isEssential, + isPartnerNode: template.openSource === false, searchableText: [ template.title || template.name, template.description || '', @@ -269,6 +271,11 @@ export const useWorkflowTemplatesStore = defineStore( return enhancedTemplates.value.filter((t) => t.isEssential) } + if (categoryId === 'partner-nodes') { + // Filter for templates where OpenSource === false + return enhancedTemplates.value.filter((t) => t.isPartnerNode) + } + // Handle extension-specific filters if (categoryId.startsWith('extension-')) { const moduleName = categoryId.replace('extension-', '') @@ -397,6 +404,22 @@ export const useWorkflowTemplatesStore = defineStore( } }) + // 3.5. Partner Nodes - virtual category for OpenSource === false templates + const partnerNodeCount = enhancedTemplates.value.filter( + (t) => t.isPartnerNode + ).length + + if (partnerNodeCount > 0) { + items.push({ + id: 'partner-nodes', + label: st( + 'templateWorkflows.category.Partner Nodes', + 'Partner Nodes' + ), + icon: 'icon-[lucide--handshake]' + }) + } + // 4. Extensions - always last const extensionCounts = enhancedTemplates.value.filter( (t) => t.sourceModule !== 'default' diff --git a/src/platform/workflow/templates/types/template.ts b/src/platform/workflow/templates/types/template.ts index 774f3a585..426dd12cf 100644 --- a/src/platform/workflow/templates/types/template.ts +++ b/src/platform/workflow/templates/types/template.ts @@ -23,6 +23,10 @@ export interface TemplateInfo { */ vram?: number size?: number + /** + * Whether this template uses open source models. When false, indicates partner/API node templates. + */ + openSource?: boolean } export interface WorkflowTemplates { diff --git a/tests-ui/tests/composables/useTemplateFiltering.test.ts b/tests-ui/tests/composables/useTemplateFiltering.test.ts index 4a83aa9f8..b6428704b 100644 --- a/tests-ui/tests/composables/useTemplateFiltering.test.ts +++ b/tests-ui/tests/composables/useTemplateFiltering.test.ts @@ -74,7 +74,8 @@ describe('useTemplateFiltering', () => { tags: ['API', 'Video'], models: ['Flux'], date: '2024-06-01', - vram: 15 * 1024 ** 3 + vram: 15 * 1024 ** 3, + openSource: false }, { name: 'portrait-flow',