[feat] Rename license filter to 'Runs On' filter in template selector (#6543)

## Summary

Renamed the templates license filter to better reflect its actual
purpose - showing where a template executes (locally in ComfyUI vs
external/remote API).

The current "License" filter has been causing confusion with model
licensing terms (e.g., Apache vs flux-dev licensing). This PR clarifies
the filter's purpose by renaming it to "Runs On" and updating the
options to be more descriptive of inference location.

<img width="196" height="230" alt="image"
src="https://github.com/user-attachments/assets/8cbea263-f399-4945-82c1-357ec185f5a7"
/>

<img width="861" height="597" alt="image"
src="https://github.com/user-attachments/assets/af116876-d7a5-49c5-b791-1fda637ff3a3"
/>


## Changes

- **Filter name**: "License" → "Runs On"
- **Filter options**: 
  - "Open Source" → "ComfyUI"
  - "Closed Source (API Nodes)" → "External or Remote API"
- **Icon**: Changed from `file-text` to `server` for better visual
representation
- **Variable naming**: Updated all related variables, types, and tests
to use `runsOn` naming convention
- **Telemetry**: Updated metadata to track `selected_runs_on` instead of
`selected_licenses`

## Why "Runs On"?

- **Clear intent**: Users want to know if a template runs locally or
requires an API call
- **Avoids confusion**: Separates the concept from model licensing terms
- **Inclusive wording**: "Remote" is included alongside "API" to help
users who may not be familiar with API terminology
- **Cloud-agnostic**: "Runs On" works whether the app itself is running
locally or in the cloud

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6543-feat-Rename-license-filter-to-Runs-On-filter-in-template-selector-29f6d73d3650811f935bc1f3fce7d7ad)
by [Unito](https://www.unito.io)
This commit is contained in:
Christian Byrne
2025-11-02 16:35:42 -08:00
committed by GitHub
parent 8dfdac3fc4
commit 8df0a3885d
5 changed files with 49 additions and 52 deletions

View File

@@ -13,7 +13,7 @@ export function useTemplateFiltering(
const searchQuery = ref('')
const selectedModels = ref<string[]>([])
const selectedUseCases = ref<string[]>([])
const selectedLicenses = ref<string[]>([])
const selectedRunsOn = ref<string[]>([])
const sortBy = ref<
| 'default'
| 'alphabetical'
@@ -63,8 +63,8 @@ export function useTemplateFiltering(
return Array.from(tagSet).sort()
})
const availableLicenses = computed(() => {
return ['Open Source', 'Closed Source (API Nodes)']
const availableRunsOn = computed(() => {
return ['ComfyUI', 'External or Remote API']
})
const debouncedSearchQuery = refDebounced(searchQuery, 50)
@@ -108,21 +108,21 @@ export function useTemplateFiltering(
})
})
const filteredByLicenses = computed(() => {
if (selectedLicenses.value.length === 0) {
const filteredByRunsOn = computed(() => {
if (selectedRunsOn.value.length === 0) {
return filteredByUseCases.value
}
return filteredByUseCases.value.filter((template) => {
// Check if template has API in its tags or name (indicating it's a closed source API node)
// 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_')
return selectedLicenses.value.some((selectedLicense) => {
if (selectedLicense === 'Closed Source (API Nodes)') {
return selectedRunsOn.value.some((selectedRunsOn) => {
if (selectedRunsOn === 'External or Remote API') {
return isApiTemplate
} else if (selectedLicense === 'Open Source') {
} else if (selectedRunsOn === 'ComfyUI') {
return !isApiTemplate
}
return false
@@ -142,7 +142,7 @@ export function useTemplateFiltering(
}
const sortedTemplates = computed(() => {
const templates = [...filteredByLicenses.value]
const templates = [...filteredByRunsOn.value]
switch (sortBy.value) {
case 'alphabetical':
@@ -195,7 +195,7 @@ export function useTemplateFiltering(
searchQuery.value = ''
selectedModels.value = []
selectedUseCases.value = []
selectedLicenses.value = []
selectedRunsOn.value = []
sortBy.value = 'default'
}
@@ -207,8 +207,8 @@ export function useTemplateFiltering(
selectedUseCases.value = selectedUseCases.value.filter((t) => t !== tag)
}
const removeLicenseFilter = (license: string) => {
selectedLicenses.value = selectedLicenses.value.filter((l) => l !== license)
const removeRunsOnFilter = (runsOn: string) => {
selectedRunsOn.value = selectedRunsOn.value.filter((r) => r !== runsOn)
}
const filteredCount = computed(() => filteredTemplates.value.length)
@@ -220,7 +220,7 @@ export function useTemplateFiltering(
search_query: searchQuery.value || undefined,
selected_models: selectedModels.value,
selected_use_cases: selectedUseCases.value,
selected_licenses: selectedLicenses.value,
selected_runs_on: selectedRunsOn.value,
sort_by: sortBy.value,
filtered_count: filteredCount.value,
total_count: totalCount.value
@@ -229,14 +229,14 @@ export function useTemplateFiltering(
// Watch for filter changes and track them
watch(
[searchQuery, selectedModels, selectedUseCases, selectedLicenses, sortBy],
[searchQuery, selectedModels, selectedUseCases, selectedRunsOn, sortBy],
() => {
// Only track if at least one filter is active (to avoid tracking initial state)
const hasActiveFilters =
searchQuery.value.trim() !== '' ||
selectedModels.value.length > 0 ||
selectedUseCases.value.length > 0 ||
selectedLicenses.value.length > 0 ||
selectedRunsOn.value.length > 0 ||
sortBy.value !== 'default'
if (hasActiveFilters) {
@@ -251,14 +251,14 @@ export function useTemplateFiltering(
searchQuery,
selectedModels,
selectedUseCases,
selectedLicenses,
selectedRunsOn,
sortBy,
// Computed
filteredTemplates,
availableModels,
availableUseCases,
availableLicenses,
availableRunsOn,
filteredCount,
totalCount,
@@ -266,6 +266,6 @@ export function useTemplateFiltering(
resetFilters,
removeModelFilter,
removeUseCaseFilter,
removeLicenseFilter
removeRunsOnFilter
}
}