mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-06-06 15:54:45 +00:00
fix: show credits in legacy user popover on non-cloud distributions (#11463)
*PR Created by the Glary-Bot Agent* --- ## Summary Credits no longer showed in the current user popover on local/desktop builds. Root cause: the credits row in `CurrentUserPopoverLegacy.vue` was gated behind `isCloud && isActiveSubscription`, and `isCloud` is a compile-time constant that resolves to `false` on local (`DISTRIBUTION='localhost'`) — so the element never rendered and `fetchBalance()` never fired (no network request, no console logs). This fix decouples the credits balance row from the `isCloud` gate. Subscription-specific UI (subscribe button, partner nodes, plans & pricing, manage plan, upgrade-to-add-credits) remains gated by `isCloud` as intended by PR #9958. ## Changes - `CurrentUserPopoverLegacy.vue`: credits row `v-if` changed from `isCloud && isActiveSubscription` → `isActiveSubscription`. On non-cloud, `isActiveSubscription` resolves to `true` via `isSubscribedOrIsNotCloud` in `useSubscription.ts`, so credits display for logged-in users. - `CurrentUserPopoverLegacy.vue`: `upgrade-to-add-credits` button now requires `isCloud && isFreeTier` (subscription-tier concept only meaningful on cloud). The `add-credits` top-up button remains available everywhere. - `CurrentUserPopoverLegacy.test.ts`: updated non-cloud tests to assert credits balance is visible and add-credits button renders, while upgrade-to-add-credits and other subscription UI stay hidden. Mirrors the behavior of `CurrentUserPopoverWorkspace.vue`, which never had the `isCloud` gate on its credits row. ## Verification - `pnpm vitest run src/components/topbar/CurrentUserPopoverLegacy.test.ts`: **21/21 passing**, including new non-cloud assertions - `pnpm typecheck`: clean - `pnpm lint` / `pnpm format:check`: clean - Live frontend dev server renders on localhost with `__DISTRIBUTION__='localhost'` (the previously-failing scenario). Attached screenshot shows the app running on local distribution; the popover itself only appears for logged-in users, so its contents are exercised by the unit tests. Fixes FE-219 ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11463-fix-show-credits-in-legacy-user-popover-on-non-cloud-distributions-3486d73d365081c587d8ee7eae9a5c3d) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
This commit is contained in:
@@ -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 { h } from 'vue'
|
||||
import { h, ref } from 'vue'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
||||
import { formatCreditsFromCents } from '@/base/credits/comfyCredits'
|
||||
@@ -103,11 +103,13 @@ vi.mock('@/stores/authStore', () => ({
|
||||
|
||||
// Mock the useSubscription composable
|
||||
const mockFetchStatus = vi.fn().mockResolvedValue(undefined)
|
||||
const mockIsFreeTier = ref(false)
|
||||
vi.mock('@/platform/cloud/subscription/composables/useSubscription', () => ({
|
||||
useSubscription: vi.fn(() => ({
|
||||
isActiveSubscription: { value: true },
|
||||
subscriptionTierName: { value: 'Creator' },
|
||||
subscriptionTier: { value: 'CREATOR' },
|
||||
isActiveSubscription: ref(true),
|
||||
isFreeTier: mockIsFreeTier,
|
||||
subscriptionTierName: ref('Creator'),
|
||||
subscriptionTier: ref('CREATOR'),
|
||||
fetchStatus: mockFetchStatus
|
||||
}))
|
||||
}))
|
||||
@@ -188,6 +190,7 @@ describe('CurrentUserPopoverLegacy', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockIsCloud.value = true
|
||||
mockIsFreeTier.value = false
|
||||
mockAuthStoreState.balance = {
|
||||
amount_micros: 100_000,
|
||||
effective_balance_micros: 100_000,
|
||||
@@ -406,14 +409,43 @@ describe('CurrentUserPopoverLegacy', () => {
|
||||
})
|
||||
})
|
||||
|
||||
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('hides credits section', () => {
|
||||
it('still shows credits balance', () => {
|
||||
renderComponent()
|
||||
expect(screen.queryByTestId('add-credits-button')).not.toBeInTheDocument()
|
||||
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()
|
||||
@@ -424,11 +456,9 @@ describe('CurrentUserPopoverLegacy', () => {
|
||||
expect(screen.queryByText('Subscribe Button')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('hides partner nodes menu item', () => {
|
||||
it('still shows partner nodes menu item', () => {
|
||||
renderComponent()
|
||||
expect(
|
||||
screen.queryByTestId('partner-nodes-menu-item')
|
||||
).not.toBeInTheDocument()
|
||||
expect(screen.getByTestId('partner-nodes-menu-item')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('hides plans & pricing menu item', () => {
|
||||
@@ -438,11 +468,9 @@ describe('CurrentUserPopoverLegacy', () => {
|
||||
).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('hides manage plan menu item', () => {
|
||||
it('still shows manage plan menu item', () => {
|
||||
renderComponent()
|
||||
expect(
|
||||
screen.queryByTestId('manage-plan-menu-item')
|
||||
).not.toBeInTheDocument()
|
||||
expect(screen.getByTestId('manage-plan-menu-item')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('still shows user settings menu item', () => {
|
||||
|
||||
@@ -29,11 +29,8 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Credits Section (cloud only) -->
|
||||
<div
|
||||
v-if="isCloud && isActiveSubscription"
|
||||
class="flex items-center gap-2 px-4 py-2"
|
||||
>
|
||||
<!-- Credits Section -->
|
||||
<div v-if="isActiveSubscription" class="flex items-center gap-2 px-4 py-2">
|
||||
<i class="icon-[lucide--component] text-sm text-amber-400" />
|
||||
<Skeleton
|
||||
v-if="authStore.isFetchingBalance"
|
||||
@@ -49,7 +46,7 @@
|
||||
class="mr-auto icon-[lucide--circle-help] cursor-help text-base text-muted-foreground"
|
||||
/>
|
||||
<Button
|
||||
v-if="isFreeTier"
|
||||
v-if="isCloud && isFreeTier"
|
||||
variant="gradient"
|
||||
size="sm"
|
||||
data-testid="upgrade-to-add-credits-button"
|
||||
@@ -82,7 +79,7 @@
|
||||
<Divider class="mx-0 my-2" />
|
||||
|
||||
<div
|
||||
v-if="isCloud && isActiveSubscription"
|
||||
v-if="isActiveSubscription"
|
||||
class="flex cursor-pointer items-center gap-2 px-4 py-2 hover:bg-secondary-background-hover"
|
||||
data-testid="partner-nodes-menu-item"
|
||||
@click="handleOpenPartnerNodesInfo"
|
||||
@@ -112,7 +109,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isCloud && isActiveSubscription"
|
||||
v-if="isActiveSubscription"
|
||||
class="flex cursor-pointer items-center gap-2 px-4 py-2 hover:bg-secondary-background-hover"
|
||||
data-testid="manage-plan-menu-item"
|
||||
@click="handleOpenPlanAndCreditsSettings"
|
||||
|
||||
Reference in New Issue
Block a user