From 91e429a62f3862195c9f6cc61f4e56421573012f Mon Sep 17 00:00:00 2001 From: Luke Mino-Altherr Date: Thu, 12 Mar 2026 17:59:05 -0700 Subject: [PATCH] fix: use order-independent tag matching in asset browser categories (#9843) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fix asset browser sidebar missing categories because `typeCategories` assumed a fixed tag order from the API. ## Changes - **What**: Replace `tags[0] === 'models'` / `tags[1]` with `tags.includes(MODELS_TAG)` and `flatMap`+`filter`, matching the pattern used by `getAssetModelFolders` and `filterByCategory`. ## Review Focus The API returns tags in arbitrary order (e.g. `['checkpoints', 'models']` instead of `['models', 'checkpoints']`). The old code filtered out most assets, resulting in an empty sidebar. New test validates arbitrary tag ordering. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9843-fix-use-order-independent-tag-matching-in-asset-browser-categories-3216d73d365081b886f3d5ab1790e19d) by [Unito](https://www.unito.io) Co-authored-by: Amp --- .../composables/useAssetBrowser.test.ts | 19 +++++++++++++++++++ .../assets/composables/useAssetBrowser.ts | 8 +++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/platform/assets/composables/useAssetBrowser.test.ts b/src/platform/assets/composables/useAssetBrowser.test.ts index 498000cc1f..ead824bef9 100644 --- a/src/platform/assets/composables/useAssetBrowser.test.ts +++ b/src/platform/assets/composables/useAssetBrowser.test.ts @@ -692,6 +692,25 @@ describe('useAssetBrowser', () => { ]) }) + it('extracts categories regardless of tag order', () => { + const assets = [ + createApiAsset({ tags: ['checkpoints', 'models'] }), + createApiAsset({ tags: ['loras', 'models'] }), + createApiAsset({ tags: ['models', 'vae'] }) + ] + + const { navItems } = useAssetBrowser(ref(assets)) + + const typeGroup = navItems.value[2] as { + items: { id: string }[] + } + expect(typeGroup.items.map((i) => i.id)).toEqual([ + 'checkpoints', + 'loras', + 'vae' + ]) + }) + it('ignores non-models root tags', () => { const assets = [ createApiAsset({ tags: ['input', 'images'] }), diff --git a/src/platform/assets/composables/useAssetBrowser.ts b/src/platform/assets/composables/useAssetBrowser.ts index 448a89b434..6879ae8125 100644 --- a/src/platform/assets/composables/useAssetBrowser.ts +++ b/src/platform/assets/composables/useAssetBrowser.ts @@ -21,6 +21,7 @@ import { getAssetBaseModels, getAssetFilename } from '@/platform/assets/utils/assetMetadataUtils' +import { MODELS_TAG } from '@/platform/assets/services/assetService' import { sortAssets } from '@/platform/assets/utils/assetSortUtils' import { useAssetDownloadStore } from '@/stores/assetDownloadStore' import type { NavGroupData, NavItemData } from '@/types/navTypes' @@ -123,9 +124,10 @@ export function useAssetBrowser( const typeCategories = computed(() => { const categories = assets.value - .filter((asset) => asset.tags[0] === 'models') - .map((asset) => asset.tags[1]) - .filter((tag): tag is string => typeof tag === 'string' && tag.length > 0) + .filter((asset) => asset.tags.includes(MODELS_TAG)) + .flatMap((asset) => + asset.tags.filter((tag) => tag !== MODELS_TAG && tag.length > 0) + ) .map((tag) => tag.split('/')[0]) return Array.from(new Set(categories))