[backport cloud/1.36] feature: model browser folder grouping (#7916)

Backport of #7892 to `cloud/1.36`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7916-backport-cloud-1-36-feature-model-browser-folder-grouping-2e36d73d365081279a6bf032c6e0893d)
by [Unito](https://www.unito.io)

Co-authored-by: Jin Yi <jin12cc@gmail.com>
This commit is contained in:
Comfy Org PR Bot
2026-01-09 10:22:03 +09:00
committed by GitHub
parent b4e4cccc31
commit aecb841cc0
6 changed files with 120 additions and 6 deletions

View File

@@ -80,7 +80,9 @@
>
{{ contentTitle }}
</h2>
<div class="min-h-0 px-6 pt-0 pb-10 overflow-y-auto">
<div
class="min-h-0 px-6 pt-0 pb-10 overflow-y-auto scrollbar-custom"
>
<slot name="content"></slot>
</div>
</main>

View File

@@ -9,7 +9,7 @@
role="button"
@click="onClick"
>
<div v-if="icon" class="py-0.5">
<div v-if="icon" class="pt-0.5">
<NavIcon :icon="icon" />
</div>
<i v-else class="text-neutral icon-[lucide--folder] text-xs shrink-0" />

View File

@@ -5,7 +5,7 @@
:key="badge.label"
:class="
cn(
'px-2 py-1 rounded text-xs font-bold uppercase tracking-wider text-modal-card-tag-foreground bg-modal-card-tag-background'
'px-2 py-1 rounded text-xs font-bold uppercase tracking-wider text-modal-card-tag-foreground bg-modal-card-tag-background break-all'
)
"
>

View File

@@ -48,7 +48,7 @@
@update:model-value="handleFilterChange"
>
<template #icon>
<i class="icon-[lucide--arrow-up-down] size-3" />
<i class="icon-[lucide--arrow-up-down]" />
</template>
</SingleSelect>
</div>

View File

@@ -15,7 +15,18 @@ export type OwnershipOption = 'all' | 'my-models' | 'public-models'
function filterByCategory(category: string) {
return (asset: AssetItem) => {
return category === 'all' || asset.tags.includes(category)
if (category === 'all') return true
// Check if any tag matches the category (for exact matches)
if (asset.tags.includes(category)) return true
// Check if any tag's top-level folder matches the category
return asset.tags.some((tag) => {
if (typeof tag === 'string' && tag.includes('/')) {
return tag.split('/')[0] === category
}
return false
})
}
}
@@ -93,7 +104,12 @@ export function useAssetBrowser(
// Type badge from non-root tag
if (typeTag) {
badges.push({ label: typeTag, type: 'type' })
// Remove category prefix from badge label (e.g. "checkpoint/model" → "model")
const badgeLabel = typeTag.includes('/')
? typeTag.substring(typeTag.indexOf('/') + 1)
: typeTag
badges.push({ label: badgeLabel, type: 'type' })
}
// Base model badge from metadata
@@ -125,6 +141,7 @@ export function useAssetBrowser(
.filter((asset) => asset.tags[0] === 'models')
.map((asset) => asset.tags[1])
.filter((tag): tag is string => typeof tag === 'string' && tag.length > 0)
.map((tag) => tag.split('/')[0]) // Extract top-level folder name
const uniqueCategories = Array.from(new Set(categories))
.sort()