Skip to content

Conversation

@Yourz
Copy link
Collaborator

@Yourz Yourz commented Dec 15, 2025

Summary

Implement true virtual scrolling for TreeExplorer using a sliding window approach to improve performance when rendering large tree structures. Previously, the component would load all the nodes at the same time when click the parent node, which costs a lot and slow the render performance.
This change introduces a sliding window mechanism that maintains only a fixed number of visible nodes (max 60) with a buffer (20 nodes) for smooth scrolling.

Changes

What

  • Add sliding window virtual list implementation to TreeExplorer.vue
  • Extract reusable virtual list utility functions to src/utils/virtualListUtils.ts
  • Add comprehensive unit tests for virtual list utilities (25 tests)
  • Use CSS pseudo-elements (::before, ::after) to create spacers that maintain accurate scrollbar position
  • Implement scroll percentage calculation adjusted for spacer heights
  • Add recursive window management for nested expanded nodes
  • Reset windows to top when scrolled to position 0

Breaking

  • Behavior change: Tree nodes are now dynamically added/removed from DOM based on scroll position. Extensions or customizations that rely on all nodes being present in the DOM simultaneously may need updates.
  • Scroll behavior: The visible nodes are now limited by a sliding window (60 nodes max). Users scrolling through very large trees will see nodes being recycled.

Dependencies

  • No new dependencies added
  • Uses existing @vueuse/core for throttling

Review Focus

  1. Performance: Verify the sliding window correctly limits DOM nodes during scrolling
  2. Scroll accuracy: Check that scrollbar position accurately reflects the total content height via CSS spacers
  3. Edge cases: Test with deeply nested trees, rapid scrolling, and collapse/expand operations
  4. Recursive handling: Verify nested expanded nodes correctly manage their own windows

Screenshots

Before(it takes more than 5 seconds to load the list):

Kapture 2025-12-15 at 18 07 53

After:
Kapture 2025-12-15 at 18 10 24

┆Issue is synchronized with this Notion page by Unito

@Yourz Yourz requested a review from a team as a code owner December 15, 2025 10:04
@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Dec 15, 2025
@github-actions
Copy link

github-actions bot commented Dec 15, 2025

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 12/17/2025, 03:52:04 PM UTC

📈 Summary

  • Total Tests: 507
  • Passed: 497 ✅
  • Failed: 0
  • Flaky: 1 ⚠️
  • Skipped: 9 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 485 / ❌ 0 / ⚠️ 1 / ⏭️ 9
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 9 / ❌ 0 / ⚠️ 0 / ⏭️ 0

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 15, 2025

📝 Walkthrough

Walkthrough

Adds virtualized sliding-window rendering to the tree: per-node window ranges, scroll-driven window shifts and spacer calculations, a nodeKeyMap for O(1) lookups, error-wrapped node actions, exposes addFolderCommand(targetNodeKey), and introduces virtual list utilities with tests.

Changes

Cohort / File(s) Summary
Virtual List Utilities
src/utils/virtualListUtils.ts
New module providing windowing primitives and exports: WindowRange, applyWindow, shiftWindowForward, shiftWindowBackward, calculateSpacerHeights, createInitialWindowRange, and calculateScrollPercentage.
Virtual List Utilities Tests
src/utils/__tests__/virtualListUtils.test.ts
New tests covering initial window creation, forward/backward shifts (including boundaries), spacer height calculations, scroll percentage math, and recursive applyWindow behavior on nested node trees.
TreeExplorer Component
src/components/common/TreeExplorer.vue
Replaces direct in-tree rendering with a scrollable container and virtualized sliding-window rendering: adds container ref and throttled scroll handler, per-parent windowRanges and parentWindowRanges, nodeKeyMap, displayRoot computed via applyWindow, spacer styling logic (getNodeChildrenStyle), error-wrapping for node actions, and exposes addFolderCommand(targetNodeKey: string).
Tree Utilities
src/utils/treeUtil.ts
findNodeByKey changed from an exported function to a module-private constant; implementation unchanged.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TreeExplorer
  participant VirtualUtils
  participant Renderer

  User->>TreeExplorer: scroll event
  TreeExplorer->>TreeExplorer: throttled handler reads scrollTop & spacers
  TreeExplorer->>VirtualUtils: calculateScrollPercentage(scrollTop, scrollHeight, clientHeight, topSpacer, bottomSpacer)
  VirtualUtils-->>TreeExplorer: scrollPercentage
  alt forward shift needed
    TreeExplorer->>VirtualUtils: shiftWindowForward(currentRange, totalChildren, bufferSize, windowSize)
  else backward shift needed
    TreeExplorer->>VirtualUtils: shiftWindowBackward(currentRange, totalChildren, bufferSize, windowSize)
  else initialize or no-op
    TreeExplorer->>VirtualUtils: createInitialWindowRange(totalChildren, windowSize)
  end
  VirtualUtils-->>TreeExplorer: updated WindowRange(s)
  TreeExplorer->>VirtualUtils: applyWindow(rootNode, windowRanges, windowSize)
  VirtualUtils-->>TreeExplorer: windowed node tree
  TreeExplorer->>Renderer: render windowed tree with spacer styles
  Renderer-->>User: visible nodes updated
Loading
✨ 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 feat/tree-explorer-virtual-list

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 15, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 12/17/2025, 03:42:50 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Dec 15, 2025

Bundle Size Report

Summary

  • Raw size: 16.6 MB baseline 16.6 MB — 🔴 +9.51 kB
  • Gzip: 3.37 MB baseline 3.37 MB — 🔴 +1.87 kB
  • Brotli: 2.59 MB baseline 2.59 MB — 🔴 +1.39 kB
  • Bundles: 99 current • 99 baseline • 54 added / 54 removed

Category Glance
App Entry Points 🔴 +9.51 kB (3.21 MB) · Vendor & Third-Party ⚪ 0 B (8.45 MB) · Other ⚪ 0 B (3.41 MB) · Graph Workspace ⚪ 0 B (997 kB) · Panels & Settings ⚪ 0 B (297 kB) · UI Components ⚪ 0 B (184 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.21 MB (baseline 3.21 MB) • 🔴 +9.51 kB

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BsDZ_7wr.js (new) 2.99 MB 🔴 +2.99 MB 🔴 +629 kB 🔴 +479 kB
assets/index-C7FTWlRH.js (removed) 2.98 MB 🟢 -2.98 MB 🟢 -627 kB 🟢 -477 kB
assets/index-BNMOMXsY.js (removed) 227 kB 🟢 -227 kB 🟢 -48.5 kB 🟢 -39.8 kB
assets/index-CrkxoFZh.js (new) 227 kB 🔴 +227 kB 🔴 +48.5 kB 🔴 +39.8 kB
assets/index-BvXXWGqJ.js (removed) 345 B 🟢 -345 B 🟢 -246 B 🟢 -232 B
assets/index-tUkINzyw.js (new) 345 B 🔴 +345 B 🔴 +245 B 🔴 +208 B

Status: 3 added / 3 removed

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

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-D62lDqg7.js (removed) 997 kB 🟢 -997 kB 🟢 -194 kB 🟢 -148 kB
assets/GraphView-DkV-gOZf.js (new) 997 kB 🔴 +997 kB 🔴 +194 kB 🔴 +148 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-CHbYubk5.js (new) 6.54 kB 🔴 +6.54 kB 🔴 +2.14 kB 🔴 +1.91 kB
assets/UserSelectView-CRkz9kt-.js (removed) 6.54 kB 🟢 -6.54 kB 🟢 -2.14 kB 🟢 -1.89 kB

Status: 1 added / 1 removed

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LegacyCreditsPanel-BfwjxMRO.js (removed) 21.4 kB 🟢 -21.4 kB 🟢 -5.16 kB 🟢 -4.5 kB
assets/LegacyCreditsPanel-CWtwDvvi.js (new) 21.4 kB 🔴 +21.4 kB 🔴 +5.16 kB 🔴 +4.5 kB
assets/KeybindingPanel-BdO_i-aV.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.42 kB 🔴 +3.01 kB
assets/KeybindingPanel-DWMUEuLe.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.42 kB 🟢 -3.01 kB
assets/ExtensionPanel-B6aSHtVo.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.57 kB 🟢 -2.25 kB
assets/ExtensionPanel-CRIlJe6b.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.57 kB 🔴 +2.25 kB
assets/AboutPanel-CjBBO_Vd.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.2 kB
assets/AboutPanel-Dv2I8GNl.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/ServerConfigPanel-BYE-qvAs.js (new) 7.07 kB 🔴 +7.07 kB 🔴 +1.99 kB 🔴 +1.76 kB
assets/ServerConfigPanel-Cn90dsGC.js (removed) 7.07 kB 🟢 -7.07 kB 🟢 -1.99 kB 🟢 -1.77 kB
assets/UserPanel-B7JjfjjB.js (new) 6.23 kB 🔴 +6.23 kB 🔴 +1.72 kB 🔴 +1.5 kB
assets/UserPanel-DHOhzTiV.js (removed) 6.23 kB 🟢 -6.23 kB 🟢 -1.72 kB 🟢 -1.5 kB
assets/settings-BhbWhsRg.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BvFz-TmQ.js 33.1 kB 33.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BxYnTA2y.js 21.5 kB 21.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C6bMjAne.js 27.1 kB 27.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C7Yhp7H7.js 24 kB 24 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CsnOn8G0.js 25.7 kB 25.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-D5BGNZ7M.js 24.8 kB 24.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-D7k3huHm.js 25 kB 25 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DamkILzl.js 26.4 kB 26.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-s1k0gw1Y.js 20.9 kB 20.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Load3D.vue_vue_type_script_setup_true_lang-DJqOQkbR.js (new) 53.7 kB 🔴 +53.7 kB 🔴 +8.49 kB 🔴 +7.29 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-PpTTZqaU.js (removed) 53.7 kB 🟢 -53.7 kB 🟢 -8.49 kB 🟢 -7.29 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-A--wQ8qP.js (removed) 48.7 kB 🟢 -48.7 kB 🟢 -10.5 kB 🟢 -9.12 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-CapB6jqX.js (new) 48.7 kB 🔴 +48.7 kB 🔴 +10.5 kB 🔴 +9.12 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-BauI_IRT.js (new) 48.4 kB 🔴 +48.4 kB 🔴 +10.7 kB 🔴 +9.36 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-jT2FxN1c.js (removed) 48.4 kB 🟢 -48.4 kB 🟢 -10.7 kB 🟢 -9.36 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-C8YdZt4W.js (removed) 14.3 kB 🟢 -14.3 kB 🟢 -3.74 kB 🟢 -3.3 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-DxHgiK0G.js (new) 14.3 kB 🔴 +14.3 kB 🔴 +3.73 kB 🔴 +3.28 kB
assets/ComfyQueueButton--ngyTZPm.js (removed) 8.52 kB 🟢 -8.52 kB 🟢 -2.5 kB 🟢 -2.23 kB
assets/ComfyQueueButton-BWQ74Wzn.js (new) 8.52 kB 🔴 +8.52 kB 🔴 +2.5 kB 🔴 +2.23 kB
assets/WidgetWithControl.vue_vue_type_script_setup_true_lang-BMkYm9-B.js (new) 3.68 kB 🔴 +3.68 kB 🔴 +1.45 kB 🔴 +1.31 kB
assets/WidgetWithControl.vue_vue_type_script_setup_true_lang-DAJdDL4W.js (removed) 3.68 kB 🟢 -3.68 kB 🟢 -1.46 kB 🟢 -1.31 kB
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-BFVhFa5C.js (new) 2.14 kB 🔴 +2.14 kB 🔴 +888 B 🔴 +766 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-DDGbaA6e.js (removed) 2.14 kB 🟢 -2.14 kB 🟢 -891 B 🟢 -769 B
assets/WidgetButton-Co3cJaMC.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +929 B 🔴 +829 B
assets/WidgetButton-D-PsyQgm.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -927 B 🟢 -816 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-CMhLYo4y.js (removed) 1.34 kB 🟢 -1.34 kB 🟢 -687 B 🟢 -598 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-SNJETyEh.js (new) 1.34 kB 🔴 +1.34 kB 🔴 +686 B 🔴 +594 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-BaJrOfDu.js (removed) 897 B 🟢 -897 B 🟢 -504 B 🟢 -431 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-BzypIsH6.js (new) 897 B 🔴 +897 B 🔴 +503 B 🔴 +433 B

Status: 10 added / 10 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-CThFG9H_.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.83 kB 🔴 +1.57 kB
assets/keybindingService-WEVXZy5g.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.83 kB 🟢 -1.57 kB
assets/serverConfigStore-CbOScD95.js (new) 2.83 kB 🔴 +2.83 kB 🔴 +909 B 🔴 +789 B
assets/serverConfigStore-DK03Dh5G.js (removed) 2.83 kB 🟢 -2.83 kB 🟢 -906 B 🟢 -793 B
assets/audioService-BRut2VSS.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +958 B 🔴 +832 B
assets/audioService-CJwYiGge.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -962 B 🟢 -826 B

Status: 3 added / 3 removed

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-B7YVLvL1.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +652 B 🔴 +552 B
assets/audioUtils-CsnsXhAD.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -651 B 🟢 -549 B
assets/mathUtil-CD4DsosH.js 1.32 kB 1.32 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.45 MB (baseline 8.45 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-other-BD0aMZBO.js (removed) 3.86 MB 🟢 -3.86 MB 🟢 -839 kB 🟢 -671 kB
assets/vendor-other-DonzFnT3.js (new) 3.86 MB 🔴 +3.86 MB 🔴 +839 kB 🔴 +671 kB
assets/vendor-primevue-8cJ9yrd4.js (new) 1.96 MB 🔴 +1.96 MB 🔴 +334 kB 🔴 +202 kB
assets/vendor-primevue-BD67ynhB.js (removed) 1.96 MB 🟢 -1.96 MB 🟢 -334 kB 🟢 -202 kB
assets/vendor-chart-BwZ_KFjV.js (removed) 452 kB 🟢 -452 kB 🟢 -99 kB 🟢 -81 kB
assets/vendor-chart-COnGAL7C.js (new) 452 kB 🔴 +452 kB 🔴 +99 kB 🔴 +81 kB
assets/vendor-tiptap-DGEie6Tj.js (removed) 232 kB 🟢 -232 kB 🟢 -45.7 kB 🟢 -37.7 kB
assets/vendor-tiptap-HMk8uRl8.js (new) 232 kB 🔴 +232 kB 🔴 +45.7 kB 🔴 +37.7 kB
assets/vendor-vue-CzyF96Dk.js (new) 160 kB 🔴 +160 kB 🔴 +37.2 kB 🔴 +31.4 kB
assets/vendor-vue-o0fksRVZ.js (removed) 160 kB 🟢 -160 kB 🟢 -37.2 kB 🟢 -31.4 kB
assets/vendor-three-C1LfRdh4.js 1.37 MB 1.37 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-BF8peZ5_.js 420 kB 420 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 5 added / 5 removed

Other — 3.41 MB (baseline 3.41 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WidgetRecordAudio-B9W-yCZP.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.24 kB 🔴 +4.64 kB
assets/WidgetRecordAudio-DWlQraOy.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.24 kB 🟢 -4.64 kB
assets/AudioPreviewPlayer-B7JCRj2V.js (removed) 13.4 kB 🟢 -13.4 kB 🟢 -3.37 kB 🟢 -3.01 kB
assets/AudioPreviewPlayer-BE8afEK_.js (new) 13.4 kB 🔴 +13.4 kB 🔴 +3.37 kB 🔴 +3.01 kB
assets/ValueControlPopover-C2G6UAJq.js (new) 5.49 kB 🔴 +5.49 kB 🔴 +1.7 kB 🔴 +1.52 kB
assets/ValueControlPopover-WjG6YOg9.js (removed) 5.49 kB 🟢 -5.49 kB 🟢 -1.71 kB 🟢 -1.52 kB
assets/WidgetGalleria-CfVM640L.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.45 kB 🟢 -1.3 kB
assets/WidgetGalleria-phq79-HG.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.45 kB 🔴 +1.3 kB
assets/WidgetColorPicker-Bh1Utl0c.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetColorPicker-C1CWNhYi.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetTextarea-DZBvn7uw.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.21 kB 🔴 +1.08 kB
assets/WidgetTextarea-WIqB8x1u.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.22 kB 🟢 -1.08 kB
assets/WidgetMarkdown-CLpkHzoB.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetMarkdown-CyJHx8r7.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/WidgetAudioUI-BprjL10W.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +1.19 kB 🔴 +1.07 kB
assets/WidgetAudioUI-DUvmvuw4.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -1.19 kB 🟢 -1.07 kB
assets/MediaVideoTop-D5eyv0dl.js (removed) 2.65 kB 🟢 -2.65 kB 🟢 -1.01 kB 🟢 -869 B
assets/MediaVideoTop-nUMswf7c.js (new) 2.65 kB 🔴 +2.65 kB 🔴 +1.01 kB 🔴 +868 B
assets/WidgetChart-B-1rxecT.js (removed) 2.48 kB 🟢 -2.48 kB 🟢 -930 B 🟢 -819 B
assets/WidgetChart-Bj4tC1Sh.js (new) 2.48 kB 🔴 +2.48 kB 🔴 +930 B 🔴 +818 B
assets/WidgetImageCompare-BZzCMXSO.js (removed) 2.21 kB 🟢 -2.21 kB 🟢 -749 B 🟢 -661 B
assets/WidgetImageCompare-DBdDspiT.js (new) 2.21 kB 🔴 +2.21 kB 🔴 +748 B 🔴 +663 B
assets/WidgetInputText-BM9J5lHA.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -920 B 🟢 -857 B
assets/WidgetInputText-D8gB_1Pc.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +919 B 🔴 +848 B
assets/WidgetToggleSwitch-B2RFQ5m3.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +834 B 🔴 +732 B
assets/WidgetToggleSwitch-Qiq7PZco.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -831 B 🟢 -734 B
assets/MediaImageTop-CmnX5tDW.js (removed) 1.75 kB 🟢 -1.75 kB 🟢 -841 B 🟢 -717 B
assets/MediaImageTop-DVNzV7QV.js (new) 1.75 kB 🔴 +1.75 kB 🔴 +842 B 🔴 +720 B
assets/MediaImageBottom-C1f1XQrB.js (removed) 1.55 kB 🟢 -1.55 kB 🟢 -731 B 🟢 -639 B
assets/MediaImageBottom-DwQbM4PL.js (new) 1.55 kB 🔴 +1.55 kB 🔴 +733 B 🔴 +641 B
assets/MediaAudioBottom-D-CV5urH.js (new) 1.51 kB 🔴 +1.51 kB 🔴 +733 B 🔴 +647 B
assets/MediaAudioBottom-DBQovYGV.js (removed) 1.51 kB 🟢 -1.51 kB 🟢 -733 B 🟢 -644 B
assets/Media3DBottom-BxYOslS3.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -731 B 🟢 -647 B
assets/Media3DBottom-DtgI60Xf.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +732 B 🔴 +646 B
assets/MediaVideoBottom-Bz8Z5d9J.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -731 B 🟢 -644 B
assets/MediaVideoBottom-Dk03BHuz.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +731 B 🔴 +646 B
assets/Media3DTop-B4vxor85.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +762 B 🔴 +654 B
assets/Media3DTop-LUWnBDoU.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -764 B 🟢 -653 B
assets/MediaAudioTop-DE9wxwm5.js (new) 1.46 kB 🔴 +1.46 kB 🔴 +740 B 🔴 +620 B
assets/MediaAudioTop-GG9iPI9C.js (removed) 1.46 kB 🟢 -1.46 kB 🟢 -742 B 🟢 -620 B
assets/WidgetSelect-2ikgC4qA.js (new) 733 B 🔴 +733 B 🔴 +361 B 🔴 +330 B
assets/WidgetSelect-47iqyOlL.js (removed) 733 B 🟢 -733 B 🟢 -364 B 🟢 -321 B
assets/WidgetInputNumber-BNLjh9w1.js (removed) 673 B 🟢 -673 B 🟢 -348 B 🟢 -286 B
assets/WidgetInputNumber-CJpsXwtt.js (new) 673 B 🔴 +673 B 🔴 +348 B 🔴 +288 B
assets/Load3D-DZ09nmL8.js (new) 424 B 🔴 +424 B 🔴 +268 B 🔴 +224 B
assets/Load3D-RtiIWEUU.js (removed) 424 B 🟢 -424 B 🟢 -266 B 🟢 -222 B
assets/WidgetLegacy-Bbg2Cgto.js (new) 364 B 🔴 +364 B 🔴 +238 B 🔴 +197 B
assets/WidgetLegacy-D4jlrcau.js (removed) 364 B 🟢 -364 B 🟢 -236 B 🟢 -194 B
assets/commands-BWp4HdfU.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CcfGaui5.js 14.4 kB 14.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CisfgZf5.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CkU12Foh.js 13 kB 13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CoH2DJa6.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-COSt-Bjx.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DalfIW5f.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DfTl0eCm.js 13.5 kB 13.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DwSJL865.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Zxyx15Vd.js 12.8 kB 12.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BDhxs-bB.js 79.9 kB 79.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BtXVDFw6.js 84.7 kB 84.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Buv6RhU4.js 82.4 kB 82.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CgJ6zvJL.js 97.2 kB 97.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CI9qb0E5.js 112 kB 112 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cu4LqtW0.js 81.6 kB 81.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cw9RZWRY.js 89 B 89 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dm19QY4N.js 92.2 kB 92.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Tihe0h_r.js 71.3 kB 71.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-wPWMutMw.js 70.4 kB 70.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-1Vh3MCrN.js 240 kB 240 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-aW9En70v.js 260 kB 260 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BIckSVgU.js 273 kB 273 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BiYpVi7D.js 263 kB 263 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bw_Jitw_.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CCEXtYfM.js 243 kB 243 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CvmVDWYd.js 323 kB 323 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-D_wreoPJ.js 267 kB 267 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Dz-0ZIBN.js 297 kB 297 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-VZsNmhG7.js 264 kB 264 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 24 added / 24 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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c414635 and d166d4a.

📒 Files selected for processing (3)
  • src/components/common/TreeExplorer.vue (5 hunks)
  • src/utils/__tests__/virtualListUtils.test.ts (1 hunks)
  • src/utils/virtualListUtils.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
src/**/*.vue

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

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.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/components/common/TreeExplorer.vue
  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.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/components/common/TreeExplorer.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/common/TreeExplorer.vue
  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.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/components/common/TreeExplorer.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Vue component file names must use PascalCase; for example, MenuHamburger.vue

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/common/TreeExplorer.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/components/common/TreeExplorer.vue
  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/components/common/TreeExplorer.vue
  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
src/**/*.ts

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

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

Minimize the surface area (exported values) of each module and composable

Files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.ts: Write tests for all changes, especially bug fixes to catch future regressions
Unit/component test files must be named **/*.test.ts or in tests-ui/ directory
Do not write change detector tests that just assert default values
Do not write tests dependent on non-behavioral features like utility classes or styles
Be parsimonious in testing; do not write redundant tests; see composable tests approach
Follow 'Don't Mock What You Don't Own' principle - avoid mocking external dependencies
Do not write tests that just test the mocks; ensure tests fail when code behaves unexpectedly
Leverage Vitest's mocking utilities where possible for test mocking
Keep module mocks contained in test files; do not use global mutable state within test files; use vi.hoisted() if necessary
For Component testing, use Vue Test Utils and follow advice about making components easy to test
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • src/utils/__tests__/virtualListUtils.test.ts
🧠 Learnings (26)
📓 Common learnings
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Steps component with Stepper without panels

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Sidebar component with Drawer

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use Teleport/Suspense when needed for component rendering

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/common/TreeExplorer.vue
  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Test across multiple viewports

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.test.ts : Aim for behavioral coverage of critical and new features in unit tests

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.test.ts : Leverage Vitest's mocking utilities where possible for test mocking

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
🧬 Code graph analysis (2)
src/utils/__tests__/virtualListUtils.test.ts (2)
src/utils/virtualListUtils.ts (7)
  • createInitialWindowRange (108-114)
  • WindowRange (3-6)
  • shiftWindowForward (49-61)
  • shiftWindowBackward (71-83)
  • calculateSpacerHeights (92-100)
  • calculateScrollPercentage (125-136)
  • applyWindow (15-39)
src/types/treeExplorerTypes.ts (1)
  • RenderedTreeExplorerNode (64-74)
src/utils/virtualListUtils.ts (1)
src/types/treeExplorerTypes.ts (1)
  • RenderedTreeExplorerNode (64-74)
⏰ 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: setup
  • GitHub Check: test
  • GitHub Check: collect
  • GitHub Check: lint-and-format
🔇 Additional comments (21)
src/utils/virtualListUtils.ts (7)

1-6: LGTM!

Clean interface definition with appropriate exports. The WindowRange type is well-defined for the sliding window use case.


15-39: LGTM!

The recursive window application correctly handles leaf nodes, empty children, and missing window ranges with a sensible fallback. The immutable return pattern is good.


49-61: LGTM!

The forward shift logic correctly maintains the window size invariant and handles boundary conditions. Returning null when no shift is needed is a clean pattern.


71-83: LGTM!

Symmetric implementation to forward shift. Correctly maintains window size and handles the start boundary.


92-100: LGTM!

Simple and correct spacer calculation. The Math.max(0, ...) guard on the bottom spacer is good defensive coding.


108-114: LGTM!

Concise factory function for initial window ranges.


125-136: LGTM!

The scroll percentage calculation correctly adjusts for spacer heights to give an accurate position within the actual content. Edge case handling for zero content height is appropriate.

src/components/common/TreeExplorer.vue (7)

2-5: LGTM!

The scroll container wrapper with throttled handler is appropriate for virtual scrolling. Using @vueuse/core's useThrottleFn aligns with coding guidelines.


116-127: LGTM!

Good cleanup logic when nodes collapse. This prevents stale window ranges from accumulating in memory.


133-162: LGTM!

The recursive spacer calculation correctly traverses only expanded nodes within their windows, keeping computation bounded.


222-285: LGTM!

The recursive window shifting logic is well-structured. Limiting recursion to children within the current window keeps the operation bounded.


301-306: LGTM!

Clean separation between the full rendered tree and the windowed display tree. The computed property ensures reactivity when window ranges change.


309-338: LGTM!

The style function correctly calculates spacer heights based on the original node's children count, not the windowed count. Using CSS variables with pseudo-elements is a clean approach.


503-514: LGTM!

Clean CSS implementation for virtual scrolling spacers. Using pseudo-elements with CSS variables is an elegant approach that avoids additional DOM elements.

src/utils/__tests__/virtualListUtils.test.ts (7)

1-14: LGTM!

Clean imports following the repository's pattern of separating type imports. Good coverage of all exported utilities.


16-31: LGTM!

Good boundary coverage for the initial window range creation.


33-57: LGTM!

Thorough testing of forward shift including boundary conditions and window size maintenance.


59-83: LGTM!

Good symmetric coverage to the forward shift tests.


85-121: LGTM!

Comprehensive spacer height tests covering all window positions (middle, start, end, full coverage).


123-149: LGTM!

Good test coverage including edge cases. The inline comments explaining the expected calculations are helpful for understanding the test logic.


151-220: LGTM!

Excellent test coverage for applyWindow including recursive application to nested children. The mock factory creates minimal but valid nodes, and the tests verify behavioral outcomes rather than implementation details.

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: 4

♻️ Duplicate comments (1)
src/components/common/TreeExplorer.vue (1)

188-219: Extract threshold constants for clarity.

The magic numbers 0.7 and 0.3 for scroll thresholds could be extracted to named constants alongside WINDOW_SIZE and BUFFER_SIZE for better readability and easier tuning.

 const WINDOW_SIZE = 60
 const BUFFER_SIZE = 20
 const NODE_HEIGHT = 28
+const SCROLL_FORWARD_THRESHOLD = 0.7
+const SCROLL_BACKWARD_THRESHOLD = 0.3

Then use these constants in the scroll handler.

The scroll percentage calculation duplication was already flagged in a past review.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d166d4a and fa3f202.

📒 Files selected for processing (1)
  • src/components/common/TreeExplorer.vue (5 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.vue

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

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/common/TreeExplorer.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Vue component file names must use PascalCase; for example, MenuHamburger.vue

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/common/TreeExplorer.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/components/common/TreeExplorer.vue
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/common/TreeExplorer.vue
⏰ 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: setup
  • GitHub Check: lint-and-format
  • GitHub Check: collect
  • GitHub Check: test
🔇 Additional comments (6)
src/components/common/TreeExplorer.vue (6)

46-73: LGTM!

Imports are well-organized. Using useThrottleFn from @vueuse/core aligns with the coding guidelines for leveraging VueUse functions.


116-127: Watch cleanup logic is correct, but consider performance.

The deep watch on expandedKeys correctly cleans up window ranges when nodes collapse. However, for very large trees with many expanded nodes, the deep comparison and iteration could become expensive. The current implementation is acceptable for typical use cases.


132-162: LGTM!

The recursive spacer height calculation correctly traverses expanded nodes and accumulates heights for nodes outside the visible window. The boundary checks are appropriate.


221-245: LGTM!

The window shifting logic correctly delegates to utility functions and recursively processes children. Using the pre-shift range for child iteration ensures consistent traversal.


300-306: LGTM!

The displayRoot computed property cleanly applies the windowing transformation. Separating the full renderedRoot from the windowed displayRoot is a good pattern that allows spacer calculations to reference the original children count.


503-514: LGTM!

Using CSS pseudo-elements for spacers is an elegant approach that avoids extra DOM nodes. The :deep(ul.virtual-node-children) selector appropriately targets PrimeVue's tree structure. This is a valid exception to the Tailwind-only guideline since pseudo-element content and CSS variables cannot be expressed with utility classes.

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa3f202 and 4f4d3e6.

📒 Files selected for processing (1)
  • src/components/common/TreeExplorer.vue (5 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.vue

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

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/common/TreeExplorer.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Vue component file names must use PascalCase; for example, MenuHamburger.vue

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/common/TreeExplorer.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/components/common/TreeExplorer.vue
🧠 Learnings (4)
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/common/TreeExplorer.vue
⏰ 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: setup
  • GitHub Check: collect
  • GitHub Check: test
  • GitHub Check: lint-and-format

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/common/TreeExplorer.vue (1)

389-400: Implement consistent error handling for async node callbacks.

The onNodeContentClick function awaits node.handleClick() without error handling, creating a potential for unhandled promise rejections. The type signature handleClick?: (...) => void | Promise<void> confirms it can return a rejected Promise. Other async node operations in this component (e.g., handleNodeLabelEdit) use the errorHandling.wrapWithErrorHandlingAsync wrapper with the node's handleError callback. Apply the same pattern here:

 const onNodeContentClick = async (
   e: MouseEvent,
   node: RenderedTreeExplorerNode
 ) => {
   if (!storeSelectionKeys) {
     selectionKeys.value = {}
   }
-  if (node.handleClick) {
-    await node.handleClick(e)
-  }
+  await errorHandling.wrapWithErrorHandlingAsync(
+    async () => {
+      if (node.handleClick) {
+        await node.handleClick(e)
+      }
+    },
+    node.handleError
+  )()
   emit('nodeClick', node, e)
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f4d3e6 and f6c6ab9.

📒 Files selected for processing (1)
  • src/components/common/TreeExplorer.vue (6 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.vue

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

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/common/TreeExplorer.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Vue component file names must use PascalCase; for example, MenuHamburger.vue

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/common/TreeExplorer.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/components/common/TreeExplorer.vue
🧠 Learnings (9)
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Be judicious with addition of new refs or other state: prefer props, avoid redundant `computed`, and prefer `computed` over `watch`

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Implement computed properties with `computed()` from Vue; avoid using a `ref` with a `watch` if a `computed` would work instead

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Use `watch` and `watchEffect` for side effects in Vue components

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use watch and watchEffect for side effects

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/common/TreeExplorer.vue
⏰ 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

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: 2

♻️ Duplicate comments (1)
src/components/common/TreeExplorer.vue (1)

2-5: Container max height is still hard-coded; consider making it configurable.

max-h-[calc(100vh-144px)] still bakes in a specific layout assumption, which can be fragile when embedding TreeExplorer in different contexts. Exposing a prop (e.g. maxHeight or style override) and binding it here would improve reusability without impacting current behavior.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6c6ab9 and 2751337.

📒 Files selected for processing (1)
  • src/components/common/TreeExplorer.vue (6 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.vue

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

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/common/TreeExplorer.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Vue component file names must use PascalCase; for example, MenuHamburger.vue

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/common/TreeExplorer.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/components/common/TreeExplorer.vue
🧠 Learnings (11)
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Be judicious with addition of new refs or other state: prefer props, avoid redundant `computed`, and prefer `computed` over `watch`

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Implement computed properties with `computed()` from Vue; avoid using a `ref` with a `watch` if a `computed` would work instead

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Use `watch` and `watchEffect` for side effects in Vue components

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use watch and watchEffect for side effects

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.{ts,tsx,vue} : Minimize nesting in code (e.g., deeply nested `if` or `for` statements); apply the Arrow Anti-Pattern principle

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.{ts,tsx,vue} : Keep functions short and functional

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/common/TreeExplorer.vue
⏰ 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). (5)
  • GitHub Check: deploy-and-comment
  • GitHub Check: setup
  • GitHub Check: test
  • GitHub Check: lint-and-format
  • GitHub Check: collect
🔇 Additional comments (4)
src/components/common/TreeExplorer.vue (4)

271-284: Efficient nodeKeyMap lookup is a solid improvement.

Building nodeKeyMap once per renderedRoot and reusing it for O(1) lookups (e.g. in getNodeChildrenStyle and exposed commands) avoids repeated tree walks in hot paths and aligns well with the virtualized rendering approach.


286-330: applyWindow + getNodeChildrenStyle integration looks correct and consistent.

Applying the window via applyWindowUtil and then deriving per-node spacers from calculateSpacerHeights and parentWindowRanges—using nodeKeyMap to reference the full child list—is a clean separation of concerns and keeps the spacer CSS in sync with the active window ranges.


472-482: Using nodeKeyMap in the exposed addFolderCommand is a good API refinement.

Looking up the target node by key via nodeKeyMap.value[targetNodeKey] before delegating to addFolderCommand avoids external callers needing to hold full node references and removes any need for ad‑hoc tree traversal on the public API surface.


495-507: Pseudo-element spacers are an appropriate way to back the virtual list.

The virtual-node-children UL with ::before/::after driven by --top-spacer/--bottom-spacer cleanly separates layout concerns from the tree data, and matches the spacer values produced in getNodeChildrenStyle, minimizing layout shift during scrolling.

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2751337 and 556dfac.

📒 Files selected for processing (2)
  • src/components/common/TreeExplorer.vue (6 hunks)
  • src/utils/treeUtil.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (13)
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/utils/treeUtil.ts
  • src/components/common/TreeExplorer.vue
src/**/*.ts

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

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

Minimize the surface area (exported values) of each module and composable

Files:

  • src/utils/treeUtil.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/utils/treeUtil.ts
  • src/components/common/TreeExplorer.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/utils/treeUtil.ts
  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/utils/treeUtil.ts
  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/utils/treeUtil.ts
  • src/components/common/TreeExplorer.vue
src/**/*.vue

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

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/common/TreeExplorer.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Vue component file names must use PascalCase; for example, MenuHamburger.vue

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/common/TreeExplorer.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/components/common/TreeExplorer.vue
🧠 Learnings (12)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/utils/treeUtil.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/utils/treeUtil.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/utils/treeUtil.ts
  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Be judicious with addition of new refs or other state: prefer props, avoid redundant `computed`, and prefer `computed` over `watch`

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Implement computed properties with `computed()` from Vue; avoid using a `ref` with a `watch` if a `computed` would work instead

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Use `watch` and `watchEffect` for side effects in Vue components

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use watch and watchEffect for side effects

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.{ts,tsx,vue} : Minimize nesting in code (e.g., deeply nested `if` or `for` statements); apply the Arrow Anti-Pattern principle

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/common/TreeExplorer.vue
⏰ 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: test
  • GitHub Check: lint-and-format
  • GitHub Check: setup
  • GitHub Check: collect
🔇 Additional comments (3)
src/components/common/TreeExplorer.vue (2)

486-491: LGTM!

The addFolderCommand exposed method correctly uses nodeKeyMap for O(1) node lookup instead of tree traversal, and includes proper null checking. The implementation is clean and type-safe.


504-515: LGTM!

The use of CSS pseudo-elements (::before and ::after) for spacers is an elegant solution that avoids extra DOM nodes. The CSS variables provide a clean interface between JavaScript and CSS for dynamic heights.

src/utils/treeUtil.ts (1)

108-122: No issues found. The privatization of findNodeByKey from export to const is safe—the function has no external consumers in the codebase and is only used internally at line 150 in combineTrees.

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: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65a27a9 and e9e56ad.

📒 Files selected for processing (1)
  • src/components/common/TreeExplorer.vue (8 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.vue

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

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/common/TreeExplorer.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Vue component file names must use PascalCase; for example, MenuHamburger.vue

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/common/TreeExplorer.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/components/common/TreeExplorer.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/components/common/TreeExplorer.vue
🧠 Learnings (11)
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Be judicious with addition of new refs or other state: prefer props, avoid redundant `computed`, and prefer `computed` over `watch`

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Implement computed properties with `computed()` from Vue; avoid using a `ref` with a `watch` if a `computed` would work instead

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Use `watch` and `watchEffect` for side effects in Vue components

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use watch and watchEffect for side effects

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.{ts,tsx,vue} : Minimize nesting in code (e.g., deeply nested `if` or `for` statements); apply the Arrow Anti-Pattern principle

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.{ts,tsx,vue} : Keep functions short and functional

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/common/TreeExplorer.vue
⏰ 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). (3)
  • GitHub Check: setup
  • GitHub Check: test
  • GitHub Check: lint-and-format
🔇 Additional comments (12)
src/components/common/TreeExplorer.vue (12)

105-128: Window configuration and collapse watcher behavior are sound.

  • The sliding-window constants (WINDOW_SIZE, BUFFER_SIZE, NODE_HEIGHT, SCROLL_FORWARD_THRESHOLD, SCROLL_BACKWARD_THRESHOLD, SCROLL_THROTTLE_MS) make the behavior self-documenting and easy to tune.
  • parentWindowRanges is correctly typed as a Record<string, WindowRange>.
  • The watch(expandedKeys, (newKeys, oldKeys) => { ... }, { deep: true }) uses the oldKeys parameter to clear window ranges for nodes that have just been collapsed. This avoids an extra prevExpandedKeys ref and keeps the logic minimal.

Preserving child window ranges when a parent collapses (only clearing the parent’s own entry) is a reasonable design choice if you want to restore each subtree’s window position after re-expansion; there’s no correctness problem in the current approach.


130-167: Total spacer height aggregation matches the windowing model and is bounded in cost.

getTotalSpacerHeights:

  • Recurses only into expanded nodes (isExpanded guard) and limits recursion to each node’s active window range.
  • Falls back to createInitialWindowRange(totalChildren, WINDOW_SIZE) when no range is present, matching how applyWindowUtil will window children.
  • Uses calculateSpacerHeights(totalChildren, range, NODE_HEIGHT) instead of duplicating math, ensuring consistency with getNodeChildrenStyle.

Because recursion is bounded by WINDOW_SIZE per expanded parent, the cost per throttled scroll event remains acceptable even for large trees. The logic aligns correctly with the way CSS pseudo-element spacers are later applied.


169-193: Reset-to-top behavior for windows is consistent and scoped.

resetNodeWindowToTop and resetWindowsToTop:

  • Only affect expanded nodes (via isExpanded checks), preventing unnecessary work on collapsed branches.
  • Use createInitialWindowRange to reset each node’s window to the initial slice, then recurse into expanded children so nested windows also return to the top.
  • Are only invoked when the scroll is at the top (from handleTreeScroll), which matches user expectations.

This provides a clear “snap back to top” semantics for the whole virtualized tree without perturbing collapsed branches.


281-306: nodeKeyMap and displayRoot computed values improve lookup performance and decouple windowing.

  • nodeKeyMap builds a flat Record<string, RenderedTreeExplorerNode> via a single traversal of renderedRoot. This replaces repeated O(n) traversals for operations like addFolderCommand and children styling, which is a significant perf improvement for large trees.
  • displayRoot applies the sliding window only at the children level via applyWindowUtil(node, parentWindowRanges.value, WINDOW_SIZE), while keeping the rest of the node data intact via object spread.

This separation—renderedRoot as the canonical full tree, displayRoot as the windowed view, and nodeKeyMap as the index—results in a clean architecture with good performance characteristics.


308-338: getNodeChildrenStyle correctly ties spacer styles to the full tree structure.

This helper:

  • Immediately returns a basic class for leaf or childless nodes, avoiding unnecessary work.
  • Uses nodeKeyMap to fetch the original, un-windowed node so spacer calculations reflect the full child count even though displayRoot children are sliced.
  • Computes the range via existing window state or createInitialWindowRange, then uses calculateSpacerHeights with NODE_HEIGHT to derive topSpacer/bottomSpacer.
  • Returns a class and style object that set CSS variables consumed by the pseudo-elements.

The approach is consistent with getTotalSpacerHeights, minimizes duplicated math, and ensures PT styling remains declarative.


371-383: Wrapping node.handleClick with centralized async error handling is a solid improvement.

The updated onNodeContentClick:

  • Initializes selectionKeys when the parent isn’t managing them, preserving previous behavior.
  • Wraps node.handleClick in errorHandling.wrapWithErrorHandlingAsync, passing any node-specific handleError.
  • Awaits the wrapped function before emitting 'nodeClick', giving error handling a chance to run first.

This brings click handling in line with the existing rename/delete error handling patterns and reduces the chance of unhandled rejections from node-defined click handlers.


389-394: extraMenuItems computed now safely supports function or array menus.

By handling:

  • undefined -> []
  • function -> contextMenuItems(menuTargetNode.value!)
  • array -> contextMenuItems

you preserve backward compatibility and allow dynamic menu generation based on the target node. The non-null assertion on menuTargetNode.value! is safe given that this computed is only used when a target node is set prior to showing the menu.


424-457: Menu items pipeline correctly integrates i18n and centralized error handling.

  • Labels for rename/delete use t('g.rename') and t('g.delete'), complying with the vue-i18n requirement.
  • Visibility flags respect the presence of handleRename/handleDelete.
  • The mapping step wraps each menu item’s command via wrapCommandWithErrorHandler, with isAsync hinted for delete, ensuring click errors are handled consistently.

This keeps UI strings localized and consolidates error handling for context menu actions.


482-492: Using nodeKeyMap in addFolderCommand is a good perf and correctness win.

Exposing:

addFolderCommand: (targetNodeKey: string) => {
  const targetNode = nodeKeyMap.value[targetNodeKey]
  if (targetNode) {
    addFolderCommand(targetNode)
  }
}

avoids repeated tree traversal and ensures the target node is resolved against the latest renderedRoot. This is more robust than walking the tree each time, especially when the backing tree can change due to new folders or renames.


196-227: Scroll handler is properly defensive; calculateScrollPercentage already safely guards against degenerate cases.

The implementation at src/utils/virtualListUtils.ts confirms:

  • When realContentHeight <= 0 (empty tree), it explicitly returns 1
  • When scrollTop < topSpacerHeight, it uses Math.max(0, ...) to prevent negative values
  • Full test coverage validates these edge cases, including a dedicated test for zero height

The concern in the original comment has already been addressed.


47-75: Imports of VueUse throttle and virtual list utilities are appropriate and cohesive.

Bringing in useThrottleFn from @vueuse/core for the scroll handler and centralizing virtual-list math in virtualListUtils (applyWindow, calculateScrollPercentage, calculateSpacerHeights, createInitialWindowRange, shiftWindowForward/Backward) is a good separation of concerns. The WindowRange type use keeps parentWindowRanges well-typed. The useThrottleFn signature correctly accepts a callback and delay (100ms), matching the VueUse specification.

No issues with these imports or their usage patterns.


7-31: Use context.node instead of instance?.node to access the current node in the nodeChildren hook.

The nodeChildren hook receives a TreePassThroughMethodOptions object where the node data is available in the context field (which contains per-node context like index, expanded, selected, and node), not in the instance field. The instance parameter refers to the component instance itself and is not documented to contain a .node property. This is inconsistent with the nodeContent hook on line 16, which correctly accesses the node via context.node. Update line 28-29 to destructure context and use context.node instead.

Likely an incorrect or invalid review comment.

@Myestery
Copy link
Collaborator

I ran into this error while testing. If you scroll really fast, the list kinda disappears

Screen.Recording.2025-12-15.at.21.03.17.mov

@Yourz
Copy link
Collaborator Author

Yourz commented Dec 16, 2025

I ran into this error while testing. If you scroll really fast, the list kinda disappears

Screen.Recording.2025-12-15.at.21.03.17.mov

maybe shorten the throttle latency would solve it? I'll try it again

@Yourz
Copy link
Collaborator Author

Yourz commented Dec 16, 2025

i tried it and got the repro path:

not only u need to scroll really fast(it seems that really fast scrolling will lead to a blank status, but finally the nodes will be displayed at the end), but also u need to move ur cursor out of the node library sidebar when blank sidebar showed up after a really fast scrolling.

Does this repro path makes sense to you? @Myestery

@Yourz Yourz enabled auto-merge (squash) December 16, 2025 15:28
@Myestery Myestery disabled auto-merge December 16, 2025 21:26
@Myestery
Copy link
Collaborator

i tried it and got the repro path:

not only u need to scroll really fast(it seems that really fast scrolling will lead to a blank status, but finally the nodes will be displayed at the end), but also u need to move ur cursor out of the node library sidebar when blank sidebar showed up after a really fast scrolling.

Does this repro path makes sense to you? @Myestery

Actually, no.
Its only related to fast scrolling.
You may want to try calculating the target window position directly from scroll position
feel free to use this link to reproduce https://pr-1716.testenvs.comfy.org

Apply suggestion from coderabbitai bot
Apply DRY principle suggestion from coderabbitai
- Use createInitialWindowRange and calculateSpacerHeights in getTotalSpacerHeights
- Use active range after shift for recursive window processing
- Remove unused export from findNodeByKey
Wrap node.handleClick() with errorHandling.wrapWithErrorHandlingAsync
to prevent unhandled promise rejections
@Yourz Yourz force-pushed the feat/tree-explorer-virtual-list branch from e9e56ad to cac8e5d Compare December 17, 2025 15:41
@Yourz
Copy link
Collaborator Author

Yourz commented Dec 17, 2025

@Myestery @christian-byrne Just fix the blank side bar

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9e56ad and cac8e5d.

📒 Files selected for processing (4)
  • src/components/common/TreeExplorer.vue (8 hunks)
  • src/utils/__tests__/virtualListUtils.test.ts (1 hunks)
  • src/utils/treeUtil.ts (1 hunks)
  • src/utils/virtualListUtils.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (13)
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

src/**/*.{vue,ts}: Avoid using ref and watch together - use computed instead if possible
Do not add ref if a prop would suffice; do not add computed if the ref/prop directly would work; use watch only when computed won't accomplish the goal
Leverage VueUse functions for performance-enhancing styles

Files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/components/common/TreeExplorer.vue
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.ts
src/**/*.ts

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

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

src/**/*.ts: Extract complex type definitions that are inlined in multiple related places - name them for reuse
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones

Files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.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

src/**/*.{ts,tsx,vue}: ESLint rules: Vue + TS rules, no floating promises, unused imports disallowed, i18n raw text restrictions in templates
Use es-toolkit for utility functions
Avoid mutable state - prefer immutability and assignment at point of declaration
Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue

Files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/components/common/TreeExplorer.vue
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/components/common/TreeExplorer.vue
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.ts
src/**/*.{js,ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript exclusively - no new JavaScript files

Files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/components/common/TreeExplorer.vue
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.ts
src/**/*.{ts,tsx,vue,js}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx,vue,js}: Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see .prettierrc
Sort and group imports by plugin, run pnpm format before committing

Files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/components/common/TreeExplorer.vue
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not use function expressions - use function declarations instead when possible

Files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.ts
src/**/*.vue

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

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

src/**/*.vue: Vue 3 SFCs must use Composition API only - no Options API
Use <script setup lang="ts"> for component logic
Use Tailwind 4 utility classes for styling - avoid <style> blocks
Use cn() utility from @/utils/tailwindUtil to merge Tailwind class names - never use :class="[]" syntax
Never use the dark: Tailwind variant - use semantic values from style.css theme instead (e.g., bg-node-component-surface)
Use Vue 3.5+ TypeScript style default prop declaration with reactive destructuring - prefer useModel to prop/emit pairs, do not use withDefaults
Do not import Vue macros unnecessarily
Use vue-i18n in composition API for string literals - place translation entries in src/locales/en/main.json
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Avoid new usage of PrimeVue components

Files:

  • src/components/common/TreeExplorer.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/common/TreeExplorer.vue
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/components/common/TreeExplorer.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Vue components must be named in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/common/TreeExplorer.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/common/TreeExplorer.vue
🧠 Learnings (35)
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to tests-ui/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to tests-ui/**/*.test.ts : For mocking, leverage Vitest's utilities where possible

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to tests-ui/**/*.test.ts : Aim for behavioral coverage of critical and new features

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to tests-ui/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files, use `vi.hoisted()` if necessary

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Test across multiple viewports

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to tests-ui/**/*.test.ts : For Component testing, use Vue Test Utils and follow advice about making components easy to test

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to tests-ui/**/*.test.ts : Do not write tests dependent on non-behavioral features like utility classes or styles

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/utils/__tests__/virtualListUtils.test.ts
  • src/components/common/TreeExplorer.vue
  • src/utils/virtualListUtils.ts
  • src/utils/treeUtil.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to src/**/*.{vue,ts} : Avoid using `ref` and `watch` together - use `computed` instead if possible

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to src/**/*.{vue,ts} : Do not add `ref` if a prop would suffice; do not add `computed` if the ref/prop directly would work; use `watch` only when `computed` won't accomplish the goal

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use watch and watchEffect for side effects

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-01T23:42:30.894Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7084
File: src/renderer/extensions/vueNodes/components/SlotConnectionDot.vue:23-26
Timestamp: 2025-12-01T23:42:30.894Z
Learning: In the ComfyUI frontend codebase, Tailwind CSS is configured with Preflight enabled (default), which automatically provides `content: ''` for pseudo-elements when using `after:` or `before:` variants - no need to explicitly add `after:content-['']`.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to src/**/*.vue : Use Tailwind 4 utility classes for styling - avoid `<style>` blocks

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to src/**/*.vue : Never use the `dark:` Tailwind variant - use semantic values from `style.css` theme instead (e.g., `bg-node-component-surface`)

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,css} : Use Tailwind CSS only for styling (no custom CSS)

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guide

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to src/**/*.vue : Avoid new usage of PrimeVue components

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to src/**/*.{ts,tsx,vue,js} : Indent with 2 spaces, use single quotes, no trailing semicolons, line width 80 - see `.prettierrc`

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-17T01:01:03.597Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-17T01:01:03.597Z
Learning: Applies to src/**/*.vue : Use `cn()` utility from `@/utils/tailwindUtil` to merge Tailwind class names - never use `:class="[]"` syntax

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/common/TreeExplorer.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).

Applied to files:

  • src/components/common/TreeExplorer.vue
🧬 Code graph analysis (3)
src/utils/__tests__/virtualListUtils.test.ts (2)
src/utils/virtualListUtils.ts (7)
  • createInitialWindowRange (108-114)
  • WindowRange (3-6)
  • shiftWindowForward (49-61)
  • shiftWindowBackward (71-83)
  • calculateSpacerHeights (92-100)
  • calculateScrollPercentage (125-136)
  • applyWindow (15-39)
src/types/treeExplorerTypes.ts (1)
  • RenderedTreeExplorerNode (64-74)
src/utils/virtualListUtils.ts (1)
src/types/treeExplorerTypes.ts (1)
  • RenderedTreeExplorerNode (64-74)
src/utils/treeUtil.ts (3)
src/types/treeExplorerTypes.ts (1)
  • TreeNode (5-8)
src/stores/queueStore.ts (1)
  • key (282-284)
src/stores/userFileStore.ts (1)
  • key (76-78)
⏰ 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: setup
  • GitHub Check: test
  • GitHub Check: collect
🔇 Additional comments (6)
src/utils/treeUtil.ts (1)

108-122: LGTM! Appropriate reduction of public API surface.

Converting findNodeByKey from an exported function to a module-private constant is well-aligned with this PR's shift to O(1) lookups via nodeKeyMap in TreeExplorer.vue. The function remains available for internal use by combineTrees (line 150), and eliminating the export reduces the module's public surface area.

Based on coding guidelines, which encourage minimizing exported values from each module.

src/utils/__tests__/virtualListUtils.test.ts (1)

1-221: Excellent test coverage for the new virtualization utilities.

The test suite comprehensively covers all exported functions with proper edge-case handling:

  • Boundary conditions (zero children, already at start/end)
  • Window capping and adjustment logic
  • Spacer calculations across different window positions
  • Recursive window application to nested structures
  • Scroll percentage with spacer adjustments

The tests follow vitest patterns correctly, use proper type imports, and provide behavioral validation for critical virtualization logic.

Based on learnings, which emphasize behavioral coverage of new features and proper use of vitest utilities.

src/components/common/TreeExplorer.vue (4)

197-213: Good addition to handle the blank screen issue during fast scrolling.

The handleMouseLeave handler addresses the reproduction path described in the PR comments: when scrolling very fast and the cursor leaves the sidebar, this ensures windows are realigned with the current scroll position. The logic correctly resets windows at the top or conditionally shifts them based on scroll percentage, preventing the blank state from persisting after cursor movement.


233-262: Iterative window shifting correctly addresses the fast-scroll blank screen issue.

The scroll handler's iterative approach (with MAX_SCROLL_ITERATIONS) directly addresses the fast-scrolling reproduction reported by Myestery. By allowing multiple window shifts per throttled scroll event and recalculating the scroll percentage after each shift, the implementation ensures the active window "catches up" to the scroll position even when the cursor has left the sidebar. This is a robust solution that balances responsiveness with safety via the iteration cap.


315-328: Efficient O(1) node lookup via computed map.

The nodeKeyMap computed property replaces O(n) tree traversals with O(1) lookups, addressing previous performance concerns. The recursive buildMap helper correctly traverses the entire tree once per render cycle, and the map is appropriately reused by getNodeChildrenStyle and addFolderCommand. This is a clean solution that eliminates repeated traversal overhead.


397-413: Error handling integration is correctly implemented.

The errorHandling composable is properly initialized (line 397) and used to wrap both node actions (lines 407-410) and menu commands. The integration respects each node's custom handleError callback, providing consistent error handling across user interactions.

Comment on lines +15 to +136
export const applyWindow = (
node: RenderedTreeExplorerNode,
windowRanges: Record<string, WindowRange>,
windowSize: number
): RenderedTreeExplorerNode => {
if (!node.children || node.leaf || node.children.length === 0) {
return node
}

const totalChildren = node.children.length
const range = windowRanges[node.key] ?? {
start: 0,
end: Math.min(windowSize, totalChildren)
}

// Recursively apply window to children
const windowedChildren = node.children
.slice(range.start, range.end)
.map((child) => applyWindow(child, windowRanges, windowSize))

return {
...node,
children: windowedChildren
}
}

/**
* Shift window forward (load more at end)
* @param currentRange - Current window range
* @param totalChildren - Total number of children
* @param bufferSize - Number of items to shift
* @param windowSize - Maximum window size
* @returns New window range, or null if no shift needed
*/
export const shiftWindowForward = (
currentRange: WindowRange,
totalChildren: number,
bufferSize: number,
windowSize: number
): WindowRange | null => {
if (currentRange.end >= totalChildren) {
return null
}
const newEnd = Math.min(currentRange.end + bufferSize, totalChildren)
const newStart = Math.max(0, newEnd - windowSize)
return { start: newStart, end: newEnd }
}

/**
* Shift window backward (load more at start)
* @param currentRange - Current window range
* @param totalChildren - Total number of children
* @param bufferSize - Number of items to shift
* @param windowSize - Maximum window size
* @returns New window range, or null if no shift needed
*/
export const shiftWindowBackward = (
currentRange: WindowRange,
totalChildren: number,
bufferSize: number,
windowSize: number
): WindowRange | null => {
if (currentRange.start <= 0) {
return null
}
const newStart = Math.max(0, currentRange.start - bufferSize)
const newEnd = Math.min(newStart + windowSize, totalChildren)
return { start: newStart, end: newEnd }
}

/**
* Calculate spacer heights for a node's children
* @param totalChildren - Total number of children
* @param range - Current window range
* @param nodeHeight - Height of each node in pixels
* @returns Top and bottom spacer heights
*/
export const calculateSpacerHeights = (
totalChildren: number,
range: WindowRange,
nodeHeight: number
): { topSpacer: number; bottomSpacer: number } => {
const topSpacer = range.start * nodeHeight
const bottomSpacer = Math.max(0, totalChildren - range.end) * nodeHeight
return { topSpacer, bottomSpacer }
}

/**
* Create initial window range for a node
* @param totalChildren - Total number of children
* @param windowSize - Maximum window size
* @returns Initial window range starting from 0
*/
export const createInitialWindowRange = (
totalChildren: number,
windowSize: number
): WindowRange => ({
start: 0,
end: Math.min(windowSize, totalChildren)
})

/**
* Calculate scroll percentage adjusted for spacer heights
* @param scrollTop - Current scroll position
* @param scrollHeight - Total scrollable height
* @param clientHeight - Visible height
* @param topSpacerHeight - Combined top spacer height
* @param bottomSpacerHeight - Combined bottom spacer height
* @returns Scroll percentage between 0 and 1
*/
export const calculateScrollPercentage = (
scrollTop: number,
scrollHeight: number,
clientHeight: number,
topSpacerHeight: number,
bottomSpacerHeight: number
): number => {
const realContentHeight = scrollHeight - topSpacerHeight - bottomSpacerHeight
if (realContentHeight <= 0) return 1
const adjustedScrollTop = Math.max(0, scrollTop - topSpacerHeight)
return (adjustedScrollTop + clientHeight) / realContentHeight
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Convert arrow function expressions to function declarations.

All exported functions in this module are pure and should use function declaration syntax per the repository's coding guidelines. Function declarations offer better hoisting clarity, improved tooling support, and align with the functional programming preferences of this codebase.

Apply this refactor to convert all exports:

-export const applyWindow = (
+export function applyWindow(
   node: RenderedTreeExplorerNode,
   windowRanges: Record<string, WindowRange>,
   windowSize: number
-): RenderedTreeExplorerNode => {
+): RenderedTreeExplorerNode {
   if (!node.children || node.leaf || node.children.length === 0) {
     return node
   }

   const totalChildren = node.children.length
   const range = windowRanges[node.key] ?? {
     start: 0,
     end: Math.min(windowSize, totalChildren)
   }

   // Recursively apply window to children
   const windowedChildren = node.children
     .slice(range.start, range.end)
     .map((child) => applyWindow(child, windowRanges, windowSize))

   return {
     ...node,
     children: windowedChildren
   }
 }

-export const shiftWindowForward = (
+export function shiftWindowForward(
   currentRange: WindowRange,
   totalChildren: number,
   bufferSize: number,
   windowSize: number
-): WindowRange | null => {
+): WindowRange | null {
   if (currentRange.end >= totalChildren) {
     return null
   }
   const newEnd = Math.min(currentRange.end + bufferSize, totalChildren)
   const newStart = Math.max(0, newEnd - windowSize)
   return { start: newStart, end: newEnd }
 }

-export const shiftWindowBackward = (
+export function shiftWindowBackward(
   currentRange: WindowRange,
   totalChildren: number,
   bufferSize: number,
   windowSize: number
-): WindowRange | null => {
+): WindowRange | null {
   if (currentRange.start <= 0) {
     return null
   }
   const newStart = Math.max(0, currentRange.start - bufferSize)
   const newEnd = Math.min(newStart + windowSize, totalChildren)
   return { start: newStart, end: newEnd }
 }

-export const calculateSpacerHeights = (
+export function calculateSpacerHeights(
   totalChildren: number,
   range: WindowRange,
   nodeHeight: number
-): { topSpacer: number; bottomSpacer: number } => {
+): { topSpacer: number; bottomSpacer: number } {
   const topSpacer = range.start * nodeHeight
   const bottomSpacer = Math.max(0, totalChildren - range.end) * nodeHeight
   return { topSpacer, bottomSpacer }
 }

-export const createInitialWindowRange = (
+export function createInitialWindowRange(
   totalChildren: number,
   windowSize: number
-): WindowRange => ({
+): WindowRange {
+  return {
     start: 0,
     end: Math.min(windowSize, totalChildren)
-})
+  }
+}

-export const calculateScrollPercentage = (
+export function calculateScrollPercentage(
   scrollTop: number,
   scrollHeight: number,
   clientHeight: number,
   topSpacerHeight: number,
   bottomSpacerHeight: number
-): number => {
+): number {
   const realContentHeight = scrollHeight - topSpacerHeight - bottomSpacerHeight
   if (realContentHeight <= 0) return 1
   const adjustedScrollTop = Math.max(0, scrollTop - topSpacerHeight)
   return (adjustedScrollTop + clientHeight) / realContentHeight
 }

Based on learnings, which indicate preference for function declarations over expressions for pure functions across TypeScript files.

🤖 Prompt for AI Agents
In src/utils/virtualListUtils.ts around lines 15-136, the file exports several
functions as arrow expressions; replace each exported const arrow function with
an exported function declaration to follow the repo guideline. Specifically,
convert export const applyWindow = (...) => { ... } into export function
applyWindow(...) : RenderedTreeExplorerNode { ... } and do the same for
shiftWindowForward, shiftWindowBackward, calculateSpacerHeights,
createInitialWindowRange, and calculateScrollPercentage, preserving all
parameter and return types, JSDoc comments, internal logic, and the export
keyword placed before the function declaration.

@Myestery Myestery added preview and removed preview labels Dec 17, 2025
Comment on lines +68 to +75
import {
applyWindow as applyWindowUtil,
calculateScrollPercentage,
calculateSpacerHeights,
createInitialWindowRange,
shiftWindowBackward as shiftWindowBackwardUtil,
shiftWindowForward as shiftWindowForwardUtil
} from '@/utils/virtualListUtils'
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we get rid of the import aliases?

Comment on lines +108 to +112
const BUFFER_SIZE = 20
const NODE_HEIGHT = 28 // Approximate height per tree node in pixels
const SCROLL_FORWARD_THRESHOLD = 0.7 // Shift window forward when scrolled past 70%
const SCROLL_BACKWARD_THRESHOLD = 0.3 // Shift window backward when scrolled below 30%
const SCROLL_THROTTLE_MS = 100 // Throttle scroll handler to every 100ms
Copy link
Contributor

Choose a reason for hiding this comment

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

For these comments, could we express the same information in the variable names and then not need the comments at all?

{ deep: true }
)
// Ref to access the tree container for scroll detection
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we cut down on some of these comments? Not sure how much they are helping

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think this could be simplified at all by pulling some of the observed state out into computed values? In essence, we have a list of items and a window range. We need to observe the list of items, determine our visible window, then calculation the spacer heights. See example. Perhaps there are some unique challenges here however. What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

makes sense. will do it.

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

Labels

preview size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants