diff --git a/src/components/dialog/content/TopUpCreditsDialogContentLegacy.test.ts b/src/components/dialog/content/TopUpCreditsDialogContentLegacy.test.ts index 22ab1dbeb56..65d094e06ce 100644 --- a/src/components/dialog/content/TopUpCreditsDialogContentLegacy.test.ts +++ b/src/components/dialog/content/TopUpCreditsDialogContentLegacy.test.ts @@ -129,7 +129,7 @@ describe('TopUpCreditsDialogContentLegacy', () => { mockShouldUseWorkspaceBilling.value = false }) - it('shows the subscription settings panel after a successful purchase', async () => { + it('shows Plan & Credits after a successful Cloud purchase', async () => { mockPurchaseCreditsDirect.mockResolvedValue(undefined) renderDialog() @@ -137,7 +137,7 @@ describe('TopUpCreditsDialogContentLegacy', () => { expect(mockPurchaseCreditsDirect).toHaveBeenCalledWith(50) expect(mockCloseDialog).toHaveBeenCalled() - expect(mockShowSettings).toHaveBeenCalledWith('subscription') + expect(mockShowSettings).toHaveBeenCalledWith('workspace') }) it('shows the credits settings panel when subscriptions are disabled', async () => { diff --git a/src/components/dialog/content/TopUpCreditsDialogContentLegacy.vue b/src/components/dialog/content/TopUpCreditsDialogContentLegacy.vue index 0ea0eee7389..09afde5d0b4 100644 --- a/src/components/dialog/content/TopUpCreditsDialogContentLegacy.vue +++ b/src/components/dialog/content/TopUpCreditsDialogContentLegacy.vue @@ -261,12 +261,9 @@ async function handleBuy() { // Close top-up dialog (keep tracking) and open credits panel to show updated balance handleClose(false) - // On the consolidated (workspace) billing flow, show the workspace settings - // panel; otherwise show the legacy subscription/credits panel. - const settingsPanel = shouldUseWorkspaceBilling.value - ? 'workspace' - : isSubscriptionEnabled() - ? 'subscription' + const settingsPanel = + shouldUseWorkspaceBilling.value || isSubscriptionEnabled() + ? 'workspace' : 'credits' settingsDialog.show(settingsPanel) } catch (error) { diff --git a/src/components/topbar/CurrentUserPopoverLegacy.test.ts b/src/components/topbar/CurrentUserPopoverLegacy.test.ts index a03764d2e0f..880264921e0 100644 --- a/src/components/topbar/CurrentUserPopoverLegacy.test.ts +++ b/src/components/topbar/CurrentUserPopoverLegacy.test.ts @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/vue' import userEvent from '@testing-library/user-event' import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest' -import { defineComponent, h, ref } from 'vue' +import { h, ref } from 'vue' import { createI18n } from 'vue-i18n' import { formatCreditsFromCents } from '@/base/credits/comfyCredits' @@ -62,10 +62,8 @@ function makeSubscription( } } -const mockFetchStatus = vi.fn().mockResolvedValue(undefined) const mockFetchBalance = vi.fn().mockResolvedValue(undefined) const mockCanAccessSubscriptionFeatures = ref(true) -const mockIsFreeTier = ref(false) const mockTier = ref('CREATOR') const mockSubscription = ref(makeSubscription()) const mockBalance = ref(null) @@ -74,28 +72,14 @@ const mockIsLoading = ref(false) vi.mock('@/composables/billing/useBillingContext', () => ({ useBillingContext: vi.fn(() => ({ canAccessSubscriptionFeatures: mockCanAccessSubscriptionFeatures, - isFreeTier: mockIsFreeTier, tier: mockTier, subscription: mockSubscription, balance: mockBalance, isLoading: mockIsLoading, - fetchStatus: mockFetchStatus, fetchBalance: mockFetchBalance })) })) -const mockShowPricingTable = vi.fn() -vi.mock( - '@/platform/cloud/subscription/composables/useSubscriptionDialog', - () => ({ - useSubscriptionDialog: vi.fn(() => ({ - show: vi.fn(), - showPricingTable: mockShowPricingTable, - hide: vi.fn() - })) - }) -) - vi.mock('@/components/common/UserAvatar.vue', () => ({ default: { name: 'UserAvatarMock', @@ -124,36 +108,9 @@ vi.mock('@/platform/telemetry', () => ({ })) })) -const mockIsCloud = vi.hoisted(() => ({ value: true })) -vi.mock('@/platform/distribution/types', () => ({ - get isCloud() { - return mockIsCloud.value - } -})) - -vi.mock('@/platform/cloud/subscription/components/SubscribeButton.vue', () => ({ - default: defineComponent({ - name: 'SubscribeButtonMock', - emits: ['subscribed'], - setup(_, { emit }) { - return () => - h( - 'button', - { - 'data-testid': 'subscribe-button-mock', - onClick: () => emit('subscribed') - }, - 'Subscribe Button' - ) - } - }) -})) - describe('CurrentUserPopoverLegacy', () => { beforeEach(() => { - mockIsCloud.value = true mockCanAccessSubscriptionFeatures.value = true - mockIsFreeTier.value = false mockTier.value = 'CREATOR' mockSubscription.value = makeSubscription() mockBalance.value = { @@ -201,15 +158,6 @@ describe('CurrentUserPopoverLegacy', () => { expect(mockFetchBalance).toHaveBeenCalled() }) - it('refreshes subscription status through the billing facade after subscribing', async () => { - mockCanAccessSubscriptionFeatures.value = false - const { user } = renderComponent() - - await user.click(screen.getByTestId('subscribe-button-mock')) - - expect(mockFetchStatus).toHaveBeenCalled() - }) - describe('subscription tier badge', () => { it('renders the tier name derived from the facade tier', () => { renderComponent() @@ -326,26 +274,15 @@ describe('CurrentUserPopoverLegacy', () => { expect(onClose).toHaveBeenCalledTimes(1) }) - it('opens subscription dialog and emits close event when plans & pricing item is clicked', async () => { - const { user, onClose } = renderComponent() - - expect(screen.getByTestId('plans-pricing-menu-item')).toBeInTheDocument() - - await user.click(screen.getByTestId('plans-pricing-menu-item')) - - expect(mockShowPricingTable).toHaveBeenCalled() - expect(onClose).toHaveBeenCalledTimes(1) - }) - - it('offers plan management on cloud', async () => { + it('opens credits settings from the legacy account menu', async () => { const { user, onClose } = renderComponent() const menuItem = screen.getByTestId('manage-plan-menu-item') - expect(menuItem).toHaveTextContent(enMessages.subscription.managePlan) + expect(menuItem).toHaveTextContent(enMessages.credits.credits) await user.click(menuItem) - expect(mockShowSettingsDialog).toHaveBeenCalledWith('subscription') + expect(mockShowSettingsDialog).toHaveBeenCalledWith('credits') expect(onClose).toHaveBeenCalledTimes(1) }) @@ -445,90 +382,4 @@ describe('CurrentUserPopoverLegacy', () => { expect(screen.getByText('0')).toBeInTheDocument() }) }) - - describe('cloud free tier', () => { - beforeEach(() => { - mockIsCloud.value = true - mockIsFreeTier.value = true - }) - - it('shows upgrade-to-add-credits button and hides add-credits button', () => { - renderComponent() - expect( - screen.getByTestId('upgrade-to-add-credits-button') - ).toBeInTheDocument() - expect(screen.queryByTestId('add-credits-button')).not.toBeInTheDocument() - }) - }) - - describe('non-cloud distribution', () => { - beforeEach(() => { - mockIsCloud.value = false - }) - - it('still shows credits balance', () => { - renderComponent() - expect(screen.getByText('1000')).toBeInTheDocument() - }) - - it('shows add-credits button and hides upgrade-to-add-credits button', () => { - renderComponent() - expect(screen.getByTestId('add-credits-button')).toBeInTheDocument() - expect( - screen.queryByTestId('upgrade-to-add-credits-button') - ).not.toBeInTheDocument() - }) - - it('hides upgrade-to-add-credits button even when on free tier', () => { - mockIsFreeTier.value = true - renderComponent() - expect(screen.getByTestId('add-credits-button')).toBeInTheDocument() - expect( - screen.queryByTestId('upgrade-to-add-credits-button') - ).not.toBeInTheDocument() - }) - - it('hides subscribe button', () => { - mockCanAccessSubscriptionFeatures.value = false - renderComponent() - expect( - screen.queryByTestId('subscribe-button-mock') - ).not.toBeInTheDocument() - }) - - it('still shows partner nodes menu item', () => { - renderComponent() - expect(screen.getByTestId('partner-nodes-menu-item')).toBeInTheDocument() - }) - - it('hides plans & pricing menu item', () => { - renderComponent() - expect( - screen.queryByTestId('plans-pricing-menu-item') - ).not.toBeInTheDocument() - }) - - it('offers credits and opens the credits panel', async () => { - const { user, onClose } = renderComponent() - - const menuItem = screen.getByTestId('manage-plan-menu-item') - expect(menuItem).toHaveTextContent(enMessages.credits.credits) - expect(menuItem).not.toHaveTextContent(enMessages.subscription.managePlan) - - await user.click(menuItem) - - expect(mockShowSettingsDialog).toHaveBeenCalledWith('credits') - expect(onClose).toHaveBeenCalledTimes(1) - }) - - it('still shows user settings menu item', () => { - renderComponent() - expect(screen.getByTestId('user-settings-menu-item')).toBeInTheDocument() - }) - - it('still shows logout menu item', () => { - renderComponent() - expect(screen.getByTestId('logout-menu-item')).toBeInTheDocument() - }) - }) }) diff --git a/src/components/topbar/CurrentUserPopoverLegacy.vue b/src/components/topbar/CurrentUserPopoverLegacy.vue index fe66148650b..cfa3195738d 100644 --- a/src/components/topbar/CurrentUserPopoverLegacy.vue +++ b/src/components/topbar/CurrentUserPopoverLegacy.vue @@ -51,16 +51,6 @@ - ', - emits: ['click'] - } - } - } - }) -} - -describe('SubscriptionPanelContentLegacy', () => { - beforeEach(() => { - mockAccessBillingPortal.mockResolvedValue(undefined) - mockIsActiveSubscription.value = true - mockIsCancelled.value = false - mockIsFreeTier.value = false - mockSubscriptionTier.value = 'STANDARD' - mockIsYearlySubscription.value = true - }) - - it('tracks cancel intent before opening the billing portal', async () => { - renderComponent() - - await userEvent.click( - screen.getByRole('button', { name: /manage subscription/i }) - ) - - expect(mockTrackSubscriptionCancellation).toHaveBeenCalledExactlyOnceWith( - 'flow_opened', - { - source: 'manage_subscription_button', - current_tier: 'standard', - cycle: 'yearly' - } - ) - expect(mockAccessBillingPortal).toHaveBeenCalledOnce() - }) -}) diff --git a/src/platform/cloud/subscription/components/SubscriptionPanelContentLegacy.vue b/src/platform/cloud/subscription/components/SubscriptionPanelContentLegacy.vue deleted file mode 100644 index d3cb1582fa8..00000000000 --- a/src/platform/cloud/subscription/components/SubscriptionPanelContentLegacy.vue +++ /dev/null @@ -1,183 +0,0 @@ - - - - - diff --git a/src/platform/cloud/subscription/composables/useSubscription.ts b/src/platform/cloud/subscription/composables/useSubscription.ts index 3279d8ac7e2..3f795828f6b 100644 --- a/src/platform/cloud/subscription/composables/useSubscription.ts +++ b/src/platform/cloud/subscription/composables/useSubscription.ts @@ -280,7 +280,6 @@ function useSubscriptionInternal() { /** * Whether cloud subscription mode is enabled (cloud distribution with subscription_required config). - * Use to determine which UI to show (SubscriptionPanel vs CreditsPanel). */ const isSubscriptionEnabled = (): boolean => Boolean(isCloud && window.__CONFIG__?.subscription_required) diff --git a/src/platform/settings/composables/useSettingUI.test.ts b/src/platform/settings/composables/useSettingUI.test.ts index 67873bde5c9..9f5a152f0b9 100644 --- a/src/platform/settings/composables/useSettingUI.test.ts +++ b/src/platform/settings/composables/useSettingUI.test.ts @@ -20,8 +20,6 @@ const env = vi.hoisted(() => { authenticatedConfigLoaded: false, partnerNodeGovernanceEnabled: false, userSecretsEnabled: false, - isActiveSubscription: false, - billingType: 'legacy' as 'legacy' | 'workspace', workspaceRole: 'owner' as 'owner' | 'member', partnerNodeGovernanceStatus: 'inactive' as | 'inactive' @@ -48,13 +46,6 @@ vi.mock('@/composables/auth/useCurrentUser', () => ({ useCurrentUser: () => ({ isLoggedIn: env.fakeRef('isLoggedIn') }) })) -vi.mock('@/composables/billing/useBillingContext', () => ({ - useBillingContext: () => ({ - canAccessSubscriptionFeatures: env.fakeRef('isActiveSubscription'), - type: env.fakeRef('billingType') - }) -})) - vi.mock('@/composables/useFeatureFlags', () => ({ useFeatureFlags: () => ({ flags: { @@ -151,8 +142,6 @@ describe('useSettingUI', () => { authenticatedConfigLoaded: false, partnerNodeGovernanceEnabled: false, userSecretsEnabled: false, - isActiveSubscription: false, - billingType: 'legacy', workspaceRole: 'owner', partnerNodeGovernanceStatus: 'inactive', partnerNodeGovernanceProviders: [] @@ -233,9 +222,7 @@ describe('useSettingUI', () => { Object.assign(env.state, { isCloud: true, isLoggedIn: true, - authenticatedConfigLoaded: true, - isActiveSubscription: true, - billingType: 'workspace' + authenticatedConfigLoaded: true }) window.__CONFIG__ = { subscription_required: false @@ -312,24 +299,18 @@ describe('useSettingUI', () => { isLoggedIn: true, billingControlEnabled: true, authenticatedConfigLoaded: true, - partnerNodeGovernanceEnabled: true, - isActiveSubscription: true + partnerNodeGovernanceEnabled: true }) window.__CONFIG__ = { subscription_required: true } as typeof window.__CONFIG__ }) - it.for(['legacy', 'workspace'] as const)( - 'uses only the Workspace panel for %s billing in the workspace layout', - (billingType) => { - env.state.billingType = billingType - const { navGroups } = useSettingUI() + it('uses the Workspace panel for Cloud billing navigation', () => { + const { navGroups } = useSettingUI() - expect(navKeys(navGroups.value)).not.toContain('subscription') - expect(navKeys(navGroups.value)).toContain('workspace') - } - ) + expect(navKeys(navGroups.value)).toContain('workspace') + }) it('exposes workspace sections as Plan & Credits, Members, and Allowlist', () => { const { navGroups } = useSettingUI() diff --git a/src/platform/settings/composables/useSettingUI.ts b/src/platform/settings/composables/useSettingUI.ts index baa370e3c39..6afee8ddc82 100644 --- a/src/platform/settings/composables/useSettingUI.ts +++ b/src/platform/settings/composables/useSettingUI.ts @@ -34,7 +34,6 @@ const CATEGORY_ICONS: Record = { PlanCredits: 'icon-[lucide--receipt-text]', secrets: 'icon-[lucide--key-round]', 'server-config': 'icon-[lucide--server]', - subscription: 'icon-[lucide--credit-card]', user: 'icon-[lucide--user]', workspace: 'icon-[lucide--building-2]', 'workspace-allowlist': 'icon-[comfy--ai-model]', diff --git a/src/platform/settings/types.ts b/src/platform/settings/types.ts index bb5765fe513..a108c4dca68 100644 --- a/src/platform/settings/types.ts +++ b/src/platform/settings/types.ts @@ -84,7 +84,6 @@ export type SettingPanelType = | 'keybinding' | 'secrets' | 'server-config' - | 'subscription' | 'user' | 'workspace' | 'workspace-allowlist'