Skip to content

Conversation

@christian-byrne
Copy link
Contributor

@christian-byrne christian-byrne commented Nov 30, 2025

Introduces cents<->usd<->credit converters plus basic formatters and adds test. Lays groundwork to start converting UI components into displaying comfy credits.

┆Issue is synchronized with this Notion page by Unito

@christian-byrne christian-byrne requested a review from a team as a code owner November 30, 2025 22:02
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Nov 30, 2025
@github-actions
Copy link

github-actions bot commented Nov 30, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 12/09/2025, 12:01:46 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Nov 30, 2025

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 12/09/2025, 12:11:13 PM UTC

📈 Summary

  • Total Tests: 490
  • Passed: 471 ✅
  • Failed: 0
  • Flaky: 10 ⚠️
  • Skipped: 9 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 462 / ❌ 0 / ⚠️ 10 / ⏭️ 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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 30, 2025

📝 Walkthrough

Walkthrough

Introduces a credits currency system with conversion utilities and formatting functions, updates UI components to display formatted credits with locale support, and adds a redesigned credit top-up dialog with new option cards. Updates subscription credit display across components and adds localization strings for the new credits interface.

Changes

Cohort / File(s) Change Summary
Credits System Core
src/base/credits/comfyCredits.ts
New module implementing currency conversion between USD, cents, and credits, plus locale-aware formatting utilities (formatCredits, formatUsd, formatCreditsFromCents, etc.). Exports constants CREDITS_PER_USD and COMFY_CREDIT_RATE_CENTS, conversion functions, and utility types.
Credits System Tests
tests-ui/tests/base/credits/comfyCredits.test.ts
Vitest unit tests validating conversion rates, USD/cents/credits conversions, round-trip conversions, and locale-based formatting.
User Display Components
src/components/common/UserCredit.vue
Updated to use formatCreditsFromCents with i18n locale for displaying user balance, replacing previous currency formatting.
Credit Top-Up UI Components
src/components/dialog/content/credit/CreditTopUpOption.vue
Redesigned as a clickable presentational card component. Props changed from amount/preselected/editable to credits/description/selected; added select emit and formattedCredits computed property.
Legacy Credit Top-Up Component
src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
New component preserving original editable top-up behavior with InputNumber, currency formatting, clamping, and purchase button with telemetry tracking.
Top-Up Dialog
src/components/dialog/content/TopUpCreditsDialogContent.vue
Added feature-flag-driven dual-design support: new credits design with current balance, credit options using CreditTopUpOption, and buy button; legacy path uses LegacyCreditTopUpOption. Adds refreshDate prop, handleBuy function with telemetry, and creditsToUsd conversion.
Subscription Credits Composable
src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
Unified formatting logic using formatCreditsFromCents with i18n locale for totalCredits, monthlyBonusCredits, and prepaidCredits. Added isLoadingBalance to public API.
Subscription Panel Component
src/platform/cloud/subscription/components/SubscriptionPanel.vue
Removed dollar sign prefixes from credit amount displays; values now render as plain formatted credits.
Component Tests
tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
Tests for CreditTopUpOption verifying rendering of formatted credits/description, selected/unselected styling, and select event emission.
Subscription Tests
tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts, tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
Updated test data and assertions to expect credit values suffixed with " Credits"; added tests for formatCreditsFromCents integration and error handling.
Feature Flags
src/composables/useFeatureFlags.ts
Changed subscriptionTiersEnabled default from false to true when server feature flag not set or remote config missing.
Feature Flag Tests
tests-ui/tests/composables/node/useCreditsBadge.test.ts
Added useFeatureFlags mock returning subscriptionTiersEnabled: false to test legacy badge behavior.
Localization
src/locales/en/main.json
Added 12 new credits-related i18n keys under credits.topUp (addMoreCredits, creditsDescription, howManyCredits, videosEstimate, templateNote, buy, purchaseSuccess, purchaseSuccessDetail, purchaseError, purchaseErrorDetail, unknownError) and top-level keys creditsAvailable and refreshes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch comfy-credits-domain

📜 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 427c889 and 1eb4675.

📒 Files selected for processing (1)
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
**/*.{js,ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript exclusively (no new JavaScript)

Files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Do not use any type in TypeScript code
Do not use as any type assertions in TypeScript code; fix the underlying type issue
Style formatting: 2 space indent, single quotes, no trailing semicolons, 80 character width
Import statements should be sorted and grouped by plugin; run pnpm format before committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates

Files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.ts: Write unit and component tests in **/*.test.ts
Use Vitest with happy-dom for unit and component tests

Files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use vue-i18n in Composition API for string literals and place new translation entries in src/locales/en/main.json

Files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
🧠 Learnings (22)
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.test.ts : Use Vitest with happy-dom for unit and component tests

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Follow naming conventions for browser tests

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.{ts,tsx,vue} : Do not use `as any` type assertions in TypeScript code; fix the underlying type issue

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.{ts,tsx,vue} : ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.{ts,tsx,vue} : Do not use `any` type in TypeScript code

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.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/**/{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:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.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/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 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:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.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/**/*.{ts,tsx,vue} : Implement proper TypeScript types throughout the codebase

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Favor pure functions (especially testable ones)

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.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/**/stores/**/*.{ts,tsx} : Use TypeScript for type safety in state management stores

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 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:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
🧬 Code graph analysis (1)
tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)
src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)
  • useSubscriptionCredits (10-44)
⏰ 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: setup
  • GitHub Check: collect
  • GitHub Check: lint-and-format
  • GitHub Check: test
🔇 Additional comments (1)
tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)

4-24: Typed vue-i18n mock and balance response alias look good

Defining GetCustomerBalanceResponse from operations and using a typed importOriginal in the vue-i18n mock removes the previous as any usage while keeping fixtures aligned with the real API surface. This is a solid, type-safe improvement for these tests.

Based on learnings, this matches the guidance to avoid as any in TypeScript tests.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link

github-actions bot commented Nov 30, 2025

Bundle Size Report

Summary

  • Raw size: 17.1 MB baseline 17.1 MB — 🔴 +10.2 kB
  • Gzip: 3.38 MB baseline 3.38 MB — 🔴 +2.01 kB
  • Brotli: 2.6 MB baseline 2.59 MB — 🔴 +1.51 kB
  • Bundles: 97 current • 97 baseline • 37 added / 37 removed

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

Per-category breakdown
App Entry Points — 3.22 MB (baseline 3.21 MB) • 🔴 +10.2 kB

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-B0qNzMyH.js (new) 3 MB 🔴 +3 MB 🔴 +623 kB 🔴 +474 kB
assets/index-BgGeTyyU.js (removed) 2.99 MB 🟢 -2.99 MB 🟢 -621 kB 🟢 -472 kB
assets/index-B_3a1qlg.js (new) 223 kB 🔴 +223 kB 🔴 +47.6 kB 🔴 +39.3 kB
assets/index-fcsHUSZF.js (removed) 223 kB 🟢 -223 kB 🟢 -47.6 kB 🟢 -39.3 kB
assets/index-Beo-v7d0.js (removed) 345 B 🟢 -345 B 🟢 -243 B 🟢 -209 B
assets/index-BU4JEmja.js (new) 345 B 🔴 +345 B 🔴 +246 B 🔴 +236 B

Status: 3 added / 3 removed

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

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-BysbTCDG.js (new) 986 kB 🔴 +986 kB 🔴 +191 kB 🔴 +145 kB
assets/GraphView-BZ5aaNu2.js (removed) 986 kB 🟢 -986 kB 🟢 -191 kB 🟢 -145 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-Bdx9N3Vs.js (new) 6.54 kB 🔴 +6.54 kB 🔴 +2.14 kB 🔴 +1.89 kB
assets/UserSelectView-C2UoG6lJ.js (removed) 6.54 kB 🟢 -6.54 kB 🟢 -2.14 kB 🟢 -1.9 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/CreditsPanel-C1ZrboPZ.js (new) 21.4 kB 🔴 +21.4 kB 🔴 +5.15 kB 🔴 +4.49 kB
assets/CreditsPanel-CUCRU04d.js (removed) 21.4 kB 🟢 -21.4 kB 🟢 -5.15 kB 🟢 -4.5 kB
assets/KeybindingPanel-Cbsxl_mv.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.42 kB 🔴 +3.01 kB
assets/KeybindingPanel-FfFz77U0.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.42 kB 🟢 -3.01 kB
assets/ExtensionPanel-DadGBvlb.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.57 kB 🟢 -2.26 kB
assets/ExtensionPanel-DFkFfh_I.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.58 kB 🔴 +2.26 kB
assets/AboutPanel-BQVBjEB-.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/AboutPanel-CVjuHIbo.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.2 kB
assets/ServerConfigPanel-BPyre06f.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +1.83 kB 🔴 +1.63 kB
assets/ServerConfigPanel-D_lhmpMX.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -1.83 kB 🟢 -1.63 kB
assets/UserPanel-CYykQKPt.js (new) 6.23 kB 🔴 +6.23 kB 🔴 +1.72 kB 🔴 +1.51 kB
assets/UserPanel-DAeNCal9.js (removed) 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 — 176 kB (baseline 176 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Load3D.vue_vue_type_script_setup_true_lang-DLR_T-F9.js (removed) 53.9 kB 🟢 -53.9 kB 🟢 -8.52 kB 🟢 -7.32 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-vJBlyi64.js (new) 53.9 kB 🔴 +53.9 kB 🔴 +8.52 kB 🔴 +7.31 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-3UnAibYw.js (removed) 48.1 kB 🟢 -48.1 kB 🟢 -10.4 kB 🟢 -8.99 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-BUDVf0eI.js (new) 48.1 kB 🔴 +48.1 kB 🔴 +10.4 kB 🔴 +8.98 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-BD18eHYI.js (removed) 46 kB 🟢 -46 kB 🟢 -10.3 kB 🟢 -8.98 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-DjeFjVhn.js (new) 46 kB 🔴 +46 kB 🔴 +10.3 kB 🔴 +8.99 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-BIPt9Eso.js (new) 12.9 kB 🔴 +12.9 kB 🔴 +3.37 kB 🔴 +2.98 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-d4MtmhFW.js (removed) 12.9 kB 🟢 -12.9 kB 🟢 -3.37 kB 🟢 -2.97 kB
assets/ComfyQueueButton-BVU2aWs_.js (removed) 8.44 kB 🟢 -8.44 kB 🟢 -2.48 kB 🟢 -2.21 kB
assets/ComfyQueueButton-DuozoqRr.js (new) 8.44 kB 🔴 +8.44 kB 🔴 +2.48 kB 🔴 +2.21 kB
assets/MediaTitle.vue_vue_type_script_setup_true_lang-9nO8lqOU.js (new) 897 B 🔴 +897 B 🔴 +505 B 🔴 +467 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-CjR5GBev.js (removed) 897 B 🟢 -897 B 🟢 -502 B 🟢 -444 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-BkTMAMst.js 1.34 kB 1.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-CMkR1knv.js 2.04 kB 2.04 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-6ZIklFyS.js 2.26 kB 2.26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 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-D3JUbTiF.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.83 kB 🟢 -1.58 kB
assets/keybindingService-DeKfY38c.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.84 kB 🔴 +1.57 kB
assets/audioService-B8rnoges.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -957 B 🟢 -822 B
assets/audioService-DgCDJn8p.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +962 B 🔴 +822 B
assets/serverConfigStore-L3qzi_1Z.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-BX1H5CIv.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -652 B 🟢 -543 B
assets/audioUtils-C8Qshsis.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +651 B 🔴 +545 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-DJFoH6N_.js 452 kB 452 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-BZV8aGUB.js 3.98 MB 3.98 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-CkvDSSUa.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-Cmu0_BY4.js 232 kB 232 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-Bz22sFex.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-BIGWPR2V.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.24 kB 🟢 -4.63 kB
assets/WidgetRecordAudio-CnwQ_nGC.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.24 kB 🔴 +4.64 kB
assets/AudioPreviewPlayer-CO2W2OUf.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.4 kB 🔴 +3.04 kB
assets/AudioPreviewPlayer-DcOJf7Zw.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.4 kB 🟢 -3.04 kB
assets/WidgetGalleria-bZV2OHCh.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.45 kB 🔴 +1.3 kB
assets/WidgetGalleria-pWldby95.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.44 kB 🟢 -1.31 kB
assets/WidgetColorPicker-DhuJggxT.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetColorPicker-OzxmwB7U.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetMarkdown-BrE9I4-M.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/WidgetMarkdown-D0A4WtwO.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.13 kB
assets/WidgetTextarea-2_h-PxbR.js (removed) 2.93 kB 🟢 -2.93 kB 🟢 -1.17 kB 🟢 -1.04 kB
assets/WidgetTextarea-BfFpX8rh.js (new) 2.93 kB 🔴 +2.93 kB 🔴 +1.17 kB 🔴 +1.03 kB
assets/WidgetAudioUI-0LD4pu6y.js (removed) 2.85 kB 🟢 -2.85 kB 🟢 -1.16 kB 🟢 -1.05 kB
assets/WidgetAudioUI-DvSCaCU7.js (new) 2.85 kB 🔴 +2.85 kB 🔴 +1.16 kB 🔴 +1.05 kB
assets/WidgetInputText-B0GbTglv.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +916 B 🔴 +851 B
assets/WidgetInputText-C0U6yA50.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -915 B 🟢 -846 B
assets/MediaImageBottom-3GG9KYhb.js (removed) 1.57 kB 🟢 -1.57 kB 🟢 -740 B 🟢 -648 B
assets/MediaImageBottom-BHSU4YtO.js (new) 1.57 kB 🔴 +1.57 kB 🔴 +742 B 🔴 +649 B
assets/MediaAudioBottom-CtMa2yA7.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +742 B 🔴 +658 B
assets/MediaAudioBottom-ro13pW9p.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -740 B 🟢 -657 B
assets/MediaVideoBottom-BB64-exc.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +739 B 🔴 +655 B
assets/MediaVideoBottom-BL_ACx7D.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -738 B 🟢 -656 B
assets/Media3DBottom-BU-3r0S3.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -730 B 🟢 -651 B
assets/Media3DBottom-sP17dVvq.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +732 B 🔴 +650 B
assets/Media3DTop-D63VwL9G.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -765 B 🟢 -657 B
assets/Media3DTop-DYWy0xJ7.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +767 B 🔴 +655 B
assets/WidgetSelect-OER6_JmF.js (new) 655 B 🔴 +655 B 🔴 +343 B 🔴 +289 B
assets/WidgetSelect-QSw6_V7R.js (removed) 655 B 🟢 -655 B 🟢 -342 B 🟢 -292 B
assets/WidgetInputNumber-BN_4-n6S.js (new) 595 B 🔴 +595 B 🔴 +326 B 🔴 +278 B
assets/WidgetInputNumber-BOZiSnwH.js (removed) 595 B 🟢 -595 B 🟢 -327 B 🟢 -273 B
assets/Load3D-CJmT4RCK.js (removed) 424 B 🟢 -424 B 🟢 -266 B 🟢 -226 B
assets/Load3D-Dl6YyDfh.js (new) 424 B 🔴 +424 B 🔴 +268 B 🔴 +226 B
assets/WidgetLegacy-CtLW5OUp.js (new) 364 B 🔴 +364 B 🔴 +238 B 🔴 +194 B
assets/WidgetLegacy-Dy1htTZ6.js (removed) 364 B 🟢 -364 B 🟢 -236 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-B1JflQcI.js 72.2 kB 72.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B2lyXe48.js 114 kB 114 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B9XEQ-pc.js 94 kB 94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BErKFzc-.js 73.1 kB 73.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Bf7Tze-u.js 83.4 kB 83.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BhGMcO4Q.js 84.3 kB 84.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CPZUloNQ.js 99 kB 99 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cw9RZWRY.js 89 B 89 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dva0z-T2.js 86.5 kB 86.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-un0K9wDS.js 81.8 kB 81.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-BPDWO8-i.js 1.46 kB 1.46 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-BtY1hGDO.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-ehTZdDBw.js 2.76 kB 2.76 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-DhnqAfj7.js 2.48 kB 2.48 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-DFci1T8T.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
assets/WidgetToggleSwitch-D6b0vE-q.js 1.58 kB 1.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 17 added / 17 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: 2

🧹 Nitpick comments (2)
src/base/credits/comfyCredits.ts (1)

6-25: Consider adding input validation for edge cases.

The formatNumber function doesn't validate inputs for edge cases like NaN, Infinity, or negative values. While Intl.NumberFormat handles these gracefully, explicit validation and error handling would make the API more robust and prevent unexpected formatting outputs.

Consider adding validation:

 const formatNumber = (
   value: number,
   options: Intl.NumberFormatOptions = DEFAULT_NUMBER_FORMAT,
   locale?: string
 ) => {
+  if (!Number.isFinite(value)) {
+    throw new TypeError(`Expected a finite number, got ${value}`)
+  }
+
   const merged: Intl.NumberFormatOptions = {
     ...DEFAULT_NUMBER_FORMAT,
     ...options
   }
tests-ui/tests/base/credits/comfyCredits.test.ts (1)

18-44: Consider adding edge case tests.

The current test suite covers happy path scenarios but lacks coverage for edge cases such as:

  • Zero values
  • Negative numbers (if supported)
  • Very large numbers
  • Custom formatting options (e.g., different decimal places)
  • The min/max fraction digits correction logic in formatNumber

Consider adding tests like:

test('handles zero values', () => {
  expect(usdToCents(0)).toBe(0)
  expect(formatCredits(0, undefined, 'en-US')).toBe('0.00')
})

test('handles large numbers', () => {
  expect(formatCredits(1000000, undefined, 'en-US')).toBe('1,000,000.00')
})

test('respects custom formatting options', () => {
  expect(formatCredits(1.23456, { maximumFractionDigits: 4 }, 'en-US')).toBe('1.2346')
})

test('corrects invalid min/max fraction digits', () => {
  // When max < min, min should be clamped to max
  expect(formatCredits(1.23456, { 
    minimumFractionDigits: 5, 
    maximumFractionDigits: 2 
  }, 'en-US')).toBe('1.23')
})
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b50b34a and 47d2e14.

📒 Files selected for processing (2)
  • src/base/credits/comfyCredits.ts (1 hunks)
  • tests-ui/tests/base/credits/comfyCredits.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json

Files:

  • src/base/credits/comfyCredits.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursorrules)

Use es-toolkit for utility functions

Files:

  • src/base/credits/comfyCredits.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use TypeScript for type safety

**/*.{ts,tsx}: Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue

Files:

  • src/base/credits/comfyCredits.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (.cursorrules)

Implement proper error handling in components and services

**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in .prettierrc
Organize imports by sorting and grouping by plugin, and run pnpm format before committing

Files:

  • src/base/credits/comfyCredits.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
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/base/credits/comfyCredits.ts
src/**/*.ts

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

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

Files:

  • src/base/credits/comfyCredits.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use camelCase for variable and setting names in TypeScript/Vue files

Files:

  • src/base/credits/comfyCredits.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,vue}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates

Files:

  • src/base/credits/comfyCredits.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
Use defaultsByInstallVersion property for gradual feature rollout based on version in settings configuration

Files:

  • src/base/credits/comfyCredits.ts
  • tests-ui/tests/base/credits/comfyCredits.test.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/base/credits/comfyCredits.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/base/credits/comfyCredits.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{test,spec}.{ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Unit and component tests should be located in tests-ui/ or co-located with components as src/components/**/*.{test,spec}.ts; E2E tests should be in browser_tests/

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Follow naming conventions for browser tests

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Tests should be cross-platform compatible using `path.resolve`, `path.join`, and `path.sep` for Windows, macOS, and Linux compatibility

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Use Vitest (with happy-dom) for unit and component tests, and Playwright for E2E tests

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
🧬 Code graph analysis (1)
tests-ui/tests/base/credits/comfyCredits.test.ts (1)
src/base/credits/comfyCredits.ts (12)
  • COMFY_CREDIT_RATE_CENTS (27-27)
  • COMFY_CREDIT_RATE_USD (28-28)
  • usdToCents (30-30)
  • formatUsdFromCents (63-67)
  • centsToCredits (33-34)
  • creditsToCents (36-37)
  • usdToCredits (39-40)
  • creditsToUsd (42-43)
  • formatCredits (45-49)
  • formatCreditsFromCents (51-55)
  • formatCreditsFromUsd (57-61)
  • formatUsd (69-73)
🪛 ESLint
tests-ui/tests/base/credits/comfyCredits.test.ts

[error] 1-1: Resolve error: EACCES: permission denied, open '/zHNWSHCQkF'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at ExportMap.get (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/export-map.js:88:22)
at processBodyStatement (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:9:31)
at Program (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:100:21)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)

(import-x/namespace)


[error] 1-1: Resolve error: EACCES: permission denied, open '/RgdkawmjpG'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-unresolved.js:31:34)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)

(import-x/no-unresolved)


[error] 1-1: Resolve error: EACCES: permission denied, open '/VbxmqDgBZW'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at importType (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/import-type.js:126:63)
at checkImportForRelativePackage (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:15:38)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:59:40
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)

(import-x/no-relative-packages)


[error] 1-1: Unable to resolve path to module 'vitest'.

(import-x/no-unresolved)


[error] 16-16: Unable to resolve path to module '@/base/credits/comfyCredits'.

(import-x/no-unresolved)

⏰ 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: setup
  • GitHub Check: test
  • GitHub Check: lint-and-format
  • GitHub Check: collect
🔇 Additional comments (2)
src/base/credits/comfyCredits.ts (2)

33-37: Asymmetric rounding may cause precision loss in round-trip conversions.

centsToCredits returns an unrounded result, while creditsToCents rounds. This asymmetry means converting cents→credits→cents may not return the original value.

Example:

const original = 211
const credits = centsToCredits(211)  // 1.004761904...
const backToCents = creditsToCents(credits)  // Math.round(211.00...) = 211 ✓

However, small floating-point errors could accumulate in chains of conversions. Consider whether this is acceptable for your use case or if both functions should round consistently.


39-44: Formatting tests assume en-US locale.

The test assertions use en-US number formatting (e.g., '1,234.57'). These tests will fail in environments with different default locales. Consider explicitly passing a locale to ensure consistent, locale-independent test results.

Wait, I need to review the test file separately. Let me skip this comment here.

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: 1

🧹 Nitpick comments (1)
tests-ui/tests/base/credits/comfyCredits.test.ts (1)

18-46: Consider adding edge case tests.

While the current test coverage is adequate, consider adding tests for edge cases to improve robustness:

  • Zero values (0 credits, 0 USD, 0 cents)
  • Very large numbers (to verify no overflow issues)
  • Rounding behavior at boundaries (e.g., values that round up vs down)
  • Negative values (if applicable to your domain)

Example additions:

test('handles edge cases correctly', () => {
  const locale = 'en-US'
  expect(usdToCents(0)).toBe(0)
  expect(centsToCredits(0)).toBe(0)
  expect(formatUsd(0, locale)).toBe('0.00')
  
  // Test rounding behavior
  expect(usdToCents(1.235)).toBe(124) // rounds to nearest cent
  expect(usdToCents(1.234)).toBe(123)
})
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47d2e14 and e1a6407.

📒 Files selected for processing (2)
  • src/base/credits/comfyCredits.ts (1 hunks)
  • tests-ui/tests/base/credits/comfyCredits.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/base/credits/comfyCredits.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursorrules)

Use es-toolkit for utility functions

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use TypeScript for type safety

**/*.{ts,tsx}: Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (.cursorrules)

Implement proper error handling in components and services

**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in .prettierrc
Organize imports by sorting and grouping by plugin, and run pnpm format before committing

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use camelCase for variable and setting names in TypeScript/Vue files

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,vue}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
Use defaultsByInstallVersion property for gradual feature rollout based on version in settings configuration

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{test,spec}.{ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Unit and component tests should be located in tests-ui/ or co-located with components as src/components/**/*.{test,spec}.ts; E2E tests should be in browser_tests/

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.{ts,tsx,js} : Use es-toolkit for utility functions
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Tests should be cross-platform compatible using `path.resolve`, `path.join`, and `path.sep` for Windows, macOS, and Linux compatibility

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Follow naming conventions for browser tests

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Use Vitest (with happy-dom) for unit and component tests, and Playwright for E2E tests

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
🧬 Code graph analysis (1)
tests-ui/tests/base/credits/comfyCredits.test.ts (1)
src/base/credits/comfyCredits.ts (12)
  • COMFY_CREDIT_RATE_CENTS (27-27)
  • COMFY_CREDIT_RATE_USD (28-28)
  • usdToCents (30-30)
  • formatUsdFromCents (63-67)
  • centsToCredits (33-34)
  • creditsToCents (36-37)
  • usdToCredits (39-40)
  • creditsToUsd (42-43)
  • formatCredits (45-49)
  • formatCreditsFromCents (51-55)
  • formatCreditsFromUsd (57-61)
  • formatUsd (69-73)
🪛 ESLint
tests-ui/tests/base/credits/comfyCredits.test.ts

[error] 1-1: Resolve error: EACCES: permission denied, open '/XSWPeiGcoH'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at ExportMap.get (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/export-map.js:88:22)
at processBodyStatement (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:9:31)
at Program (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:100:21)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)

(import-x/namespace)


[error] 1-1: Resolve error: EACCES: permission denied, open '/bQNEyktcgu'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-unresolved.js:31:34)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)

(import-x/no-unresolved)


[error] 1-1: Resolve error: EACCES: permission denied, open '/bmbDktuJVY'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/[email protected]/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/[email protected][email protected]_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at importType (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/import-type.js:126:63)
at checkImportForRelativePackage (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:15:38)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:59:40
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint[email protected]_eslint@[email protected]__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/[email protected][email protected]/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)

(import-x/no-relative-packages)


[error] 1-1: Unable to resolve path to module 'vitest'.

(import-x/no-unresolved)


[error] 16-16: Unable to resolve path to module '@/base/credits/comfyCredits'.

(import-x/no-unresolved)

⏰ 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). (5)
  • GitHub Check: deploy-and-comment
  • GitHub Check: test
  • GitHub Check: setup
  • GitHub Check: collect
  • GitHub Check: lint-and-format
🔇 Additional comments (5)
tests-ui/tests/base/credits/comfyCredits.test.ts (5)

1-16: Imports look good.

The imports follow project guidelines by using test from vitest and correctly import all necessary functions from the comfyCredits module.


19-22: Constant verification is correct.

The test properly verifies both conversion rate constants and uses toBeCloseTo for floating-point comparison.


29-32: Conversion logic is verified correctly.

The tests properly verify bidirectional conversion between cents and credits with appropriate assertions.


34-37: USD/credits conversions are correct.

The bidirectional conversion tests properly verify the math: 2.1 USD = 210 cents = 1 credit, and 3.5 credits = 735 cents = 7.35 USD.


39-45: Formatting tests with explicit locale look good.

The explicit 'en-US' locale parameter ensures consistent test results across different environments, addressing previous review feedback.

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: 0

🧹 Nitpick comments (4)
src/base/credits/comfyCredits.ts (1)

1-29: formatNumber guard may surprise callers when minFractionDigits > default max

The min/max guard prevents Intl from throwing, which is good, but in the case where a caller sets minimumFractionDigits higher than the default maximumFractionDigits, the current fix (minimum = maximum) silently drops the requested precision. You may want to instead raise maximumFractionDigits to minimumFractionDigits (or let Intl throw) so that explicit caller intent for more decimals is preserved.

-  if (
-    typeof merged.maximumFractionDigits === 'number' &&
-    typeof merged.minimumFractionDigits === 'number' &&
-    merged.maximumFractionDigits < merged.minimumFractionDigits
-  ) {
-    merged.minimumFractionDigits = merged.maximumFractionDigits
-  }
+  if (
+    typeof merged.maximumFractionDigits === 'number' &&
+    typeof merged.minimumFractionDigits === 'number' &&
+    merged.maximumFractionDigits < merged.minimumFractionDigits
+  ) {
+    merged.maximumFractionDigits = merged.minimumFractionDigits
+  }
src/components/common/UserCredit.vue (1)

35-38: Confirm units for amount_micros and consider localizing the "credits" suffix

This computed assumes authStore.balance?.amount_micros is already in cents. If it is still in micros (as the name suggests), this will inflate displayed credits by 10,000×. Please double‑check the backend/SDK type for amount_micros and, if it’s micros, convert to cents before calling formatCreditsFromCents.

Also, per the project i18n guidelines, the 'credits' suffix should ideally come from vue‑i18n rather than being hard‑coded in the computed string (e.g., use a translation like credits.balanceLabel with the formatted number as an interpolation parameter).

src/components/dialog/content/credit/CreditTopUpOption.vue (1)

9-28: Tighten display amount handling and centralize USD/credits labeling

The editable/non‑editable display logic is generally solid, but a few details are worth tightening up:

  • displayUsdAmount uses Math.max(1, editable ? customAmount.value : amount). In edge cases where amount or customAmount could be 0 or negative (e.g., transient InputNumber states), the displayed USD/credits would be clamped to 1 while handleBuyNow still uses the raw amount/customAmount. If that’s a realistic scenario, consider aligning the purchase amount with displayUsdAmount or clamping earlier (e.g., in the ref) so display and behavior always match.
  • formattedUsd manually builds a $${...toFixed(2)} string using usdToCents. Since you already have formatUsd/formatUsdFromCents in comfyCredits.ts, it may be cleaner and more consistent to use those helpers for USD formatting instead of re‑implementing the pattern here.
  • As in other files, the "credits" suffix is hard‑coded in formattedCredits. To follow the i18n guidance, consider moving this to a vue‑i18n key (e.g., credits.topUp.optionLabel) and interpolating the formatted numeric part.

Also applies to: 72-83

src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)

3-14: Verify balance units and consider i18n for the "credits" suffix

formatBalance assumes the *_micros fields from authStore.balance are already in cents (maybeCents). If those fields are still micros, this will vastly overstate the user’s credit amounts. Please confirm the unit of amount_micros, cloud_credit_balance_micros, and prepaid_balance_micros and, if needed, convert micros → cents before calling formatCreditsFromCents.

Since formatBalance produces user-facing strings (including ' credits'), it would also be more in line with the i18n guidelines to move the suffix into a vue‑i18n translation (e.g., credits.subscription.balance) and let components or composables interpolate the numeric portion.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1a6407 and ca13f55.

📒 Files selected for processing (5)
  • src/base/credits/comfyCredits.ts (1 hunks)
  • src/components/common/UserCredit.vue (3 hunks)
  • src/components/dialog/content/credit/CreditTopUpOption.vue (3 hunks)
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1 hunks)
  • tests-ui/tests/base/credits/comfyCredits.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests-ui/tests/base/credits/comfyCredits.test.ts
🧰 Additional context used
📓 Path-based instructions (21)
**/*.vue

📄 CodeRabbit inference engine (.cursorrules)

**/*.vue: Use setup() function for component logic in Vue 3 Composition API
Utilize ref and reactive for reactive state in Vue 3
Implement computed properties with computed() function
Use watch and watchEffect for side effects in Vue 3
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection in Vue 3
Use Vue 3.5 style of default prop declaration with defineProps()
Organize Vue components in <script> <style> order
Use Tailwind CSS for styling Vue components
Implement responsive design with Tailwind CSS
Do not use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage). Use replacements: Select, Popover, DatePicker, ToggleSwitch, Drawer, AutoComplete, Tabs, Stepper, Message respectively
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components in Vue 3
Follow Vue 3 style guide and naming conventions
Never use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage)

Never use :class="[]" to merge class names - always use import { cn } from '@/utils/tailwindUtil' for class merging in Vue templates

**/*.vue: Use TypeScript with Vue 3 Single File Components (.vue files)
Name Vue components in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (.cursorrules)

Implement proper error handling in components and services

**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in .prettierrc
Organize imports by sorting and grouping by plugin, and run pnpm format before committing

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use camelCase for variable and setting names in TypeScript/Vue files

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
**/*.{vue,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Never use dark: or dark-theme: Tailwind variants - instead use semantic values from style.css theme, e.g. bg-node-component-surface

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,vue}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursorrules)

Use es-toolkit for utility functions

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use TypeScript for type safety

**/*.{ts,tsx}: Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
src/**/*.ts

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

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

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
Use defaultsByInstallVersion property for gradual feature rollout based on version in settings configuration

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.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/useSubscriptionCredits.ts
**/composables/use*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables in the format useXyz.ts

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
🧠 Learnings (12)
📚 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 : Replace PrimeVue InputSwitch component with ToggleSwitch

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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 : Replace PrimeVue Calendar component with DatePicker

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Do not use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage). Use replacements: Select, Popover, DatePicker, ToggleSwitch, Drawer, AutoComplete, Tabs, Stepper, Message respectively

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Never use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage)

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Utilize ref and reactive for reactive state in Vue 3

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.{vue,ts,tsx} : Leverage VueUse functions for performance-enhancing utilities

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.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 : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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/components/dialog/content/credit/CreditTopUpOption.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 : Replace PrimeVue Steps component with Stepper without panels

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Implement computed properties with computed() function

Applied to files:

  • src/components/common/UserCredit.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/composables/useSubscriptionCredits.ts
🧬 Code graph analysis (1)
src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (2)
src/stores/firebaseAuthStore.ts (1)
  • useFirebaseAuthStore (53-473)
src/base/credits/comfyCredits.ts (1)
  • formatCreditsFromCents (61-74)
⏰ 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: setup
  • GitHub Check: lint-and-format
  • GitHub Check: collect
  • GitHub Check: test
🔇 Additional comments (5)
src/base/credits/comfyCredits.ts (2)

31-47: Conversion helpers look consistent and numerically sane

The cents↔USD↔credits helpers (usdToCents, centsToCredits, creditsToCents, usdToCredits, creditsToUsd) are internally consistent, use integer cents as the base, and correctly apply rounding where needed. This should give stable round‑trips at cent precision for realistic values.


48-115: Formatting wrappers provide a clean, typed surface over Intl

FormatOptions plus the formatCredits* / formatUsd* functions are nicely typed and keep formatting concerns (locale, options) decoupled from conversion concerns. The shared formatNumber core should make future tweaks to default fraction digits or locales straightforward.

src/components/common/UserCredit.vue (1)

10-15: Wallet icon change is consistent with credit semantics

Switching the Tag icon to pi pi-wallet better matches the credit/balance concept and keeps visuals aligned with the other updated credit UIs.

src/components/dialog/content/credit/CreditTopUpOption.vue (1)

3-8: Wallet icon matches other credit-related components

The Tag icon update to pi pi-wallet keeps this top-up option visually in sync with the rest of the credit UI.

src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)

15-49: Computed credit strings with fallback behavior look good

The three computed values (totalCredits, monthlyBonusCredits, prepaidCredits) consistently use formatBalance, catch formatting errors, log a descriptive message, and fall back to formatting 0 credits. This should make the UI resilient to missing/invalid balance data while still surfacing issues in the console.

@christian-byrne christian-byrne added needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch core/1.33 Backport PRs for core 1.33 cloud/1.33 Backport PRs for cloud 1.33 labels Dec 2, 2025
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: 1

♻️ Duplicate comments (2)
tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts (1)

1-3: Prefer test over it in new Vitest suites

Project unit-test guidelines call for test instead of it. For consistency with other updated specs (e.g., comfyCredits tests), consider importing test from vitest and renaming these cases accordingly.

Also applies to: 53-66

tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)

2-2: Align on test instead of it for Vitest cases

This spec still imports and uses it even though the project test rules prefer test. For consistency with comfyCredits.test.ts and future maintenance, consider switching to:

-import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { beforeEach, describe, expect, test, vi } from 'vitest'

and renaming each it( to test(.

Also applies to: 78-147

🧹 Nitpick comments (1)
tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)

80-96: Avoid as any on mocked balances where possible

Several expectations rely on authStore.balance = { ... } as any. If there’s a balance type exported from the store (or a shared interface), consider using a more specific type (e.g., Partial<BalanceType>) instead of as any to keep these tests type-safe while still minimal.

Also applies to: 111-121, 125-135

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca13f55 and d1006dd.

📒 Files selected for processing (8)
  • src/base/credits/comfyCredits.ts (1 hunks)
  • src/components/common/UserCredit.vue (2 hunks)
  • src/components/dialog/content/credit/CreditTopUpOption.vue (3 hunks)
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1 hunks)
  • tests-ui/tests/base/credits/comfyCredits.test.ts (1 hunks)
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts (1 hunks)
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts (2 hunks)
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/base/credits/comfyCredits.ts
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
🧰 Additional context used
📓 Path-based instructions (21)
**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/common/UserCredit.vue
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursorrules)

Use es-toolkit for utility functions

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use TypeScript for type safety

**/*.{ts,tsx}: Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (.cursorrules)

Implement proper error handling in components and services

**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in .prettierrc
Organize imports by sorting and grouping by plugin, and run pnpm format before committing

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/common/UserCredit.vue
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use camelCase for variable and setting names in TypeScript/Vue files

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/common/UserCredit.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,vue}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/common/UserCredit.vue
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
Use defaultsByInstallVersion property for gradual feature rollout based on version in settings configuration

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
**/*.{test,spec}.{ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Unit and component tests should be located in tests-ui/ or co-located with components as src/components/**/*.{test,spec}.ts; E2E tests should be in browser_tests/

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
**/*.vue

📄 CodeRabbit inference engine (.cursorrules)

**/*.vue: Use setup() function for component logic in Vue 3 Composition API
Utilize ref and reactive for reactive state in Vue 3
Implement computed properties with computed() function
Use watch and watchEffect for side effects in Vue 3
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection in Vue 3
Use Vue 3.5 style of default prop declaration with defineProps()
Organize Vue components in <script> <style> order
Use Tailwind CSS for styling Vue components
Implement responsive design with Tailwind CSS
Do not use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage). Use replacements: Select, Popover, DatePicker, ToggleSwitch, Drawer, AutoComplete, Tabs, Stepper, Message respectively
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components in Vue 3
Follow Vue 3 style guide and naming conventions
Never use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage)

Never use :class="[]" to merge class names - always use import { cn } from '@/utils/tailwindUtil' for class merging in Vue templates

**/*.vue: Use TypeScript with Vue 3 Single File Components (.vue files)
Name Vue components in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
**/*.{vue,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Never use dark: or dark-theme: Tailwind variants - instead use semantic values from style.css theme, e.g. bg-node-component-surface

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
**/composables/use*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables in the format useXyz.ts

Files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
🧠 Learnings (32)
📓 Common learnings
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js} : Unit and component tests should be located in `tests-ui/` or co-located with components as `src/components/**/*.{test,spec}.ts`; E2E tests should be in `browser_tests/`

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Use Vitest (with happy-dom) for unit and component tests, and Playwright for E2E tests

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.{vue,ts,tsx} : Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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/components/dialog/content/credit/CreditTopUpOption.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 : Replace PrimeVue InputSwitch component with ToggleSwitch

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Do not use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage). Use replacements: Select, Popover, DatePicker, ToggleSwitch, Drawer, AutoComplete, Tabs, Stepper, Message respectively

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Never use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage)

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.{vue,ts,tsx} : Leverage VueUse functions for performance-enhancing utilities

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Utilize ref and reactive for reactive state in Vue 3

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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 : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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 : Replace PrimeVue Calendar component with DatePicker

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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 : Replace PrimeVue Steps component with Stepper without panels

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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/components/dialog/content/credit/CreditTopUpOption.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 : Replace PrimeVue Dropdown component with Select

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Vitest test files should use coverage enabled with text, json, and html reporters as configured in `vitest.config.ts`

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Follow naming conventions for browser tests

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Tests should be cross-platform compatible using `path.resolve`, `path.join`, and `path.sep` for Windows, macOS, and Linux compatibility

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.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/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 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 vue-i18n for ALL UI strings

Applied to files:

  • src/components/common/UserCredit.vue
🧬 Code graph analysis (2)
tests-ui/tests/base/credits/comfyCredits.test.ts (1)
src/base/credits/comfyCredits.ts (12)
  • COMFY_CREDIT_RATE_CENTS (31-31)
  • COMFY_CREDIT_RATE_USD (32-32)
  • usdToCents (34-34)
  • formatUsdFromCents (102-115)
  • centsToCredits (36-37)
  • creditsToCents (39-40)
  • usdToCredits (42-43)
  • creditsToUsd (45-46)
  • formatCredits (54-59)
  • formatCreditsFromCents (61-74)
  • formatCreditsFromUsd (76-89)
  • formatUsd (91-100)
tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)
src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)
  • useSubscriptionCredits (10-65)
⏰ 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). (5)
  • GitHub Check: deploy-and-comment
  • GitHub Check: setup
  • GitHub Check: test
  • GitHub Check: collect
  • GitHub Check: lint-and-format
🔇 Additional comments (5)
src/components/common/UserCredit.vue (1)

12-17: Credits formatting + i18n usage looks solid

Using formatCreditsFromCents with a safe ?? 0 default and appending t('credits.credits') gives consistent, localized "0.00 Credits"-style output and avoids balance null/undefined pitfalls. The wallet icon change also matches the new credits-focused UX.

Also applies to: 24-27, 35-42

tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts (1)

20-24: Mocks and expectations aligned with new credits formatting

Updating mockCreditsData and assertions to "10.00 Credits" / "5.00 Credits" keeps this suite consistent with the centralized credits formatter and suffix semantics.

Also applies to: 155-159

tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts (1)

53-66: Coverage for credit/USD display behavior looks good

The tests exercise both preset and editable flows, verifying "1.00 Credits" / "$2.10" as well as the recomputed "2.00 Credits" label when customAmount changes, which matches the comfyCredits helpers’ behavior.

tests-ui/tests/base/credits/comfyCredits.test.ts (1)

1-46: Comprehensive, locale-stable coverage for comfyCredits

These tests thoroughly cover conversion helpers and formatting, and the explicit 'en-US' locale on formatting calls prevents locale-dependent flakiness. This gives strong confidence in the new credits utilities.

tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)

4-16: Tests accurately mirror credits formatting and fallback behavior

The new cases around "0.00 Credits" defaults, specific cent values (210/420/630), and the formatCreditsFromCents error spy all line up with useSubscriptionCredits’s formatBalance and try/catch fallback, giving good regression coverage for the new credits-domain logic.

Also applies to: 78-107, 111-121, 125-135

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: 0

Caution

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

⚠️ Outside diff range comments (1)
src/components/dialog/content/credit/CreditTopUpOption.vue (1)

98-106: Guard purchaseCredits with try/finally so loading state can’t get stuck

If authActions.purchaseCredits rejects, loading.value stays true, the spinner never clears, and didClickBuyNow is never set (so no balance refresh on unmount). Wrapping the call in try/finally (and optionally logging) keeps the UI resilient:

-const handleBuyNow = async () => {
-  const creditAmount = displayUsdAmount.value
-  telemetry?.trackApiCreditTopupButtonPurchaseClicked(creditAmount)
-
-  loading.value = true
-  await authActions.purchaseCredits(creditAmount)
-  loading.value = false
-  didClickBuyNow.value = true
-}
+const handleBuyNow = async () => {
+  const creditAmount = displayUsdAmount.value
+  telemetry?.trackApiCreditTopupButtonPurchaseClicked(creditAmount)
+
+  loading.value = true
+  try {
+    await authActions.purchaseCredits(creditAmount)
+    didClickBuyNow.value = true
+  } catch (error) {
+    console.error('[CreditTopUpOption] Failed to purchase credits:', error)
+    // Optionally surface a toast here if desired.
+  } finally {
+    loading.value = false
+  }
+}
🧹 Nitpick comments (5)
src/base/credits/comfyCredits.ts (1)

1-115: Credit conversion and formatting helpers look consistent; minor DRY opportunity

The conversion + formatting pipeline is coherent (usd↔cents↔credits, shared DEFAULT_NUMBER_FORMAT, and the min/max-fraction guard). If you want to pare things down further, you could derive small helper types from FormatOptions for the “from cents/usd” helpers instead of repeating inline { cents|usd; locale?; numberOptions? } shapes, but that’s purely optional.

tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts (1)

1-67: Use test instead of it and be mindful of locale‑dependent formatting

The behavior under test looks correct, but per project test guidelines you should prefer test over it, and the numeric assertions assume an en‑US number format.

You can address both by:

  • Switching to test:
-import { describe, expect, it, vi } from 'vitest'
+import { describe, expect, test, vi } from 'vitest'
@@
-describe('CreditTopUpOption', () => {
-  it('renders converted credit price for preset amounts', () => {
+describe('CreditTopUpOption', () => {
+  test('renders converted credit price for preset amounts', () => {
@@
-  it('updates credit label when editable amount changes', async () => {
+  test('updates credit label when editable amount changes', async () => {
  • If these tests ever need to run under non‑en‑US locales, consider either passing an explicit locale into the comfyCredits helpers (via vue‑i18n’s current locale) or mocking Intl.NumberFormat in the test setup so '1.00' / '$2.10' remain stable across environments.

Based on learnings, the vitest style guidance applies here.

src/components/common/UserCredit.vue (1)

12-42: Pass vue‑i18n locale into formatCreditsFromCents for consistent formatting

The balance calculation itself is sound, but formatCreditsFromCents currently relies on the environment default locale, while labels come from vue‑i18n. To keep digits/grouping aligned with the active app locale, consider:

-const { t } = useI18n()
+const { t, locale } = useI18n()
@@
-  const cents = authStore.balance?.amount_micros ?? 0
-  const amount = formatCreditsFromCents({ cents })
+  const cents = authStore.balance?.amount_micros ?? 0
+  const amount = formatCreditsFromCents({ cents, locale: locale.value })
   return `${amount} ${t('credits.credits')}`

This makes the numeric format follow the same locale as your translations.

As per coding guidelines, vue‑i18n should drive user‑visible formatting.

src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)

2-5: Use vue‑i18n locale when formatting subscription credit balances

formatBalance correctly handles undefined balances and error fallbacks, but like UserCredit.vue it lets formatCreditsFromCents pick the environment locale while labels come from vue‑i18n.

To keep number formatting aligned with your active app locale, you could do:

-export function useSubscriptionCredits() {
-  const authStore = useFirebaseAuthStore()
-  const { t } = useI18n()
+export function useSubscriptionCredits() {
+  const authStore = useFirebaseAuthStore()
+  const { t, locale } = useI18n()
@@
-    const cents = maybeCents ?? 0
-    const amount = formatCreditsFromCents({ cents })
+    const cents = maybeCents ?? 0
+    const amount = formatCreditsFromCents({
+      cents,
+      locale: locale.value
+    })

That ensures balances render with the same locale settings as the rest of the subscription UI.

As per coding guidelines, vue‑i18n should be the source of truth for user‑visible formatting.

Also applies to: 14-19, 21-55

src/components/dialog/content/credit/CreditTopUpOption.vue (1)

79-96: Wire vue‑i18n locale into credits/USD formatting for consistent output

formattedCredits and formattedUsd use comfyCredits helpers but don’t pass a locale, so formatting may not follow the current vue‑i18n locale.

You can align them with the rest of the app like this:

-const { t } = useI18n()
+const { t, locale } = useI18n()
@@
-const formattedCredits = computed(
-  () =>
-    `${formatCreditsFromUsd({ usd: displayUsdAmount.value })} ${t('credits.credits')}`
-)
+const formattedCredits = computed(
+  () =>
+    `${formatCreditsFromUsd({
+      usd: displayUsdAmount.value,
+      locale: locale.value
+    })} ${t('credits.credits')}`
+)
@@
-const formattedUsd = computed(
-  () => `$${formatUsd({ value: displayUsdAmount.value })}`
-)
+const formattedUsd = computed(
+  () => `$${formatUsd({ value: displayUsdAmount.value, locale: locale.value })}`
+)

This keeps the number formatting (decimal separator, grouping, etc.) in sync with the active translation locale.

As per coding guidelines, vue‑i18n should drive localized formatting in components.

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: 6

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c43bf4 and b23ab6b.

📒 Files selected for processing (8)
  • src/base/credits/comfyCredits.ts (1 hunks)
  • src/components/common/UserCredit.vue (2 hunks)
  • src/components/dialog/content/credit/CreditTopUpOption.vue (3 hunks)
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1 hunks)
  • tests-ui/tests/base/credits/comfyCredits.test.ts (1 hunks)
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts (1 hunks)
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts (2 hunks)
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (23)
**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/common/UserCredit.vue
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/base/credits/comfyCredits.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursorrules)

Use es-toolkit for utility functions

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/base/credits/comfyCredits.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use TypeScript for type safety

**/*.{ts,tsx}: Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/base/credits/comfyCredits.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (.cursorrules)

Implement proper error handling in components and services

**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in .prettierrc
Organize imports by sorting and grouping by plugin, and run pnpm format before committing

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/common/UserCredit.vue
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/base/credits/comfyCredits.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use camelCase for variable and setting names in TypeScript/Vue files

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/common/UserCredit.vue
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/base/credits/comfyCredits.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,vue}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/common/UserCredit.vue
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/base/credits/comfyCredits.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
Use defaultsByInstallVersion property for gradual feature rollout based on version in settings configuration

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/base/credits/comfyCredits.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
**/*.{test,spec}.{ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Unit and component tests should be located in tests-ui/ or co-located with components as src/components/**/*.{test,spec}.ts; E2E tests should be in browser_tests/

Files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
**/composables/use*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables in the format useXyz.ts

Files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
**/*.vue

📄 CodeRabbit inference engine (.cursorrules)

**/*.vue: Use setup() function for component logic in Vue 3 Composition API
Utilize ref and reactive for reactive state in Vue 3
Implement computed properties with computed() function
Use watch and watchEffect for side effects in Vue 3
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection in Vue 3
Use Vue 3.5 style of default prop declaration with defineProps()
Organize Vue components in <script> <style> order
Use Tailwind CSS for styling Vue components
Implement responsive design with Tailwind CSS
Do not use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage). Use replacements: Select, Popover, DatePicker, ToggleSwitch, Drawer, AutoComplete, Tabs, Stepper, Message respectively
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components in Vue 3
Follow Vue 3 style guide and naming conventions
Never use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage)

Never use :class="[]" to merge class names - always use import { cn } from '@/utils/tailwindUtil' for class merging in Vue templates

**/*.vue: Use TypeScript with Vue 3 Single File Components (.vue files)
Name Vue components in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.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/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.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/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
**/*.{vue,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Never use dark: or dark-theme: Tailwind variants - instead use semantic values from style.css theme, e.g. bg-node-component-surface

Files:

  • src/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.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/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
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/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Files:

  • src/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/common/UserCredit.vue
  • src/components/dialog/content/credit/CreditTopUpOption.vue
src/**/*.ts

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

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

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.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/useSubscriptionCredits.ts
🧠 Learnings (35)
📓 Common learnings
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Vitest test files should use coverage enabled with text, json, and html reporters as configured in `vitest.config.ts`

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Follow naming conventions for browser tests

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Tests should be cross-platform compatible using `path.resolve`, `path.join`, and `path.sep` for Windows, macOS, and Linux compatibility

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Use Vitest (with happy-dom) for unit and component tests, and Playwright for E2E tests

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.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/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.{vue,ts,tsx} : Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.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/**/{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/components/common/UserCredit.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 vue-i18n for ALL UI strings

Applied to files:

  • src/components/common/UserCredit.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 : Replace PrimeVue InputSwitch component with ToggleSwitch

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Do not use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage). Use replacements: Select, Popover, DatePicker, ToggleSwitch, Drawer, AutoComplete, Tabs, Stepper, Message respectively

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Never use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage)

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.{vue,ts,tsx} : Leverage VueUse functions for performance-enhancing utilities

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Utilize ref and reactive for reactive state in Vue 3

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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 : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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 : Replace PrimeVue Calendar component with DatePicker

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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 : Replace PrimeVue Steps component with Stepper without panels

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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/components/dialog/content/credit/CreditTopUpOption.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 : Replace PrimeVue Dropdown component with Select

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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/composables/useSubscriptionCredits.ts
📚 Learning: 2025-11-24T19:47:14.779Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:14.779Z
Learning: Applies to **/*.{ts,tsx,vue} : Use `const settingStore = useSettingStore()` and `settingStore.get('Comfy.SomeSetting')` to retrieve settings in TypeScript/Vue files

Applied to files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-24T19:46:52.279Z
Learning: Applies to **/*.vue : Implement computed properties with computed() function

Applied to files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js} : Unit and component tests should be located in `tests-ui/` or co-located with components as `src/components/**/*.{test,spec}.ts`; E2E tests should be in `browser_tests/`

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
🧬 Code graph analysis (3)
tests-ui/tests/base/credits/comfyCredits.test.ts (1)
src/base/credits/comfyCredits.ts (11)
  • COMFY_CREDIT_RATE_CENTS (31-31)
  • COMFY_CREDIT_RATE_USD (32-32)
  • usdToCents (34-34)
  • centsToCredits (36-37)
  • creditsToCents (39-40)
  • usdToCredits (42-43)
  • creditsToUsd (45-46)
  • formatCredits (54-59)
  • formatCreditsFromCents (61-74)
  • formatCreditsFromUsd (76-89)
  • formatUsd (91-100)
tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)
src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)
  • useSubscriptionCredits (10-68)
src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (2)
src/stores/firebaseAuthStore.ts (1)
  • useFirebaseAuthStore (53-473)
src/base/credits/comfyCredits.ts (1)
  • formatCreditsFromCents (61-74)
⏰ 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: test
  • GitHub Check: setup
  • GitHub Check: lint-and-format
  • GitHub Check: collect
🔇 Additional comments (18)
tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts (1)

154-159: LGTM: Tests correctly validate formatted credit display.

The expectations properly verify that the component displays formatted credit values with the localized suffix.

src/components/common/UserCredit.vue (3)

12-12: LGTM: Icon updated to better represent credits.

The change from pi-dollar to pi-wallet better reflects the shift from USD to credits-based display.


37-45: LGTM: Proper i18n integration for credit formatting.

The implementation correctly uses formatCreditsFromCents with locale-aware formatting and appends the translated credits label via t('credits.credits'). The fallback to 0 when balance is undefined is appropriate.

As per coding guidelines, using vue-i18n in Composition API for user-facing strings.


37-45: Clarify the units of amount_micros with the backend team.

The field is documented as microamount (1/1,000,000 of currency unit) in the API schema, yet the frontend code treats it as cents by passing it directly to formatCreditsFromCents() which divides by 210 (the cent-to-credit rate). The test case confirms 210 units map to 1 credit, consistent with cent units. Verify with the backend team whether amount_micros actually contains cents (1/100) or true micros (1/1,000,000), or if the field should be renamed for clarity.

tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts (1)

5-25: LGTM: Clean mock setup following project patterns.

The mocks for Firebase auth actions and telemetry are concise and use vitest mock functions appropriately. The i18n setup is minimal but sufficient for testing credit formatting.

Based on learnings, using existing test utilities and vitest mock functions.

tests-ui/tests/base/credits/comfyCredits.test.ts (1)

1-46: LGTM: Comprehensive test coverage with proper locale handling.

The test suite correctly:

  • Uses test instead of it per project guidelines
  • Passes explicit locale ('en-US') to all formatting functions, preventing flakiness
  • Covers all core conversion functions (USD↔cents↔credits)
  • Validates both conversion rates and formatting output
  • Uses appropriate assertions (toBe for exact matches, toBeCloseTo for floating-point comparisons)

Based on learnings, following existing test patterns and addressing locale-dependent formatting concerns from past reviews.

tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (3)

8-17: LGTM: Proper i18n mock setup.

The vue-i18n mock correctly returns the translation token and locale, allowing tests to verify the complete formatted output including the translated suffix.


98-108: LGTM: Excellent error handling test.

The test properly uses a spy to simulate formatting errors and verifies that the composable falls back gracefully to formatting 0. The spy is restored after the test, preventing interference with other tests.

Based on learnings, using vitest mock functions appropriately.


92-96: Test values correctly demonstrate credit conversion.

The test uses amount_micros: 210 which, given the conversion rate of 210 cents per credit, correctly results in '1.00 Credits'. The test values (210, 420, 630) are well-chosen multiples that produce clean decimal outputs (1.00, 2.00, 3.00).

src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (3)

14-22: LGTM: Clean formatting helper with proper i18n.

The formatBalance helper effectively centralizes the formatting logic:

  • Handles undefined values gracefully with nullish coalescing
  • Uses locale-aware formatting via formatCreditsFromCents
  • Appends translated credits suffix using t('credits.credits')

As per coding guidelines, using vue-i18n for user-facing strings.


24-58: LGTM: Robust error handling with consistent fallback.

All three credit computeds (totalCredits, monthlyBonusCredits, prepaidCredits) follow the same pattern:

  • Try to format the balance value
  • Catch any formatting errors
  • Log the error for debugging
  • Return a safe fallback (formatBalance(0))

This ensures the UI never breaks due to formatting errors.


60-67: LGTM: Added loading state to public API.

The addition of isLoadingBalance to the return value allows consumers to show appropriate loading states while balance data is being fetched.

src/components/dialog/content/credit/CreditTopUpOption.vue (3)

5-5: LGTM: Icon updated for consistency.

The change from pi-dollar to pi-wallet aligns with the shift to credits-based display and matches the icon change in UserCredit.vue.


9-34: LGTM: Clear separation of editable and non-editable modes.

The restructured template provides distinct UX for each mode:

  • Editable: InputNumber with USD prefix and inline credits label
  • Non-editable: Two-line display with emphasized credits and supporting USD

The layout is clear and appropriate for each use case.


80-99: LGTM: Robust clamping and locale-aware formatting.

The implementation correctly:

  • Clamps values between $1 and $1000, handling NaN cases
  • Uses displayUsdAmount to ensure editable and non-editable paths use the same clamped value
  • Formats credits and USD with locale-aware helpers
  • Appends translated credits label

The clamping on input/blur (lines 20-27) addresses the past review comment about keeping input, labels, and purchase amount in sync.

As per coding guidelines, using vue-i18n for user-facing strings and proper computed properties for derived state.

src/base/credits/comfyCredits.ts (3)

20-26: LGTM: Defensive handling of conflicting fraction digit options.

The logic prevents Intl.NumberFormat from throwing when maximumFractionDigits < minimumFractionDigits by adjusting minimumFractionDigits down to match. This ensures formatting never fails due to misconfigured options.


1-115: LGTM: Well-structured credit conversion and formatting module.

The module provides:

  • Clear separation between conversion (USD↔cents↔credits) and formatting
  • Type-safe public API with exported types
  • Consistent 2-decimal formatting via DEFAULT_NUMBER_FORMAT
  • Locale-aware formatting through Intl.NumberFormat
  • Defensive option handling to prevent formatting errors

The structure is clean, testable, and provides all necessary utilities for the credit system.

As per coding guidelines, using proper TypeScript types and avoiding any.


31-46: Add documentation explaining the 210-cent credit rate.

The conversion rate ($2.10 per 1 credit) is mathematically correct and well-tested, but lacks any comment explaining the business rationale. This unusual rate (roughly 0.476 credits per $1 USD) differs from typical SaaS platforms that use larger, rounder scales. Add a comment above COMFY_CREDIT_RATE_CENTS clarifying whether this rate is final, approved, or subject to change—this helps future maintainers understand the intended pricing model.

@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Dec 9, 2025
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)
tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts (1)

3-3: Use test instead of it per project guidelines.

The coding guidelines require using test instead of it for Vitest test cases.

Apply this diff:

-import { describe, expect, it } from 'vitest'
+import { describe, expect, test } from 'vitest'

 describe('CreditTopUpOption', () => {
-  it('renders credit amount and description', () => {
+  test('renders credit amount and description', () => {
     const wrapper = mountOption({ credits: 5000, description: '~500 videos*' })
     expect(wrapper.text()).toContain('5,000')
     expect(wrapper.text()).toContain('~500 videos*')
   })

-  it('applies selected styling when selected', () => {
+  test('applies selected styling when selected', () => {
     const wrapper = mountOption({ selected: true })
     expect(wrapper.find('div').classes()).toContain('bg-surface-secondary')
     expect(wrapper.find('div').classes()).toContain('border-primary')
   })

-  it('applies unselected styling when not selected', () => {
+  test('applies unselected styling when not selected', () => {
     const wrapper = mountOption({ selected: false })
     expect(wrapper.find('div').classes()).toContain('bg-surface-tertiary')
     expect(wrapper.find('div').classes()).toContain('border-border-primary')
   })

-  it('emits select event when clicked', async () => {
+  test('emits select event when clicked', async () => {
     const wrapper = mountOption()
     await wrapper.find('div').trigger('click')
     expect(wrapper.emitted('select')).toHaveLength(1)
   })
 })

Based on learnings and coding guidelines for tests-ui/**/*.test.{js,ts,jsx,tsx}.

Also applies to: 29-52

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b23ab6b and 1305620.

📒 Files selected for processing (7)
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts (1 hunks)
  • src/components/dialog/content/TopUpCreditsDialogContent.vue (2 hunks)
  • src/components/dialog/content/credit/CreditTopUpOption.vue (1 hunks)
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue (1 hunks)
  • src/locales/en/main.json (1 hunks)
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue (3 hunks)
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.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

src/**/*.{ts,tsx,vue}: Write expressive and self-documenting code to reduce the need for comments; clean redundant comments as you go
Consider if there is a simpler way to introduce functionality before writing code; choose the simpler approach when possible
Use refactoring to make complex code simpler
Keep functions short and functional
Minimize nesting in code (e.g., if () { ... } or for () { ... }) to avoid arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions (especially testable ones)
Watch out for code smells and refactor to avoid them
Implement proper error handling in code
If a complex type definition is inlined in multiple related places, extract and name it for reuse

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Name Vue components in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
**/*.{js,ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript exclusively (no new JavaScript)

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs with Composition API only (.vue files)
Use Tailwind 4 styling and avoid <style> blocks in Vue components
Use <script setup lang="ts"> for component logic in Vue components
Use Vue 3.5 TypeScript style of default prop declaration with reactive props destructuring
Do not use withDefaults or runtime props declaration in Vue components
Prefer useModel to separately defining a prop and emit in Vue components
Use ref for reactive state in Vue components
Implement computed properties with computed() instead of using ref and watch
Use watch and watchEffect for side effects in Vue components
Use provide/inject for dependency injection only when simpler alternatives (Store or composable) are not suitable
Do not use the dark: Tailwind variant; use semantic values from style.css theme instead (e.g., bg-node-component-surface)
Use import { cn } from '@/utils/tailwindUtil' to merge class names instead of :class="[]"
Avoid new usage of PrimeVue components
Use VueUse functions for performance-enhancing styles in Vue components
Do not import Vue macros unnecessarily in components
Be judicious with addition of new refs or other state; prefer using props or composables when possible
Do not add a computed if it's possible to use a ref or prop directly
Do not use a watch if a computed would work instead
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Do not use any type in TypeScript code
Do not use as any type assertions in TypeScript code; fix the underlying type issue
Style formatting: 2 space indent, single quotes, no trailing semicolons, 80 character width
Import statements should be sorted and grouped by plugin; run pnpm format before committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use vue-i18n in Composition API for string literals and place new translation entries in src/locales/en/main.json

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
src/**/*.ts

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

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

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.ts: Write unit and component tests in **/*.test.ts
Use Vitest with happy-dom for unit and component tests

Files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
🧠 Learnings (27)
📚 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 : Replace PrimeVue InputSwitch component with ToggleSwitch

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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 : Define proper props and emits definitions in Vue components

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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 : Replace PrimeVue Dropdown component with Select

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Implement proper props and emits definitions in Vue components

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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 proper props and emits definitions

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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 : Prefer emit/event-name for state changes over other communication patterns

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.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/SubscriptionPanel.vue
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.test.ts : Write unit and component tests in `**/*.test.ts`

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.test.ts : Use Vitest with happy-dom for unit and component tests

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Follow naming conventions for browser tests

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
📚 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 : Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)

Applied to files:

  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guide

Applied to files:

  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Use Vue 3.5 TypeScript style of default prop declaration with reactive props destructuring

Applied to files:

  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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/components/dialog/content/credit/LegacyCreditTopUpOption.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Follow Vue 3 style guide and naming conventions

Applied to files:

  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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 : Follow Vue 3 style guide and naming conventions

Applied to files:

  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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 : Use vue 3.5 style of default prop declaration

Applied to files:

  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
🧬 Code graph analysis (1)
src/components/dialog/content/TopUpCreditsDialogContent.stories.ts (1)
src/components/input/SingleSelect.stories.ts (1)
  • Story (40-40)
⏰ 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 (2)
src/components/dialog/content/credit/LegacyCreditTopUpOption.vue (1)

111-116: Consider the implications of fire-and-forget balance refresh.

The onBeforeUnmount hook calls fetchBalance() without awaiting, using void to suppress the floating promise warning. While this prevents blocking unmount, it means the balance refresh may not complete if the component unmounts during navigation, potentially leaving stale data.

If immediate balance consistency is important, consider refreshing the balance in the parent component after the dialog closes, or document that this is a best-effort refresh that may not complete.

// Current approach (fire-and-forget):
void authActions.fetchBalance()

// Alternative: Let parent handle refresh after dialog closes
// Remove onBeforeUnmount and emit an event for parent to handle

This pattern is acceptable if the balance will be refreshed through other means (e.g., when the user returns to a view that displays the balance), but it's worth documenting the intent.

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

124-124: No action needed: composable returns formatted values with units.

The useSubscriptionCredits composable returns formatted strings that include units. The formatBalance function (line 14-22 in useSubscriptionCredits.ts) appends the i18n-translated "credits" unit to the formatted amount: return '${amount} ${t('credits.credits')}'. Removing the dollar sign prefix is appropriate since the composable already provides the full formatted value with unit label.

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: 1

♻️ Duplicate comments (2)
src/components/dialog/content/TopUpCreditsDialogContent.vue (2)

151-168: Make creditOptions reactive to locale changes.

The creditOptions array is initialized once with t() calls, so descriptions won't update if the user changes locale at runtime. This issue was flagged in a previous review and remains unresolved.

Convert to a computed property:

-const creditOptions: CreditOption[] = [
+const creditOptions = computed<CreditOption[]>(() => [
   {
     credits: 1000,
     description: t('credits.topUp.videosEstimate', { count: 100 })
   },
   {
     credits: 5000,
     description: t('credits.topUp.videosEstimate', { count: 500 })
   },
   {
     credits: 10000,
     description: t('credits.topUp.videosEstimate', { count: 1000 })
   },
   {
     credits: 20000,
     description: t('credits.topUp.videosEstimate', { count: 2000 })
   }
-]
+])

As per coding guidelines, this ensures descriptions update immediately when locale changes, improving the i18n user experience.


170-186: Replace placeholder conversion logic and complete success handling.

Multiple issues remain in this function:

  1. Line 178: The conversion uses placeholder logic (selectedCredits.value / 100). According to the PR description, this PR introduces conversion helpers that should be used here.
  2. Line 180: The TODO comment indicates incomplete success handling (no event emission or dialog close).
  3. Line 182: Error handling only logs to console without user-facing feedback.

The conversion logic issue was flagged in a previous review. Import and use the proper conversion utilities from the comfy-credits domain:

+import { creditsToUsd } from '@/utils/comfyCredits'
+
 const handleBuy = async () => {
   if (!selectedCredits.value) return

-  telemetry?.trackApiCreditTopupButtonPurchaseClicked(selectedCredits.value)
-
   loading.value = true
   try {
-    // Convert credits to USD (this would need to be implemented based on your conversion rate)
-    const usdAmount = selectedCredits.value / 100 // Example conversion, adjust as needed
+    const usdAmount = creditsToUsd(selectedCredits.value)
+    telemetry?.trackApiCreditTopupButtonPurchaseClicked(usdAmount)
     await authActions.purchaseCredits(usdAmount)
-    // Optionally emit success event or close dialog
+    // TODO: Emit success event or close dialog on successful purchase
   } catch (error) {
     console.error('Purchase failed:', error)
+    // TODO: Show user-facing error message (e.g., toast notification)
   } finally {
     loading.value = false
   }
 }

The placeholder conversion logic must be fixed before production as it will cause incorrect charges.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1305620 and f3e291d.

📒 Files selected for processing (3)
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts (1 hunks)
  • src/components/dialog/content/TopUpCreditsDialogContent.vue (2 hunks)
  • src/composables/useFeatureFlags.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
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/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/composables/useFeatureFlags.ts
src/**/*.ts

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

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

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/composables/useFeatureFlags.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

src/**/*.{ts,tsx,vue}: Write expressive and self-documenting code to reduce the need for comments; clean redundant comments as you go
Consider if there is a simpler way to introduce functionality before writing code; choose the simpler approach when possible
Use refactoring to make complex code simpler
Keep functions short and functional
Minimize nesting in code (e.g., if () { ... } or for () { ... }) to avoid arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions (especially testable ones)
Watch out for code smells and refactor to avoid them
Implement proper error handling in code
If a complex type definition is inlined in multiple related places, extract and name it for reuse

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/composables/useFeatureFlags.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/composables/useFeatureFlags.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/composables/useFeatureFlags.ts
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/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/composables/useFeatureFlags.ts
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
**/*.{js,ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript exclusively (no new JavaScript)

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/composables/useFeatureFlags.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Do not use any type in TypeScript code
Do not use as any type assertions in TypeScript code; fix the underlying type issue
Style formatting: 2 space indent, single quotes, no trailing semicolons, 80 character width
Import statements should be sorted and grouped by plugin; run pnpm format before committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/composables/useFeatureFlags.ts
**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use vue-i18n in Composition API for string literals and place new translation entries in src/locales/en/main.json

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/composables/useFeatureFlags.ts
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/components/dialog/content/TopUpCreditsDialogContent.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Name Vue components in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs with Composition API only (.vue files)
Use Tailwind 4 styling and avoid <style> blocks in Vue components
Use <script setup lang="ts"> for component logic in Vue components
Use Vue 3.5 TypeScript style of default prop declaration with reactive props destructuring
Do not use withDefaults or runtime props declaration in Vue components
Prefer useModel to separately defining a prop and emit in Vue components
Use ref for reactive state in Vue components
Implement computed properties with computed() instead of using ref and watch
Use watch and watchEffect for side effects in Vue components
Use provide/inject for dependency injection only when simpler alternatives (Store or composable) are not suitable
Do not use the dark: Tailwind variant; use semantic values from style.css theme instead (e.g., bg-node-component-surface)
Use import { cn } from '@/utils/tailwindUtil' to merge class names instead of :class="[]"
Avoid new usage of PrimeVue components
Use VueUse functions for performance-enhancing styles in Vue components
Do not import Vue macros unnecessarily in components
Be judicious with addition of new refs or other state; prefer using props or composables when possible
Do not add a computed if it's possible to use a ref or prop directly
Do not use a watch if a computed would work instead
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/dialog/content/TopUpCreditsDialogContent.vue
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/composables/useFeatureFlags.ts
src/composables/use*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables as useXyz.ts

Files:

  • src/composables/useFeatureFlags.ts
🧠 Learnings (6)
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.{ts,vue} : Use vue-i18n in Composition API for string literals and place new translation entries in `src/locales/en/main.json`

Applied to files:

  • src/components/dialog/content/TopUpCreditsDialogContent.vue
📚 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/components/dialog/content/TopUpCreditsDialogContent.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/components/dialog/content/TopUpCreditsDialogContent.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/components/dialog/content/TopUpCreditsDialogContent.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/components/dialog/content/TopUpCreditsDialogContent.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Implement computed properties with `computed()` instead of using `ref` and `watch`

Applied to files:

  • src/components/dialog/content/TopUpCreditsDialogContent.vue
🧬 Code graph analysis (2)
src/components/dialog/content/TopUpCreditsDialogContent.stories.ts (1)
src/components/input/SingleSelect.stories.ts (1)
  • Story (40-40)
src/composables/useFeatureFlags.ts (1)
src/scripts/api.ts (1)
  • api (1289-1289)
🔇 Additional comments (3)
src/composables/useFeatureFlags.ts (1)

12-13: LGTM!

The new SUBSCRIPTION_TIERS_ENABLED feature flag is implemented consistently with existing flags and properly defaults to true for the new design.

Also applies to: 35-41

src/components/dialog/content/TopUpCreditsDialogContent.stories.ts (1)

1-41: LGTM!

The Storybook setup is well-structured with proper TypeScript typing, clear documentation, and coverage of both refreshDate states (present and undefined).

src/components/dialog/content/TopUpCreditsDialogContent.vue (1)

110-138: LGTM!

The imports, interface definition, and props destructuring follow Vue 3.5 Composition API patterns correctly. The CreditOption interface is well-defined, and the new refreshDate prop is properly typed as optional.

christian-byrne and others added 5 commits December 9, 2025 02:13
- Add new credit selection UI matching Figma design (1k, 5k, 10k, 20k credits)
- Remove manual input, use predefined amounts with video estimates
- Integrate with subscription_tiers_enabled feature flag (defaults to true)
- Fix credit to USD conversion using proper comfyCredits utilities
- Add user-facing error handling with toast notifications
- Extract shared parameter types in comfyCredits.ts for better DRY
- Add reactive feature flag support with computed()
- Create Storybook stories for easy testing
- Maintain backward compatibility with legacy design

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

Co-Authored-By: Claude <[email protected]>
- Add formatCreditsFromSubscriptionMicros for special backend format
- Update useSubscriptionCredits to use subscription-specific conversion
- Fix test mocking to use new function
- Keep standard credit conversion unchanged (210 credits per USD)
- Backend sends subscription data in format where 210 units = 1 credit

🤖 Generated with Claude Code

Co-Authored-By: Claude <[email protected]>
- Replace inline formatting with shared formatters in TopUpCreditsDialogContent
- Fix error handling in LegacyCreditTopUpOption to prevent stuck loading state
- Extract clampUsd function to shared utilities for reuse
- Replace local Intl.NumberFormat with shared formatCredits utility
- Remove accidentally committed markdown file
Return 0 immediately for NaN values instead of clamping NaN->0->1,
making the actual behavior consistent with the documented behavior.
- Update CREDITS_PER_USD constant and all dependent calculations
- Update test expectations to match new conversion rate
- Update subscription conversion comments and test values
The test was failing because subscriptionTiersEnabled defaults to true,
causing isCreditsBadge to check for componentIconSvg instead of unicode.
Mock the feature flag to false to test legacy badge behavior.
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: 5

♻️ Duplicate comments (4)
tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts (1)

19-24: Mock data still hardcodes formatted strings instead of raw values.

The mock now returns fully formatted strings like '10.00 Credits' matching the updated composable output. However, this still tightly couples the test to the formatting implementation as previously noted. If the formatting logic changes, both the composable and these mocks must be updated.

tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts (1)

1-52: Use test instead of it per project guidelines.

Based on the coding guidelines, test cases should use test instead of it in Vitest. This has been noted in previous reviews.

tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)

2-2: Use test instead of it per project guidelines.

The test cases use it but project guidelines require test in Vitest. This has been noted in previous reviews.

Also applies to: 80-140

src/components/dialog/content/TopUpCreditsDialogContent.vue (1)

158-175: Make creditOptions reactive to locale changes.

The creditOptions array is initialized once with t() calls, so descriptions won't update if the user changes locale at runtime. Convert to a computed property.

-const creditOptions: CreditOption[] = [
+const creditOptions = computed<CreditOption[]>(() => [
   {
     credits: 1000,
     description: t('credits.topUp.videosEstimate', { count: 100 })
   },
   // ... other options
-]
+])

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between caea6ae and 3cf8c9d.

📒 Files selected for processing (14)
  • src/base/credits/comfyCredits.ts (1 hunks)
  • src/components/common/UserCredit.vue (2 hunks)
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts (1 hunks)
  • src/components/dialog/content/TopUpCreditsDialogContent.vue (2 hunks)
  • src/components/dialog/content/credit/CreditTopUpOption.vue (1 hunks)
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue (1 hunks)
  • src/composables/useFeatureFlags.ts (1 hunks)
  • src/locales/en/main.json (1 hunks)
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue (3 hunks)
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1 hunks)
  • tests-ui/tests/base/credits/comfyCredits.test.ts (1 hunks)
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts (1 hunks)
  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts (2 hunks)
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (18)
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{js,ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript exclusively (no new JavaScript)

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/base/credits/comfyCredits.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/composables/useFeatureFlags.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Do not use any type in TypeScript code
Do not use as any type assertions in TypeScript code; fix the underlying type issue
Style formatting: 2 space indent, single quotes, no trailing semicolons, 80 character width
Import statements should be sorted and grouped by plugin; run pnpm format before committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/base/credits/comfyCredits.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/composables/useFeatureFlags.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.ts: Write unit and component tests in **/*.test.ts
Use Vitest with happy-dom for unit and component tests

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use vue-i18n in Composition API for string literals and place new translation entries in src/locales/en/main.json

Files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/base/credits/comfyCredits.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/composables/useFeatureFlags.ts
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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/base/credits/comfyCredits.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/composables/useFeatureFlags.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

src/**/*.{ts,tsx,vue}: Write expressive and self-documenting code to reduce the need for comments; clean redundant comments as you go
Consider if there is a simpler way to introduce functionality before writing code; choose the simpler approach when possible
Use refactoring to make complex code simpler
Keep functions short and functional
Minimize nesting in code (e.g., if () { ... } or for () { ... }) to avoid arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions (especially testable ones)
Watch out for code smells and refactor to avoid them
Implement proper error handling in code
If a complex type definition is inlined in multiple related places, extract and name it for reuse

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/base/credits/comfyCredits.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/composables/useFeatureFlags.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/composables/useFeatureFlags.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/base/credits/comfyCredits.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/composables/useFeatureFlags.ts
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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
  • src/composables/useFeatureFlags.ts
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Name Vue components in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3 SFCs with Composition API only (.vue files)
Use Tailwind 4 styling and avoid <style> blocks in Vue components
Use <script setup lang="ts"> for component logic in Vue components
Use Vue 3.5 TypeScript style of default prop declaration with reactive props destructuring
Do not use withDefaults or runtime props declaration in Vue components
Prefer useModel to separately defining a prop and emit in Vue components
Use ref for reactive state in Vue components
Implement computed properties with computed() instead of using ref and watch
Use watch and watchEffect for side effects in Vue components
Use provide/inject for dependency injection only when simpler alternatives (Store or composable) are not suitable
Do not use the dark: Tailwind variant; use semantic values from style.css theme instead (e.g., bg-node-component-surface)
Use import { cn } from '@/utils/tailwindUtil' to merge class names instead of :class="[]"
Avoid new usage of PrimeVue components
Use VueUse functions for performance-enhancing styles in Vue components
Do not import Vue macros unnecessarily in components
Be judicious with addition of new refs or other state; prefer using props or composables when possible
Do not add a computed if it's possible to use a ref or prop directly
Do not use a watch if a computed would work instead
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
src/**/*.ts

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

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

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/base/credits/comfyCredits.ts
  • src/composables/useFeatureFlags.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/useSubscriptionCredits.ts
  • src/composables/useFeatureFlags.ts
src/composables/use*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables as useXyz.ts

Files:

  • src/composables/useFeatureFlags.ts
🧠 Learnings (41)
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 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:

  • tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts
  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.stories.ts
  • src/base/credits/comfyCredits.ts
  • src/composables/useFeatureFlags.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.test.ts : Write unit and component tests in `**/*.test.ts`

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.test.ts : Use Vitest with happy-dom for unit and component tests

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Follow naming conventions for browser tests

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 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 : Replace PrimeVue InputSwitch component with ToggleSwitch

Applied to files:

  • src/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
📚 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/components/dialog/content/credit/CreditTopUpOption.vue
  • tests-ui/tests/base/credits/comfyCredits.test.ts
  • src/components/dialog/content/TopUpCreditsDialogContent.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/components/dialog/content/credit/CreditTopUpOption.vue
  • src/components/common/UserCredit.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/platform/cloud/subscription/components/SubscriptionPanel.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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/components/common/UserCredit.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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/components/common/UserCredit.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.{ts,vue} : Use vue-i18n in Composition API for string literals and place new translation entries in `src/locales/en/main.json`

Applied to files:

  • src/components/common/UserCredit.vue
  • src/components/dialog/content/TopUpCreditsDialogContent.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 vue-i18n for ALL UI strings

Applied to files:

  • src/components/common/UserCredit.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/components/common/UserCredit.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Avoid new usage of PrimeVue components

Applied to files:

  • src/components/common/UserCredit.vue
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Tests should be cross-platform compatible using `path.resolve`, `path.join`, and `path.sep` for Windows, macOS, and Linux compatibility

Applied to files:

  • tests-ui/tests/base/credits/comfyCredits.test.ts
📚 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/composables/useSubscriptionCredits.ts
📚 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/components/dialog/content/TopUpCreditsDialogContent.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Implement computed properties with `computed()` instead of using `ref` and `watch`

Applied to files:

  • src/components/dialog/content/TopUpCreditsDialogContent.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 : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/dialog/content/TopUpCreditsDialogContent.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/components/dialog/content/TopUpCreditsDialogContent.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Be judicious with addition of new refs or other state; prefer using props or composables when possible

Applied to files:

  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Use `ref` for reactive state in Vue components

Applied to files:

  • src/components/dialog/content/TopUpCreditsDialogContent.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} : Implement proper error handling

Applied to files:

  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Implement proper error handling in code

Applied to files:

  • src/components/dialog/content/TopUpCreditsDialogContent.vue
  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
📚 Learning: 2025-12-09T04:35:40.491Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:40.491Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.

Applied to files:

  • src/locales/en/main.json
📚 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/SubscriptionPanel.vue
📚 Learning: 2025-12-08T01:21:41.351Z
Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI_frontend PR: 7214
File: src/i18n.ts:97-98
Timestamp: 2025-12-08T01:21:41.351Z
Learning: In src/i18n.ts and related i18n code, use `Record<string, unknown>` for locale data structures (including custom nodes i18n data) to maintain consistency with existing patterns used in localeLoaders, nodeDefsLoaders, commandsLoaders, and settingsLoaders.

Applied to files:

  • src/base/credits/comfyCredits.ts
📚 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 : Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)

Applied to files:

  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Use Vue 3.5 TypeScript style of default prop declaration with reactive props destructuring

Applied to files:

  • src/components/dialog/content/credit/LegacyCreditTopUpOption.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/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guide

Applied to files:

  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Implement proper props and emits definitions in Vue components

Applied to files:

  • src/components/dialog/content/credit/LegacyCreditTopUpOption.vue
🧬 Code graph analysis (3)
tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)
src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)
  • useSubscriptionCredits (10-69)
tests-ui/tests/base/credits/comfyCredits.test.ts (1)
src/base/credits/comfyCredits.ts (12)
  • CREDITS_PER_USD (31-31)
  • COMFY_CREDIT_RATE_CENTS (32-32)
  • usdToCents (34-34)
  • formatUsdFromCents (123-132)
  • centsToCredits (36-37)
  • creditsToCents (39-40)
  • usdToCredits (42-43)
  • creditsToUsd (45-46)
  • formatCredits (66-71)
  • formatCreditsFromCents (73-82)
  • formatCreditsFromUsd (84-93)
  • formatUsd (112-121)
src/components/dialog/content/TopUpCreditsDialogContent.stories.ts (1)
src/components/input/SingleSelect.stories.ts (1)
  • Story (40-40)
⏰ 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: test
  • GitHub Check: setup
  • GitHub Check: lint-and-format
  • GitHub Check: collect
🔇 Additional comments (13)
tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts (1)

157-158: LGTM: Assertions align with updated mock data.

The assertions correctly verify the formatted credit values with the " Credits" suffix, consistent with the new formatting approach.

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

124-124: LGTM: Credit display now uses composable-formatted values.

The component correctly removes the dollar sign prefix and displays the formatted values from useSubscriptionCredits, which include the " Credits" suffix per the new formatting approach. This aligns with the PR's goal of standardizing credit display across the UI.

Also applies to: 137-137, 165-165

tests-ui/tests/base/credits/comfyCredits.test.ts (1)

1-46: LGTM: Comprehensive test coverage with proper locale handling.

The tests correctly use test instead of it, pass explicit locale to all formatting functions for deterministic results, and cover the full range of conversion and formatting utilities. Previous review comments have been addressed.

src/components/dialog/content/credit/CreditTopUpOption.vue (1)

1-43: LGTM: Component simplified to passive option card with proper formatting.

The component has been successfully refactored from an interactive purchase component to a passive selectable option card. Key improvements:

  • Uses shared formatCredits utility for consistent formatting
  • Locale-aware via vue-i18n
  • Clear separation of concerns (presentation only, no business logic)
  • Previous review comments regarding clamping and formatting have been addressed

Note: This is a breaking API change (props and emits changed), but tests have been updated accordingly.

tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)

8-17: LGTM: Clean mock strategy and comprehensive error handling tests.

The vue-i18n mock is well-structured and the error handling test properly uses a spy on formatCreditsFromSubscriptionMicros to verify fallback behavior. The test coverage effectively validates that the composable returns formatted strings with the expected " Credits" suffix.

Also applies to: 99-111

src/composables/useFeatureFlags.ts (1)

60-69: The feature flag default change is intentional and properly coordinated.

The subscriptionTiersEnabled default is documented in TopUpCreditsDialogContent.stories.ts as "(defaults to new design)" and is backed by complete backend support for subscription tier APIs. The feature flag can still be overridden via remote config if needed, making this a safe, controlled rollout.

src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)

14-23: LGTM on the formatBalance helper.

The inline comment clarifies the non-standard unit conversion (211 units = 1 credit), addressing the previous concern about the *_micros naming convention. The implementation correctly uses the shared formatter with locale support.

src/components/dialog/content/TopUpCreditsDialogContent.vue (2)

146-148: LGTM on reactive feature flag.

The useNewDesign is now correctly wrapped in computed(), ensuring the UI updates if the feature flag changes at runtime.


177-212: LGTM on purchase handler with comprehensive error handling.

The handleBuy function properly handles the purchase flow with:

  • Loading state management via try/finally
  • Success toast with formatted credits and amount
  • Error toast with extracted error message
  • Telemetry tracking

This addresses the previous feedback about user-facing error handling.

src/components/dialog/content/TopUpCreditsDialogContent.stories.ts (1)

1-41: LGTM on Storybook stories.

The story file follows standard Storybook conventions with appropriate coverage for the refreshDate prop variations. The documentation clearly explains the feature flag behavior.

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

1847-1861: LGTM on new locale entries.

The new credit-related locale keys follow established patterns with proper interpolation syntax for dynamic values ({count}, {credits}, {amount}, {error}, {date}).

src/base/credits/comfyCredits.ts (2)

6-29: Shared formatter helper is cohesive and defensive.

Centralizing locale-aware formatting in formatNumber with default+override merging and a min/max fraction guard keeps all public formatters consistent without mutating caller options. No changes needed here.


134-142: clampUsd behavior and JSDoc are now consistent.

Early NaN handling with return 0 plus clamping numeric inputs into [1, 1000] matches the documentation and gives a clear, safe contract for caller code.

1. Fix critical business logic inconsistency:
   - Both UserCredit.vue and useSubscriptionCredits use same backend field (amount_micros)
   - Field contains cents despite *_micros naming convention
   - Unified to use formatCreditsFromCents for consistent conversion

2. Remove duplicate try/catch blocks in computed properties:
   - formatBalance handles undefined values safely via ?? operator
   - Simplified computed properties to direct function calls
   - Updated error handling test to expect errors to propagate

3. Remove unused formatCreditsFromSubscriptionMicros function
- Remove unused context parameter
- Add required currency field to mock balance data
- Use proper typing for Firebase auth store balance object
@christian-byrne
Copy link
Contributor Author

Due to the deadline, I really need to merge this. Future PRs will be fixing the style to make it match the designs exactly. Please leave reviews still and I will implement changes tomorrow.

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

♻️ Duplicate comments (2)
tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)

2-2: Use test instead of it per project guidelines.

This was already flagged in a previous review. Replace it with test throughout the file.

src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)

14-22: API naming discrepancy persists.

The comment on line 15 documents that the backend returns cents despite the *_micros naming convention. This was flagged in a previous review regarding the mismatch between backend schema documentation (claiming "microamount 1/1,000,000") and actual values (cents 1/100).

While the comment helps, this should be tracked for resolution with the backend team to ensure the API contract is correctly documented.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3cf8c9d and 427c889.

📒 Files selected for processing (5)
  • .storybook/preview.ts (1 hunks)
  • src/base/credits/comfyCredits.ts (1 hunks)
  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1 hunks)
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts (1 hunks)
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
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/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
src/**/*.ts

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

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

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.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/useSubscriptionCredits.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

src/**/*.{ts,tsx,vue}: Write expressive and self-documenting code to reduce the need for comments; clean redundant comments as you go
Consider if there is a simpler way to introduce functionality before writing code; choose the simpler approach when possible
Use refactoring to make complex code simpler
Keep functions short and functional
Minimize nesting in code (e.g., if () { ... } or for () { ... }) to avoid arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions (especially testable ones)
Watch out for code smells and refactor to avoid them
Implement proper error handling in code
If a complex type definition is inlined in multiple related places, extract and name it for reuse

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
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/useSubscriptionCredits.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • src/base/credits/comfyCredits.ts
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/useSubscriptionCredits.ts
**/*.{js,ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript exclusively (no new JavaScript)

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts
  • src/base/credits/comfyCredits.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Do not use any type in TypeScript code
Do not use as any type assertions in TypeScript code; fix the underlying type issue
Style formatting: 2 space indent, single quotes, no trailing semicolons, 80 character width
Import statements should be sorted and grouped by plugin; run pnpm format before committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts
  • src/base/credits/comfyCredits.ts
**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use vue-i18n in Composition API for string literals and place new translation entries in src/locales/en/main.json

Files:

  • src/platform/cloud/subscription/composables/useSubscriptionCredits.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts
  • src/base/credits/comfyCredits.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.ts: Write unit and component tests in **/*.test.ts
Use Vitest with happy-dom for unit and component tests

Files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts
🧠 Learnings (18)
📚 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/composables/useSubscriptionCredits.ts
  • .storybook/preview.ts
📚 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/composables/useSubscriptionCredits.ts
📚 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/useSubscriptionCredits.ts
  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts
  • src/base/credits/comfyCredits.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.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/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.test.ts : Use Vitest with happy-dom for unit and component tests

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Follow naming conventions for browser tests

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts
  • tests-ui/tests/composables/node/useCreditsBadge.test.ts
📚 Learning: 2025-12-08T01:21:41.351Z
Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI_frontend PR: 7214
File: src/i18n.ts:97-98
Timestamp: 2025-12-08T01:21:41.351Z
Learning: In src/i18n.ts and related i18n code, use `Record<string, unknown>` for locale data structures (including custom nodes i18n data) to maintain consistency with existing patterns used in localeLoaders, nodeDefsLoaders, commandsLoaders, and settingsLoaders.

Applied to files:

  • src/base/credits/comfyCredits.ts
🧬 Code graph analysis (2)
src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)
src/base/credits/comfyCredits.ts (1)
  • formatCreditsFromCents (73-82)
tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)
src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)
  • useSubscriptionCredits (10-44)
⏰ 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: setup
  • GitHub Check: lint-and-format
  • GitHub Check: test
  • GitHub Check: collect
🔇 Additional comments (8)
tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts (1)

139-148: LGTM!

The isLoadingBalance test correctly verifies the computed property reflects the store's isFetchingBalance state reactively.

tests-ui/tests/composables/node/useCreditsBadge.test.ts (1)

20-26: LGTM!

The mock correctly isolates the legacy badge behavior by disabling subscriptionTiersEnabled. The inline comment clearly documents the test intent.

src/platform/cloud/subscription/composables/useSubscriptionCredits.ts (1)

10-43: Well-structured composable with clean formatting logic.

The formatBalance helper centralizes the formatting logic effectively. The composable correctly:

  • Uses computed() for derived state
  • Leverages i18n for user-facing strings
  • Provides a clean public API surface

The simplification of error handling (removing try/catch) aligns with the previous review feedback.

src/base/credits/comfyCredits.ts (5)

1-29: Well-implemented number formatting with defensive validation.

The formatNumber helper correctly:

  • Provides sensible defaults (2 decimal places)
  • Validates that maximumFractionDigits >= minimumFractionDigits to prevent Intl.NumberFormat errors
  • Uses proper locale-aware formatting

This is a solid foundation for the credit formatting utilities.


31-46: Conversion functions are mathematically sound.

The rounding strategies are appropriate:

  • Math.round() for integer conversions (cents, credits)
  • Two-step rounding in creditsToUsd (* 100 / 100) ensures USD precision to 2 decimal places

The functions maintain consistency across the conversion chain.


48-64: LGTM!

The exported types are clean and provide good API documentation. This addresses the prior review suggestion about extracting shared parameter types.


95-115: Note: formatUsd produces plain numbers, not currency-formatted strings.

formatUsd formats the numeric value without a currency symbol (e.g., "10.00" not "$10.00"). This appears intentional for flexibility, but verify this matches the expected usage in UI components that consume this function.

If currency symbols are needed in some contexts, consider either:

  • Adding a separate formatUsdCurrency variant using style: 'currency'
  • Documenting this behavior in a JSDoc comment

117-125: LGTM!

The clampUsd implementation correctly handles:

  • NaN input → returns 0 (early exit)
  • Valid numbers → clamped to [1, 1000]

The JSDoc accurately describes this behavior. This addresses the prior review concern about documentation mismatch.

- Remove unused __STORYBOOK__ global declaration and assignment
- Fix vi.mock importOriginal parameter typing to use proper module type
- Replace 'as any' type assertions with proper GetCustomerBalanceResponse type
- Import and use typed GetCustomerBalanceResponse from comfyRegistryTypes

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

Co-Authored-By: Claude <[email protected]>
@christian-byrne christian-byrne added cloud/1.34 Backport PRs for cloud 1.34 and removed core/1.33 Backport PRs for core 1.33 cloud/1.33 Backport PRs for cloud 1.33 labels Dec 9, 2025
@christian-byrne
Copy link
Contributor Author

Will implement designs properly in followup PR.

@christian-byrne christian-byrne merged commit aef4083 into main Dec 9, 2025
33 checks passed
@christian-byrne christian-byrne deleted the comfy-credits-domain branch December 9, 2025 12:11
github-actions bot pushed a commit that referenced this pull request Dec 9, 2025
Introduces cents<->usd<->credit converters plus basic formatters and
adds test. Lays groundwork to start converting UI components into
displaying comfy credits.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7061-add-shared-comfy-credit-conversion-helpers-2bb6d73d3650810bb34fdf9bb3fc115b)
by [Unito](https://www.unito.io)

---------

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

@christian-byrne Successfully backported to #7293

@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 9, 2025
christian-byrne added a commit that referenced this pull request Dec 9, 2025
Backport of #7061 to `cloud/1.34`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7293-backport-cloud-1-34-add-shared-comfy-credit-conversion-helpers-2c46d73d365081a9b1bcfb82462c3d7f)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <[email protected]>
Co-authored-by: Claude <[email protected]>
Enferlain pushed a commit to Enferlain/ComfyUI_frontend that referenced this pull request Dec 9, 2025
Introduces cents<->usd<->credit converters plus basic formatters and
adds test. Lays groundwork to start converting UI components into
displaying comfy credits.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7061-add-shared-comfy-credit-conversion-helpers-2bb6d73d3650810bb34fdf9bb3fc115b)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude <[email protected]>
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 size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants