mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-11 16:10:05 +00:00
[backport cloud/1.36] feat: Stale-while-revalidate pattern for AssetBrowserModal (#7889)
Backport of #7880 to `cloud/1.36` Automatically created by backport workflow. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7889-backport-cloud-1-36-feat-Stale-while-revalidate-pattern-for-AssetBrowserModal-2e26d73d365081fb854bfe4189a94bef) by [Unito](https://www.unito.io) Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
@@ -63,12 +63,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
breakpointsTailwind,
|
||||
useAsyncState,
|
||||
useBreakpoints
|
||||
} from '@vueuse/core'
|
||||
import { computed, provide, watch } from 'vue'
|
||||
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'
|
||||
import { computed, provide } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import SearchBox from '@/components/common/SearchBox.vue'
|
||||
@@ -81,68 +77,68 @@ import type { AssetDisplayItem } from '@/platform/assets/composables/useAssetBro
|
||||
import { useAssetBrowser } from '@/platform/assets/composables/useAssetBrowser'
|
||||
import { useModelUpload } from '@/platform/assets/composables/useModelUpload'
|
||||
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
||||
import { assetService } from '@/platform/assets/services/assetService'
|
||||
import { formatCategoryLabel } from '@/platform/assets/utils/categoryLabel'
|
||||
import { useAssetDownloadStore } from '@/stores/assetDownloadStore'
|
||||
import { useAssetsStore } from '@/stores/assetsStore'
|
||||
import { useModelToNodeStore } from '@/stores/modelToNodeStore'
|
||||
import { OnCloseKey } from '@/types/widgetTypes'
|
||||
|
||||
const { t } = useI18n()
|
||||
const assetStore = useAssetsStore()
|
||||
const modelToNodeStore = useModelToNodeStore()
|
||||
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||
|
||||
const props = defineProps<{
|
||||
nodeType?: string
|
||||
assetType?: string
|
||||
onSelect?: (asset: AssetItem) => void
|
||||
onClose?: () => void
|
||||
showLeftPanel?: boolean
|
||||
title?: string
|
||||
assetType?: string
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'asset-select': [asset: AssetDisplayItem]
|
||||
close: []
|
||||
}>()
|
||||
|
||||
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||
|
||||
provide(OnCloseKey, props.onClose ?? (() => {}))
|
||||
|
||||
const fetchAssets = async () => {
|
||||
// Compute the cache key based on nodeType or assetType
|
||||
const cacheKey = computed(() => {
|
||||
if (props.nodeType) return props.nodeType
|
||||
if (props.assetType) return `tag:${props.assetType}`
|
||||
return ''
|
||||
})
|
||||
|
||||
// Read directly from store cache - reactive to any store updates
|
||||
const fetchedAssets = computed(
|
||||
() => assetStore.modelAssetsByNodeType.get(cacheKey.value) ?? []
|
||||
)
|
||||
|
||||
const isStoreLoading = computed(
|
||||
() => assetStore.modelLoadingByNodeType.get(cacheKey.value) ?? false
|
||||
)
|
||||
|
||||
// Only show loading spinner when loading AND no cached data
|
||||
const isLoading = computed(
|
||||
() => isStoreLoading.value && fetchedAssets.value.length === 0
|
||||
)
|
||||
|
||||
async function refreshAssets(): Promise<AssetItem[]> {
|
||||
if (props.nodeType) {
|
||||
return (await assetService.getAssetsForNodeType(props.nodeType)) ?? []
|
||||
return await assetStore.updateModelsForNodeType(props.nodeType)
|
||||
}
|
||||
|
||||
if (props.assetType) {
|
||||
return (await assetService.getAssetsByTag(props.assetType)) ?? []
|
||||
return await assetStore.updateModelsForTag(props.assetType)
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
const {
|
||||
state: fetchedAssets,
|
||||
isLoading,
|
||||
execute
|
||||
} = useAsyncState<AssetItem[]>(fetchAssets, [], { immediate: false })
|
||||
// Trigger background refresh on mount
|
||||
void refreshAssets()
|
||||
|
||||
watch(
|
||||
() => [props.nodeType, props.assetType],
|
||||
async () => {
|
||||
await execute()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const assetDownloadStore = useAssetDownloadStore()
|
||||
|
||||
watch(
|
||||
() => assetDownloadStore.hasActiveDownloads,
|
||||
async (currentlyActive, previouslyActive) => {
|
||||
if (previouslyActive && !currentlyActive) {
|
||||
await execute()
|
||||
}
|
||||
}
|
||||
)
|
||||
const { isUploadButtonEnabled, showUploadDialog } =
|
||||
useModelUpload(refreshAssets)
|
||||
|
||||
const {
|
||||
searchQuery,
|
||||
@@ -153,8 +149,6 @@ const {
|
||||
updateFilters
|
||||
} = useAssetBrowser(fetchedAssets)
|
||||
|
||||
const modelToNodeStore = useModelToNodeStore()
|
||||
|
||||
const primaryCategoryTag = computed(() => {
|
||||
const assets = fetchedAssets.value ?? []
|
||||
const tagFromAssets = assets
|
||||
@@ -202,6 +196,4 @@ function handleAssetSelectAndEmit(asset: AssetDisplayItem) {
|
||||
// It handles the appropriate transformation (filename extraction or full asset)
|
||||
props.onSelect?.(asset)
|
||||
}
|
||||
|
||||
const { isUploadButtonEnabled, showUploadDialog } = useModelUpload(execute)
|
||||
</script>
|
||||
|
||||
@@ -3,13 +3,11 @@ import UploadModelDialog from '@/platform/assets/components/UploadModelDialog.vu
|
||||
import UploadModelDialogHeader from '@/platform/assets/components/UploadModelDialogHeader.vue'
|
||||
import UploadModelUpgradeModal from '@/platform/assets/components/UploadModelUpgradeModal.vue'
|
||||
import UploadModelUpgradeModalHeader from '@/platform/assets/components/UploadModelUpgradeModalHeader.vue'
|
||||
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
||||
import { useDialogStore } from '@/stores/dialogStore'
|
||||
import type { UseAsyncStateReturn } from '@vueuse/core'
|
||||
import { computed } from 'vue'
|
||||
|
||||
export function useModelUpload(
|
||||
execute?: UseAsyncStateReturn<AssetItem[], [], true>['execute']
|
||||
onUploadSuccess?: () => Promise<unknown> | void
|
||||
) {
|
||||
const dialogStore = useDialogStore()
|
||||
const { flags } = useFeatureFlags()
|
||||
@@ -37,7 +35,7 @@ export function useModelUpload(
|
||||
component: UploadModelDialog,
|
||||
props: {
|
||||
onUploadSuccess: async () => {
|
||||
await execute?.()
|
||||
await onUploadSuccess?.()
|
||||
}
|
||||
},
|
||||
dialogComponentProps: {
|
||||
|
||||
Reference in New Issue
Block a user