Skip to content

Gate embedded checkout design rollout - #14496

Closed
dante01yoon wants to merge 3 commits into
comfydesigner/saved-method-confirmfrom
jaewon/fe-1467-embedded-checkout-flag
Closed

Gate embedded checkout design rollout#14496
dante01yoon wants to merge 3 commits into
comfydesigner/saved-method-confirmfrom
jaewon/fe-1467-embedded-checkout-flag

Conversation

@dante01yoon

@dante01yoon dante01yoon commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Gate the stacked embedded checkout UI behind the server feature flag embedded_checkout_enabled so rollout defaults to the existing hosted checkout while the backend dependencies land.

Changes

  • What: Adds the typed server/remote-config flag (default false) and applies it at the existing usePaymentElement activation seam. Disabled keeps the legacy checkout path; enabled activates the complete embedded Payment Element layout when VITE_STRIPE_PUBLISHABLE_KEY is configured.
  • Regression coverage: Component tests assert both disabled → legacy and enabled → embedded routing. Stale stacked-design expectations now match the shipped formatted annual total, embedded back action, and Stripe Payment Element options.
  • Dependencies: Stacked on feat(billing): saved-method confirm and confirm-screen convergence #14449feat(billing): visual pass for the embedded checkout #14447. Embedded subscription payment requires Comfy-Org/cloud#5859.

Review Focus

The design stack previously enabled the Payment Element whenever a publishable key existed, leaving no rollout escape hatch. This is intentionally one gate at the checkout boundary rather than flag checks throughout the design components.

Backend readiness:

  • Core embedded subscription payment — hard blocker: cloud#5859 owns confirmation_token forwarding, exact first-invoice PaymentIntent confirmation, 3DS/Alipay handling, and saving the resulting default payment method. Keep the flag off until that contract is deployed and verified.
  • Promo requote — hard blocker for enabling promo UX, not core embedded payment: initial subscribe accepts and validates promotion_code, but preview/requote does not accept it, so the UI cannot show a validated discounted total before consent. Keep promo dark/disabled until preview support lands.
  • Saved methods — optional dark feature: backend resolves one default payment method internally but exposes no list/selection contract or display metadata. The frontend passes null, so saved-method selection stays dark and does not block collecting a new method through Payment Element.

Verified with:

  • pnpm test:unit src/platform/workspace/components/SubscriptionRequiredDialogContentUnified.test.ts src/platform/workspace/components/SubscriptionAddPaymentPreviewWorkspace.test.ts src/platform/workspace/components/UnifiedStripePaymentSelector.test.ts (18 passed)
  • pnpm test:unit src/composables/useFeatureFlags.test.ts (28 passed)
  • pnpm typecheck
  • ESLint and oxfmt checks on all changed files
  • Commit hooks: stylelint, oxfmt, oxlint, ESLint, typecheck; push hook: knip

Real cloud/payment screenshots were not available in this workspace; routing evidence is covered by the focused component tests. Do not merge until #14449/#14447 and cloud#5859 are safe for rollout.

Screenshots (if applicable)

Not available: this isolated workspace has no authenticated billing account or deployed cloud#5859 backend.

@dosubot dosubot Bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Jul 31, 2026
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 39f32861-baed-4dd8-a4c6-855d0ae2cc7d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds the EMBEDDED_CHECKOUT_ENABLED flag to remote configuration and feature-flag resolution. Subscription checkout now enables Stripe Payment Element behavior only when the flag and publishable key are configured. Tests cover enabled and disabled states.

Changes

Embedded checkout gating

Layer / File(s) Summary
Feature flag contract
src/composables/useFeatureFlags.ts, src/platform/remoteConfig/types.ts
Adds EMBEDDED_CHECKOUT_ENABLED, the embeddedCheckoutEnabled getter, and the optional remote configuration property.
Checkout behavior gating
src/platform/workspace/components/SubscriptionRequiredDialogContentUnified.vue
Requires both embeddedCheckoutEnabled and a Stripe publishable key. The embedded payment, confirmation, success, and height-animation paths use this condition.
Checkout behavior tests
src/platform/workspace/components/SubscriptionRequiredDialogContentUnified.test.ts
Adds reactive mocks and verifies preview behavior when embedded checkout is disabled and enabled.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RemoteConfig
  participant useFeatureFlags
  participant SubscriptionRequiredDialogContentUnified
  participant PaymentPreview
  RemoteConfig->>useFeatureFlags: provide embedded_checkout_enabled
  useFeatureFlags->>SubscriptionRequiredDialogContentUnified: expose embeddedCheckoutEnabled
  SubscriptionRequiredDialogContentUnified->>PaymentPreview: pass usePaymentElement
  PaymentPreview-->>SubscriptionRequiredDialogContentUnified: render checkout preview
Loading

Possibly related PRs

Suggested labels: preview

Suggested reviewers: benceruleanlu, austinmroz


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
End-To-End Regression Coverage For Fixes ❓ Inconclusive The changed files and description are available, but the PR title and commit subjects are not provided, so the required bug-fix signal cannot be verified. Provide the PR title and commit subjects to determine whether the end-to-end regression coverage check applies.
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Adr Compliance For Entity/Litegraph Changes ✅ Passed The changed-file list contains no files under src/lib/litegraph/, src/ecs/, or graph-entity-related paths; the check is not applicable.
Title check ✅ Passed The title clearly summarizes the main change: gating the embedded checkout rollout.
Description check ✅ Passed The description covers the summary, changes, review focus, dependencies, validation, rollout conditions, and screenshot status.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jaewon/fe-1467-embedded-checkout-flag

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dosubot

dosubot Bot commented Jul 31, 2026

Copy link
Copy Markdown

📄 Knowledge review

Dosu skipped reviewing this PR because your organization has used its 200 included credits for the month. Your usage will reset on 2026-08-01. To have Dosu review this PR before then, ask your organization admin to upgrade to a pro account.


Leave Feedback Ask Dosu about ComfyUI_frontend Add Dosu to your team

@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown

🎭 Playwright: ❌ 1755 passed, 5 failed · 3 flaky

❌ Failed Tests

📊 Browser Reports

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 07/31/2026, 07:27:18 PM UTC

Links

📦 Bundle Size

⏳ Size data collection in progress…

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 73.3 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 58.1 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 76.3 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.5 MB heap
large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 66.3 MB heap
large-graph-pan: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.0 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 55.7 MB heap
minimap-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 68.1 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 58.7 MB heap
subgraph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 72.9 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.4 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 160ms TBT · 98.0 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 80.7 MB heap
vue-large-graph-idle: · 56.3 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 169.3 MB heap
vue-large-graph-pan: · 53.7 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 1133ms TBT · 170.2 MB heap
workflow-execution: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 52.1 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 8
canvas-idle: task duration 770ms
canvas-idle: script duration 28ms
canvas-idle: TBT 0ms
canvas-idle: heap used 73.3 MB
canvas-idle: DOM nodes 15
canvas-idle: event listeners 5
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 50ms
canvas-mouse-sweep: layout count 12
canvas-mouse-sweep: style recalc count 80
canvas-mouse-sweep: task duration 1151ms
canvas-mouse-sweep: script duration 159ms
canvas-mouse-sweep: TBT 0ms
canvas-mouse-sweep: heap used 58.1 MB
canvas-mouse-sweep: DOM nodes -114
canvas-mouse-sweep: event listeners -71
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 31
canvas-zoom-sweep: task duration 573ms
canvas-zoom-sweep: script duration 30ms
canvas-zoom-sweep: TBT 0ms
canvas-zoom-sweep: heap used 76.3 MB
canvas-zoom-sweep: DOM nodes 75
canvas-zoom-sweep: event listeners 21
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 9ms
dom-widget-clipping: layout count 0
dom-widget-clipping: style recalc count 11
dom-widget-clipping: task duration 476ms
dom-widget-clipping: script duration 67ms
dom-widget-clipping: TBT 0ms
dom-widget-clipping: heap used 57.5 MB
dom-widget-clipping: DOM nodes 17
dom-widget-clipping: event listeners 4
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 8
large-graph-idle: task duration 1001ms
large-graph-idle: script duration 146ms
large-graph-idle: TBT 0ms
large-graph-idle: heap used 66.3 MB
large-graph-idle: DOM nodes -293
large-graph-idle: event listeners -147
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 13ms
large-graph-pan: layout count 0
large-graph-pan: style recalc count 67
large-graph-pan: task duration 1635ms
large-graph-pan: script duration 537ms
large-graph-pan: TBT 0ms
large-graph-pan: heap used 61.0 MB
large-graph-pan: DOM nodes -297
large-graph-pan: event listeners -159
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 16ms
large-graph-zoom: layout count 60
large-graph-zoom: style recalc count 64
large-graph-zoom: task duration 1883ms
large-graph-zoom: script duration 655ms
large-graph-zoom: TBT 0ms
large-graph-zoom: heap used 55.7 MB
large-graph-zoom: DOM nodes -301
large-graph-zoom: event listeners -149
minimap-idle: avg frame time 17ms
minimap-idle: p95 frame time 17ms
minimap-idle: layout duration 0ms
minimap-idle: style recalc duration 9ms
minimap-idle: layout count 0
minimap-idle: style recalc count 8
minimap-idle: task duration 990ms
minimap-idle: script duration 142ms
minimap-idle: TBT 0ms
minimap-idle: heap used 68.1 MB
minimap-idle: DOM nodes -293
minimap-idle: event listeners -162
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 13ms
subgraph-dom-widget-clipping: layout count 0
subgraph-dom-widget-clipping: style recalc count 46
subgraph-dom-widget-clipping: task duration 488ms
subgraph-dom-widget-clipping: script duration 129ms
subgraph-dom-widget-clipping: TBT 0ms
subgraph-dom-widget-clipping: heap used 58.7 MB
subgraph-dom-widget-clipping: DOM nodes 18
subgraph-dom-widget-clipping: event listeners 11
subgraph-idle: avg frame time 17ms
subgraph-idle: p95 frame time 17ms
subgraph-idle: layout duration 0ms
subgraph-idle: style recalc duration 9ms
subgraph-idle: layout count 0
subgraph-idle: style recalc count 8
subgraph-idle: task duration 694ms
subgraph-idle: script duration 23ms
subgraph-idle: TBT 0ms
subgraph-idle: heap used 72.9 MB
subgraph-idle: DOM nodes 16
subgraph-idle: event listeners 7
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 45ms
subgraph-mouse-sweep: layout count 16
subgraph-mouse-sweep: style recalc count 77
subgraph-mouse-sweep: task duration 1004ms
subgraph-mouse-sweep: script duration 114ms
subgraph-mouse-sweep: TBT 0ms
subgraph-mouse-sweep: heap used 64.4 MB
subgraph-mouse-sweep: DOM nodes 64
subgraph-mouse-sweep: event listeners 7
subgraph-transition-enter: avg frame time 17ms
subgraph-transition-enter: p95 frame time 17ms
subgraph-transition-enter: layout duration 14ms
subgraph-transition-enter: style recalc duration 34ms
subgraph-transition-enter: layout count 14
subgraph-transition-enter: style recalc count 18
subgraph-transition-enter: task duration 1137ms
subgraph-transition-enter: script duration 43ms
subgraph-transition-enter: TBT 160ms
subgraph-transition-enter: heap used 98.0 MB
subgraph-transition-enter: DOM nodes 13673
subgraph-transition-enter: event listeners 2371
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 42ms
viewport-pan-sweep: layout count 0
viewport-pan-sweep: style recalc count 250
viewport-pan-sweep: task duration 5860ms
viewport-pan-sweep: script duration 1783ms
viewport-pan-sweep: TBT 0ms
viewport-pan-sweep: heap used 80.7 MB
viewport-pan-sweep: DOM nodes -293
viewport-pan-sweep: event listeners -128
vue-large-graph-idle: avg frame time 18ms
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 18570ms
vue-large-graph-idle: script duration 736ms
vue-large-graph-idle: TBT 0ms
vue-large-graph-idle: heap used 169.3 MB
vue-large-graph-idle: DOM nodes -8312
vue-large-graph-idle: event listeners -16386
vue-large-graph-pan: avg frame time 19ms
vue-large-graph-pan: p95 frame time 17ms
vue-large-graph-pan: layout duration 0ms
vue-large-graph-pan: style recalc duration 30ms
vue-large-graph-pan: layout count 0
vue-large-graph-pan: style recalc count 181
vue-large-graph-pan: task duration 23817ms
vue-large-graph-pan: script duration 1199ms
vue-large-graph-pan: TBT 1133ms
vue-large-graph-pan: heap used 170.2 MB
vue-large-graph-pan: DOM nodes -8312
vue-large-graph-pan: event listeners -16383
workflow-execution: avg frame time 17ms
workflow-execution: p95 frame time 17ms
workflow-execution: layout duration 1ms
workflow-execution: style recalc duration 24ms
workflow-execution: layout count 4
workflow-execution: style recalc count 15
workflow-execution: task duration 153ms
workflow-execution: script duration 13ms
workflow-execution: TBT 0ms
workflow-execution: heap used 52.1 MB
workflow-execution: DOM nodes 135
workflow-execution: event listeners 68
Raw data
{
  "timestamp": "2026-07-31T19:43:31.341Z",
  "gitSha": "f59a077e52dca9256a7e7f8edef7c60217a53617",
  "branch": "jaewon/fe-1467-embedded-checkout-flag",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2122.109000000023,
      "styleRecalcs": 7,
      "styleRecalcDurationMs": 8.654000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 805.7149999999999,
      "heapDeltaBytes": 5147480,
      "heapUsedBytes": 77023444,
      "domNodes": 14,
      "jsHeapTotalBytes": 19521536,
      "scriptDurationMs": 27.961999999999996,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-idle",
      "durationMs": 2086.06199999997,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.113999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 735.05,
      "heapDeltaBytes": 5122308,
      "heapUsedBytes": 76647080,
      "domNodes": 16,
      "jsHeapTotalBytes": 19521536,
      "scriptDurationMs": 27.722,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2079.2879999999627,
      "styleRecalcs": 78,
      "styleRecalcDurationMs": 48.773,
      "layouts": 12,
      "layoutDurationMs": 4.1659999999999995,
      "taskDurationMs": 1189.632,
      "heapDeltaBytes": -20690272,
      "heapUsedBytes": 50782016,
      "domNodes": -291,
      "jsHeapTotalBytes": 19910656,
      "scriptDurationMs": 160.93699999999998,
      "eventListeners": -151,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2001.423999999929,
      "styleRecalcs": 81,
      "styleRecalcDurationMs": 51.43599999999999,
      "layouts": 12,
      "layoutDurationMs": 3.8249999999999993,
      "taskDurationMs": 1112.806,
      "heapDeltaBytes": -250288,
      "heapUsedBytes": 71166532,
      "domNodes": 64,
      "jsHeapTotalBytes": 20570112,
      "scriptDurationMs": 157.622,
      "eventListeners": 9,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1752.7109999999766,
      "styleRecalcs": 30,
      "styleRecalcDurationMs": 20.464000000000002,
      "layouts": 6,
      "layoutDurationMs": 0.7749999999999999,
      "taskDurationMs": 562.067,
      "heapDeltaBytes": 8281108,
      "heapUsedBytes": 80072880,
      "domNodes": 74,
      "jsHeapTotalBytes": 19521536,
      "scriptDurationMs": 29.619000000000003,
      "eventListeners": 21,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1765.912999999955,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 19.954000000000004,
      "layouts": 6,
      "layoutDurationMs": 0.8200000000000002,
      "taskDurationMs": 584.821,
      "heapDeltaBytes": 8373912,
      "heapUsedBytes": 79946640,
      "domNodes": 75,
      "jsHeapTotalBytes": 19783680,
      "scriptDurationMs": 30.632,
      "eventListeners": 21,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 700.9499999999775,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 8.61,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 456.22300000000007,
      "heapDeltaBytes": -11469940,
      "heapUsedBytes": 60299196,
      "domNodes": 18,
      "jsHeapTotalBytes": 20045824,
      "scriptDurationMs": 63.888,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 761.9700000000194,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 8.754999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 495.923,
      "heapDeltaBytes": -11153112,
      "heapUsedBytes": 60217568,
      "domNodes": 16,
      "jsHeapTotalBytes": 20307968,
      "scriptDurationMs": 70.353,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2058.530000000019,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.300000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1012.688,
      "heapDeltaBytes": 7182436,
      "heapUsedBytes": 69326164,
      "domNodes": -295,
      "jsHeapTotalBytes": 5038080,
      "scriptDurationMs": 144.81700000000004,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2056.6929999999957,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 7.611,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 988.383,
      "heapDeltaBytes": 7184184,
      "heapUsedBytes": 69694212,
      "domNodes": -290,
      "jsHeapTotalBytes": 5300224,
      "scriptDurationMs": 147.94899999999998,
      "eventListeners": -146,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2544.001000000037,
      "styleRecalcs": 67,
      "styleRecalcDurationMs": 13.315000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1637.8129999999999,
      "heapDeltaBytes": 6073872,
      "heapUsedBytes": 69579320,
      "domNodes": -297,
      "jsHeapTotalBytes": 4718592,
      "scriptDurationMs": 542.256,
      "eventListeners": -143,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2524.357999999893,
      "styleRecalcs": 66,
      "styleRecalcDurationMs": 12.629000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1632.6660000000002,
      "heapDeltaBytes": -5868892,
      "heapUsedBytes": 58417188,
      "domNodes": -297,
      "jsHeapTotalBytes": 5038080,
      "scriptDurationMs": 532.5640000000001,
      "eventListeners": -175,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3731.956000000025,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 15.873000000000001,
      "layouts": 60,
      "layoutDurationMs": 8.433,
      "taskDurationMs": 1926.3960000000002,
      "heapDeltaBytes": -4686188,
      "heapUsedBytes": 60338120,
      "domNodes": -303,
      "jsHeapTotalBytes": 6873088,
      "scriptDurationMs": 677.611,
      "eventListeners": -150,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3599.3799999999965,
      "styleRecalcs": 64,
      "styleRecalcDurationMs": 15.423999999999996,
      "layouts": 60,
      "layoutDurationMs": 7.86,
      "taskDurationMs": 1840.388,
      "heapDeltaBytes": -8707216,
      "heapUsedBytes": 56387432,
      "domNodes": -298,
      "jsHeapTotalBytes": 7921664,
      "scriptDurationMs": 631.9,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "minimap-idle",
      "durationMs": 2045.1600000000099,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.833,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 981.848,
      "heapDeltaBytes": 7517376,
      "heapUsedBytes": 71554104,
      "domNodes": -294,
      "jsHeapTotalBytes": 4513792,
      "scriptDurationMs": 141.316,
      "eventListeners": -148,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "minimap-idle",
      "durationMs": 2040.7470000000103,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.847999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 998.059,
      "heapDeltaBytes": 6889700,
      "heapUsedBytes": 71193772,
      "domNodes": -291,
      "jsHeapTotalBytes": 4775936,
      "scriptDurationMs": 142.588,
      "eventListeners": -176,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 753.3000000000243,
      "styleRecalcs": 45,
      "styleRecalcDurationMs": 13.351999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 498.54099999999994,
      "heapDeltaBytes": -10467908,
      "heapUsedBytes": 61479676,
      "domNodes": 16,
      "jsHeapTotalBytes": 19259392,
      "scriptDurationMs": 131.954,
      "eventListeners": 11,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 697.714000000019,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 12.288,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 478.165,
      "heapDeltaBytes": -10286004,
      "heapUsedBytes": 61591308,
      "domNodes": 20,
      "jsHeapTotalBytes": 19521536,
      "scriptDurationMs": 126.23899999999999,
      "eventListeners": 10,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2014.8310000000151,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.601,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 701.773,
      "heapDeltaBytes": 4743008,
      "heapUsedBytes": 76499292,
      "domNodes": 16,
      "jsHeapTotalBytes": 19259392,
      "scriptDurationMs": 23.317,
      "eventListeners": 7,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2019.5660000000544,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.954,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 685.3000000000001,
      "heapDeltaBytes": 4767356,
      "heapUsedBytes": 76472480,
      "domNodes": 16,
      "jsHeapTotalBytes": 20045824,
      "scriptDurationMs": 22.165,
      "eventListeners": 7,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1785.9770000000026,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 45.89699999999999,
      "layouts": 16,
      "layoutDurationMs": 5.050000000000001,
      "taskDurationMs": 999.104,
      "heapDeltaBytes": -3746084,
      "heapUsedBytes": 67564140,
      "domNodes": 64,
      "jsHeapTotalBytes": 19783680,
      "scriptDurationMs": 115.17399999999998,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1787.1399999999085,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 45.016,
      "layouts": 16,
      "layoutDurationMs": 4.9319999999999995,
      "taskDurationMs": 1009.371,
      "heapDeltaBytes": -4157296,
      "heapUsedBytes": 67574416,
      "domNodes": 63,
      "jsHeapTotalBytes": 20045824,
      "scriptDurationMs": 113.01899999999998,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 1468.9149999999245,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 34.29599999999999,
      "layouts": 14,
      "layoutDurationMs": 14.110999999999999,
      "taskDurationMs": 1137.4930000000002,
      "heapDeltaBytes": 29808292,
      "heapUsedBytes": 102718444,
      "domNodes": 13673,
      "jsHeapTotalBytes": 17039360,
      "scriptDurationMs": 42.95400000000001,
      "eventListeners": 2371,
      "totalBlockingTimeMs": 160,
      "frameDurationMs": 16.669999999999952,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 9438.342999999975,
      "styleRecalcs": 249,
      "styleRecalcDurationMs": 41.956999999999994,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 5954.758,
      "heapDeltaBytes": 20989360,
      "heapUsedBytes": 83495756,
      "domNodes": -294,
      "jsHeapTotalBytes": 6524928,
      "scriptDurationMs": 1816.0029999999997,
      "eventListeners": -129,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 9385.453999999982,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 42.24999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 5764.448,
      "heapDeltaBytes": 23766584,
      "heapUsedBytes": 85734656,
      "domNodes": -291,
      "jsHeapTotalBytes": 7573504,
      "scriptDurationMs": 1750.0690000000002,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 18745.758999999965,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 18476.202999999998,
      "heapDeltaBytes": -49130788,
      "heapUsedBytes": 180845756,
      "domNodes": -8312,
      "jsHeapTotalBytes": -11939840,
      "scriptDurationMs": 738.085,
      "eventListeners": -16385,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 18924.387000000024,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 18663.493000000002,
      "heapDeltaBytes": -55030004,
      "heapUsedBytes": 174100096,
      "domNodes": -8312,
      "jsHeapTotalBytes": -6754304,
      "scriptDurationMs": 733.3829999999999,
      "eventListeners": -16387,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 24105.150000000038,
      "styleRecalcs": 180,
      "styleRecalcDurationMs": 29.367000000000033,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 23868.146,
      "heapDeltaBytes": -38254084,
      "heapUsedBytes": 177067948,
      "domNodes": -8312,
      "jsHeapTotalBytes": -14675968,
      "scriptDurationMs": 1196.283,
      "eventListeners": -16385,
      "totalBlockingTimeMs": 1144,
      "frameDurationMs": 18.889999999999905,
      "p95FrameDurationMs": 16.799999999995634
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 24044.45599999997,
      "styleRecalcs": 182,
      "styleRecalcDurationMs": 29.986999999999988,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 23766.134000000002,
      "heapDeltaBytes": -43577892,
      "heapUsedBytes": 179935756,
      "domNodes": -8312,
      "jsHeapTotalBytes": -9981952,
      "scriptDurationMs": 1201.5339999999999,
      "eventListeners": -16381,
      "totalBlockingTimeMs": 1122,
      "frameDurationMs": 18.330000000000048,
      "p95FrameDurationMs": 16.799999999995634
    },
    {
      "name": "workflow-execution",
      "durationMs": 508.8349999999764,
      "styleRecalcs": 19,
      "styleRecalcDurationMs": 27.534000000000002,
      "layouts": 4,
      "layoutDurationMs": 1.644,
      "taskDurationMs": 174.07799999999995,
      "heapDeltaBytes": -15676300,
      "heapUsedBytes": 54973620,
      "domNodes": 154,
      "jsHeapTotalBytes": 6676480,
      "scriptDurationMs": 15.247,
      "eventListeners": 67,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.670000000000012,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 477.5910000000749,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 19.903000000000002,
      "layouts": 3,
      "layoutDurationMs": 0.678,
      "taskDurationMs": 131.34400000000002,
      "heapDeltaBytes": -16454132,
      "heapUsedBytes": 54341640,
      "domNodes": 115,
      "jsHeapTotalBytes": 6938624,
      "scriptDurationMs": 10.821,
      "eventListeners": 68,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    }
  ]
}

@dante01yoon

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/platform/workspace/components/SubscriptionRequiredDialogContentUnified.test.ts`:
- Around line 89-94: Update SubscriptionAddPaymentPreviewWorkspaceStub to render
distinct semantic hosted or embedded checkout content based on
usePaymentElement, rather than exposing the raw prop via data-testid. Revise the
affected tests around the stub to query the rendered checkout state by
accessible role or name, preserving assertions for both payment-element modes.
- Line 119: Move the VITE_STRIPE_PUBLISHABLE_KEY stub out of the shared setup
around the suite and into the specific test that requires it, or restore it in
that test’s afterEach cleanup. Update the test setup containing vi.stubEnv so
the environment variable is not left stubbed after the test completes, without
relying on unstubEnvs.
- Around line 12-18: Move the reactive mock bindings mockCheckoutStep,
mockPreviewVariant, and mockEmbeddedCheckoutEnabled into a vi.hoisted()
initializer placed before the vi.mock calls, and create or import the required
Vue ref API within that hoisted initializer as well. Update the
useSubscriptionCheckout mock factory to reference the hoisted state so module
initialization cannot access bindings in the temporal dead zone.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1b131b38-89d8-4d73-a726-cbe714581684

📥 Commits

Reviewing files that changed from the base of the PR and between d17d468 and d58732f.

📒 Files selected for processing (4)
  • src/composables/useFeatureFlags.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/workspace/components/SubscriptionRequiredDialogContentUnified.test.ts
  • src/platform/workspace/components/SubscriptionRequiredDialogContentUnified.vue

@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 63.63636% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/composables/useFeatureFlags.ts 33.33% 2 Missing ⚠️
...nents/SubscriptionRequiredDialogContentUnified.vue 75.00% 2 Missing ⚠️
@@                          Coverage Diff                          @@
##             comfydesigner/saved-method-confirm   #14496   +/-   ##
=====================================================================
  Coverage                                      ?   79.07%           
=====================================================================
  Files                                         ?     1762           
  Lines                                         ?   104552           
  Branches                                      ?    35437           
=====================================================================
  Hits                                          ?    82679           
  Misses                                        ?    21419           
  Partials                                      ?      454           
Flag Coverage Δ
unit 69.64% <63.63%> (?)

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

Files with missing lines Coverage Δ
src/composables/useFeatureFlags.ts 81.20% <33.33%> (ø)
...nents/SubscriptionRequiredDialogContentUnified.vue 55.68% <75.00%> (ø)
🚀 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.

@dante01yoon

Copy link
Copy Markdown
Collaborator Author

CI follow-up:

  • Full unit suite is now green after updating three stale expectations inherited from the stacked checkout design (14,249 tests in the prior run; current CI: Tests Unit passes).
  • Lint/format, typecheck, knip, build, Storybook, telemetry, website E2E, and focused checkout tests pass.
  • The Playwright screenshot matrix still fails after a failed-job rerun, only in unrelated canvas/mobile baselines: mobileBaseline.spec.ts, rerouteNode.spec.ts, and interaction.spec.ts. None navigate to or exercise checkout; this PR changes only checkout feature-flag routing and test expectations. No unrelated screenshot baselines were updated.

@dante01yoon

Copy link
Copy Markdown
Collaborator Author

Follow-up on the remaining red checks: the stacked base PR #14449 currently has the exact same failures (playwright-tests (chromium-2x), playwright-tests (chromium-0.5x), playwright-tests (mobile-chrome), and aggregate e2e-status). On this PR, all 16 Chromium shards and every checkout-related/unit check pass; the 5 failed assertions are canvas/mobile screenshot baselines outside the checkout surface. The failed jobs were already rerun with the same result. No feature code or checkout baseline change is warranted here, so no no-op commit was pushed. Review feedback remains fully addressed/resolved, and CodeRabbit approved the current head.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant