subscription page (#6064)

Summary

Implements cloud subscription management UI and flow for ComfyUI Cloud
users.

  Core Features:
- Subscription Status Tracking: Global reactive state management for
subscription status across all components
  using shared subscriptionStatus ref
- Subscribe to Run Button: Replaces the Run button in the actionbar with
a "Subscribe to Run" button for users
  without active subscriptions
- Subscription Required Dialog: Modal dialog with subscription benefits,
pricing, and checkout flow with video
  background
- Subscription Settings Panel: New settings panel showing subscription
status, renewal date, and quick access to
  billing management
- Auto-detection & Polling: Automatically polls subscription status
after checkout completion and syncs state
  across the application


https://github.com/user-attachments/assets/f41b8e6a-5845-48a7-8169-3a6fc0d2e5c8



┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6064-subscription-page-28d6d73d36508135a2a0fe7c94b40852)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Terry Jia
2025-10-18 23:21:30 -04:00
committed by GitHub
parent d83e34d0fc
commit 7e1e8e3b65
22 changed files with 1232 additions and 14 deletions

View File

@@ -3,6 +3,7 @@ import type { Component } from 'vue'
import { useI18n } from 'vue-i18n'
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
import { isCloud } from '@/platform/distribution/types'
import type { SettingTreeNode } from '@/platform/settings/settingStore'
import { useSettingStore } from '@/platform/settings/settingStore'
import type { SettingParams } from '@/platform/settings/types'
@@ -23,6 +24,7 @@ export function useSettingUI(
| 'server-config'
| 'user'
| 'credits'
| 'subscription'
) {
const { t } = useI18n()
const { isLoggedIn } = useCurrentUser()
@@ -78,6 +80,22 @@ export function useSettingUI(
)
}
const subscriptionPanel: SettingPanelItem | null = !isCloud
? null
: {
node: {
key: 'subscription',
label: 'PlanCredits',
children: []
},
component: defineAsyncComponent(
() =>
import(
'@/platform/cloud/subscription/components/SubscriptionPanel.vue'
)
)
}
const userPanel: SettingPanelItem = {
node: {
key: 'user',
@@ -129,7 +147,8 @@ export function useSettingUI(
userPanel,
keybindingPanel,
extensionPanel,
...(isElectron() ? [serverConfigPanel] : [])
...(isElectron() ? [serverConfigPanel] : []),
...(isCloud && subscriptionPanel ? [subscriptionPanel] : [])
].filter((panel) => panel.component)
)
@@ -155,13 +174,16 @@ export function useSettingUI(
})
const groupedMenuTreeNodes = computed<SettingTreeNode[]>(() => [
// Account settings - only show credits when user is authenticated
// Account settings - show different panels based on distribution and auth state
{
key: 'account',
label: 'Account',
children: [
userPanel.node,
...(isLoggedIn.value ? [creditsPanel.node] : [])
...(isLoggedIn.value && isCloud && subscriptionPanel
? [subscriptionPanel.node]
: []),
...(isLoggedIn.value && !isCloud ? [creditsPanel.node] : [])
].map(translateCategory)
},
// Normal settings stored in the settingStore