[backport cloud/1.46] feat(billing): role-aware run-lock for cancelled/inactive team plans (FE-978)#13006
[backport cloud/1.46] feat(billing): role-aware run-lock for cancelled/inactive team plans (FE-978)#13006comfy-pr-bot wants to merge 1 commit into
Conversation
…(FE-978) (#12786) ## Summary Cancelled / inactive team plans keep members but lock runs; the run button and the subscription-required dialog are now role-aware — owners are routed to the pricing/subscribe flow, members (who cannot subscribe) see "contact your workspace owner to resubscribe". ## Changes - **What**: `SubscribeToRun.vue` becomes a role-aware locked run button (owner → "Subscribe to Run"; member → neutral locked "Run" + contact-owner tooltip; both open the subscription dialog). `SubscriptionRequiredDialogContentWorkspace.vue` branches on role (member → read-only contact-owner panel, no pricing/subscribe affordance; owner → existing pricing/preview; member view suppressed for `out_of_credits` so the active-but-low-credits path is unchanged). `subscription.inactive.*` i18n keys. - **Breaking**: none. ## Review Focus - Role source = `useWorkspaceUI().permissions.value.canManageSubscription` (owner / personal = true, member = false) — the same accessor `SubscriptionPanelContentWorkspace.vue` uses. - **No BE work**: the run-gate already exists server-side (`InactiveSubscriptionError`; `is_active` checked before funds). The lock is gated on `is_active`, the same field the orchestrator uses, so FE/BE stay consistent; leftover-credits-while-inactive remains blocked by design. - Complements #12785 (FE-878 precondition→modal routing); disjoint file sets. Design: DES-197, Figma 3253-18670 / 3253-18671 / 3246-13962. - Tests: `SubscribeToRun` (4) / `CloudRunButtonWrapper` (3) / `SubscriptionRequiredDialogContentWorkspace` role cases — member sees contact-owner (no subscribe), owner sees pricing, run locks on `!is_active` and unlocks when active (22 total); full `test:unit` green. Fixes FE-978
Codecov Report❌ Patch coverage is
@@ Coverage Diff @@
## cloud/1.46 #13006 +/- ##
=============================================
Coverage ? 61.88%
=============================================
Files ? 1456
Lines ? 75297
Branches ? 21250
=============================================
Hits ? 46599
Misses ? 28350
Partials ? 348
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
📦 Bundle Size
⚡ Performance Report
Absolute values
Raw data{
"timestamp": "2026-06-19T13:40:46.985Z",
"gitSha": "72b1ee4fbddd4d05762ca8c2c3b91388c85a5ebc",
"branch": "backport-12786-to-cloud-1.46",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2044.8089999999866,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.620000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 419.14000000000004,
"heapDeltaBytes": -2426216,
"heapUsedBytes": 56273312,
"domNodes": 20,
"jsHeapTotalBytes": 26214400,
"scriptDurationMs": 23.186999999999998,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-idle",
"durationMs": 2011.3199999999551,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.737000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 380.76300000000003,
"heapDeltaBytes": -2454172,
"heapUsedBytes": 56292276,
"domNodes": 16,
"jsHeapTotalBytes": 26476544,
"scriptDurationMs": 17.842999999999996,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1908.5680000000025,
"styleRecalcs": 77,
"styleRecalcDurationMs": 42.885999999999996,
"layouts": 12,
"layoutDurationMs": 5.666,
"taskDurationMs": 855.178,
"heapDeltaBytes": -13776712,
"heapUsedBytes": 55473004,
"domNodes": -256,
"jsHeapTotalBytes": 19591168,
"scriptDurationMs": 119.01100000000001,
"eventListeners": -197,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1800.2839999999196,
"styleRecalcs": 73,
"styleRecalcDurationMs": 35.41,
"layouts": 12,
"layoutDurationMs": 3.6799999999999997,
"taskDurationMs": 752.327,
"heapDeltaBytes": -7537728,
"heapUsedBytes": 51153604,
"domNodes": 55,
"jsHeapTotalBytes": 25690112,
"scriptDurationMs": 116.24,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1732.2320000000104,
"styleRecalcs": 29,
"styleRecalcDurationMs": 19.437,
"layouts": 6,
"layoutDurationMs": 0.6589999999999998,
"taskDurationMs": 297.76399999999995,
"heapDeltaBytes": 23780480,
"heapUsedBytes": 73100728,
"domNodes": 78,
"jsHeapTotalBytes": 10747904,
"scriptDurationMs": 22.482,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1721.936000000028,
"styleRecalcs": 32,
"styleRecalcDurationMs": 15.638,
"layouts": 6,
"layoutDurationMs": 0.544,
"taskDurationMs": 312.502,
"heapDeltaBytes": 2240988,
"heapUsedBytes": 60537168,
"domNodes": 78,
"jsHeapTotalBytes": 25690112,
"scriptDurationMs": 25.247,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 561.5040000000135,
"styleRecalcs": 12,
"styleRecalcDurationMs": 7.6800000000000015,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 341.63699999999994,
"heapDeltaBytes": 7344260,
"heapUsedBytes": 65722824,
"domNodes": 20,
"jsHeapTotalBytes": 19136512,
"scriptDurationMs": 60.611000000000004,
"eventListeners": 0,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "dom-widget-clipping",
"durationMs": 564.9190000000317,
"styleRecalcs": 11,
"styleRecalcDurationMs": 7.62,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 344.302,
"heapDeltaBytes": 7428736,
"heapUsedBytes": 66093908,
"domNodes": 18,
"jsHeapTotalBytes": 18874368,
"scriptDurationMs": 54.918,
"eventListeners": 0,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2004.6330000000125,
"styleRecalcs": 10,
"styleRecalcDurationMs": 7.5600000000000005,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 506.3070000000001,
"heapDeltaBytes": -12618000,
"heapUsedBytes": 59722504,
"domNodes": 20,
"jsHeapTotalBytes": 12464128,
"scriptDurationMs": 82.163,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 2005.1799999999957,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.296,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 559.539,
"heapDeltaBytes": -8446636,
"heapUsedBytes": 61441068,
"domNodes": 20,
"jsHeapTotalBytes": 11677696,
"scriptDurationMs": 100.293,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66999999999998,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2110.2940000000103,
"styleRecalcs": 69,
"styleRecalcDurationMs": 19.166999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1025.5069999999998,
"heapDeltaBytes": 11398360,
"heapUsedBytes": 83738328,
"domNodes": 18,
"jsHeapTotalBytes": 12640256,
"scriptDurationMs": 359.23199999999997,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2085.8690000000024,
"styleRecalcs": 69,
"styleRecalcDurationMs": 19.895999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1004.4869999999999,
"heapDeltaBytes": 9957308,
"heapUsedBytes": 82173928,
"domNodes": 18,
"jsHeapTotalBytes": 12640256,
"scriptDurationMs": 357.13500000000005,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3080.603999999994,
"styleRecalcs": 65,
"styleRecalcDurationMs": 19.641000000000002,
"layouts": 60,
"layoutDurationMs": 8.393999999999998,
"taskDurationMs": 1330.048,
"heapDeltaBytes": -4660600,
"heapUsedBytes": 69609348,
"domNodes": 14,
"jsHeapTotalBytes": 11415552,
"scriptDurationMs": 508.20500000000004,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3130.019999999945,
"styleRecalcs": 65,
"styleRecalcDurationMs": 20.345,
"layouts": 60,
"layoutDurationMs": 8.398000000000001,
"taskDurationMs": 1271.4789999999998,
"heapDeltaBytes": -5665688,
"heapUsedBytes": 68421108,
"domNodes": 14,
"jsHeapTotalBytes": 10366976,
"scriptDurationMs": 473.62100000000004,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2026.3290000000325,
"styleRecalcs": 10,
"styleRecalcDurationMs": 7.498999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 491.68100000000004,
"heapDeltaBytes": -9345116,
"heapUsedBytes": 63582332,
"domNodes": 20,
"jsHeapTotalBytes": 8269824,
"scriptDurationMs": 75.331,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2010.1560000000518,
"styleRecalcs": 9,
"styleRecalcDurationMs": 6.709999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 503.49700000000007,
"heapDeltaBytes": -9471124,
"heapUsedBytes": 63866780,
"domNodes": 18,
"jsHeapTotalBytes": 8269824,
"scriptDurationMs": 87.45899999999999,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 558.7179999999989,
"styleRecalcs": 47,
"styleRecalcDurationMs": 10.904,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 345.396,
"heapDeltaBytes": 5284408,
"heapUsedBytes": 58842516,
"domNodes": 20,
"jsHeapTotalBytes": 11010048,
"scriptDurationMs": 125.40100000000001,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 564.2829999999321,
"styleRecalcs": 48,
"styleRecalcDurationMs": 11.777,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 360.50800000000004,
"heapDeltaBytes": 7726148,
"heapUsedBytes": 66372988,
"domNodes": 22,
"jsHeapTotalBytes": 19136512,
"scriptDurationMs": 122.49799999999999,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2023.8190000000031,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.672,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 360.694,
"heapDeltaBytes": 4288228,
"heapUsedBytes": 72180532,
"domNodes": 20,
"jsHeapTotalBytes": 21495808,
"scriptDurationMs": 19.264,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2006.027999999901,
"styleRecalcs": 11,
"styleRecalcDurationMs": 10.057,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 374.47799999999995,
"heapDeltaBytes": 3437364,
"heapUsedBytes": 66751232,
"domNodes": 22,
"jsHeapTotalBytes": 14942208,
"scriptDurationMs": 18.861,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1691.0780000000045,
"styleRecalcs": 76,
"styleRecalcDurationMs": 35.684999999999995,
"layouts": 16,
"layoutDurationMs": 4.276999999999999,
"taskDurationMs": 649.329,
"heapDeltaBytes": -10667892,
"heapUsedBytes": 47961364,
"domNodes": 62,
"jsHeapTotalBytes": 26214400,
"scriptDurationMs": 90.52000000000001,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1698.851999999988,
"styleRecalcs": 75,
"styleRecalcDurationMs": 38.979,
"layouts": 16,
"layoutDurationMs": 4.149,
"taskDurationMs": 685.848,
"heapDeltaBytes": -10817868,
"heapUsedBytes": 47939880,
"domNodes": 63,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 93.139,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-transition-enter",
"durationMs": 1067.4849999999765,
"styleRecalcs": 15,
"styleRecalcDurationMs": 28.60599999999999,
"layouts": 4,
"layoutDurationMs": 12.763,
"taskDurationMs": 777.835,
"heapDeltaBytes": 4586940,
"heapUsedBytes": 82632616,
"domNodes": 13833,
"jsHeapTotalBytes": 17563648,
"scriptDurationMs": 32.096,
"eventListeners": 2529,
"totalBlockingTimeMs": 144,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "viewport-pan-sweep",
"durationMs": 8115.385000000004,
"styleRecalcs": 251,
"styleRecalcDurationMs": 59.167,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3520.234,
"heapDeltaBytes": -2711896,
"heapUsedBytes": 67583980,
"domNodes": 22,
"jsHeapTotalBytes": 17883136,
"scriptDurationMs": 1152.6619999999998,
"eventListeners": 20,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8166.738000000009,
"styleRecalcs": 251,
"styleRecalcDurationMs": 59.824000000000005,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3895.215,
"heapDeltaBytes": 1177268,
"heapUsedBytes": 72468368,
"domNodes": 20,
"jsHeapTotalBytes": 21815296,
"scriptDurationMs": 1354.5720000000001,
"eventListeners": 20,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 13720.07199999996,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 13703.969999999998,
"heapDeltaBytes": -22898836,
"heapUsedBytes": 169988000,
"domNodes": -3310,
"jsHeapTotalBytes": 20680704,
"scriptDurationMs": 544.4180000000001,
"eventListeners": -16469,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.223333333333358,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 13443.997000000081,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 13430.068000000003,
"heapDeltaBytes": -33175500,
"heapUsedBytes": 188087056,
"domNodes": -8334,
"jsHeapTotalBytes": 28114944,
"scriptDurationMs": 600.298,
"eventListeners": -16464,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.220000000000073,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-pan",
"durationMs": 15629.798999999992,
"styleRecalcs": 80,
"styleRecalcDurationMs": 21.339,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 15612.795,
"heapDeltaBytes": -72486368,
"heapUsedBytes": 156009280,
"domNodes": -8329,
"jsHeapTotalBytes": 15003648,
"scriptDurationMs": 889.6999999999999,
"eventListeners": -16460,
"totalBlockingTimeMs": 3,
"frameDurationMs": 18.333333333333332,
"p95FrameDurationMs": 33.29999999999927
},
{
"name": "vue-large-graph-pan",
"durationMs": 16021.73700000003,
"styleRecalcs": 82,
"styleRecalcDurationMs": 21.321999999999953,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 16001.250000000002,
"heapDeltaBytes": -25507412,
"heapUsedBytes": 170323020,
"domNodes": -3308,
"jsHeapTotalBytes": 20418560,
"scriptDurationMs": 891.3579999999998,
"eventListeners": -16472,
"totalBlockingTimeMs": 7,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 463.7989999999945,
"styleRecalcs": 18,
"styleRecalcDurationMs": 24.713,
"layouts": 6,
"layoutDurationMs": 1.7599999999999998,
"taskDurationMs": 127.59899999999999,
"heapDeltaBytes": 5540020,
"heapUsedBytes": 65239220,
"domNodes": 168,
"jsHeapTotalBytes": 3145728,
"scriptDurationMs": 22.310000000000002,
"eventListeners": 69,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.799999999999727
},
{
"name": "workflow-execution",
"durationMs": 463.43000000001666,
"styleRecalcs": 16,
"styleRecalcDurationMs": 22.563,
"layouts": 5,
"layoutDurationMs": 1.3299999999999998,
"taskDurationMs": 119.47300000000001,
"heapDeltaBytes": 5198220,
"heapUsedBytes": 64950776,
"domNodes": 157,
"jsHeapTotalBytes": 2883584,
"scriptDurationMs": 18.348,
"eventListeners": 69,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
}
]
} |
🎭 Playwright: ✅ 1671 passed, 0 failed · 1 flaky📊 Browser Reports
|
Backport of #12786 to
cloud/1.46Automatically created by backport workflow.