Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/components/widget/layout/BaseModalLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
2 changes: 1 addition & 1 deletion src/components/widget/nav/NavItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
2 changes: 1 addition & 1 deletion src/platform/assets/components/AssetBadgeGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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'
)
"
>
Expand Down
2 changes: 1 addition & 1 deletion src/platform/assets/components/AssetFilterBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
95 changes: 95 additions & 0 deletions src/platform/assets/composables/useAssetBrowser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,48 @@ describe('useAssetBrowser', () => {

expect(result.description).toBe('loras model')
})

it('removes category prefix from badge labels', () => {
const apiAsset = createApiAsset({
tags: ['models', 'checkpoint/stable-diffusion-v1-5']
})

const { filteredAssets } = useAssetBrowser(ref([apiAsset]))
const result = filteredAssets.value[0]

expect(result.badges).toContainEqual({
label: 'stable-diffusion-v1-5',
type: 'type'
})
})

it('handles tags without slash for badges', () => {
const apiAsset = createApiAsset({
tags: ['models', 'checkpoints']
})

const { filteredAssets } = useAssetBrowser(ref([apiAsset]))
const result = filteredAssets.value[0]

expect(result.badges).toContainEqual({
label: 'checkpoints',
type: 'type'
})
})

it('handles tags with multiple slashes in badges', () => {
const apiAsset = createApiAsset({
tags: ['models', 'checkpoint/subfolder/model-name']
})

const { filteredAssets } = useAssetBrowser(ref([apiAsset]))
const result = filteredAssets.value[0]

expect(result.badges).toContainEqual({
label: 'subfolder/model-name',
type: 'type'
})
})
})

describe('Tag-Based Filtering', () => {
Expand Down Expand Up @@ -533,5 +575,58 @@ describe('useAssetBrowser', () => {
selectedCategory.value = 'unknown'
expect(contentTitle.value).toBe('Assets')
})

it('groups models by top-level folder name', () => {
const assets = [
createApiAsset({
id: 'asset-1',
tags: ['models', 'Chatterbox/subfolder1/model1']
}),
createApiAsset({
id: 'asset-2',
tags: ['models', 'Chatterbox/subfolder2/model2']
}),
createApiAsset({
id: 'asset-3',
tags: ['models', 'Chatterbox/subfolder3/model3']
}),
createApiAsset({
id: 'asset-4',
tags: ['models', 'OtherFolder/subfolder1/model4']
})
]

const { availableCategories, selectedCategory, categoryFilteredAssets } =
useAssetBrowser(ref(assets))

// Should group all Chatterbox subfolders under single category
expect(availableCategories.value).toEqual([
{ id: 'all', label: 'All Models', icon: 'icon-[lucide--folder]' },
{
id: 'Chatterbox',
label: 'Chatterbox',
icon: 'icon-[lucide--package]'
},
{
id: 'OtherFolder',
label: 'OtherFolder',
icon: 'icon-[lucide--package]'
}
])

// When selecting Chatterbox category, should include all models from its subfolders
selectedCategory.value = 'Chatterbox'
expect(categoryFilteredAssets.value).toHaveLength(3)
expect(categoryFilteredAssets.value.map((a) => a.id)).toEqual([
'asset-1',
'asset-2',
'asset-3'
])

// When selecting OtherFolder category, should include only its models
selectedCategory.value = 'OtherFolder'
expect(categoryFilteredAssets.value).toHaveLength(1)
expect(categoryFilteredAssets.value[0].id).toBe('asset-4')
})
})
})
21 changes: 19 additions & 2 deletions src/platform/assets/composables/useAssetBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
}
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down