Skip to content

Conversation

@christian-byrne
Copy link
Contributor

@christian-byrne christian-byrne commented Dec 9, 2025

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

@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Dec 9, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Review skipped — only excluded labels are configured. (1)
  • backport

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This 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

Cohort / File(s) Summary
Configuration & Environment
.env_example, src/vite-env.d.ts, src/config/stripePricingTableConfig.ts, src/platform/remoteConfig/types.ts, global.d.ts
Added Stripe pricing table environment variables and configuration utilities. Introduced VITE_STRIPE_PUBLISHABLE_KEY and VITE_STRIPE_PRICING_TABLE_ID with TypeScript interfaces for Vite, Window, and RemoteConfig types. Created config resolution utilities getStripePricingTableConfig() and hasStripePricingTableConfig() with fallback chain (remoteConfig → window.CONFIG → env vars → defaults).
Localization
src/locales/en/main.json
Added i18n strings for pricing table UI including descriptions, loading states, error messages, and subscription-related copy (contact us, enterprise options).
Stripe Pricing Component & Loader
src/platform/cloud/subscription/components/StripePricingTable.vue, src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
Created new Vue 3 component to render Stripe pricing table with support for loading, error, and missing-config states. Introduced shared composable for idempotent Stripe script loading with singleton pattern, tracking load state and errors.
Subscription Components Integration
src/platform/cloud/subscription/components/SubscribeButton.vue, src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue, src/platform/cloud/subscription/composables/useSubscription.ts, src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
Integrated Stripe pricing flow into subscription components. Added feature flag support (subscription_tiers_enabled) for conditional Stripe pricing display, subscription status polling (3-second intervals, 5-minute max), dialog size adaptation, and await-state tracking for Stripe subscriptions. Updated dialog service invocation pattern.
Settings UI
src/platform/settings/composables/useSettingUI.ts
Refactored plan credits panel visibility logic to depend on feature flag and subscription state. Replaced hard-coded subscription_required checks with computed shouldShowPlanCreditsPanel condition.
Tests
tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
Added unit tests for StripePricingTable component covering script loading and rendering with valid config, and missing-config message display.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch credits/stripe-table

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

❤️ Share

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

@christian-byrne christian-byrne changed the title Add Stripe pricing table integration for subscription dialog feat: add Stripe pricing table integration for subscription dialog (conditional on feature flag) Dec 9, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d3f918 and 6241fd7.

📒 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.ts
  • src/composables/useFeatureFlags.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/vite-env.d.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/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.ts
  • src/composables/useFeatureFlags.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/vite-env.d.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/remoteConfig/types.ts
  • src/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 () { ... } or for () { ... }) to avoid arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions (especially testable ones)
Watch out for code smells and refactor to avoid them
Implement proper error handling in code
If a complex type definition is inlined in multiple related places, extract and name it for reuse

Files:

  • src/config/stripePricingTableConfig.ts
  • src/composables/useFeatureFlags.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/vite-env.d.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/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.ts
  • src/composables/useFeatureFlags.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/vite-env.d.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
**/*.{js,ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript exclusively (no new JavaScript)

Files:

  • src/config/stripePricingTableConfig.ts
  • src/composables/useFeatureFlags.ts
  • global.d.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/vite-env.d.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • src/config/stripePricingTableConfig.ts
  • src/composables/useFeatureFlags.ts
  • global.d.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/vite-env.d.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/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.ts
  • src/composables/useFeatureFlags.ts
  • global.d.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/vite-env.d.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/useFeatureFlags.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/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.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/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.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/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.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/components/SubscribeButton.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/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.ts
  • src/composables/useFeatureFlags.ts
  • global.d.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/vite-env.d.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/remoteConfig/types.ts
  • src/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.ts
  • src/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.ts
  • src/platform/settings/composables/useSettingUI.ts
  • 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 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.ts
  • src/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.ts
  • src/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.ts
  • src/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.ts
  • src/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.ts
  • src/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.ts
  • 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/settings/composables/useSettingUI.ts
  • 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 **/*.{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.ts
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscription.ts
  • src/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.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/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 useDialogService composable 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_ENABLED feature flag follows the established patterns in this file, with a safe default of false and 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 RemoteConfig type, maintaining consistency with the Window.__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 missingConfig message 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 the hasStripePricingTableConfig helper 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 createSharedComposable to ensure singleton state across all consumers, preventing duplicate script loads.

src/platform/cloud/subscription/components/StripePricingTable.vue (2)

106-114: Consider using watchEffect for 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.setInterval for 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6241fd7 and 66f805b.

📒 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.ts
  • src/composables/useFeatureFlags.ts
src/**/*.ts

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

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

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

Files:

  • src/config/stripePricingTableConfig.ts
  • src/composables/useFeatureFlags.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

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

Files:

  • src/config/stripePricingTableConfig.ts
  • src/composables/useFeatureFlags.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/config/stripePricingTableConfig.ts
  • src/composables/useFeatureFlags.ts
**/*.{js,ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript exclusively (no new JavaScript)

Files:

  • src/config/stripePricingTableConfig.ts
  • src/composables/useFeatureFlags.ts
  • global.d.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • src/config/stripePricingTableConfig.ts
  • src/composables/useFeatureFlags.ts
  • global.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.ts
  • src/composables/useFeatureFlags.ts
  • global.d.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/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.ts
  • src/composables/useFeatureFlags.ts
  • global.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‑safe

Adding 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
@github-actions
Copy link

github-actions bot commented Dec 9, 2025

🎭 Playwright Test Results

Some tests failed

⏰ Completed at: 12/09/2025, 11:14:28 AM UTC

📈 Summary

  • Total Tests: 488
  • Passed: 467 ✅
  • Failed: 1 ❌
  • Flaky: 11 ⚠️
  • Skipped: 9 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 458 / ❌ 1 / ⚠️ 11 / ⏭️ 9
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 6 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@github-actions
Copy link

github-actions bot commented Dec 9, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 12/09/2025, 11:06:02 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Dec 9, 2025

Bundle Size Report

Summary

  • Raw size: 17.1 MB baseline 17.1 MB — 🔴 +1.45 kB
  • Gzip: 3.38 MB baseline 3.38 MB — 🔴 +365 B
  • Brotli: 2.59 MB baseline 2.59 MB — 🔴 +323 B
  • Bundles: 97 current • 97 baseline • 37 added / 37 removed

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

Per-category breakdown
App Entry Points — 3.21 MB (baseline 3.21 MB) • 🔴 +768 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BgGeTyyU.js (new) 2.99 MB 🔴 +2.99 MB 🔴 +621 kB 🔴 +472 kB
assets/index-Cx2PM0r7.js (removed) 2.99 MB 🟢 -2.99 MB 🟢 -621 kB 🟢 -472 kB
assets/index-0xlTLVLf.js (removed) 223 kB 🟢 -223 kB 🟢 -47.6 kB 🟢 -39.3 kB
assets/index-fcsHUSZF.js (new) 223 kB 🔴 +223 kB 🔴 +47.6 kB 🔴 +39.3 kB
assets/index-Beo-v7d0.js (new) 345 B 🔴 +345 B 🔴 +243 B 🔴 +209 B
assets/index-CHlPvQ9W.js (removed) 345 B 🟢 -345 B 🟢 -246 B 🟢 -238 B

Status: 3 added / 3 removed

Graph Workspace — 986 kB (baseline 985 kB) • 🔴 +682 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-BZ5aaNu2.js (new) 986 kB 🔴 +986 kB 🔴 +191 kB 🔴 +145 kB
assets/GraphView-CWsPgtOW.js (removed) 985 kB 🟢 -985 kB 🟢 -191 kB 🟢 -145 kB

Status: 1 added / 1 removed

Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/UserSelectView-3HYb8nBt.js (removed) 6.54 kB 🟢 -6.54 kB 🟢 -2.14 kB 🟢 -1.89 kB
assets/UserSelectView-C2UoG6lJ.js (new) 6.54 kB 🔴 +6.54 kB 🔴 +2.14 kB 🔴 +1.9 kB

Status: 1 added / 1 removed

Panels & Settings — 298 kB (baseline 298 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CreditsPanel-CUCRU04d.js (new) 21.4 kB 🔴 +21.4 kB 🔴 +5.15 kB 🔴 +4.5 kB
assets/CreditsPanel-uYXvBkRu.js (removed) 21.4 kB 🟢 -21.4 kB 🟢 -5.15 kB 🟢 -4.49 kB
assets/KeybindingPanel-FfFz77U0.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.42 kB 🔴 +3.01 kB
assets/KeybindingPanel-mFD2r5rg.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.42 kB 🟢 -3.01 kB
assets/ExtensionPanel-Bg8Vbhy6.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.58 kB 🟢 -2.26 kB
assets/ExtensionPanel-DadGBvlb.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.57 kB 🔴 +2.26 kB
assets/AboutPanel-CdXJQDp9.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.2 kB
assets/AboutPanel-CVjuHIbo.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.2 kB
assets/ServerConfigPanel-Ber6_C4J.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -1.83 kB 🟢 -1.63 kB
assets/ServerConfigPanel-D_lhmpMX.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +1.83 kB 🔴 +1.63 kB
assets/UserPanel-DAeNCal9.js (new) 6.23 kB 🔴 +6.23 kB 🔴 +1.72 kB 🔴 +1.51 kB
assets/UserPanel-DLR1pHcG.js (removed) 6.23 kB 🟢 -6.23 kB 🟢 -1.72 kB 🟢 -1.5 kB
assets/settings-BhbWhsRg.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BXTtSH4O.js 33.3 kB 33.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C9Pzn-NG.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CCy2fA_h.js 27.3 kB 27.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CQpqEFfl.js 26.6 kB 26.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DHcnxypw.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DhFTK9fY.js 25.1 kB 25.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DlT4t_ui.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DRgSrIdD.js 24.2 kB 24.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-tjkeqiZq.js 21.1 kB 21.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

UI Components — 176 kB (baseline 176 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Load3D.vue_vue_type_script_setup_true_lang-CkL9rpFF.js (removed) 53.9 kB 🟢 -53.9 kB 🟢 -8.52 kB 🟢 -7.31 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-DLR_T-F9.js (new) 53.9 kB 🔴 +53.9 kB 🔴 +8.52 kB 🔴 +7.32 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-3UnAibYw.js (new) 48.1 kB 🔴 +48.1 kB 🔴 +10.4 kB 🔴 +8.99 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-Clr79L4n.js (removed) 48.1 kB 🟢 -48.1 kB 🟢 -10.4 kB 🟢 -8.99 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-BD18eHYI.js (new) 46 kB 🔴 +46 kB 🔴 +10.3 kB 🔴 +8.98 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-BmaYf7PI.js (removed) 46 kB 🟢 -46 kB 🟢 -10.3 kB 🟢 -8.98 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-d4MtmhFW.js (new) 12.9 kB 🔴 +12.9 kB 🔴 +3.37 kB 🔴 +2.97 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-DetkOJm1.js (removed) 12.9 kB 🟢 -12.9 kB 🟢 -3.37 kB 🟢 -2.97 kB
assets/ComfyQueueButton-BVU2aWs_.js (new) 8.44 kB 🔴 +8.44 kB 🔴 +2.48 kB 🔴 +2.21 kB
assets/ComfyQueueButton-iiQjWW-M.js (removed) 8.44 kB 🟢 -8.44 kB 🟢 -2.48 kB 🟢 -2.21 kB
assets/MediaTitle.vue_vue_type_script_setup_true_lang-CjR5GBev.js (new) 897 B 🔴 +897 B 🔴 +502 B 🔴 +444 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-CnVKTyKe.js (removed) 897 B 🟢 -897 B 🟢 -504 B 🟢 -451 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-BkTMAMst.js 1.34 kB 1.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-CMkR1knv.js 2.04 kB 2.04 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-6ZIklFyS.js 2.26 kB 2.26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-D3JUbTiF.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/keybindingService-DklATgK9.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.83 kB 🟢 -1.58 kB
assets/audioService-B8rnoges.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +957 B 🔴 +822 B
assets/audioService-DnQNx9wa.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -962 B 🟢 -822 B
assets/serverConfigStore-L3qzi_1Z.js 2.83 kB 2.83 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 2 added / 2 removed

Utilities & Hooks — 3.18 kB (baseline 3.18 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-BX1H5CIv.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +652 B 🔴 +543 B
assets/audioUtils-D0ENC8LR.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -651 B 🟢 -548 B
assets/mathUtil-CD4DsosH.js 1.32 kB 1.32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeFilterUtil-CXKCRJ-m.js 460 B 460 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 1 added / 1 removed

Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-chart-DJFoH6N_.js 452 kB 452 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-BZV8aGUB.js 3.98 MB 3.98 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-CkvDSSUa.js 1.96 MB 1.96 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-aR6ntw5X.js 1.37 MB 1.37 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-Cmu0_BY4.js 232 kB 232 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-Bz22sFex.js 160 kB 160 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-BZLod3g9.js 407 kB 407 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 3.81 MB (baseline 3.81 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WidgetRecordAudio-BIGWPR2V.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.24 kB 🔴 +4.63 kB
assets/WidgetRecordAudio-mNAbBbFy.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.24 kB 🟢 -4.64 kB
assets/AudioPreviewPlayer-DcOJf7Zw.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.4 kB 🔴 +3.04 kB
assets/AudioPreviewPlayer-DSMDArSw.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.4 kB 🟢 -3.04 kB
assets/WidgetGalleria-C5oK7NXY.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.45 kB 🟢 -1.3 kB
assets/WidgetGalleria-pWldby95.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.44 kB 🔴 +1.31 kB
assets/WidgetColorPicker-DhuJggxT.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetColorPicker-FhKBWqHU.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetMarkdown-CEm-YkdK.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetMarkdown-D0A4WtwO.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/WidgetTextarea-2_h-PxbR.js (new) 2.93 kB 🔴 +2.93 kB 🔴 +1.17 kB 🔴 +1.04 kB
assets/WidgetTextarea-BrKzI-Zk.js (removed) 2.93 kB 🟢 -2.93 kB 🟢 -1.17 kB 🟢 -1.03 kB
assets/WidgetAudioUI-0LD4pu6y.js (new) 2.85 kB 🔴 +2.85 kB 🔴 +1.16 kB 🔴 +1.05 kB
assets/WidgetAudioUI-DnAHz4Lq.js (removed) 2.85 kB 🟢 -2.85 kB 🟢 -1.17 kB 🟢 -1.05 kB
assets/WidgetInputText-BLXsO6X1.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -917 B 🟢 -848 B
assets/WidgetInputText-C0U6yA50.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +915 B 🔴 +846 B
assets/MediaImageBottom-3GG9KYhb.js (new) 1.57 kB 🔴 +1.57 kB 🔴 +740 B 🔴 +648 B
assets/MediaImageBottom-Dz8nXr2t.js (removed) 1.57 kB 🟢 -1.57 kB 🟢 -742 B 🟢 -648 B
assets/MediaAudioBottom-D9IwrAC5.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -743 B 🟢 -660 B
assets/MediaAudioBottom-ro13pW9p.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +740 B 🔴 +657 B
assets/MediaVideoBottom-BL_ACx7D.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +738 B 🔴 +656 B
assets/MediaVideoBottom-CvMMOpQD.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -739 B 🟢 -658 B
assets/Media3DBottom-BhXc-c-W.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -731 B 🟢 -653 B
assets/Media3DBottom-BU-3r0S3.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +730 B 🔴 +651 B
assets/Media3DTop-D63VwL9G.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +765 B 🔴 +657 B
assets/Media3DTop-RKlT43Y-.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -766 B 🟢 -652 B
assets/WidgetSelect-jZdjmdfY.js (removed) 655 B 🟢 -655 B 🟢 -342 B 🟢 -289 B
assets/WidgetSelect-QSw6_V7R.js (new) 655 B 🔴 +655 B 🔴 +342 B 🔴 +292 B
assets/WidgetInputNumber-BOZiSnwH.js (new) 595 B 🔴 +595 B 🔴 +327 B 🔴 +273 B
assets/WidgetInputNumber-XK2aRf9T.js (removed) 595 B 🟢 -595 B 🟢 -330 B 🟢 -278 B
assets/Load3D-CJmT4RCK.js (new) 424 B 🔴 +424 B 🔴 +266 B 🔴 +226 B
assets/Load3D-CNqFc3vG.js (removed) 424 B 🟢 -424 B 🟢 -267 B 🟢 -226 B
assets/WidgetLegacy-DIfj9m3J.js (removed) 364 B 🟢 -364 B 🟢 -238 B 🟢 -192 B
assets/WidgetLegacy-Dy1htTZ6.js (new) 364 B 🔴 +364 B 🔴 +236 B 🔴 +194 B
assets/commands-_s-RvhJR.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BuUILW6P.js 13 kB 13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BV4R6fLx.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BWp4HdfU.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CLwPdnT6.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CWMchBmd.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DazTQhtc.js 12.9 kB 12.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DmWrOe93.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DwiH7Kr6.js 13.8 kB 13.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-mS3LCNPn.js 14.5 kB 14.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B1JflQcI.js 72.2 kB 72.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B2lyXe48.js 114 kB 114 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B9XEQ-pc.js 94 kB 94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BErKFzc-.js 73.1 kB 73.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Bf7Tze-u.js 83.4 kB 83.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BhGMcO4Q.js 84.3 kB 84.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CPZUloNQ.js 99 kB 99 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cw9RZWRY.js 89 B 89 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dva0z-T2.js 86.5 kB 86.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-un0K9wDS.js 81.8 kB 81.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-BPDWO8-i.js 1.46 kB 1.46 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-BtY1hGDO.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-ehTZdDBw.js 2.76 kB 2.76 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BC3OlaIn.js 342 kB 342 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BsqN8-W1.js 285 kB 285 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bw_Jitw_.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CK2saYDx.js 307 kB 307 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Cm5kR4Hi.js 306 kB 306 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CMrh-uxB.js 310 kB 310 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DlUIOit1.js 369 kB 369 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DNu_xoP2.js 282 kB 282 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DpcvlpZe.js 303 kB 303 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-IyjOYIl-.js 317 kB 317 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-DhnqAfj7.js 2.48 kB 2.48 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-DFci1T8T.js 2.21 kB 2.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-D6b0vE-q.js 1.58 kB 1.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 17 added / 17 removed

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 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 ESLint no-floating-promises error. Since showSubscriptionDialog is 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-in ImportMetaEnv instead of redefining it.

The interfaces inside declare global override rather than augment Vite's built-in types from vite/client. Move ImportMetaEnv outside the declare global block 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: Use flags.subscriptionTiersEnabled to include remote config resolution.

The featureFlag() function only calls api.getServerFeature(), but flags.subscriptionTiersEnabled also checks remoteConfig.value.subscription_tiers_enabled first. 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 subscriptionPanel is already null when !isCloud || !window.__CONFIG__?.subscription_required (lines 96-98), the check on line 115 is redundant—if that condition were true, line 114 would already return false.

   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 using flags.subscriptionTiersEnabled directly.

The useFeatureFlags composable already exposes a subscriptionTiersEnabled getter on flags, 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.env is always defined. If this is defensive programming for edge cases, consider adding a comment explaining when import.meta.env might be undefined.


12-29: Add explicit return type for better API clarity.

As a public API function, getStripePricingTableConfig should 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 as useSubscriptionDialog.ts.

Consider using flags.subscriptionTiersEnabled directly instead of featureFlag() 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 between hasValidConfig and resolvedConfig.

hasValidConfig returns true if both props.publishableKey and props.pricingTableId are provided, but resolvedConfig allows partial prop overrides (e.g., only publishableKey from props with pricingTableId from 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 missing isLoading state 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 querySelector and addEventListener, leaving the promise unresolved. Additionally, isLoading.value is not set to true for 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 isActiveSubscription becomes true, this watcher calls both emit('close', true) and handleClose(). If the parent listens to both the close event and provides an onClose prop 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. handleContactUs is an async function, but when called from the @click handler on line 50, the returned promise isn't handled. If commandStore.execute throws, 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

📥 Commits

Reviewing files that changed from the base of the PR and between 66f805b and 19a3a9f.

📒 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.ts
  • src/vite-env.d.ts
  • src/config/stripePricingTableConfig.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/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.ts
  • src/vite-env.d.ts
  • src/config/stripePricingTableConfig.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/platform/cloud/subscription/composables/useSubscription.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/platform/settings/composables/useSettingUI.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/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 () { ... } or for () { ... }) to avoid arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions (especially testable ones)
Watch out for code smells and refactor to avoid them
Implement proper error handling in code
If a complex type definition is inlined in multiple related places, extract and name it for reuse

Files:

  • src/platform/settings/composables/useSettingUI.ts
  • src/vite-env.d.ts
  • src/config/stripePricingTableConfig.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/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.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/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.ts
  • src/vite-env.d.ts
  • src/config/stripePricingTableConfig.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/remoteConfig/types.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/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.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/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.ts
  • src/vite-env.d.ts
  • src/config/stripePricingTableConfig.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/remoteConfig/types.ts
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • global.d.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/platform/cloud/subscription/composables/useSubscription.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • src/platform/settings/composables/useSettingUI.ts
  • src/vite-env.d.ts
  • src/config/stripePricingTableConfig.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/remoteConfig/types.ts
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • global.d.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/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.ts
  • src/vite-env.d.ts
  • src/config/stripePricingTableConfig.ts
  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/remoteConfig/types.ts
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • global.d.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/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.vue
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • src/platform/cloud/subscription/components/StripePricingTable.vue
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/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.ts
  • src/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.ts
  • src/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.ts
  • src/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.ts
  • src/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.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • 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,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/platform/settings/composables/useSettingUI.ts
  • 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 Vue 3's Teleport component when needed

Applied to files:

  • src/platform/settings/composables/useSettingUI.ts
  • 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 **/*.{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
  • 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 **/*.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.ts
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue
  • src/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.ts
  • src/vite-env.d.ts
  • src/config/stripePricingTableConfig.ts
  • src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts
  • src/platform/remoteConfig/types.ts
  • tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts
  • global.d.ts
  • src/platform/cloud/subscription/composables/useSubscriptionDialog.ts
  • src/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.ts
  • src/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.vue
  • src/platform/cloud/subscription/components/SubscribeButton.vue
  • src/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.ts
  • src/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_example pattern with appropriate VITE_ 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 useDialogService import 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 groupedMenuTreeNodes correctly 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 resolvedConfig and tableContainer ref, triggers on changes, and includes proper guards before rendering. The immediate: true option ensures initial render on mount.


89-95: Consider using type assertion for custom element.

The stripe-pricing-table is 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 HTMLElement

This 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 issue
src/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.

…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
@christian-byrne christian-byrne added needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch cloud/1.34 Backport PRs for cloud 1.34 labels Dec 9, 2025
Comment on lines +187 to +210
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)
}

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> => {

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

Comment on lines +6 to +10
interface StripePricingTableConfig {
publishableKey: string
pricingTableId: string
}

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

Comment on lines +66 to +104
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],

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
}
}

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

Comment on lines +82 to +84
if (stripeElement.value) {
stripeElement.value.remove()
stripeElement.value = null

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

Comment on lines +45 to +75
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')
})

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

Comment on lines +45 to +75
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')
})

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

Comment on lines +191 to +199
const poll = async () => {
try {
await fetchStatus()
} catch (error) {
console.error(
'[SubscriptionDialog] Failed to poll subscription status',
error
)
}

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

@diffray-bot
Copy link

diffray diffray code review

Free public review - Want AI code reviews on your PRs? Check out diffray.ai

Summary

Validated 14 issues: 10 kept (2 high, 5 medium, 3 low), 4 filtered (1 incorrect, 3 low value)

Issues Found: 10

See 9 individual line comment(s) for details.

Full issue list (click to expand)

🟡 MEDIUM - Duplicated polling logic

File: src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue:187-210

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


🔵 LOW - Missing explicit return type

File: src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts:24

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


🔵 LOW - Missing explicit return type

File: src/config/stripePricingTableConfig.ts:6-10

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


🔵 LOW - Long method - renderPricingTable

File: src/platform/cloud/subscription/components/StripePricingTable.vue:66-104

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


🟠 HIGH - Unsafe type assertion without validation

File: src/platform/cloud/subscription/components/StripePricingTable.vue:101

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


🟡 MEDIUM - Missing null check after async operation

File: src/platform/cloud/subscription/components/StripePricingTable.vue:82-84

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


🟡 MEDIUM - Missing cleanup in afterEach

File: tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts:45-75

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


🟡 MEDIUM - Missing edge case tests for error and loading states

File: tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts:45-75

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


🟡 MEDIUM - Async poll function without error propagation

File: src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue:191-199

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


🟡 MEDIUM - Single Responsibility Principle violation

File: src/platform/settings/composables/useSettingUI.ts:22-247

Category: quality

Description: useSettingUI composable handles multiple unrelated responsibilities: panel configuration, settings tree building, menu grouping, translation, and default category resolution

Suggestion: Split into focused composables: useSettingPanels() for panel definitions, useSettingsTree() for tree building logic, useSettingsMenu() for menu grouping. This will improve testability and make each piece easier to understand and modify independently.

Confidence: 65%

Rule: arch_srp_violation



Powered by DiffRay - AI Code Review | Learn more

@christian-byrne
Copy link
Contributor Author

Due to the deadline, I really need to merge this. Please leave reviews still and I will implement changes tomorrow.

@christian-byrne christian-byrne merged commit 8209f5a into main Dec 9, 2025
37 of 38 checks passed
@christian-byrne christian-byrne deleted the credits/stripe-table branch December 9, 2025 11:45
github-actions bot pushed a commit that referenced this pull request Dec 9, 2025
…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)
@comfy-pr-bot
Copy link
Member

@christian-byrne Successfully backported to #7292

@github-actions github-actions bot removed the needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch label Dec 9, 2025
christian-byrne added a commit that referenced this pull request Dec 9, 2025
…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]>
Enferlain pushed a commit to Enferlain/ComfyUI_frontend that referenced this pull request Dec 9, 2025
…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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:auth area:cloud cloud/1.34 Backport PRs for cloud 1.34 size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants