Skip to content

fix: suppress link rendering during slot sync after graph reconfigure#8367

Merged
christian-byrne merged 7 commits intomainfrom
vue-nodes-link-unalign
Feb 3, 2026
Merged

fix: suppress link rendering during slot sync after graph reconfigure#8367
christian-byrne merged 7 commits intomainfrom
vue-nodes-link-unalign

Conversation

@christian-byrne
Copy link
Contributor

@christian-byrne christian-byrne commented Jan 28, 2026

Description

Fixes link alignment issues after undo/redo operations in Vue Nodes 2.0. When multiple connections exist from the same output to different nodes, performing an undo would cause the connections to become misaligned with their inputs.

Root Cause

When undo triggers loadGraphData, the graph is reconfigured and Vue node components are destroyed and recreated. The new slot elements mount and schedule RAF-batched position syncs via scheduleSlotLayoutSync. However, links are drawn before the RAF batch completes, causing getSlotPosition() to return stale/missing positions.

Solution

  • Export a new flushPendingSlotLayoutSyncs() function from useSlotElementTracking.ts
  • Create a useGraphConfigureSlotSync composable that flushes pending syncs after graph configuration
  • Integrate the flush into addAfterConfigureHandler in app.ts, called after onAfterGraphConfigured
  • Force canvas redraw after flushing to render links with correct positions

Testing

  • Added unit tests for flushPendingSlotLayoutSyncs
  • Added unit tests for useGraphConfigureSlotSync composable
  • Manual verification: connections now align correctly after undo/redo operations

┆Issue is synchronized with this Notion page by Unito

@christian-byrne christian-byrne requested a review from a team as a code owner January 28, 2026 08:19
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jan 28, 2026
@github-actions
Copy link

github-actions bot commented Jan 28, 2026

🎭 Playwright Tests: ✅ Passed

Results: 507 passed, 0 failed, 0 flaky, 8 skipped (Total: 515)

📊 Browser Reports
  • chromium: View Report (✅ 495 / ❌ 0 / ⚠️ 0 / ⏭️ 8)
  • 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)

@github-actions
Copy link

github-actions bot commented Jan 28, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 01/30/2026, 02:02:29 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 28, 2026

Warning

Rate limit exceeded

@christian-byrne has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 39 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Adds a pending-slot-sync flag to layout store, re-asserts the flag when scheduling slot syncs, exports and updates flushScheduledSlotLayoutSync to manage the flag and canvas dirtying, and prevents link rendering in LGraphCanvas while slot positions are pending.

Changes

Cohort / File(s) Summary
Layout State Management
src/renderer/core/layout/store/layoutStore.ts
Adds private _pendingSlotSync, public getter pendingSlotSync and method setPendingSlotSync(value) to track pending slot-position synchronization.
Slot Sync Tracking
src/renderer/extensions/vueNodes/composables/useSlotElementTracking.ts
scheduleSlotLayoutSync now calls layoutStore.setPendingSlotSync(true) when adding pending nodes; flushScheduledSlotLayoutSync() is exported and updated to clear the pending flag and mark canvas dirty after processing (and to clear the flag when there are no pending nodes).
App Configure Flow
src/scripts/app.ts
Imports layoutStore and flushScheduledSlotLayoutSync; sets layoutStore.setPendingSlotSync(true) during Vue-nodes reconfigure; finally block calls flushScheduledSlotLayoutSync() and marks canvas dirty when Vue-nodes mode is active.
Rendering Guards
src/lib/litegraph/src/LGraphCanvas.ts
Adds guards to skip link rendering (two insertion points) when layoutStore.pendingSlotSync is true and clears visible reroute set to avoid rendering links until slot positions are synchronized.

Sequence Diagram

sequenceDiagram
    participant App as App (configure)
    participant Layout as layoutStore
    participant SlotTrack as useSlotElementTracking
    participant Canvas as LGraphCanvas

    App->>Layout: setPendingSlotSync(true)
    App->>SlotTrack: scheduleSlotLayoutSync()
    SlotTrack->>Layout: setPendingSlotSync(true)
    Note over Canvas: Canvas checks pending flag and\nskips link rendering while true (clears visible reroute set)
    App->>SlotTrack: flushScheduledSlotLayoutSync()
    SlotTrack->>SlotTrack: process pending slot nodes
    SlotTrack->>Layout: setPendingSlotSync(false)
    SlotTrack-->>App: return
    App->>Canvas: markDirty()
    Canvas->>Canvas: render links using synced slot positions
Loading

Suggested Reviewers

  • AustinMroz
  • simula-r
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch vue-nodes-link-unalign

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.

@coderabbitai coderabbitai bot requested review from AustinMroz and DrJKL January 28, 2026 08:20
@christian-byrne christian-byrne marked this pull request as draft January 28, 2026 08:21
@christian-byrne christian-byrne marked this pull request as ready for review January 28, 2026 08:21
@github-actions
Copy link

github-actions bot commented Jan 28, 2026

Bundle Size Report

Summary

  • Raw size: 22.1 MB baseline 22.1 MB — 🔴 +660 B
  • Gzip: 4.61 MB baseline 4.61 MB — 🔴 +98 B
  • Brotli: 3.42 MB baseline 3.42 MB — 🔴 +288 B
  • Bundles: 173 current • 173 baseline • 81 added / 81 removed

Category Glance
Data & Services 🔴 +866 B (2.71 MB) · Other 🟢 -198 B (7.1 MB) · Panels & Settings 🟢 -8 B (471 kB) · Vendor & Third-Party ⚪ 0 B (10.7 MB) · Graph Workspace ⚪ 0 B (974 kB) · Views & Navigation ⚪ 0 B (80.7 kB) · + 5 more

Per-category breakdown
App Entry Points — 26 kB (baseline 26 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-B8BoGvvV.js (removed) 26 kB 🟢 -26 kB 🟢 -7.51 kB 🟢 -6.61 kB
assets/index-BT9E2ZAU.js (new) 26 kB 🔴 +26 kB 🔴 +7.5 kB 🔴 +6.61 kB

Status: 1 added / 1 removed

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

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-d6deFrXy.js (new) 974 kB 🔴 +974 kB 🔴 +197 kB 🔴 +149 kB
assets/GraphView-OqG5I-Q1.js (removed) 974 kB 🟢 -974 kB 🟢 -197 kB 🟢 -149 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-CnmJLMIp.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +3.6 kB 🔴 +3.05 kB
assets/CloudSurveyView-DLbX7w_v.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -3.6 kB 🟢 -3.05 kB
assets/CloudLoginView-BPP6Razq.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.09 kB 🟢 -2.71 kB
assets/CloudLoginView-DgQhOSZy.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.09 kB 🔴 +2.71 kB
assets/UserCheckView-CkBTz4F7.js (new) 10.5 kB 🔴 +10.5 kB 🔴 +2.45 kB 🔴 +2.13 kB
assets/UserCheckView-DceH8OCs.js (removed) 10.5 kB 🟢 -10.5 kB 🟢 -2.44 kB 🟢 -2.13 kB
assets/CloudLayoutView-BJtba192.js (removed) 8.54 kB 🟢 -8.54 kB 🟢 -2.24 kB 🟢 -1.96 kB
assets/CloudLayoutView-BmKZqeTU.js (new) 8.54 kB 🔴 +8.54 kB 🔴 +2.24 kB 🔴 +1.95 kB
assets/CloudSignupView-w8W5O5cW.js (new) 8.18 kB 🔴 +8.18 kB 🔴 +2.33 kB 🔴 +2.02 kB
assets/CloudSignupView-yq1ESUXW.js (removed) 8.18 kB 🟢 -8.18 kB 🟢 -2.33 kB 🟢 -2.02 kB
assets/CloudForgotPasswordView-BFOnmsSp.js (removed) 6.26 kB 🟢 -6.26 kB 🟢 -1.93 kB 🟢 -1.69 kB
assets/CloudForgotPasswordView-CE3oQJJ2.js (new) 6.26 kB 🔴 +6.26 kB 🔴 +1.93 kB 🔴 +1.69 kB
assets/UserSelectView-BVXiNB63.js (removed) 5.28 kB 🟢 -5.28 kB 🟢 -1.76 kB 🟢 -1.58 kB
assets/UserSelectView-CtOea-zJ.js (new) 5.28 kB 🔴 +5.28 kB 🔴 +1.76 kB 🔴 +1.57 kB
assets/CloudSubscriptionRedirectView-C_RhR6Fq.js (removed) 5.27 kB 🟢 -5.27 kB 🟢 -1.73 kB 🟢 -1.55 kB
assets/CloudSubscriptionRedirectView-D8LHMO8a.js (new) 5.27 kB 🔴 +5.27 kB 🔴 +1.73 kB 🔴 +1.54 kB
assets/CloudAuthTimeoutView-BAdKANNq.js (new) 5.24 kB 🔴 +5.24 kB 🔴 +1.71 kB 🔴 +1.49 kB
assets/CloudAuthTimeoutView-BWKjYVGF.js (removed) 5.24 kB 🟢 -5.24 kB 🟢 -1.71 kB 🟢 -1.48 kB
assets/CloudSorryContactSupportView-n5f-fGMz.js 1.97 kB 1.97 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/layout-V93lMUpe.js 500 B 500 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 9 added / 9 removed

Panels & Settings — 471 kB (baseline 471 kB) • 🟢 -8 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WorkspacePanel-CD6XquVz.js (new) 29.8 kB 🔴 +29.8 kB 🔴 +5.89 kB 🔴 +5.15 kB
assets/WorkspacePanel-cSBGDuKt.js (removed) 29.8 kB 🟢 -29.8 kB 🟢 -5.89 kB 🟢 -5.14 kB
assets/LegacyCreditsPanel-CurmF-C8.js (removed) 23.8 kB 🟢 -23.8 kB 🟢 -5.94 kB 🟢 -5.22 kB
assets/LegacyCreditsPanel-D9WD2KUi.js (new) 23.8 kB 🔴 +23.8 kB 🔴 +5.95 kB 🔴 +5.23 kB
assets/SubscriptionPanel-2NrygNwr.js (new) 21 kB 🔴 +21 kB 🔴 +5.05 kB 🔴 +4.45 kB
assets/SubscriptionPanel-BfT4O7Pw.js (removed) 21 kB 🟢 -21 kB 🟢 -5.04 kB 🟢 -4.44 kB
assets/KeybindingPanel-BMpP9dWE.js (new) 14.3 kB 🔴 +14.3 kB 🔴 +3.74 kB 🔴 +3.33 kB
assets/KeybindingPanel-C6QWM5xk.js (removed) 14.3 kB 🟢 -14.3 kB 🟢 -3.74 kB 🟢 -3.32 kB
assets/AboutPanel-DlMxOTjD.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.68 kB 🔴 +2.43 kB
assets/AboutPanel-LhHAHRfK.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.68 kB 🟢 -2.43 kB
assets/ExtensionPanel-CXDUXQkw.js (removed) 10.2 kB 🟢 -10.2 kB 🟢 -2.71 kB 🟢 -2.4 kB
assets/ExtensionPanel-IQJghzOY.js (new) 10.2 kB 🔴 +10.2 kB 🔴 +2.71 kB 🔴 +2.4 kB
assets/ServerConfigPanel-BD3AQL8k.js (new) 7.23 kB 🔴 +7.23 kB 🔴 +2.17 kB 🔴 +1.93 kB
assets/ServerConfigPanel-C7eJPLUf.js (removed) 7.23 kB 🟢 -7.23 kB 🟢 -2.17 kB 🟢 -1.94 kB
assets/UserPanel-u63Q5g-v.js (new) 6.58 kB 🔴 +6.58 kB 🔴 +1.9 kB 🔴 +1.68 kB
assets/UserPanel-ZuECulXk.js (removed) 6.58 kB 🟢 -6.58 kB 🟢 -1.9 kB 🟢 -1.67 kB
assets/refreshRemoteConfig-9IE36XS8.js (removed) 1.31 kB 🟢 -1.31 kB 🟢 -574 B 🟢 -499 B
assets/refreshRemoteConfig-Du0HrR6z.js (new) 1.31 kB 🔴 +1.31 kB 🔴 +573 B 🔴 +494 B
assets/config-CY8nFoyq.js (removed) 1.16 kB 🟢 -1.16 kB 🟢 -611 B 🟢 -543 B
assets/config-haAYiP_1.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +603 B 🔴 +537 B
assets/cloudRemoteConfig-CZEw3NCY.js (removed) 1.11 kB 🟢 -1.11 kB 🟢 -512 B 🟢 -450 B
assets/cloudRemoteConfig-vrp9jqY4.js (new) 1.11 kB 🔴 +1.11 kB 🔴 +509 B 🔴 +438 B
assets/refreshRemoteConfig-ByZfZbWo.js (removed) 169 B 🟢 -169 B 🟢 -108 B 🟢 -102 B
assets/refreshRemoteConfig-ZRLAqM8L.js (new) 169 B 🔴 +169 B 🔴 +108 B 🔴 +111 B
assets/remoteConfig-B0mlVvm7.js 788 B 788 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-2UNjEj6k.js 32.9 kB 32.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-B2OMGvh7.js 31.2 kB 31.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BcujOfpn.js 29.6 kB 29.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BI09_t23.js 29.4 kB 29.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BKamuseh.js 25.8 kB 25.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BlTun9tZ.js 26.4 kB 26.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CZ62uO3e.js 30.2 kB 30.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DaK-NByz.js 35.2 kB 35.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DaS3cSXp.js 39.4 kB 39.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DWbMuaAa.js 32 kB 32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-S7pA60Hj.js 30.4 kB 30.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 12 added / 12 removed

User & Accounts — 3.94 kB (baseline 3.94 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-CZNeLZ9l.js (new) 3.54 kB 🔴 +3.54 kB 🔴 +1.24 kB 🔴 +1.05 kB
assets/auth-DXIjklI5.js (removed) 3.54 kB 🟢 -3.54 kB 🟢 -1.24 kB 🟢 -1.07 kB
assets/firebaseAuthStore-BAGxD41o.js (removed) 217 B 🟢 -217 B 🟢 -138 B 🟢 -117 B
assets/firebaseAuthStore-CuiwxdZt.js (new) 217 B 🔴 +217 B 🔴 +136 B 🔴 +116 B
assets/auth-ngxUAH7-.js (new) 178 B 🔴 +178 B 🔴 +142 B 🔴 +135 B
assets/auth-xtrHtn6I.js (removed) 178 B 🟢 -178 B 🟢 -142 B 🟢 -144 B

Status: 3 added / 3 removed

Editors & Dialogs — 2.89 kB (baseline 2.89 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-63910WHz.js (new) 2.71 kB 🔴 +2.71 kB 🔴 +1.28 kB 🔴 +1.14 kB
assets/useSubscriptionDialog-Chzg7_Ef.js (removed) 2.71 kB 🟢 -2.71 kB 🟢 -1.29 kB 🟢 -1.13 kB
assets/useSubscriptionDialog-B7WaTQMA.js (removed) 179 B 🟢 -179 B 🟢 -110 B 🟢 -95 B
assets/useSubscriptionDialog-BkKcARyw.js (new) 179 B 🔴 +179 B 🔴 +110 B 🔴 +95 B

Status: 2 added / 2 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-DIofqHsw.js (new) 9.52 kB 🔴 +9.52 kB 🔴 +2.68 kB 🔴 +2.41 kB
assets/ComfyQueueButton-MPAF7aDT.js (removed) 9.52 kB 🟢 -9.52 kB 🟢 -2.69 kB 🟢 -2.41 kB
assets/SubscribeButton-DlSkVN7E.js (new) 4.63 kB 🔴 +4.63 kB 🔴 +1.56 kB 🔴 +1.39 kB
assets/SubscribeButton-u1adibXa.js (removed) 4.63 kB 🟢 -4.63 kB 🟢 -1.57 kB 🟢 -1.39 kB
assets/cloudFeedbackTopbarButton-BR82d_4w.js (new) 1.24 kB 🔴 +1.24 kB 🔴 +675 B 🔴 +574 B
assets/cloudFeedbackTopbarButton-DccvfEDa.js (removed) 1.24 kB 🟢 -1.24 kB 🟢 -674 B 🟢 -571 B
assets/ComfyQueueButton-EJLCL6vx.js (new) 181 B 🔴 +181 B 🔴 +118 B 🔴 +107 B
assets/ComfyQueueButton-Wim-ibl_.js (removed) 181 B 🟢 -181 B 🟢 -118 B 🟢 -114 B
assets/Button-Bb_i0j7c.js 3.82 kB 3.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudBadge-CzKMhVcP.js 1.85 kB 1.85 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/TopbarBadge-qACg_vGT.js 8.36 kB 8.36 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar-D80lITos.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-DSv9NFvF.js 2.41 kB 2.41 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 4 added / 4 removed

Data & Services — 2.71 MB (baseline 2.71 MB) • 🔴 +866 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-PON-9pnx.js (new) 2.01 MB 🔴 +2.01 MB 🔴 +425 kB 🔴 +324 kB
assets/dialogService-C23fG8O6.js (removed) 2.01 MB 🟢 -2.01 MB 🟢 -424 kB 🟢 -324 kB
assets/api-CCYdPEh3.js (new) 675 kB 🔴 +675 kB 🔴 +149 kB 🔴 +119 kB
assets/api-CWzHVoQl.js (removed) 674 kB 🟢 -674 kB 🟢 -149 kB 🟢 -118 kB
assets/releaseStore-Cn4Qv9nd.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.4 kB 🟢 -2.12 kB
assets/releaseStore-DHyma6s0.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.4 kB 🔴 +2.12 kB
assets/keybindingService-D2lmxGls.js (new) 6.78 kB 🔴 +6.78 kB 🔴 +1.74 kB 🔴 +1.51 kB
assets/keybindingService-zmPfrxnY.js (removed) 6.78 kB 🟢 -6.78 kB 🟢 -1.75 kB 🟢 -1.51 kB
assets/bootstrapStore-BWHx6cZW.js (removed) 2.69 kB 🟢 -2.69 kB 🟢 -1.03 kB 🟢 -967 B
assets/bootstrapStore-DV_7BxZL.js (new) 2.69 kB 🔴 +2.69 kB 🔴 +1.03 kB 🔴 +929 B
assets/userStore-BePFrLvJ.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -811 B 🟢 -723 B
assets/userStore-DuikIXvm.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +810 B 🔴 +723 B
assets/audioService-BOHdIev2.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +931 B 🔴 +809 B
assets/audioService-dRCkKY2j.js (removed) 2.03 kB 🟢 -2.03 kB 🟢 -932 B 🟢 -812 B
assets/releaseStore-bcyVkMT2.js (removed) 140 B 🟢 -140 B 🟢 -106 B 🟢 -106 B
assets/releaseStore-CNU0F4gt.js (new) 140 B 🔴 +140 B 🔴 +106 B 🔴 +102 B
assets/serverConfigStore-DOoqLe5c.js 2.64 kB 2.64 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 8 added / 8 removed

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useErrorHandling-BcCX7s1a.js (new) 5.21 kB 🔴 +5.21 kB 🔴 +1.53 kB 🔴 +1.35 kB
assets/useErrorHandling-Cv0hm5AV.js (removed) 5.21 kB 🟢 -5.21 kB 🟢 -1.53 kB 🟢 -1.35 kB
assets/useWorkspaceUI-B8oeeVss.js (removed) 3.42 kB 🟢 -3.42 kB 🟢 -976 B 🟢 -834 B
assets/useWorkspaceUI-BpojMocC.js (new) 3.42 kB 🔴 +3.42 kB 🔴 +975 B 🔴 +835 B
assets/useSubscriptionActions-D6c1V_dC.js (new) 2.22 kB 🔴 +2.22 kB 🔴 +870 B 🔴 +755 B
assets/useSubscriptionActions-Dy4r1xGb.js (removed) 2.22 kB 🟢 -2.22 kB 🟢 -873 B 🟢 -764 B
assets/subscriptionCheckoutUtil-BxKTV29A.js (removed) 2.03 kB 🟢 -2.03 kB 🟢 -873 B 🟢 -761 B
assets/subscriptionCheckoutUtil-CMmL7KBU.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +872 B 🔴 +769 B
assets/useSubscriptionCredits-BIt8I8s9.js (removed) 1.39 kB 🟢 -1.39 kB 🟢 -595 B 🟢 -517 B
assets/useSubscriptionCredits-Cw4YvGtV.js (new) 1.39 kB 🔴 +1.39 kB 🔴 +600 B 🔴 +526 B
assets/audioUtils-CJBxbyZE.js (new) 970 B 🔴 +970 B 🔴 +547 B 🔴 +461 B
assets/audioUtils-DPF2qhnH.js (removed) 970 B 🟢 -970 B 🟢 -548 B 🟢 -458 B
assets/useCurrentUser-Cfl6GyhN.js (removed) 145 B 🟢 -145 B 🟢 -114 B 🟢 -98 B
assets/useCurrentUser-l6bcvDVw.js (new) 145 B 🔴 +145 B 🔴 +114 B 🔴 +94 B
assets/_plugin-vue_export-helper-DuK_Fly3.js 467 B 467 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/colorUtil-GMAsfHxw.js 7.2 kB 7.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/markdownRendererUtil-ivqHoiOs.js 1.78 kB 1.78 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/tailwindUtil-CJjrIEVR.js 488 B 488 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 7 added / 7 removed

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

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-chart-DHGfk3hn.js 408 kB 408 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-jpGqhHNG.js 4.1 MB 4.1 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-4Jj8eU28.js 3.04 MB 3.04 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-aCG649nF.js 263 kB 263 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-CERwhPwK.js 1.83 MB 1.83 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-BxrEVL6s.js 650 kB 650 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-Dwii0E-t.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-IX6P8SWv.js 398 kB 398 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 7.1 MB (baseline 7.1 MB) • 🟢 -198 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-BZ9tDby6.js (removed) 180 kB 🟢 -180 kB 🟢 -43.3 kB 🟢 -36.2 kB
assets/core-BHd9zWC-.js (new) 180 kB 🔴 +180 kB 🔴 +43.3 kB 🔴 +36.2 kB
assets/WidgetSelect-BTHF5DDh.js (new) 52.2 kB 🔴 +52.2 kB 🔴 +11.5 kB 🔴 +10 kB
assets/WidgetSelect-CTvO_aUT.js (removed) 52.2 kB 🟢 -52.2 kB 🟢 -11.5 kB 🟢 -10 kB
assets/Load3DControls-Ccyd9m7e.js (new) 35.9 kB 🔴 +35.9 kB 🔴 +5.87 kB 🔴 +5.08 kB
assets/Load3DControls-Col4SX6H.js (removed) 35.9 kB 🟢 -35.9 kB 🟢 -5.87 kB 🟢 -5.08 kB
assets/SubscriptionRequiredDialogContent-9zIRbmqJ.js (new) 28.7 kB 🔴 +28.7 kB 🔴 +6.79 kB 🔴 +5.93 kB
assets/SubscriptionRequiredDialogContent-DkBMOxyk.js (removed) 28.7 kB 🟢 -28.7 kB 🟢 -6.78 kB 🟢 -5.92 kB
assets/CurrentUserPopoverWorkspace-00GbN1aB.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -4.99 kB 🟢 -4.42 kB
assets/CurrentUserPopoverWorkspace-CdkD4wRB.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +4.99 kB 🔴 +4.42 kB
assets/Load3D-BxFjuxmg.js (new) 19.2 kB 🔴 +19.2 kB 🔴 +4.37 kB 🔴 +3.85 kB
assets/Load3D-CIZeyVVm.js (removed) 19.2 kB 🟢 -19.2 kB 🟢 -4.37 kB 🟢 -3.85 kB
assets/WidgetInputNumber-fTgEogks.js (removed) 18.3 kB 🟢 -18.3 kB 🟢 -4.52 kB 🟢 -4.03 kB
assets/WidgetInputNumber-GN1k6eLE.js (new) 18.3 kB 🔴 +18.3 kB 🔴 +4.52 kB 🔴 +4.03 kB
assets/WidgetRecordAudio-Bi90YugX.js (new) 18.3 kB 🔴 +18.3 kB 🔴 +4.97 kB 🔴 +4.44 kB
assets/WidgetRecordAudio-czXF6Bbu.js (removed) 18.3 kB 🟢 -18.3 kB 🟢 -4.97 kB 🟢 -4.44 kB
assets/SubscriptionPanelContentWorkspace-B0jML-Zl.js (new) 18.2 kB 🔴 +18.2 kB 🔴 +4.47 kB 🔴 +3.9 kB
assets/SubscriptionPanelContentWorkspace-CJNHr6C9.js (removed) 18.2 kB 🟢 -18.2 kB 🟢 -4.47 kB 🟢 -3.9 kB
assets/WidgetImageCrop-45yuOiNR.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +4.14 kB 🔴 +3.63 kB
assets/WidgetImageCrop-C_n49czp.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -4.14 kB 🟢 -3.63 kB
assets/PanelTemplate-4MWp8ap-.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +5.45 kB 🔴 +4.8 kB
assets/PanelTemplate-C75prV7c.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -5.45 kB 🟢 -4.8 kB
assets/AudioPreviewPlayer-Bo_BtpPC.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.97 kB 🟢 -2.65 kB
assets/AudioPreviewPlayer-DMJxWlyx.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.98 kB 🔴 +2.65 kB
assets/InviteMemberDialogContent-CHnZnM-Q.js (removed) 8.36 kB 🟢 -8.36 kB 🟢 -2.5 kB 🟢 -2.17 kB
assets/InviteMemberDialogContent-DIiLeoKd.js (new) 8.36 kB 🔴 +8.36 kB 🔴 +2.51 kB 🔴 +2.17 kB
assets/WidgetWithControl-BtdyRS93.js (new) 8.07 kB 🔴 +8.07 kB 🔴 +2.68 kB 🔴 +2.41 kB
assets/WidgetWithControl-Duvr_QlF.js (removed) 8.07 kB 🟢 -8.07 kB 🟢 -2.68 kB 🟢 -2.41 kB
assets/CreateWorkspaceDialogContent-CRUNickN.js (new) 5.93 kB 🔴 +5.93 kB 🔴 +1.93 kB 🔴 +1.68 kB
assets/CreateWorkspaceDialogContent-DdH3l3R9.js (removed) 5.93 kB 🟢 -5.93 kB 🟢 -1.93 kB 🟢 -1.68 kB
assets/EditWorkspaceDialogContent-D4-RuFvO.js (removed) 5.7 kB 🟢 -5.7 kB 🟢 -1.88 kB 🟢 -1.64 kB
assets/EditWorkspaceDialogContent-yzLxuCAc.js (new) 5.7 kB 🔴 +5.7 kB 🔴 +1.88 kB 🔴 +1.64 kB
assets/ValueControlPopover-C7CzlL9n.js (removed) 5.17 kB 🟢 -5.17 kB 🟢 -1.68 kB 🟢 -1.49 kB
assets/ValueControlPopover-eey5sa14.js (new) 5.17 kB 🔴 +5.17 kB 🔴 +1.68 kB 🔴 +1.5 kB
assets/DeleteWorkspaceDialogContent-Cnkxe0_T.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.56 kB 🟢 -1.35 kB
assets/DeleteWorkspaceDialogContent-Cuhcwu82.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.56 kB 🔴 +1.35 kB
assets/LeaveWorkspaceDialogContent-CkMRezIY.js (removed) 4.41 kB 🟢 -4.41 kB 🟢 -1.5 kB 🟢 -1.3 kB
assets/LeaveWorkspaceDialogContent-oFtlM68E.js (new) 4.41 kB 🔴 +4.41 kB 🔴 +1.5 kB 🔴 +1.3 kB
assets/RemoveMemberDialogContent-Caf4tL1_.js (removed) 4.38 kB 🟢 -4.38 kB 🟢 -1.45 kB 🟢 -1.27 kB
assets/RemoveMemberDialogContent-DhMqKMra.js (new) 4.38 kB 🔴 +4.38 kB 🔴 +1.45 kB 🔴 +1.26 kB
assets/RevokeInviteDialogContent-Cv6z6cJF.js (removed) 4.29 kB 🟢 -4.29 kB 🟢 -1.47 kB 🟢 -1.29 kB
assets/RevokeInviteDialogContent-D5uunMUq.js (new) 4.29 kB 🔴 +4.29 kB 🔴 +1.47 kB 🔴 +1.29 kB
assets/GlobalToast-BexxQ9v3.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.1 kB 🔴 +945 B
assets/GlobalToast-DfmV2ARq.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.1 kB 🟢 -945 B
assets/SubscribeToRun-BA03Cueu.js (new) 2.96 kB 🔴 +2.96 kB 🔴 +1.15 kB 🔴 +1.01 kB
assets/SubscribeToRun-D3o893lu.js (removed) 2.96 kB 🟢 -2.96 kB 🟢 -1.16 kB 🟢 -1.01 kB
assets/cloudSessionCookie-7FABp-oW.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -929 B 🟢 -802 B
assets/cloudSessionCookie-BPsANQRo.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +930 B 🔴 +802 B
assets/BaseViewTemplate-BZiHpwOR.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.04 kB 🔴 +938 B
assets/BaseViewTemplate-Dyiv9Vp_.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -941 B
assets/CloudRunButtonWrapper-CUwIRgeE.js (new) 1.79 kB 🔴 +1.79 kB 🔴 +643 B 🔴 +568 B
assets/CloudRunButtonWrapper-D5vO5YVt.js (removed) 1.79 kB 🟢 -1.79 kB 🟢 -647 B 🟢 -563 B
assets/cloudBadges-D-CB4KTx.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +536 B 🔴 +491 B
assets/cloudBadges-DQsArL7q.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -538 B 🟢 -498 B
assets/graphHasMissingNodes-Bq79tMrQ.js (new) 1.06 kB 🔴 +1.06 kB 🔴 +463 B 🔴 +409 B
assets/graphHasMissingNodes-W0T4o18_.js (removed) 1.06 kB 🟢 -1.06 kB 🟢 -462 B 🟢 -418 B
assets/cloudSubscription-Az_B5Pb_.js (removed) 976 B 🟢 -976 B 🟢 -466 B 🟢 -399 B
assets/cloudSubscription-B87VLvKt.js (new) 976 B 🔴 +976 B 🔴 +462 B 🔴 +400 B
assets/nightlyBadges-B6aNYDXi.js (removed) 595 B 🟢 -595 B 🟢 -356 B 🟢 -310 B
assets/nightlyBadges-COBSmkIl.js (new) 595 B 🔴 +595 B 🔴 +354 B 🔴 +309 B
assets/SubscriptionPanelContentWorkspace-Bk-TWVyy.js (removed) 266 B 🟢 -266 B 🟢 -136 B 🟢 -125 B
assets/SubscriptionPanelContentWorkspace-CLQESwvO.js (new) 266 B 🔴 +266 B 🔴 +136 B 🔴 +115 B
assets/WidgetInputNumber-Ctkqq6z4.js (new) 186 B 🔴 +186 B 🔴 +119 B 🔴 +111 B
assets/WidgetInputNumber-N-9uf4J6.js (removed) 186 B 🟢 -186 B 🟢 -119 B 🟢 -115 B
assets/WidgetLegacy-BCjKv3tc.js (new) 164 B 🔴 +164 B 🔴 +125 B 🔴 +115 B
assets/WidgetLegacy-TZAEbz-e.js (removed) 164 B 🟢 -164 B 🟢 -125 B 🟢 -111 B
assets/Load3D-Bxnln7SX.js (removed) 131 B 🟢 -131 B 🟢 -107 B 🟢 -107 B
assets/Load3D-CW_W_Sas.js (new) 131 B 🔴 +131 B 🔴 +107 B 🔴 +115 B
assets/auto-DWs2ctGL.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BEw5ErI4.js 18.5 kB 18.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BGeHkplA.js 17.9 kB 17.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BV0l36Iz.js 17.2 kB 17.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-C_Y3D6Cn.js 17.8 kB 17.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-C6piRza5.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Cf8Zq1td.js 18.8 kB 18.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CiziP3Xs.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-D1595tOr.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DXauvccL.js 20.6 kB 20.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-P5QCEfZc.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-WbYP_D61.js 17 kB 17 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/i18n-BlyhGDPa.js 500 kB 500 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/i18n-byadgsvD.js 188 B 188 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/LazyImage-DHwPdKGO.js 14.1 kB 14.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BHtk4Fg_.js 174 kB 174 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BMSlgLcp.js 155 kB 155 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BQCWi9e4.js 112 kB 112 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CJicmTR7.js 113 kB 113 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CNOkBy-u.js 126 kB 126 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CySb1R5_.js 151 kB 151 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-D0g10ZKf.js 131 kB 131 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DMUPIFMF.js 133 kB 133 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DpsGU4si.js 126 kB 126 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dz6IPJXM.js 144 kB 144 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-lrEzMywH.js 128 kB 128 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Media3DTop-DUmUhXD6.js 2.38 kB 2.38 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-CD66_Mw_.js 2 kB 2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-Bqe7yvm_.js 2.34 kB 2.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-De3MzVmp.js 2.82 kB 2.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/mixpanel.module-CC2-PIpB.js 143 B 143 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-A7pvB7zM.js 370 kB 370 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BIVjUijC.js 345 kB 345 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Chkn0HaI.js 343 kB 343 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CK_6GHao.js 452 kB 452 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CToVAwnT.js 373 kB 373 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DDabdWgx.js 417 kB 417 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DgvJyE3d.js 386 kB 386 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DjxaeFt_.js 416 kB 416 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DslnWEGg.js 377 kB 377 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-EPAM3kwk.js 373 kB 373 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-NrulhNyH.js 366 kB 366 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/previousFullPath-CmezY7As.js 838 B 838 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-cVp-94Rc.js 1.96 kB 1.96 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Slider-D4lsf6Ob.js 4.21 kB 4.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-BJiJuR5i.js 518 B 518 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-CUtab2CB.js 4.71 kB 4.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-D79nBMxa.js 186 B 186 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-CiXfBVBH.js 2.79 kB 2.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetColorPicker-BxNqMlFv.js 3.71 kB 3.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetGalleria-DDD96zwa.js 4.57 kB 4.57 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-A6pZMGtc.js 3.79 kB 3.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputText-DSMUKRnt.js 2.58 kB 2.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField-MDImyvc3.js 2.7 kB 2.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetMarkdown-a8bZhyc5.js 3.49 kB 3.49 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-ERx8czR8.js 1.31 kB 1.31 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetTextarea-CV3BoahN.js 3.87 kB 3.87 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-ZdaYkxkD.js 3.26 kB 3.26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetTypes-KPj-zM0O.js 573 B 573 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

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

🤖 Fix all issues with AI agents
In `@src/composables/graph/useGraphConfigureSlotSync.test.ts`:
- Around line 43-58: The test mutates LiteGraph.vueNodesMode directly and
restores it manually at the test end which can be skipped if the test throws;
change the test to restore vueNodesMode in an afterEach hook instead—capture the
original value of (LiteGraph as { vueNodesMode: boolean }).vueNodesMode before
each test (or in the test setup), and in afterEach reset it so
useGraphConfigureSlotSync tests never leave global state modified; reference the
LiteGraph.vueNodesMode mutation and the onGraphConfigured call in
useGraphConfigureSlotSync to locate where to capture and restore the original
value.

In `@src/renderer/extensions/vueNodes/composables/useSlotElementTracking.test.ts`:
- Around line 7-8: Remove the redundant "type-assertion" test that checks typeof
flushPendingSlotLayoutSyncs === 'function' — delete the it block named 'should
be a function' (which references flushPendingSlotLayoutSyncs) so tests only
cover behavior (e.g., the existing no-throw test). After removing that it block,
run the test suite and remove any now-unused imports related to the deleted test
if the linter flags them.

Comment on lines 43 to 58
it('should not flush when vue nodes mode is disabled', async () => {
const { LiteGraph } = await import('@/lib/litegraph/src/litegraph')
;(LiteGraph as { vueNodesMode: boolean }).vueNodesMode = false

const { flushPendingSlotLayoutSyncs } =
await import('@/renderer/extensions/vueNodes/composables/useSlotElementTracking')
const { useGraphConfigureSlotSync } =
await import('./useGraphConfigureSlotSync')

const { onGraphConfigured } = useGraphConfigureSlotSync()
onGraphConfigured()

expect(flushPendingSlotLayoutSyncs).not.toHaveBeenCalled()

;(LiteGraph as { vueNodesMode: boolean }).vueNodesMode = true
})
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider using afterEach for mock state restoration.

The manual restoration of vueNodesMode on line 57 could be missed if the test throws before reaching it. Using afterEach ensures cleanup runs regardless of test outcome.

♻️ Proposed refactor
 describe('useGraphConfigureSlotSync', () => {
+  let originalVueNodesMode: boolean
+
   beforeEach(() => {
     vi.clearAllMocks()
   })

+  afterEach(async () => {
+    const { LiteGraph } = await import('@/lib/litegraph/src/litegraph')
+    ;(LiteGraph as { vueNodesMode: boolean }).vueNodesMode = true
+  })

   // ... first test unchanged ...

   it('should not flush when vue nodes mode is disabled', async () => {
     const { LiteGraph } = await import('@/lib/litegraph/src/litegraph')
     ;(LiteGraph as { vueNodesMode: boolean }).vueNodesMode = false

     const { flushPendingSlotLayoutSyncs } =
       await import('@/renderer/extensions/vueNodes/composables/useSlotElementTracking')
     const { useGraphConfigureSlotSync } =
       await import('./useGraphConfigureSlotSync')

     const { onGraphConfigured } = useGraphConfigureSlotSync()
     onGraphConfigured()

     expect(flushPendingSlotLayoutSyncs).not.toHaveBeenCalled()
-
-    ;(LiteGraph as { vueNodesMode: boolean }).vueNodesMode = true
   })
 })

As per coding guidelines: "Leverage Vitest utilities for mocking where possible and keep module mocks contained without global mutable state."

🧰 Tools
🪛 ESLint

[error] 44-44: Unable to resolve path to module '@/lib/litegraph/src/litegraph'.

(import-x/no-unresolved)


[error] 48-48: Unable to resolve path to module '@/renderer/extensions/vueNodes/composables/useSlotElementTracking'.

(import-x/no-unresolved)


[error] 50-50: Unable to resolve path to module './useGraphConfigureSlotSync'.

(import-x/no-unresolved)

🤖 Prompt for AI Agents
In `@src/composables/graph/useGraphConfigureSlotSync.test.ts` around lines 43 -
58, The test mutates LiteGraph.vueNodesMode directly and restores it manually at
the test end which can be skipped if the test throws; change the test to restore
vueNodesMode in an afterEach hook instead—capture the original value of
(LiteGraph as { vueNodesMode: boolean }).vueNodesMode before each test (or in
the test setup), and in afterEach reset it so useGraphConfigureSlotSync tests
never leave global state modified; reference the LiteGraph.vueNodesMode mutation
and the onGraphConfigured call in useGraphConfigureSlotSync to locate where to
capture and restore the original value.

Comment on lines 7 to 8
it('should be a function', () => {
expect(typeof flushPendingSlotLayoutSyncs).toBe('function')
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider removing the type-assertion test.

The test typeof flushPendingSlotLayoutSyncs === 'function' is a change-detector test that verifies existence rather than behavior. TypeScript's type system already guarantees this at compile time. The second test (no-throw behavior) provides the meaningful coverage.

As per coding guidelines: "Do not write change detector tests that just assert defaults are certain values."

🤖 Prompt for AI Agents
In `@src/renderer/extensions/vueNodes/composables/useSlotElementTracking.test.ts`
around lines 7 - 8, Remove the redundant "type-assertion" test that checks
typeof flushPendingSlotLayoutSyncs === 'function' — delete the it block named
'should be a function' (which references flushPendingSlotLayoutSyncs) so tests
only cover behavior (e.g., the existing no-throw test). After removing that it
block, run the test suite and remove any now-unused imports related to the
deleted test if the linter flags them.

@dosubot dosubot bot added size:S This PR changes 10-29 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jan 28, 2026
@coderabbitai coderabbitai bot requested a review from simula-r January 28, 2026 08:35
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

🤖 Fix all issues with AI agents
In `@src/renderer/extensions/vueNodes/composables/useSlotElementTracking.test.ts`:
- Around line 11-13: Add tests that cover the active path of
flushScheduledSlotLayoutSync by mocking its dependencies: stub
useSharedCanvasPositionConversion to return a predictable convert function, mock
useNodeSlotRegistryStore to provide a registry with one or more pending nodes
(their slot ids and nodeRects), and spy on layoutStore (or its updateSlotLayout
method) to assert it is called with converted positions; include assertions that
pending sync entries are cleared after flushScheduledSlotLayoutSync runs and
that no calls occur when registry is empty. Use the functions/objects
flushScheduledSlotLayoutSync, useSharedCanvasPositionConversion,
useNodeSlotRegistryStore, and layoutStore in your mocks/spies so the test
targets the real behavior rather than only the no-op path.

Comment on lines 11 to 13
it('should not throw when called with no pending syncs', () => {
expect(() => flushScheduledSlotLayoutSync()).not.toThrow()
})
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider adding more meaningful behavioral tests.

The current test only verifies the function doesn't throw when there are no pending syncs. While this provides minimal coverage for the early-return path, consider testing actual behavior with pending nodes when the module's dependencies can be mocked.

Do you want me to generate a more comprehensive test suite that mocks the dependencies (useSharedCanvasPositionConversion, useNodeSlotRegistryStore, layoutStore) to verify actual sync behavior?

🤖 Prompt for AI Agents
In `@src/renderer/extensions/vueNodes/composables/useSlotElementTracking.test.ts`
around lines 11 - 13, Add tests that cover the active path of
flushScheduledSlotLayoutSync by mocking its dependencies: stub
useSharedCanvasPositionConversion to return a predictable convert function, mock
useNodeSlotRegistryStore to provide a registry with one or more pending nodes
(their slot ids and nodeRects), and spy on layoutStore (or its updateSlotLayout
method) to assert it is called with converted positions; include assertions that
pending sync entries are cleared after flushScheduledSlotLayoutSync runs and
that no calls occur when registry is empty. Use the functions/objects
flushScheduledSlotLayoutSync, useSharedCanvasPositionConversion,
useNodeSlotRegistryStore, and layoutStore in your mocks/spies so the test
targets the real behavior rather than only the no-op path.

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:S This PR changes 10-29 lines, ignoring generated files. labels Jan 29, 2026
@coderabbitai coderabbitai bot requested a review from Myestery January 29, 2026 04:49
@github-actions
Copy link

🔧 Auto-fixes Applied

This PR has been automatically updated to fix linting and formatting issues.

⚠️ Important: Your local branch is now behind. Run git pull before making additional changes to avoid conflicts.

Changes made:

  • ESLint auto-fixes
  • Oxfmt formatting

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 (2)
src/lib/litegraph/src/LGraphNode.ts (1)

3942-3972: Exclude unsynced slots from bounds to avoid stale layout calculations.

#measureSlot returns early when positions are unsynced, but #measureSlots still pushes those slots into createBounds, which can reuse stale boundingRect values and skew widget layout/hit‑testing while Vue positions are pending. Consider only adding slots that were actually measured.

🛠️ Suggested fix
-  `#measureSlot`(
+  `#measureSlot`(
     slot: NodeInputSlot | NodeOutputSlot,
     slotIndex: number,
     isInput: boolean
-  ): void {
+  ): boolean {
     const pos = isInput
       ? this.getInputPos(slotIndex)
       : this.getOutputPos(slotIndex)

     // Skip if position not yet synced (Vue mode)
-    if (!pos) return
+    if (!pos) return false

     slot.boundingRect[0] = pos[0] - LiteGraph.NODE_SLOT_HEIGHT * 0.5
     slot.boundingRect[1] = pos[1] - LiteGraph.NODE_SLOT_HEIGHT * 0.5
     slot.boundingRect[2] = slot.isWidgetInputSlot
       ? BaseWidget.margin
       : LiteGraph.NODE_SLOT_HEIGHT
     slot.boundingRect[3] = LiteGraph.NODE_SLOT_HEIGHT
+    return true
   }

   `#measureSlots`(): ReadOnlyRect | null {
     const slots: (NodeInputSlot | NodeOutputSlot)[] = []

     for (const [slotIndex, slot] of this.#concreteInputs.entries()) {
       // Unrecognized nodes (Nodes with error) has inputs but no widgets. Treat
       // converted inputs as normal inputs.
       /** Widget input slots are handled in {`@link` layoutWidgetInputSlots} */
       if (this.widgets?.length && isWidgetInputSlot(slot)) continue

-      this.#measureSlot(slot, slotIndex, true)
-      slots.push(slot)
+      if (this.#measureSlot(slot, slotIndex, true)) {
+        slots.push(slot)
+      }
     }
     for (const [slotIndex, slot] of this.#concreteOutputs.entries()) {
-      this.#measureSlot(slot, slotIndex, false)
-      slots.push(slot)
+      if (this.#measureSlot(slot, slotIndex, false)) {
+        slots.push(slot)
+      }
     }
src/lib/litegraph/src/LGraphCanvas.ts (1)

5653-5671: Avoid the as Point assertion in the fallback start position.

The new undefined-position guards are good. However, Line 5664 uses a type assertion; prefer a typed tuple constant to keep assertions as a last resort.

♻️ Suggested refactor to avoid the type assertion
-        const startPos =
-          outputId === -1
-            ? ([start_node.pos[0] + 10, start_node.pos[1] + 10] as Point)
-            : LiteGraph.vueNodesMode
-              ? getSlotPosition(start_node, outputId, false)
-              : start_node.getOutputPos(outputId)
+        const fallbackStartPos: Point = [
+          start_node.pos[0] + 10,
+          start_node.pos[1] + 10
+        ]
+        const startPos =
+          outputId === -1
+            ? fallbackStartPos
+            : LiteGraph.vueNodesMode
+              ? getSlotPosition(start_node, outputId, false)
+              : start_node.getOutputPos(outputId)

Based on learnings: Type assertions are a last resort (acceptable for legacy code interop).

Also applies to: 5700-5706, 5730-5736, 5807-5814, 5833-5839

🤖 Fix all issues with AI agents
In `@plan.md`:
- Line 1: Add a top-level heading to the Markdown file to satisfy MD041 by
inserting a level-1 heading (for example "# Description") at the very top of
plan.md so the document starts with a top-level heading; ensure the heading text
matches the file's section purpose (e.g., "Description") and is the first
non-blank line.

plan.md Outdated
@@ -0,0 +1,21 @@
## Description
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use a top‑level heading to satisfy MD041.

🛠️ Suggested fix
-## Description
+# Description
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Description
# Description
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🤖 Prompt for AI Agents
In `@plan.md` at line 1, Add a top-level heading to the Markdown file to satisfy
MD041 by inserting a level-1 heading (for example "# Description") at the very
top of plan.md so the document starts with a top-level heading; ensure the
heading text matches the file's section purpose (e.g., "Description") and is the
first non-blank line.

@dosubot dosubot bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jan 29, 2026
After graph reconfiguration (e.g., undo/redo), there's a timing gap where
canvas renders links before Vue components have mounted and synced slot
positions to layoutStore.

This adds a pendingSlotSync flag to layoutStore that:
- Is set to true at start of graph.onConfigure()
- Is cleared after flushScheduledSlotLayoutSync() completes
- Causes drawConnections() to skip link rendering when true

This prevents links from rendering with stale/missing positions during the
brief window between configure() completing and Vue components syncing.

Amp-Thread-ID: https://ampcode.com/threads/T-019c084c-49dd-764b-8125-8938c42612c8
Co-authored-by: Amp <amp@ampcode.com>
@christian-byrne christian-byrne changed the title fix: flush pending slot layout syncs after graph configure fix: suppress link rendering during slot sync after graph reconfigure Jan 29, 2026
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

🤖 Fix all issues with AI agents
In `@src/lib/litegraph/src/LGraphCanvas.ts`:
- Around line 5617-5619: Before the early return in LGraphCanvas where you check
"if (LiteGraph.vueNodesMode && layoutStore.pendingSlotSync) return", clear the
visible reroute cache to avoid stale entries; specifically reset
this.#visibleReroutes (the private cache used for hit-testing) to an empty
collection before returning so reroutes are refreshed once slot positions sync.

benceruleanlu
benceruleanlu previously approved these changes Jan 29, 2026
Copy link
Member

@benceruleanlu benceruleanlu left a comment

Choose a reason for hiding this comment

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

LGTM after taking a look at issues mentioned

Also, did the agent forget to commit or push the unit tests mentioned? having those as a regression test would be nice

if (pendingNodes.size === 0) return
export function flushScheduledSlotLayoutSync() {
if (pendingNodes.size === 0) {
// Even if no pending nodes, clear the flag (e.g., graph with no nodes)
Copy link
Member

Choose a reason for hiding this comment

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

Possible race condition: flushScheduledSlotLayoutSync() is called synchronously right after onConfigure. If Vue slot elements haven’t mounted yet, pendingNodes.size === 0 here, so this block clears pendingSlotSync and returns. That re‑enables link rendering before any DOM-based slot positions exist, which can reintroduce the misaligned-links bug under load. pendingNodes only becomes non‑empty when useSlotElementTracking runs in onMounted and calls scheduleSlotLayoutSync(). Consider only clearing the flag after a real flush (non-empty), or setting pendingSlotSync to true in scheduleSlotLayoutSync() so late mounts re‑assert it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in commit 2e1845b - scheduleSlotLayoutSync() now re-asserts the pendingSlotSync flag for late-mounting Vue components, and we only clear the flag when there are actual nodes to process.

private addAfterConfigureHandler(graph: LGraph) {
const { onConfigure } = graph
graph.onConfigure = function (...args) {
// Set pending sync flag to suppress link rendering until slots are synced
Copy link
Member

Choose a reason for hiding this comment

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

Potential stuck state: if onConfigure (or callbacks it triggers) throws, pendingSlotSync is never cleared because the flush/clear logic is after the call. That can permanently suppress link rendering. Suggest wrapping the handler body in try/finally and clearing the flag in finally (or at least in a catch) so links don’t stay hidden on error paths.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in commit c2d548b - wrapped the onConfigure handler body in try/finally to ensure the flush runs even if an error is thrown.

Subagent 5 and others added 3 commits January 29, 2026 16:29
Clears #visibleReroutes before the early return to prevent stale reroute
entries from affecting hit-testing while pendingSlotSync is true.

Addresses CodeRabbit review feedback.

Amp-Thread-ID: https://ampcode.com/threads/T-019c0be1-0c2e-752d-b793-c6687e36c61c
Co-authored-by: Amp <amp@ampcode.com>
Re-asserts pendingSlotSync flag in scheduleSlotLayoutSync() so that Vue
components mounting after the synchronous flushScheduledSlotLayoutSync()
call in onConfigure will keep link rendering suppressed until their
slots are synced.

Only clears the flag when there are actual nodes to process, allowing
the RAF callback to properly sync late mounts.

Addresses review feedback from benceruleanlu.

Amp-Thread-ID: https://ampcode.com/threads/T-019c0be1-0c2e-752d-b793-c6687e36c61c
Co-authored-by: Amp <amp@ampcode.com>
Ensures pendingSlotSync flag is cleared even if an error is thrown during
graph configuration. This prevents links from being permanently hidden
if onConfigure or its callbacks throw an exception.

Addresses review feedback from benceruleanlu.

Amp-Thread-ID: https://ampcode.com/threads/T-019c0be1-0c2e-752d-b793-c6687e36c61c
Co-authored-by: Amp <amp@ampcode.com>
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

🤖 Fix all issues with AI agents
In `@src/renderer/extensions/vueNodes/composables/useSlotElementTracking.ts`:
- Around line 37-51: flushScheduledSlotLayoutSync currently returns early when
pendingNodes.size === 0 without clearing layoutStore's pending flag, causing
pendingSlotSync to remain true for workflows with no Vue nodes; modify
flushScheduledSlotLayoutSync so that when pendingNodes.size === 0 you call
layoutStore.setPendingSlotSync(false) before returning (or alternatively only
set the pending flag where scheduleSlotLayoutSync actually enqueues work),
ensuring the pendingSlotSync flag is cleared even when no
RAF/scheduleSlotLayoutSync was ever invoked.

Subagent 5 and others added 2 commits January 29, 2026 17:14
… Vue nodes

When no Vue nodes exist, pendingNodes stays empty but pendingSlotSync was
set to true in app.ts. Without clearing the flag in the early return path,
link rendering would be permanently suppressed for non-Vue-node workflows.

Amp-Thread-ID: https://ampcode.com/threads/T-019c0c55-76a9-7128-88ff-f9c7b428a2a3
Co-authored-by: Amp <amp@ampcode.com>
After clearing the pendingSlotSync flag, the canvas needs to be marked
dirty to trigger a redraw. Without this, links wouldn't appear until
user interaction because the canvas didn't know it needed to re-render.

Amp-Thread-ID: https://ampcode.com/threads/T-019c0c55-76a9-7128-88ff-f9c7b428a2a3
Co-authored-by: Amp <amp@ampcode.com>
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

🤖 Fix all issues with AI agents
In `@src/renderer/extensions/vueNodes/composables/useSlotElementTracking.ts`:
- Line 15: The import "import { app } from '@/scripts/app'" in
useSlotElementTracking.ts is causing ESLint import-x/no-unresolved; either
update the project alias resolver to map "@" to the src directory including
src/scripts/app.ts, or change the import to a resolvable path (e.g., relative
import to the actual file) so the symbol app in useSlotElementTracking.ts
resolves; make the change where the import appears (useSlotElementTracking.ts)
or in the build/ESLint alias config so linting passes.

import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import { getSlotKey } from '@/renderer/core/layout/slots/slotIdentifier'
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
import { app } from '@/scripts/app'
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 30, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Resolve the @/scripts/app import or lint will fail.

ESLint flags import-x/no-unresolved for this path. Please confirm the alias
resolver includes src/scripts/app.ts, or adjust the import to a resolvable
path.

🧰 Tools
🪛 ESLint

[error] 15-15: Unable to resolve path to module '@/scripts/app'.

(import-x/no-unresolved)

🤖 Prompt for AI Agents
In `@src/renderer/extensions/vueNodes/composables/useSlotElementTracking.ts` at
line 15, The import "import { app } from '@/scripts/app'" in
useSlotElementTracking.ts is causing ESLint import-x/no-unresolved; either
update the project alias resolver to map "@" to the src directory including
src/scripts/app.ts, or change the import to a resolvable path (e.g., relative
import to the actual file) so the symbol app in useSlotElementTracking.ts
resolves; make the change where the import appears (useSlotElementTracking.ts)
or in the build/ESLint alias config so linting passes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a false positive - the @/scripts/app import resolves correctly and lint passes locally with no errors. The project's alias resolver includes this path.

Copy link
Contributor

Choose a reason for hiding this comment

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

@christian-byrne, thank you for the clarification! I understand the import resolves correctly in your environment and the alias configuration is properly set up. I'll disregard this ESLint report.


🧠 Learnings used
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,ts} : Leverage VueUse functions for performance-enhancing styles

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-28T02:00:53.680Z
Learning: Applies to **/*.vue : Define slots via template usage, not `defineSlots`

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-28T02:00:53.680Z
Learning: Applies to **/*.{js,ts,tsx,vue} : Unused imports are disallowed and must be removed

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-01-27T20:51:47.936Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid `ts-expect-error` - fix the underlying type issue instead

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-28T02:00:53.680Z
Learning: Applies to **/*.{ts,tsx,vue} : Never use `as any` type assertions; fix the underlying type issue instead

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-28T02:00:53.680Z
Learning: Applies to eslint.config.ts : Configure ESLint with Vue + TS rules, no floating promises, and unused imports disallowed

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/AGENTS.md:0-0
Timestamp: 2026-01-28T02:01:01.525Z
Learning: Applies to src/lib/litegraph/**/*.{ts,tsx} : Always import from the barrel export for subgraph code to avoid circular dependencies (import from '@/lib/litegraph/src/litegraph' instead of individual modules like '@/lib/litegraph/src/LGraph')

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-01-27T20:51:47.936Z
Learning: Applies to src/**/*.{js,ts,vue} : Implement proper error propagation

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-01-27T20:51:47.936Z
Learning: Applies to src/**/*.{js,ts,vue} : Validate trusted sources before processing

Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:21.073Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, linting rules enforce keeping `import type` statements separate from regular `import` statements, even when importing from the same module. Do not suggest consolidating them into a single import statement.

When the synchronous flush is called with no pending nodes, we now check
if the graph has any nodes. If it does, we keep the flag set to allow
Vue components to mount and re-assert it. If the graph is empty (no nodes),
we clear the flag since no Vue components will mount.

This fixes the regression where links rendered with stale positions because
the flag was cleared before Vue components had a chance to sync.

Amp-Thread-ID: https://ampcode.com/threads/T-019c0c55-76a9-7128-88ff-f9c7b428a2a3
Co-authored-by: Amp <amp@ampcode.com>
@christian-byrne
Copy link
Contributor Author

Review Comments Addressed

Pushed 3 commits addressing the review feedback:

1. CodeRabbit - Clear reroute cache (LGraphCanvas.ts)

Commit bf21a055: Now clears this.#visibleReroutes before the early return to prevent stale reroute entries from affecting hit-testing while pendingSlotSync is true.

2. @benceruleanlu - Race condition with late mounts (useSlotElementTracking.ts)

Commit 2e1845bb: scheduleSlotLayoutSync() now re-asserts the pendingSlotSync flag so Vue components mounting after the synchronous flushScheduledSlotLayoutSync() call will keep link rendering suppressed until their slots are synced. The flag is only cleared when there are actual nodes to process.

3. @benceruleanlu - Error handling stuck state (app.ts)

Commit c2d548bf: Wrapped the onConfigure handler body in try/finally to ensure pendingSlotSync is cleared even if an error is thrown during graph configuration, preventing links from being permanently hidden.

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

Labels

size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants