fix: dedupe Bypass context-menu items by making legacy entry state-aware#12296
fix: dedupe Bypass context-menu items by making legacy entry state-aware#12296christian-byrne wants to merge 3 commits into
Conversation
Right-clicking a bypassed node showed two bypass items in the Vue
context menu: a plain 'Bypass' from the legacy LiteGraph
`getExtraMenuOptions` hook in litegraphService and 'Remove Bypass'
from the Vue `getBypassOption` composable. The Vue menu's exact-label
deduplicator collapses the unbypassed case (both emit 'Bypass') but
not the bypassed case ('Bypass' vs 'Remove Bypass').
Make the legacy hook emit a stateful label that matches the Vue label,
so existing exact-label dedupe (which prefers the Vue source) handles
both states uniformly. The legacy LiteGraph menu (Comfy.UseNewMenu:
Disabled) now also shows the correct conditional label, which was
previously stuck on 'Bypass' regardless of node state.
Fixes FE-720
Address Oracle review on FE-720 fix: the label was derived from the right-clicked node's mode (`this.mode`), but the click action operates on the entire selection via `toggleSelectedNodesMode`. On a mixed multi-selection (some nodes bypassed, some not), right-clicking a bypassed node would show 'Remove Bypass' even though clicking it bypasses the rest of the selection. Extract the predicate as `areAllSelectedNodesInMode` on the `useSelectedLiteGraphItems` composable so the label and the action share one source of truth, and have the legacy bypass menu entry use it. Adds a unit test covering all-bypassed, mixed, and empty cases.
📝 WalkthroughWalkthroughAdds an exported helper to check whether all selected nodes share a given mode, refactors toggle logic to use it (switching to ALWAYS when already matching), exposes the helper, and updates context menu labeling and tests so "Remove Bypass" appears when appropriate. ChangesConditional Bypass Label Display
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Suggested reviewers
Poem
Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (1 error)
✅ Passed checks (6 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
🎨 Storybook: ✅ Built — View Storybook |
|
Acknowledged — waiting for the substantive CodeRabbit review pass. Will address any findings once they post. |
🎭 Playwright: ✅ 1592 passed, 0 failed · 8 flaky📊 Browser Reports
|
📦 Bundle: 5.36 MB gzip 🔴 +150 BDetailsSummary
Category Glance App Entry Points — 26.1 kB (baseline 26.1 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 1.24 MB (baseline 1.24 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 82.9 kB (baseline 82.9 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 9 added / 9 removed / 2 unchanged Panels & Settings — 527 kB (baseline 527 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 10 added / 10 removed / 14 unchanged User & Accounts — 17.8 kB (baseline 17.8 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 5 added / 5 removed / 2 unchanged Editors & Dialogs — 112 kB (baseline 112 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 4 added / 4 removed UI Components — 58 kB (baseline 58 kB) • ⚪ 0 BReusable component library chunks
Status: 5 added / 5 removed / 8 unchanged Data & Services — 3.16 MB (baseline 3.16 MB) • 🔴 +606 BStores, services, APIs, and repositories
Status: 13 added / 13 removed / 4 unchanged Utilities & Hooks — 366 kB (baseline 366 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 13 added / 13 removed / 18 unchanged Vendor & Third-Party — 9.94 MB (baseline 9.94 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 16 unchanged Other — 9.16 MB (baseline 9.16 MB) • ⚪ 0 BBundles that do not match a named category
Status: 57 added / 57 removed / 86 unchanged ⚡ Performance Report
All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-05-15T20:17:38.243Z",
"gitSha": "0931ba705ceb4d9c4b19133b1fc513a090178479",
"branch": "glary/fix-duplicate-bypass-menu-item",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2062.8340000000094,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.851999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 506.378,
"heapDeltaBytes": 35032740,
"heapUsedBytes": 88101552,
"domNodes": 18,
"jsHeapTotalBytes": 46661632,
"scriptDurationMs": 30,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-idle",
"durationMs": 2013.824999999997,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.064,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 469.441,
"heapDeltaBytes": -9887464,
"heapUsedBytes": 58644916,
"domNodes": -260,
"jsHeapTotalBytes": 20668416,
"scriptDurationMs": 23.8,
"eventListeners": -129,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1892.2259999999937,
"styleRecalcs": 78,
"styleRecalcDurationMs": 45.648,
"layouts": 12,
"layoutDurationMs": 4.595,
"taskDurationMs": 835.592,
"heapDeltaBytes": -2798676,
"heapUsedBytes": 63290968,
"domNodes": 61,
"jsHeapTotalBytes": 20541440,
"scriptDurationMs": 131.67000000000002,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1873.6369999999738,
"styleRecalcs": 77,
"styleRecalcDurationMs": 42.028999999999996,
"layouts": 12,
"layoutDurationMs": 4.037,
"taskDurationMs": 850.347,
"heapDeltaBytes": 19165364,
"heapUsedBytes": 68260356,
"domNodes": -262,
"jsHeapTotalBytes": 16904192,
"scriptDurationMs": 125.10000000000002,
"eventListeners": -129,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1720.3690000000051,
"styleRecalcs": 31,
"styleRecalcDurationMs": 17.895,
"layouts": 6,
"layoutDurationMs": 0.568,
"taskDurationMs": 304.19,
"heapDeltaBytes": 505724,
"heapUsedBytes": 49137240,
"domNodes": 77,
"jsHeapTotalBytes": 14942208,
"scriptDurationMs": 20.232000000000006,
"eventListeners": 21,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1734.6210000000042,
"styleRecalcs": 31,
"styleRecalcDurationMs": 19.498,
"layouts": 6,
"layoutDurationMs": 0.738,
"taskDurationMs": 347.1770000000001,
"heapDeltaBytes": 793788,
"heapUsedBytes": 48855360,
"domNodes": 79,
"jsHeapTotalBytes": 14680064,
"scriptDurationMs": 27.509999999999998,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 552.9360000000167,
"styleRecalcs": 10,
"styleRecalcDurationMs": 10.875000000000004,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 345.9220000000001,
"heapDeltaBytes": 8798840,
"heapUsedBytes": 57646688,
"domNodes": 16,
"jsHeapTotalBytes": 14942208,
"scriptDurationMs": 55.37500000000001,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.669999999999998,
"p95FrameDurationMs": 16.799999999999727
},
{
"name": "dom-widget-clipping",
"durationMs": 528.3459999999991,
"styleRecalcs": 10,
"styleRecalcDurationMs": 7.161999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 324.36999999999995,
"heapDeltaBytes": 8881200,
"heapUsedBytes": 57369752,
"domNodes": 16,
"jsHeapTotalBytes": 15204352,
"scriptDurationMs": 52.952,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "large-graph-idle",
"durationMs": 2021.333999999996,
"styleRecalcs": 11,
"styleRecalcDurationMs": 10.713000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 592.596,
"heapDeltaBytes": 8141520,
"heapUsedBytes": 65688732,
"domNodes": -258,
"jsHeapTotalBytes": 3493888,
"scriptDurationMs": 109.924,
"eventListeners": -131,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2015.8710000000042,
"styleRecalcs": 11,
"styleRecalcDurationMs": 9.264000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 576.743,
"heapDeltaBytes": 7921020,
"heapUsedBytes": 64931884,
"domNodes": -256,
"jsHeapTotalBytes": 552960,
"scriptDurationMs": 102.07200000000002,
"eventListeners": -129,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2207.7500000000045,
"styleRecalcs": 68,
"styleRecalcDurationMs": 17.338,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1213.1059999999998,
"heapDeltaBytes": 48126456,
"heapUsedBytes": 109595088,
"domNodes": -263,
"jsHeapTotalBytes": 33030144,
"scriptDurationMs": 407.43700000000007,
"eventListeners": -129,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2177.33800000002,
"styleRecalcs": 69,
"styleRecalcDurationMs": 18.114999999999995,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1189.1180000000002,
"heapDeltaBytes": 58021900,
"heapUsedBytes": 118334616,
"domNodes": -263,
"jsHeapTotalBytes": 40603648,
"scriptDurationMs": 396.10599999999994,
"eventListeners": -127,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3219.581000000005,
"styleRecalcs": 66,
"styleRecalcDurationMs": 18.849,
"layouts": 60,
"layoutDurationMs": 7.803999999999999,
"taskDurationMs": 1405.4379999999999,
"heapDeltaBytes": 44861952,
"heapUsedBytes": 106213172,
"domNodes": -266,
"jsHeapTotalBytes": 44068864,
"scriptDurationMs": 485.974,
"eventListeners": -125,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3219.251999999983,
"styleRecalcs": 66,
"styleRecalcDurationMs": 20.267,
"layouts": 60,
"layoutDurationMs": 7.679,
"taskDurationMs": 1331.1350000000002,
"heapDeltaBytes": 3148676,
"heapUsedBytes": 64985028,
"domNodes": -266,
"jsHeapTotalBytes": 5066752,
"scriptDurationMs": 480.58,
"eventListeners": -127,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2038.2409999999709,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.674000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 569.5360000000001,
"heapDeltaBytes": 3940832,
"heapUsedBytes": 62932800,
"domNodes": -260,
"jsHeapTotalBytes": 5795840,
"scriptDurationMs": 102.64300000000001,
"eventListeners": -129,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2027.6719999999955,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.820999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 569.172,
"heapDeltaBytes": 13814532,
"heapUsedBytes": 75189372,
"domNodes": -263,
"jsHeapTotalBytes": 4018176,
"scriptDurationMs": 98.632,
"eventListeners": -129,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 553.6309999999958,
"styleRecalcs": 47,
"styleRecalcDurationMs": 11.124,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 364.36600000000004,
"heapDeltaBytes": -12540376,
"heapUsedBytes": 53195440,
"domNodes": 20,
"jsHeapTotalBytes": 21065728,
"scriptDurationMs": 125.919,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 543.0730000000494,
"styleRecalcs": 48,
"styleRecalcDurationMs": 11.38,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 349.65500000000003,
"heapDeltaBytes": 15381532,
"heapUsedBytes": 64629636,
"domNodes": 21,
"jsHeapTotalBytes": 16777216,
"scriptDurationMs": 112.61399999999999,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "subgraph-idle",
"durationMs": 2016.715000000005,
"styleRecalcs": 12,
"styleRecalcDurationMs": 10.916,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 475.30300000000005,
"heapDeltaBytes": 11570060,
"heapUsedBytes": 61708904,
"domNodes": -257,
"jsHeapTotalBytes": 17260544,
"scriptDurationMs": 23.076,
"eventListeners": -129,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "subgraph-idle",
"durationMs": 2003.7429999999858,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.140999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 353.879,
"heapDeltaBytes": 22972248,
"heapUsedBytes": 71851372,
"domNodes": 19,
"jsHeapTotalBytes": 15204352,
"scriptDurationMs": 15.342000000000002,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1724.6459999999786,
"styleRecalcs": 75,
"styleRecalcDurationMs": 37.009,
"layouts": 16,
"layoutDurationMs": 4.537,
"taskDurationMs": 747.1350000000001,
"heapDeltaBytes": 13246772,
"heapUsedBytes": 62461220,
"domNodes": -262,
"jsHeapTotalBytes": 19263488,
"scriptDurationMs": 91.845,
"eventListeners": -131,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1693.885000000023,
"styleRecalcs": 76,
"styleRecalcDurationMs": 36.409,
"layouts": 16,
"layoutDurationMs": 4.685,
"taskDurationMs": 674.43,
"heapDeltaBytes": -4368776,
"heapUsedBytes": 64183524,
"domNodes": 62,
"jsHeapTotalBytes": 19398656,
"scriptDurationMs": 89.427,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-transition-enter",
"durationMs": 1065.6619999999748,
"styleRecalcs": 16,
"styleRecalcDurationMs": 24.443000000000005,
"layouts": 4,
"layoutDurationMs": 11.283000000000001,
"taskDurationMs": 837.539,
"heapDeltaBytes": -24024924,
"heapUsedBytes": 118897452,
"domNodes": 12627,
"jsHeapTotalBytes": -30216192,
"scriptDurationMs": 31.992000000000008,
"eventListeners": 1637,
"totalBlockingTimeMs": 146,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 8178.616000000005,
"styleRecalcs": 251,
"styleRecalcDurationMs": 55.364999999999995,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4037.242,
"heapDeltaBytes": 23798868,
"heapUsedBytes": 81178104,
"domNodes": -260,
"jsHeapTotalBytes": 8097792,
"scriptDurationMs": 1413.4719999999998,
"eventListeners": -113,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8123.287000000005,
"styleRecalcs": 249,
"styleRecalcDurationMs": 51.706,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3825.5579999999995,
"heapDeltaBytes": 24479596,
"heapUsedBytes": 82520376,
"domNodes": -262,
"jsHeapTotalBytes": 6262784,
"scriptDurationMs": 1272.3289999999997,
"eventListeners": -143,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 13133.935000000009,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 13080.639000000001,
"heapDeltaBytes": -5908808,
"heapUsedBytes": 248036508,
"domNodes": -8331,
"jsHeapTotalBytes": 2420736,
"scriptDurationMs": 649.5730000000001,
"eventListeners": -16488,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.219999999999953,
"p95FrameDurationMs": 16.80000000000291
},
{
"name": "vue-large-graph-idle",
"durationMs": 10735.455000000002,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 10723.504,
"heapDeltaBytes": -37408664,
"heapUsedBytes": 165590628,
"domNodes": -8331,
"jsHeapTotalBytes": 16838656,
"scriptDurationMs": 582.538,
"eventListeners": -16468,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.219999999999953,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-pan",
"durationMs": 15316.821000000004,
"styleRecalcs": 75,
"styleRecalcDurationMs": 18.338000000000022,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 15294.077000000001,
"heapDeltaBytes": 7630124,
"heapUsedBytes": 269574576,
"domNodes": -8331,
"jsHeapTotalBytes": -2383872,
"scriptDurationMs": 1010.977,
"eventListeners": -16486,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.219999999999953,
"p95FrameDurationMs": 16.80000000000291
},
{
"name": "vue-large-graph-pan",
"durationMs": 12653.804000000036,
"styleRecalcs": 65,
"styleRecalcDurationMs": 17.258999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 12637.301,
"heapDeltaBytes": -32893540,
"heapUsedBytes": 177920004,
"domNodes": -8331,
"jsHeapTotalBytes": -17063936,
"scriptDurationMs": 855.823,
"eventListeners": -16464,
"totalBlockingTimeMs": 2,
"frameDurationMs": 17.219999999999953,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 448.49400000003925,
"styleRecalcs": 15,
"styleRecalcDurationMs": 21.858,
"layouts": 5,
"layoutDurationMs": 1.6360000000000001,
"taskDurationMs": 122.531,
"heapDeltaBytes": 5269592,
"heapUsedBytes": 55531264,
"domNodes": 165,
"jsHeapTotalBytes": 262144,
"scriptDurationMs": 24.799999999999997,
"eventListeners": 71,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "workflow-execution",
"durationMs": 482.1470000000545,
"styleRecalcs": 19,
"styleRecalcDurationMs": 20.647,
"layouts": 4,
"layoutDurationMs": 1.1289999999999998,
"taskDurationMs": 123.08899999999997,
"heapDeltaBytes": 5297952,
"heapUsedBytes": 55572812,
"domNodes": 175,
"jsHeapTotalBytes": 262144,
"scriptDurationMs": 27.050000000000004,
"eventListeners": 71,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000273
}
]
} |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/services/litegraphService.ts`:
- Around line 723-725: Replace the hard-coded labels in the toggle payload with
vue-i18n lookups: call t('main.bypass.remove') when
areAllSelectedNodesInMode(LGraphEventMode.BYPASS) is true, otherwise
t('main.bypass.add'), using the same scope where the current content is set (the
code referencing areAllSelectedNodesInMode and LGraphEventMode.BYPASS). Add
corresponding keys ("main.bypass.remove" and "main.bypass.add") to the English
locale file under the main namespace with values "Remove Bypass" and "Bypass",
and ensure the module has access to the i18n `t` function (import or use
existing composable) so the labels are localized.
🪄 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: 06a8b17f-49b6-429f-84bf-87047ce95b98
📒 Files selected for processing (4)
src/composables/canvas/useSelectedLiteGraphItems.test.tssrc/composables/canvas/useSelectedLiteGraphItems.tssrc/composables/graph/contextMenuConverter.test.tssrc/services/litegraphService.ts
| content: areAllSelectedNodesInMode(LGraphEventMode.BYPASS) | ||
| ? 'Remove Bypass' | ||
| : 'Bypass', |
There was a problem hiding this comment.
Localize the new bypass labels via vue-i18n.
These user-facing labels are raw string literals in a .ts file. Please route them through translation keys (and add the new key to src/locales/en/main.json).
Suggested change
options.push({
content: areAllSelectedNodesInMode(LGraphEventMode.BYPASS)
- ? 'Remove Bypass'
- : 'Bypass',
+ ? t('contextMenu.RemoveBypass')
+ : t('contextMenu.Bypass'),
callback: () => {
toggleSelectedNodesMode(LGraphEventMode.BYPASS)
canvas.setDirty(true, true)
}
})As per coding guidelines: src/**/*.{ts,tsx,vue} says to “Use vue-i18n for ALL user-facing strings,” with entries in src/locales/en/main.json.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/services/litegraphService.ts` around lines 723 - 725, Replace the
hard-coded labels in the toggle payload with vue-i18n lookups: call
t('main.bypass.remove') when areAllSelectedNodesInMode(LGraphEventMode.BYPASS)
is true, otherwise t('main.bypass.add'), using the same scope where the current
content is set (the code referencing areAllSelectedNodesInMode and
LGraphEventMode.BYPASS). Add corresponding keys ("main.bypass.remove" and
"main.bypass.add") to the English locale file under the main namespace with
values "Remove Bypass" and "Bypass", and ensure the module has access to the
i18n `t` function (import or use existing composable) so the labels are
localized.
There was a problem hiding this comment.
Good catch — fixed in ad3ad327b.
Used the existing locale keys contextMenu.Bypass / contextMenu.Remove Bypass (already defined in src/locales/en/main.json and used by the Vue getBypassOption in useNodeMenuOptions.ts) rather than creating new contextMenu.RemoveBypass / main.bypass.* keys, so the legacy LiteGraph entry stays byte-identical to the Vue entry in every locale — which is what the menu deduplicator's exact-label match relies on.
content: areAllSelectedNodesInMode(LGraphEventMode.BYPASS)
? t('contextMenu.Remove Bypass')
: t('contextMenu.Bypass'),t was already imported in this file (import { st, t } from '@/i18n' at line 14).
There was a problem hiding this comment.
Skipped: comment is from another GitHub bot.
Codecov Report❌ Patch coverage is
@@ Coverage Diff @@
## main #12296 +/- ##
===========================================
- Coverage 74.07% 59.57% -14.50%
===========================================
Files 1521 1412 -109
Lines 87192 71886 -15306
Branches 23325 19032 -4293
===========================================
- Hits 64588 42827 -21761
- Misses 21772 28586 +6814
+ Partials 832 473 -359
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 1003 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Addresses CodeRabbit review: per AGENTS.md, all user-facing strings
must use vue-i18n. The Vue `getBypassOption` already uses
`t('contextMenu.Bypass')` and `t('contextMenu.Remove Bypass')` —
reuse the same keys so the legacy LiteGraph entry stays exact-label
identical to the Vue entry (which is how the menu deduplicator
collapses them) in every locale.
PR Created by the Glary-Bot Agent
Summary
Right-clicking a bypassed node showed two bypass-related items in the Vue node context menu (see FE-720):
Bypassfrom the legacy LiteGraphgetExtraMenuOptionshook inlitegraphService.ts.Remove Bypass(withCtrl+Band an icon) from the VuegetBypassOptioncomposable inuseNodeMenuOptions.ts.The Vue menu's exact-label deduplicator in
contextMenuConverter.tsalready collapses the unbypassed case (both registrations emitBypass→ exact match → Vue source wins), but not the bypassed case (BypassvsRemove Bypass).Fix
Make the legacy hook emit a stateful label that matches the Vue label, so the existing exact-label dedupe handles both states uniformly — no new label-equivalence rules, no callback-identity coupling, no blacklist that could hide third-party extension items.
The label must reflect what the click action will actually do. The action (
toggleSelectedNodesMode) operates on the whole selection and only un-bypasses when every selected node is already inBYPASS. To keep the label and the action in sync (and avoid a misleadingRemove Bypasson mixed selections), the predicate is extracted asareAllSelectedNodesInModeon theuseSelectedLiteGraphItemscomposable and reused by both the toggle and the menu label.Side benefit: the legacy LiteGraph menu (
Comfy.UseNewMenu: 'Disabled') also gets the correct conditional label, which previously was stuck onBypassregardless of node state.Considered and rejected:
bypass: ['bypass', 'remove bypass']to theequivalentsmap — would silently drop third-party extension menu items labeledBypass.'Bypass'toHARD_BLACKLIST— same third-party problem.litegraphServiceandcontextMenuConverterfor a 3-line behavioral change.Tests
contextMenuConverter.test.ts: two new tests — legacy + VueRemove Bypasscollapse to the Vue item;BypassandRemove Bypassare NOT treated as equivalents (locks in that we did not regress by adding a label-equivalence rule that would hide extension items).useSelectedLiteGraphItems.test.ts: one new test forareAllSelectedNodesInModecovering all-bypassed, mixed, and empty-selection cases — directly addresses the review concern that the label could drift from the toggle's predicate.Local verification:
Manual browser verification was attempted via Playwright but the test harness could not reliably reproduce the Vue context-menu open state in headless mode within the available time budget. The behavior is exercised end-to-end by the existing Playwright suite (
browser_tests/tests/vueNodes/interactions/node/contextMenu.spec.ts) and gated by the targeted unit tests above.┆Issue is synchronized with this Notion page by Unito