Skip to content

Conversation

@jtydhr88
Copy link
Collaborator

@jtydhr88 jtydhr88 commented Dec 8, 2025

Summary

preserve Vue node reactivity during undo/redo operations

Root Cause: The Vue reactivity chain was broken during undo/redo operations:

  1. handleDeleteNode was deleting nodeRefs and nodeTriggers
  2. Vue components still held references to the old refs
  3. When nodes were recreated, finalizeOperation tried to call triggers but they were already deleted
  4. Vue didn't know the data had changed, so nodes didn't visually update

fix #7040

Screenshots

2025-12-07.22-27-30.mp4

┆Issue is synchronized with this Notion page by Unito

@jtydhr88 jtydhr88 requested a review from a team as a code owner December 8, 2025 03:33
@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Dec 8, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 8, 2025

📝 Walkthrough

Walkthrough

The PR modifies the layout store to preserve node reactive references during undo/redo operations and properly clean them up when Vue components unmount, addressing an issue where undo operations caused the graph to lose track of nodes and connections.

Changes

Cohort / File(s) Summary
Layout Store Cleanup
src/renderer/core/layout/store/layoutStore.ts
Adds cleanupNodeRef() method to remove per-node reactive refs on demand. Changes initialization and node-creation flows to avoid clearing refs/triggers, preserving them for undo/redo scenarios. Refs remain until explicit cleanup or component unmount.
Component Lifecycle
src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
Adds onUnmounted hook to invoke layoutStore.cleanupNodeRef() when the node layout component unmounts, ensuring proper cleanup of Vue reactivity bindings.

Possibly related PRs

  • #6966: Modifies the same LayoutStoreImpl class with height-normalization and LayoutSource handling logic, indicating concurrent or dependent layout store enhancements.

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR directly addresses issue #7040 by preserving Vue node reactivity during undo/redo through a new cleanupNodeRef method and lifecycle hook integration.
Out of Scope Changes check ✅ Passed All changes focus on fixing Vue reactivity preservation during undo/redo operations as specified in linked issue #7040.
✨ 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 undo-issue

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

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 12/08/2025, 03:34:50 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 12/08/2025, 03:43:00 AM UTC

📈 Summary

  • Total Tests: 497
  • Passed: 485 ✅
  • Failed: 0
  • Flaky: 2 ⚠️
  • Skipped: 10 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 476 / ❌ 0 / ⚠️ 2 / ⏭️ 10
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 6 / ❌ 0 / ⚠️ 0 / ⏭️ 0

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

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

Bundle Size Report

Summary

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

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

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

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-Cp5R3HbP.js (new) 2.98 MB 🔴 +2.98 MB 🔴 +620 kB 🔴 +471 kB
assets/index-I76iGr-o.js (removed) 2.98 MB 🟢 -2.98 MB 🟢 -620 kB 🟢 -471 kB
assets/index-BZqbo7Ub.js (new) 223 kB 🔴 +223 kB 🔴 +47.6 kB 🔴 +39.2 kB
assets/index-C0KBoIsP.js (removed) 223 kB 🟢 -223 kB 🟢 -47.6 kB 🟢 -39.2 kB
assets/index-Bc1TVRpP.js (removed) 345 B 🟢 -345 B 🟢 -245 B 🟢 -201 B
assets/index-C-DcymAX.js (new) 345 B 🔴 +345 B 🔴 +245 B 🔴 +233 B

Status: 3 added / 3 removed

Graph Workspace — 976 kB (baseline 976 kB) • 🔴 +68 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-CrOgEG5s.js (new) 976 kB 🔴 +976 kB 🔴 +189 kB 🔴 +144 kB
assets/GraphView-DhG0hpjR.js (removed) 976 kB 🟢 -976 kB 🟢 -189 kB 🟢 -144 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

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

Status: 1 added / 1 removed

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CreditsPanel-CH8aUIJJ.js (removed) 21.4 kB 🟢 -21.4 kB 🟢 -5.15 kB 🟢 -4.5 kB
assets/CreditsPanel-CMevXXj8.js (new) 21.4 kB 🔴 +21.4 kB 🔴 +5.15 kB 🔴 +4.5 kB
assets/KeybindingPanel-CV-GbKBy.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.42 kB 🔴 +3.02 kB
assets/KeybindingPanel-DXBfEAXE.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.42 kB 🟢 -3.01 kB
assets/ExtensionPanel-BAx8pTQU.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.58 kB 🟢 -2.26 kB
assets/ExtensionPanel-D6u5A7oN.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.58 kB 🔴 +2.26 kB
assets/AboutPanel-CiV_W6-d.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/AboutPanel-CpPmMuP3.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/ServerConfigPanel-BnIbtDlX.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -1.83 kB 🟢 -1.63 kB
assets/ServerConfigPanel-DQQ53wvO.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +1.83 kB 🔴 +1.63 kB
assets/UserPanel-Bs11CIRC.js (removed) 6.23 kB 🟢 -6.23 kB 🟢 -1.72 kB 🟢 -1.5 kB
assets/UserPanel-CgNof55T.js (new) 6.23 kB 🔴 +6.23 kB 🔴 +1.72 kB 🔴 +1.51 kB
assets/settings-BhbWhsRg.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BXTtSH4O.js 33.3 kB 33.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C9Pzn-NG.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CCy2fA_h.js 27.3 kB 27.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CQpqEFfl.js 26.6 kB 26.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DHcnxypw.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DhFTK9fY.js 25.1 kB 25.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DlT4t_ui.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DRgSrIdD.js 24.2 kB 24.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-tjkeqiZq.js 21.1 kB 21.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Load3D.vue_vue_type_script_setup_true_lang-BjmDWniK.js (removed) 53.9 kB 🟢 -53.9 kB 🟢 -8.52 kB 🟢 -7.32 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-CFiOsYuj.js (new) 53.9 kB 🔴 +53.9 kB 🔴 +8.52 kB 🔴 +7.31 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-DYNErZei.js (removed) 48 kB 🟢 -48 kB 🟢 -10.3 kB 🟢 -8.97 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-s_EqGJy-.js (new) 48 kB 🔴 +48 kB 🔴 +10.3 kB 🔴 +8.97 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-DOmx2xfk.js (new) 46.9 kB 🔴 +46.9 kB 🔴 +10.5 kB 🔴 +9.17 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-gDJ5xsw3.js (removed) 46.9 kB 🟢 -46.9 kB 🟢 -10.5 kB 🟢 -9.17 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-BpERodRt.js (new) 12.9 kB 🔴 +12.9 kB 🔴 +3.37 kB 🔴 +2.97 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-D75rUBU1.js (removed) 12.9 kB 🟢 -12.9 kB 🟢 -3.37 kB 🟢 -2.97 kB
assets/ComfyQueueButton-BqLdUsJs.js (removed) 8.44 kB 🟢 -8.44 kB 🟢 -2.48 kB 🟢 -2.21 kB
assets/ComfyQueueButton-BTbZN018.js (new) 8.44 kB 🔴 +8.44 kB 🔴 +2.48 kB 🔴 +2.22 kB
assets/MediaTitle.vue_vue_type_script_setup_true_lang-Cc_Y9j6G.js (removed) 897 B 🟢 -897 B 🟢 -503 B 🟢 -435 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-D0495bGP.js (new) 897 B 🔴 +897 B 🔴 +504 B 🔴 +461 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-BPGmgVoN.js 1.34 kB 1.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-CFWrwaAG.js 2.04 kB 2.04 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-6ZIklFyS.js 2.26 kB 2.26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

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

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-CQYBXdy0.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/keybindingService-Diy7OfUo.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.83 kB 🟢 -1.58 kB
assets/audioService-D0PUlxOV.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +963 B 🔴 +830 B
assets/audioService-DfJd3fR3.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -963 B 🟢 -829 B
assets/serverConfigStore-L3qzi_1Z.js 2.83 kB 2.83 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 2 added / 2 removed

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-Lu7w4bP-.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -650 B 🟢 -546 B
assets/audioUtils-x7-cA4Hq.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +651 B 🔴 +549 B
assets/mathUtil-CTARWQ-l.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeFilterUtil-CXKCRJ-m.js 460 B 460 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 1 added / 1 removed

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

External libraries and shared vendor chunks

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

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WidgetRecordAudio-D01g6QYd.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.24 kB 🔴 +4.63 kB
assets/WidgetRecordAudio-iQ7bzvSP.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.24 kB 🟢 -4.63 kB
assets/AudioPreviewPlayer-2EA67QGT.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.4 kB 🟢 -3.03 kB
assets/AudioPreviewPlayer-cKVBPiRo.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.4 kB 🔴 +3.04 kB
assets/WidgetGalleria-CsxXi2_4.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.44 kB 🟢 -1.3 kB
assets/WidgetGalleria-DGm7u1hR.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.45 kB 🔴 +1.3 kB
assets/WidgetColorPicker-BsNwQFz8.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetColorPicker-CDnE_FAE.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetMarkdown-BaXMMOTf.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.12 kB
assets/WidgetMarkdown-CQuKCiU7.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetTextarea-BR_tG2zm.js (new) 2.93 kB 🔴 +2.93 kB 🔴 +1.17 kB 🔴 +1.04 kB
assets/WidgetTextarea-CPfbpgE-.js (removed) 2.93 kB 🟢 -2.93 kB 🟢 -1.17 kB 🟢 -1.04 kB
assets/WidgetAudioUI-B8Z9pxew.js (new) 2.85 kB 🔴 +2.85 kB 🔴 +1.16 kB 🔴 +1.05 kB
assets/WidgetAudioUI-nCDZSNud.js (removed) 2.85 kB 🟢 -2.85 kB 🟢 -1.17 kB 🟢 -1.05 kB
assets/WidgetInputText-LQiBd4zR.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -917 B 🟢 -847 B
assets/WidgetInputText-tIqN8Iez.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +916 B 🔴 +847 B
assets/MediaImageBottom-cm2zZydh.js (new) 1.57 kB 🔴 +1.57 kB 🔴 +743 B 🔴 +647 B
assets/MediaImageBottom-CoWClxyG.js (removed) 1.57 kB 🟢 -1.57 kB 🟢 -741 B 🟢 -646 B
assets/MediaAudioBottom-CRY0CYRZ.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -742 B 🟢 -656 B
assets/MediaAudioBottom-TUs_l1HQ.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +744 B 🔴 +657 B
assets/MediaVideoBottom-BWRyFICF.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -740 B 🟢 -654 B
assets/MediaVideoBottom-wB94xhft.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +742 B 🔴 +654 B
assets/Media3DBottom-Bz_xJ_m6.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -734 B 🟢 -653 B
assets/Media3DBottom-Cp1VaV7e.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +732 B 🔴 +651 B
assets/Media3DTop-BfQpJauy.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -764 B 🟢 -652 B
assets/Media3DTop-DJSef2Wj.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +766 B 🔴 +653 B
assets/WidgetSelect-DILmqPzr.js (removed) 655 B 🟢 -655 B 🟢 -344 B 🟢 -291 B
assets/WidgetSelect-QXMHVqsO.js (new) 655 B 🔴 +655 B 🔴 +343 B 🔴 +291 B
assets/WidgetInputNumber-DirfkLuN.js (removed) 595 B 🟢 -595 B 🟢 -329 B 🟢 -277 B
assets/WidgetInputNumber-DZIGAuSN.js (new) 595 B 🔴 +595 B 🔴 +330 B 🔴 +279 B
assets/Load3D-BZLoHski.js (new) 424 B 🔴 +424 B 🔴 +266 B 🔴 +220 B
assets/Load3D-CWBvvE-V.js (removed) 424 B 🟢 -424 B 🟢 -266 B 🟢 -223 B
assets/WidgetLegacy-BaMgs8tC.js (new) 364 B 🔴 +364 B 🔴 +237 B 🔴 +199 B
assets/WidgetLegacy-BecNOi6c.js (removed) 364 B 🟢 -364 B 🟢 -236 B 🟢 -195 B
assets/commands-_s-RvhJR.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BuUILW6P.js 13 kB 13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BV4R6fLx.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BWp4HdfU.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CLwPdnT6.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CWMchBmd.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DazTQhtc.js 12.9 kB 12.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DmWrOe93.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DwiH7Kr6.js 13.8 kB 13.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-mS3LCNPn.js 14.5 kB 14.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B1JflQcI.js 72.2 kB 72.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B2lyXe48.js 114 kB 114 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B9XEQ-pc.js 94 kB 94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BErKFzc-.js 73.1 kB 73.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Bf7Tze-u.js 83.4 kB 83.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BhGMcO4Q.js 84.3 kB 84.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CPZUloNQ.js 99 kB 99 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cw9RZWRY.js 89 B 89 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dva0z-T2.js 86.5 kB 86.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-un0K9wDS.js 81.8 kB 81.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-BPDWO8-i.js 1.46 kB 1.46 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-BtY1hGDO.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-ehTZdDBw.js 2.76 kB 2.76 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-8e6QYQW0.js 283 kB 283 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-A_9dx4yn.js 304 kB 304 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BbD3HDi7.js 307 kB 307 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BOJhIPft.js 369 kB 369 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bw_Jitw_.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-C-Pw33mW.js 317 kB 317 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-ChLyG0UJ.js 285 kB 285 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CUVPxA4l.js 342 kB 342 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Dx5Y4xrW.js 310 kB 310 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-JqO5mNmW.js 306 kB 306 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-j6EYUdOM.js 2.48 kB 2.48 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-D5bj5c8l.js 2.21 kB 2.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-DPJMnc2A.js 1.58 kB 1.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 17 added / 17 removed

@DrJKL DrJKL requested a review from AustinMroz December 8, 2025 03:36
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/renderer/core/layout/store/layoutStore.ts (1)

971-1012: Initialization behavior change is sound but may double‑trigger watchers

Not clearing nodeRefs/nodeTriggers in initializeFromLiteGraph and instead triggering all existing triggers is a reasonable way to preserve Vue reactivity across re‑initialization and matches the undo/redo root cause described in the PR.

However:

  • this.ynodes.clear() + subsequent set calls will already emit Yjs YMapEvents for each affected node, and the ynodes.observe handler above will call the corresponding nodeTriggers.
  • The explicit this.nodeTriggers.forEach((trigger) => trigger()) at the end can therefore cause each active consumer to recompute twice per initialization.

For typical graph sizes this is probably fine, but if initialization becomes hot or graphs get large, you may want to:

  • Either rely solely on the Yjs observer for node‑id‑scoped triggers, or
  • Justify this extra pass with a comment explaining the specific case Yjs events don’t cover.

It would be good to add or extend a test that initializes from LiteGraph, performs a delete + undo cycle, and asserts that node layouts remain reactive, to lock in this 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 8c5584c and 06450d0.

📒 Files selected for processing (2)
  • src/renderer/core/layout/store/layoutStore.ts (4 hunks)
  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
src/**/*.{vue,ts}

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

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

Files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
  • src/renderer/core/layout/store/layoutStore.ts
src/**/*.ts

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

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

Files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
  • src/renderer/core/layout/store/layoutStore.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

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

Files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
  • src/renderer/core/layout/store/layoutStore.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
  • src/renderer/core/layout/store/layoutStore.ts
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript exclusively; no new JavaScript code

Files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
  • src/renderer/core/layout/store/layoutStore.ts
**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
  • src/renderer/core/layout/store/layoutStore.ts
🧠 Learnings (13)
📓 Common learnings
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/components/rightSidePanel/parameters/TabParameters.vue:10-0
Timestamp: 2025-12-04T21:43:49.363Z
Learning: Vue 3.5+ supports reactive props destructure in <script setup>. Destructuring props directly (e.g., `const { nodes } = defineProps<{ nodes: LGraphNode[] }>()`) maintains reactivity through compiler transformation. This is the recommended modern approach and does not require using `props.x` or `toRef`/`toRefs`.
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
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/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks
📚 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/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks

Applied to files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
  • src/renderer/core/layout/store/layoutStore.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.vue : Use `computed` instead of a `ref` and `watch` if possible

Applied to files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.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 : Implement computed() for derived state in Vue 3 Composition API

Applied to files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.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 : Use ref/reactive for state management in Vue 3 Composition API

Applied to files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.vue : Avoid using `ref` if a prop would accomplish the design goals; avoid using `computed` if a `ref` or prop directly would work

Applied to files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
📚 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 : Implement computed properties with computed()

Applied to files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.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 : Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API

Applied to files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
📚 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/renderer/extensions/vueNodes/layout/useNodeLayout.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 : Extract complex conditionals to computed properties

Applied to files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
📚 Learning: 2025-12-04T21:43:49.363Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/components/rightSidePanel/parameters/TabParameters.vue:10-0
Timestamp: 2025-12-04T21:43:49.363Z
Learning: Vue 3.5+ supports reactive props destructure in <script setup>. Destructuring props directly (e.g., `const { nodes } = defineProps<{ nodes: LGraphNode[] }>()`) maintains reactivity through compiler transformation. This is the recommended modern approach and does not require using `props.x` or `toRef`/`toRefs`.

Applied to files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
📚 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,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/renderer/extensions/vueNodes/layout/useNodeLayout.ts
📚 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/**/stores/**/*.{ts,tsx} : Maintain clear public interfaces and restrict extension access in stores

Applied to files:

  • src/renderer/core/layout/store/layoutStore.ts
🧬 Code graph analysis (2)
src/renderer/extensions/vueNodes/layout/useNodeLayout.ts (1)
src/renderer/core/layout/store/layoutStore.ts (1)
  • layoutStore (1485-1485)
src/renderer/core/layout/store/layoutStore.ts (3)
src/lib/litegraph/src/LGraphNode.ts (2)
  • NodeId (94-94)
  • trigger (1392-1414)
src/renderer/core/layout/types.ts (1)
  • NodeId (40-40)
src/lib/litegraph/src/LGraph.ts (1)
  • trigger (1205-1217)
⏰ 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 (2)
src/renderer/core/layout/store/layoutStore.ts (1)

1095-1127: Keeping nodeRefs/nodeTriggers on delete fixes undo but relies on external teardown

The change in handleDeleteNode to stop deleting nodeRefs and nodeTriggers is exactly what’s needed to allow finalizeOperation and the Yjs observer to re‑use the same triggers on undo/redo so Vue sees the recreated node.

Two follow‑ups to keep this robust:

  • This now assumes that components using getNodeLayoutRef will call cleanupNodeRef on unmount; otherwise refs/triggers for permanently deleted nodes will stay around and keep being triggered unnecessarily.
  • Please consider adding a regression test for the specific failure reported in #7040 (e.g., delete a node, undo, and assert the Vue node remains draggable / layout updates) so future refactors of delete/undo behavior can’t reintroduce this bug.

As per store guidelines, this keeps the public surface small but does rely on consumers respecting the lifecycle contract.

src/renderer/extensions/vueNodes/layout/useNodeLayout.ts (1)

1-23: onUnmounted cleanup correctly complements the store changes

Wiring onUnmounted to layoutStore.cleanupNodeRef(nodeId) is a good match for the new store API and addresses subscription cleanup for node‑specific refs, aligning with the “clean up subscriptions in state management” guidance.

A couple of points to verify:

  • useNodeLayout should only be called from component setup (or an effect scope tied to a component), otherwise onUnmounted won’t be registered correctly.
  • nodeIdMaybe should be stable for the lifetime of the component (which matches current expectations for node components), since toValue is called once and that value is used for cleanup.

If those assumptions hold, this change looks solid. It would be useful to add a component‑level test (or e2e test) that mounts a Vue node, deletes it, undoes the delete, and confirms the node remains interactive and the UI doesn’t break as in #7040.

Copy link
Collaborator

@AustinMroz AustinMroz left a comment

Choose a reason for hiding this comment

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

The increased reliance on onUnmounted is concerning, but from testing, the changes appear both sufficient and minimal.

@jtydhr88 jtydhr88 merged commit 6820633 into main Dec 8, 2025
32 checks passed
@jtydhr88 jtydhr88 deleted the undo-issue branch December 8, 2025 18:38
@christian-byrne christian-byrne added needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch core/1.33 Backport PRs for core 1.33 labels Dec 9, 2025
github-actions bot pushed a commit that referenced this pull request Dec 9, 2025
## Summary
preserve Vue node reactivity during undo/redo operations

Root Cause: The Vue reactivity chain was broken during undo/redo
operations:
1. handleDeleteNode was deleting nodeRefs and nodeTriggers
2. Vue components still held references to the old refs
3. When nodes were recreated, finalizeOperation tried to call triggers
but they were already deleted
4. Vue didn't know the data had changed, so nodes didn't visually update

fix #7040

## Screenshots


https://github.com/user-attachments/assets/2feb294a-36e8-4bbe-b3f7-b7015066abc5

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7222-fix-preserve-Vue-node-reactivity-during-undo-redo-operations-2c36d73d3650819ab72afb10cbdaf39a)
by [Unito](https://www.unito.io)
@comfy-pr-bot
Copy link
Member

@jtydhr88 Successfully backported to #7257

@github-actions github-actions bot removed the needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch label Dec 9, 2025
christian-byrne pushed a commit that referenced this pull request Dec 9, 2025
…do operations (#7257)

Backport of #7222 to `core/1.33`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7257-backport-core-1-33-fix-preserve-Vue-node-reactivity-during-undo-redo-operations-2c46d73d36508184aff1c7c0e8e82408)
by [Unito](https://www.unito.io)

Co-authored-by: Terry Jia <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core/1.33 Backport PRs for core 1.33 size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nodes 2.0: pressing Ctrl + Z to undo something causes the graph to lose track of nodes and connections

5 participants