[backport cloud/1.48] fix(workspace): show subscribe prompt for ended subscriptions - #14510
Conversation
- Treat `subscription_status: ended` as terminal even when `is_active`
and paid-plan metadata lag behind.
- Show the subscribe prompt instead of a stale Standard plan.
- Keep cloud billing mocks internally consistent and add component and
end-to-end regression coverage.
The subscription panel required `ended` **and** `is_active=false`. When
the terminal status arrived first, stale active/plan data suppressed the
subscribe prompt.
```mermaid
flowchart LR
subgraph BEFORE[Before]
direction TB
B1[Billing state loads] --> B2{"ended AND is_active=false?"}
B2 -- Yes --> B3[Show subscribe prompt]
B2 -- "No: ended + stale active" --> B4[Show stale Standard plan]
end
subgraph AFTER[After]
direction TB
A1[Billing state loads] --> A2{"subscription_status = ended?"}
A2 -- Yes --> A3[Show subscribe prompt]
A2 -- No --> A4{"Active paid plan?"}
A4 -- Yes --> A5[Show current plan]
A4 -- No --> A3
end
```
- `SubscriptionPanelContentWorkspace.vue`: ended status now takes
precedence over stale paid-plan guards.
- `CloudWorkspaceMockHelper.ts`: `current_plan_slug` always has a
matching plan.
- Tests retain stale active/paid/team-plan state so the regression
specifically verifies ended-status precedence.
- Component tests: 42 passed
- Cloud Playwright regression: 1 passed
- App and browser typechecks
- Formatting, lint, commit hooks, and `knip`
🎭 Playwright: ✅ 1761 passed, 0 failed · 1 flaky📊 Browser Reports
🎨 Storybook: ✅ Built — View Storybook📦 Bundle Size
⚡ Performance Report
Absolute values
Raw data{
"timestamp": "2026-07-31T22:27:20.669Z",
"gitSha": "485270ce8fcec637c085639225f3cf6dbc75477d",
"branch": "backport-14504-to-cloud-1.48",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2151.341000000002,
"styleRecalcs": 9,
"styleRecalcDurationMs": 10.537,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 619.158,
"heapDeltaBytes": 3866636,
"heapUsedBytes": 71955032,
"domNodes": 18,
"jsHeapTotalBytes": 20578304,
"scriptDurationMs": 26.340999999999998,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-idle",
"durationMs": 2035.2169999999887,
"styleRecalcs": 9,
"styleRecalcDurationMs": 9.693000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 541.845,
"heapDeltaBytes": 4012224,
"heapUsedBytes": 72056900,
"domNodes": 18,
"jsHeapTotalBytes": 20316160,
"scriptDurationMs": 23.807000000000002,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1969.5820000000026,
"styleRecalcs": 76,
"styleRecalcDurationMs": 46.161,
"layouts": 12,
"layoutDurationMs": 4.082,
"taskDurationMs": 983.1199999999999,
"heapDeltaBytes": -14744192,
"heapUsedBytes": 53187940,
"domNodes": -271,
"jsHeapTotalBytes": 20705280,
"scriptDurationMs": 135.35,
"eventListeners": -146,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1883.570000000077,
"styleRecalcs": 76,
"styleRecalcDurationMs": 41.442,
"layouts": 12,
"layoutDurationMs": 3.6069999999999998,
"taskDurationMs": 976.699,
"heapDeltaBytes": -18522156,
"heapUsedBytes": 49365596,
"domNodes": -274,
"jsHeapTotalBytes": 20967424,
"scriptDurationMs": 135.541,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1753.9169999999444,
"styleRecalcs": 31,
"styleRecalcDurationMs": 20.200999999999997,
"layouts": 6,
"layoutDurationMs": 0.7309999999999999,
"taskDurationMs": 423.1579999999999,
"heapDeltaBytes": 6980328,
"heapUsedBytes": 74900760,
"domNodes": 78,
"jsHeapTotalBytes": 20316160,
"scriptDurationMs": 23.035,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1754.9920000000157,
"styleRecalcs": 32,
"styleRecalcDurationMs": 19.238,
"layouts": 6,
"layoutDurationMs": 0.7310000000000001,
"taskDurationMs": 448.9920000000001,
"heapDeltaBytes": 7134124,
"heapUsedBytes": 75066164,
"domNodes": 78,
"jsHeapTotalBytes": 20316160,
"scriptDurationMs": 26.828,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 620.2759999999898,
"styleRecalcs": 11,
"styleRecalcDurationMs": 7.949999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 409.1,
"heapDeltaBytes": -12539872,
"heapUsedBytes": 55364572,
"domNodes": 18,
"jsHeapTotalBytes": 21889024,
"scriptDurationMs": 62.183,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 646.0999999999331,
"styleRecalcs": 13,
"styleRecalcDurationMs": 8.565,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 405.265,
"heapDeltaBytes": -12164840,
"heapUsedBytes": 55859992,
"domNodes": 22,
"jsHeapTotalBytes": 21102592,
"scriptDurationMs": 61.297,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 2034.610999999984,
"styleRecalcs": 7,
"styleRecalcDurationMs": 7.421999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 763.2529999999999,
"heapDeltaBytes": 4763808,
"heapUsedBytes": 66203472,
"domNodes": -273,
"jsHeapTotalBytes": 4784128,
"scriptDurationMs": 130.23000000000002,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2056.4640000000054,
"styleRecalcs": 8,
"styleRecalcDurationMs": 8.858,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 815.191,
"heapDeltaBytes": 6810068,
"heapUsedBytes": 66242300,
"domNodes": -276,
"jsHeapTotalBytes": 5832704,
"scriptDurationMs": 140.53799999999998,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-pan",
"durationMs": 2250.9880000000067,
"styleRecalcs": 68,
"styleRecalcDurationMs": 13.994,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1374.641,
"heapDeltaBytes": -4711208,
"heapUsedBytes": 54983160,
"domNodes": -279,
"jsHeapTotalBytes": 5308416,
"scriptDurationMs": 457.38,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2263.6699999999337,
"styleRecalcs": 67,
"styleRecalcDurationMs": 13.305000000000005,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1386.51,
"heapDeltaBytes": 4888260,
"heapUsedBytes": 65104332,
"domNodes": -282,
"jsHeapTotalBytes": 4464640,
"scriptDurationMs": 465.944,
"eventListeners": -146,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3312.133000000017,
"styleRecalcs": 65,
"styleRecalcDurationMs": 15.665999999999999,
"layouts": 60,
"layoutDurationMs": 7.6290000000000004,
"taskDurationMs": 1623.352,
"heapDeltaBytes": 5256916,
"heapUsedBytes": 66764244,
"domNodes": -281,
"jsHeapTotalBytes": 7405568,
"scriptDurationMs": 573.7719999999999,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3364.325000000008,
"styleRecalcs": 65,
"styleRecalcDurationMs": 16.255000000000003,
"layouts": 60,
"layoutDurationMs": 7.868999999999999,
"taskDurationMs": 1615.939,
"heapDeltaBytes": 24616632,
"heapUsedBytes": 86094992,
"domNodes": 12,
"jsHeapTotalBytes": 8912896,
"scriptDurationMs": 596.193,
"eventListeners": 10,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2038.0349999999794,
"styleRecalcs": 8,
"styleRecalcDurationMs": 9.089,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 770.781,
"heapDeltaBytes": 6733480,
"heapUsedBytes": 67129248,
"domNodes": -277,
"jsHeapTotalBytes": 4259840,
"scriptDurationMs": 130.59199999999998,
"eventListeners": -146,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2041.6369999999233,
"styleRecalcs": 7,
"styleRecalcDurationMs": 7.303999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 828.9329999999999,
"heapDeltaBytes": 6131844,
"heapUsedBytes": 66899676,
"domNodes": -279,
"jsHeapTotalBytes": 4521984,
"scriptDurationMs": 142.559,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 595.3509999999937,
"styleRecalcs": 47,
"styleRecalcDurationMs": 11.523,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 408.177,
"heapDeltaBytes": -11682420,
"heapUsedBytes": 56259892,
"domNodes": 20,
"jsHeapTotalBytes": 21626880,
"scriptDurationMs": 121.55799999999998,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 668.788999999947,
"styleRecalcs": 46,
"styleRecalcDurationMs": 11.207,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 441.30300000000005,
"heapDeltaBytes": -12013300,
"heapUsedBytes": 55835076,
"domNodes": 18,
"jsHeapTotalBytes": 22151168,
"scriptDurationMs": 130.562,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-idle",
"durationMs": 2009.8310000000197,
"styleRecalcs": 9,
"styleRecalcDurationMs": 9.719,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 574.8109999999999,
"heapDeltaBytes": 3397564,
"heapUsedBytes": 71425380,
"domNodes": 18,
"jsHeapTotalBytes": 20840448,
"scriptDurationMs": 19.734,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2017.9030000000466,
"styleRecalcs": 10,
"styleRecalcDurationMs": 10.377999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 590.826,
"heapDeltaBytes": -21869864,
"heapUsedBytes": 46081212,
"domNodes": 20,
"jsHeapTotalBytes": 20180992,
"scriptDurationMs": 21.068,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1714.681999999982,
"styleRecalcs": 76,
"styleRecalcDurationMs": 39.493,
"layouts": 16,
"layoutDurationMs": 4.352,
"taskDurationMs": 819.198,
"heapDeltaBytes": -5507608,
"heapUsedBytes": 62668976,
"domNodes": 62,
"jsHeapTotalBytes": 21364736,
"scriptDurationMs": 99.544,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1736.7619999999988,
"styleRecalcs": 76,
"styleRecalcDurationMs": 38.811,
"layouts": 16,
"layoutDurationMs": 5.162,
"taskDurationMs": 884.6129999999999,
"heapDeltaBytes": -20726444,
"heapUsedBytes": 47189560,
"domNodes": -275,
"jsHeapTotalBytes": 21491712,
"scriptDurationMs": 103.187,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 1451.1759999999754,
"styleRecalcs": 18,
"styleRecalcDurationMs": 32.32800000000001,
"layouts": 14,
"layoutDurationMs": 13.579,
"taskDurationMs": 1052.606,
"heapDeltaBytes": 2059588,
"heapUsedBytes": 74542192,
"domNodes": 13673,
"jsHeapTotalBytes": 15204352,
"scriptDurationMs": 40.08700000000001,
"eventListeners": 2371,
"totalBlockingTimeMs": 158,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8602.043999999978,
"styleRecalcs": 249,
"styleRecalcDurationMs": 37.528000000000006,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4825.315,
"heapDeltaBytes": 9690432,
"heapUsedBytes": 69010328,
"domNodes": -276,
"jsHeapTotalBytes": 6795264,
"scriptDurationMs": 1473.1680000000001,
"eventListeners": -126,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8575.120000000083,
"styleRecalcs": 250,
"styleRecalcDurationMs": 39.861,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4913.101000000001,
"heapDeltaBytes": 9112988,
"heapUsedBytes": 67874012,
"domNodes": -275,
"jsHeapTotalBytes": 6270976,
"scriptDurationMs": 1516.202,
"eventListeners": -126,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 17643.191000000003,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17624.232,
"heapDeltaBytes": -40073192,
"heapUsedBytes": 166478396,
"domNodes": -8312,
"jsHeapTotalBytes": -11206656,
"scriptDurationMs": 573.927,
"eventListeners": -16389,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.780000000000047,
"p95FrameDurationMs": 16.80000000000291
},
{
"name": "vue-large-graph-idle",
"durationMs": 17612.919000000034,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17551.817,
"heapDeltaBytes": -39933872,
"heapUsedBytes": 166705680,
"domNodes": -8312,
"jsHeapTotalBytes": -13565952,
"scriptDurationMs": 598.936,
"eventListeners": -16389,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666763,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 21055.106999999964,
"styleRecalcs": 144,
"styleRecalcDurationMs": 17.91799999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21034.266000000003,
"heapDeltaBytes": -32266300,
"heapUsedBytes": 176741992,
"domNodes": -8312,
"jsHeapTotalBytes": -9723904,
"scriptDurationMs": 936.6719999999999,
"eventListeners": -16381,
"totalBlockingTimeMs": 303,
"frameDurationMs": 17.773333333333238,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-pan",
"durationMs": 21437.414999999986,
"styleRecalcs": 148,
"styleRecalcDurationMs": 20.930999999999976,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21381.862999999998,
"heapDeltaBytes": -41732160,
"heapUsedBytes": 158294672,
"domNodes": -8312,
"jsHeapTotalBytes": -15667200,
"scriptDurationMs": 985.4679999999998,
"eventListeners": -16379,
"totalBlockingTimeMs": 227,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 469.1960000000108,
"styleRecalcs": 19,
"styleRecalcDurationMs": 23.057999999999996,
"layouts": 3,
"layoutDurationMs": 1.3599999999999999,
"taskDurationMs": 135.951,
"heapDeltaBytes": -15853576,
"heapUsedBytes": 51061996,
"domNodes": 156,
"jsHeapTotalBytes": 7995392,
"scriptDurationMs": 12.054,
"eventListeners": 67,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 465.73000000000775,
"styleRecalcs": 14,
"styleRecalcDurationMs": 20.544999999999998,
"layouts": 3,
"layoutDurationMs": 0.6330000000000001,
"taskDurationMs": 121.37500000000001,
"heapDeltaBytes": -16019948,
"heapUsedBytes": 51450892,
"domNodes": 119,
"jsHeapTotalBytes": 7471104,
"scriptDurationMs": 10.686000000000002,
"eventListeners": 65,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
}
]
} |
|
Important Review skippedIgnore keyword(s) in the title. ⛔ Ignored keywords (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
📄 Knowledge reviewDosu skipped reviewing this PR because your organization has used its |
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## cloud/1.48 #14510 +/- ##
=============================================
Coverage ? 69.13%
=============================================
Files ? 1659
Lines ? 85653
Branches ? 22874
=============================================
Hits ? 59217
Misses ? 26326
Partials ? 110
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Summary
Backport of #14504 to
cloud/1.48.subscription_status: endedas terminal even when paid-plan metadata is stale.Validation
knippush hook