[feat] Add Partner Nodes virtual category and rename license filter (#6542)

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 <noreply@anthropic.com>
This commit is contained in:
Christian Byrne
2025-11-02 20:50:16 -08:00
committed by GitHub
parent 6fe88dba54
commit 4810b5728a
5 changed files with 41 additions and 8 deletions

View File

@@ -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
})

View File

@@ -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",

View File

@@ -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'

View File

@@ -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 {

View File

@@ -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',