Skip to content

Conversation

@christian-byrne
Copy link
Contributor

@christian-byrne christian-byrne commented Dec 11, 2025

Summary

  • Replace StripePricingTable with CustomPricingTable component
  • Add intelligent subscription tier detection and button logic
  • Remove Stripe dependencies and feature flags
  • Clean up unused Stripe-related files and configurations

┆Issue is synchronized with this Notion page by Unito

@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Dec 11, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 11, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Removes Stripe pricing-table config, loader, component and tests; adds a new PricingTable component; updates the subscription dialog polling/visibility to use the new component; and exposes subscriptionStatus from the subscription composable. Also adds subscription-related locale strings.

Changes

Cohort / File(s) Summary
Stripe integration removal
src/config/stripePricingTableConfig.ts, src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
Deleted Stripe pricing-table configuration, types/constants, env helpers, and the shared composable that loaded the Stripe script.
Removed Stripe component & tests
src/platform/cloud/subscription/components/StripePricingTable.vue, tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
Removed the Vue SFC that rendered <stripe-pricing-table> and its entire unit test suite.
New custom pricing table
src/platform/cloud/subscription/components/PricingTable.vue
Added a Vue SFC rendering a responsive three-tier pricing table with per-tier actions, checkout/billing portal flows, auth checks, loading state, and error handling.
Subscription dialog & polling refactor
src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
Replaced Stripe usage with PricingTable, removed feature-flag gating for the table, and changed polling to a fixed attempt-based scheme with focus-based restart and proper cleanup.
Subscription composable API change
src/platform/cloud/subscription/composables/useSubscription.ts
Added subscriptionStatus to the returned public API of useSubscriptionInternal.
Localization additions
src/locales/en/main.json
Added subscription UI strings (e.g., usdPerMonth, mostPopular, currentPlan, subscribeTo, labels for credits/max duration/GPU/LoRA, videoEstimate entries, upgradeTo, changeTo) and credits/maxDuration objects per tier.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant UI as PricingTable (component)
participant Auth as Auth / User session
participant Sub as useSubscription (composable)
participant API as Backend (checkout / billing portal)
Note over UI,Auth: User clicks Subscribe / Change
UI->>Auth: verify authentication
alt not authenticated
Auth-->>UI: prompt login flow
else authenticated
UI->>Sub: read subscriptionStatus / current plan
alt has active subscription
UI->>API: request billing portal URL
API-->>UI: billing portal URL
UI->>UI: open billing portal (new tab)
else no active subscription
UI->>API: request checkout URL for chosen tier
API-->>UI: checkout URL
UI->>UI: open checkout URL (new tab)
end
end
Note right of UI: show loading / error states as needed

Possibly related PRs

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch credit/custom-table

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 347068c and d3afe2b.

📒 Files selected for processing (2)
  • src/platform/cloud/subscription/components/PricingTable.vue (1 hunks)
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue (7 hunks)

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

@github-actions
Copy link

github-actions bot commented Dec 11, 2025

🎭 Playwright Test Results

Some tests failed

⏰ Completed at: 12/11/2025, 09:21:43 AM UTC

📈 Summary

  • Total Tests: 490
  • Passed: 471 ✅
  • Failed: 2 ❌
  • Flaky: 8 ⚠️
  • Skipped: 9 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 462 / ❌ 2 / ⚠️ 8 / ⏭️ 9
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 6 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@github-actions
Copy link

github-actions bot commented Dec 11, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 12/11/2025, 09:12:17 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Dec 11, 2025

Bundle Size Report

Summary

  • Raw size: 17.1 MB baseline 17.1 MB — 🔴 +839 B
  • Gzip: 3.39 MB baseline 3.39 MB — 🔴 +197 B
  • Brotli: 2.6 MB baseline 2.6 MB — 🟢 -159 B
  • Bundles: 97 current • 97 baseline • 39 added / 39 removed

Category Glance
App Entry Points 🔴 +839 B (3.23 MB) · Vendor & Third-Party ⚪ 0 B (8.56 MB) · Other ⚪ 0 B (3.81 MB) · Graph Workspace ⚪ 0 B (992 kB) · Panels & Settings ⚪ 0 B (298 kB) · UI Components ⚪ 0 B (178 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.23 MB (baseline 3.23 MB) • 🔴 +839 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-DzS1FniT.js (new) 3.01 MB 🔴 +3.01 MB 🔴 +625 kB 🔴 +475 kB
assets/index-BHsc0MXr.js (removed) 3 MB 🟢 -3 MB 🟢 -625 kB 🟢 -475 kB
assets/index-CcOIReC2.js (removed) 224 kB 🟢 -224 kB 🟢 -47.7 kB 🟢 -39.4 kB
assets/index-yI51RxH2.js (new) 224 kB 🔴 +224 kB 🔴 +47.7 kB 🔴 +39.3 kB
assets/index-Bh3ac-Vo.js (new) 345 B 🔴 +345 B 🔴 +244 B 🔴 +209 B
assets/index-C16Zi5Qk.js (removed) 345 B 🟢 -345 B 🟢 -246 B 🟢 -208 B

Status: 3 added / 3 removed

Graph Workspace — 992 kB (baseline 992 kB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-Ci0x0wUd.js (new) 992 kB 🔴 +992 kB 🔴 +192 kB 🔴 +146 kB
assets/GraphView-DS71kz1b.js (removed) 992 kB 🟢 -992 kB 🟢 -192 kB 🟢 -146 kB

Status: 1 added / 1 removed

Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/UserSelectView-BOptmO62.js (removed) 6.54 kB 🟢 -6.54 kB 🟢 -2.14 kB 🟢 -1.91 kB
assets/UserSelectView-C-ED9uS8.js (new) 6.54 kB 🔴 +6.54 kB 🔴 +2.14 kB 🔴 +1.91 kB

Status: 1 added / 1 removed

Panels & Settings — 298 kB (baseline 298 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LegacyCreditsPanel-B0hPQtG8.js (removed) 21.4 kB 🟢 -21.4 kB 🟢 -5.16 kB 🟢 -4.5 kB
assets/LegacyCreditsPanel-COdLGi-M.js (new) 21.4 kB 🔴 +21.4 kB 🔴 +5.15 kB 🔴 +4.5 kB
assets/KeybindingPanel-D6tmfvAX.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.42 kB 🟢 -3.02 kB
assets/KeybindingPanel-DEuYN9Nf.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.42 kB 🔴 +3.02 kB
assets/ExtensionPanel-BYNO_7yu.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.57 kB 🔴 +2.26 kB
assets/ExtensionPanel-Ce9hstJq.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.57 kB 🟢 -2.26 kB
assets/AboutPanel-D__EnuXS.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/AboutPanel-DSTS_fv_.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/ServerConfigPanel-B_m2TTfT.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +1.83 kB 🔴 +1.63 kB
assets/ServerConfigPanel-DQu59C15.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -1.83 kB 🟢 -1.63 kB
assets/UserPanel-bD8T4Hq7.js (removed) 6.23 kB 🟢 -6.23 kB 🟢 -1.72 kB 🟢 -1.51 kB
assets/UserPanel-DGUh2s81.js (new) 6.23 kB 🔴 +6.23 kB 🔴 +1.72 kB 🔴 +1.51 kB
assets/settings-BhbWhsRg.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BXTtSH4O.js 33.3 kB 33.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C9Pzn-NG.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CCy2fA_h.js 27.3 kB 27.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CQpqEFfl.js 26.6 kB 26.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DHcnxypw.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DhFTK9fY.js 25.1 kB 25.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DlT4t_ui.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DRgSrIdD.js 24.2 kB 24.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-tjkeqiZq.js 21.1 kB 21.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

UI Components — 178 kB (baseline 178 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Load3D.vue_vue_type_script_setup_true_lang-L1GIDDRs.js (removed) 53.7 kB 🟢 -53.7 kB 🟢 -8.49 kB 🟢 -7.3 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-oOjWgJQa.js (new) 53.7 kB 🔴 +53.7 kB 🔴 +8.49 kB 🔴 +7.29 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-DjHJZ4t8.js (new) 48.1 kB 🔴 +48.1 kB 🔴 +10.4 kB 🔴 +8.99 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-DklmsXkZ.js (removed) 48.1 kB 🟢 -48.1 kB 🟢 -10.4 kB 🟢 -8.98 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-rVEIyjZV.js (removed) 48 kB 🟢 -48 kB 🟢 -10.7 kB 🟢 -9.32 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-uHYIkz3Q.js (new) 48 kB 🔴 +48 kB 🔴 +10.7 kB 🔴 +9.32 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-D5vfQsYV.js (removed) 12.9 kB 🟢 -12.9 kB 🟢 -3.37 kB 🟢 -2.98 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-jg9zxxim.js (new) 12.9 kB 🔴 +12.9 kB 🔴 +3.37 kB 🔴 +2.96 kB
assets/ComfyQueueButton-DfdOHzXE.js (removed) 8.44 kB 🟢 -8.44 kB 🟢 -2.48 kB 🟢 -2.21 kB
assets/ComfyQueueButton-yovSigWi.js (new) 8.44 kB 🔴 +8.44 kB 🔴 +2.48 kB 🔴 +2.21 kB
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-BRhtUT90.js (new) 2.47 kB 🔴 +2.47 kB 🔴 +936 B 🔴 +808 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-BxCTPwGi.js (removed) 2.47 kB 🟢 -2.47 kB 🟢 -936 B 🟢 -804 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-Buqomh9L.js (new) 897 B 🔴 +897 B 🔴 +502 B 🔴 +445 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-DwyN3R51.js (removed) 897 B 🟢 -897 B 🟢 -504 B 🟢 -432 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-Cwpu8HZY.js 1.34 kB 1.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-DF5qH0wo.js 2.04 kB 2.04 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 7 added / 7 removed

Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-Cy2s_yJq.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/keybindingService-DBJ1iJ9A.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.83 kB 🟢 -1.58 kB
assets/audioService-BnJVt_xR.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +961 B 🔴 +830 B
assets/audioService-DlQdXM8g.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -962 B 🟢 -826 B
assets/serverConfigStore-BHXc4r-I.js 2.83 kB 2.83 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 2 added / 2 removed

Utilities & Hooks — 3.18 kB (baseline 3.18 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-B4qwUMeY.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -652 B 🟢 -550 B
assets/audioUtils-Dn8fJ0up.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +649 B 🔴 +548 B
assets/mathUtil-CD4DsosH.js 1.32 kB 1.32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeFilterUtil-CXKCRJ-m.js 460 B 460 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 1 added / 1 removed

Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-chart-CLbS5yW5.js 452 kB 452 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-DTTVAq37.js 3.98 MB 3.98 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-BOn_1tHb.js 1.96 MB 1.96 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-aR6ntw5X.js 1.37 MB 1.37 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-CvMnMneH.js 232 kB 232 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-C5KrCLZ4.js 160 kB 160 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-BZLod3g9.js 407 kB 407 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 3.81 MB (baseline 3.81 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WidgetRecordAudio-DaCcCX5Y.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.23 kB 🟢 -4.62 kB
assets/WidgetRecordAudio-DArRPXeY.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.23 kB 🔴 +4.63 kB
assets/AudioPreviewPlayer-DQxVCuo1.js (new) 13.4 kB 🔴 +13.4 kB 🔴 +3.37 kB 🔴 +3.01 kB
assets/AudioPreviewPlayer-Yu7a3445.js (removed) 13.4 kB 🟢 -13.4 kB 🟢 -3.37 kB 🟢 -3.01 kB
assets/WidgetGalleria-CIvmOh4h.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.45 kB 🔴 +1.31 kB
assets/WidgetGalleria-DN6T8PNM.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.45 kB 🟢 -1.31 kB
assets/WidgetColorPicker-DLVUnkfs.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetColorPicker-DXk6I0KZ.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetTextarea-BheX5nZx.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.22 kB 🟢 -1.09 kB
assets/WidgetTextarea-DbIn69ZZ.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.22 kB 🔴 +1.07 kB
assets/WidgetMarkdown-DmNojBgV.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/WidgetMarkdown-IlkYwq1d.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetAudioUI-aEdAK-lZ.js (removed) 2.85 kB 🟢 -2.85 kB 🟢 -1.17 kB 🟢 -1.05 kB
assets/WidgetAudioUI-w4rxebtZ.js (new) 2.85 kB 🔴 +2.85 kB 🔴 +1.17 kB 🔴 +1.05 kB
assets/WidgetInputText-BUm_v3Yc.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +917 B 🔴 +825 B
assets/WidgetInputText-CkS8gL4v.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -919 B 🟢 -848 B
assets/WidgetToggleSwitch-Btzy60xt.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -834 B 🟢 -729 B
assets/WidgetToggleSwitch-qdiGv9Ke.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +834 B 🔴 +729 B
assets/MediaImageBottom-2-5gKY48.js (new) 1.55 kB 🔴 +1.55 kB 🔴 +736 B 🔴 +641 B
assets/MediaImageBottom-Bbe0rU_n.js (removed) 1.55 kB 🟢 -1.55 kB 🟢 -732 B 🟢 -642 B
assets/MediaAudioBottom-BgJ-AIlw.js (removed) 1.51 kB 🟢 -1.51 kB 🟢 -734 B 🟢 -651 B
assets/MediaAudioBottom-C19aPYOa.js (new) 1.51 kB 🔴 +1.51 kB 🔴 +733 B 🔴 +651 B
assets/Media3DBottom-C1DqseVo.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -731 B 🟢 -649 B
assets/Media3DBottom-Cz2Hclnf.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +731 B 🔴 +651 B
assets/MediaVideoBottom-B-daK0T6.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -731 B 🟢 -650 B
assets/MediaVideoBottom-C1DBz89O.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +732 B 🔴 +656 B
assets/Media3DTop-13LSRibZ.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +766 B 🔴 +653 B
assets/Media3DTop-DIR96hN-.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -766 B 🟢 -648 B
assets/WidgetSelect-BJqV6oSx.js (new) 655 B 🔴 +655 B 🔴 +345 B 🔴 +288 B
assets/WidgetSelect-c-1kMniv.js (removed) 655 B 🟢 -655 B 🟢 -344 B 🟢 -288 B
assets/WidgetInputNumber-BnL-3_rV.js (removed) 595 B 🟢 -595 B 🟢 -329 B 🟢 -277 B
assets/WidgetInputNumber-C5sgWRUq.js (new) 595 B 🔴 +595 B 🔴 +329 B 🔴 +276 B
assets/Load3D-2YjfPa6C.js (new) 424 B 🔴 +424 B 🔴 +270 B 🔴 +223 B
assets/Load3D-I99BoxTt.js (removed) 424 B 🟢 -424 B 🟢 -267 B 🟢 -229 B
assets/WidgetLegacy-Ce633oUh.js (new) 364 B 🔴 +364 B 🔴 +238 B 🔴 +194 B
assets/WidgetLegacy-CLxQX52L.js (removed) 364 B 🟢 -364 B 🟢 -237 B 🟢 -194 B
assets/commands-_s-RvhJR.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BuUILW6P.js 13 kB 13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BV4R6fLx.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BWp4HdfU.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CLwPdnT6.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CWMchBmd.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DazTQhtc.js 12.9 kB 12.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DmWrOe93.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DwiH7Kr6.js 13.8 kB 13.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-mS3LCNPn.js 14.5 kB 14.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BMi-Aksj.js 99 kB 99 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CqR8skJT.js 73.1 kB 73.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cw9RZWRY.js 89 B 89 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DcRHAFEy.js 81.7 kB 81.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DdFdLxku.js 72.2 kB 72.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DJAtuVu5.js 84.3 kB 84.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DK8I9Rk3.js 114 kB 114 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-gP_ssnMb.js 83.4 kB 83.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-nxXY9vGp.js 94 kB 94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Ycd3gqkA.js 86.5 kB 86.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-DBM2-uF8.js 1.46 kB 1.46 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-Dv8etOwH.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-DPTn18Gu.js 2.65 kB 2.65 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BC3OlaIn.js 342 kB 342 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BsqN8-W1.js 285 kB 285 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bw_Jitw_.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CK2saYDx.js 307 kB 307 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Cm5kR4Hi.js 306 kB 306 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CMrh-uxB.js 310 kB 310 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DlUIOit1.js 369 kB 369 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DNu_xoP2.js 282 kB 282 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DpcvlpZe.js 303 kB 303 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-IyjOYIl-.js 317 kB 317 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-BAE_xj62.js 2.48 kB 2.48 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-CoEHTkmg.js 2.21 kB 2.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 18 added / 18 removed

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/locales/en/main.json (1)

1954-1965: Missing videoEstimate in creator tier benefits.

The standard and pro tiers include a videoEstimate in their benefits (visible in existing structure), but the creator tier does not. This causes a hardcoded fallback value '288' in CustomPricingTable.vue (line 198). Consider adding the videoEstimate field to the creator tier benefits for consistency and to avoid hardcoded values in the component.

       "creator": {
         "name": "Creator",
         "price": "35.00",
         "benefits": {
           "monthlyCredits": "7,400",
           "monthlyCreditsLabel": "monthly credits",
           "maxDuration": "30 min",
           "maxDurationLabel": "max duration of each workflow run",
           "gpuLabel": "RTX 6000 Pro (96GB VRAM)",
           "addCreditsLabel": "Add more credits whenever",
-          "customLoRAsLabel": "Import your own LoRAs"
+          "customLoRAsLabel": "Import your own LoRAs",
+          "videoEstimate": "288"
         }
       },
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b2df19 and b02a620.

📒 Files selected for processing (8)
  • src/config/stripePricingTableConfig.ts (0 hunks)
  • src/locales/en/main.json (2 hunks)
  • src/platform/cloud/subscription/components/CustomPricingTable.vue (1 hunks)
  • src/platform/cloud/subscription/components/StripePricingTable.vue (0 hunks)
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue (6 hunks)
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts (0 hunks)
  • src/platform/cloud/subscription/composables/useSubscription.ts (1 hunks)
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts (0 hunks)
💤 Files with no reviewable changes (4)
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
  • src/config/stripePricingTableConfig.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
🧰 Additional context used
📓 Path-based instructions (11)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Minimize the surface area (exported values) of each module and composable

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/locales/en/main.json
  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
🧠 Learnings (14)
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks

Applied to files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guide

Applied to files:

  • src/platform/cloud/subscription/components/CustomPricingTable.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/platform/cloud/subscription/components/CustomPricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Implement computed properties with `computed()` from Vue; avoid using a `ref` with a `watch` if a `computed` would work instead

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Implement computed() for derived state in Vue 3 Composition API

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Extract complex conditionals to computed properties

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Be judicious with addition of new refs or other state: prefer props, avoid redundant `computed`, and prefer `computed` over `watch`

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement computed properties with computed()

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint-and-format
  • GitHub Check: test
  • GitHub Check: collect
  • GitHub Check: setup
🔇 Additional comments (4)
src/platform/cloud/subscription/composables/useSubscription.ts (1)

221-239: LGTM!

Exposing subscriptionStatus alongside the existing state is appropriate for the new CustomPricingTable component's needs. The shared composable pattern ensures proper state management, and cleanup is handled in the existing watch on logout.

src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue (1)

178-215: Polling logic is sound but consider edge case.

The polling implementation with MAX_POLL_ATTEMPTS = 3 is cleaner than time-based. However, note that if a user triggers the dialog multiple times in quick succession (close and reopen), the pollAttempts counter resets correctly via startPolling(), but the fetch continues asynchronously. This is generally fine since fetchStatus updates shared state.

One minor observation: the pollAttempts variable on line 181 is a plain let rather than a ref, which is acceptable here since it's only used internally for control flow and doesn't need reactivity.

src/platform/cloud/subscription/components/CustomPricingTable.vue (2)

316-343: LGTM on error handling.

The handleSubscribe function properly uses wrapWithErrorHandlingAsync for error reporting and the finally block ensures loading state is always reset. The early return after accessBillingPortal() for existing subscribers is handled correctly since finally still executes.


1-134: Template structure is well-organized.

The pricing card layout is clean and accessible. The feature checkmarks/crosses are decorative since they accompany text labels, so no additional aria-labels are needed. The Button component receives proper labels via the getButtonLabel function.

- Replace StripePricingTable with CustomPricingTable component
- Add intelligent subscription tier detection and button logic
- Remove Stripe dependencies and feature flags
- Update subscription dialog to use custom component

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@christian-byrne christian-byrne added needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch cloud/1.34 Backport PRs for cloud 1.34 labels Dec 11, 2025
Ensures parsing errors are caught by surrounding try-catch for
consistent error handling
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue (1)

178-215: Consider making pollAttempts a ref or resetting it more defensively.

The pollAttempts variable is declared with let (line 181) but isn't reactive. While this works since it's only used procedurally within startPolling/poll, the current implementation has a subtle timing behavior:

  1. poll() is called immediately (line 211) → pollAttempts becomes 1
  2. If < 3 attempts, interval fires after 3s → pollAttempts becomes 2
  3. After another 3s → pollAttempts becomes 3, polling stops

This means polling runs for ~6 seconds with 3 attempts at t=0, t=3s, t=6s. If the intent was 3 poll intervals (9 seconds total), the immediate poll() call shouldn't increment the counter, or MAX_POLL_ATTEMPTS should be 4.

If 3 interval-based polls were intended:

 const poll = async () => {
   try {
     await fetchStatus()
-    pollAttempts++
-
-    if (pollAttempts >= MAX_POLL_ATTEMPTS) {
-      stopPolling()
-    }
   } catch (error) {
     console.error(
       '[SubscriptionDialog] Failed to poll subscription status',
       error
     )
     stopPolling()
   }
 }

 void poll()
 pollInterval = window.setInterval(() => {
+  pollAttempts++
+  if (pollAttempts >= MAX_POLL_ATTEMPTS) {
+    stopPolling()
+    return
+  }
   void poll()
 }, POLL_INTERVAL_MS)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b02a620 and 65a6cca.

📒 Files selected for processing (8)
  • src/config/stripePricingTableConfig.ts (0 hunks)
  • src/locales/en/main.json (2 hunks)
  • src/platform/cloud/subscription/components/PricingTable.vue (1 hunks)
  • src/platform/cloud/subscription/components/StripePricingTable.vue (0 hunks)
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue (6 hunks)
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts (0 hunks)
  • src/platform/cloud/subscription/composables/useSubscription.ts (1 hunks)
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts (0 hunks)
💤 Files with no reviewable changes (4)
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/config/stripePricingTableConfig.ts
🧰 Additional context used
📓 Path-based instructions (11)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Minimize the surface area (exported values) of each module and composable

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/locales/en/main.json
  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
🧠 Learnings (13)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/platform/cloud/subscription/composables/useSubscription.ts
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Implement computed properties with `computed()` from Vue; avoid using a `ref` with a `watch` if a `computed` would work instead

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Implement computed() for derived state in Vue 3 Composition API

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Extract complex conditionals to computed properties

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Be judicious with addition of new refs or other state: prefer props, avoid redundant `computed`, and prefer `computed` over `watch`

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement computed properties with computed()

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint-and-format
  • GitHub Check: setup
  • GitHub Check: test
  • GitHub Check: collect
🔇 Additional comments (5)
src/platform/cloud/subscription/composables/useSubscription.ts (1)

245-245: LGTM!

Exposing subscriptionStatus in the return object is a clean way to provide downstream components (like the new PricingTable.vue) access to the raw subscription state without duplicating fetch logic.

src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue (1)

173-176: LGTM!

Clean simplification removing the feature flag gating. The computed property now correctly shows the custom pricing table for all cloud distributions with subscription_required enabled.

src/locales/en/main.json (1)

1998-2012: LGTM!

The new locale keys are well-structured and properly support the custom pricing table component. The interpolation placeholders ({plan}) in subscribeTo, upgradeTo, and changeTo are correctly defined.

src/platform/cloud/subscription/components/PricingTable.vue (2)

237-259: Verify tier change UX: button shows "Change to {plan}" but redirects to billing portal.

When a user has an active subscription and clicks "Change to Pro", the tierKey parameter is captured but not used—the function always calls accessBillingPortal() without passing the target tier. This may be intentional (Stripe portal handles upgrades), but the button label "Change to {plan}" suggests a direct tier change action.

Please confirm this is the intended UX. If users expect clicking "Change to Pro" to initiate a direct upgrade rather than navigating to the generic billing portal, consider passing the tier to the backend or clarifying the button label.


1-111: Template structure and styling look good.

The component follows Vue 3 Composition API patterns, uses Tailwind for styling as per guidelines, and properly leverages i18n for user-facing strings. The responsive flex layout with tier cards is well-structured.

@github-actions
Copy link

🔧 Auto-fixes Applied

This PR has been automatically updated to fix linting and formatting issues.

⚠️ Important: Your local branch is now behind. Run git pull before making additional changes to avoid conflicts.

Changes made:

  • ESLint auto-fixes
  • Prettier formatting

- Add videoEstimate keys to all tier benefits in main.json
- Replace hardcoded '288' with proper i18n call for creator tier
- Ensures all tiers use consistent localization patterns
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/platform/cloud/subscription/components/PricingTable.vue (2)

167-201: tiers array is not reactive—locale changes won't update tier names.

The tiers array calls t() at module initialization time. If the user's locale changes at runtime, these strings won't update.

Wrap tiers in a computed():

-const tiers: PricingTierConfig[] = [
+const tiers = computed<PricingTierConfig[]>(() => [
   // ... tier configs
-]
+])

Then update template to use tiers.value in the v-for.


187-187: Hardcoded videoEstimate for creator tier breaks i18n consistency.

Line 187 has videoEstimate: '288' hardcoded while other tiers use t(). This breaks i18n support.

-    videoEstimate: '288',
+    videoEstimate: t('subscription.tiers.creator.benefits.videoEstimate'),

Ensure the corresponding locale key exists in main.json.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65a6cca and ffd2adf.

📒 Files selected for processing (1)
  • src/platform/cloud/subscription/components/PricingTable.vue (1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks
📚 Learning: 2025-12-05T20:35:28.330Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/locales/en/main.json:2257-2272
Timestamp: 2025-12-05T20:35:28.330Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, vue-i18n pluralization uses a two-parameter pattern: `t('key', { count: value })` where the `count` property in the interpolation object automatically triggers plural selection from pipe-separated locale strings (e.g., "no items | 1 item | {count} items"). This is the correct pattern used throughout the codebase, as validated by Playwright tests.

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{components,composables}/**/*.{ts,tsx,vue} : Use vue-i18n for ALL user-facing strings by adding them to `src/locales/en/main.json`

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Use vue-i18n in composition API for any string literals; place new translation entries in `src/locales/en/main.json`

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Implement computed properties with `computed()` from Vue; avoid using a `ref` with a `watch` if a `computed` would work instead

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
🔇 Additional comments (2)
src/platform/cloud/subscription/components/PricingTable.vue (2)

258-277: LGTM!

The handleSubscribe function correctly:

  • Guards against invalid states (non-cloud, loading, current plan)
  • Manages loading state with try/finally
  • Routes existing subscribers to billing portal vs. new checkout
  • Uses error handling wrapper for consistent error reporting

111-123: PrimeVue Button usage in this component is acceptable for now.

The custom button components (TextButton, IconTextButton, IconButton) do not support the severity and loading props required here. Until Reka UI button components are integrated (the library is installed but not yet configured for button usage), PrimeVue Button remains the only viable option for handling subscription state styling and async loading states.

Consider this component as a candidate for refactoring once alternative button components with full feature parity are available.

- Wrap response.json() in try-catch to handle non-JSON responses
- Fall back to response.text() and HTTP status information
- Preserve original HTTP error details instead of masking with JSON parse errors
- Ensure robust error reporting for HTML/text responses from server
@github-actions
Copy link

🔧 Auto-fixes Applied

This PR has been automatically updated to fix linting and formatting issues.

⚠️ Important: Your local branch is now behind. Run git pull before making additional changes to avoid conflicts.

Changes made:

  • ESLint auto-fixes
  • Prettier formatting

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/platform/cloud/subscription/components/PricingTable.vue (1)

167-201: tiers array should be reactive for locale changes.

The tiers array calls t() at module initialization time. If the user's locale changes at runtime, these strings won't update.

Wrap in computed():

-const tiers: PricingTierConfig[] = [
+const tiers = computed<PricingTierConfig[]>(() => [
   {
     id: 'STANDARD',
     key: 'standard',
     name: t('subscription.tiers.standard.name'),
     // ... rest
   },
   // ... other tiers
-]
+])

Then update the template's v-for to use tiers.value.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ffd2adf and 347068c.

📒 Files selected for processing (2)
  • src/locales/en/main.json (5 hunks)
  • src/platform/cloud/subscription/components/PricingTable.vue (1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs (Single File Components) with Composition API only; do not use Options API
Vue components must use <script setup lang="ts"> for component logic
Use Vue 3.5 TypeScript style for default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer useModel to separately defining a prop and emit
Use Tailwind 4 utility classes for styling; avoid using <style> blocks in Vue components
Use semantic Tailwind values from style.css theme instead of the dark: variant; for example, use bg-node-component-surface instead of dark: prefixes
Always use cn() utility from @/utils/tailwindUtil to merge Tailwind class names; do not use :class="[]" syntax
Use ref for reactive state in Vue Composition API components
Implement computed properties with computed() from Vue; avoid using a ref with a watch if a computed would work instead
Use watch and watchEffect for side effects in Vue components
Implement lifecycle hooks using onMounted, onUpdated, and other Vue lifecycle functions
Use provide/inject for dependency injection; do not use dependency injection if a Store or shared composable would be simpler
Do not import Vue macros unnecessarily; only use when needed
Be judicious with addition of new refs or other state: prefer props, avoid redundant computed, and prefer computed over watch
Use VueUse functions for performance-enhancing styles
In Vue Components, implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Implement proper error handling in Vue components
Follow Vue 3 style guide and naming conventions
Use vue-i18n in composition API for any string literals; place new translation entries in src/locales/en/main.json
Avoid new usage of PrimeVue components; prefer shadcn/vue or Reka UI instead

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
**/*.{ts,tsx,js,jsx,vue,json}

📄 CodeRabbit inference engine (AGENTS.md)

Code style: Use 2-space indentation, single quotes, no trailing semicolons, and 80-character line width (see .prettierrc)

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
  • src/locales/en/main.json
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Imports must be sorted and grouped by plugin; run pnpm format before committing
Use TypeScript for type safety; never use any type - use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Use es-toolkit for utility functions
Write code that is expressive and self-documenting; avoid comments unless absolutely necessary; do not add or retain redundant comments
Keep functions short and functional
Minimize nesting in code (e.g., deeply nested if or for statements); apply the Arrow Anti-Pattern principle
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/platform/cloud/subscription/components/PricingTable.vue
🧠 Learnings (7)
📚 Learning: 2025-12-05T20:35:28.330Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/locales/en/main.json:2257-2272
Timestamp: 2025-12-05T20:35:28.330Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, vue-i18n pluralization uses a two-parameter pattern: `t('key', { count: value })` where the `count` property in the interpolation object automatically triggers plural selection from pipe-separated locale strings (e.g., "no items | 1 item | {count} items"). This is the correct pattern used throughout the codebase, as validated by Playwright tests.

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{components,composables}/**/*.{ts,tsx,vue} : Use vue-i18n for ALL user-facing strings by adding them to `src/locales/en/main.json`

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Use vue-i18n in composition API for any string literals; place new translation entries in `src/locales/en/main.json`

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-12-09T20:22:23.620Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T20:22:23.620Z
Learning: Applies to **/*.vue : Implement computed properties with `computed()` from Vue; avoid using a `ref` with a `watch` if a `computed` would work instead

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/platform/cloud/subscription/components/PricingTable.vue
🔇 Additional comments (5)
src/locales/en/main.json (1)

2016-2025: LGTM! Locale entries are properly structured.

The new subscription strings are well-organized with tier-specific values for credits and maxDuration, and the videoEstimate keys have been added to all tier benefits as requested in the previous review.

src/platform/cloud/subscription/components/PricingTable.vue (4)

1-127: Template structure is clean and follows conventions.

The template properly uses Tailwind utility classes, i18n for labels, and handles conditional rendering for tier features. The responsive flex layout is appropriate for the pricing table.


160-165: Verify Founder's Edition to Creator mapping UX.

The FOUNDERS_EDITION is mapped to 'creator', which means users with a Founder's Edition subscription will see "Current Plan" on the Creator tier card.

If Founder's Edition has different benefits than Creator, this could confuse users who might think they're on the Creator plan. Consider:

  1. Adding a separate display for Founder's Edition users, or
  2. Confirming this mapping reflects equivalent plan benefits

211-230: Helper functions are well-structured.

The currentTierKey computed property correctly derives from subscription state, and the button label/severity functions appropriately handle the three states (current plan, new subscription, plan change).


272-291: handleSubscribe error handling is solid.

The use of wrapWithErrorHandlingAsync with reportError ensures errors are properly surfaced to users. The finally block correctly resets loading state regardless of success/failure.

- Map FOUNDERS_EDITION to 'standard' tier for current plan display
- Change polling to only start on window focus (when user returns from checkout)
- Clean up event listeners properly in onBeforeUnmount
- Improves UX by not polling immediately when dialog opens
@christian-byrne christian-byrne merged commit f5f0e20 into main Dec 11, 2025
13 of 14 checks passed
@christian-byrne christian-byrne deleted the credit/custom-table branch December 11, 2025 09:12
github-actions bot pushed a commit that referenced this pull request Dec 11, 2025
## Summary
- Replace StripePricingTable with CustomPricingTable component
- Add intelligent subscription tier detection and button logic
- Remove Stripe dependencies and feature flags
- Clean up unused Stripe-related files and configurations

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7359-feat-replace-Stripe-pricing-table-with-custom-implementation-2c66d73d365081f684d4ec81c7cc6790)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude <[email protected]>
@comfy-pr-bot
Copy link
Member

@christian-byrne Successfully backported to #7361

@github-actions github-actions bot removed the needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch label Dec 11, 2025
christian-byrne added a commit that referenced this pull request Dec 11, 2025
…implementation (#7361)

Backport of #7359 to `cloud/1.34`

Automatically created by backport workflow.

Co-authored-by: Christian Byrne <[email protected]>
Co-authored-by: Claude <[email protected]>
@github-actions
Copy link

🔧 Auto-fixes Applied

This PR has been automatically updated to fix linting and formatting issues.

⚠️ Important: Your local branch is now behind. Run git pull before making additional changes to avoid conflicts.

Changes made:

  • ESLint auto-fixes
  • Prettier formatting

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

Labels

cloud/1.34 Backport PRs for cloud 1.34 preview size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants