[backport core/1.51] fix(workspace): hide subscription CTA on Local - #15716
[backport core/1.51] fix(workspace): hide subscription CTA on Local#15716comfy-pr-bot wants to merge 1 commit into
Conversation
## Why QA findings 3 and 6 expose the same invalid Local-only state: - **Finding 3:** a Local personal workspace without a subscription shows `Subscribe`. - **Finding 6:** switching to another Local workspace recomputes billing state and shows the same `Subscribe` action. Local workspace switching from [FE-1584](https://linear.app/comfyorg/issue/FE-1584/add-workspace-switcher-to-localdesktop-credits-only-no-settings) is limited to authentication and credits. Local does not support Cloud subscription management, so neither workspace state should offer a subscription CTA. ### Root cause `CurrentUserPopoverWorkspace` derived `showSubscribeAction` only from subscription access, delinquency, lifecycle, and permission state. It did not include the app distribution. In Local, an unsubscribed workspace can validly have no subscription access while retaining workspace-management permissions; that combination incorrectly satisfied the Cloud `Subscribe` condition. A workspace switch recalculated the same condition, which is why findings 3 and 6 had the same visible outcome. ## How - Gate `showSubscribeAction` on the existing deterministic `isCloud` distribution value. - Preserve the existing Subscribe/Resubscribe behavior for Cloud distributions. - Add unit coverage for a Local workspace changing from personal to an unsubscribed team workspace. - Extend the Local workspace-switch browser test to assert the CTA is absent both before and after the switch. ## AS IS  Local after switching to Team Workspace incorrectly shows `Subscribe`. ## TO BE  Local after switching to Team Workspace keeps subscription actions hidden. ## Testing - `pnpm test:unit src/platform/workspace/components/CurrentUserPopoverWorkspace.test.ts` - `pnpm test:browser:local browser_tests/tests/workspace/localWorkspaceSwitcher.spec.ts --project=chromium` - `pnpm typecheck` - `pnpm typecheck:browser` - `pnpm knip` - lint-staged: oxfmt, stylelint, oxlint, ESLint ## References - [QA findings](https://app.notion.com/p/3c36d73d365080b4a1b7ea008d323c69) - [FE-1584](https://linear.app/comfyorg/issue/FE-1584/add-workspace-switcher-to-localdesktop-credits-only-no-settings) --------- Co-authored-by: Amp <amp@ampcode.com>
🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1825 passed, 0 failed · 2 flaky📊 Browser Reports
📦 Bundle Size
⚡ Performance Report
✅ No regressions detected. All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-08-23T08:21:28.266Z",
"gitSha": "87aacbd58eb3557bab9f1de16b2e4bb66c9f9c95",
"branch": "backport-15601-to-core-1.51",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2016.3790000001427,
"styleRecalcs": 10,
"styleRecalcDurationMs": 5.974,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 440.905,
"heapDeltaBytes": 5053040,
"heapUsedBytes": 70560400,
"domNodes": 20,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 6.414999999999999,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-idle",
"durationMs": 2000.8680000000822,
"styleRecalcs": 10,
"styleRecalcDurationMs": 5.946999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 376.468,
"heapDeltaBytes": 5395692,
"heapUsedBytes": 70862996,
"domNodes": 20,
"jsHeapTotalBytes": 24117248,
"scriptDurationMs": 5.773999999999998,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1770.808999999872,
"styleRecalcs": 73,
"styleRecalcDurationMs": 29.192999999999998,
"layouts": 12,
"layoutDurationMs": 3.101,
"taskDurationMs": 686.0820000000001,
"heapDeltaBytes": -130072,
"heapUsedBytes": 65252192,
"domNodes": 55,
"jsHeapTotalBytes": 25432064,
"scriptDurationMs": 78.792,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1702.8620000000956,
"styleRecalcs": 73,
"styleRecalcDurationMs": 24.936000000000003,
"layouts": 12,
"layoutDurationMs": 2.465,
"taskDurationMs": 657.165,
"heapDeltaBytes": -18237104,
"heapUsedBytes": 47218556,
"domNodes": -278,
"jsHeapTotalBytes": 23433216,
"scriptDurationMs": 69.82900000000001,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1665.2259999998478,
"styleRecalcs": 29,
"styleRecalcDurationMs": 12.118,
"layouts": 6,
"layoutDurationMs": 0.539,
"taskDurationMs": 300.431,
"heapDeltaBytes": 8200836,
"heapUsedBytes": 73725608,
"domNodes": 77,
"jsHeapTotalBytes": 23592960,
"scriptDurationMs": 7.892000000000001,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1670.7839999999123,
"styleRecalcs": 32,
"styleRecalcDurationMs": 12.432,
"layouts": 6,
"layoutDurationMs": 0.5049999999999999,
"taskDurationMs": 310.771,
"heapDeltaBytes": 8222248,
"heapUsedBytes": 73859360,
"domNodes": 79,
"jsHeapTotalBytes": 24117248,
"scriptDurationMs": 8.509999999999998,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "dom-widget-clipping",
"durationMs": 522.2049999999854,
"styleRecalcs": 13,
"styleRecalcDurationMs": 5.8180000000000005,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 295.122,
"heapDeltaBytes": -11533612,
"heapUsedBytes": 53907652,
"domNodes": 22,
"jsHeapTotalBytes": 25690112,
"scriptDurationMs": 39.04600000000001,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 426.6539999998713,
"styleRecalcs": 11,
"styleRecalcDurationMs": 4.6339999999999995,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 266.207,
"heapDeltaBytes": -11437028,
"heapUsedBytes": 54041188,
"domNodes": 18,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 35.41,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "large-graph-idle",
"durationMs": 2013.3280000000013,
"styleRecalcs": 9,
"styleRecalcDurationMs": 5.138999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 502.16499999999996,
"heapDeltaBytes": 13039620,
"heapUsedBytes": 73190324,
"domNodes": -281,
"jsHeapTotalBytes": 3768320,
"scriptDurationMs": 11.794999999999996,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2007.7329999999165,
"styleRecalcs": 11,
"styleRecalcDurationMs": 6.083999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 504.7539999999999,
"heapDeltaBytes": 12620800,
"heapUsedBytes": 74688780,
"domNodes": -280,
"jsHeapTotalBytes": 4292608,
"scriptDurationMs": 10.793999999999999,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2084.5220000001063,
"styleRecalcs": 68,
"styleRecalcDurationMs": 8.597000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 890.3570000000001,
"heapDeltaBytes": 5915616,
"heapUsedBytes": 67284504,
"domNodes": -284,
"jsHeapTotalBytes": 5271552,
"scriptDurationMs": 226.462,
"eventListeners": -147,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-pan",
"durationMs": 2138.5580000001028,
"styleRecalcs": 68,
"styleRecalcDurationMs": 10.289,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 928.296,
"heapDeltaBytes": 9764952,
"heapUsedBytes": 70857532,
"domNodes": -284,
"jsHeapTotalBytes": 3960832,
"scriptDurationMs": 235.74399999999997,
"eventListeners": -147,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3068.905000000086,
"styleRecalcs": 65,
"styleRecalcDurationMs": 10.637,
"layouts": 60,
"layoutDurationMs": 6.22,
"taskDurationMs": 1014.943,
"heapDeltaBytes": 16496632,
"heapUsedBytes": 79253904,
"domNodes": 12,
"jsHeapTotalBytes": 4718592,
"scriptDurationMs": 266.567,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-zoom",
"durationMs": 3078.9199999999255,
"styleRecalcs": 66,
"styleRecalcDurationMs": 11.372000000000002,
"layouts": 60,
"layoutDurationMs": 6.130000000000001,
"taskDurationMs": 1016.127,
"heapDeltaBytes": 16545048,
"heapUsedBytes": 79273500,
"domNodes": 14,
"jsHeapTotalBytes": 5767168,
"scriptDurationMs": 273.181,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2000.985000000128,
"styleRecalcs": 8,
"styleRecalcDurationMs": 4.9239999999999995,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 504.86300000000006,
"heapDeltaBytes": 9743400,
"heapUsedBytes": 71239548,
"domNodes": -282,
"jsHeapTotalBytes": 2981888,
"scriptDurationMs": 12.053999999999998,
"eventListeners": -177,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2038.75499999981,
"styleRecalcs": 9,
"styleRecalcDurationMs": 5.293999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 505.252,
"heapDeltaBytes": 13459304,
"heapUsedBytes": 74031948,
"domNodes": -283,
"jsHeapTotalBytes": 2195456,
"scriptDurationMs": 10.607999999999995,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 520.5290000001241,
"styleRecalcs": 46,
"styleRecalcDurationMs": 6.644000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 299.38300000000004,
"heapDeltaBytes": -10050544,
"heapUsedBytes": 55534012,
"domNodes": 18,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 81.349,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 501.26000000000204,
"styleRecalcs": 47,
"styleRecalcDurationMs": 7.738,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 311.16700000000003,
"heapDeltaBytes": -11125904,
"heapUsedBytes": 54365940,
"domNodes": 20,
"jsHeapTotalBytes": 25952256,
"scriptDurationMs": 85.581,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "subgraph-idle",
"durationMs": 2005.0289999999222,
"styleRecalcs": 11,
"styleRecalcDurationMs": 6.194,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 379.38000000000005,
"heapDeltaBytes": 5594820,
"heapUsedBytes": 71088704,
"domNodes": 22,
"jsHeapTotalBytes": 23855104,
"scriptDurationMs": 5.9,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2006.2480000001415,
"styleRecalcs": 10,
"styleRecalcDurationMs": 6.538999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 375.36,
"heapDeltaBytes": 5546560,
"heapUsedBytes": 71104740,
"domNodes": 20,
"jsHeapTotalBytes": 24117248,
"scriptDurationMs": 5.543000000000001,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1712.474999999813,
"styleRecalcs": 77,
"styleRecalcDurationMs": 29.487,
"layouts": 16,
"layoutDurationMs": 3.7520000000000002,
"taskDurationMs": 625.9399999999999,
"heapDeltaBytes": -3608668,
"heapUsedBytes": 61915440,
"domNodes": 63,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 59.356,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66999999999998,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1678.7390000001778,
"styleRecalcs": 75,
"styleRecalcDurationMs": 27.033,
"layouts": 16,
"layoutDurationMs": 3.337,
"taskDurationMs": 571.768,
"heapDeltaBytes": -3787104,
"heapUsedBytes": 61798264,
"domNodes": 61,
"jsHeapTotalBytes": 24117248,
"scriptDurationMs": 57.74799999999999,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 932.213000000047,
"styleRecalcs": 19,
"styleRecalcDurationMs": 24.53799999999999,
"layouts": 14,
"layoutDurationMs": 8.494,
"taskDurationMs": 739.771,
"heapDeltaBytes": -6052176,
"heapUsedBytes": 79338980,
"domNodes": 13673,
"jsHeapTotalBytes": 9437184,
"scriptDurationMs": 12.443000000000003,
"eventListeners": 2373,
"totalBlockingTimeMs": 118,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8112.544000000071,
"styleRecalcs": 249,
"styleRecalcDurationMs": 24.096,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3106.3460000000005,
"heapDeltaBytes": 384860,
"heapUsedBytes": 60596184,
"domNodes": -281,
"jsHeapTotalBytes": 4485120,
"scriptDurationMs": 700.277,
"eventListeners": -163,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8120.644999999968,
"styleRecalcs": 249,
"styleRecalcDurationMs": 25.95,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3176.355,
"heapDeltaBytes": 13302272,
"heapUsedBytes": 73931828,
"domNodes": -281,
"jsHeapTotalBytes": 4222976,
"scriptDurationMs": 714.788,
"eventListeners": -133,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 12495.00399999988,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 11458.041,
"heapDeltaBytes": -25773852,
"heapUsedBytes": 172655980,
"domNodes": -8312,
"jsHeapTotalBytes": -6754304,
"scriptDurationMs": 82.08699999999999,
"eventListeners": -16391,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.220000000000073,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 12515.419000000065,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 11465.859,
"heapDeltaBytes": -31045084,
"heapUsedBytes": 166160116,
"domNodes": -8312,
"jsHeapTotalBytes": -12525568,
"scriptDurationMs": 83.13400000000001,
"eventListeners": -16393,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.22666666666664,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 15064.343000000008,
"styleRecalcs": 72,
"styleRecalcDurationMs": 12.822,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 14329.239999999998,
"heapDeltaBytes": -41563172,
"heapUsedBytes": 170676052,
"domNodes": -8312,
"jsHeapTotalBytes": -13901824,
"scriptDurationMs": 343.05800000000005,
"eventListeners": -16385,
"totalBlockingTimeMs": 54,
"frameDurationMs": 17.219999999999953,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 15321.736999999985,
"styleRecalcs": 82,
"styleRecalcDurationMs": 13.632000000000005,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 14605.640000000001,
"heapDeltaBytes": -27719388,
"heapUsedBytes": 169633448,
"domNodes": -8312,
"jsHeapTotalBytes": -14692352,
"scriptDurationMs": 358.817,
"eventListeners": -16387,
"totalBlockingTimeMs": 3,
"frameDurationMs": 16.66333333333326,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 426.8819999999778,
"styleRecalcs": 15,
"styleRecalcDurationMs": 16.25,
"layouts": 3,
"layoutDurationMs": 0.961,
"taskDurationMs": 84.00599999999999,
"heapDeltaBytes": 4966724,
"heapUsedBytes": 69489308,
"domNodes": 128,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 5.91,
"eventListeners": 97,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666682,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "workflow-execution",
"durationMs": 435.8669999999165,
"styleRecalcs": 13,
"styleRecalcDurationMs": 11.21,
"layouts": 2,
"layoutDurationMs": 0.3180000000000001,
"taskDurationMs": 78.70400000000001,
"heapDeltaBytes": 4930028,
"heapUsedBytes": 69527284,
"domNodes": 123,
"jsHeapTotalBytes": 4718592,
"scriptDurationMs": 5.516,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.700000000000273
}
]
} |
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## core/1.51 #15716 +/- ##
==========================================
Coverage 81.65% 81.65%
==========================================
Files 1884 1884
Lines 107107 107108 +1
Branches 33108 33109 +1
==========================================
+ Hits 87456 87457 +1
+ Misses 19318 19309 -9
- Partials 333 342 +9
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 7 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Backport of #15601 to
core/1.51Automatically created by backport workflow.