fix(billing): stop reporting "processing" while a payment waits on the customer - #14910
Conversation
…e customer The billing-operation toast is created once when the operation starts and is never revised, so an operation that later parks on a 3DS challenge kept announcing "Processing payment — setting up your workspace...". The store already tracks the action URL that marks that state and renders a verification prompt from it, so the toast contradicted the prompt beside it. Replace the toast on the first transition into the action-required state, and give it a prompt icon rather than the spinner, which otherwise keeps claiming work is underway while nothing is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
🎭 Playwright: ✅ 1782 passed, 0 failed · 5 flaky📊 Browser Reports
🎨 Storybook: ✅ Built — View Storybook📦 Bundle: 8.63 MB gzip 🔴 +138 BDetailsSummary
Category Glance App Entry Points — 3.67 kB (baseline 3.67 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 1.36 MB (baseline 1.36 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 2 added / 2 removed / 1 unchanged Views & Navigation — 124 kB (baseline 124 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 13 added / 13 removed / 4 unchanged Panels & Settings — 570 kB (baseline 570 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 10 added / 10 removed / 16 unchanged User & Accounts — 27 kB (baseline 27 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 6 added / 6 removed / 4 unchanged Editors & Dialogs — 125 kB (baseline 125 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 7 added / 7 removed / 1 unchanged UI Components — 67.1 kB (baseline 67.1 kB) • ⚪ 0 BReusable component library chunks
Status: 6 added / 6 removed / 8 unchanged Data & Services — 3.49 MB (baseline 3.49 MB) • 🔴 +622 BStores, services, APIs, and repositories
Status: 14 added / 14 removed / 3 unchanged Utilities & Hooks — 547 kB (baseline 547 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 21 added / 21 removed / 17 unchanged Vendor & Third-Party — 16.3 MB (baseline 16.3 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 17 unchanged Other — 13.8 MB (baseline 13.8 MB) • 🔴 +408 BBundles that do not match a named category
Status: 76 added / 76 removed / 210 unchanged ⚡ Performance Report
Show regressions
All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-08-07T20:54:26.595Z",
"gitSha": "0b9ab96a0ff4435cc05b874c74541735a63a1d1d",
"branch": "fix/billing-toast-action-required",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2045.7910000000084,
"styleRecalcs": 8,
"styleRecalcDurationMs": 8.122999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 675.63,
"heapDeltaBytes": 5831268,
"heapUsedBytes": 70250580,
"domNodes": 16,
"jsHeapTotalBytes": 24903680,
"scriptDurationMs": 26.416,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-idle",
"durationMs": 2068.9590000000635,
"styleRecalcs": 9,
"styleRecalcDurationMs": 9.767000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 632.729,
"heapDeltaBytes": 5600240,
"heapUsedBytes": 69916628,
"domNodes": 18,
"jsHeapTotalBytes": 24903680,
"scriptDurationMs": 27.811,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1913.1659999999897,
"styleRecalcs": 77,
"styleRecalcDurationMs": 45.716,
"layouts": 12,
"layoutDurationMs": 3.764,
"taskDurationMs": 961.2149999999999,
"heapDeltaBytes": 512108,
"heapUsedBytes": 64862240,
"domNodes": 60,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 136.79799999999997,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1873.578000000066,
"styleRecalcs": 75,
"styleRecalcDurationMs": 44.278,
"layouts": 12,
"layoutDurationMs": 3.778,
"taskDurationMs": 959.195,
"heapDeltaBytes": -26436,
"heapUsedBytes": 64169756,
"domNodes": 58,
"jsHeapTotalBytes": 24903680,
"scriptDurationMs": 137.464,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1751.2459999999805,
"styleRecalcs": 31,
"styleRecalcDurationMs": 18.772000000000002,
"layouts": 6,
"layoutDurationMs": 0.6739999999999999,
"taskDurationMs": 475.576,
"heapDeltaBytes": 8841956,
"heapUsedBytes": 73268160,
"domNodes": 75,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 27.377000000000002,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1772.4499999999352,
"styleRecalcs": 34,
"styleRecalcDurationMs": 21.768000000000004,
"layouts": 6,
"layoutDurationMs": 0.6990000000000002,
"taskDurationMs": 476.753,
"heapDeltaBytes": 8645212,
"heapUsedBytes": 73254348,
"domNodes": 81,
"jsHeapTotalBytes": 24903680,
"scriptDurationMs": 29.402,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 705.6790000000319,
"styleRecalcs": 9,
"styleRecalcDurationMs": 7.471999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 420.77899999999994,
"heapDeltaBytes": -11497640,
"heapUsedBytes": 53097284,
"domNodes": 14,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 63.96199999999999,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 668.8789999999472,
"styleRecalcs": 10,
"styleRecalcDurationMs": 7.370999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 418.958,
"heapDeltaBytes": -11245848,
"heapUsedBytes": 53184352,
"domNodes": 16,
"jsHeapTotalBytes": 25690112,
"scriptDurationMs": 66.812,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66999999999998,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "large-graph-idle",
"durationMs": 2017.628000000002,
"styleRecalcs": 8,
"styleRecalcDurationMs": 8.303,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 876.592,
"heapDeltaBytes": 6225636,
"heapUsedBytes": 66831020,
"domNodes": -286,
"jsHeapTotalBytes": 3510272,
"scriptDurationMs": 146.221,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-idle",
"durationMs": 2033.9629999999715,
"styleRecalcs": 9,
"styleRecalcDurationMs": 9.524999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 837.5740000000001,
"heapDeltaBytes": 7096672,
"heapUsedBytes": 66826968,
"domNodes": -282,
"jsHeapTotalBytes": 2985984,
"scriptDurationMs": 146.929,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2402.1700000000124,
"styleRecalcs": 68,
"styleRecalcDurationMs": 13.881999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1469.789,
"heapDeltaBytes": 3912900,
"heapUsedBytes": 64848364,
"domNodes": -283,
"jsHeapTotalBytes": 3440640,
"scriptDurationMs": 491.89200000000005,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2343.2240000000775,
"styleRecalcs": 67,
"styleRecalcDurationMs": 13.334999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1441.161,
"heapDeltaBytes": 7025044,
"heapUsedBytes": 68691260,
"domNodes": -284,
"jsHeapTotalBytes": 3702784,
"scriptDurationMs": 488.5930000000001,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3711.456999999996,
"styleRecalcs": 64,
"styleRecalcDurationMs": 15.595999999999998,
"layouts": 60,
"layoutDurationMs": 8.33,
"taskDurationMs": 1808.3960000000002,
"heapDeltaBytes": -4539444,
"heapUsedBytes": 57504004,
"domNodes": -286,
"jsHeapTotalBytes": 5607424,
"scriptDurationMs": 660.111,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3532.447999999931,
"styleRecalcs": 65,
"styleRecalcDurationMs": 16.316,
"layouts": 60,
"layoutDurationMs": 8.107,
"taskDurationMs": 1749.273,
"heapDeltaBytes": 15322508,
"heapUsedBytes": 77545476,
"domNodes": -287,
"jsHeapTotalBytes": 6393856,
"scriptDurationMs": 631.162,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2039.2150000000129,
"styleRecalcs": 9,
"styleRecalcDurationMs": 9.347000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 789.5790000000001,
"heapDeltaBytes": 6992712,
"heapUsedBytes": 68174632,
"domNodes": -284,
"jsHeapTotalBytes": 3510272,
"scriptDurationMs": 135.25400000000002,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "minimap-idle",
"durationMs": 2044.7869999999284,
"styleRecalcs": 6,
"styleRecalcDurationMs": 5.447,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 875.084,
"heapDeltaBytes": 6714988,
"heapUsedBytes": 68164300,
"domNodes": -283,
"jsHeapTotalBytes": 3248128,
"scriptDurationMs": 147.316,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 701.1439999999993,
"styleRecalcs": 46,
"styleRecalcDurationMs": 13.812999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 464.995,
"heapDeltaBytes": -10926264,
"heapUsedBytes": 53486816,
"domNodes": 18,
"jsHeapTotalBytes": 27000832,
"scriptDurationMs": 136.84799999999998,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 701.5989999999874,
"styleRecalcs": 46,
"styleRecalcDurationMs": 11.203000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 447.491,
"heapDeltaBytes": -10628352,
"heapUsedBytes": 53737700,
"domNodes": 18,
"jsHeapTotalBytes": 25952256,
"scriptDurationMs": 126.49000000000002,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-idle",
"durationMs": 2022.849000000008,
"styleRecalcs": 10,
"styleRecalcDurationMs": 10.409000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 615.9689999999999,
"heapDeltaBytes": 5924812,
"heapUsedBytes": 70312124,
"domNodes": 20,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 22.945999999999998,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2003.2720000000381,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.947000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 626.355,
"heapDeltaBytes": 6009180,
"heapUsedBytes": 70493936,
"domNodes": 18,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 25.885,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66999999999998,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1739.689999999996,
"styleRecalcs": 78,
"styleRecalcDurationMs": 43.616,
"layouts": 16,
"layoutDurationMs": 5.014,
"taskDurationMs": 856.0530000000001,
"heapDeltaBytes": -3880044,
"heapUsedBytes": 60631956,
"domNodes": 64,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 104.46900000000001,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1759.2420000000857,
"styleRecalcs": 75,
"styleRecalcDurationMs": 38.690000000000005,
"layouts": 16,
"layoutDurationMs": 4.538,
"taskDurationMs": 910.0380000000001,
"heapDeltaBytes": -3469588,
"heapUsedBytes": 60943860,
"domNodes": 60,
"jsHeapTotalBytes": 25690112,
"scriptDurationMs": 104.50899999999999,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 1434.00900000006,
"styleRecalcs": 17,
"styleRecalcDurationMs": 32.483,
"layouts": 13,
"layoutDurationMs": 12.671999999999999,
"taskDurationMs": 1059.556,
"heapDeltaBytes": 30647432,
"heapUsedBytes": 99384920,
"domNodes": 13673,
"jsHeapTotalBytes": 15990784,
"scriptDurationMs": 42.978,
"eventListeners": 2375,
"totalBlockingTimeMs": 144,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 9345.786000000033,
"styleRecalcs": 249,
"styleRecalcDurationMs": 40.403999999999996,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 5320.048999999999,
"heapDeltaBytes": 25607160,
"heapUsedBytes": 85663024,
"domNodes": -284,
"jsHeapTotalBytes": 4751360,
"scriptDurationMs": 1651.213,
"eventListeners": -159,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 9286.195000000022,
"styleRecalcs": 249,
"styleRecalcDurationMs": 39.449,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 5288.817000000001,
"heapDeltaBytes": 24255740,
"heapUsedBytes": 83634612,
"domNodes": -283,
"jsHeapTotalBytes": 6062080,
"scriptDurationMs": 1676.473,
"eventListeners": -131,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.80000000000109
},
{
"name": "vue-large-graph-idle",
"durationMs": 17662.14000000002,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17641.353,
"heapDeltaBytes": -39335980,
"heapUsedBytes": 166796360,
"domNodes": -8312,
"jsHeapTotalBytes": -7540736,
"scriptDurationMs": 630.7609999999999,
"eventListeners": -16387,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 17734.185000000027,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17713.847,
"heapDeltaBytes": -40789892,
"heapUsedBytes": 167485336,
"domNodes": -8312,
"jsHeapTotalBytes": -8855552,
"scriptDurationMs": 609.4300000000001,
"eventListeners": -16387,
"totalBlockingTimeMs": 0,
"frameDurationMs": 18.89333333333331,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 21051.84799999995,
"styleRecalcs": 143,
"styleRecalcDurationMs": 19.17199999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21025.058999999997,
"heapDeltaBytes": -41589604,
"heapUsedBytes": 176669464,
"domNodes": -8312,
"jsHeapTotalBytes": -8396800,
"scriptDurationMs": 972.3410000000001,
"eventListeners": -16383,
"totalBlockingTimeMs": 357,
"frameDurationMs": 18.333333333333332,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 21949.34599999999,
"styleRecalcs": 158,
"styleRecalcDurationMs": 22.713999999999956,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21915.004,
"heapDeltaBytes": -41867168,
"heapUsedBytes": 164515848,
"domNodes": -8312,
"jsHeapTotalBytes": -11968512,
"scriptDurationMs": 992.7839999999999,
"eventListeners": -16379,
"totalBlockingTimeMs": 459,
"frameDurationMs": 17.776666666666763,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 468.87199999991935,
"styleRecalcs": 13,
"styleRecalcDurationMs": 24.334999999999997,
"layouts": 3,
"layoutDurationMs": 0.667,
"taskDurationMs": 134.61200000000002,
"heapDeltaBytes": 5329912,
"heapUsedBytes": 68620528,
"domNodes": 132,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 13.287000000000003,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 473.07499999999436,
"styleRecalcs": 13,
"styleRecalcDurationMs": 23.413000000000004,
"layouts": 3,
"layoutDurationMs": 0.788,
"taskDurationMs": 124.294,
"heapDeltaBytes": 5092908,
"heapUsedBytes": 68543788,
"domNodes": 123,
"jsHeapTotalBytes": 4718592,
"scriptDurationMs": 11.488999999999999,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
}
]
} |
📝 WalkthroughWalkthroughBilling operations now centralize progress-toast handling. Payment verification states replace processing toasts with warning toasts, use new localized messages, display an exclamation icon, and avoid repeated announcements during polling. ChangesBilling action-required toast flow
Estimated code review effort: 2 (Simple) | ~15 minutes Sequence Diagram(s)sequenceDiagram
participant BillingOperationStore
participant ToastSystem
participant GlobalToast
BillingOperationStore->>ToastSystem: start billing operation
ToastSystem->>GlobalToast: show processing or action-required toast
BillingOperationStore->>ToastSystem: update payment action URL state
ToastSystem->>GlobalToast: replace the current progress toast
Possibly related PRs
Suggested labels: Suggested reviewers: Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 inconclusive)
✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
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/components/toast/GlobalToast.vue`:
- Around line 6-12: Add aria-hidden="true" to both decorative <i> elements in
the toast severity rendering within GlobalToast.vue, including the warning icon
and spinner, so assistive technology announces only the toast summary.
In `@src/platform/workspace/stores/billingOperationStore.test.ts`:
- Around line 701-727: Update the bank-challenge toast tests around
startOperation, including the cases at lines 729-754 and 756-780, to use the
real i18n plugin/backend instead of the mocked t function from `@/i18n`. Assert
each toast’s rendered summary value from the configured translations rather than
raw billingOperation.* translation keys, while preserving the existing toast
behavior assertions.
In `@src/platform/workspace/stores/billingOperationStore.ts`:
- Around line 285-301: Preserve the existing actionUrl in the operation update
when a pending response omits action_url. Update the logic around
authenticationRequiredSeen and the operations.value Map set so a valid new URL
replaces it, null clears it only for successful or terminal-failure responses,
and pending responses retain the prior URL.
🪄 Autofix
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: c4b7af60-31a2-4679-b0a6-087617b8b277
📒 Files selected for processing (4)
src/components/toast/GlobalToast.vuesrc/locales/en/main.jsonsrc/platform/workspace/stores/billingOperationStore.test.tssrc/platform/workspace/stores/billingOperationStore.ts
The icon carries no information the summary does not, so announcing it only adds noise. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks — went through all three. One applied, two declined with reasons. 1.
|
Codecov Report❌ Patch coverage is
@@ Coverage Diff @@
## main #14910 +/- ##
==========================================
- Coverage 78.98% 78.80% -0.18%
==========================================
Files 1866 1866
Lines 111132 112209 +1077
Branches 31445 32521 +1076
==========================================
+ Hits 87779 88431 +652
- Misses 22886 23286 +400
- Partials 467 492 +25
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 380 files with indirect coverage changes 🚀 New features to boost your workflow:
|
dante01yoon
left a comment
There was a problem hiding this comment.
I verified the backend rather than assuming the mocked sequence: Cloud’s OpenAPI contract does define action_url as the current deterministic signal that a pending operation cannot proceed without the customer, and the handler returns the persisted URL while the operation is pending. So deriving the UI from the current server field is valid. I’m not ready to approve the implementation yet for two reasons.
Unanchored:
- issue: This behavior still consumes a handwritten
BillingOpStatusResponseinsrc/platform/workspace/api/workspaceApi.ts, even though@comfyorg/ingest-typesalready exports the generated contract. Because this change adds UI behavior that depends on the exact semantics ofaction_url, please use the generated response type rather than a duplicate frontend contract. - question: The PR has no linked issue, production report, or real-app AS IS/TO BE capture. The added unit test proves the frontend behaves for a mocked response, but not that the stale toast is occurring in the actual 3DS flow. Could you add a real reproduction/capture or link the evidence that established the bug?
The toast keyed on authenticationRequiredSeen, a sticky flag that never returns to false, so it relied on the server retaining the URL for every pending poll. The contract does not promise that: action_url is defined as present exactly while the operation cannot proceed without the customer, and absent otherwise. Keying on the sticky flag could therefore leave the toast asking for verification after the action it points at had gone. Track the current field instead, swapping only when the answer changes so a dismissed toast does not return on every poll. authenticationRequiredSeen goes back to carrying only polling cadence and timeout. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks for verifying the backend rather than taking the mocked sequence at face value — the inline point was right and is fixed in f034138 (reply in that thread). The two unanchored points: Generated type — already the case
// src/platform/workspace/api/workspaceApi.ts:1-35
import type {
...
BillingOpStatusResponse,
...
} from '@comfyorg/ingest-types'
// :148
export type { BillingOpStatusResponse }So ReproductionFair — the unit tests prove the store's behaviour against a mocked response, not that the state occurs. It does; I reproduced it end to end on a fresh workspace before writing the fix. Steps (any environment in Stripe test mode):
AS IS — the toast reads "Processing payment — setting up your workspace..." with a spinner, for the entire time the operation is waiting on the customer. It sits next to the "Complete verification" affordance rendered from the same TO BE — "Verify your payment to finish setting up your workspace" with a prompt icon, for as long as Worth adding: the parked state is also reached before any payment exists — an operation waiting for the customer to finish checkout shows the same "Processing payment" copy with no charge having been attempted. Same root cause, same fix. I've added the reproduction to the PR description. The detailed capture (screenshots, timings, operation IDs) is from an internal environment so I've kept it out of a public repo — happy to share it internally, and to link the tracking issue there. For completeness on the timing question that motivated this: once the challenge is completed, activation is automatic and fast — the grant landed 2 seconds after the challenge in my run. Nothing is stuck; the copy just says otherwise while the customer is the one being waited on. |
dante01yoon
left a comment
There was a problem hiding this comment.
Re-reviewed the current action_url-driven implementation. The generated backend contract defines action_url as the current customer-action signal, and the toast now follows transitions of that validated field rather than the sticky authenticationRequiredSeen history. I verified initial action URLs, repeated polls, URL removal, and terminal cleanup; the focused billing-operation store suite passes all 56 tests, and the PR CI is green. I do not see a regression from this change.
Summary
The billing-operation toast is created once when the operation starts and never revised, so an operation that parks on a 3DS challenge kept announcing "Processing payment — setting up your workspace..." while it was in fact waiting on the customer.
Changes
action_url, which the generated contract defines as present exactly while a pending operation cannot proceed without the customer. The store already tracks that field and already renders a verification prompt from it — only the toast was left behind, so it contradicted the prompt beside it. The toast swaps whenever that answer changes, in either direction, so it can never outlive the action it points at.Reproduction
Any environment in Stripe test mode:
4000 0027 6000 3184.status: "pending"withaction_urlset to the Stripe-hosted invoice page.AS IS — "Processing payment — setting up your workspace..." with a spinner, for the whole time the operation waits on the customer, beside a "Complete verification" affordance rendered from the same
action_url. A reload does not clear it.TO BE — "Verify your payment to finish setting up your workspace" with a prompt icon, for as long as
action_urlis present.The same state is reached before any payment exists, when the operation is waiting for the customer to finish checkout.
Before / after
flowchart TD A["Subscription operation starts"] --> B["⟳ Processing payment —<br/>setting up your workspace…"] B --> C["Poll returns action_url<br/>(bank challenge required)"] C --> D["Before: ⟳ Processing payment —<br/>setting up your workspace…"] C --> E["After: ⚠ Verify your payment to<br/>finish setting up your workspace"] D --> F["Contradicts the 'Complete<br/>verification' prompt beside it"] E --> G["Matches the 'Complete<br/>verification' prompt beside it"] E --> H["action_url clears →<br/>reverts to processing"]Review Focus
action_url, not on the stickyauthenticationRequiredSeen— so it cannot ask for verification after the verification action has gone.authenticationRequiredSeencontinues to carry only polling cadence and the 23h timeout.severity: 'warn'only selects the icon inGlobalToast; this toast group renders through a custom#messageslot, so severity carries no other behaviour here. The state is conveyed in the summary text, not by icon or colour alone.SubscriptionPanelContentWorkspace.vue). Same fix, different surface — left for a follow-up to keep this reviewable.Verification
billingOperationStoretests: 56 passed, 4 new. Each new test fails without the store change (verified by stashing it).vitest run src/platform/workspace src/components/toast— 1075 passed.vue-tsc --noEmit,oxfmt --check,oxlint --type-aware,eslint— clean.