mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-03 06:47:33 +00:00
[fix] simplify useAssetBrowser
This commit is contained in:
@@ -2,6 +2,7 @@ import { computed, ref } from 'vue'
|
||||
|
||||
import type { UUID } from '@/lib/litegraph/src/utils/uuid'
|
||||
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
||||
import { formatSize } from '@/utils/formatUtil'
|
||||
|
||||
type AssetBadge = {
|
||||
label: string
|
||||
@@ -38,7 +39,7 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
|
||||
asset.user_metadata?.description || `${typeTag || 'Unknown'} model`
|
||||
|
||||
// Format file size
|
||||
const formattedSize = formatFileSize(asset.size)
|
||||
const formattedSize = formatSize(asset.size)
|
||||
|
||||
// Create badges from tags and metadata
|
||||
const badges: AssetBadge[] = []
|
||||
@@ -75,20 +76,6 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to format file sizes
|
||||
function formatFileSize(bytes: number): string {
|
||||
const units = ['B', 'KB', 'MB', 'GB']
|
||||
let size = bytes
|
||||
let unitIndex = 0
|
||||
|
||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||
size /= 1024
|
||||
unitIndex++
|
||||
}
|
||||
|
||||
return `${size.toFixed(1)} ${units[unitIndex]}`
|
||||
}
|
||||
|
||||
// Extract available categories from assets
|
||||
const availableCategories = computed(() => {
|
||||
const categorySet = new Set<string>()
|
||||
@@ -124,27 +111,27 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
|
||||
return category?.label || 'Assets'
|
||||
})
|
||||
|
||||
// Filter functions
|
||||
const filterByCategory = (category: string) => (asset: AssetItem) => {
|
||||
if (category === 'all') return true
|
||||
return asset.tags.includes(category)
|
||||
}
|
||||
|
||||
const filterByQuery = (query: string) => (asset: AssetItem) => {
|
||||
if (!query) return true
|
||||
const lowerQuery = query.toLowerCase()
|
||||
return (
|
||||
asset.name.toLowerCase().includes(lowerQuery) ||
|
||||
asset.user_metadata?.description?.toLowerCase().includes(lowerQuery) ||
|
||||
asset.tags.some((tag) => tag.toLowerCase().includes(lowerQuery))
|
||||
)
|
||||
}
|
||||
|
||||
// Computed filtered and transformed assets
|
||||
const filteredAssets = computed(() => {
|
||||
let filtered = [...assets]
|
||||
|
||||
// Filter by category (tag-based)
|
||||
if (selectedCategory.value !== 'all') {
|
||||
filtered = filtered.filter((asset) =>
|
||||
asset.tags.includes(selectedCategory.value)
|
||||
)
|
||||
}
|
||||
|
||||
// Filter by search query
|
||||
if (searchQuery.value) {
|
||||
const query = searchQuery.value.toLowerCase()
|
||||
filtered = filtered.filter(
|
||||
(asset) =>
|
||||
asset.name.toLowerCase().includes(query) ||
|
||||
asset.user_metadata?.description?.toLowerCase().includes(query) ||
|
||||
asset.tags.some((tag) => tag.toLowerCase().includes(query))
|
||||
)
|
||||
}
|
||||
const filtered = assets
|
||||
.filter(filterByCategory(selectedCategory.value))
|
||||
.filter(filterByQuery(searchQuery.value))
|
||||
|
||||
// Sort assets
|
||||
filtered.sort((a, b) => {
|
||||
@@ -164,18 +151,6 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
|
||||
})
|
||||
|
||||
// Actions
|
||||
function setSearchQuery(query: string) {
|
||||
searchQuery.value = query
|
||||
}
|
||||
|
||||
function setCategory(category: string) {
|
||||
selectedCategory.value = category
|
||||
}
|
||||
|
||||
function setSortBy(sort: string) {
|
||||
sortBy.value = sort
|
||||
}
|
||||
|
||||
function selectAsset(asset: AssetDisplayItem): UUID {
|
||||
if (import.meta.env.DEV) {
|
||||
console.log('Asset selected:', asset.id, asset.name)
|
||||
@@ -195,9 +170,6 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
|
||||
filteredAssets,
|
||||
|
||||
// Actions
|
||||
setSearchQuery,
|
||||
setCategory,
|
||||
setSortBy,
|
||||
selectAsset,
|
||||
transformAssetForDisplay
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ describe('useAssetBrowser', () => {
|
||||
|
||||
// Adds display properties
|
||||
expect(result.description).toBe('Test model')
|
||||
expect(result.formattedSize).toBe('2.0 GB')
|
||||
expect(result.formattedSize).toBe('2 GB')
|
||||
expect(result.badges).toContainEqual({
|
||||
label: 'checkpoints',
|
||||
type: 'type'
|
||||
})
|
||||
expect(result.badges).toContainEqual({ label: '2.0 GB', type: 'size' })
|
||||
expect(result.badges).toContainEqual({ label: '2 GB', type: 'size' })
|
||||
})
|
||||
|
||||
it('creates fallback description from tags when metadata missing', () => {
|
||||
@@ -59,10 +59,10 @@ describe('useAssetBrowser', () => {
|
||||
const { transformAssetForDisplay } = useAssetBrowser([])
|
||||
|
||||
const testCases = [
|
||||
{ size: 512, expected: '512.0 B' },
|
||||
{ size: 512, expected: '512 B' },
|
||||
{ size: 1536, expected: '1.5 KB' },
|
||||
{ size: 2097152, expected: '2.0 MB' },
|
||||
{ size: 3221225472, expected: '3.0 GB' }
|
||||
{ size: 2097152, expected: '2 MB' },
|
||||
{ size: 3221225472, expected: '3 GB' }
|
||||
]
|
||||
|
||||
testCases.forEach(({ size, expected }) => {
|
||||
@@ -81,9 +81,9 @@ describe('useAssetBrowser', () => {
|
||||
createApiAsset({ id: '3', tags: ['models', 'checkpoints'] })
|
||||
]
|
||||
|
||||
const { setCategory, filteredAssets } = useAssetBrowser(assets)
|
||||
const { selectedCategory, filteredAssets } = useAssetBrowser(assets)
|
||||
|
||||
setCategory('checkpoints')
|
||||
selectedCategory.value = 'checkpoints'
|
||||
await nextTick()
|
||||
|
||||
expect(filteredAssets.value).toHaveLength(2)
|
||||
@@ -100,9 +100,9 @@ describe('useAssetBrowser', () => {
|
||||
createApiAsset({ id: '2', tags: ['models', 'loras'] })
|
||||
]
|
||||
|
||||
const { setCategory, filteredAssets } = useAssetBrowser(assets)
|
||||
const { selectedCategory, filteredAssets } = useAssetBrowser(assets)
|
||||
|
||||
setCategory('all')
|
||||
selectedCategory.value = 'all'
|
||||
await nextTick()
|
||||
|
||||
expect(filteredAssets.value).toHaveLength(2)
|
||||
@@ -117,9 +117,9 @@ describe('useAssetBrowser', () => {
|
||||
createApiAsset({ name: 'photorealistic_v2.safetensors' })
|
||||
]
|
||||
|
||||
const { setSearchQuery, filteredAssets } = useAssetBrowser(assets)
|
||||
const { searchQuery, filteredAssets } = useAssetBrowser(assets)
|
||||
|
||||
setSearchQuery('realistic')
|
||||
searchQuery.value = 'realistic'
|
||||
await nextTick()
|
||||
|
||||
expect(filteredAssets.value).toHaveLength(2)
|
||||
@@ -142,9 +142,9 @@ describe('useAssetBrowser', () => {
|
||||
})
|
||||
]
|
||||
|
||||
const { setSearchQuery, filteredAssets } = useAssetBrowser(assets)
|
||||
const { searchQuery, filteredAssets } = useAssetBrowser(assets)
|
||||
|
||||
setSearchQuery('fantasy')
|
||||
searchQuery.value = 'fantasy'
|
||||
await nextTick()
|
||||
|
||||
expect(filteredAssets.value).toHaveLength(1)
|
||||
@@ -154,9 +154,9 @@ describe('useAssetBrowser', () => {
|
||||
it('handles empty search results', async () => {
|
||||
const assets = [createApiAsset({ name: 'test.safetensors' })]
|
||||
|
||||
const { setSearchQuery, filteredAssets } = useAssetBrowser(assets)
|
||||
const { searchQuery, filteredAssets } = useAssetBrowser(assets)
|
||||
|
||||
setSearchQuery('nonexistent')
|
||||
searchQuery.value = 'nonexistent'
|
||||
await nextTick()
|
||||
|
||||
expect(filteredAssets.value).toHaveLength(0)
|
||||
@@ -180,11 +180,11 @@ describe('useAssetBrowser', () => {
|
||||
})
|
||||
]
|
||||
|
||||
const { setSearchQuery, setCategory, filteredAssets } =
|
||||
const { searchQuery, selectedCategory, filteredAssets } =
|
||||
useAssetBrowser(assets)
|
||||
|
||||
setSearchQuery('realistic')
|
||||
setCategory('checkpoints')
|
||||
searchQuery.value = 'realistic'
|
||||
selectedCategory.value = 'checkpoints'
|
||||
await nextTick()
|
||||
|
||||
expect(filteredAssets.value).toHaveLength(1)
|
||||
@@ -202,9 +202,9 @@ describe('useAssetBrowser', () => {
|
||||
createApiAsset({ name: 'beta.safetensors' })
|
||||
]
|
||||
|
||||
const { setSortBy, filteredAssets } = useAssetBrowser(assets)
|
||||
const { sortBy, filteredAssets } = useAssetBrowser(assets)
|
||||
|
||||
setSortBy('name')
|
||||
sortBy.value = 'name'
|
||||
await nextTick()
|
||||
|
||||
const names = filteredAssets.value.map((asset) => asset.name)
|
||||
@@ -222,9 +222,9 @@ describe('useAssetBrowser', () => {
|
||||
createApiAsset({ created_at: '2024-02-01T00:00:00Z' })
|
||||
]
|
||||
|
||||
const { setSortBy, filteredAssets } = useAssetBrowser(assets)
|
||||
const { sortBy, filteredAssets } = useAssetBrowser(assets)
|
||||
|
||||
setSortBy('date')
|
||||
sortBy.value = 'date'
|
||||
await nextTick()
|
||||
|
||||
const dates = filteredAssets.value.map((asset) => asset.created_at)
|
||||
@@ -262,9 +262,13 @@ describe('useAssetBrowser', () => {
|
||||
const { availableCategories } = useAssetBrowser(assets)
|
||||
|
||||
expect(availableCategories.value).toEqual([
|
||||
{ id: 'all', label: 'All Models', icon: 'i-lucide:folder' },
|
||||
{ id: 'checkpoints', label: 'Checkpoints', icon: 'i-lucide:package' },
|
||||
{ id: 'loras', label: 'Loras', icon: 'i-lucide:package' }
|
||||
{ id: 'all', label: 'All Models', icon: 'icon-[lucide--folder]' },
|
||||
{
|
||||
id: 'checkpoints',
|
||||
label: 'Checkpoints',
|
||||
icon: 'icon-[lucide--package]'
|
||||
},
|
||||
{ id: 'loras', label: 'Loras', icon: 'icon-[lucide--package]' }
|
||||
])
|
||||
})
|
||||
|
||||
@@ -277,8 +281,8 @@ describe('useAssetBrowser', () => {
|
||||
const { availableCategories } = useAssetBrowser(assets)
|
||||
|
||||
expect(availableCategories.value).toEqual([
|
||||
{ id: 'all', label: 'All Models', icon: 'i-lucide:folder' },
|
||||
{ id: 'vae', label: 'Vae', icon: 'i-lucide:package' }
|
||||
{ id: 'all', label: 'All Models', icon: 'icon-[lucide--folder]' },
|
||||
{ id: 'vae', label: 'Vae', icon: 'icon-[lucide--package]' }
|
||||
])
|
||||
})
|
||||
|
||||
@@ -291,24 +295,28 @@ describe('useAssetBrowser', () => {
|
||||
const { availableCategories } = useAssetBrowser(assets)
|
||||
|
||||
expect(availableCategories.value).toEqual([
|
||||
{ id: 'all', label: 'All Models', icon: 'i-lucide:folder' },
|
||||
{ id: 'checkpoints', label: 'Checkpoints', icon: 'i-lucide:package' }
|
||||
{ id: 'all', label: 'All Models', icon: 'icon-[lucide--folder]' },
|
||||
{
|
||||
id: 'checkpoints',
|
||||
label: 'Checkpoints',
|
||||
icon: 'icon-[lucide--package]'
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
it('computes content title from selected category', () => {
|
||||
const assets = [createApiAsset({ tags: ['models', 'checkpoints'] })]
|
||||
const { setCategory, contentTitle } = useAssetBrowser(assets)
|
||||
const { selectedCategory, contentTitle } = useAssetBrowser(assets)
|
||||
|
||||
// Default
|
||||
expect(contentTitle.value).toBe('All Models')
|
||||
|
||||
// Set specific category
|
||||
setCategory('checkpoints')
|
||||
selectedCategory.value = 'checkpoints'
|
||||
expect(contentTitle.value).toBe('Checkpoints')
|
||||
|
||||
// Unknown category
|
||||
setCategory('unknown')
|
||||
selectedCategory.value = 'unknown'
|
||||
expect(contentTitle.value).toBe('Assets')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user