-
Notifications
You must be signed in to change notification settings - Fork 408
fix: dropdown widget fetching output files #6734
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🎭 Playwright Test Results⏰ Completed at: 11/18/2025, 11:27:08 AM UTC 📈 Summary
📊 Test Reports by Browser
🎉 Click on the links above to view detailed test results for each browser configuration. |
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 11/18/2025, 11:17:32 AM UTC 🔗 Links🎉 Your Storybook is ready for review! |
Bundle Size ReportSummary
Category Glance Per-category breakdownApp Entry Points — 3.14 MB (baseline 3.14 MB) • ⚪ 0 BMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 789 kB (baseline 789 kB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 8.03 kB (baseline 8.03 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 1 added / 1 removed Panels & Settings — 307 kB (baseline 307 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 6 added / 6 removed UI Components — 138 kB (baseline 136 kB) • 🔴 +1.97 kBReusable component library chunks
Status: 6 added / 6 removed Data & Services — 12.6 kB (baseline 12.6 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 2 added / 2 removed Utilities & Hooks — 5.87 kB (baseline 5.87 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed Vendor & Third-Party — 5.32 MB (baseline 5.32 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 3.94 MB (baseline 3.94 MB) • ⚪ 0 BBundles that do not match a named category
Status: 20 added / 20 removed |
| }) | ||
|
|
||
| if (!response.ok) { | ||
| console.error('Failed to fetch output files:', response.statusText) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[architecture] medium Priority
Issue: Missing error handling for API failures - store returns empty array on error
Context: Users won't know when output file fetching fails, and dropdown will appear empty
Suggestion: Add error state tracking and user notification for fetch failures
|
|
||
| const outputImages = computed(() => { | ||
| return outputs.value.filter((filename) => { | ||
| const ext = filename.toLowerCase().split('.').pop() || '' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[performance] low Priority
Issue: Inefficient file extension parsing with repeated split operations
Context: Each computed property calls split('.').pop() for every file, causing O(n*m) complexity
Suggestion: Pre-process file extensions once or use more efficient parsing like filename.lastIndexOf('.')
| return ['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp', 'tiff'].includes(ext) | ||
| }) | ||
| }) | ||
| const outputVideos = computed(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[quality] medium Priority
Issue: Code duplication across outputImages, outputVideos, and outputAudios computed properties
Context: Same filtering logic repeated three times, violating DRY principle
Suggestion: Extract to a helper function: getFilesByExtensions(extensions) or use a shared utility
| } | ||
| } | ||
|
|
||
| const fetchOutputFiles = async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[architecture] high Priority
Issue: Potential race condition with promise caching mechanism
Context: If multiple components call fetchOutputFiles() while promise is resolving, they all get the same promise but thePromise.value is set to null in finally block
Suggestion: Consider using a more robust caching mechanism or ensure promise is cleared only after all consumers are notified
| } | ||
| // Fetch output files on component mount | ||
| onMounted(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[performance] medium Priority
Issue: Unconditional output files fetch on component mount regardless of widget type
Context: Every dropdown widget will fetch output files even if not needed (non-media widgets)
Suggestion: Only fetch output files when assetKind indicates media types (image/video/audio)
| import { api } from '@/scripts/api' | ||
| import { useAssetsStore } from '@/stores/assetsStore' | ||
| import { useQueueStore } from '@/stores/queueStore' | ||
| import { useOutputsStore } from '@/stores/outputsStore' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[architecture] critical Priority
Issue: Breaking change - removed queue store dependency without data migration
Context: Old implementation extracted outputs from queueStore.historyTasks but new implementation uses fresh API calls, potentially losing user data
Suggestion: Add migration path or ensure existing workflows aren't broken
| } | ||
| })() | ||
| return outputFiles.map((filename, index) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[architecture] medium Priority
Issue: Simplified output handling may not preserve subfolder structure from original queue-based implementation
Context: Old code constructed paths with subfolder info, new code uses direct filenames from API
Suggestion: Verify API returns files with full path or add subfolder handling
| class="icon-[lucide--circle-off] size-30 text-zinc-500/20" | ||
| /> | ||
| </div> | ||
| <template v-if="items.length === 0"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[quality] low Priority
Issue: Template structure change from div to template is good but missing semantic improvement
Context: Using template wrapper is more performant than div for conditional rendering
Suggestion: Consider adding proper ARIA attributes or role for better accessibility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comprehensive PR Review
This review is generated by Claude. It may not always be accurate, as with human reviewers. If you believe that any of the comments are invalid or incorrect, please state why for each. For others, please implement the changes in one way or another.
Review Summary
PR: fix: dropdown widget fetching output files (#6734)
Impact: 113 additions, 38 deletions across 3 files
Focus: Refactoring dropdown widget to use dedicated outputs store instead of queue store
Issue Distribution
- Critical: 1
- High: 1
- Medium: 4
- Low: 2
Category Breakdown
- Architecture: 5 issues
- Code Quality: 2 issues
- Performance: 1 issues
- Security: 0 issues
Key Findings
Architecture & Design
Critical: The migration from queue store to outputs store represents a breaking change that may lose existing user data or functionality. The old implementation extracted outputs from queue history with subfolder structure, while the new approach uses direct API calls.
High Priority: Race condition potential in the outputs store promise caching mechanism could lead to inconsistent state when multiple components fetch simultaneously.
Medium Priority: The new outputs store lacks proper error handling, which means users won't be notified when API calls fail, resulting in empty dropdowns without explanation.
Performance Impact
The unconditional fetching of output files on component mount for all dropdown widgets is inefficient - this should only happen for media-type widgets. The file extension filtering also uses inefficient string operations that could be optimized.
Code Quality
Several areas need improvement: code duplication in file type filtering logic, inconsistent type handling between string/number widget values and string-only output files, and missing proper error states.
Positive Observations
- Good architectural direction separating concerns with dedicated outputs store
- Improved template structure using template instead of div for conditional rendering
- Clean separation of file types with computed properties
- Proper TypeScript usage with explicit type definitions
References
- ComfyUI Frontend Repository Guide
- Vue 3 Best Practices
- Pinia Store Patterns
Next Steps
- Critical: Address the breaking change concern - ensure data migration path exists
- High: Fix race condition in outputs store promise handling
- Medium: Add proper error handling and user feedback for API failures
- Medium: Optimize performance by conditional fetching based on widget type
- Add tests to verify output file fetching behavior
- Consider backward compatibility implications
Testing Recommendations
- Test dropdown behavior with and without existing output files
- Verify subfolder structure preservation
- Test error scenarios (API failures, network issues)
- Verify performance with large numbers of output files
- Test concurrent widget mounting scenarios
This is a comprehensive automated review. For architectural decisions requiring human judgment, please request additional manual review.
| <div class="absolute inset-0 flex items-center justify-center"> | ||
| <i | ||
| title="No items" | ||
| class="icon-[lucide--circle-off] size-30 text-zinc-500/20" | ||
| /> | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: We also have this
| <template #content> |
(not blocking this PR).
| const outputImages = computed(() => { | ||
| return outputs.value.filter((filename) => { | ||
| const ext = filename.toLowerCase().split('.').pop() || '' | ||
| return ['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp', 'tiff'].includes(ext) | ||
| }) | ||
| }) | ||
| const outputVideos = computed(() => { | ||
| return outputs.value.filter((filename) => { | ||
| const ext = filename.toLowerCase().split('.').pop() || '' | ||
| return ['mp4', 'webm', 'mov', 'avi', 'mkv'].includes(ext) | ||
| }) | ||
| }) | ||
| const outputAudios = computed(() => { | ||
| return outputs.value.filter((filename) => { | ||
| const ext = filename.toLowerCase().split('.').pop() || '' | ||
| return ['mp3', 'ogg', 'wav', 'flac'].includes(ext) | ||
| }) | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it could be optimized to only need a single traversal?
| import { defineStore } from 'pinia' | ||
| import { computed, ref } from 'vue' | ||
|
|
||
| export const useOutputsStore = defineStore('outputs', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/src/platform/assets/composables/media/useMediaAssets.ts
const outputAssets = useMediaAssets('output')
It looks like most of the code in src/stores/outputsStore.ts could be replaced with something like const outputAssets = useMediaAssets('output'). I think it would be better to use the existing store. What do you think?
| outputs.add(annotatedPath) | ||
| } | ||
| }) | ||
| const outputFiles = ((): string[] => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/src/platform/assets/composables/useMediaAssetFiltering.ts#L62
And you can reuse this format utility!
viva-jinyi
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn’t seem to cover both Cloud and OSS. Since internal/files can only fetch output files in the OSS environment, I think it would be better to use useMediaAssets.ts. It’s already implemented to work for both OSS and Cloud, and we can update it later when the new API becomes available.
|
I tried this API, but it doesn't work. I don't know why. you can see this image, so I use the fetch to get the list However, I still did it according to your request. You can see it here #6809, and you can actually run the code to compare their differences.
|

related #5827 (comment)
┆Issue is synchronized with this Notion page by Unito