Skip to content

Conversation

@Myestery
Copy link
Collaborator

@Myestery Myestery commented Dec 6, 2025

Summary

  • Filter out .DS_Store and _output_images_will_be_put_here placeholder files from remote widget file lists
  • Fixes the "Load Image (from Outputs)" node always showing an image load error on macOS

Problem

On macOS, the .DS_Store file (a hidden system file automatically created by Finder) was being included in the output folder file list returned by /internal/files/output. When the "Load Image (from Outputs)" node refreshed its file list, .DS_Store would be selected as the first file, causing the image preview to fail since it's not a valid image.

Solution

Added a filter in useRemoteWidget.ts to exclude .DS_Store and the _output_images_will_be_put_here placeholder file from file lists returned by remote widget API calls.

Test plan

  • Create a "Load Image (from Outputs)" node on macOS
  • Click the refresh button
  • Verify no image load error appears
  • Verify valid output images are displayed correctly

Before

Screenshot 2025-12-06 at 04 10 12

After

Screen.Recording.2025-12-06.at.04.10.33.mov

┆Issue is synchronized with this Notion page by Unito

Filter out .DS_Store and placeholder files from remote widget file lists.

On macOS, the .DS_Store file (a hidden system file created by Finder) was
being included in the output folder file list. When the "Load Image (from
Outputs)" node refreshed, it would select .DS_Store as the first file,
causing the image preview to fail with an error since .DS_Store is not a
valid image file.

This fix filters out .DS_Store and the _output_images_will_be_put_here
placeholder file from file lists returned by remote widget API calls.
@Myestery Myestery requested a review from a team as a code owner December 6, 2025 02:57
@dosubot dosubot bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Dec 6, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 6, 2025

📝 Walkthrough

Walkthrough

Introduces a filtering mechanism to useRemoteWidget composable that removes system and temporary file references from array responses. A new filterFileList function prunes arrays by excluding items matching .DS_Store or _output_images_will_be_put_here patterns, and fetchData applies this filter to array data returned from remote sources.

Changes

Cohort / File(s) Summary
File filtering for remote widget data
src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
Added filterFileList function to remove system and temporary file references from array responses; modified fetchData to filter array data through this function while leaving non-array responses unchanged
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/load-image-output-ds-store

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 6, 2025

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 12/06/2025, 03:23:54 AM UTC

📈 Summary

  • Total Tests: 490
  • Passed: 472 ✅
  • Failed: 0
  • Flaky: 8 ⚠️
  • Skipped: 10 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 463 / ❌ 0 / ⚠️ 8 / ⏭️ 10
  • 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 Dec 6, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 12/06/2025, 03:15:21 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Dec 6, 2025

Bundle Size Report

Summary

  • Raw size: 17 MB baseline 17 MB — 🔴 +416 B
  • Gzip: 3.38 MB baseline 3.38 MB — 🔴 +177 B
  • Brotli: 2.59 MB baseline 2.59 MB — 🟢 -73 B
  • Bundles: 97 current • 97 baseline • 37 added / 37 removed

Category Glance
App Entry Points 🔴 +416 B (3.2 MB) · Vendor & Third-Party ⚪ 0 B (8.56 MB) · Other ⚪ 0 B (3.81 MB) · Graph Workspace ⚪ 0 B (974 kB) · Panels & Settings ⚪ 0 B (298 kB) · UI Components ⚪ 0 B (177 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.2 MB (baseline 3.2 MB) • 🔴 +416 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-DEEvwYw6.js (new) 2.97 MB 🔴 +2.97 MB 🔴 +619 kB 🔴 +471 kB
assets/index-Bnx48smV.js (removed) 2.97 MB 🟢 -2.97 MB 🟢 -619 kB 🟢 -471 kB
assets/index-B1EM7DRC.js (new) 223 kB 🔴 +223 kB 🔴 +47.6 kB 🔴 +39.3 kB
assets/index-CfA7BP6W.js (removed) 223 kB 🟢 -223 kB 🟢 -47.6 kB 🟢 -39.3 kB
assets/index-COoLxe-q.js (removed) 345 B 🟢 -345 B 🟢 -244 B 🟢 -234 B
assets/index-p5hVLsDq.js (new) 345 B 🔴 +345 B 🔴 +246 B 🔴 +200 B

Status: 3 added / 3 removed

Graph Workspace — 974 kB (baseline 974 kB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-vbNvWMoP.js (removed) 974 kB 🟢 -974 kB 🟢 -188 kB 🟢 -144 kB
assets/GraphView-Zsmlax0v.js (new) 974 kB 🔴 +974 kB 🔴 +188 kB 🔴 +144 kB

Status: 1 added / 1 removed

Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/UserSelectView-BMrBnBia.js (removed) 6.54 kB 🟢 -6.54 kB 🟢 -2.14 kB 🟢 -1.9 kB
assets/UserSelectView-CBc3tTS0.js (new) 6.54 kB 🔴 +6.54 kB 🔴 +2.14 kB 🔴 +1.9 kB

Status: 1 added / 1 removed

Panels & Settings — 298 kB (baseline 298 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CreditsPanel-B-zRAfUO.js (removed) 21.4 kB 🟢 -21.4 kB 🟢 -5.15 kB 🟢 -4.5 kB
assets/CreditsPanel-BgduTTOz.js (new) 21.4 kB 🔴 +21.4 kB 🔴 +5.15 kB 🔴 +4.5 kB
assets/KeybindingPanel-CqJ8O7O-.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.42 kB 🔴 +3.01 kB
assets/KeybindingPanel-DlaxnNYL.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.42 kB 🟢 -3.02 kB
assets/ExtensionPanel-ByT-evo4.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.58 kB 🔴 +2.26 kB
assets/ExtensionPanel-Ca1jpde5.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.57 kB 🟢 -2.26 kB
assets/AboutPanel-BALzxTfj.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/AboutPanel-DIXId4Uy.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/ServerConfigPanel-DZEepYbY.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -1.83 kB 🟢 -1.63 kB
assets/ServerConfigPanel-DZLN9HjR.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +1.83 kB 🔴 +1.63 kB
assets/UserPanel-BRZ50cmF.js (removed) 6.23 kB 🟢 -6.23 kB 🟢 -1.72 kB 🟢 -1.51 kB
assets/UserPanel-EV-49eEc.js (new) 6.23 kB 🔴 +6.23 kB 🔴 +1.72 kB 🔴 +1.51 kB
assets/settings-BhbWhsRg.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BXTtSH4O.js 33.3 kB 33.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C9Pzn-NG.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CCy2fA_h.js 27.3 kB 27.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CQpqEFfl.js 26.6 kB 26.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DHcnxypw.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DhFTK9fY.js 25.1 kB 25.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DlT4t_ui.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DRgSrIdD.js 24.2 kB 24.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-tjkeqiZq.js 21.1 kB 21.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

UI Components — 177 kB (baseline 177 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Load3D.vue_vue_type_script_setup_true_lang-Cc1-3pLx.js (new) 53.9 kB 🔴 +53.9 kB 🔴 +8.52 kB 🔴 +7.31 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-DQ_HrzWR.js (removed) 53.9 kB 🟢 -53.9 kB 🟢 -8.52 kB 🟢 -7.31 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-DAhRvtDs.js (removed) 47.9 kB 🟢 -47.9 kB 🟢 -10.3 kB 🟢 -8.97 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-DBN8Ea3p.js (new) 47.9 kB 🔴 +47.9 kB 🔴 +10.3 kB 🔴 +8.97 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-BRJ1SfbA.js (removed) 46.9 kB 🟢 -46.9 kB 🟢 -10.5 kB 🟢 -9.17 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-DRVuOLuf.js (new) 46.9 kB 🔴 +46.9 kB 🔴 +10.5 kB 🔴 +9.19 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-DXpZlK5j.js (new) 12.9 kB 🔴 +12.9 kB 🔴 +3.37 kB 🔴 +2.97 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-MxRmVJJb.js (removed) 12.9 kB 🟢 -12.9 kB 🟢 -3.37 kB 🟢 -2.97 kB
assets/ComfyQueueButton-Byp-beJY.js (removed) 8.44 kB 🟢 -8.44 kB 🟢 -2.47 kB 🟢 -2.21 kB
assets/ComfyQueueButton-rr0EKLHc.js (new) 8.44 kB 🔴 +8.44 kB 🔴 +2.48 kB 🔴 +2.21 kB
assets/MediaTitle.vue_vue_type_script_setup_true_lang-BD6J32yx.js (removed) 897 B 🟢 -897 B 🟢 -503 B 🟢 -440 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-CoAx5xyL.js (new) 897 B 🔴 +897 B 🔴 +504 B 🔴 +445 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-BRkyALVq.js 1.34 kB 1.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-BxCujTML.js 2.04 kB 2.04 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-OWi66h7l.js 2.26 kB 2.26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-CdBEVHmm.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.83 kB 🟢 -1.58 kB
assets/keybindingService-DqX-jtTT.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/audioService-C7sfYvWi.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +962 B 🔴 +822 B
assets/audioService-Lb0O0grF.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -962 B 🟢 -828 B
assets/serverConfigStore-DoucbuhB.js 2.83 kB 2.83 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 2 added / 2 removed

Utilities & Hooks — 2.94 kB (baseline 2.94 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-Bb01hnDP.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +652 B 🔴 +543 B
assets/audioUtils-U1Iis3N8.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -650 B 🟢 -549 B
assets/mathUtil-CTARWQ-l.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeFilterUtil-CXKCRJ-m.js 460 B 460 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 1 added / 1 removed

Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-chart-AOHFmsOW.js 452 kB 452 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-CtZJbx9q.js 3.98 MB 3.98 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-BeMfDZy5.js 1.96 MB 1.96 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-aR6ntw5X.js 1.37 MB 1.37 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-CZ8p6YbU.js 232 kB 232 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-CM5juDXV.js 160 kB 160 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-BZLod3g9.js 407 kB 407 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 3.81 MB (baseline 3.81 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WidgetRecordAudio-DgXZUyUv.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.24 kB 🔴 +4.64 kB
assets/WidgetRecordAudio-zerDQWvO.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.24 kB 🟢 -4.63 kB
assets/AudioPreviewPlayer-BcnVrFTr.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.4 kB 🟢 -3.04 kB
assets/AudioPreviewPlayer-BjKLWLU-.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.4 kB 🔴 +3.04 kB
assets/WidgetGalleria-DCu-h-em.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.44 kB 🟢 -1.3 kB
assets/WidgetGalleria-wI3sNtpk.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.45 kB 🔴 +1.31 kB
assets/WidgetColorPicker-CBLCyrPG.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetColorPicker-fXd-_PJM.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetMarkdown-B481woZw.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.12 kB
assets/WidgetMarkdown-DlFQbpIS.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetTextarea-D2DEDEvS.js (removed) 2.93 kB 🟢 -2.93 kB 🟢 -1.17 kB 🟢 -1.03 kB
assets/WidgetTextarea-sCJtROs5.js (new) 2.93 kB 🔴 +2.93 kB 🔴 +1.17 kB 🔴 +1.03 kB
assets/WidgetAudioUI-CFnhuPhn.js (removed) 2.85 kB 🟢 -2.85 kB 🟢 -1.16 kB 🟢 -1.06 kB
assets/WidgetAudioUI-CxmBSvdb.js (new) 2.85 kB 🔴 +2.85 kB 🔴 +1.17 kB 🔴 +1.06 kB
assets/WidgetInputText-CeGd5hkE.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +918 B 🔴 +849 B
assets/WidgetInputText-Datpe-SJ.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -916 B 🟢 -847 B
assets/MediaImageBottom-DcN4sfVu.js (new) 1.57 kB 🔴 +1.57 kB 🔴 +741 B 🔴 +648 B
assets/MediaImageBottom-kfos-6HS.js (removed) 1.57 kB 🟢 -1.57 kB 🟢 -743 B 🟢 -648 B
assets/MediaAudioBottom-D-Kb_jTe.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +742 B 🔴 +656 B
assets/MediaAudioBottom-DAiQJ7d1.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -742 B 🟢 -663 B
assets/MediaVideoBottom-BPZWOV8N.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -741 B 🟢 -660 B
assets/MediaVideoBottom-CE9H9hZ7.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +741 B 🔴 +657 B
assets/Media3DBottom-BPeJ5hl7.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -733 B 🟢 -656 B
assets/Media3DBottom-CmpzFfBp.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +732 B 🔴 +654 B
assets/Media3DTop-BV2QXTFM.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +767 B 🔴 +647 B
assets/Media3DTop-kL8vgdz7.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -765 B 🟢 -651 B
assets/WidgetSelect-C-RAluq6.js (removed) 655 B 🟢 -655 B 🟢 -342 B 🟢 -287 B
assets/WidgetSelect-DrT9ntQr.js (new) 655 B 🔴 +655 B 🔴 +343 B 🔴 +285 B
assets/WidgetInputNumber-CcZ1DFM3.js (removed) 595 B 🟢 -595 B 🟢 -328 B 🟢 -273 B
assets/WidgetInputNumber-COZlSa1M.js (new) 595 B 🔴 +595 B 🔴 +329 B 🔴 +274 B
assets/Load3D-C-Vxvbw4.js (removed) 424 B 🟢 -424 B 🟢 -265 B 🟢 -223 B
assets/Load3D-D1CcrjGt.js (new) 424 B 🔴 +424 B 🔴 +265 B 🔴 +231 B
assets/WidgetLegacy-CMkmOVoM.js (new) 364 B 🔴 +364 B 🔴 +237 B 🔴 +193 B
assets/WidgetLegacy-CvsSbApO.js (removed) 364 B 🟢 -364 B 🟢 -236 B 🟢 -194 B
assets/commands-_s-RvhJR.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BuUILW6P.js 13 kB 13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BV4R6fLx.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BWp4HdfU.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CLwPdnT6.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CWMchBmd.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DazTQhtc.js 12.9 kB 12.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DmWrOe93.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DwiH7Kr6.js 13.8 kB 13.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-mS3LCNPn.js 14.5 kB 14.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B1JflQcI.js 72.2 kB 72.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B2lyXe48.js 114 kB 114 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B9XEQ-pc.js 94 kB 94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BErKFzc-.js 73.1 kB 73.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Bf7Tze-u.js 83.4 kB 83.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BhGMcO4Q.js 84.3 kB 84.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CPZUloNQ.js 99 kB 99 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cw9RZWRY.js 89 B 89 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dva0z-T2.js 86.5 kB 86.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-un0K9wDS.js 81.8 kB 81.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-CxoCWIb1.js 1.46 kB 1.46 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-Dfil_e4_.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-hmtA3SJn.js 2.76 kB 2.76 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-8e6QYQW0.js 283 kB 283 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-A_9dx4yn.js 304 kB 304 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BbD3HDi7.js 307 kB 307 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BOJhIPft.js 369 kB 369 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bw_Jitw_.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-C-Pw33mW.js 317 kB 317 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-ChLyG0UJ.js 285 kB 285 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CUVPxA4l.js 342 kB 342 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Dx5Y4xrW.js 310 kB 310 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-JqO5mNmW.js 306 kB 306 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-wbQtTR0r.js 2.48 kB 2.48 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-LIXuaXNa.js 2.21 kB 2.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-DOfuzDiX.js 1.58 kB 1.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 17 added / 17 removed

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cde49d5 and 61c566e.

📒 Files selected for processing (1)
  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript exclusively; no new JavaScript code

Files:

  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,vue}: Use camelCase for variable and function names
Indent with 2 spaces (see .prettierrc)
Use single quotes for strings (see .prettierrc)
No trailing semicolons (see .prettierrc)
Maximum line width of 80 characters (see .prettierrc)
Sort and group imports by plugin (run pnpm format before committing)
Never use any type; use proper TypeScript types instead
Never use as any type assertions; fix the underlying type issue instead
Avoid code comments unless absolutely necessary; write expressive, self-documenting code instead
When writing new code, ask if there is a simpler way to introduce the same functionality; if yes, choose the simpler approach
Use refactoring to make complex code simpler
Use es-toolkit for utility functions
Use Vite for fast development and building
Implement proper error handling
Write tests for all changes, especially bug fixes to catch future regressions

Files:

  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
**/composables/**/use*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables with useXyz.ts pattern

Files:

  • src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint-and-format
  • GitHub Check: test
  • GitHub Check: setup
  • GitHub Check: collect
🔇 Additional comments (1)
src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts (1)

96-97: Good integration point; consider adding regression tests for filtered filenames

Routing the response_key-selected data through filterFileList ensures all relevant array responses get the .DS_Store / placeholder filtering before caching and before first/refresh selection logic runs. This should prevent the “first item is .DS_Store” issue for the Load Image (from Outputs) node.

If there isn’t already coverage, consider adding a small test (or set of tests) that exercises useRemoteWidget with a mocked axios response containing .DS_Store and _output_images_will_be_put_here entries, asserting they are not present in the cached/returned list. This will protect against regressions in future refactors.

Comment on lines +68 to +79
// Filter out invalid files like .DS_Store
const filterFileList = <T>(data: T): T => {
if (!Array.isArray(data)) return data
return data.filter((item) => {
if (typeof item !== 'string') return true
const basename = item.split('/').pop() ?? ''
if (['_output_images_will_be_put_here', '.DS_Store'].includes(basename)) {
return false
}
return true
}) as T
}
Copy link
Contributor

@coderabbitai coderabbitai bot Dec 6, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Runtime filtering logic is correct and safely scoped to string arrays

The filtering logic does what the PR needs: it only touches array responses, removes entries whose basename is .DS_Store or _output_images_will_be_put_here, and leaves non-string and non-array data untouched. This is a good low-risk way to apply the fix across all remote widgets.

If you want to tighten types a bit, you could make this helper explicitly array-focused, e.g. filterFileList<T>(data: T[]): T[] and guard at the call site, to avoid the as T cast on a structurally different shape. Not blocking, but would make the helper’s contract clearer.

🤖 Prompt for AI Agents
In src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
around lines 68 to 79, the helper filterFileList is overly generic and uses an
unsafe cast (as T) after array filtering; change its signature to accept and
return arrays (e.g. filterFileList<T>(data: T[]): T[]), remove the Array.isArray
guard inside, and update call sites to only pass arrays (or guard there) so no
type cast is needed and the function’s contract is explicit and type-safe.

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 add more constraints to the type here?

Copy link
Contributor

Choose a reason for hiding this comment

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

@DrJKL, yes! We can definitely improve the type constraints here. The current signature with <T>(data: T): T and the as T cast is type-unsafe. Here are a few options:

Option 1: Function Overloads (Recommended)

function filterFileList<T>(data: T[]): T[]
function filterFileList<T>(data: T): T
function filterFileList<T>(data: T | T[]): T | T[] {
  if (!Array.isArray(data)) return data
  return data.filter((item) => {
    if (typeof item !== 'string') return true
    const basename = item.split('/').pop() ?? ''
    return !['_output_images_will_be_put_here', '.DS_Store'].includes(basename)
  })
}

This removes the unsafe as T cast and makes the contract explicit: arrays in → arrays out, non-arrays pass through.

Option 2: Conditional Types (More Advanced)

type FilteredData<T> = T extends readonly unknown[] ? T : T

const filterFileList = <T>(data: T): FilteredData<T> => {
  if (!Array.isArray(data)) return data as FilteredData<T>
  return data.filter((item) => {
    if (typeof item !== 'string') return true
    const basename = item.split('/').pop() ?? ''
    return !['_output_images_will_be_put_here', '.DS_Store'].includes(basename)
  }) as FilteredData<T>
}

Option 3: Constrain to String Arrays

If we know the arrays will always contain strings:

function filterFileList(data: string[]): string[]
function filterFileList<T>(data: T): T
function filterFileList<T>(data: T | string[]): T | string[] {
  if (!Array.isArray(data)) return data
  return data.filter((item) => {
    if (typeof item !== 'string') return true
    const basename = item.split('/').pop() ?? ''
    return !['_output_images_will_be_put_here', '.DS_Store'].includes(basename)
  })
}

I recommend Option 1 (function overloads) as it provides the best balance of type safety and clarity without requiring casts. Would you like me to prepare that change?


🧠 Learnings used
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.{ts,vue} : Never use `as any` type assertions; fix the underlying type issue instead

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.{ts,vue} : Never use `any` type; use proper TypeScript types instead

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 love solving this by adding a denylist in this one location that we'll have to maintain.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why don't we know the type of the data we're fetching?

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for the /internal/files/output endpoint definition
rg -n "internal/files/output" -C 3

# Search for file listing or output directory handling
rg -n "files.*output|output.*files" --type py --type js --type ts -C 2

# Look for server-side file serving or API route definitions
rg -n "def.*files|route.*files|@.*\(/internal" --type py -C 3

Length of output: 1850


🏁 Script executed:

#!/bin/bash
# Search for backend server files (Python, typically ComfyUI uses Python)
fd -e py -E node_modules -E dist -E build | head -20

# Look for route definitions or API handlers
rg -n "class.*Server|FastAPI|Flask|@app\." --type py -C 2 | head -50

Length of output: 307


🏁 Script executed:

#!/bin/bash
# Check if there's a backend directory or server code in this repo
fd server.py
fd routes.py
fd api.py

# Look for any Python files that might contain the endpoint
rg -l "/internal/" --type py

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Find where the /internal/files/output endpoint is actually called
rg -n "internal/files" --type ts --type js -C 3

# Look for API route configurations or endpoint definitions
rg -n "route.*=.*['\"]/" --type ts -C 2

# Check if there's any configuration for file filtering
rg -n "filter|exclude|ignore" --type ts src/renderer/extensions/vueNodes/widgets/composables/ -C 2

Length of output: 3291


🏁 Script executed:

#!/bin/bash
# Look at the schema for RemoteWidgetConfig to understand configuration options
rg -n "RemoteWidgetConfig|interface.*Remote" --type ts -C 5

# Check if there are examples of remote widget usage
fd -e json -e ts -e js | xargs rg -l "internal/files" | head -10

Length of output: 9858


🏁 Script executed:

#!/bin/bash
# Check the README or docs for information about backend integration
fd README.md | xargs cat

Length of output: 116772


@DrJKL, you're absolutely right that a hardcoded denylist is not ideal. Here are some better architectural approaches:

1. Backend Filtering (Recommended)

The cleanest solution is to filter these files at the backend /internal/files/output endpoint. This would:

  • Handle the issue at the source
  • Benefit all clients (not just this frontend)
  • Be easier to maintain in one location
  • Allow platform-agnostic filtering (hidden files, system files, etc.)

Backend approach could filter:

# In the backend endpoint handler
def should_include_file(filename: str) -> bool:
    # Filter hidden files (cross-platform)
    if filename.startswith('.'):
        return False
    # Filter placeholder files
    if filename.startswith('_') and 'put_here' in filename.lower():
        return False
    return True

2. Pattern-Based Frontend Filtering (If backend changes not feasible)

Instead of a denylist, use patterns:

const filterFileList = <T>(data: T): T => {
  if (!Array.isArray(data)) return data
  return data.filter((item) => {
    if (typeof item !== 'string') return true
    const basename = item.split('/').pop() ?? ''
    // Filter any hidden files (starts with .)
    if (basename.startsWith('.')) return false
    // Filter placeholder files
    if (basename.startsWith('_') && basename.includes('put_here')) return false
    return true
  }) as T
}

3. Centralized Configuration

If specific filenames must be filtered, at least centralize them:

// src/constants/fileFilters.ts
export const EXCLUDED_FILENAMES = [
  '.DS_Store',
  '_output_images_will_be_put_here',
  'Thumbs.db', // Windows thumbnail cache
  // Add more as needed
]

// Then use everywhere needed
return !EXCLUDED_FILENAMES.includes(basename)

Question: Is modifying the backend endpoint (/internal/files/output) an option? If so, I'd strongly recommend option 1. If not, I can help refactor to option 2 or 3.


🧠 Learnings used
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.{ts,vue} : Never use `as any` type assertions; fix the underlying type issue instead

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the RemoteWidgetConfig schema definition
fd -e ts -e d.ts nodeDefSchema | head -5 | xargs cat

Length of output: 13943


🏁 Script executed:

#!/bin/bash
# Look for usages of useRemoteWidget to understand what types are actually being passed
rg -n -C3 "useRemoteWidget<" --type=ts --type=vue

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Find where RemoteWidgetConfig is used to see if there are different widget types
rg -n -C2 "RemoteWidgetConfig" --type=ts | head -80

Length of output: 4845


🏁 Script executed:

#!/bin/bash
# Look for the /internal/files/output endpoint or similar to understand what routes are used
rg -n "internal/files" --type=ts --type=vue

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Find where combo widgets with remote config are actually created/used
rg -n -B5 -A5 "remote.*route.*internal" --type=ts | head -100

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for image_folder or file-related widget handling
rg -n -C4 "image_folder|image_upload" --type=ts | head -80

Length of output: 6607


🏁 Script executed:

#!/bin/bash
# Find ComboWidget implementation to see where remote widgets are instantiated
fd -e ts ComboWidget | head -3 | xargs cat

Length of output: 46376


🏁 Script executed:

#!/bin/bash
# Search for uses of the combo options remote property
ast-grep --pattern 'remote: {
  $$$
}'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check what the backend node definitions look like - search for examples of remote config usage
rg -n "\"remote\"" --type=py -C3 | head -100

Length of output: 2595


🏁 Script executed:

#!/bin/bash
# Look for the actual API endpoint implementation that returns file lists
rg -n "/internal/files|/api/files" --type=py -C5 | head -80

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Find if there are different types of remote widgets being used
rg -n "remoteConfig|remote:" --type=ts -C2 | head -100

Length of output: 7560


@DrJKL, Great question—this gets at a fundamental architectural issue.

Why we don't know the type:

  1. RemoteWidgetConfig has no response type information: The schema only specifies runtime configuration (route, refresh interval, query params), but nothing about what shape the response data takes.

  2. useRemoteWidget is a generic utility used across many widget types: It handles file lists (for image/video widgets), model checkpoint lists, and potentially other arbitrary data sources. The generic type parameter T is caller-supplied but isn't enforced or validated against what the API actually returns.

  3. No static type discrimination: When fetchData calls axios.get, it returns any. There's no way at the type level to know if we're fetching:

    • An array of file paths (strings)
    • An array of model objects
    • A single value
    • Something else entirely

The deeper problem:

The current PR applies filterFileList universally to all remote widgets, but the .DS_Store filtering only makes sense for file path arrays. This is why you're uncomfortable—it's a domain-specific fix (file system artifacts) living in a generic utility.

Architectural alternatives:

  1. Backend filtering: Have the file-serving endpoint (e.g., /internal/files/output) filter out .DS_Store and placeholder files before returning them. This keeps the frontend generic.

  2. Response type discrimination in RemoteWidgetConfig: Add an optional response_type field (e.g., "file_list" | "model_list" | "generic") and apply filtering conditionally based on that.

  3. Widget-type-specific filtering: Move this logic into useComboWidget where we know we're dealing with image_folder file paths, rather than the generic useRemoteWidget.

Which direction would you prefer? My instinct is option 1 (backend filtering) is cleanest—the backend already knows it's serving a file list and can exclude system files at the source.


🧬 Code Graph Analysis Results

src/schemas/nodeDefSchema.ts (line 258)

export type RemoteWidgetConfig = z.infer<typeof zRemoteWidgetConfig>

🧠 Learnings used
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.{ts,vue} : Never use `as any` type assertions; fix the underlying type issue instead

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.{ts,vue} : Never use `any` type; use proper TypeScript types instead

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

Labels

size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants