[backport cloud/1.47] fix(workspace): gate billing controls by role#13834
Conversation
## Summary Make Members eligibility follow the active billing plan instead of the personal/team workspace type. A personal workspace on a Team plan now gets the same Members experience as a team workspace on the same plan. ## Root cause The Members surface had three independent workspace-type gates: - `useTeamPlan` treated “team workspace + subscribed” as the Team-plan signal, so a personal workspace was always classified as not being on Team even when billing reported a Team plan. - `useMembersPanel` inherited the personal-workspace permission and layout defaults, which forced the single-user row, disabled Invite, and rendered the Team upgrade banner. - Member and pending-invite loading short-circuited for personal workspaces, so valid Team-plan members could not be fetched even if the UI gate was corrected. ## How this fixes it - Derive `hasTeamPlan`, active Team-plan, cancelled/lapsed, and loading states from billing plan identity plus subscription state. - Overlay Members permissions and table layout from the plan and workspace role. Team-plan owners can invite and manage members regardless of workspace type; personal plans keep the single-user experience. - Wait for billing initialization before deciding whether to fetch members/invites or show an upgrade state. - Remove the store-level personal-workspace short-circuits for member and invite APIs. - Keep workspace-container actions such as delete/leave governed by workspace type; only the Members entitlement moves to plan-based logic. ## Before / After ### Before A personal workspace with a Team plan was treated as a personal plan: Invite was disabled and the UI asked the user to upgrade to Team. <img width="1400" alt="Before: Personal Workspace on Team plan incorrectly shows disabled Invite and Upgrade to Team" src="https://github.com/user-attachments/assets/f0d7a99c-6d7b-4cac-b3c0-9d3c9266830f" /> ### After The same personal-workspace + Team-plan scenario loads the Team member list and enables owner member-management actions. <img width="1400" alt="After: Personal Workspace on Team plan shows member list, Invite, roles, and member actions" src="https://github.com/user-attachments/assets/7e2fbcd7-d8e3-4ae8-a9df-ad59974ecf52" /> ## Review Focus - Team-plan owners receive member management regardless of workspace type. - Personal plans remain single-user. - Loading, cancelled, and lapsed states do not briefly expose an incorrect upgrade or invite state. - Workspace delete/leave behavior remains workspace-type based. ## Validation - 168 focused Vitest tests passed. - `pnpm typecheck` passed. - `pnpm lint` passed. - `pnpm knip` passed. - Cloud Playwright: 7/7 tests passed in `memberRoleChange.spec.ts`, including personal workspace + Team plan regression coverage. - Pre-commit style, format, lint, and type checks passed.
Gate workspace billing mutations by the active role and scope creator-only protections to the Personal/default workspace, matching the backend policy. | Action | Personal/default workspace | Additional workspace | | --- | --- | --- | | Billing lifecycle (subscribe, change plan, cancel, reactivate, top up) | Any owner | Any owner | | Team to Personal downgrade | Original creator only | Original creator only | | Leave | Eligible collaborators; original creator cannot leave | Any member or owner, including the creator | | Demote or remove the creator | Not allowed | Allowed for another owner, subject to backend last-owner validation | | Delete | Not available | Any owner after the active-subscription lock clears | Members remain read-only for billing mutations. Members access continues to follow the active Team plan rather than workspace type. - Protect the Personal/default workspace creator from Leave, demotion, and removal while allowing entitled collaborators to leave. - Treat an additional workspace creator as an ordinary owner for Leave and member management. - Allow any owner to manage the billing lifecycle; keep Team-to-Personal downgrade original-creator-only. - Recheck Leave and Delete permissions when captured menu commands execute. - Hide Delete for Personal workspaces and members, and keep it disabled while an additional workspace has an active subscription. - Incorporate the workspace-type policy from #13831 without replacing this PR's billing lifecycle guards. #13810 is merged. - Personal creator protection versus additional workspace creator behavior. - Any-owner billing lifecycle access versus original-creator-only downgrade. - Stale menu-command permission and subscription-lock checks. - 201 focused unit tests passed. - 7 cloud Playwright tests passed. - `pnpm typecheck`, `pnpm lint`, `pnpm knip`, and `pnpm format:check` passed. Lint reports only existing repository warnings. Captured from the Vite cloud app with mocked workspace API state. | Personal/default workspace creator | Additional workspace creator | | --- | --- | | <img width="720" alt="Personal workspace creator menu with billing actions but no Leave or Delete action" src="https://github.com/user-attachments/assets/1fa2e62f-9b93-4d8c-b9bb-d02a2a671531" /> | <img width="720" alt="Additional workspace creator menu with Leave and subscription-locked Delete actions" src="https://github.com/user-attachments/assets/3cb7255d-2e41-44d4-a7f8-feddcb90644d" /> | The Personal/default creator has no Leave or Delete action. An additional workspace creator can leave; Delete remains disabled until the active-subscription lock clears. <img width="720" alt="Another owner can change the additional workspace creator role or remove the creator" src="https://github.com/user-attachments/assets/8fb7b5a5-63b4-4124-a99a-85121f8fa374" /> Another owner can change or remove the creator, subject to backend last-owner validation. (cherry picked from commit 51884bc)
|
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:
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
🎭 Playwright: ✅ 1690 passed, 0 failed · 5 flaky📊 Browser Reports
🎨 Storybook: ✅ Built — View Storybook📦 Bundle Size
⚡ Performance Report
Absolute values
Raw data{
"timestamp": "2026-07-19T22:17:19.834Z",
"gitSha": "aeebbbeeb866f50f6b475484132941213b8e5324",
"branch": "backport-13812-to-cloud-1.47",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2006.2350000000038,
"styleRecalcs": 9,
"styleRecalcDurationMs": 7.969,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 391.44199999999995,
"heapDeltaBytes": -6356020,
"heapUsedBytes": 45788536,
"domNodes": -286,
"jsHeapTotalBytes": 17690624,
"scriptDurationMs": 15.305000000000001,
"eventListeners": -199,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-idle",
"durationMs": 2062.498000000005,
"styleRecalcs": 11,
"styleRecalcDurationMs": 9.756,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 401.71599999999995,
"heapDeltaBytes": -7363840,
"heapUsedBytes": 62489924,
"domNodes": -268,
"jsHeapTotalBytes": 19546112,
"scriptDurationMs": 14.799,
"eventListeners": -199,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1989.4269999999779,
"styleRecalcs": 74,
"styleRecalcDurationMs": 41.693,
"layouts": 12,
"layoutDurationMs": 3.6530000000000005,
"taskDurationMs": 913.91,
"heapDeltaBytes": 17883452,
"heapUsedBytes": 70791172,
"domNodes": -282,
"jsHeapTotalBytes": 16117760,
"scriptDurationMs": 127.356,
"eventListeners": -199,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1788.6550000000625,
"styleRecalcs": 72,
"styleRecalcDurationMs": 33.312000000000005,
"layouts": 12,
"layoutDurationMs": 3.4850000000000003,
"taskDurationMs": 748.627,
"heapDeltaBytes": -4006696,
"heapUsedBytes": 47834520,
"domNodes": -265,
"jsHeapTotalBytes": 17428480,
"scriptDurationMs": 113.77800000000002,
"eventListeners": -199,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1774.10900000001,
"styleRecalcs": 32,
"styleRecalcDurationMs": 19.967000000000002,
"layouts": 6,
"layoutDurationMs": 0.768,
"taskDurationMs": 376.016,
"heapDeltaBytes": -3695812,
"heapUsedBytes": 66313368,
"domNodes": -222,
"jsHeapTotalBytes": 12206080,
"scriptDurationMs": 21.496,
"eventListeners": -184,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1738.9760000000933,
"styleRecalcs": 33,
"styleRecalcDurationMs": 16.354,
"layouts": 6,
"layoutDurationMs": 0.6079999999999998,
"taskDurationMs": 325.141,
"heapDeltaBytes": 292696,
"heapUsedBytes": 52720860,
"domNodes": -235,
"jsHeapTotalBytes": 8253440,
"scriptDurationMs": 17.241999999999997,
"eventListeners": -186,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "dom-widget-clipping",
"durationMs": 602.328,
"styleRecalcs": 13,
"styleRecalcDurationMs": 9.538,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 386.55500000000006,
"heapDeltaBytes": -22283632,
"heapUsedBytes": 47513012,
"domNodes": -269,
"jsHeapTotalBytes": 6438912,
"scriptDurationMs": 56.059,
"eventListeners": -203,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 563.4800000000268,
"styleRecalcs": 12,
"styleRecalcDurationMs": 8.532,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 338.638,
"heapDeltaBytes": 7272616,
"heapUsedBytes": 66490712,
"domNodes": 20,
"jsHeapTotalBytes": 19136512,
"scriptDurationMs": 56.501000000000005,
"eventListeners": 0,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 2043.1240000000344,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.020999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 529.9100000000001,
"heapDeltaBytes": -1837224,
"heapUsedBytes": 59252964,
"domNodes": -268,
"jsHeapTotalBytes": -1093632,
"scriptDurationMs": 92.54600000000002,
"eventListeners": -199,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-idle",
"durationMs": 2038.628000000017,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.223999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 512.0469999999999,
"heapDeltaBytes": -25320316,
"heapUsedBytes": 59974788,
"domNodes": -259,
"jsHeapTotalBytes": 1122304,
"scriptDurationMs": 88.61,
"eventListeners": -199,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2130.258000000026,
"styleRecalcs": 69,
"styleRecalcDurationMs": 16.976000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1070.435,
"heapDeltaBytes": 19557540,
"heapUsedBytes": 81712352,
"domNodes": -271,
"jsHeapTotalBytes": -364544,
"scriptDurationMs": 388.77,
"eventListeners": -197,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "large-graph-pan",
"durationMs": 2105.3060000000414,
"styleRecalcs": 69,
"styleRecalcDurationMs": 21.436,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1045.772,
"heapDeltaBytes": 17814364,
"heapUsedBytes": 79718844,
"domNodes": -272,
"jsHeapTotalBytes": 684032,
"scriptDurationMs": 374.869,
"eventListeners": -197,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3080.573999999956,
"styleRecalcs": 62,
"styleRecalcDurationMs": 15.219999999999997,
"layouts": 60,
"layoutDurationMs": 6.962999999999999,
"taskDurationMs": 1265.1979999999999,
"heapDeltaBytes": 12495424,
"heapUsedBytes": 67078856,
"domNodes": 6,
"jsHeapTotalBytes": 0,
"scriptDurationMs": 478.50800000000004,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-zoom",
"durationMs": 3042.5689999999577,
"styleRecalcs": 63,
"styleRecalcDurationMs": 15.272,
"layouts": 60,
"layoutDurationMs": 6.781000000000001,
"taskDurationMs": 1202.757,
"heapDeltaBytes": 14311024,
"heapUsedBytes": 68807808,
"domNodes": 8,
"jsHeapTotalBytes": 0,
"scriptDurationMs": 461.41099999999994,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2034.7120000000132,
"styleRecalcs": 7,
"styleRecalcDurationMs": 6.752999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 553.701,
"heapDeltaBytes": -3644796,
"heapUsedBytes": 59623680,
"domNodes": -272,
"jsHeapTotalBytes": -1617920,
"scriptDurationMs": 98.881,
"eventListeners": -197,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2025.7530000000088,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.224999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 512.478,
"heapDeltaBytes": -4519144,
"heapUsedBytes": 58590936,
"domNodes": -269,
"jsHeapTotalBytes": -1880064,
"scriptDurationMs": 84.862,
"eventListeners": -197,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 621.5540000000033,
"styleRecalcs": 47,
"styleRecalcDurationMs": 11.972999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 434.58799999999997,
"heapDeltaBytes": 8032252,
"heapUsedBytes": 60540460,
"domNodes": -285,
"jsHeapTotalBytes": 10350592,
"scriptDurationMs": 125.67899999999999,
"eventListeners": -197,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 598.6870000000408,
"styleRecalcs": 46,
"styleRecalcDurationMs": 10.108,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 399.838,
"heapDeltaBytes": 6570924,
"heapUsedBytes": 59011072,
"domNodes": -285,
"jsHeapTotalBytes": 10874880,
"scriptDurationMs": 123.56500000000001,
"eventListeners": -197,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66666666666665,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2009.346999999991,
"styleRecalcs": 11,
"styleRecalcDurationMs": 9.933000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 380.739,
"heapDeltaBytes": -3479716,
"heapUsedBytes": 49052532,
"domNodes": -285,
"jsHeapTotalBytes": 16904192,
"scriptDurationMs": 14.033,
"eventListeners": -199,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 1991.5500000000748,
"styleRecalcs": 9,
"styleRecalcDurationMs": 7.785,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 343.95300000000003,
"heapDeltaBytes": -2136944,
"heapUsedBytes": 60919996,
"domNodes": 18,
"jsHeapTotalBytes": 25186304,
"scriptDurationMs": 13.215000000000002,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1693.4640000000059,
"styleRecalcs": 75,
"styleRecalcDurationMs": 37.43,
"layouts": 16,
"layoutDurationMs": 4.464999999999999,
"taskDurationMs": 663.745,
"heapDeltaBytes": 18927116,
"heapUsedBytes": 75101888,
"domNodes": 60,
"jsHeapTotalBytes": 18874368,
"scriptDurationMs": 92.497,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66999999999998,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1763.1329999999252,
"styleRecalcs": 77,
"styleRecalcDurationMs": 41.148,
"layouts": 16,
"layoutDurationMs": 4.507000000000001,
"taskDurationMs": 734.976,
"heapDeltaBytes": -16648180,
"heapUsedBytes": 53370708,
"domNodes": -230,
"jsHeapTotalBytes": 20070400,
"scriptDurationMs": 94.426,
"eventListeners": -199,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-transition-enter",
"durationMs": 982.0160000000442,
"styleRecalcs": 20,
"styleRecalcDurationMs": 32.41799999999999,
"layouts": 16,
"layoutDurationMs": 16.126,
"taskDurationMs": 761.0489999999999,
"heapDeltaBytes": 30066356,
"heapUsedBytes": 102518844,
"domNodes": 13673,
"jsHeapTotalBytes": 16515072,
"scriptDurationMs": 27.986000000000004,
"eventListeners": 2533,
"totalBlockingTimeMs": 163,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 8175.506999999981,
"styleRecalcs": 251,
"styleRecalcDurationMs": 56.092,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3904.5270000000005,
"heapDeltaBytes": -1315940,
"heapUsedBytes": 71247684,
"domNodes": 20,
"jsHeapTotalBytes": 16048128,
"scriptDurationMs": 1303.833,
"eventListeners": 20,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.80000000000109
},
{
"name": "viewport-pan-sweep",
"durationMs": 8142.606999999998,
"styleRecalcs": 251,
"styleRecalcDurationMs": 51.90399999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3918.36,
"heapDeltaBytes": 8949460,
"heapUsedBytes": 77180332,
"domNodes": -268,
"jsHeapTotalBytes": 7794688,
"scriptDurationMs": 1429.294,
"eventListeners": -183,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 12832.358999999997,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 12811.750999999997,
"heapDeltaBytes": -14269964,
"heapUsedBytes": 186567136,
"domNodes": -3302,
"jsHeapTotalBytes": 21204992,
"scriptDurationMs": 535.461,
"eventListeners": -16376,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.77333333333336,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 12056.70299999997,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 12041.005000000001,
"heapDeltaBytes": -41054440,
"heapUsedBytes": 177917520,
"domNodes": -8314,
"jsHeapTotalBytes": 26804224,
"scriptDurationMs": 535.971,
"eventListeners": -16370,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.223333333333358,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 15340.936999999996,
"styleRecalcs": 76,
"styleRecalcDurationMs": 16.966000000000037,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 15316.447,
"heapDeltaBytes": -46310356,
"heapUsedBytes": 169082052,
"domNodes": -3300,
"jsHeapTotalBytes": -552960,
"scriptDurationMs": 850.371,
"eventListeners": -16375,
"totalBlockingTimeMs": 7,
"frameDurationMs": 17.220000000000073,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 15157.118999999966,
"styleRecalcs": 73,
"styleRecalcDurationMs": 17.295000000000005,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 15120.686,
"heapDeltaBytes": -35493868,
"heapUsedBytes": 168256084,
"domNodes": -3300,
"jsHeapTotalBytes": 8884224,
"scriptDurationMs": 847.6239999999999,
"eventListeners": -16374,
"totalBlockingTimeMs": 3,
"frameDurationMs": 17.223333333333358,
"p95FrameDurationMs": 16.80000000000291
},
{
"name": "workflow-execution",
"durationMs": 443.672000000106,
"styleRecalcs": 11,
"styleRecalcDurationMs": 16.519,
"layouts": 2,
"layoutDurationMs": 0.41200000000000003,
"taskDurationMs": 138.122,
"heapDeltaBytes": -6763176,
"heapUsedBytes": 45334576,
"domNodes": -263,
"jsHeapTotalBytes": 126976,
"scriptDurationMs": 8.286999999999999,
"eventListeners": -175,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "workflow-execution",
"durationMs": 518.8400000000684,
"styleRecalcs": 12,
"styleRecalcDurationMs": 23.897000000000002,
"layouts": 3,
"layoutDurationMs": 0.5799999999999998,
"taskDurationMs": 163.729,
"heapDeltaBytes": -3611152,
"heapUsedBytes": 49103836,
"domNodes": -156,
"jsHeapTotalBytes": 651264,
"scriptDurationMs": 12.931999999999999,
"eventListeners": -132,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
}
]
} |
🎨 Storybook: 🚧 Building... |
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## cloud/1.47 #13834 +/- ##
=============================================
Coverage ? 78.30%
=============================================
Files ? 1662
Lines ? 93231
Branches ? 32313
=============================================
Hits ? 73006
Misses ? 19616
Partials ? 609
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
deepme987
left a comment
There was a problem hiding this comment.
assuming these were already reviewed, blind approving
Summary
Backports #13812 to
cloud/1.47after the automatic cherry-pick conflicted. This branch is stacked on the current #13814 head.Changes
Review Focus
consolidated_billing_enabledfor Personal billing routing while leavingbilling_control_enabledindependent.BillingStatusBannerstory/test and Storybook workspace mock deleted because their runtime surface is absent on this branch.Validation
memberRoleChange.spec.ts: 7 passed.Screenshots