mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-24 14:45:36 +00:00
refactor(assets): remove isAssetPreviewSupported wrapper and simplify callers
Follow-up to the previous FE-729 commit. After deleting
isAssetAPIEnabled, isAssetPreviewSupported() became a wrapper that
always returned true. Remove the function and simplify all callers.
Changes:
- Delete isAssetPreviewSupported() from assetPreviewUtil.ts.
- Media3DTop.vue: drop the isAssetPreviewSupported() arm of the
loadThumbnail guard (asset.name check is still required).
- saveMesh.ts: unwrap two `if (isAssetPreviewSupported()) { ... }`
blocks in applySaveGLBOutput and the SaveGLB beforeRegisterNodeDef
extension callback.
- FormDropdownMenuItem.vue: drop the early return from
resolveMeshPreview.
- useLoad3d.ts: drop the isAssetPreviewSupported() arm of the
modelReady guard.
- Tests: remove the dead "asset preview is unsupported" branches
(useLoad3d, Media3DTop, FormDropdownMenuItem) and clean up the
associated mocks and hoisted state.
Auto-fixed unrelated tailwind class-order lint errors in five files
(VirtualGrid, RightSidePanel, Textarea, ModelInfoPanel,
WidgetSelectDefault) to keep CI green.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
ref="container"
|
||||
class="h-full scrollbar-thin scrollbar-thumb-(--dialog-surface) scrollbar-track-transparent scrollbar-gutter-stable overflow-y-auto [overflow-anchor:none]"
|
||||
class="scrollbar-thin scrollbar-thumb-(--dialog-surface) scrollbar-track-transparent scrollbar-gutter-stable h-full overflow-y-auto [overflow-anchor:none]"
|
||||
>
|
||||
<div :style="topSpacerStyle" />
|
||||
<div :style="mergedGridStyle">
|
||||
|
||||
@@ -370,7 +370,7 @@ function handleTitleCancel() {
|
||||
</section>
|
||||
|
||||
<!-- Panel Content -->
|
||||
<div class="flex-1 scrollbar-thin overflow-y-auto">
|
||||
<div class="scrollbar-thin flex-1 overflow-y-auto">
|
||||
<TabErrors v-if="activeTab === 'errors'" />
|
||||
<template v-else-if="!hasSelection">
|
||||
<TabGlobalParameters v-if="activeTab === 'parameters'" />
|
||||
|
||||
@@ -23,7 +23,7 @@ defineExpose({
|
||||
v-model="modelValue"
|
||||
:class="
|
||||
cn(
|
||||
'flex min-h-16 w-full scrollbar-gutter-stable rounded-lg border-none bg-secondary-background px-3 py-2 text-sm text-base-foreground placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-border-default focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',
|
||||
'scrollbar-gutter-stable flex min-h-16 w-full rounded-lg border-none bg-secondary-background px-3 py-2 text-sm text-base-foreground placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-border-default focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',
|
||||
className
|
||||
)
|
||||
"
|
||||
|
||||
@@ -75,7 +75,6 @@ vi.mock('@/renderer/core/canvas/canvasStore', () => ({
|
||||
}))
|
||||
|
||||
vi.mock('@/platform/assets/utils/assetPreviewUtil', () => ({
|
||||
isAssetPreviewSupported: vi.fn(() => false),
|
||||
persistThumbnail: vi.fn().mockResolvedValue(undefined)
|
||||
}))
|
||||
|
||||
@@ -1483,22 +1482,9 @@ describe('useLoad3d', () => {
|
||||
expect(composable).toBeDefined()
|
||||
})
|
||||
|
||||
it('does not call captureThumbnail when asset preview is unsupported', async () => {
|
||||
const { isAssetPreviewSupported } =
|
||||
it('captures thumbnail and persists it when a model_file widget has a value', async () => {
|
||||
const { persistThumbnail } =
|
||||
await import('@/platform/assets/utils/assetPreviewUtil')
|
||||
vi.mocked(isAssetPreviewSupported).mockReturnValue(false)
|
||||
|
||||
const { handler } = await getModelReadyHandler()
|
||||
handler()
|
||||
await Promise.resolve()
|
||||
|
||||
expect(mockLoad3d.captureThumbnail).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('captures thumbnail and persists it when asset preview is supported and a model_file widget has a value', async () => {
|
||||
const { isAssetPreviewSupported, persistThumbnail } =
|
||||
await import('@/platform/assets/utils/assetPreviewUtil')
|
||||
vi.mocked(isAssetPreviewSupported).mockReturnValue(true)
|
||||
vi.mocked(Load3dUtils.splitFilePath).mockReturnValue([
|
||||
'',
|
||||
'cube.glb'
|
||||
@@ -1523,9 +1509,8 @@ describe('useLoad3d', () => {
|
||||
})
|
||||
|
||||
it('skips persistence when the model widget has no value', async () => {
|
||||
const { isAssetPreviewSupported, persistThumbnail } =
|
||||
const { persistThumbnail } =
|
||||
await import('@/platform/assets/utils/assetPreviewUtil')
|
||||
vi.mocked(isAssetPreviewSupported).mockReturnValue(true)
|
||||
mockNode.widgets = [
|
||||
{ name: 'model_file', value: '' } as unknown as IWidget
|
||||
]
|
||||
@@ -1539,9 +1524,8 @@ describe('useLoad3d', () => {
|
||||
})
|
||||
|
||||
it('swallows captureThumbnail rejections silently', async () => {
|
||||
const { isAssetPreviewSupported, persistThumbnail } =
|
||||
const { persistThumbnail } =
|
||||
await import('@/platform/assets/utils/assetPreviewUtil')
|
||||
vi.mocked(isAssetPreviewSupported).mockReturnValue(true)
|
||||
vi.mocked(Load3dUtils.splitFilePath).mockReturnValue([
|
||||
'',
|
||||
'broken.glb'
|
||||
|
||||
@@ -8,10 +8,7 @@ import { useChainCallback } from '@/composables/functional/useChainCallback'
|
||||
import type Load3d from '@/extensions/core/load3d/Load3d'
|
||||
import Load3dUtils from '@/extensions/core/load3d/Load3dUtils'
|
||||
import { createLoad3d } from '@/extensions/core/load3d/createLoad3d'
|
||||
import {
|
||||
isAssetPreviewSupported,
|
||||
persistThumbnail
|
||||
} from '@/platform/assets/utils/assetPreviewUtil'
|
||||
import { persistThumbnail } from '@/platform/assets/utils/assetPreviewUtil'
|
||||
import type {
|
||||
AnimationItem,
|
||||
CameraConfig,
|
||||
@@ -862,7 +859,7 @@ export const useLoad3d = (nodeOrRef: MaybeRef<LGraphNode | null>) => {
|
||||
isFirstModelLoad = false
|
||||
},
|
||||
modelReady: () => {
|
||||
if (!load3d || !isAssetPreviewSupported()) return
|
||||
if (!load3d) return
|
||||
|
||||
const node = nodeRef.value
|
||||
const modelWidget = node?.widgets?.find(
|
||||
|
||||
@@ -50,7 +50,6 @@ vi.mock('@/scripts/domWidget', () => ({
|
||||
}))
|
||||
|
||||
vi.mock('@/platform/assets/utils/assetPreviewUtil', () => ({
|
||||
isAssetPreviewSupported: vi.fn(() => false),
|
||||
persistThumbnail: vi.fn()
|
||||
}))
|
||||
|
||||
|
||||
@@ -17,10 +17,7 @@ type SaveMeshOutput = NodeOutputWith<{
|
||||
'3d'?: ResultItem[]
|
||||
}>
|
||||
import type { CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import {
|
||||
isAssetPreviewSupported,
|
||||
persistThumbnail
|
||||
} from '@/platform/assets/utils/assetPreviewUtil'
|
||||
import { persistThumbnail } from '@/platform/assets/utils/assetPreviewUtil'
|
||||
import { app } from '@/scripts/app'
|
||||
import { ComponentWidgetImpl, addWidget } from '@/scripts/domWidget'
|
||||
import { useExtensionService } from '@/services/extensionService'
|
||||
@@ -60,15 +57,13 @@ function applySaveGLBOutput(node: LGraphNode, fileInfo: ResultItem): void {
|
||||
silentOnNotFound: true
|
||||
})
|
||||
|
||||
if (isAssetPreviewSupported()) {
|
||||
const filename = fileInfo.filename ?? ''
|
||||
void load3d
|
||||
.whenLoadIdle()
|
||||
.then(() => load3d.captureThumbnail(256, 256))
|
||||
.then((dataUrl) => fetch(dataUrl).then((r) => r.blob()))
|
||||
.then((blob) => persistThumbnail(filename, blob))
|
||||
.catch(() => {})
|
||||
}
|
||||
const filename = fileInfo.filename ?? ''
|
||||
void load3d
|
||||
.whenLoadIdle()
|
||||
.then(() => load3d.captureThumbnail(256, 256))
|
||||
.then((dataUrl) => fetch(dataUrl).then((r) => r.blob()))
|
||||
.then((blob) => persistThumbnail(filename, blob))
|
||||
.catch(() => {})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -194,16 +189,14 @@ useExtensionService().registerExtension({
|
||||
silentOnNotFound: true
|
||||
})
|
||||
|
||||
if (isAssetPreviewSupported()) {
|
||||
const filename = fileInfo.filename ?? ''
|
||||
const filename = fileInfo.filename ?? ''
|
||||
|
||||
void load3d
|
||||
.whenLoadIdle()
|
||||
.then(() => load3d.captureThumbnail(256, 256))
|
||||
.then((dataUrl) => fetch(dataUrl).then((r) => r.blob()))
|
||||
.then((blob) => persistThumbnail(filename, blob))
|
||||
.catch(() => {})
|
||||
}
|
||||
void load3d
|
||||
.whenLoadIdle()
|
||||
.then(() => load3d.captureThumbnail(256, 256))
|
||||
.then((dataUrl) => fetch(dataUrl).then((r) => r.blob()))
|
||||
.then((blob) => persistThumbnail(filename, blob))
|
||||
.catch(() => {})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,15 +5,12 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { AssetMeta } from '../schemas/mediaAssetSchema'
|
||||
import Media3DTop from './Media3DTop.vue'
|
||||
|
||||
const {
|
||||
mockUseIntersectionObserver,
|
||||
mockFindServerPreviewUrl,
|
||||
mockIsAssetPreviewSupported
|
||||
} = vi.hoisted(() => ({
|
||||
mockUseIntersectionObserver: vi.fn(),
|
||||
mockFindServerPreviewUrl: vi.fn(),
|
||||
mockIsAssetPreviewSupported: vi.fn(() => true)
|
||||
}))
|
||||
const { mockUseIntersectionObserver, mockFindServerPreviewUrl } = vi.hoisted(
|
||||
() => ({
|
||||
mockUseIntersectionObserver: vi.fn(),
|
||||
mockFindServerPreviewUrl: vi.fn()
|
||||
})
|
||||
)
|
||||
|
||||
vi.mock('@vueuse/core', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof VueUseCore>()
|
||||
@@ -24,8 +21,7 @@ vi.mock('@vueuse/core', async (importOriginal) => {
|
||||
})
|
||||
|
||||
vi.mock('../utils/assetPreviewUtil', () => ({
|
||||
findServerPreviewUrl: mockFindServerPreviewUrl,
|
||||
isAssetPreviewSupported: mockIsAssetPreviewSupported
|
||||
findServerPreviewUrl: mockFindServerPreviewUrl
|
||||
}))
|
||||
|
||||
function makeAsset(overrides: Partial<AssetMeta> = {}): AssetMeta {
|
||||
@@ -66,7 +62,6 @@ const globalConfig = { mocks: { $t: (key: string) => key } }
|
||||
describe('Media3DTop', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockIsAssetPreviewSupported.mockReturnValue(true)
|
||||
})
|
||||
|
||||
it('renders the placeholder when no thumbnail has loaded', () => {
|
||||
@@ -117,18 +112,6 @@ describe('Media3DTop', () => {
|
||||
expect(img).toHaveAttribute('src', 'http://server/from-name.png')
|
||||
})
|
||||
|
||||
it('skips the server query when isAssetPreviewSupported is false', async () => {
|
||||
fireObserverIntersecting()
|
||||
mockIsAssetPreviewSupported.mockReturnValue(false)
|
||||
render(Media3DTop, {
|
||||
props: { asset: makeAsset() },
|
||||
global: globalConfig
|
||||
})
|
||||
await flush()
|
||||
|
||||
expect(mockFindServerPreviewUrl).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('picks up a patched preview_url after the IntersectionObserver gate has closed', async () => {
|
||||
// Initial render: observer fires, server has no preview yet — hasAttempted=true
|
||||
fireObserverIntersecting()
|
||||
|
||||
@@ -23,10 +23,7 @@ import { useIntersectionObserver } from '@vueuse/core'
|
||||
import { onBeforeUnmount, ref, watch } from 'vue'
|
||||
|
||||
import type { AssetMeta } from '../schemas/mediaAssetSchema'
|
||||
import {
|
||||
findServerPreviewUrl,
|
||||
isAssetPreviewSupported
|
||||
} from '../utils/assetPreviewUtil'
|
||||
import { findServerPreviewUrl } from '../utils/assetPreviewUtil'
|
||||
|
||||
const { asset } = defineProps<{ asset: AssetMeta }>()
|
||||
|
||||
@@ -49,7 +46,7 @@ async function loadThumbnail() {
|
||||
|
||||
if (!asset?.src) return
|
||||
|
||||
if (asset.name && isAssetPreviewSupported()) {
|
||||
if (asset.name) {
|
||||
const serverPreviewUrl = await findServerPreviewUrl(asset.name)
|
||||
if (serverPreviewUrl) {
|
||||
thumbnailSrc.value = serverPreviewUrl
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
rows="3"
|
||||
:class="
|
||||
cn(
|
||||
'w-full resize-y scrollbar-gutter-stable rounded-lg border border-transparent bg-transparent px-3 py-2 text-sm text-component-node-foreground transition-colors outline-none focus:bg-component-node-widget-background',
|
||||
'scrollbar-gutter-stable w-full resize-y rounded-lg border border-transparent bg-transparent px-3 py-2 text-sm text-component-node-foreground transition-colors outline-none focus:bg-component-node-widget-background',
|
||||
isImmutable && 'cursor-not-allowed'
|
||||
)
|
||||
"
|
||||
|
||||
@@ -3,7 +3,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
findOutputAsset,
|
||||
findServerPreviewUrl,
|
||||
isAssetPreviewSupported,
|
||||
persistThumbnail
|
||||
} from '@/platform/assets/utils/assetPreviewUtil'
|
||||
|
||||
@@ -77,12 +76,6 @@ const localAssetWithPreview = {
|
||||
preview_url: '/api/view?type=output&filename=preview.png'
|
||||
}
|
||||
|
||||
describe('isAssetPreviewSupported', () => {
|
||||
it('returns true (asset API is always available)', () => {
|
||||
expect(isAssetPreviewSupported()).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('findOutputAsset', () => {
|
||||
beforeEach(() => vi.clearAllMocks())
|
||||
|
||||
|
||||
@@ -10,15 +10,6 @@ interface AssetRecord {
|
||||
preview_id?: string | null
|
||||
}
|
||||
|
||||
/**
|
||||
* Asset preview support. Asset API is always available post-BE-786, so this
|
||||
* unconditionally returns `true`. Kept as a function to preserve the existing
|
||||
* caller surface; callers can be simplified in a follow-up.
|
||||
*/
|
||||
export function isAssetPreviewSupported(): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
async function fetchAssets(
|
||||
params: Record<string, string>
|
||||
): Promise<AssetRecord[]> {
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
<div
|
||||
data-testid="widget-select-default-viewport"
|
||||
role="presentation"
|
||||
class="flex max-h-56 min-w-full scrollbar-thin scrollbar-thumb-alpha-smoke-500-50 scrollbar-track-transparent scrollbar-gutter-stable flex-col gap-1 overflow-y-auto p-1 text-xs"
|
||||
class="scrollbar-thin scrollbar-thumb-alpha-smoke-500-50 scrollbar-track-transparent scrollbar-gutter-stable flex max-h-56 min-w-full flex-col gap-1 overflow-y-auto p-1 text-xs"
|
||||
:style="viewportStyle"
|
||||
@pointerdown.capture.self="handleViewportPointerDown"
|
||||
>
|
||||
|
||||
@@ -12,14 +12,12 @@ import { AssetKindKey } from './types'
|
||||
import type { FormDropdownMenuItemProps } from './types'
|
||||
|
||||
const mockFindServerPreviewUrl = vi.hoisted(() => vi.fn())
|
||||
const mockIsAssetPreviewSupported = vi.hoisted(() => vi.fn(() => true))
|
||||
const intersectionCallbacks = vi.hoisted(
|
||||
() => [] as Array<(entries: Array<{ isIntersecting: boolean }>) => void>
|
||||
)
|
||||
|
||||
vi.mock('@/platform/assets/utils/assetPreviewUtil', () => ({
|
||||
findServerPreviewUrl: (name: string) => mockFindServerPreviewUrl(name),
|
||||
isAssetPreviewSupported: () => mockIsAssetPreviewSupported()
|
||||
findServerPreviewUrl: (name: string) => mockFindServerPreviewUrl(name)
|
||||
}))
|
||||
|
||||
vi.mock('@vueuse/core', () => ({
|
||||
@@ -83,7 +81,6 @@ describe('FormDropdownMenuItem', () => {
|
||||
beforeEach(() => {
|
||||
intersectionCallbacks.length = 0
|
||||
mockFindServerPreviewUrl.mockReset()
|
||||
mockIsAssetPreviewSupported.mockReset().mockReturnValue(true)
|
||||
})
|
||||
|
||||
describe('Label and name', () => {
|
||||
@@ -167,14 +164,6 @@ describe('FormDropdownMenuItem', () => {
|
||||
expect(img.getAttribute('src')).toBe('/api/preview/resolved.png')
|
||||
})
|
||||
|
||||
it('skips lookup when asset preview is unsupported', async () => {
|
||||
mockIsAssetPreviewSupported.mockReturnValue(false)
|
||||
renderItem({ name: '3d/model.glb' }, { assetKind: 'mesh' })
|
||||
fireIntersection(true)
|
||||
await flushPromises()
|
||||
expect(mockFindServerPreviewUrl).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('only looks up once for repeated intersection events', async () => {
|
||||
mockFindServerPreviewUrl.mockResolvedValue(null)
|
||||
renderItem({ name: '3d/model.glb' }, { assetKind: 'mesh' })
|
||||
|
||||
@@ -5,10 +5,7 @@ import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { cn } from '@comfyorg/tailwind-utils'
|
||||
|
||||
import {
|
||||
findServerPreviewUrl,
|
||||
isAssetPreviewSupported
|
||||
} from '@/platform/assets/utils/assetPreviewUtil'
|
||||
import { findServerPreviewUrl } from '@/platform/assets/utils/assetPreviewUtil'
|
||||
|
||||
import { AssetKindKey } from './types'
|
||||
import type { FormDropdownMenuItemProps } from './types'
|
||||
@@ -40,7 +37,6 @@ function toLookupName(name: string): string {
|
||||
}
|
||||
|
||||
async function resolveMeshPreview() {
|
||||
if (!isAssetPreviewSupported()) return
|
||||
const url = await findServerPreviewUrl(toLookupName(props.name))
|
||||
if (url) resolvedMeshPreview.value = url
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user