Skip to content

[backport cloud/1.47] fix(workspace): derive Members access from Team plan#13814

Open
comfy-pr-bot wants to merge 2 commits into
cloud/1.47from
backport-13810-to-cloud-1.47
Open

[backport cloud/1.47] fix(workspace): derive Members access from Team plan#13814
comfy-pr-bot wants to merge 2 commits into
cloud/1.47from
backport-13810-to-cloud-1.47

Conversation

@comfy-pr-bot

Copy link
Copy Markdown
Member

Backport of #13810 to cloud/1.47

Automatically created by backport workflow.

## 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.
@comfy-pr-bot comfy-pr-bot added the backport Backporting a PR onto a release candidate label Jul 19, 2026
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 19, 2026
@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 07/19/2026, 04:02:37 AM UTC

Links

📦 Bundle Size

⏳ Size data collection in progress…

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.3 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 51.2 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 55.5 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 63.3 MB heap
large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 59.4 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 79.3 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.8 MB heap
minimap-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 56.9 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 47.0 MB heap
subgraph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 47.2 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 71.4 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 143ms TBT · 93.4 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 62.4 MB heap
vue-large-graph-idle: · 58.1 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 161.4 MB heap
vue-large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 21ms TBT · 164.3 MB heap
workflow-execution: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 49.2 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 417ms
canvas-idle: script duration 20ms
canvas-idle: TBT 0ms
canvas-idle: heap used 53.3 MB
canvas-idle: DOM nodes -127
canvas-idle: event listeners -97
canvas-mouse-sweep: avg frame time 17ms
canvas-mouse-sweep: p95 frame time 17ms
canvas-mouse-sweep: layout duration 4ms
canvas-mouse-sweep: style recalc duration 41ms
canvas-mouse-sweep: layout count 12
canvas-mouse-sweep: style recalc count 76
canvas-mouse-sweep: task duration 829ms
canvas-mouse-sweep: script duration 114ms
canvas-mouse-sweep: TBT 0ms
canvas-mouse-sweep: heap used 51.2 MB
canvas-mouse-sweep: DOM nodes -248
canvas-mouse-sweep: event listeners -199
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 20ms
canvas-zoom-sweep: layout count 6
canvas-zoom-sweep: style recalc count 32
canvas-zoom-sweep: task duration 375ms
canvas-zoom-sweep: script duration 22ms
canvas-zoom-sweep: TBT 0ms
canvas-zoom-sweep: heap used 55.5 MB
canvas-zoom-sweep: DOM nodes -228
canvas-zoom-sweep: event listeners -184
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 338ms
dom-widget-clipping: script duration 55ms
dom-widget-clipping: TBT 0ms
dom-widget-clipping: heap used 63.3 MB
dom-widget-clipping: DOM nodes 18
dom-widget-clipping: event listeners 0
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 10
large-graph-idle: task duration 531ms
large-graph-idle: script duration 87ms
large-graph-idle: TBT 0ms
large-graph-idle: heap used 59.4 MB
large-graph-idle: DOM nodes -121
large-graph-idle: event listeners -98
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 22ms
large-graph-pan: layout count 0
large-graph-pan: style recalc count 70
large-graph-pan: task duration 1071ms
large-graph-pan: script duration 376ms
large-graph-pan: TBT 0ms
large-graph-pan: heap used 79.3 MB
large-graph-pan: DOM nodes -126
large-graph-pan: event listeners -97
large-graph-zoom: avg frame time 17ms
large-graph-zoom: p95 frame time 17ms
large-graph-zoom: layout duration 8ms
large-graph-zoom: style recalc duration 17ms
large-graph-zoom: layout count 60
large-graph-zoom: style recalc count 63
large-graph-zoom: task duration 1284ms
large-graph-zoom: script duration 456ms
large-graph-zoom: TBT 0ms
large-graph-zoom: heap used 65.8 MB
large-graph-zoom: DOM nodes 8
large-graph-zoom: event listeners 8
minimap-idle: avg frame time 17ms
minimap-idle: p95 frame time 17ms
minimap-idle: layout duration 0ms
minimap-idle: style recalc duration 8ms
minimap-idle: layout count 0
minimap-idle: style recalc count 8
minimap-idle: task duration 582ms
minimap-idle: script duration 90ms
minimap-idle: TBT 0ms
minimap-idle: heap used 56.9 MB
minimap-idle: DOM nodes -269
minimap-idle: event listeners -199
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 14ms
subgraph-dom-widget-clipping: layout count 0
subgraph-dom-widget-clipping: style recalc count 47
subgraph-dom-widget-clipping: task duration 404ms
subgraph-dom-widget-clipping: script duration 116ms
subgraph-dom-widget-clipping: TBT 0ms
subgraph-dom-widget-clipping: heap used 47.0 MB
subgraph-dom-widget-clipping: DOM nodes -264
subgraph-dom-widget-clipping: event listeners -197
subgraph-idle: avg frame time 17ms
subgraph-idle: p95 frame time 17ms
subgraph-idle: layout duration 0ms
subgraph-idle: style recalc duration 8ms
subgraph-idle: layout count 0
subgraph-idle: style recalc count 10
subgraph-idle: task duration 394ms
subgraph-idle: script duration 15ms
subgraph-idle: TBT 0ms
subgraph-idle: heap used 47.2 MB
subgraph-idle: DOM nodes -284
subgraph-idle: event listeners -197
subgraph-mouse-sweep: avg frame time 17ms
subgraph-mouse-sweep: p95 frame time 17ms
subgraph-mouse-sweep: layout duration 5ms
subgraph-mouse-sweep: style recalc duration 40ms
subgraph-mouse-sweep: layout count 16
subgraph-mouse-sweep: style recalc count 76
subgraph-mouse-sweep: task duration 760ms
subgraph-mouse-sweep: script duration 91ms
subgraph-mouse-sweep: TBT 0ms
subgraph-mouse-sweep: heap used 71.4 MB
subgraph-mouse-sweep: DOM nodes -103
subgraph-mouse-sweep: event listeners -97
subgraph-transition-enter: avg frame time 17ms
subgraph-transition-enter: p95 frame time 17ms
subgraph-transition-enter: layout duration 13ms
subgraph-transition-enter: style recalc duration 29ms
subgraph-transition-enter: layout count 14
subgraph-transition-enter: style recalc count 18
subgraph-transition-enter: task duration 752ms
subgraph-transition-enter: script duration 29ms
subgraph-transition-enter: TBT 143ms
subgraph-transition-enter: heap used 93.4 MB
subgraph-transition-enter: DOM nodes 13673
subgraph-transition-enter: event listeners 2531
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 55ms
viewport-pan-sweep: layout count 0
viewport-pan-sweep: style recalc count 251
viewport-pan-sweep: task duration 3821ms
viewport-pan-sweep: script duration 1213ms
viewport-pan-sweep: TBT 0ms
viewport-pan-sweep: heap used 62.4 MB
viewport-pan-sweep: DOM nodes -201
viewport-pan-sweep: event listeners -140
vue-large-graph-idle: avg frame time 17ms
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 10684ms
vue-large-graph-idle: script duration 519ms
vue-large-graph-idle: TBT 0ms
vue-large-graph-idle: heap used 161.4 MB
vue-large-graph-idle: DOM nodes -3300
vue-large-graph-idle: event listeners -16374
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 20ms
vue-large-graph-pan: layout count 0
vue-large-graph-pan: style recalc count 66
vue-large-graph-pan: task duration 13690ms
vue-large-graph-pan: script duration 817ms
vue-large-graph-pan: TBT 21ms
vue-large-graph-pan: heap used 164.3 MB
vue-large-graph-pan: DOM nodes -3301
vue-large-graph-pan: event listeners -16371
workflow-execution: avg frame time 17ms
workflow-execution: p95 frame time 17ms
workflow-execution: layout duration 1ms
workflow-execution: style recalc duration 22ms
workflow-execution: layout count 3
workflow-execution: style recalc count 16
workflow-execution: task duration 149ms
workflow-execution: script duration 10ms
workflow-execution: TBT 0ms
workflow-execution: heap used 49.2 MB
workflow-execution: DOM nodes -3
workflow-execution: event listeners -47
Raw data
{
  "timestamp": "2026-07-19T04:11:43.918Z",
  "gitSha": "7f942e067cb8f1ccb81cd6be2c0177b0166a0d9a",
  "branch": "backport-13810-to-cloud-1.47",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2032.0689999999786,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.492999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 387.246,
      "heapDeltaBytes": -4827732,
      "heapUsedBytes": 49329368,
      "domNodes": 18,
      "jsHeapTotalBytes": 24379392,
      "scriptDurationMs": 18.700999999999997,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2072.6789999999937,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 9.421,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 447.729,
      "heapDeltaBytes": -7506604,
      "heapUsedBytes": 62523296,
      "domNodes": -271,
      "jsHeapTotalBytes": 19546112,
      "scriptDurationMs": 20.354000000000003,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1885.671000000002,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 41.077000000000005,
      "layouts": 12,
      "layoutDurationMs": 3.724,
      "taskDurationMs": 814.307,
      "heapDeltaBytes": -2300496,
      "heapUsedBytes": 50161740,
      "domNodes": -258,
      "jsHeapTotalBytes": 16904192,
      "scriptDurationMs": 112.22,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1841.875000000016,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 40.826,
      "layouts": 12,
      "layoutDurationMs": 3.577,
      "taskDurationMs": 843.1759999999999,
      "heapDeltaBytes": -12787012,
      "heapUsedBytes": 57205860,
      "domNodes": -238,
      "jsHeapTotalBytes": 19808256,
      "scriptDurationMs": 115.60999999999999,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1743.565999999987,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 18.477,
      "layouts": 6,
      "layoutDurationMs": 0.5840000000000001,
      "taskDurationMs": 379.524,
      "heapDeltaBytes": -3547784,
      "heapUsedBytes": 66384892,
      "domNodes": -218,
      "jsHeapTotalBytes": 12730368,
      "scriptDurationMs": 21.706,
      "eventListeners": -182,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1742.1269999999822,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 21.566000000000003,
      "layouts": 6,
      "layoutDurationMs": 0.704,
      "taskDurationMs": 370.995,
      "heapDeltaBytes": -1515552,
      "heapUsedBytes": 50017216,
      "domNodes": -237,
      "jsHeapTotalBytes": 8515584,
      "scriptDurationMs": 21.397,
      "eventListeners": -186,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 562.8059999999948,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 8.004000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 344.043,
      "heapDeltaBytes": 7496360,
      "heapUsedBytes": 66631116,
      "domNodes": 18,
      "jsHeapTotalBytes": 17301504,
      "scriptDurationMs": 56.894999999999996,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666682,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 534.148000000016,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 6.989999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 332.525,
      "heapDeltaBytes": 7167500,
      "heapUsedBytes": 66141664,
      "domNodes": 18,
      "jsHeapTotalBytes": 19136512,
      "scriptDurationMs": 52.181,
      "eventListeners": 0,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2040.8029999999826,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.979000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 519.048,
      "heapDeltaBytes": -8762840,
      "heapUsedBytes": 64238688,
      "domNodes": 20,
      "jsHeapTotalBytes": 10104832,
      "scriptDurationMs": 86.021,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2040.4760000000124,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 7.9959999999999996,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 543.264,
      "heapDeltaBytes": -8224788,
      "heapUsedBytes": 60246856,
      "domNodes": -261,
      "jsHeapTotalBytes": -1323008,
      "scriptDurationMs": 87.663,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2086.7790000000355,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 18.157,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1037.072,
      "heapDeltaBytes": 29664652,
      "heapUsedBytes": 82389076,
      "domNodes": -270,
      "jsHeapTotalBytes": 204800,
      "scriptDurationMs": 369.846,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2129.304999999988,
      "styleRecalcs": 70,
      "styleRecalcDurationMs": 26.398999999999997,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1105.46,
      "heapDeltaBytes": 10433716,
      "heapUsedBytes": 83962424,
      "domNodes": 18,
      "jsHeapTotalBytes": 12640256,
      "scriptDurationMs": 381.195,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3136.090999999965,
      "styleRecalcs": 63,
      "styleRecalcDurationMs": 17.541,
      "layouts": 60,
      "layoutDurationMs": 7.792000000000001,
      "taskDurationMs": 1288.2849999999999,
      "heapDeltaBytes": 13387940,
      "heapUsedBytes": 69202500,
      "domNodes": 8,
      "jsHeapTotalBytes": 1835008,
      "scriptDurationMs": 460.93600000000004,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3117.838000000006,
      "styleRecalcs": 63,
      "styleRecalcDurationMs": 17.309,
      "layouts": 60,
      "layoutDurationMs": 7.469,
      "taskDurationMs": 1278.8619999999999,
      "heapDeltaBytes": 13970856,
      "heapUsedBytes": 68698204,
      "domNodes": 8,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 450.621,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2028.0260000000112,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.2669999999999995,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 565.879,
      "heapDeltaBytes": -17190004,
      "heapUsedBytes": 59487472,
      "domNodes": -267,
      "jsHeapTotalBytes": 4530176,
      "scriptDurationMs": 89.135,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "minimap-idle",
      "durationMs": 2038.626000000022,
      "styleRecalcs": 7,
      "styleRecalcDurationMs": 8.346,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 597.27,
      "heapDeltaBytes": -16703724,
      "heapUsedBytes": 59785548,
      "domNodes": -271,
      "jsHeapTotalBytes": 4005888,
      "scriptDurationMs": 91.859,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 614.9800000000027,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 16.389,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 420.83900000000006,
      "heapDeltaBytes": -22426420,
      "heapUsedBytes": 47554292,
      "domNodes": -269,
      "jsHeapTotalBytes": 5914624,
      "scriptDurationMs": 118.765,
      "eventListeners": -197,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 582.3489999999083,
      "styleRecalcs": 46,
      "styleRecalcDurationMs": 11.141000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 386.552,
      "heapDeltaBytes": -1453920,
      "heapUsedBytes": 51100600,
      "domNodes": -259,
      "jsHeapTotalBytes": -135168,
      "scriptDurationMs": 114.15499999999999,
      "eventListeners": -197,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2007.2979999999916,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 7.812000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 384.926,
      "heapDeltaBytes": -3609124,
      "heapUsedBytes": 49014404,
      "domNodes": -284,
      "jsHeapTotalBytes": 17428480,
      "scriptDurationMs": 14.519999999999998,
      "eventListeners": -197,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2010.5179999999905,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.884999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 403.20099999999996,
      "heapDeltaBytes": -2621260,
      "heapUsedBytes": 49871472,
      "domNodes": -284,
      "jsHeapTotalBytes": 17690624,
      "scriptDurationMs": 16.129,
      "eventListeners": -197,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1762.1819999999957,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 36.255,
      "layouts": 16,
      "layoutDurationMs": 4.592,
      "taskDurationMs": 747.938,
      "heapDeltaBytes": 20976708,
      "heapUsedBytes": 80208156,
      "domNodes": 61,
      "jsHeapTotalBytes": 40632320,
      "scriptDurationMs": 90.64500000000001,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1746.9950000000267,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 42.745,
      "layouts": 16,
      "layoutDurationMs": 4.803,
      "taskDurationMs": 772.946,
      "heapDeltaBytes": 16903172,
      "heapUsedBytes": 69427464,
      "domNodes": -266,
      "jsHeapTotalBytes": 14282752,
      "scriptDurationMs": 90.837,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 948.5459999999648,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 29.22099999999999,
      "layouts": 14,
      "layoutDurationMs": 13.366000000000003,
      "taskDurationMs": 751.901,
      "heapDeltaBytes": 29863164,
      "heapUsedBytes": 97959048,
      "domNodes": 13673,
      "jsHeapTotalBytes": 14680064,
      "scriptDurationMs": 28.699,
      "eventListeners": 2531,
      "totalBlockingTimeMs": 143,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8092.052000000023,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 54.894,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3695.046,
      "heapDeltaBytes": 16165228,
      "heapUsedBytes": 69252976,
      "domNodes": -260,
      "jsHeapTotalBytes": 2039808,
      "scriptDurationMs": 1189.181,
      "eventListeners": -183,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8166.804999999954,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 55.23400000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 3947.8590000000004,
      "heapDeltaBytes": 5628196,
      "heapUsedBytes": 61711372,
      "domNodes": -142,
      "jsHeapTotalBytes": 11169792,
      "scriptDurationMs": 1236.18,
      "eventListeners": -96,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 10632.642000000033,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 10615.659000000001,
      "heapDeltaBytes": -52462180,
      "heapUsedBytes": 171067148,
      "domNodes": -3300,
      "jsHeapTotalBytes": 5242880,
      "scriptDurationMs": 526.366,
      "eventListeners": -16368,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333338,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 10771.485999999983,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 10752.863000000001,
      "heapDeltaBytes": -48662920,
      "heapUsedBytes": 167317452,
      "domNodes": -3300,
      "jsHeapTotalBytes": -6844416,
      "scriptDurationMs": 511.8020000000001,
      "eventListeners": -16380,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.77333333333336,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 14019.496000000003,
      "styleRecalcs": 67,
      "styleRecalcDurationMs": 18.68700000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13999.364,
      "heapDeltaBytes": -17766780,
      "heapUsedBytes": 177477972,
      "domNodes": -3302,
      "jsHeapTotalBytes": 16138240,
      "scriptDurationMs": 776.883,
      "eventListeners": -16370,
      "totalBlockingTimeMs": 2,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 13402.478000000086,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 21.976000000000024,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13381.004999999997,
      "heapDeltaBytes": -46431980,
      "heapUsedBytes": 167141248,
      "domNodes": -3300,
      "jsHeapTotalBytes": 4952064,
      "scriptDurationMs": 857.7470000000001,
      "eventListeners": -16372,
      "totalBlockingTimeMs": 40,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 447.8149999999914,
      "styleRecalcs": 15,
      "styleRecalcDurationMs": 24.747,
      "layouts": 3,
      "layoutDurationMs": 1.161,
      "taskDurationMs": 198.248,
      "heapDeltaBytes": -22904296,
      "heapUsedBytes": 46199820,
      "domNodes": -146,
      "jsHeapTotalBytes": 6701056,
      "scriptDurationMs": 10.538,
      "eventListeners": -158,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "workflow-execution",
      "durationMs": 453.6950000000388,
      "styleRecalcs": 17,
      "styleRecalcDurationMs": 19.492,
      "layouts": 3,
      "layoutDurationMs": 1.147,
      "taskDurationMs": 100.469,
      "heapDeltaBytes": 4775648,
      "heapUsedBytes": 56930296,
      "domNodes": 141,
      "jsHeapTotalBytes": 262144,
      "scriptDurationMs": 8.665,
      "eventListeners": 65,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    }
  ]
}

🎭 Playwright: ✅ 1690 passed, 0 failed · 5 flaky

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

@github-actions

Copy link
Copy Markdown

🎭 Playwright: ⏳ Running...

@dante01yoon dante01yoon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified as a clean backport of #13810 to cloud/1.47. The actual added and removed lines match the original PR, the branch is mergeable, and there are no failing checks; remaining CI is still in progress.

@codecov

codecov Bot commented Jul 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.22222% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../platform/workspace/composables/useMembersPanel.ts 94.44% 1 Missing ⚠️
@@              Coverage Diff              @@
##             cloud/1.47   #13814   +/-   ##
=============================================
  Coverage              ?   78.26%           
=============================================
  Files                 ?     1662           
  Lines                 ?    93135           
  Branches              ?    32251           
=============================================
  Hits                  ?    72888           
  Misses                ?    19635           
  Partials              ?      612           
Flag Coverage Δ
unit 66.35% <97.22%> (?)

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

Files with missing lines Coverage Δ
...omponents/dialogs/settings/MembersPanelContent.vue 100.00% <100.00%> (ø)
...ponents/dialogs/settings/WorkspacePanelContent.vue 96.29% <100.00%> (ø)
src/platform/workspace/composables/useTeamPlan.ts 100.00% <100.00%> (ø)
...rc/platform/workspace/stores/teamWorkspaceStore.ts 91.84% <ø> (ø)
.../platform/workspace/composables/useMembersPanel.ts 95.27% <94.44%> (ø)
🚀 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.

comfy-pr-bot pushed a commit that referenced this pull request Jul 19, 2026
…13834)

## Summary

Backports #13812 to `cloud/1.47` after the [automatic
cherry-pick](https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/29704878740)
conflicted. This branch is stacked on the current #13814 head.

## Changes

- **What**: Applies role-gated billing mutations, Personal/default
creator protection, additional-workspace creator actions, and
execution-time permission rechecks.
- **Dependencies**: Depends on #13814; merge it first so this PR narrows
to the #13812 backport.

## Review Focus

- Combines #13814 plan-driven Members access with #13812 role and
creator policy.
- Corrects the cloud workspace fixture to use
`consolidated_billing_enabled` for Personal billing routing while
leaving `billing_control_enabled` independent.
- Keeps the `BillingStatusBanner` story/test and Storybook workspace
mock deleted because their runtime surface is absent on this branch.

## Validation

- Focused unit suite: 18 files, 397 tests passed.
- Main and browser typechecks passed; focused formatting passed.
- Cloud `memberRoleChange.spec.ts`: 7 passed.

## Screenshots

| 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"
/> |

<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"
/>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport Backporting a PR onto a release candidate size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants