Files
ComfyUI_frontend/src/platform/assets/components/MediaVideoTop.vue
Jin Yi 06ba106f59 Media Assets Management Sidebar Tab Implementation (#6112)
## 📋 Overview
Implemented a new Media Assets sidebar tab in ComfyUI for managing
user-uploaded input files and generated output files. This feature
supports both local and cloud environments and is currently enabled only
in development mode.

## 🎯 Key Features

### 1. Media Assets Sidebar Tab
- **Imported** / **Generated** files separated by tabs
- Visual display with file preview cards
- Gallery view support (navigable with arrow keys)

### 2. Environment-Specific Implementation
- **`useInternalMediaAssets`**: For local environment
  - Fetches file list via `/files` API
  - Retrieves generation task execution time via `/history` API
  - Processes history data using the same logic as QueueSidebarTab
- **`useCloudMediaAssets`**: For cloud environment
  - File retrieval through assetService
  - History data processing using TaskItemImpl
- Auto-truncation of long filenames over 20 characters (e.g.,
`very_long_filename_here.png` → `very_long_...here.png`)

### 3. Execution Time Display
- Shows task execution time on generated image cards (e.g., "2.3s")
- Calculated from History API's `execution_start` and
`execution_success` messages
- Displayed at MediaAssetCard's duration chip location

### 4. Gallery Feature
- Full-screen gallery mode on image click
- Navigate between images with keyboard arrows
- Exit gallery with ESC key
- Reuses ResultGallery component from QueueSidebarTab

### 5. Development Mode Only
- Excluded from production builds using `import.meta.env.DEV` condition
- Feature in development, scheduled for official release after
stabilization

## 🛠️ Technical Changes

### New Files Added
- `src/components/sidebar/tabs/AssetsSidebarTab.vue` - Main sidebar tab
component
- `src/composables/sidebarTabs/useAssetsSidebarTab.ts` - Sidebar tab
definition
- `src/composables/useInternalMediaAssets.ts` - Local environment
implementation
- `src/composables/useCloudMediaAssets.ts` - Cloud environment
implementation
- `packages/design-system/src/icons/image-ai-edit.svg` - Icon addition

### Modified Files
- `src/stores/workspace/sidebarTabStore.ts` - Added dev mode only tab
display logic
- `src/platform/assets/components/MediaAssetCard.vue` - Added execution
time display, zoom event
- `src/platform/assets/components/MediaImageTop.vue` - Added image
dimension detection
- `packages/shared-frontend-utils/src/formatUtil.ts` - Added media type
determination utility functions
- `src/locales/en/main.json` - Added translation keys


[media_asset_OSS_cloud.webm](https://github.com/user-attachments/assets/a6ee3b49-19ed-4735-baad-c2ac2da868ef)

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions <github-actions@github.com>
2025-10-29 03:39:16 +00:00

69 lines
1.6 KiB
Vue

<template>
<div
class="relative size-full overflow-hidden rounded bg-black"
@mouseenter="isHovered = true"
@mouseleave="isHovered = false"
>
<video
ref="videoRef"
:controls="shouldShowControls"
preload="none"
:poster="asset.preview_url"
class="relative size-full object-contain"
@click.stop
@play="onVideoPlay"
@pause="onVideoPause"
@ended="onVideoEnded"
>
<source :src="asset.src || ''" />
</video>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import type { AssetContext, AssetMeta } from '../schemas/mediaAssetSchema'
const { asset } = defineProps<{
asset: AssetMeta
context: AssetContext
}>()
const emit = defineEmits<{
play: [assetId: string]
videoPlayingStateChanged: [isPlaying: boolean]
videoControlsChanged: [showControls: boolean]
}>()
const videoRef = ref<HTMLVideoElement>()
const isHovered = ref(false)
const isPlaying = ref(false)
// Always show controls when not playing, hide/show based on hover when playing
const shouldShowControls = computed(() => !isPlaying.value || isHovered.value)
watch(shouldShowControls, (controlsVisible) => {
emit('videoControlsChanged', controlsVisible)
})
onMounted(() => {
emit('videoControlsChanged', shouldShowControls.value)
})
const onVideoPlay = () => {
isPlaying.value = true
emit('videoPlayingStateChanged', true)
}
const onVideoPause = () => {
isPlaying.value = false
emit('videoPlayingStateChanged', false)
}
const onVideoEnded = () => {
isPlaying.value = false
emit('videoPlayingStateChanged', false)
}
</script>