-
Notifications
You must be signed in to change notification settings - Fork 440
feat: add Stripe pricing table integration for subscription dialog (conditional on feature flag) #7288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Important Review skippedAuto reviews are limited based on label configuration. 🚫 Review skipped — only excluded labels are configured. (1)
Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the 📝 WalkthroughWalkthroughThis change introduces Stripe pricing table integration to the subscription system. It adds configuration utilities, environment variables, TypeScript types, a new Vue component for rendering the pricing table, and updates subscription-related components to conditionally display Stripe pricing based on a feature flag. Changes
✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (15)
.env_example(1 hunks)global.d.ts(1 hunks)src/composables/useFeatureFlags.ts(2 hunks)src/config/stripePricingTableConfig.ts(1 hunks)src/locales/en/main.json(3 hunks)src/platform/cloud/subscription/components/StripePricingTable.vue(1 hunks)src/platform/cloud/subscription/components/SubscribeButton.vue(4 hunks)src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue(2 hunks)src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts(1 hunks)src/platform/cloud/subscription/composables/useSubscription.ts(3 hunks)src/platform/cloud/subscription/composables/useSubscriptionDialog.ts(3 hunks)src/platform/remoteConfig/types.ts(1 hunks)src/platform/settings/composables/useSettingUI.ts(6 hunks)src/vite-env.d.ts(1 hunks)tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (15)
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/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/vite-env.d.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscription.tssrc/platform/cloud/subscription/components/SubscribeButton.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/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/vite-env.d.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/composables/useSubscription.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 () { ... }orfor () { ... }) 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/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/vite-env.d.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscription.tssrc/platform/cloud/subscription/components/SubscribeButton.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/vite-env.d.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscription.tssrc/platform/cloud/subscription/components/SubscribeButton.vue
**/*.{js,ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively (no new JavaScript)
Files:
src/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tsglobal.d.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/vite-env.d.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tstests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscription.tssrc/platform/cloud/subscription/components/SubscribeButton.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Do not useanytype in TypeScript code
Do not useas anytype 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; runpnpm formatbefore committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates
Files:
src/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tsglobal.d.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/vite-env.d.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tstests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscription.tssrc/platform/cloud/subscription/components/SubscribeButton.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/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tsglobal.d.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/vite-env.d.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tstests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscription.tssrc/platform/cloud/subscription/components/SubscribeButton.vue
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/composables/useFeatureFlags.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/composables/useSubscription.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/composables/useFeatureFlags.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscription.tssrc/platform/cloud/subscription/components/SubscribeButton.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/composables/useFeatureFlags.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscription.tssrc/platform/cloud/subscription/components/SubscribeButton.vue
src/composables/use*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables as
useXyz.ts
Files:
src/composables/useFeatureFlags.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/StripePricingTable.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/components/StripePricingTable.test.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/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/components/SubscribeButton.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3 SFCs with Composition API only (.vuefiles)
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 usewithDefaultsor runtime props declaration in Vue components
PreferuseModelto separately defining a prop and emit in Vue components
Usereffor reactive state in Vue components
Implement computed properties withcomputed()instead of usingrefandwatch
UsewatchandwatchEffectfor side effects in Vue components
Useprovide/injectfor dependency injection only when simpler alternatives (Store or composable) are not suitable
Do not use thedark:Tailwind variant; use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Useimport { 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 acomputedif it's possible to use arefor prop directly
Do not use awatchif acomputedwould 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/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/components/SubscribeButton.vue
🧠 Learnings (39)
📚 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/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tsglobal.d.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/vite-env.d.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tstests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/composables/useSubscription.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 Suspense for async components
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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 **/*.vue : Use Suspense for async components
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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 : Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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/useSubscriptionDialog.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 cleanup for async operations in Vue components
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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 : Extract complex conditionals to computed properties
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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 **/*.vue : Utilize Vue 3's Teleport component when needed
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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 : Utilize Vue 3's Teleport component when needed
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/settings/composables/useSettingUI.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 : Use setup() function in Vue 3 Composition API
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/SubscribeButton.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 Teleport/Suspense when needed for component rendering
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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/composables/use*.ts : Name composables as `useXyz.ts`
Applied to files:
src/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/cloud/subscription/composables/useSubscription.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} : Leverage VueUse functions for performance-enhancing styles
Applied to files:
src/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/settings/composables/useSettingUI.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/StripePricingTable.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/components/StripePricingTable.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/components/StripePricingTable.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/platform/cloud/subscription/components/StripePricingTable.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/StripePricingTable.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/components/StripePricingTable.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/components/StripePricingTable.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/components/StripePricingTable.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/components/StripePricingTable.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/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/StripePricingTable.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/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/StripePricingTable.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/platform/settings/composables/useSettingUI.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,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/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/StripePricingTable.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 existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Applied to files:
src/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/SubscribeButton.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/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/SubscribeButton.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,tsx,vue} : ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates
Applied to files:
src/platform/settings/composables/useSettingUI.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:
src/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscription.tssrc/platform/cloud/subscription/components/SubscribeButton.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/platform/cloud/subscription/components/StripePricingTable.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/platform/cloud/subscription/components/StripePricingTable.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/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/components/SubscribeButton.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-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 `<script setup lang="ts">` for component logic in Vue components
Applied to files:
src/platform/cloud/subscription/components/SubscribeButton.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/platform/cloud/subscription/components/SubscribeButton.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/platform/cloud/subscription/components/SubscribeButton.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/platform/cloud/subscription/components/SubscribeButton.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 lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Applied to files:
src/platform/cloud/subscription/components/SubscribeButton.vue
🧬 Code graph analysis (5)
src/config/stripePricingTableConfig.ts (1)
src/platform/remoteConfig/remoteConfig.ts (1)
remoteConfig(22-22)
src/composables/useFeatureFlags.ts (1)
src/scripts/api.ts (1)
api(1289-1289)
src/platform/cloud/subscription/composables/useSubscriptionDialog.ts (1)
src/composables/useFeatureFlags.ts (2)
useFeatureFlags(20-58)subscriptionTiersEnabled(43-48)
src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts (1)
src/config/stripePricingTableConfig.ts (1)
STRIPE_PRICING_TABLE_SCRIPT_SRC(3-4)
src/platform/settings/composables/useSettingUI.ts (2)
src/platform/cloud/subscription/composables/useSubscription.ts (1)
useSubscription(244-244)src/composables/useFeatureFlags.ts (2)
useFeatureFlags(20-58)subscriptionTiersEnabled(43-48)
🔇 Additional comments (15)
.env_example (1)
45-48: LGTM!The Stripe configuration examples follow the existing file patterns and use the correct
VITE_prefix for client-side environment variables.src/platform/cloud/subscription/composables/useSubscription.ts (1)
16-16: LGTM!The refactor from a direct service instance to the
useDialogServicecomposable is cleaner and aligns with the Vue 3 composition API patterns used throughout the codebase.Also applies to: 40-40, 100-106
src/composables/useFeatureFlags.ts (1)
13-14: LGTM!The new
SUBSCRIPTION_TIERS_ENABLEDfeature flag follows the established patterns in this file, with a safe default offalseand consistent naming conventions.Also applies to: 42-48
global.d.ts (1)
16-17: LGTM!The new optional Stripe configuration properties follow the existing naming convention and are correctly typed as optional strings, consistent with the layered configuration resolution approach (remoteConfig → window.CONFIG → env vars).
src/platform/remoteConfig/types.ts (1)
37-38: LGTM!The Stripe configuration properties are correctly added to the
RemoteConfigtype, maintaining consistency with theWindow.__CONFIG__interface and following the established naming convention.src/locales/en/main.json (1)
1884-1897: LGTM!The localization entries are well-written and cover all necessary UI states: loading, error, and missing configuration. The
missingConfigmessage provides helpful guidance for configuration debugging.src/platform/cloud/subscription/composables/useSubscriptionDialog.ts (1)
43-55: LGTM - dialog customization for Stripe pricing table.The conditional styling appropriately handles the wider modal needed for the multi-column Stripe pricing table layout while maintaining the existing narrower dialog for the default path.
src/config/stripePricingTableConfig.ts (1)
1-34: LGTM!The configuration resolution follows a sensible priority order (remoteConfig → window.CONFIG → env vars). The
||chaining correctly treats empty strings as falsy, and thehasStripePricingTableConfighelper provides a clean API for consumers to check config availability.src/platform/cloud/subscription/components/SubscribeButton.vue (1)
129-149: LGTM - Stripe pricing flow integration.The conditional branching for Stripe pricing is clear: when enabled, it shows the subscription dialog and awaits subscription activation via the watch, otherwise falls back to the existing subscription flow with polling.
src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts (1)
100-102: LGTM!Good use of
createSharedComposableto ensure singleton state across all consumers, preventing duplicate script loads.src/platform/cloud/subscription/components/StripePricingTable.vue (2)
106-114: Consider usingwatchEffectfor cleaner reactive dependency tracking.The current watch with an array of dependencies and manual guards inside the callback could be simplified. However, the existing implementation is functionally correct.
116-119: LGTM!Proper cleanup of the dynamically created Stripe element on component unmount to prevent memory leaks.
src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue (3)
175-210: Polling implementation looks correct with proper cleanup.The polling mechanism correctly:
- Uses
window.setIntervalfor proper typing- Implements max duration timeout to prevent indefinite polling
- Calls
stopPolling()before starting to prevent duplicate intervals- Handles errors gracefully without crashing
One minor suggestion: consider using exponential backoff if the server is under load, though the fixed 3-second interval is reasonable for this use case.
261-263: LGTM!Proper cleanup on unmount ensures no lingering intervals. Combined with the watcher cleanup and
handleClose, this provides comprehensive protection against memory leaks.
266-273: Scoped styles for PrimeVue component overrides are acceptable.While the coding guidelines prefer Tailwind over
<style>blocks, these:deep()selectors are necessary for styling PrimeVue components in the legacy dialog path and are appropriately scoped.
src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
Show resolved
Hide resolved
src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
Show resolved
Hide resolved
src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
Outdated
Show resolved
Hide resolved
tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
Show resolved
Hide resolved
6241fd7 to
66f805b
Compare
There was a problem hiding this 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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
.env_example(1 hunks)global.d.ts(1 hunks)src/composables/useFeatureFlags.ts(2 hunks)src/config/stripePricingTableConfig.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
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/config/stripePricingTableConfig.tssrc/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/config/stripePricingTableConfig.tssrc/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 () { ... }orfor () { ... }) 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/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.ts
**/*.{js,ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively (no new JavaScript)
Files:
src/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tsglobal.d.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Do not useanytype in TypeScript code
Do not useas anytype 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; runpnpm formatbefore committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates
Files:
src/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tsglobal.d.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/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tsglobal.d.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
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/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/composables/useFeatureFlags.ts
src/composables/use*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables as
useXyz.ts
Files:
src/composables/useFeatureFlags.ts
🧠 Learnings (1)
📚 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/config/stripePricingTableConfig.tssrc/composables/useFeatureFlags.tsglobal.d.ts
🧬 Code graph analysis (2)
src/config/stripePricingTableConfig.ts (1)
src/platform/remoteConfig/remoteConfig.ts (1)
remoteConfig(22-22)
src/composables/useFeatureFlags.ts (1)
src/scripts/api.ts (1)
api(1289-1289)
🔇 Additional comments (3)
src/composables/useFeatureFlags.ts (1)
15-16: Enum extension is consistent and type‑safeAdding
SUBSCRIPTION_TIERS_ENABLED = 'subscription_tiers_enabled'follows the existing pattern and keeps feature access strongly typed. No issues here.src/config/stripePricingTableConfig.ts (2)
31-34: LGTM!The logic correctly validates that both configuration values are present and truthy. The implementation is clear and concise.
3-4: No action needed. The script URL correctly uses Stripe's/v3/evergreen endpoint, which receives continuous updates under Stripe's documented versioning model that limits breaking changes to biannual major releases. This is the recommended approach per Stripe's official pricing table documentation.
- Add StripePricingTable component with Stripe web component integration - Update subscription dialog to show Stripe pricing table when feature flag enabled - Add stripePricingTableConfig for environment-based configuration - Add useStripePricingTableLoader composable for script loading - Update dialog styling with proper width (1100px) and rounded corners - Add contact us and enterprise links to subscription dialog - Include comprehensive test coverage for new components
66f805b to
19a3a9f
Compare
🎭 Playwright Test Results❌ Some tests failed ⏰ Completed at: 12/09/2025, 11:14:28 AM UTC 📈 Summary
📊 Test Reports by Browser
🎉 Click on the links above to view detailed test results for each browser configuration. |
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 12/09/2025, 11:06:02 AM UTC 🔗 Links🎉 Your Storybook is ready for review! |
Bundle Size ReportSummary
Category Glance Per-category breakdownApp Entry Points — 3.21 MB (baseline 3.21 MB) • 🔴 +768 BMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 986 kB (baseline 985 kB) • 🔴 +682 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 1 added / 1 removed Panels & Settings — 298 kB (baseline 298 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 6 added / 6 removed UI Components — 176 kB (baseline 176 kB) • ⚪ 0 BReusable component library chunks
Status: 6 added / 6 removed Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 2 added / 2 removed Utilities & Hooks — 3.18 kB (baseline 3.18 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 3.81 MB (baseline 3.81 MB) • ⚪ 0 BBundles that do not match a named category
Status: 17 added / 17 removed |
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/platform/cloud/subscription/composables/useSubscription.ts (1)
100-106: Fix floating promise to resolve pipeline failure.The
showSubscriptionRequiredDialog()call returns a Promise that is not awaited, causing the ESLintno-floating-promiseserror. SinceshowSubscriptionDialogis synchronous (returns void), you need to explicitly handle the promise.const showSubscriptionDialog = () => { if (isCloud) { useTelemetry()?.trackSubscription('modal_opened') } - showSubscriptionRequiredDialog() + void showSubscriptionRequiredDialog() }Alternatively, if the dialog result matters, make the function async and await:
- const showSubscriptionDialog = () => { + const showSubscriptionDialog = async () => { if (isCloud) { useTelemetry()?.trackSubscription('modal_opened') } - showSubscriptionRequiredDialog() + await showSubscriptionRequiredDialog() }
♻️ Duplicate comments (12)
src/vite-env.d.ts (1)
19-27: Extend Vite's built-inImportMetaEnvinstead of redefining it.The interfaces inside
declare globaloverride rather than augment Vite's built-in types fromvite/client. MoveImportMetaEnvoutside thedeclare globalblock to leverage TypeScript's declaration merging:declare global { interface Window { __COMFYUI_FRONTEND_VERSION__: string } - - interface ImportMetaEnv { - readonly VITE_STRIPE_PUBLISHABLE_KEY?: string - readonly VITE_STRIPE_PRICING_TABLE_ID?: string - } - - interface ImportMeta { - readonly env: ImportMetaEnv - } } + +interface ImportMetaEnv { + readonly VITE_STRIPE_PUBLISHABLE_KEY?: string + readonly VITE_STRIPE_PRICING_TABLE_ID?: string +}src/platform/settings/composables/useSettingUI.ts (2)
38-43: Useflags.subscriptionTiersEnabledto include remote config resolution.The
featureFlag()function only callsapi.getServerFeature(), butflags.subscriptionTiersEnabledalso checksremoteConfig.value.subscription_tiers_enabledfirst. This inconsistency could cause the feature flag to behave differently here than in other parts of the application.- const { isActiveSubscription } = useSubscription() - const { featureFlag } = useFeatureFlags() - const subscriptionTiersEnabled = featureFlag( - 'subscription_tiers_enabled', - false - ) + const { isActiveSubscription } = useSubscription() + const { flags } = useFeatureFlags()Then update the usage on line 116:
- if (!subscriptionTiersEnabled.value) return true + if (!flags.subscriptionTiersEnabled) return true
113-118: Redundant condition check.Since
subscriptionPanelis alreadynullwhen!isCloud || !window.__CONFIG__?.subscription_required(lines 96-98), the check on line 115 is redundant—if that condition were true, line 114 would already returnfalse.const shouldShowPlanCreditsPanel = computed(() => { if (!subscriptionPanel) return false - if (!isCloud || !window.__CONFIG__?.subscription_required) return false - if (!subscriptionTiersEnabled.value) return true + if (!flags.subscriptionTiersEnabled) return true return isActiveSubscription.value })src/platform/cloud/subscription/composables/useSubscriptionDialog.ts (1)
13-24: Consider usingflags.subscriptionTiersEnableddirectly.The
useFeatureFlagscomposable already exposes asubscriptionTiersEnabledgetter onflags, as shown in the relevant code snippets. Using it directly would be more concise and consistent:- const { featureFlag } = useFeatureFlags() - const subscriptionTiersEnabled = featureFlag( - 'subscription_tiers_enabled', - false - ) + const { flags } = useFeatureFlags() const showStripeDialog = computed( () => - subscriptionTiersEnabled.value && + flags.subscriptionTiersEnabled && isCloud && window.__CONFIG__?.subscription_required )This avoids creating a redundant computed ref for the same feature flag.
src/config/stripePricingTableConfig.ts (2)
6-10: Consider removing optional chaining if types are correct.The optional chaining on
import.meta.env?.[key]may be unnecessary if the Vite environment types are properly configured. In a standard Vite context,import.meta.envis always defined. If this is defensive programming for edge cases, consider adding a comment explaining whenimport.meta.envmight be undefined.
12-29: Add explicit return type for better API clarity.As a public API function,
getStripePricingTableConfigshould declare an explicit return type. This improves IDE support, documents the API contract, and prevents accidental breaking changes. As per coding guidelines, proper TypeScript types should be used throughout the codebase.+interface StripePricingTableConfig { + publishableKey: string + pricingTableId: string +} + -export function getStripePricingTableConfig() { +export function getStripePricingTableConfig(): StripePricingTableConfig {src/platform/cloud/subscription/components/SubscribeButton.vue (2)
57-64: Same refactor opportunity asuseSubscriptionDialog.ts.Consider using
flags.subscriptionTiersEnableddirectly instead offeatureFlag()for consistency:-const { featureFlag } = useFeatureFlags() -const subscriptionTiersEnabled = featureFlag( - 'subscription_tiers_enabled', - false -) +const { flags } = useFeatureFlags() const shouldUseStripePricing = computed( - () => isCloud && subscriptionTiersEnabled.value + () => isCloud && flags.subscriptionTiersEnabled )
116-127: Watch creates a new object on every evaluation.The current watch creates a new object literal on each evaluation, which could cause unnecessary re-evaluations. Consider using a getter array or watching the refs directly:
watch( - () => ({ - awaiting: isAwaitingStripeSubscription.value, - isActive: isActiveSubscription.value - }), - ({ awaiting, isActive }) => { - if (shouldUseStripePricing.value && awaiting && isActive) { + [isAwaitingStripeSubscription, isActiveSubscription], + ([awaiting, isActive]) => { + if (shouldUseStripePricing.value && awaiting && isActive) { emit('subscribed') isAwaitingStripeSubscription.value = false } } )This avoids object allocation overhead and makes the watch dependencies explicit.
src/platform/cloud/subscription/components/StripePricingTable.vue (1)
59-62: Inconsistent validation logic betweenhasValidConfigandresolvedConfig.
hasValidConfigreturnstrueif bothprops.publishableKeyandprops.pricingTableIdare provided, butresolvedConfigallows partial prop overrides (e.g., onlypublishableKeyfrom props withpricingTableIdfrom fallback). This creates an inconsistency where a partial prop configuration may render correctly but show "missing config" state.Consider aligning the validation:
const hasValidConfig = computed(() => { - if (props.publishableKey && props.pricingTableId) return true - return hasStripePricingTableConfig() + const { publishableKey, pricingTableId } = resolvedConfig.value + return Boolean(publishableKey && pricingTableId) })src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts (1)
37-65: Race condition and missingisLoadingstate when attaching listeners to existing script.This issue was previously flagged. When an existing script is found but hasn't finished loading, there's a race where the script could complete between
querySelectorandaddEventListener, leaving the promise unresolved. Additionally,isLoading.valueis not set totruefor this code path.Apply this diff to address both issues:
if (existingScript) { if (existingScript.dataset.loaded === 'true') { resolveLoaded() return Promise.resolve() } + isLoading.value = true pendingPromise = new Promise<void>((resolve, reject) => { + const handleLoad = () => { + existingScript.dataset.loaded = 'true' + resolveLoaded() + resolve() + } + existingScript.addEventListener( 'load', - () => { - existingScript.dataset.loaded = 'true' - resolveLoaded() - resolve() - }, + handleLoad, { once: true } ) existingScript.addEventListener( 'error', () => { const err = new Error('Stripe pricing table script failed to load') resolveError(err) reject(err) }, { once: true } ) + + // Handle race: script may have loaded between querySelector and addEventListener + if (existingScript.dataset.loaded === 'true') { + handleLoad() + } }) return pendingPromise }src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue (2)
224-232: Potential double invocation of close logic.This issue was previously flagged. When
isActiveSubscriptionbecomestrue, this watcher calls bothemit('close', true)andhandleClose(). If the parent listens to both thecloseevent and provides anonCloseprop that performs similar actions, this could lead to duplicate side effects.Consider consolidating to a single close mechanism:
watch( () => isActiveSubscription.value, (isActive) => { if (isActive && showStripePricingTable.value) { - emit('close', true) handleClose() + emit('close', true) } } )Or remove one of the close invocations if they serve the same purpose.
243-250: Async handler called without await may result in unhandled promise rejection.This issue was previously flagged.
handleContactUsis an async function, but when called from the@clickhandler on line 50, the returned promise isn't handled. IfcommandStore.executethrows, the error won't be caught.Add error handling:
const handleContactUs = async () => { telemetry?.trackHelpResourceClicked({ resource_type: 'help_feedback', is_external: true, source: 'subscription' }) - await commandStore.execute('Comfy.ContactSupport') + try { + await commandStore.execute('Comfy.ContactSupport') + } catch (error) { + console.error('[SubscriptionDialog] Failed to open contact support', error) + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (14)
.env_example(1 hunks)global.d.ts(1 hunks)src/config/stripePricingTableConfig.ts(1 hunks)src/locales/en/main.json(2 hunks)src/platform/cloud/subscription/components/StripePricingTable.vue(1 hunks)src/platform/cloud/subscription/components/SubscribeButton.vue(4 hunks)src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue(2 hunks)src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts(1 hunks)src/platform/cloud/subscription/composables/useSubscription.ts(3 hunks)src/platform/cloud/subscription/composables/useSubscriptionDialog.ts(3 hunks)src/platform/remoteConfig/types.ts(1 hunks)src/platform/settings/composables/useSettingUI.ts(6 hunks)src/vite-env.d.ts(1 hunks)tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
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/settings/composables/useSettingUI.tssrc/vite-env.d.tssrc/config/stripePricingTableConfig.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.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/settings/composables/useSettingUI.tssrc/vite-env.d.tssrc/config/stripePricingTableConfig.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.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 () { ... }orfor () { ... }) 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/settings/composables/useSettingUI.tssrc/vite-env.d.tssrc/config/stripePricingTableConfig.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.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/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/platform/settings/composables/useSettingUI.tssrc/vite-env.d.tssrc/config/stripePricingTableConfig.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/remoteConfig/types.tssrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.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/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.ts
**/*.{js,ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively (no new JavaScript)
Files:
src/platform/settings/composables/useSettingUI.tssrc/vite-env.d.tssrc/config/stripePricingTableConfig.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/remoteConfig/types.tstests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.tssrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vueglobal.d.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Do not useanytype in TypeScript code
Do not useas anytype 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; runpnpm formatbefore committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates
Files:
src/platform/settings/composables/useSettingUI.tssrc/vite-env.d.tssrc/config/stripePricingTableConfig.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/remoteConfig/types.tstests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.tssrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vueglobal.d.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.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/settings/composables/useSettingUI.tssrc/vite-env.d.tssrc/config/stripePricingTableConfig.tssrc/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/remoteConfig/types.tstests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.tssrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vueglobal.d.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.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/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3 SFCs with Composition API only (.vuefiles)
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 usewithDefaultsor runtime props declaration in Vue components
PreferuseModelto separately defining a prop and emit in Vue components
Usereffor reactive state in Vue components
Implement computed properties withcomputed()instead of usingrefandwatch
UsewatchandwatchEffectfor side effects in Vue components
Useprovide/injectfor dependency injection only when simpler alternatives (Store or composable) are not suitable
Do not use thedark:Tailwind variant; use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Useimport { 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 acomputedif it's possible to use arefor prop directly
Do not use awatchif acomputedwould 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/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
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/StripePricingTable.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/components/StripePricingTable.test.ts
🧠 Learnings (57)
📚 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/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/StripePricingTable.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/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/StripePricingTable.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/platform/settings/composables/useSettingUI.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,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/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/StripePricingTable.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/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.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 : Use setup() function in Vue 3 Composition API
Applied to files:
src/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/composables/useSubscriptionDialog.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 existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Applied to files:
src/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/SubscribeButton.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 Vue 3's Teleport component when needed
Applied to files:
src/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.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:
src/platform/settings/composables/useSettingUI.tssrc/config/stripePricingTableConfig.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 **/*.vue : Use VueUse functions for performance-enhancing styles in Vue components
Applied to files:
src/platform/settings/composables/useSettingUI.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:
src/platform/settings/composables/useSettingUI.tssrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vuesrc/platform/cloud/subscription/composables/useSubscription.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/settings/composables/useSettingUI.tssrc/vite-env.d.tssrc/config/stripePricingTableConfig.tssrc/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/remoteConfig/types.tstests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.tsglobal.d.tssrc/platform/cloud/subscription/composables/useSubscriptionDialog.tssrc/platform/cloud/subscription/composables/useSubscription.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:
src/vite-env.d.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} : If a complex type definition is inlined in multiple related places, extract and name it for reuse
Applied to files:
src/vite-env.d.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} : Consider if there is a simpler way to introduce functionality before writing code; choose the simpler approach when possible
Applied to files:
src/vite-env.d.tssrc/config/stripePricingTableConfig.ts
📚 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: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/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/config/stripePricingTableConfig.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} : Write expressive and self-documenting code to reduce the need for comments; clean redundant comments as you go
Applied to files:
src/config/stripePricingTableConfig.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/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guide
Applied to files:
src/platform/cloud/subscription/components/StripePricingTable.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/platform/cloud/subscription/components/StripePricingTable.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/platform/cloud/subscription/components/StripePricingTable.vuesrc/platform/cloud/subscription/components/SubscribeButton.vuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.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/composables/use*.ts : Name composables as `useXyz.ts`
Applied to files:
src/platform/cloud/subscription/composables/useStripePricingTableLoader.tssrc/platform/cloud/subscription/composables/useSubscription.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/StripePricingTable.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/components/StripePricingTable.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/components/StripePricingTable.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/platform/cloud/subscription/components/StripePricingTable.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/components/StripePricingTable.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/components/StripePricingTable.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/StripePricingTable.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/StripePricingTable.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} : Test user workflows in browser tests
Applied to files:
tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.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} : Prefer specific selectors in browser tests
Applied to files:
tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.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} : Use Playwright fixtures for browser tests
Applied to files:
tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.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/components/StripePricingTable.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/components/StripePricingTable.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/components/StripePricingTable.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 **/*.vue : Do not use a `watch` if a `computed` would work instead
Applied to files:
src/platform/cloud/subscription/components/SubscribeButton.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 `watch` and `watchEffect` for side effects in Vue components
Applied to files:
src/platform/cloud/subscription/components/SubscribeButton.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 watch and watchEffect for side effects
Applied to files:
src/platform/cloud/subscription/components/SubscribeButton.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/platform/cloud/subscription/components/SubscribeButton.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} : Watch out for code smells and refactor to avoid them
Applied to files:
src/platform/cloud/subscription/components/SubscribeButton.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/platform/cloud/subscription/components/SubscribeButton.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 : Do not add a `computed` if it's possible to use a `ref` or prop directly
Applied to files:
src/platform/cloud/subscription/components/SubscribeButton.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/platform/cloud/subscription/components/SubscribeButton.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/platform/cloud/subscription/components/SubscribeButton.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 `<script setup lang="ts">` for component logic in Vue components
Applied to files:
src/platform/cloud/subscription/components/SubscribeButton.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/platform/cloud/subscription/components/SubscribeButton.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/platform/cloud/subscription/components/SubscribeButton.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 lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Applied to files:
src/platform/cloud/subscription/components/SubscribeButton.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 Suspense for async components
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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 **/*.vue : Use Suspense for async components
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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/useSubscriptionDialog.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 : Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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 cleanup for async operations in Vue components
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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 : Extract complex conditionals to computed properties
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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 **/*.vue : Utilize Vue 3's Teleport component when needed
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.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 : Use Teleport/Suspense when needed for component rendering
Applied to files:
src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
🧬 Code graph analysis (4)
src/platform/settings/composables/useSettingUI.ts (2)
src/platform/cloud/subscription/composables/useSubscription.ts (1)
useSubscription(244-244)src/composables/useFeatureFlags.ts (2)
useFeatureFlags(22-79)subscriptionTiersEnabled(60-69)
src/config/stripePricingTableConfig.ts (1)
src/platform/remoteConfig/remoteConfig.ts (1)
remoteConfig(22-22)
src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts (1)
src/config/stripePricingTableConfig.ts (1)
STRIPE_PRICING_TABLE_SCRIPT_SRC(3-4)
src/platform/cloud/subscription/composables/useSubscriptionDialog.ts (1)
src/composables/useFeatureFlags.ts (2)
useFeatureFlags(22-79)subscriptionTiersEnabled(60-69)
🪛 GitHub Actions: CI: Lint Format
src/platform/cloud/subscription/composables/useSubscription.ts
[error] 105-105: typescript-eslint(no-floating-promises): Promises must be awaited.
⏰ 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). (3)
- GitHub Check: collect
- GitHub Check: setup
- GitHub Check: test
🔇 Additional comments (11)
global.d.ts (1)
16-17: LGTM!The new optional Stripe configuration properties follow the existing naming convention (snake_case) and are correctly typed as optional strings, consistent with the rest of
Window.__CONFIG__..env_example (1)
45-48: LGTM!The documented environment variables follow the existing
.env_examplepattern with appropriateVITE_prefixes and placeholder values. The descriptive comment clarifies the feature-flag context.src/platform/cloud/subscription/composables/useSubscription.ts (1)
16-16: LGTM on import organization.The
useDialogServiceimport is appropriately grouped with other service/store imports.src/platform/settings/composables/useSettingUI.ts (2)
172-174: LGTM on conditional panel inclusion.The spread pattern correctly guards both the computed flag and the nullable
subscriptionPanel.
206-210: LGTM on menu tree integration.The conditional inclusion in
groupedMenuTreeNodescorrectly combines login state, computed visibility flag, and null check.src/platform/remoteConfig/types.ts (1)
41-42: LGTM!The new optional Stripe configuration fields follow the existing naming convention (snake_case) and are appropriately typed as optional strings, consistent with other config fields in
RemoteConfig.src/locales/en/main.json (1)
1898-1911: LGTM!The new i18n entries for the pricing table and subscription dialog are well-structured and follow existing conventions. The keys are descriptive and the messages are user-friendly.
src/platform/cloud/subscription/components/StripePricingTable.vue (2)
106-114: LGTM - Watch pattern is appropriate.The watch correctly observes both
resolvedConfigandtableContainerref, triggers on changes, and includes proper guards before rendering. Theimmediate: trueoption ensures initial render on mount.
89-95: Consider using type assertion for custom element.The
stripe-pricing-tableis a custom web component. While the current implementation works, using a more explicit type or adding a brief comment would improve clarity:- const stripeTable = document.createElement('stripe-pricing-table') + // Stripe pricing table web component (https://stripe.com/docs/payments/checkout/pricing-table) + const stripeTable = document.createElement('stripe-pricing-table') as HTMLElementThis is a minor improvement for documentation purposes.
⛔ Skipped due to learnings
Learnt from: DrJKL Repo: Comfy-Org/ComfyUI_frontend PR: 7137 File: src/components/rightSidePanel/RightSidePanel.vue:174-180 Timestamp: 2025-12-06T02:11:00.366Z Learning: PrimeVue components have poor TypeScript typing, so type assertions (like `as RightSidePanelTab`) may be necessary when handling emitted events or prop values from PrimeVue components like TabList.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 issuesrc/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue (2)
175-210: Polling implementation looks solid with proper cleanup.The polling logic correctly:
- Uses
stopPolling()before starting to prevent duplicate intervals- Implements a maximum duration safeguard (5 minutes)
- Handles errors gracefully without crashing
- Cleans up in
onBeforeUnmount
212-222: Good reactive orchestration for polling lifecycle.The watcher correctly starts polling when the Stripe pricing table is shown and stops it otherwise, with
{ immediate: true }ensuring proper initialization.
src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
Show resolved
Hide resolved
src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
Show resolved
Hide resolved
src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
Outdated
Show resolved
Hide resolved
tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
Show resolved
Hide resolved
tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
Show resolved
Hide resolved
…leaks
- Add attribute assertions for publishable-key and pricing-table-id
- Replace static mock values with mutable Vue refs for better test control
- Add { once: true } option to event listeners to prevent memory leaks
- Rename mockLoadScript to mockLoadStripeScript for clarity
- Add explicit StripePricingTableConfig interface and return type annotation - Remove unnecessary optional chaining on import.meta.env - Fix hasValidConfig to use resolved config values consistently - Replace featureFlag calls with unified flags object from useFeatureFlags - Optimize watch in SubscribeButton to avoid object allocation on each run - Remove duplicate close mechanism in SubscriptionRequiredDialogContent - Remove unused import in StripePricingTable component
- Fix race condition in useStripePricingTableLoader by setting isLoading=true immediately when finding existing script and checking script state after attaching listeners - Replace duplicate featureFlag computed in useSubscriptionDialog with existing flags.subscriptionTiersEnabled for consistency - Add proper check for already-loaded scripts to handle synchronous resolution cases
- Remove unused hasStripePricingTableConfig function - Change StripePricingTableConfig from exported to internal interface - No breaking changes since these exports weren't being used
| const startPolling = () => { | ||
| stopPolling() | ||
| pollStartTime = Date.now() | ||
| const poll = async () => { | ||
| try { | ||
| await fetchStatus() | ||
| } catch (error) { | ||
| console.error( | ||
| '[SubscriptionDialog] Failed to poll subscription status', | ||
| error | ||
| ) | ||
| } | ||
| } | ||
| void poll() | ||
| pollInterval = window.setInterval(() => { | ||
| if (Date.now() - pollStartTime > MAX_POLL_DURATION_MS) { | ||
| stopPolling() | ||
| return | ||
| } | ||
| void poll() | ||
| }, POLL_INTERVAL_MS) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 MEDIUM - Duplicated polling logic
Category: quality
Description:
Similar polling implementation exists in SubscribeButton.vue (lines 75-105) with nearly identical structure
Suggestion:
Extract the common polling logic into a shared composable like useSubscriptionPolling() to avoid duplication
Confidence: 90%
Rule: ts_extract_duplicated_logic_into_functions
| pendingPromise = null | ||
| } | ||
|
|
||
| const loadScript = (): Promise<void> => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔵 LOW - Missing explicit return type
Category: quality
Description:
Function loadScript doesn't specify return type explicitly
Suggestion:
Add explicit return type: const loadScript = (): Promise =>
Confidence: 65%
Rule: ts_missing_return_type
| interface StripePricingTableConfig { | ||
| publishableKey: string | ||
| pricingTableId: string | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔵 LOW - Missing explicit return type
Category: quality
Description:
Function getEnvValue doesn't specify return type explicitly
Suggestion:
Add explicit return type: function getEnvValue(...): string | undefined
Confidence: 75%
Rule: ts_missing_return_type
| const { publishableKey, pricingTableId } = resolvedConfig.value | ||
| if (!publishableKey || !pricingTableId) { | ||
| return | ||
| } | ||
| const renderKey = `${publishableKey}:${pricingTableId}` | ||
| if (renderKey === lastRenderedKey.value && isReady.value) { | ||
| return | ||
| } | ||
| try { | ||
| await loadScript() | ||
| loadError.value = null | ||
| if (!tableContainer.value) { | ||
| return | ||
| } | ||
| if (stripeElement.value) { | ||
| stripeElement.value.remove() | ||
| stripeElement.value = null | ||
| } | ||
| const stripeTable = document.createElement('stripe-pricing-table') | ||
| stripeTable.setAttribute('publishable-key', publishableKey) | ||
| stripeTable.setAttribute('pricing-table-id', pricingTableId) | ||
| stripeTable.style.display = 'block' | ||
| stripeTable.style.width = '100%' | ||
| stripeTable.style.minHeight = '420px' | ||
| tableContainer.value.appendChild(stripeTable) | ||
| stripeElement.value = stripeTable | ||
| lastRenderedKey.value = renderKey | ||
| isReady.value = true | ||
| } catch (error) { | ||
| console.error('[StripePricingTable] Failed to load pricing table', error) | ||
| loadError.value = (error as Error).message | ||
| isReady.value = false | ||
| } | ||
| } | ||
| watch( | ||
| [resolvedConfig, () => tableContainer.value], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔵 LOW - Long method - renderPricingTable
Category: quality
Description:
The renderPricingTable function is 39 lines long with multiple responsibilities (validation, script loading, DOM manipulation)
Suggestion:
Consider extracting createStripeTableElement() and appendStripeTable() into separate functions
Confidence: 60%
Rule: quality_long_method
| loadError.value = (error as Error).message | ||
| isReady.value = false | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟠 HIGH - Unsafe type assertion without validation
Category: bug
Description:
Error cast to Error type without validating it's actually an Error instance
Suggestion:
Add type guard: loadError.value = error instanceof Error ? error.message : String(error)
Confidence: 85%
Rule: ts_avoid_unsafe_type_assertions
| if (stripeElement.value) { | ||
| stripeElement.value.remove() | ||
| stripeElement.value = null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 MEDIUM - Missing null check after async operation
Category: bug
Description:
tableContainer.value checked after await but element could be unmounted during loadScript()
Suggestion:
Add early return with null check: if (!tableContainer.value) return after each async operation
Confidence: 70%
Rule: bug_missing_null_check
| global: { | ||
| plugins: [i18n] | ||
| } | ||
| }) | ||
|
|
||
| describe('StripePricingTable', () => { | ||
| beforeEach(() => { | ||
| currentConfig = { | ||
| publishableKey: 'pk_test_123', | ||
| pricingTableId: 'prctbl_123' | ||
| } | ||
| hasConfig = true | ||
| mockLoadStripeScript.mockReset().mockResolvedValue(undefined) | ||
| mockIsLoaded.value = false | ||
| mockIsLoading.value = false | ||
| mockError.value = null | ||
| }) | ||
|
|
||
| it('renders the Stripe pricing table when config is available', async () => { | ||
| const wrapper = mountComponent() | ||
|
|
||
| await flushPromises() | ||
|
|
||
| expect(mockLoadStripeScript).toHaveBeenCalled() | ||
|
|
||
| const stripePricingTable = wrapper.find('stripe-pricing-table') | ||
| expect(stripePricingTable.exists()).toBe(true) | ||
| expect(stripePricingTable.attributes('publishable-key')).toBe('pk_test_123') | ||
| expect(stripePricingTable.attributes('pricing-table-id')).toBe('prctbl_123') | ||
| }) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 MEDIUM - Missing cleanup in afterEach
Category: bug
Description:
Mocks and module state not cleaned up between tests, can cause test pollution
Suggestion:
Add afterEach(() => { vi.restoreAllMocks() }) to ensure clean state between tests
Confidence: 80%
Rule: vitest_cleanup_after_each
| global: { | ||
| plugins: [i18n] | ||
| } | ||
| }) | ||
|
|
||
| describe('StripePricingTable', () => { | ||
| beforeEach(() => { | ||
| currentConfig = { | ||
| publishableKey: 'pk_test_123', | ||
| pricingTableId: 'prctbl_123' | ||
| } | ||
| hasConfig = true | ||
| mockLoadStripeScript.mockReset().mockResolvedValue(undefined) | ||
| mockIsLoaded.value = false | ||
| mockIsLoading.value = false | ||
| mockError.value = null | ||
| }) | ||
|
|
||
| it('renders the Stripe pricing table when config is available', async () => { | ||
| const wrapper = mountComponent() | ||
|
|
||
| await flushPromises() | ||
|
|
||
| expect(mockLoadStripeScript).toHaveBeenCalled() | ||
|
|
||
| const stripePricingTable = wrapper.find('stripe-pricing-table') | ||
| expect(stripePricingTable.exists()).toBe(true) | ||
| expect(stripePricingTable.attributes('publishable-key')).toBe('pk_test_123') | ||
| expect(stripePricingTable.attributes('pricing-table-id')).toBe('prctbl_123') | ||
| }) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 MEDIUM - Missing edge case tests for error and loading states
Category: quality
Description:
Test suite only covers happy path and missing config. Missing tests for loading state and error state when script loading fails.
Suggestion:
Add test cases for: 1) Loading state (verify 'stripe-table-loading' element appears while script loads), 2) Error state (mock loadScript to reject and verify 'stripe-table-error' element appears)
Confidence: 85%
Rule: test_js_missing_edge_cases
| const poll = async () => { | ||
| try { | ||
| await fetchStatus() | ||
| } catch (error) { | ||
| console.error( | ||
| '[SubscriptionDialog] Failed to poll subscription status', | ||
| error | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 MEDIUM - Async poll function without error propagation
Category: bug
Description:
Poll errors are logged but don't stop polling or notify user of failures
Suggestion:
Track consecutive errors and stop polling after threshold, or show user notification after repeated failures
Confidence: 75%
Rule: ts_log_errors_instead_of_failing_silently
|
|
Due to the deadline, I really need to merge this. Please leave reviews still and I will implement changes tomorrow. |
…onditional on feature flag) (#7288) Integrates Stripe's pricing table web component into the subscription dialog when the subscription_tiers_enabled feature flag is active. The implementation includes a new StripePricingTable component that loads Stripe's pricing table script and renders the table with proper error handling and loading states. The subscription dialog now displays the Stripe pricing table with contact us and enterprise links, using a 1100px width that balances multi-column layout with visual design. Configuration supports environment variables, remote config, and window config for the Stripe publishable key and pricing table ID. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7288-feat-add-Stripe-pricing-table-integration-for-subscription-dialog-conditional-on-featur-2c46d73d365081fa9d93c213df118996) by [Unito](https://www.unito.io)
|
@christian-byrne Successfully backported to #7292 |
…subscription dialog (conditional on feature flag) (#7292) Backport of #7288 to `cloud/1.34` Automatically created by backport workflow. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7292-backport-cloud-1-34-feat-add-Stripe-pricing-table-integration-for-subscription-dialog--2c46d73d36508111869ddf32de921b29) by [Unito](https://www.unito.io) Co-authored-by: Christian Byrne <[email protected]>
…onditional on feature flag) (Comfy-Org#7288) Integrates Stripe's pricing table web component into the subscription dialog when the subscription_tiers_enabled feature flag is active. The implementation includes a new StripePricingTable component that loads Stripe's pricing table script and renders the table with proper error handling and loading states. The subscription dialog now displays the Stripe pricing table with contact us and enterprise links, using a 1100px width that balances multi-column layout with visual design. Configuration supports environment variables, remote config, and window config for the Stripe publishable key and pricing table ID. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7288-feat-add-Stripe-pricing-table-integration-for-subscription-dialog-conditional-on-featur-2c46d73d365081fa9d93c213df118996) by [Unito](https://www.unito.io)
Integrates Stripe's pricing table web component into the subscription dialog when the subscription_tiers_enabled feature flag is active. The implementation includes a new StripePricingTable component that loads Stripe's pricing table script and renders the table with proper error handling and loading states. The subscription dialog now displays the Stripe pricing table with contact us and enterprise links, using a 1100px width that balances multi-column layout with visual design. Configuration supports environment variables, remote config, and window config for the Stripe publishable key and pricing table ID.
┆Issue is synchronized with this Notion page by Unito