diff --git a/src/platform/assets/composables/useAssetBrowser.ts b/src/platform/assets/composables/useAssetBrowser.ts index 31668aa2f..e368046c4 100644 --- a/src/platform/assets/composables/useAssetBrowser.ts +++ b/src/platform/assets/composables/useAssetBrowser.ts @@ -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() @@ -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 } diff --git a/tests-ui/platform/assets/composables/useAssetBrowser.test.ts b/tests-ui/platform/assets/composables/useAssetBrowser.test.ts index cf2b410a1..d7d4f74dc 100644 --- a/tests-ui/platform/assets/composables/useAssetBrowser.test.ts +++ b/tests-ui/platform/assets/composables/useAssetBrowser.test.ts @@ -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') }) })