fix: prevent re-opening same workflow from silently discarding unsaved edits#10834
fix: prevent re-opening same workflow from silently discarding unsaved edits#10834dante01yoon wants to merge 4 commits intomainfrom
Conversation
Reproduces #10766 — when the same workflow file is loaded twice, the second load silently overwrites unsaved edits without any save/discard prompt or new tab creation.
…d edits When the user loads a workflow file that matches an already-open tab, afterLoadNewGraph reused the existing tab and called changeTracker.reset(), silently overwriting any unsaved modifications. Add an isModified guard to isSameActiveWorkflowLoad so that modified workflows are not silently overwritten — a new tab is opened instead. - Fixes #10766
🎨 Storybook: ✅ Built — View Storybook |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughPrevents unsaved workflow changes from being silently overwritten when reloading the same workflow source by refusing to reuse an active, modified workflow; instead the reload opens a new workflow/tab. Adds a Playwright regression test that verifies either preservation of edits or creation of a new tab when reloading the same workflow. Changes
Sequence Diagram(s)(omitted — changes do not introduce a new multi-component sequential flow requiring visualization) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 7✅ Passed checks (7 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
🎭 Playwright: ✅ 938 passed, 0 failed · 4 flaky📊 Browser Reports
|
📦 Bundle: 5.11 MB gzip 🔴 +106 BDetailsSummary
Category Glance App Entry Points — 22.3 kB (baseline 22.3 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 1.2 MB (baseline 1.2 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 76.6 kB (baseline 76.6 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 9 added / 9 removed / 2 unchanged Panels & Settings — 484 kB (baseline 484 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 10 added / 10 removed / 12 unchanged User & Accounts — 17.1 kB (baseline 17.1 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 5 added / 5 removed / 2 unchanged Editors & Dialogs — 109 kB (baseline 109 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 2 added / 2 removed UI Components — 60.3 kB (baseline 60.3 kB) • ⚪ 0 BReusable component library chunks
Status: 5 added / 5 removed / 8 unchanged Data & Services — 2.97 MB (baseline 2.97 MB) • 🔴 +32 BStores, services, APIs, and repositories
Status: 13 added / 13 removed / 4 unchanged Utilities & Hooks — 338 kB (baseline 338 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 13 added / 13 removed / 13 unchanged Vendor & Third-Party — 9.8 MB (baseline 9.8 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 16 unchanged Other — 8.44 MB (baseline 8.44 MB) • ⚪ 0 BBundles that do not match a named category
Status: 55 added / 55 removed / 79 unchanged ⚡ Performance Report
No regressions detected. All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-04-03T06:11:39.080Z",
"gitSha": "90c08e37f443b32af0f28ec1af245956ecb5cea3",
"branch": "fix/workflow-reopen-overwrites-changes",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2055.3940000000352,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.334,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 371.977,
"heapDeltaBytes": 20289888,
"heapUsedBytes": 63160424,
"domNodes": 20,
"jsHeapTotalBytes": 23068672,
"scriptDurationMs": 21.728,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-idle",
"durationMs": 2021.9639999999117,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.705,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 346.246,
"heapDeltaBytes": 20331268,
"heapUsedBytes": 63202540,
"domNodes": 20,
"jsHeapTotalBytes": 22806528,
"scriptDurationMs": 21.199999999999996,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-idle",
"durationMs": 2023.775999999998,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.593,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 327.701,
"heapDeltaBytes": 20403188,
"heapUsedBytes": 63172488,
"domNodes": 20,
"jsHeapTotalBytes": 22282240,
"scriptDurationMs": 20.281,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2017.8300000000036,
"styleRecalcs": 85,
"styleRecalcDurationMs": 41.238,
"layouts": 12,
"layoutDurationMs": 3.1700000000000004,
"taskDurationMs": 933.326,
"heapDeltaBytes": 16071448,
"heapUsedBytes": 58822980,
"domNodes": 67,
"jsHeapTotalBytes": 23330816,
"scriptDurationMs": 129.631,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2035.0979999999481,
"styleRecalcs": 82,
"styleRecalcDurationMs": 41.537000000000006,
"layouts": 12,
"layoutDurationMs": 3.1820000000000004,
"taskDurationMs": 937.7919999999999,
"heapDeltaBytes": 16382728,
"heapUsedBytes": 58827404,
"domNodes": 68,
"jsHeapTotalBytes": 23330816,
"scriptDurationMs": 130.56699999999998,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1801.6379999999117,
"styleRecalcs": 76,
"styleRecalcDurationMs": 36.856,
"layouts": 12,
"layoutDurationMs": 3.224,
"taskDurationMs": 717.279,
"heapDeltaBytes": 15892308,
"heapUsedBytes": 58338280,
"domNodes": 60,
"jsHeapTotalBytes": 23592960,
"scriptDurationMs": 129.296,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1730.985999999973,
"styleRecalcs": 30,
"styleRecalcDurationMs": 15.457999999999998,
"layouts": 6,
"layoutDurationMs": 0.539,
"taskDurationMs": 278.114,
"heapDeltaBytes": 24697812,
"heapUsedBytes": 67577036,
"domNodes": 78,
"jsHeapTotalBytes": 20709376,
"scriptDurationMs": 22.347,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1735.0410000000238,
"styleRecalcs": 32,
"styleRecalcDurationMs": 17.759999999999998,
"layouts": 6,
"layoutDurationMs": 0.6219999999999999,
"taskDurationMs": 290.449,
"heapDeltaBytes": 24725584,
"heapUsedBytes": 67175544,
"domNodes": 80,
"jsHeapTotalBytes": 20447232,
"scriptDurationMs": 24.657000000000004,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1733.5729999999785,
"styleRecalcs": 32,
"styleRecalcDurationMs": 17.487999999999996,
"layouts": 6,
"layoutDurationMs": 0.6349999999999999,
"taskDurationMs": 292.851,
"heapDeltaBytes": 15776268,
"heapUsedBytes": 67249604,
"domNodes": 79,
"jsHeapTotalBytes": 23330816,
"scriptDurationMs": 25.01300000000001,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "dom-widget-clipping",
"durationMs": 527.3070000000075,
"styleRecalcs": 14,
"styleRecalcDurationMs": 9.331,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 331.86199999999997,
"heapDeltaBytes": 6545420,
"heapUsedBytes": 49152708,
"domNodes": 22,
"jsHeapTotalBytes": 13107200,
"scriptDurationMs": 63.03900000000001,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 511.649000000034,
"styleRecalcs": 13,
"styleRecalcDurationMs": 11.485000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 331.437,
"heapDeltaBytes": 6542592,
"heapUsedBytes": 49019020,
"domNodes": 22,
"jsHeapTotalBytes": 12845056,
"scriptDurationMs": 65.08900000000001,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.669999999999998,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "dom-widget-clipping",
"durationMs": 537.4490000000378,
"styleRecalcs": 13,
"styleRecalcDurationMs": 9.538000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 327.87699999999995,
"heapDeltaBytes": 6153588,
"heapUsedBytes": 49010252,
"domNodes": 22,
"jsHeapTotalBytes": 13631488,
"scriptDurationMs": 66.47900000000001,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "large-graph-idle",
"durationMs": 2020.2259999999796,
"styleRecalcs": 11,
"styleRecalcDurationMs": 10.521,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 531.415,
"heapDeltaBytes": 2027564,
"heapUsedBytes": 52723396,
"domNodes": -255,
"jsHeapTotalBytes": 15921152,
"scriptDurationMs": 93.681,
"eventListeners": -125,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 2028.2029999999622,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.011999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 527.849,
"heapDeltaBytes": 4841588,
"heapUsedBytes": 55507532,
"domNodes": -258,
"jsHeapTotalBytes": 15921152,
"scriptDurationMs": 96.589,
"eventListeners": -127,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2012.681999999927,
"styleRecalcs": 12,
"styleRecalcDurationMs": 9.524000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 531.5920000000001,
"heapDeltaBytes": 6823524,
"heapUsedBytes": 65607908,
"domNodes": -255,
"jsHeapTotalBytes": 16035840,
"scriptDurationMs": 92.406,
"eventListeners": -129,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2131.1450000000036,
"styleRecalcs": 70,
"styleRecalcDurationMs": 17.233,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1038.569,
"heapDeltaBytes": 15481824,
"heapUsedBytes": 68396200,
"domNodes": -258,
"jsHeapTotalBytes": 18485248,
"scriptDurationMs": 383.17400000000004,
"eventListeners": -127,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2105.8460000000423,
"styleRecalcs": 69,
"styleRecalcDurationMs": 15.931000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1037.9279999999999,
"heapDeltaBytes": 16272864,
"heapUsedBytes": 68158960,
"domNodes": -260,
"jsHeapTotalBytes": 17698816,
"scriptDurationMs": 382.14300000000003,
"eventListeners": -125,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "large-graph-pan",
"durationMs": 2165.6770000000733,
"styleRecalcs": 69,
"styleRecalcDurationMs": 15.702,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1053.645,
"heapDeltaBytes": 16375356,
"heapUsedBytes": 68380096,
"domNodes": -260,
"jsHeapTotalBytes": 18485248,
"scriptDurationMs": 396.015,
"eventListeners": -125,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3152.5139999999965,
"styleRecalcs": 67,
"styleRecalcDurationMs": 17.307,
"layouts": 60,
"layoutDurationMs": 6.848999999999999,
"taskDurationMs": 1274.8819999999998,
"heapDeltaBytes": 6887944,
"heapUsedBytes": 61813436,
"domNodes": -263,
"jsHeapTotalBytes": 18018304,
"scriptDurationMs": 480.245,
"eventListeners": -123,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3161.989999999946,
"styleRecalcs": 66,
"styleRecalcDurationMs": 16.232999999999997,
"layouts": 60,
"layoutDurationMs": 6.886,
"taskDurationMs": 1266.7579999999998,
"heapDeltaBytes": 7276480,
"heapUsedBytes": 61927856,
"domNodes": -264,
"jsHeapTotalBytes": 17231872,
"scriptDurationMs": 473.81999999999994,
"eventListeners": -125,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3167.0990000000074,
"styleRecalcs": 66,
"styleRecalcDurationMs": 15.200999999999999,
"layouts": 60,
"layoutDurationMs": 6.930000000000001,
"taskDurationMs": 1270.014,
"heapDeltaBytes": 9294284,
"heapUsedBytes": 64247516,
"domNodes": -265,
"jsHeapTotalBytes": 15921152,
"scriptDurationMs": 471.03099999999995,
"eventListeners": -123,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2019.5949999999812,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.275999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 510.08200000000005,
"heapDeltaBytes": 4455980,
"heapUsedBytes": 56783128,
"domNodes": -261,
"jsHeapTotalBytes": 15134720,
"scriptDurationMs": 95.60199999999999,
"eventListeners": -125,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2009.1549999999643,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.716999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 512.988,
"heapDeltaBytes": 3663196,
"heapUsedBytes": 56447052,
"domNodes": -258,
"jsHeapTotalBytes": 16707584,
"scriptDurationMs": 94.53500000000001,
"eventListeners": -127,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "minimap-idle",
"durationMs": 2021.9940000000634,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.303000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 509.72400000000005,
"heapDeltaBytes": 4255276,
"heapUsedBytes": 56437016,
"domNodes": -258,
"jsHeapTotalBytes": 16183296,
"scriptDurationMs": 93.75500000000001,
"eventListeners": -125,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 541.5120000000115,
"styleRecalcs": 48,
"styleRecalcDurationMs": 11.623000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 344.32700000000006,
"heapDeltaBytes": 6784640,
"heapUsedBytes": 49625128,
"domNodes": 22,
"jsHeapTotalBytes": 12582912,
"scriptDurationMs": 121.72400000000002,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 533.0490000000054,
"styleRecalcs": 48,
"styleRecalcDurationMs": 11.185,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 340.52299999999997,
"heapDeltaBytes": 6556712,
"heapUsedBytes": 49604536,
"domNodes": 20,
"jsHeapTotalBytes": 12845056,
"scriptDurationMs": 120.80499999999999,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 535.0750000000062,
"styleRecalcs": 48,
"styleRecalcDurationMs": 11.495999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 337.767,
"heapDeltaBytes": 6560824,
"heapUsedBytes": 49579340,
"domNodes": 22,
"jsHeapTotalBytes": 13107200,
"scriptDurationMs": 120.93499999999999,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-idle",
"durationMs": 1997.6230000000328,
"styleRecalcs": 11,
"styleRecalcDurationMs": 10.421,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 333.069,
"heapDeltaBytes": 20825148,
"heapUsedBytes": 63992876,
"domNodes": 22,
"jsHeapTotalBytes": 22806528,
"scriptDurationMs": 17.014,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-idle",
"durationMs": 2001.3959999999997,
"styleRecalcs": 11,
"styleRecalcDurationMs": 9.730000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 337.82800000000003,
"heapDeltaBytes": 20362200,
"heapUsedBytes": 63034068,
"domNodes": 21,
"jsHeapTotalBytes": 23068672,
"scriptDurationMs": 17.465,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2022.8060000000596,
"styleRecalcs": 11,
"styleRecalcDurationMs": 9.765999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 328.2,
"heapDeltaBytes": 19970080,
"heapUsedBytes": 63122516,
"domNodes": 22,
"jsHeapTotalBytes": 22806528,
"scriptDurationMs": 16.988,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1954.2379999999753,
"styleRecalcs": 85,
"styleRecalcDurationMs": 43.29,
"layouts": 16,
"layoutDurationMs": 3.9979999999999998,
"taskDurationMs": 863.509,
"heapDeltaBytes": 11880564,
"heapUsedBytes": 54713340,
"domNodes": 74,
"jsHeapTotalBytes": 22544384,
"scriptDurationMs": 97.852,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1970.7910000000766,
"styleRecalcs": 84,
"styleRecalcDurationMs": 42.442,
"layouts": 16,
"layoutDurationMs": 4.135,
"taskDurationMs": 862.401,
"heapDeltaBytes": 11887552,
"heapUsedBytes": 54945212,
"domNodes": 73,
"jsHeapTotalBytes": 22282240,
"scriptDurationMs": 97.269,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1965.9970000000158,
"styleRecalcs": 84,
"styleRecalcDurationMs": 42.563,
"layouts": 16,
"layoutDurationMs": 4.037,
"taskDurationMs": 884.539,
"heapDeltaBytes": 11807504,
"heapUsedBytes": 54576484,
"domNodes": 73,
"jsHeapTotalBytes": 22806528,
"scriptDurationMs": 98.828,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8188.0820000000085,
"styleRecalcs": 250,
"styleRecalcDurationMs": 40.674,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3545.036,
"heapDeltaBytes": 13611656,
"heapUsedBytes": 62005100,
"domNodes": -257,
"jsHeapTotalBytes": 20496384,
"scriptDurationMs": 1243.917,
"eventListeners": -105,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.80000000000109
},
{
"name": "viewport-pan-sweep",
"durationMs": 8184.877000000029,
"styleRecalcs": 251,
"styleRecalcDurationMs": 42.467999999999996,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3468.389,
"heapDeltaBytes": 26696032,
"heapUsedBytes": 77716652,
"domNodes": -256,
"jsHeapTotalBytes": 18485248,
"scriptDurationMs": 1214.519,
"eventListeners": -111,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333338,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8211.393999999927,
"styleRecalcs": 251,
"styleRecalcDurationMs": 42.465999999999994,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3549.0220000000004,
"heapDeltaBytes": 29078720,
"heapUsedBytes": 79565720,
"domNodes": -256,
"jsHeapTotalBytes": 19271680,
"scriptDurationMs": 1229.577,
"eventListeners": -111,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 11521.600000000035,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 11508.9,
"heapDeltaBytes": -28304436,
"heapUsedBytes": 166294580,
"domNodes": -8331,
"jsHeapTotalBytes": 27090944,
"scriptDurationMs": 556.91,
"eventListeners": -16464,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.220000000000073,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 11415.50600000005,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 11404.473,
"heapDeltaBytes": -50189700,
"heapUsedBytes": 158149004,
"domNodes": -8331,
"jsHeapTotalBytes": 17391616,
"scriptDurationMs": 575.819,
"eventListeners": -16464,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.223333333333358,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 11700.229000000036,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 11689.974,
"heapDeltaBytes": -24682620,
"heapUsedBytes": 167036176,
"domNodes": -8331,
"jsHeapTotalBytes": 27090944,
"scriptDurationMs": 556.956,
"eventListeners": -16462,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.223333333333237,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 13932.326999999987,
"styleRecalcs": 64,
"styleRecalcDurationMs": 12.64700000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 13910.495,
"heapDeltaBytes": -45065876,
"heapUsedBytes": 165453232,
"domNodes": -8331,
"jsHeapTotalBytes": 27877376,
"scriptDurationMs": 821.0519999999999,
"eventListeners": -16460,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 33.30000000000291
},
{
"name": "vue-large-graph-pan",
"durationMs": 14149.373000000083,
"styleRecalcs": 64,
"styleRecalcDurationMs": 12.945999999999986,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 14128.297,
"heapDeltaBytes": -23016024,
"heapUsedBytes": 173785284,
"domNodes": -8333,
"jsHeapTotalBytes": 24907776,
"scriptDurationMs": 825.115,
"eventListeners": -16458,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 33.29999999999927
},
{
"name": "vue-large-graph-pan",
"durationMs": 13875.147999999968,
"styleRecalcs": 66,
"styleRecalcDurationMs": 12.830999999999982,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 13857.860999999999,
"heapDeltaBytes": -47279264,
"heapUsedBytes": 163167996,
"domNodes": -8331,
"jsHeapTotalBytes": 21848064,
"scriptDurationMs": 836.902,
"eventListeners": -16462,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.220000000000073,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 455.41400000001886,
"styleRecalcs": 19,
"styleRecalcDurationMs": 24.262,
"layouts": 4,
"layoutDurationMs": 1.1850000000000003,
"taskDurationMs": 113.72700000000002,
"heapDeltaBytes": 4624276,
"heapUsedBytes": 49153596,
"domNodes": 169,
"jsHeapTotalBytes": 262144,
"scriptDurationMs": 23.705,
"eventListeners": 71,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "workflow-execution",
"durationMs": 441.29899999995814,
"styleRecalcs": 16,
"styleRecalcDurationMs": 20.922000000000004,
"layouts": 5,
"layoutDurationMs": 1.0990000000000002,
"taskDurationMs": 114.046,
"heapDeltaBytes": 4498672,
"heapUsedBytes": 48867284,
"domNodes": 156,
"jsHeapTotalBytes": 262144,
"scriptDurationMs": 28.39099999999999,
"eventListeners": 71,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.799999999999727
},
{
"name": "workflow-execution",
"durationMs": 449.28300000003674,
"styleRecalcs": 19,
"styleRecalcDurationMs": 26.202999999999996,
"layouts": 4,
"layoutDurationMs": 1.0090000000000001,
"taskDurationMs": 112.91799999999999,
"heapDeltaBytes": 4395480,
"heapUsedBytes": 48408568,
"domNodes": 159,
"jsHeapTotalBytes": 262144,
"scriptDurationMs": 22.212999999999997,
"eventListeners": 71,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.700000000000273
}
]
} |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@browser_tests/tests/workflowReopenOverwrite.spec.ts`:
- Around line 44-49: The test mutates widgets_values[0] on the serialized
KSampler node which hardcodes widget ordering; instead locate the live node's
seed widget index by name and use that index to update the serialized node's
widgets_values array. In practice, find the node where n.type === 'KSampler'
(ksNode), inspect its widgets (or widgets_meta) to find the seed widget
name/key, get that index, and then assign the seed value into
ksNode.widgets_values[seedIndex] rather than using 0.
- Around line 67-75: The assertion is too permissive and uses a hardcoded
baseline; capture the workflow count before reload (e.g.,
preReloadWorkflowCount) and then replace the OR check so the test only passes if
either seedAfterReload === modifiedSeed (preserved) or workflowCount ===
preReloadWorkflowCount + 1 (a single new tab opened), instead of comparing to a
fixed > 2 value; update the expect message to reference preReloadWorkflowCount,
modifiedSeed, and seedAfterReload to make failures clear and remove the brittle
hardcoded threshold.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 26c494b7-3b0a-498b-b288-e03f3140b692
📒 Files selected for processing (2)
browser_tests/tests/workflowReopenOverwrite.spec.tssrc/platform/workflow/core/services/workflowService.ts
- Resolve seed widget index by name instead of hardcoding [0] - Capture workflow count before reload for relative comparison
There was a problem hiding this comment.
🧹 Nitpick comments (1)
browser_tests/tests/workflowReopenOverwrite.spec.ts (1)
16-17: UnnecessarynextFrame()afterloadWorkflow().Per repository conventions,
comfyPage.loadWorkflow()already handles all necessary synchronization and waiting. ThenextFrame()call on line 17 is redundant.♻️ Suggested simplification
// Step 1: Load a workflow from file (establishes a "source" filename) await comfyPage.workflow.loadWorkflow('nodes/single_ksampler') - await comfyPage.nextFrame()Based on learnings: "In browser_tests tests for the Comfy-Org/ComfyUI_frontend repository, the
comfyPage.loadWorkflow()method already handles all necessary synchronization and waiting."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@browser_tests/tests/workflowReopenOverwrite.spec.ts` around lines 16 - 17, Remove the redundant call to comfyPage.nextFrame() that immediately follows comfyPage.workflow.loadWorkflow('nodes/single_ksampler'); loadWorkflow already performs the necessary synchronization/waiting, so delete the comfyPage.nextFrame() invocation (referencing comfyPage.workflow.loadWorkflow and comfyPage.nextFrame) to simplify the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@browser_tests/tests/workflowReopenOverwrite.spec.ts`:
- Around line 16-17: Remove the redundant call to comfyPage.nextFrame() that
immediately follows comfyPage.workflow.loadWorkflow('nodes/single_ksampler');
loadWorkflow already performs the necessary synchronization/waiting, so delete
the comfyPage.nextFrame() invocation (referencing
comfyPage.workflow.loadWorkflow and comfyPage.nextFrame) to simplify the test.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ad95fa2f-40b3-4a36-9b93-b96b48e14773
📒 Files selected for processing (1)
browser_tests/tests/workflowReopenOverwrite.spec.ts
The programmatic widget edit did not fire checkState(), so isModified stayed false and the fix had no effect. Call checkState() explicitly to mirror what happens on mouseup/keyup during real user interaction.
QA 🔍 FocusedRun: https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/23936435159 · Download artifacts · All videos Video Reviewlinux QA Video Report
AI ReviewSummaryThe PR fixes a bug where re-loading a workflow file that is already open and has unsaved changes would silently overwrite those changes without warning. The fix adds a check to ensure that a workflow is only reused if it has not been modified; otherwise, it opens a new tab.
Behavior Changes
Timeline Comparison
Confirmed Issues[Unsaved changes silently overwritten]
Overall RiskThe risk is low. The change is a targeted logical guard in the workflow loading service that specifically protects against data loss when a user drags-and-drops or re-opens a file they are currently editing. The provided regression test ensures this specific scenario is covered. Verdict{"verdict": "REPRODUCED", "risk": "low", "confidence": "high"} |
Summary
When a user loads a workflow file that is already open in a tab and has unsaved modifications, the second load silently overwrites all changes via
changeTracker.reset()without any save/discard prompt or new tab creation.Root cause:
isSameActiveWorkflowLoadinworkflowService.tsmatched the active workflow by path/id but did not checkisModified, so modified workflows were treated identically to unmodified ones.Fix: Add
!existingWorkflow.isModifiedguard toisSameActiveWorkflowLoad. When the active workflow has unsaved edits, the condition falls through tocreateNewTemporary(), opening a new tab instead of overwriting.Reproduction Steps
test_workflow.json0to99999)0, no save prompt shownAS IS (Before Fix)
Re-loading
test_workflow.jsonafter editing seed to99999:changeTracker.reset()overwrites seed back to0TO BE (After Fix)
Re-loading
test_workflow.jsonafter editing seed to99999:0)99999Red-Green Verification
test: add failing test for workflow reopen overwriting unsaved changesfix: prevent re-opening same workflow from silently discarding unsaved editsTest Plan
browser_tests/tests/workflowReopenOverwrite.spec.ts┆Issue is synchronized with this Notion page by Unito