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

@@ -1,4 +1,5 @@
import { merge } from 'es-toolkit/compat'
import { defineAsyncComponent } from 'vue'
import type { Component } from 'vue'
import ApiNodesSignInContent from '@/components/dialog/content/ApiNodesSignInContent.vue'
@@ -13,6 +14,7 @@ import UpdatePasswordContent from '@/components/dialog/content/UpdatePasswordCon
import ComfyOrgHeader from '@/components/dialog/header/ComfyOrgHeader.vue'
import SettingDialogHeader from '@/components/dialog/header/SettingDialogHeader.vue'
import { t } from '@/i18n'
import { isCloud } from '@/platform/distribution/types'
import SettingDialogContent from '@/platform/settings/components/SettingDialogContent.vue'
import type { ExecutionErrorWsMessage } from '@/schemas/apiSchema'
import { useDialogStore } from '@/stores/dialogStore'
@@ -485,6 +487,37 @@ export const useDialogService = () => {
})
}
function showSubscriptionRequiredDialog() {
if (!isCloud) {
return
}
dialogStore.showDialog({
key: 'subscription-required',
component: defineAsyncComponent(
() =>
import(
'@/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue'
)
),
props: {
onClose: () => {
dialogStore.closeDialog({ key: 'subscription-required' })
}
},
dialogComponentProps: {
closable: true,
style: 'width: 700px;',
pt: {
header: { class: '!p-0 !m-0' },
content: {
class: 'overflow-hidden !p-0 !m-0'
}
}
}
})
}
return {
showLoadWorkflowWarning,
showMissingModelsWarning,
@@ -495,6 +528,7 @@ export const useDialogService = () => {
showManagerProgressDialog,
showApiNodesSignInDialog,
showSignInDialog,
showSubscriptionRequiredDialog,
showTopUpCreditsDialog,
showUpdatePasswordDialog,
showExtensionDialog,