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

@github-actions
Copy link

github-actions bot commented Oct 17, 2025

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 10/24/2025, 05:58:39 AM UTC

📈 Summary

  • Total Tests: 499
  • Passed: 466 ✅
  • Failed: 0
  • Flaky: 2 ⚠️
  • Skipped: 31 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 457 / ❌ 0 / ⚠️ 2 / ⏭️ 31
  • 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.

@github-actions
Copy link

github-actions bot commented Oct 17, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 10/24/2025, 05:43:24 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

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.

@viva-jinyi viva-jinyi force-pushed the feature/media-asset-sidebar-tab branch from 172b3c3 to be16171 Compare October 20, 2025 06:25
@github-actions
Copy link

github-actions bot commented Oct 20, 2025

Bundle Size Report

Summary

  • Raw size: 12.3 MB baseline 12.3 MB — 🔴 +6.02 kB
  • Gzip: 2.49 MB baseline 2.48 MB — 🔴 +1.34 kB
  • Brotli: 1.96 MB baseline 1.96 MB — 🔴 +691 B
  • Bundles: 56 current • 56 baseline • 16 added / 16 removed

Category Glance
App Entry Points 🔴 +5.69 kB (3.3 MB) · Graph Workspace 🔴 +335 B (713 kB) · Vendor & Third-Party ⚪ 0 B (5.36 MB) · Other ⚪ 0 B (2.58 MB) · Panels & Settings ⚪ 0 B (294 kB) · UI Components ⚪ 0 B (12.3 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.3 MB (baseline 3.29 MB) • 🔴 +5.69 kB _Main entry bundles and manifests_ | File | Before | After | Δ Raw | Δ Gzip | Δ Brotli | | ---------------------------------------- | ------- | ------- | ----------------------- | ---------------------- | ----------------------- | | **assets/index-CMkEzUg0.js** _(new)_ | — | 2.68 MB | 🔴 +2.68 MB | 🔴 +557 kB | 🔴 +422 kB | | ~~assets/index-Bn4mcbF8.js~~ _(removed)_ | 2.68 MB | — | 🟢 -2.68 MB | 🟢 -556 kB | 🟢 -421 kB | | ~~assets/index-DqZ3XyGx.js~~ _(removed)_ | 614 kB | — | 🟢 -614 kB | 🟢 -114 kB | 🟢 -90.2 kB | | **assets/index-hrrLJHxV.js** _(new)_ | — | 614 kB | 🔴 +614 kB | 🔴 +114 kB | 🔴 +90.1 kB |

Status: 2 added / 2 removed

Graph Workspace — 713 kB (baseline 712 kB) • 🔴 +335 B _Graph editor runtime, canvas, workflow orchestration_ | File | Before | After | Δ Raw | Δ Gzip | Δ Brotli | | -------------------------------------------- | ------ | ------ | ---------------------- | ---------------------- | ---------------------- | | **assets/GraphView-bMJLL44c.js** _(new)_ | — | 713 kB | 🔴 +713 kB | 🔴 +140 kB | 🔴 +108 kB | | ~~assets/GraphView-zxChLZ3d.js~~ _(removed)_ | 712 kB | — | 🟢 -712 kB | 🟢 -140 kB | 🟢 -108 kB |

Status: 1 added / 1 removed

Views & Navigation — 8.15 kB (baseline 8.15 kB) • ⚪ 0 B _Top-level views, pages, and routed surfaces_ | File | Before | After | Δ Raw | Δ Gzip | Δ Brotli | | ------------------------------------------------- | ------- | ------- | ----------------------- | ----------------------- | ----------------------- | | **assets/UserSelectView-CFaTo5_Q.js** _(new)_ | — | 8.15 kB | 🔴 +8.15 kB | 🔴 +2.46 kB | 🔴 +2.16 kB | | ~~assets/UserSelectView-DIulM0up.js~~ _(removed)_ | 8.15 kB | — | 🟢 -8.15 kB | 🟢 -2.47 kB | 🟢 -2.15 kB |

Status: 1 added / 1 removed

Panels & Settings — 294 kB (baseline 294 kB) • ⚪ 0 B _Configuration panels, inspectors, and settings screens_ | File | Before | After | Δ Raw | Δ Gzip | Δ Brotli | | ---------------------------------------------------- | ------- | ------- | ----------------------- | ----------------------- | ----------------------- | | **assets/CreditsPanel-Bo18EkkI.js** _(new)_ | — | 22.1 kB | 🔴 +22.1 kB | 🔴 +5.28 kB | 🔴 +4.6 kB | | ~~assets/CreditsPanel-IqMyc7Du.js~~ _(removed)_ | 22.1 kB | — | 🟢 -22.1 kB | 🟢 -5.28 kB | 🟢 -4.6 kB | | **assets/KeybindingPanel-bD0vtzzz.js** _(new)_ | — | 15.2 kB | 🔴 +15.2 kB | 🔴 +3.76 kB | 🔴 +3.31 kB | | ~~assets/KeybindingPanel-iNFLHeIf.js~~ _(removed)_ | 15.2 kB | — | 🟢 -15.2 kB | 🟢 -3.76 kB | 🟢 -3.31 kB | | **assets/ExtensionPanel-DbxrYX85.js** _(new)_ | — | 12.1 kB | 🔴 +12.1 kB | 🔴 +2.83 kB | 🔴 +2.47 kB | | ~~assets/ExtensionPanel-OrjbJS0F.js~~ _(removed)_ | 12.1 kB | — | 🟢 -12.1 kB | 🟢 -2.83 kB | 🟢 -2.47 kB | | **assets/AboutPanel-CkwC-JI6.js** _(new)_ | — | 10.3 kB | 🔴 +10.3 kB | 🔴 +2.66 kB | 🔴 +2.33 kB | | ~~assets/AboutPanel-DZeSgxLV.js~~ _(removed)_ | 10.3 kB | — | 🟢 -10.3 kB | 🟢 -2.66 kB | 🟢 -2.35 kB | | ~~assets/ServerConfigPanel-BMgotDNq.js~~ _(removed)_ | 8.2 kB | — | 🟢 -8.2 kB | 🟢 -2.16 kB | 🟢 -1.89 kB | | **assets/ServerConfigPanel-C7BWke8u.js** _(new)_ | — | 8.2 kB | 🔴 +8.2 kB | 🔴 +2.16 kB | 🔴 +1.9 kB | | ~~assets/UserPanel-hw7WxpaD.js~~ _(removed)_ | 7.91 kB | — | 🟢 -7.91 kB | 🟢 -2.06 kB | 🟢 -1.79 kB | | **assets/UserPanel-jKu_xRdT.js** _(new)_ | — | 7.91 kB | 🔴 +7.91 kB | 🔴 +2.06 kB | 🔴 +1.8 kB | | assets/settings-B-df0dZe.js | 20.7 kB | 20.7 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/settings-CI6OKvJn.js | 22.9 kB | 22.9 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/settings-CXGVj_nD.js | 24.5 kB | 24.5 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/settings-DfQ6dSJj.js | 31.6 kB | 31.6 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/settings-DJ2QgDzm.js | 25.2 kB | 25.2 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/settings-DRNLPMG6.js | 23.7 kB | 23.7 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/settings-DVVycxDc.js | 19.9 kB | 19.9 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/settings-G6Dybj1b.js | 24.1 kB | 24.1 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/settings-M6_GZccG.js | 26 kB | 26 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B |

Status: 6 added / 6 removed

UI Components — 12.3 kB (baseline 12.3 kB) • ⚪ 0 B _Reusable component library chunks_ | File | Before | After | Δ Raw | Δ Gzip | Δ Brotli | | ----------------------------------------------------------------- | ------- | ------- | ----------------------- | ----------------------- | ----------------------- | | **assets/ComfyQueueButton-Cr1FF2Xt.js** _(new)_ | — | 11.1 kB | 🔴 +11.1 kB | 🔴 +2.76 kB | 🔴 +2.44 kB | | ~~assets/ComfyQueueButton-MMCxJeIn.js~~ _(removed)_ | 11.1 kB | — | 🟢 -11.1 kB | 🟢 -2.76 kB | 🟢 -2.44 kB | | assets/UserAvatar.vue_vue_type_script_setup_true_lang-C9bSkTC5.js | 1.12 kB | 1.12 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B |

Status: 1 added / 1 removed

Data & Services — 10 kB (baseline 10 kB) • ⚪ 0 B _Stores, services, APIs, and repositories_ | File | Before | After | Δ Raw | Δ Gzip | Δ Brotli | | ---------------------------------------------------- | ------- | ------- | ----------------------- | ----------------------- | ----------------------- | | ~~assets/keybindingService-BuTi_yvU.js~~ _(removed)_ | 7.21 kB | — | 🟢 -7.21 kB | 🟢 -1.75 kB | 🟢 -1.51 kB | | **assets/keybindingService-CFOCX-xD.js** _(new)_ | — | 7.21 kB | 🔴 +7.21 kB | 🔴 +1.75 kB | 🔴 +1.5 kB | | ~~assets/serverConfigStore-CvX_HMTJ.js~~ _(removed)_ | 2.79 kB | — | 🟢 -2.79 kB | 🟢 -891 B | 🟢 -777 B | | **assets/serverConfigStore-DGtDMYK2.js** _(new)_ | — | 2.79 kB | 🔴 +2.79 kB | 🔴 +889 B | 🔴 +775 B |

Status: 2 added / 2 removed

Utilities & Hooks — 1.07 kB (baseline 1.07 kB) • ⚪ 0 B _Helpers, composables, and utility bundles_ | File | Before | After | Δ Raw | Δ Gzip | Δ Brotli | | --------------------------- | ------- | ------- | ------------------ | ------------------ | ------------------ | | assets/mathUtil-CTARWQ-l.js | 1.07 kB | 1.07 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B |
Vendor & Third-Party — 5.36 MB (baseline 5.36 MB) • ⚪ 0 B _External libraries and shared vendor chunks_ | File | Before | After | Δ Raw | Δ Gzip | Δ Brotli | | ------------------------------------------------ | ------- | ------- | ----------------------- | ----------------------- | ----------------------- | | **assets/vendor-other-Cf3diXgO.js** _(new)_ | — | 3.22 MB | 🔴 +3.22 MB | 🔴 +685 kB | 🔴 +549 kB | | ~~assets/vendor-other-EuL9bHKm.js~~ _(removed)_ | 3.22 MB | — | 🟢 -3.22 MB | 🟢 -685 kB | 🟢 -549 kB | | **assets/vendor-tiptap-CfWvY-eC.js** _(new)_ | — | 232 kB | 🔴 +232 kB | 🔴 +45.7 kB | 🔴 +37.7 kB | | ~~assets/vendor-tiptap-DY0_3CMM.js~~ _(removed)_ | 232 kB | — | 🟢 -232 kB | 🟢 -45.7 kB | 🟢 -37.7 kB | | **assets/vendor-vue-D_foLepl.js** _(new)_ | — | 92.4 kB | 🔴 +92.4 kB | 🔴 +23.9 kB | 🔴 +20.8 kB | | ~~assets/vendor-vue-Di9L6lvm.js~~ _(removed)_ | 92.4 kB | — | 🟢 -92.4 kB | 🟢 -23.9 kB | 🟢 -20.8 kB | | assets/vendor-primevue-PESgPnbc.js | 517 B | 517 B | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/vendor-visualization-BEfdbjRw.js | 1.82 MB | 1.82 MB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B |

Status: 3 added / 3 removed

Other — 2.58 MB (baseline 2.58 MB) • ⚪ 0 B _Bundles that do not match a named category_ | File | Before | After | Δ Raw | Δ Gzip | Δ Brotli | | --------------------------- | ------- | ------- | ------------------ | ------------------ | ------------------ | | assets/commands-B2KZRBmX.js | 15.1 kB | 15.1 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/commands-Bw-ckyga.js | 13.9 kB | 13.9 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/commands-C_NmM85I.js | 13.8 kB | 13.8 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/commands-CuozCW4W.js | 14 kB | 14 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/commands-DGfVUJCR.js | 16.2 kB | 16.2 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/commands-dOJNDogK.js | 14.5 kB | 14.5 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/commands-DwiE551e.js | 14.7 kB | 14.7 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/commands-Fw7mvqSy.js | 13.1 kB | 13.1 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/commands-FXnO1W4Q.js | 13.2 kB | 13.2 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/main-Bgu6_Hvd.js | 59.5 kB | 59.5 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/main-Bv0L0qvp.js | 93 kB | 93 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/main-C3Doz3n_.js | 67.6 kB | 67.6 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/main-C7eBl607.js | 70.7 kB | 70.7 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/main-CHiV9ds2.js | 76.4 kB | 76.4 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/main-CIc79Nts.js | 68.5 kB | 68.5 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/main-DK5LmuBm.js | 58.8 kB | 58.8 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/main-J1nit7cj.js | 66.3 kB | 66.3 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/main-W97XgvAQ.js | 80.4 kB | 80.4 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/nodeDefs-BePSqkA4.js | 195 kB | 195 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/nodeDefs-BfT7dJcF.js | 204 kB | 204 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/nodeDefs-BiAtoiXc.js | 194 kB | 194 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/nodeDefs-CDfbduPY.js | 219 kB | 219 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/nodeDefs-CDurg_KW.js | 197 kB | 197 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/nodeDefs-CE-vG3RG.js | 182 kB | 182 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/nodeDefs-DAwVV156.js | 200 kB | 200 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/nodeDefs-DexhCMEi.js | 233 kB | 233 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B | | assets/nodeDefs-kTrYLFPK.js | 184 kB | 184 kB | ⚪ 0 B | ⚪ 0 B | ⚪ 0 B |

viva-jinyi added a commit that referenced this pull request Oct 20, 2025
- Move composables to platform/assets directory structure
- Extract interface-based abstraction (IAssetsProvider) for cloud/internal implementations
- Move constants to module scope to avoid re-initialization
- Extract helper functions (truncateFilename, assetMappers) for reusability
- Rename getMediaTypeFromFilename to return singular form (image/video/audio)
- Add deprecated plural version for backward compatibility
- Add comprehensive test coverage for new utility functions

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

Co-Authored-By: Claude <[email protected]>
viva-jinyi added a commit that referenced this pull request Oct 20, 2025
- Move composables to platform/assets directory structure
- Extract interface-based abstraction (IAssetsProvider) for cloud/internal implementations
- Move constants to module scope to avoid re-initialization
- Extract helper functions (truncateFilename, assetMappers) for reusability
- Rename getMediaTypeFromFilename to return singular form (image/video/audio)
- Add deprecated plural version for backward compatibility
- Add comprehensive test coverage for new utility functions

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

Co-Authored-By: Claude <[email protected]>
@viva-jinyi viva-jinyi force-pushed the feature/media-asset-sidebar-tab branch from f6b8dbb to 308f864 Compare October 20, 2025 08:50
@viva-jinyi viva-jinyi marked this pull request as ready for review October 20, 2025 08:50
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Oct 20, 2025
viva-jinyi added a commit that referenced this pull request Oct 22, 2025
- Move composables to platform/assets directory structure
- Extract interface-based abstraction (IAssetsProvider) for cloud/internal implementations
- Move constants to module scope to avoid re-initialization
- Extract helper functions (truncateFilename, assetMappers) for reusability
- Rename getMediaTypeFromFilename to return singular form (image/video/audio)
- Add deprecated plural version for backward compatibility
- Add comprehensive test coverage for new utility functions

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

Co-Authored-By: Claude <[email protected]>
@viva-jinyi viva-jinyi force-pushed the feature/media-asset-sidebar-tab branch from bee62d3 to 61eed48 Compare October 22, 2025 02:08
viva-jinyi added a commit that referenced this pull request Oct 22, 2025
- Move composables to platform/assets directory structure
- Extract interface-based abstraction (IAssetsProvider) for cloud/internal implementations
- Move constants to module scope to avoid re-initialization
- Extract helper functions (truncateFilename, assetMappers) for reusability
- Rename getMediaTypeFromFilename to return singular form (image/video/audio)
- Add deprecated plural version for backward compatibility
- Add comprehensive test coverage for new utility functions

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

Co-Authored-By: Claude <[email protected]>
@viva-jinyi viva-jinyi force-pushed the feature/media-asset-sidebar-tab branch from ac427e5 to bd23ccc Compare October 22, 2025 03:06
viva-jinyi added a commit that referenced this pull request Oct 22, 2025
- Move composables to platform/assets directory structure
- Extract interface-based abstraction (IAssetsProvider) for cloud/internal implementations
- Move constants to module scope to avoid re-initialization
- Extract helper functions (truncateFilename, assetMappers) for reusability
- Rename getMediaTypeFromFilename to return singular form (image/video/audio)
- Add deprecated plural version for backward compatibility
- Add comprehensive test coverage for new utility functions

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

Co-Authored-By: Claude <[email protected]>
@viva-jinyi viva-jinyi force-pushed the feature/media-asset-sidebar-tab branch from 97d6a6f to 6769687 Compare October 22, 2025 12:51
viva-jinyi added a commit that referenced this pull request Oct 22, 2025
- Move composables to platform/assets directory structure
- Extract interface-based abstraction (IAssetsProvider) for cloud/internal implementations
- Move constants to module scope to avoid re-initialization
- Extract helper functions (truncateFilename, assetMappers) for reusability
- Rename getMediaTypeFromFilename to return singular form (image/video/audio)
- Add deprecated plural version for backward compatibility
- Add comprehensive test coverage for new utility functions

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

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

@DrJKL DrJKL left a comment

Choose a reason for hiding this comment

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

Reviewed from the bottom up 🙃

@christian-byrne christian-byrne added the claude-review Add to trigger a PR code review from Claude Code label Oct 22, 2025
})
// Override the url getter to use asset.preview_url
Object.defineProperty(resultItem, 'url', {
Copy link

Choose a reason for hiding this comment

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

[security] high Priority

Issue: Direct DOM manipulation vulnerability - Using object.defineProperty to dynamically override url getter creates potential XSS vector
Context: Overriding object getters at runtime can lead to unexpected behavior and security issues if the asset data is not sanitized
Suggestion: Use a computed property or safer mapping approach instead of defineProperty to avoid runtime property manipulation

viva-jinyi and others added 12 commits October 24, 2025 14:41
…truncation

- Add file format tags (PNG, JPG, etc.) for input directory assets
- Truncate long filenames in input assets with originalFilename preservation
- Show file format chip independently from duration chip
- Fix conditional display logic for chips in MediaAssetCard
- Apply consistent filename truncation (20 chars) across cloud assets

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

Co-Authored-By: Claude <[email protected]>
- Add optional includePublic parameter (defaults to true) to getAssetsByTag
- Exclude public assets for media assets in sidebar by passing false
- Use URLSearchParams for cleaner query string construction

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

Co-Authored-By: Claude <[email protected]>
- Implement factory pattern with useAsyncState for composables
- Add internationalization support for aria-labels
- Remove deprecated functions and improve type safety
- Simplify component logic with VueUse patterns
- Add comprehensive edge case tests
## Summary
- Extract sidebar template into reusable AssetSidebarTemplate component
- Replace PrimeVue Tabs with TextButton for better visual consistency  
- Improve job detail view header layout with better spacing

## Changes
- Created `AssetSidebarTemplate.vue` as a reusable template component
- Replaced PrimeVue Tabs with TextButton components for tab navigation
- Added i18n translation key for "Back to all assets" button
- Improved spacing and layout in job detail view header
- Maintained all existing functionality while cleaning up template
structure

## Test Plan
- [ ] Verify tab switching between Imported and Generated tabs works
correctly
- [ ] Test job detail view displays properly with Job ID and execution
time
- [ ] Confirm "Back to all assets" button returns to main view
- [ ] Check that all existing media asset features remain functional
- [ ] Verify UI consistency with other sidebar tabs


[screen-capture.webm](https://github.com/user-attachments/assets/4ed192e1-a9f7-4fc1-a41e-f732741dd55d)
- Create AssetsStore following QueueStore pattern for history-based assets
- Use useAsyncState for async state management (loading/error handling)
- Support both cloud and local environments (via isCloud flag)
- Auto-update history assets on status events in GraphView
- Refactor useMediaAssets composables to use AssetsStore
- Remove deprecated getMediaKindFromFilename function (no usages found)
- Define MediaType using const assertion pattern
- Apply as const to extension arrays with type guards
- Use type assertions for type-safe includes checks
- Integrate AssetsStore with useNodeImageUpload
- Automatically update input assets when uploading to input folder
- Support drag & drop, paste, and file selection

Solution 2 complete: Real-time assets sync with upload triggers
Related: #6112 code review feedback applied
- Integrate AssetsStore with WidgetSelectDropdown component
- Auto-refresh input assets after file upload via dropdown widget
- Ensures Assets sidebar stays in sync with uploaded files

Part of reactive assets update implementation for better UX
@viva-jinyi viva-jinyi force-pushed the feature/media-asset-sidebar-tab branch from 21df448 to 4eac455 Compare October 24, 2025 05:41
Comment on lines +10 to +12
const props = defineProps<{
modelValue: string
}>()
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this use defineModel?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't usually like composables that aren't using refs or other composables.
Could this be a constant?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't usually like composables that aren't using refs or other composables.

Can you explain reasoning to help others learn?

}
const handleOutputCountClick = () => {
emit('output-count-click')
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this not being consumed yet?

:title="asset.name"
>
{{ fileName }}
{{ truncateFilename(fileName) }}
Copy link
Contributor

Choose a reason for hiding this comment

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

It feels like there's a lot of duplication across these, could they be joined into a single component?

}>()
const emit = defineEmits<{
'image-loaded': [width: number, height: number]
Copy link
Contributor

Choose a reason for hiding this comment

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

If it weren't in the litegraph section, I'd say you should use the Size type 🫤

Comment on lines +127 to +140
return {
// States
inputAssets,
historyAssets,
inputLoading,
historyLoading,
inputError,
historyError,
isLoading,

// Actions
updateInputs,
updateHistory,
update
Copy link
Contributor

Choose a reason for hiding this comment

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

I like this store, just to check, all of these are used within this PR?

Comment on lines +28 to +35
/**
* Check if a string is a valid UUID (any version)
* @param str - The string to check
* @returns true if the string is a valid UUID
*/
export function isValidUuid(str: string): boolean {
return uuidValidate(str)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we just use the uuid method in place wherever this is being called?

* @param str - The string to extract UUID from
* @returns The extracted UUID or null if not found
*/
export function extractUuidFromString(str: string): string | null {
Copy link
Contributor

Choose a reason for hiding this comment

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

What strings do we have that start with a UUID but contain other text?


describe('getMediaTypeFromFilename', () => {
describe('image files', () => {
it('should identify image extensions correctly', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Did I already recommend it.for?

@christian-byrne
Copy link
Contributor

Also, the bugs that occurred in #2125 no longer happen.

I can reproduce it on this branch. Steps:

  1. Generate some images
  2. Open Gallery with an image in the middle of the list
  3. Use Ctrl+Enter to queue a job while the gallery is still open
  4. the gallery changes automatically (it shoudln't)

@JorgeR81
Copy link

JorgeR81 commented Oct 26, 2025

This looks nice, but it would be more useful if it had a search field.
If you have more than 1000 images, it's not practical to use just by scrolling images.

You could add ( to each image ), other information useful for the search:

  • the name of the workflow in which image was generated
  • The node's ID number in which image was generated

This last parameter is useful because complex workflows create lots of images ( e.g. Control Nets, multiple samplers, upscalers ), but in the gallery, we may only want to look at the final image.

I already asked for something similar for Queue sidebar, a while algo:

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

Labels

claude-review Add to trigger a PR code review from Claude Code size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The queue windows are covering the generated images with information, that's not really needed.

5 participants