Skip to content

Conversation

viva-jinyi
Copy link
Member

@viva-jinyi viva-jinyi commented Oct 17, 2025

📋 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.pngvery_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

- Implement new sidebar tab for managing imported/generated files
- Add separate composables for internal and cloud environments
- Display execution time from history API on generated outputs
- Support gallery view with keyboard navigation
- Auto-truncate long filenames in cloud environment
- Add utility functions for media type detection
- Enable feature only in development mode

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Copy link

github-actions bot commented Oct 17, 2025

🎭 Playwright Test Results

Some tests failed

⏰ Completed at: 10/17/2025, 03:26:15 PM UTC

📈 Summary

  • Total Tests: 499
  • Passed: 467 ✅
  • Failed: 1 ❌
  • Flaky: 1 ⚠️
  • Skipped: 30 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 458 / ❌ 1 / ⚠️ 1 / ⏭️ 30
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 6 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

Copy link

github-actions bot commented Oct 17, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 10/17/2025, 03:11:14 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

Comment on lines +488 to +491
const imageExts = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp']
const videoExts = ['mp4', 'webm', 'mov', 'avi']
const audioExts = ['mp3', 'wav', 'ogg', 'flac']
const threeDExts = ['obj', 'fbx', 'gltf', 'glb']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: We can move these to the module scope (avoid re-initialization on every call)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we combine the concept of media kind and media type? It seems to be exactly the same but just differing between plural vs. singular. I think singular is better to align with MIME https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types

Comment on lines +67 to +84
const lastDotIndex = output.filename.lastIndexOf('.')
const nameWithoutExt =
lastDotIndex > -1
? output.filename.substring(0, lastDotIndex)
: output.filename
const extension =
lastDotIndex > -1
? output.filename.substring(lastDotIndex)
: ''

// If name without extension is still long, truncate it
if (nameWithoutExt.length > 10) {
displayName =
nameWithoutExt.substring(0, 10) +
'...' +
nameWithoutExt.substring(nameWithoutExt.length - 10) +
extension
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: extract this to a helper function then use es-toolkit truncate helper.

Comment on lines +88 to +108
id: `${taskItem.promptId}-${output.nodeId}-${output.filename}`,
name: displayName,
size: 0, // We don't have size info from history
created_at: taskItem.executionStartTimestamp
? new Date(taskItem.executionStartTimestamp).toISOString()
: new Date().toISOString(),
tags: ['output'],
preview_url: output.url,
user_metadata: {
originalFilename: output.filename, // Store original filename
promptId: taskItem.promptId,
nodeId: output.nodeId,
subfolder: output.subfolder,
...(executionTimeInSeconds && {
executionTimeInSeconds
}),
...(output.format && {
format: output.format
}),
...(taskItem.workflow && {
workflow: taskItem.workflow
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: extract this logic to a dedicate mapping function so that:

  • it is more explicit and expressive
  • we don't need the inline && notation
  • we can declare the output type explicitly to prevent future mistakes

Comment on lines +81 to +101
id: `${taskItem.promptId}-${output.nodeId}-${output.filename}`,
name: output.filename,
size: 0,
created_at: executionStartTimestamp
? new Date(executionStartTimestamp).toISOString()
: new Date().toISOString(),
tags: ['output'],
preview_url: output.url,
user_metadata: {
promptId: taskItem.promptId,
nodeId: output.nodeId,
subfolder: output.subfolder,
...(executionTimeInSeconds && {
executionTimeInSeconds
}),
...(output.format && {
format: output.format
}),
...(taskItem.workflow && {
workflow: taskItem.workflow
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@christian-byrne christian-byrne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put the composables in the platform/assets folder and then re-arrange so it's like:

useMediaAssets/
    useAssetsApi.ts
    useInternalFilesApi.ts
    index.ts

then inside the index.ts file you can put:

import { isCloud } from '@/platform/distribution/types'

if (isCloud) { export { useAssetsApi as useMediaAssets } from './useAssetsApi' } 
else { export { useInternalFilesApi as useMediaAssets } from './useInternalFilesApi' }

Then we should also define an interface or abstract class

interface IAssetsProvider {
   loading: ref<boolean>
   error: ref<null | string>
   fetchMediaList: () => UninifedType
}

This way, no other parts of the codebase need to understand the difference in implementations for assets - everything is abstracted behind the UnifiedType and AssetsProvider concepts. This makes refactoring, reasoning about the code, and especially dealing with types considerably easier and more maintainable.

The additional benefit is that for OSS build, the entire useAssetsApi.ts file actually gets tree-shaken.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants