Skip to content

feat(workspace): scope framing for the local workspace switcher - #15438

Merged
dante01yoon merged 8 commits into
dante01yoon/fe-1584-local-workspace-switcherfrom
comfydesigner/switcher-credits-menu
Aug 20, 2026
Merged

feat(workspace): scope framing for the local workspace switcher#15438
dante01yoon merged 8 commits into
dante01yoon/fe-1584-local-workspace-switcherfrom
comfydesigner/switcher-credits-menu

Conversation

@comfydesigner

@comfydesigner comfydesigner commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Stacked on #15164. Adds the local-only scope framing to the workspace switcher menu, per DES-787 / FE-1584. Design: Menu States (6245-41540).

Behavioral spec

  1. On local, the workspace switcher picks whose credits you spend — nothing else (shipped by feat(workspace): enable local credit workspace switching FE-1584 #15164; unchanged here).
  2. Workspace rows are identical to cloud: name, role, check on the active row.
  3. The scope explainer, off cloud only: the "Workspaces only affect which credits you use." caption, whose info icon carries the full tooltip ("Runs that use partner nodes spend credits from this workspace. Unlike on Cloud, every workspace saves to your usual output folder."), positioned left so the rows stay visible during hover.
  4. No "manage workspaces" entry on local (already gated isCloud by feat(workspace): enable local credit workspace switching FE-1584 #15164; unchanged here).

Deferred: per-row credit balances

Earlier commits on this branch built the designed per-row balances (read-only token mint + balance fetch per workspace, 60s cache) and then removed them — deferred post-V1 so local rows stay in parity with cloud's switcher. Deferring also drops this PR's interim fetch pattern and its two open dependencies: confirming the balance endpoint applies the member min-rule per identity, and the eventual balance field on the workspace list response. The implementation is intact in this branch's history for the follow-up.

Verification

  • pnpm test:unit — popover suite 10 passed (scope framing off-cloud, rows/roles, cloud unaffected).
  • Cloud behavior unchanged: caption/tooltip are !isCloud only; no balance fetches on any distribution; create-workspace button untouched.

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0b98ea87-273c-44fd-991f-6f1b40d4371d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 08/20/2026, 12:00:31 AM UTC

Links

🎭 Playwright: ✅ 1835 passed, 0 failed

📊 Browser Reports
  • chromium: View Report (✅ 1814 / ❌ 0 / ⚠️ 0 / ⏭️ 5)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 18 / ❌ 0 / ⚠️ 0 / ⏭️ 0)

📦 Bundle Size

⏳ Size data collection in progress…

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 58.0 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 58.8 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 60.4 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 67.6 MB heap
large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 72.9 MB heap
large-graph-pan: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 72.3 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 73.2 MB heap
legacy-node-drag: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 74.9 MB heap
minimap-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 73.9 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 69.0 MB heap
subgraph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 59.2 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 56.2 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 89ms TBT · 91.9 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 77.4 MB heap
vue-large-graph-idle: · 56.2 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 167.3 MB heap
vue-large-graph-pan: · 58.1 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 7ms TBT · 176.2 MB heap
workflow-execution: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.6 MB heap

ℹ️ No baseline found — significance unavailable.

Absolute values
Metric Value
canvas-idle: avg frame time 17ms
canvas-idle: p95 frame time 17ms
canvas-idle: layout duration 0ms
canvas-idle: style recalc duration 8ms
canvas-idle: layout count 0
canvas-idle: style recalc count 10
canvas-idle: task duration 501ms
canvas-idle: script duration 9ms
canvas-idle: TBT 0ms
canvas-idle: heap used 58.0 MB
canvas-idle: DOM nodes -280
canvas-idle: event listeners -150
canvas-mouse-sweep: avg frame time 17ms
canvas-mouse-sweep: p95 frame time 17ms
canvas-mouse-sweep: layout duration 3ms
canvas-mouse-sweep: style recalc duration 30ms
canvas-mouse-sweep: layout count 12
canvas-mouse-sweep: style recalc count 72
canvas-mouse-sweep: task duration 750ms
canvas-mouse-sweep: script duration 92ms
canvas-mouse-sweep: TBT 0ms
canvas-mouse-sweep: heap used 58.8 MB
canvas-mouse-sweep: DOM nodes -280
canvas-mouse-sweep: event listeners -151
canvas-zoom-sweep: avg frame time 17ms
canvas-zoom-sweep: p95 frame time 17ms
canvas-zoom-sweep: layout duration 1ms
canvas-zoom-sweep: style recalc duration 14ms
canvas-zoom-sweep: layout count 6
canvas-zoom-sweep: style recalc count 31
canvas-zoom-sweep: task duration 287ms
canvas-zoom-sweep: script duration 9ms
canvas-zoom-sweep: TBT 0ms
canvas-zoom-sweep: heap used 60.4 MB
canvas-zoom-sweep: DOM nodes 77
canvas-zoom-sweep: event listeners 19
dom-widget-clipping: avg frame time 17ms
dom-widget-clipping: p95 frame time 17ms
dom-widget-clipping: layout duration 0ms
dom-widget-clipping: style recalc duration 7ms
dom-widget-clipping: layout count 0
dom-widget-clipping: style recalc count 11
dom-widget-clipping: task duration 314ms
dom-widget-clipping: script duration 47ms
dom-widget-clipping: TBT 0ms
dom-widget-clipping: heap used 67.6 MB
dom-widget-clipping: DOM nodes 18
dom-widget-clipping: event listeners 1
large-graph-idle: avg frame time 17ms
large-graph-idle: p95 frame time 17ms
large-graph-idle: layout duration 0ms
large-graph-idle: style recalc duration 8ms
large-graph-idle: layout count 0
large-graph-idle: style recalc count 9
large-graph-idle: task duration 498ms
large-graph-idle: script duration 14ms
large-graph-idle: TBT 0ms
large-graph-idle: heap used 72.9 MB
large-graph-idle: DOM nodes -264
large-graph-idle: event listeners -148
large-graph-pan: avg frame time 17ms
large-graph-pan: p95 frame time 17ms
large-graph-pan: layout duration 0ms
large-graph-pan: style recalc duration 15ms
large-graph-pan: layout count 0
large-graph-pan: style recalc count 70
large-graph-pan: task duration 927ms
large-graph-pan: script duration 263ms
large-graph-pan: TBT 0ms
large-graph-pan: heap used 72.3 MB
large-graph-pan: DOM nodes -275
large-graph-pan: event listeners -163
large-graph-zoom: avg frame time 17ms
large-graph-zoom: p95 frame time 17ms
large-graph-zoom: layout duration 7ms
large-graph-zoom: style recalc duration 13ms
large-graph-zoom: layout count 60
large-graph-zoom: style recalc count 65
large-graph-zoom: task duration 1126ms
large-graph-zoom: script duration 319ms
large-graph-zoom: TBT 0ms
large-graph-zoom: heap used 73.2 MB
large-graph-zoom: DOM nodes -130
large-graph-zoom: event listeners -69
legacy-node-drag: avg frame time 17ms
legacy-node-drag: p95 frame time 17ms
legacy-node-drag: layout duration 0ms
legacy-node-drag: style recalc duration 11ms
legacy-node-drag: layout count 0
legacy-node-drag: style recalc count 48
legacy-node-drag: task duration 1213ms
legacy-node-drag: script duration 376ms
legacy-node-drag: TBT 0ms
legacy-node-drag: heap used 74.9 MB
legacy-node-drag: DOM nodes -126
legacy-node-drag: event listeners 110
minimap-idle: avg frame time 17ms
minimap-idle: p95 frame time 17ms
minimap-idle: layout duration 0ms
minimap-idle: style recalc duration 6ms
minimap-idle: layout count 0
minimap-idle: style recalc count 8
minimap-idle: task duration 471ms
minimap-idle: script duration 13ms
minimap-idle: TBT 0ms
minimap-idle: heap used 73.9 MB
minimap-idle: DOM nodes -264
minimap-idle: event listeners -149
subgraph-dom-widget-clipping: avg frame time 17ms
subgraph-dom-widget-clipping: p95 frame time 17ms
subgraph-dom-widget-clipping: layout duration 0ms
subgraph-dom-widget-clipping: style recalc duration 11ms
subgraph-dom-widget-clipping: layout count 0
subgraph-dom-widget-clipping: style recalc count 48
subgraph-dom-widget-clipping: task duration 323ms
subgraph-dom-widget-clipping: script duration 99ms
subgraph-dom-widget-clipping: TBT 0ms
subgraph-dom-widget-clipping: heap used 69.0 MB
subgraph-dom-widget-clipping: DOM nodes 21
subgraph-dom-widget-clipping: event listeners 7
subgraph-idle: avg frame time 17ms
subgraph-idle: p95 frame time 17ms
subgraph-idle: layout duration 0ms
subgraph-idle: style recalc duration 7ms
subgraph-idle: layout count 0
subgraph-idle: style recalc count 10
subgraph-idle: task duration 427ms
subgraph-idle: script duration 7ms
subgraph-idle: TBT 0ms
subgraph-idle: heap used 59.2 MB
subgraph-idle: DOM nodes -281
subgraph-idle: event listeners -151
subgraph-mouse-sweep: avg frame time 17ms
subgraph-mouse-sweep: p95 frame time 17ms
subgraph-mouse-sweep: layout duration 4ms
subgraph-mouse-sweep: style recalc duration 31ms
subgraph-mouse-sweep: layout count 16
subgraph-mouse-sweep: style recalc count 75
subgraph-mouse-sweep: task duration 678ms
subgraph-mouse-sweep: script duration 74ms
subgraph-mouse-sweep: TBT 0ms
subgraph-mouse-sweep: heap used 56.2 MB
subgraph-mouse-sweep: DOM nodes -282
subgraph-mouse-sweep: event listeners -151
subgraph-transition-enter: avg frame time 17ms
subgraph-transition-enter: p95 frame time 17ms
subgraph-transition-enter: layout duration 11ms
subgraph-transition-enter: style recalc duration 25ms
subgraph-transition-enter: layout count 15
subgraph-transition-enter: style recalc count 20
subgraph-transition-enter: task duration 719ms
subgraph-transition-enter: script duration 20ms
subgraph-transition-enter: TBT 89ms
subgraph-transition-enter: heap used 91.9 MB
subgraph-transition-enter: DOM nodes 13673
subgraph-transition-enter: event listeners 2373
viewport-pan-sweep: avg frame time 17ms
viewport-pan-sweep: p95 frame time 17ms
viewport-pan-sweep: layout duration 0ms
viewport-pan-sweep: style recalc duration 41ms
viewport-pan-sweep: layout count 0
viewport-pan-sweep: style recalc count 251
viewport-pan-sweep: task duration 3383ms
viewport-pan-sweep: script duration 840ms
viewport-pan-sweep: TBT 0ms
viewport-pan-sweep: heap used 77.4 MB
viewport-pan-sweep: DOM nodes -259
viewport-pan-sweep: event listeners -133
vue-large-graph-idle: avg frame time 18ms
vue-large-graph-idle: p95 frame time 17ms
vue-large-graph-idle: layout duration 0ms
vue-large-graph-idle: style recalc duration 0ms
vue-large-graph-idle: layout count 0
vue-large-graph-idle: style recalc count 0
vue-large-graph-idle: task duration 14827ms
vue-large-graph-idle: script duration 112ms
vue-large-graph-idle: TBT 0ms
vue-large-graph-idle: heap used 167.3 MB
vue-large-graph-idle: DOM nodes -8312
vue-large-graph-idle: event listeners -16389
vue-large-graph-pan: avg frame time 17ms
vue-large-graph-pan: p95 frame time 17ms
vue-large-graph-pan: layout duration 0ms
vue-large-graph-pan: style recalc duration 16ms
vue-large-graph-pan: layout count 0
vue-large-graph-pan: style recalc count 161
vue-large-graph-pan: task duration 17489ms
vue-large-graph-pan: script duration 353ms
vue-large-graph-pan: TBT 7ms
vue-large-graph-pan: heap used 176.2 MB
vue-large-graph-pan: DOM nodes -8312
vue-large-graph-pan: event listeners -16386
workflow-execution: avg frame time 17ms
workflow-execution: p95 frame time 17ms
workflow-execution: layout duration 1ms
workflow-execution: style recalc duration 16ms
workflow-execution: layout count 4
workflow-execution: style recalc count 10
workflow-execution: task duration 80ms
workflow-execution: script duration 6ms
workflow-execution: TBT 0ms
workflow-execution: heap used 61.6 MB
workflow-execution: DOM nodes 125
workflow-execution: event listeners 62
Raw data
{
  "timestamp": "2026-08-20T00:10:40.133Z",
  "gitSha": "8533ba08317f576c7285e64a5539e5887fda0e6e",
  "branch": "comfydesigner/switcher-credits-menu",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2090.7580000000507,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.037999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 582.8800000000001,
      "heapDeltaBytes": 1711252,
      "heapUsedBytes": 62583804,
      "domNodes": -281,
      "jsHeapTotalBytes": 4448256,
      "scriptDurationMs": 10.400999999999998,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "canvas-idle",
      "durationMs": 2038.8239999999769,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 7.752,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 420.09000000000003,
      "heapDeltaBytes": -1733672,
      "heapUsedBytes": 58976060,
      "domNodes": -279,
      "jsHeapTotalBytes": 4448256,
      "scriptDurationMs": 7.422999999999999,
      "eventListeners": -151,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1745.4819999999245,
      "styleRecalcs": 72,
      "styleRecalcDurationMs": 33.31,
      "layouts": 12,
      "layoutDurationMs": 3.5649999999999995,
      "taskDurationMs": 820.018,
      "heapDeltaBytes": 2113284,
      "heapUsedBytes": 62127264,
      "domNodes": -280,
      "jsHeapTotalBytes": 4448256,
      "scriptDurationMs": 98.17799999999998,
      "eventListeners": -151,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1693.3890000000247,
      "styleRecalcs": 71,
      "styleRecalcDurationMs": 27.458000000000002,
      "layouts": 12,
      "layoutDurationMs": 3.28,
      "taskDurationMs": 679.1769999999999,
      "heapDeltaBytes": 368336,
      "heapUsedBytes": 61087796,
      "domNodes": -279,
      "jsHeapTotalBytes": 4710400,
      "scriptDurationMs": 85.467,
      "eventListeners": -151,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1708.825999999931,
      "styleRecalcs": 30,
      "styleRecalcDurationMs": 15.367999999999999,
      "layouts": 6,
      "layoutDurationMs": 0.5349999999999999,
      "taskDurationMs": 297.09200000000004,
      "heapDeltaBytes": 2723124,
      "heapUsedBytes": 62921748,
      "domNodes": 77,
      "jsHeapTotalBytes": 4718592,
      "scriptDurationMs": 9.4,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1663.7379999999666,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 13.483,
      "layouts": 6,
      "layoutDurationMs": 0.5599999999999999,
      "taskDurationMs": 277.354,
      "heapDeltaBytes": 3053604,
      "heapUsedBytes": 63702956,
      "domNodes": 77,
      "jsHeapTotalBytes": 5242880,
      "scriptDurationMs": 8.005000000000003,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 555.3309999999101,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 7.282,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 333.616,
      "heapDeltaBytes": 10646596,
      "heapUsedBytes": 70721080,
      "domNodes": 18,
      "jsHeapTotalBytes": 4456448,
      "scriptDurationMs": 49.739,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 495.03100000003997,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 6.273999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 295.014,
      "heapDeltaBytes": 10685348,
      "heapUsedBytes": 70999832,
      "domNodes": 18,
      "jsHeapTotalBytes": 4718592,
      "scriptDurationMs": 43.658,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2028.09400000001,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 10.489999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 501.803,
      "heapDeltaBytes": 2465228,
      "heapUsedBytes": 76474936,
      "domNodes": -262,
      "jsHeapTotalBytes": -2101248,
      "scriptDurationMs": 13.869000000000003,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2031.725999999935,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 5.842,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 493.574,
      "heapDeltaBytes": 2341556,
      "heapUsedBytes": 76429080,
      "domNodes": -266,
      "jsHeapTotalBytes": -2363392,
      "scriptDurationMs": 13.317999999999996,
      "eventListeners": -147,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2125.630000000001,
      "styleRecalcs": 70,
      "styleRecalcDurationMs": 15.946000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1013.3230000000002,
      "heapDeltaBytes": -7548612,
      "heapUsedBytes": 67478224,
      "domNodes": -271,
      "jsHeapTotalBytes": -565248,
      "scriptDurationMs": 264.392,
      "eventListeners": -147,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2068.870000000061,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 14.518999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 841.5879999999999,
      "heapDeltaBytes": 10074752,
      "heapUsedBytes": 84154312,
      "domNodes": -278,
      "jsHeapTotalBytes": 4939776,
      "scriptDurationMs": 262.53700000000003,
      "eventListeners": -179,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3095.324000000005,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 14.966,
      "layouts": 60,
      "layoutDurationMs": 7.234000000000001,
      "taskDurationMs": 1168.087,
      "heapDeltaBytes": 770544,
      "heapUsedBytes": 76943984,
      "domNodes": -267,
      "jsHeapTotalBytes": -2363392,
      "scriptDurationMs": 325.218,
      "eventListeners": -145,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3032.4889999999414,
      "styleRecalcs": 63,
      "styleRecalcDurationMs": 11.942000000000002,
      "layouts": 60,
      "layoutDurationMs": 7.079999999999999,
      "taskDurationMs": 1083.671,
      "heapDeltaBytes": 14879360,
      "heapUsedBytes": 76629496,
      "domNodes": 8,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 313.539,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "legacy-node-drag",
      "durationMs": 2156.782000000021,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 11.309999999999997,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1206.237,
      "heapDeltaBytes": 11433348,
      "heapUsedBytes": 94157420,
      "domNodes": 16,
      "jsHeapTotalBytes": 8581120,
      "scriptDurationMs": 372.612,
      "eventListeners": 186,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "legacy-node-drag",
      "durationMs": 2188.4619999999586,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 10.349,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1220.448,
      "heapDeltaBytes": -21486048,
      "heapUsedBytes": 63004820,
      "domNodes": -267,
      "jsHeapTotalBytes": 7143424,
      "scriptDurationMs": 379.077,
      "eventListeners": 33,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2018.3350000000928,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 5.932999999999997,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 478.87300000000005,
      "heapDeltaBytes": 1791764,
      "heapUsedBytes": 77520164,
      "domNodes": -264,
      "jsHeapTotalBytes": -3411968,
      "scriptDurationMs": 14.092999999999998,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2023.2479999999669,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 5.655,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 463.435,
      "heapDeltaBytes": 1785656,
      "heapUsedBytes": 77554356,
      "domNodes": -264,
      "jsHeapTotalBytes": -3149824,
      "scriptDurationMs": 11.553999999999998,
      "eventListeners": -149,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 523.3050000000503,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 11.494,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 332.886,
      "heapDeltaBytes": 11804880,
      "heapUsedBytes": 72927792,
      "domNodes": 22,
      "jsHeapTotalBytes": 5505024,
      "scriptDurationMs": 100.65599999999999,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 512.3670000000402,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 9.763999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 314.039,
      "heapDeltaBytes": 10937388,
      "heapUsedBytes": 71776260,
      "domNodes": 20,
      "jsHeapTotalBytes": 5505024,
      "scriptDurationMs": 97.292,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2011.7180000000872,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 6.894000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 459.46999999999997,
      "heapDeltaBytes": 3582580,
      "heapUsedBytes": 63716408,
      "domNodes": -281,
      "jsHeapTotalBytes": 4186112,
      "scriptDurationMs": 8.447999999999999,
      "eventListeners": -151,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2018.1929999999966,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 6.937,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 395.425,
      "heapDeltaBytes": -304912,
      "heapUsedBytes": 60438000,
      "domNodes": -281,
      "jsHeapTotalBytes": 4448256,
      "scriptDurationMs": 5.788999999999999,
      "eventListeners": -151,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1715.7399999999825,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 33.04899999999999,
      "layouts": 16,
      "layoutDurationMs": 4.32,
      "taskDurationMs": 716.561,
      "heapDeltaBytes": -1902760,
      "heapUsedBytes": 59193908,
      "domNodes": -282,
      "jsHeapTotalBytes": 4710400,
      "scriptDurationMs": 79.15700000000001,
      "eventListeners": -151,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1709.57599999997,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 29.717,
      "layouts": 16,
      "layoutDurationMs": 4.035,
      "taskDurationMs": 639.783,
      "heapDeltaBytes": -2191688,
      "heapUsedBytes": 58629416,
      "domNodes": -281,
      "jsHeapTotalBytes": 4448256,
      "scriptDurationMs": 67.86,
      "eventListeners": -151,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 883.764000000042,
      "styleRecalcs": 20,
      "styleRecalcDurationMs": 25.09,
      "layouts": 15,
      "layoutDurationMs": 10.657,
      "taskDurationMs": 718.9159999999999,
      "heapDeltaBytes": 20087560,
      "heapUsedBytes": 96376216,
      "domNodes": 13673,
      "jsHeapTotalBytes": 16515072,
      "scriptDurationMs": 20.471999999999998,
      "eventListeners": 2373,
      "totalBlockingTimeMs": 89,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8142.555000000016,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 40.476,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3437.4599999999996,
      "heapDeltaBytes": 7224544,
      "heapUsedBytes": 81388224,
      "domNodes": -260,
      "jsHeapTotalBytes": -1351680,
      "scriptDurationMs": 841.8319999999999,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333338,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8136.683999999832,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 40.933,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3328.7259999999997,
      "heapDeltaBytes": 6873380,
      "heapUsedBytes": 80932856,
      "domNodes": -258,
      "jsHeapTotalBytes": -827392,
      "scriptDurationMs": 837.456,
      "eventListeners": -133,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 16419.788999999924,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 15203.030000000002,
      "heapDeltaBytes": -48101988,
      "heapUsedBytes": 176829780,
      "domNodes": -8312,
      "jsHeapTotalBytes": -14356480,
      "scriptDurationMs": 126.12300000000002,
      "eventListeners": -16387,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.779999999999927,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 14962.98999999999,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 14450.098,
      "heapDeltaBytes": -46230028,
      "heapUsedBytes": 174083976,
      "domNodes": -8312,
      "jsHeapTotalBytes": -11440128,
      "scriptDurationMs": 98.201,
      "eventListeners": -16391,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 18153.511999999977,
      "styleRecalcs": 160,
      "styleRecalcDurationMs": 15.66999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 17613.051,
      "heapDeltaBytes": -40989788,
      "heapUsedBytes": 178870076,
      "domNodes": -8312,
      "jsHeapTotalBytes": -14163968,
      "scriptDurationMs": 351.594,
      "eventListeners": -16385,
      "totalBlockingTimeMs": 5,
      "frameDurationMs": 17.219999999999953,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 17904.952000000092,
      "styleRecalcs": 162,
      "styleRecalcDurationMs": 16.009999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 17365.211,
      "heapDeltaBytes": -28685952,
      "heapUsedBytes": 190609560,
      "domNodes": -8312,
      "jsHeapTotalBytes": -13377536,
      "scriptDurationMs": 353.815,
      "eventListeners": -16387,
      "totalBlockingTimeMs": 9,
      "frameDurationMs": 17.220000000000073,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 93.42800000001716,
      "styleRecalcs": 6,
      "styleRecalcDurationMs": 12.235,
      "layouts": 5,
      "layoutDurationMs": 1.48,
      "taskDurationMs": 62.482000000000006,
      "heapDeltaBytes": 3038016,
      "heapUsedBytes": 63428444,
      "domNodes": 126,
      "jsHeapTotalBytes": 786432,
      "scriptDurationMs": 5.1850000000000005,
      "eventListeners": 25,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "workflow-execution",
      "durationMs": 464.6420000001399,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 19.339,
      "layouts": 2,
      "layoutDurationMs": 0.397,
      "taskDurationMs": 97.733,
      "heapDeltaBytes": 4932384,
      "heapUsedBytes": 65835764,
      "domNodes": 123,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 6.237999999999999,
      "eventListeners": 99,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    }
  ]
}

@github-actions github-actions Bot added the risk:R3 PR risk grade (advisory shadow check; grader-owned) label Aug 19, 2026
@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

@@                               Coverage Diff                                @@
##           dante01yoon/fe-1584-local-workspace-switcher   #15438      +/-   ##
================================================================================
+ Coverage                                         80.92%   80.97%   +0.05%     
================================================================================
  Files                                              1884     1883       -1     
  Lines                                            123653   122977     -676     
  Branches                                          38468    38317     -151     
================================================================================
- Hits                                             100063    99584     -479     
+ Misses                                            23089    22892     -197     
  Partials                                            501      501              
Flag Coverage Δ
unit 73.00% <100.00%> (-0.26%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
.../workspace/components/WorkspaceSwitcherPopover.vue 68.25% <100.00%> (+2.15%) ⬆️

... and 23 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@comfydesigner comfydesigner changed the title feat(workspace): credits-source rows and scope framing for the local switcher feat(workspace): scope framing for the local workspace switcher Aug 19, 2026
@comfydesigner
comfydesigner marked this pull request as ready for review August 20, 2026 00:07
@dosubot dosubot Bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Aug 20, 2026
@github-actions github-actions Bot added risk:R2 PR risk grade (advisory shadow check; grader-owned) and removed risk:R3 PR risk grade (advisory shadow check; grader-owned) labels Aug 20, 2026
@dante01yoon

dante01yoon commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Focused design delta on top of #15164

These screenshots were captured from the actual running local ComfyUI app with the same authenticated user and workspace data on both branches.

This PR is stacked directly on #15164 and is intended to be reviewed as the local-only scope-framing change. It does not change workspace switching, authentication, or API behavior.

AS IS — #15164 running app

AS IS — #15164 in the running local ComfyUI app

The local switcher already reuses the Cloud row/selection pattern, but the UI does not explain that selecting a workspace affects only the credit source.

TO BE — #15438 running app

TO BE — #15438 in the running local ComfyUI app

This PR adds only:

  • The local-only caption: “Workspaces only affect which credits you use.”
  • An info tooltip clarifying that partner-node runs spend credits from the selected workspace and that local output still goes to the usual output folder.
  • Coverage proving the explanation is shown off-Cloud and Cloud remains unchanged.

Review scope: the switching implementation remains in #15164; this PR can be reviewed and merged as the focused design/copy layer stacked on it.

@dante01yoon
dante01yoon merged commit ff4b46d into dante01yoon/fe-1584-local-workspace-switcher Aug 20, 2026
81 of 82 checks passed
@dante01yoon
dante01yoon deleted the comfydesigner/switcher-credits-menu branch August 20, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:R2 PR risk grade (advisory shadow check; grader-owned) size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants