mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-02 20:22:08 +00:00
## Summary Render generated video previews in list items using a real video element (instead of an image element (this caused errors before)) and include a custom play button with dimming per [the designs](https://www.figma.com/design/LVilZgHGk5RwWOkVN6yCEK/Queue-Progress-Modal?node-id=3928-39270&m=dev). ## Changes - **What**: - List item preview path now renders a `video` element when `isVideoPreview` is true. - Video list preview uses `preload="metadata"`, `muted`, `playsinline`, and `pointer-events-none` so row click behavior stays unchanged. - Kept the custom overlay/play affordance and increased overlay dimming from `bg-black/10` to `bg-black/15`. - Updated tests for `AssetsListItem`, `MediaVideoTop`, and `AssetsSidebarListView`. ## Review Focus - Confirm list item click behavior still opens/selects asset (no inline playback interaction). - Confirm video list previews now show actual video frame path instead of broken image fallback. ## Limitation Backend does not currently provide a dedicated poster/thumbnail image for video outputs in the job preview payload. In the frontend today, we can either show a video icon placeholder, or load/render the full video itself to obtain a preview frame. ## Screenshots (if applicable) <img width="427" height="499" alt="image" src="https://github.com/user-attachments/assets/3f974817-9d73-4fee-9fa5-2f1f68942c06" /> <img width="230" height="92" alt="image" src="https://github.com/user-attachments/assets/1fbfdd6a-72dd-47e2-96bf-8f7eb41c36f2" />
93 lines
2.4 KiB
TypeScript
93 lines
2.4 KiB
TypeScript
import { mount } from '@vue/test-utils'
|
|
import { defineComponent } from 'vue'
|
|
import { describe, expect, it, vi } from 'vitest'
|
|
|
|
import type { OutputStackListItem } from '@/platform/assets/composables/useOutputStacks'
|
|
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
|
|
|
import AssetsSidebarListView from './AssetsSidebarListView.vue'
|
|
|
|
vi.mock('vue-i18n', () => ({
|
|
useI18n: () => ({
|
|
t: (key: string) => key
|
|
})
|
|
}))
|
|
|
|
vi.mock('@/stores/assetsStore', () => ({
|
|
useAssetsStore: () => ({
|
|
isAssetDeleting: () => false
|
|
})
|
|
}))
|
|
|
|
const VirtualGridStub = defineComponent({
|
|
name: 'VirtualGrid',
|
|
props: {
|
|
items: {
|
|
type: Array,
|
|
default: () => []
|
|
}
|
|
},
|
|
template:
|
|
'<div><slot v-for="item in items" :key="item.key" name="item" :item="item" /></div>'
|
|
})
|
|
|
|
const buildAsset = (id: string, name: string): AssetItem =>
|
|
({
|
|
id,
|
|
name,
|
|
tags: []
|
|
}) satisfies AssetItem
|
|
|
|
const buildOutputItem = (asset: AssetItem): OutputStackListItem => ({
|
|
key: `asset-${asset.id}`,
|
|
asset
|
|
})
|
|
|
|
const mountListView = (assetItems: OutputStackListItem[] = []) =>
|
|
mount(AssetsSidebarListView, {
|
|
props: {
|
|
assetItems,
|
|
selectableAssets: [],
|
|
isSelected: () => false,
|
|
isStackExpanded: () => false,
|
|
toggleStack: async () => {},
|
|
assetType: 'output'
|
|
},
|
|
global: {
|
|
stubs: {
|
|
VirtualGrid: VirtualGridStub
|
|
}
|
|
}
|
|
})
|
|
|
|
describe('AssetsSidebarListView', () => {
|
|
it('shows generated assets header when there are assets', () => {
|
|
const wrapper = mountListView([buildOutputItem(buildAsset('a1', 'x.png'))])
|
|
|
|
expect(wrapper.text()).toContain('sideToolbar.generatedAssetsHeader')
|
|
})
|
|
|
|
it('does not show assets header when there are no assets', () => {
|
|
const wrapper = mountListView([])
|
|
|
|
expect(wrapper.text()).not.toContain('sideToolbar.generatedAssetsHeader')
|
|
})
|
|
|
|
it('marks mp4 assets as video previews', () => {
|
|
const videoAsset = {
|
|
...buildAsset('video-asset', 'clip.mp4'),
|
|
preview_url: '/api/view/clip.mp4',
|
|
user_metadata: {}
|
|
} satisfies AssetItem
|
|
|
|
const wrapper = mountListView([buildOutputItem(videoAsset)])
|
|
|
|
const listItems = wrapper.findAllComponents({ name: 'AssetsListItem' })
|
|
const assetListItem = listItems.at(-1)
|
|
|
|
expect(assetListItem).toBeDefined()
|
|
expect(assetListItem?.props('previewUrl')).toBe('/api/view/clip.mp4')
|
|
expect(assetListItem?.props('isVideoPreview')).toBe(true)
|
|
})
|
|
})
|