mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-08 06:30:04 +00:00
load assets browser before fetch completes and show loading state (#6189)
## Summary Moves the fetch and post-fetch logic associated with the asset browser into the component and shows a loading state while fetching. To test, use this branch: https://github.com/comfyanonymous/ComfyUI/pull/10045 https://github.com/user-attachments/assets/718974d5-efc7-46a0-bcd6-e82596d4c389 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6189-load-assets-browser-before-fetch-completes-and-show-loading-state-2946d73d365081879d1bd05d86e8c036) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
import { d, t } from '@/i18n'
|
||||
import type { FilterState } from '@/platform/assets/components/AssetFilterBar.vue'
|
||||
@@ -65,7 +66,10 @@ export interface AssetDisplayItem extends AssetItem {
|
||||
* Asset Browser composable
|
||||
* Manages search, filtering, asset transformation and selection logic
|
||||
*/
|
||||
export function useAssetBrowser(assets: AssetItem[] = []) {
|
||||
export function useAssetBrowser(
|
||||
assetsSource: Ref<AssetItem[] | undefined> = ref<AssetItem[] | undefined>([])
|
||||
) {
|
||||
const assets = computed<AssetItem[]>(() => assetsSource.value ?? [])
|
||||
// State
|
||||
const searchQuery = ref('')
|
||||
const selectedCategory = ref('all')
|
||||
@@ -116,9 +120,10 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
|
||||
}
|
||||
|
||||
const availableCategories = computed(() => {
|
||||
const categories = assets
|
||||
.filter((asset) => asset.tags[0] === 'models' && asset.tags[1])
|
||||
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)
|
||||
|
||||
const uniqueCategories = Array.from(new Set(categories))
|
||||
.sort()
|
||||
@@ -152,7 +157,7 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
|
||||
|
||||
// Category-filtered assets for filter options (before search/format/base model filters)
|
||||
const categoryFilteredAssets = computed(() => {
|
||||
return assets.filter(filterByCategory(selectedCategory.value))
|
||||
return assets.value.filter(filterByCategory(selectedCategory.value))
|
||||
})
|
||||
|
||||
const filteredAssets = computed(() => {
|
||||
@@ -161,8 +166,8 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
|
||||
.filter(filterByFileFormats(filters.value.fileFormats))
|
||||
.filter(filterByBaseModels(filters.value.baseModels))
|
||||
|
||||
// Sort assets
|
||||
filtered.sort((a, b) => {
|
||||
const sortedAssets = [...filtered]
|
||||
sortedAssets.sort((a, b) => {
|
||||
switch (filters.value.sortBy) {
|
||||
case 'name-desc':
|
||||
return b.name.localeCompare(a.name)
|
||||
@@ -179,7 +184,7 @@ export function useAssetBrowser(assets: AssetItem[] = []) {
|
||||
})
|
||||
|
||||
// Transform to display format
|
||||
return filtered.map(transformAssetForDisplay)
|
||||
return sortedAssets.map(transformAssetForDisplay)
|
||||
})
|
||||
|
||||
function updateFilters(newFilters: FilterState) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { t } from '@/i18n'
|
||||
import AssetBrowserModal from '@/platform/assets/components/AssetBrowserModal.vue'
|
||||
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
||||
import { assetService } from '@/platform/assets/services/assetService'
|
||||
import { useDialogStore } from '@/stores/dialogStore'
|
||||
import type { DialogComponentProps } from '@/stores/dialogStore'
|
||||
|
||||
@@ -51,33 +49,6 @@ export const useAssetBrowserDialog = () => {
|
||||
dialogStore.closeDialog({ key: dialogKey })
|
||||
}
|
||||
|
||||
const assets: AssetItem[] = await assetService
|
||||
.getAssetsForNodeType(props.nodeType)
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
'Failed to fetch assets for node type:',
|
||||
props.nodeType,
|
||||
error
|
||||
)
|
||||
return []
|
||||
})
|
||||
|
||||
// Extract node type category from first asset's tags (e.g., "loras", "checkpoints")
|
||||
// Tags are ordered: ["models", "loras"] so take the second tag
|
||||
const nodeTypeCategory =
|
||||
assets[0]?.tags?.find((tag) => tag !== 'models') ?? 'models'
|
||||
|
||||
const acronyms = new Set(['VAE', 'CLIP', 'GLIGEN'])
|
||||
const categoryLabel = nodeTypeCategory
|
||||
.split('_')
|
||||
.map((word) => {
|
||||
const uc = word.toUpperCase()
|
||||
return acronyms.has(uc) ? uc : word
|
||||
})
|
||||
.join(' ')
|
||||
|
||||
const title = t('assetBrowser.allCategory', { category: categoryLabel })
|
||||
|
||||
dialogStore.showDialog({
|
||||
key: dialogKey,
|
||||
component: AssetBrowserModal,
|
||||
@@ -85,8 +56,6 @@ export const useAssetBrowserDialog = () => {
|
||||
nodeType: props.nodeType,
|
||||
inputName: props.inputName,
|
||||
currentValue: props.currentValue,
|
||||
assets,
|
||||
title,
|
||||
onSelect: handleAssetSelected,
|
||||
onClose: () => dialogStore.closeDialog({ key: dialogKey })
|
||||
},
|
||||
@@ -100,25 +69,12 @@ export const useAssetBrowserDialog = () => {
|
||||
dialogStore.closeDialog({ key: dialogKey })
|
||||
}
|
||||
|
||||
const assets = await assetService
|
||||
.getAssetsByTag(options.assetType)
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
'Failed to fetch assets for tag:',
|
||||
options.assetType,
|
||||
error
|
||||
)
|
||||
return []
|
||||
})
|
||||
|
||||
dialogStore.showDialog({
|
||||
key: dialogKey,
|
||||
component: AssetBrowserModal,
|
||||
props: {
|
||||
nodeType: undefined,
|
||||
inputName: undefined,
|
||||
assets,
|
||||
showLeftPanel: true,
|
||||
assetType: options.assetType,
|
||||
title: options.title,
|
||||
onSelect: handleAssetSelected,
|
||||
onClose: () => dialogStore.closeDialog({ key: dialogKey })
|
||||
|
||||
Reference in New Issue
Block a user