-
Notifications
You must be signed in to change notification settings - Fork 461
[feat] Add async model upload with WebSocket progress tracking #7746
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] Add async model upload with WebSocket progress tracking #7746
Conversation
📝 WalkthroughWalkthroughAdds async model upload support: feature flag, async upload API + schema, WebSocket asset_download handling, a Pinia asset download store with progress toasts, upload wizard/UI updates for processing/preview flows, and model-cache refresh wiring on download completion. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User (UI)
participant Wizard as Upload Wizard
participant Service as Asset Service
participant Server as Backend
participant WS as WebSocket
participant Store as Asset Download Store
participant Cache as Model Cache
rect rgb(200,220,240)
Note over User,Cache: Async upload path (flag enabled)
User->>Wizard: start upload
Wizard->>Wizard: check flags.asyncModelUploadEnabled
Wizard->>Wizard: uploadPreviewImage()
Wizard->>Service: uploadAssetAsync(metadata, preview_id)
Service->>Server: POST /assets/download
Server-->>Service: 202 { task_id, status: 'created' }
Service-->>Wizard: AsyncUploadResponse (task)
Wizard->>Store: trackDownload(task_id, modelType)
Wizard->>Wizard: set uploadStatus = 'processing'
Server->>WS: emit asset_download { status:'running', ... }
WS->>Store: handleAssetDownload()
Store->>User: show progress toast (throttled)
Server->>WS: emit asset_download { status:'completed', asset_id, ... }
WS->>Store: handleAssetDownload()
Store->>Cache: request model cache refresh (updateModelsForNodeType)
Store->>User: show success toast
end
rect rgb(240,220,200)
Note over User,Cache: Sync upload path (flag disabled)
User->>Wizard: start upload
Wizard->>Wizard: check flags.asyncModelUploadEnabled
Wizard->>Wizard: uploadPreviewImage()
Wizard->>Service: uploadAssetFromUrl(user_metadata, preview_id)
Service->>Server: POST /assets/upload
Server-->>Service: 200 { asset ... }
Service-->>Wizard: asset response
Wizard->>Wizard: set uploadStatus = 'success'
Wizard->>Cache: refreshModelCaches()
Wizard->>User: advance step / show success
end
Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (1 passed)
✨ Finishing touches
Comment |
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 01/06/2026, 07:36:23 PM UTC 🔗 Links🎉 Your Storybook is ready for review! |
🎭 Playwright Test Results⏰ Completed at: 01/06/2026, 07:42:18 PM UTC 📈 Summary
📊 Test Reports by Browser
🎉 Click on the links above to view detailed test results for each browser configuration. |
Bundle Size ReportSummary
Category Glance Per-category breakdownApp Entry Points — 3.24 MB (baseline 3.23 MB) • 🔴 +6.99 kBMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 1.01 MB (baseline 1.01 MB) • 🔴 +431 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 6.63 kB (baseline 6.63 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 1 added / 1 removed Panels & Settings — 300 kB (baseline 300 kB) • 🔴 +2 BConfiguration panels, inspectors, and settings screens
Status: 6 added / 6 removed UI Components — 196 kB (baseline 193 kB) • 🔴 +2.75 kBReusable component library chunks
Status: 9 added / 9 removed Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 2 added / 2 removed Utilities & Hooks — 1.41 kB (baseline 1.41 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed Vendor & Third-Party — 9.19 MB (baseline 9.19 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 3.5 MB (baseline 3.5 MB) • ⚪ 0 BBundles that do not match a named category
Status: 20 added / 20 removed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (14)
src/composables/useFeatureFlags.tssrc/locales/en/main.jsonsrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/composables/useAssetDownloadProgress.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/platform/remoteConfig/types.tssrc/schemas/apiSchema.tssrc/scripts/api.tssrc/stores/assetDownloadStore.tssrc/views/GraphView.vue
🧰 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/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelProgress.vue
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/schemas/apiSchema.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelProgress.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelProgress.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not useanytype oras anytype assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code
Files:
src/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelProgress.vue
**/*.{ts,tsx,vue,js,jsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width
Files:
src/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/locales/en/main.jsonsrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelProgress.vue
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Minimize the surface area (exported values) of each module and composable
Files:
src/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/schemas/apiSchema.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/services/assetService.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.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/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelFooter.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.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/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelFooter.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.vue
**/**/use[A-Z]*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables using the pattern
useXyz.ts
Files:
src/platform/assets/composables/useUploadModelWizard.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.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/assets/components/UploadModelFooter.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3.5+ with TypeScript in.vuefiles, exclusively using Composition API with<script setup lang="ts">syntax
Use Tailwind 4 for styling in Vue components; avoid<style>blocks
Name Vue components using PascalCase (e.g.,MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not usewithDefaultsor runtime props declaration
Prefercomputed()overrefwithwatchwhen deriving values
PreferuseModelover separately defining prop and emit for two-way binding
Usevue-i18nin composition API for string literals; place new translation entries insrc/locales/en/main.json
Usecn()utility function from@/utils/tailwindUtilfor merging Tailwind class names; do not use:class="[]"syntax
Do not use thedark:Tailwind variant; use semantic values from thestyle.csstheme instead (e.g.,bg-node-component-surface)
Do not use!importantor the!important prefix for Tailwind classes; find and correct interfering!importantclasses instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
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/assets/components/UploadModelFooter.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.vue
src/**/stores/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores
Files:
src/stores/assetDownloadStore.ts
**/*Store.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name Pinia stores using the pattern
*Store.ts
Files:
src/stores/assetDownloadStore.ts
🧠 Learnings (24)
📚 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/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/schemas/apiSchema.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/schemas/apiSchema.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/schemas/apiSchema.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/scripts/api.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useAssetDownloadProgress.tssrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelProgress.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/**/stores/**/*.{ts,tsx} : Use TypeScript for type safety in state management stores
Applied to files:
src/platform/assets/composables/useUploadModelWizard.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/**/{services,composables}/**/*.{ts,tsx} : Use `api.fileURL()` for static file access instead of constructing URLs directly
Applied to files:
src/platform/assets/services/assetService.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/**/{services,composables}/**/*.{ts,tsx} : Use `api.apiURL()` for backend endpoints instead of constructing URLs directly
Applied to files:
src/platform/assets/services/assetService.ts
📚 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/assets/components/UploadModelFooter.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-21T06:04:12.548Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.548Z
Learning: Applies to **/*Store.ts : Name Pinia stores using the pattern `*Store.ts`
Applied to files:
src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/stores/**/*.{ts,tsx} : Maintain clear public interfaces and restrict extension access in stores
Applied to files:
src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-21T06:04:12.548Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.548Z
Learning: Applies to **/**/use[A-Z]*.ts : Name composables using the pattern `useXyz.ts`
Applied to files:
src/platform/assets/composables/useAssetDownloadProgress.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/assets/composables/useAssetDownloadProgress.tssrc/views/GraphView.vue
📚 Learning: 2025-12-21T06:04:12.548Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.548Z
Learning: Applies to **/*.vue : Use Vue 3.5+ with TypeScript in `.vue` files, exclusively using Composition API with `<script setup lang="ts">` syntax
Applied to files:
src/platform/assets/composables/useAssetDownloadProgress.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.
Applied to files:
src/locales/en/main.json
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{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/locales/en/main.json
📚 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/locales/en/main.json
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Steps component with Stepper without panels
Applied to files:
src/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue InputSwitch component with ToggleSwitch
Applied to files:
src/platform/assets/components/UploadModelProgress.vue
🧬 Code graph analysis (5)
src/platform/assets/composables/useUploadModelWizard.ts (2)
src/composables/useFeatureFlags.ts (1)
useFeatureFlags(24-95)src/platform/assets/services/assetService.ts (1)
assetService(509-509)
src/scripts/api.ts (1)
src/schemas/apiSchema.ts (1)
AssetDownloadWsMessage(168-168)
src/platform/assets/services/assetService.ts (1)
src/platform/assets/schemas/assetSchema.ts (2)
AsyncUploadResponse(91-91)asyncUploadResponseSchema(84-84)
src/stores/assetDownloadStore.ts (4)
src/platform/assets/composables/useAssetDownloadProgress.ts (1)
AssetDownload(7-16)src/platform/updates/common/toastStore.ts (1)
useToastStore(8-39)src/schemas/apiSchema.ts (1)
AssetDownloadWsMessage(168-168)src/scripts/api.ts (1)
api(1309-1309)
src/composables/useFeatureFlags.ts (2)
src/platform/remoteConfig/remoteConfig.ts (1)
remoteConfig(22-22)src/scripts/api.ts (1)
api(1309-1309)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: setup
- GitHub Check: test
- GitHub Check: lint-and-format
- GitHub Check: collect
🔇 Additional comments (17)
src/platform/remoteConfig/types.ts (1)
42-42: LGTM - Feature flag field added correctly.The new optional boolean field follows the existing naming convention and pattern for remote config feature flags.
src/views/GraphView.vue (2)
63-63: LGTM - Asset download store integration follows established patterns.The store is properly initialized and follows the same pattern as other stores in this component.
Also applies to: 91-91
259-259: LGTM - Proper lifecycle management for asset download events.Event binding and cleanup correctly mirrors the existing executionStore pattern, preventing memory leaks.
Also applies to: 276-276
src/scripts/api.ts (2)
20-20: LGTM - AssetDownloadWsMessage type properly integrated.The type import and BackendApiCalls interface extension follow the established patterns for WebSocket message types.
Also applies to: 157-157
669-670: LGTM - Asset download message handling implemented correctly.The message dispatch follows the same pattern as other WebSocket message types.
src/platform/assets/components/UploadModelFooter.vue (2)
84-87: LGTM - Finish button logic supports async upload flow.Allowing the "Finish" button for both 'processing' and 'success' states enables users to close the dialog while downloads continue in the background, which aligns with the async upload UX described in the PR objectives.
125-125: LGTM - Upload status type updated to reflect result-based flow.The prop type change from status-based values (idle/uploading) to result-based values (processing/success/error) is consistent with the broader refactoring described in the PR.
src/locales/en/main.json (1)
2272-2272: LGTM - i18n keys for async upload flow added correctly.The new localization keys follow the repository's naming conventions and provide clear messaging for the processing, download, and error states.
Also applies to: 2278-2279, 2331-2335
src/schemas/apiSchema.ts (1)
138-147: LGTM - Asset download WebSocket message schema is well-structured.The schema uses Zod v3-compatible patterns and provides comprehensive type-safe validation for asset download progress tracking. The status enum values ('created', 'running', 'completed', 'failed') follow standard task lifecycle conventions.
Based on learnings, Zod v3 compatibility is maintained.
Also applies to: 168-168
src/composables/useFeatureFlags.ts (1)
18-18: LGTM - Async model upload feature flag properly implemented.The new feature flag follows the established pattern: checks remote config first, then falls back to the server feature flag with a sensible default of
false. This allows the feature to be controlled server-side while maintaining backward compatibility.Also applies to: 77-85
src/platform/assets/components/UploadModelDialog.vue (1)
29-29: InitializeuploadStatuswith a default value instead of using non-null assertion.The state machine guarantees
uploadStatusis always set beforecurrentStepreaches 3, but the non-null assertion!masks a type inconsistency. SinceuploadStatusis declared asref<'processing' | 'success' | 'error'>()without an initial value, its type includesundefined.Initialize it with a default value (e.g.,
ref<'processing' | 'success' | 'error'>('processing')) to remove theundefinedfrom the type and eliminate the need for the assertion.src/platform/assets/composables/useAssetDownloadProgress.ts (1)
18-56: Consider cleanup and potential stale data retention.The
activeDownloadsMap persists across component lifecycles since it's a local ref. If a component using this composable unmounts and remounts, stale download entries (that never reachedcompletedorfailed) may remain indefinitely. WhileuseEventListenercleans up the listener on unmount, the Map itself is not cleared.Verify whether this composable is intended to be:
- Instance-scoped (new Map per component): If so, stale entries are acceptable since each instance is independent.
- Globally shared (singleton-like behavior): If so, consider exposing a
clearDownloads()method or periodic cleanup to prevent memory growth from abandoned tasks.Given the PR also includes
assetDownloadStore(which appears to be the centralized, global store for this data), clarify whether this composable is still needed or if it's redundant. If both exist, document their distinct purposes clearly.src/stores/assetDownloadStore.ts (1)
63-76: Fire-and-forget async call in completion handler.Line 68 uses
void refreshModelCaches(modelType)to explicitly discard the promise. This is acceptable for fire-and-forget behavior, but if cache refresh failures should be surfaced to the user (e.g., via a warning toast), consider awaiting the call and handling errors.Verify whether silent cache refresh failures are acceptable UX. If not, handle errors:
if (modelType) { try { await refreshModelCaches(modelType) } catch (error) { console.error('Failed to refresh model caches:', error) toastStore.add({ severity: 'warn', summary: st('assetBrowser.cacheRefreshFailed', 'Cache refresh failed'), detail: st('assetBrowser.cacheRefreshFailedDetail', 'Please refresh manually.'), life: 5000 }) } pendingModelTypes.delete(data.task_id) }src/platform/assets/composables/useUploadModelWizard.ts (3)
159-184: Preview image upload helper looks correct.The
uploadPreviewImagefunction correctly:
- Extracts the base filename (handles filenames without extensions)
- Derives the extension from the MIME type
- Uploads the preview image separately
- Returns
undefinedon error, allowing the main upload to proceed without a previewThe filename splitting at line 165 (
filename.split('.')[0]) works for most cases. For filenames like"model.v2.safetensors", only"model"is used, which is acceptable for preview naming.
226-250: Async upload flow handles both sync and async responses correctly.The feature-flagged async upload path correctly:
- Uploads the preview image first to obtain
preview_id- Constructs
userMetadatawith source information- Calls
uploadAssetAsyncand handles bothasync(202) andsync(200) responses- Tracks async downloads via the store
- Refreshes model caches on sync completion
The logic is sound and aligns with the PR objectives.
252-263: Non-async upload path preserved correctly.The fallback to
uploadAssetFromUrlwhen the async flag is disabled maintains the original behavior while benefiting from the new helper functions (uploadPreviewImage,refreshModelCaches,userMetadataconstruction).src/platform/assets/components/UploadModelProgress.vue (1)
3-10: The i18n keysassetBrowser.processingModelandassetBrowser.processingModelDescriptionare properly defined insrc/locales/en/main.jsonwith values "Download started" and "You can close this dialog. The download will continue in the background." respectively. The component correctly uses these keys in the Vue template.
|
@CodeRabbit full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/platform/assets/components/UploadModelDialog.vue (2)
27-34: Consider defensive handling instead of non-null assertion.The non-null assertion (
uploadStatus!) assumesuploadStatusis always defined at step 3. While this is likely true given the flow (upload must start to reach step 3), a defensive approach would be safer.Per coding guidelines, prefer proper TypeScript types over assertions. Consider either:
- Providing a default value in the template binding
- Using a computed property that guarantees a value at step 3
🔎 Suggested defensive approach
<!-- Step 3: Upload Progress --> <UploadModelProgress v-else-if="currentStep === 3" - :result="uploadStatus!" + :result="uploadStatus ?? 'processing'" :error="uploadError" :metadata="wizardData.metadata" :model-type="selectedModelType" :preview-image="wizardData.previewImage" />Alternatively, ensure
uploadStatusis always initialized when entering step 3 in the composable.
108-120: Consider using Tailwind instead of scoped styles.Per coding guidelines, Vue components should use Tailwind 4 for styling and avoid
<style>blocks. The responsive width styling could be achieved with Tailwind classes.🔎 Suggested Tailwind approach
<div - class="upload-model-dialog flex flex-col justify-between gap-6 p-4 pt-6 border-t border-border-default" + class="flex flex-col justify-between gap-6 p-4 pt-6 border-t border-border-default w-[90vw] max-w-[800px] min-h-[400px] sm:w-auto sm:min-w-[600px]" >Then remove the
<style scoped>block entirely.
♻️ Duplicate comments (6)
src/platform/assets/services/assetService.ts (1)
484-491: Unhandled Zod validation errors may leak internal details.Lines 487 and 490 call
asyncUploadResponseSchema.parse()without try-catch. If the backend returns an unexpected response shape, Zod will throw an error with internal schema details that may confuse end users or leak API structure.🔎 Wrap Zod parsing in try-catch with user-friendly error
const data = await res.json() + try { if (res.status === 202) { return asyncUploadResponseSchema.parse({ type: 'async', task: data }) } return asyncUploadResponseSchema.parse({ type: 'sync', asset: data }) + } catch (error) { + console.error('Invalid async upload response:', error) + throw new Error( + st( + 'assetBrowser.errorInvalidResponse', + 'Received invalid response from server. Please try again.' + ) + ) + }src/platform/assets/components/UploadModelProgress.vue (1)
12-29: Duplicated model preview card UI.The model preview card structure (image + metadata display) is duplicated between the processing state (lines 12-29) and success state (lines 41-59). Consider extracting to a reusable component
ModelPreviewCard.vue.Also applies to: 41-59
src/platform/assets/composables/useUploadModelWizard.ts (1)
186-197: Promise.all brittleness in cache refresh.The
refreshModelCachesfunction usesPromise.all, which will fail entirely if any single provider's cache update fails. This also duplicates logic fromassetDownloadStore.ts(lines 42-58) which correctly usesPromise.allSettled.🔎 Use Promise.allSettled for resilience
async function refreshModelCaches() { if (!selectedModelType.value) return const providers = modelToNodeStore.getAllNodeProviders( selectedModelType.value ) - await Promise.all( + const results = await Promise.allSettled( providers.map((provider) => assetsStore.updateModelsForNodeType(provider.nodeDef.name) ) ) + // Log failures without blocking completion + for (const result of results) { + if (result.status === 'rejected') { + console.error('Failed to refresh model cache:', result.reason) + } + } }src/stores/assetDownloadStore.ts (3)
12-21: Duplicate interface definition.The
AssetDownloadinterface is duplicated in multiple locations. As noted in previous reviews, consider consolidating to a shared types file (e.g.,src/types/asset.ts) to maintain a single source of truth.
29-31: Non-reactive Maps without cleanup method.
pendingModelTypesandlastToastTimeare non-reactive Maps used for internal tracking. As noted in previous reviews, consider exposing areset()method to clear all Maps for cleanup scenarios (logout, app reset).
128-130: Manual lifecycle requires caller diligence.The
setup()method must be called manually by consumers to bind event listeners. As noted in previous reviews, consider adding clear JSDoc comments warning thatsetup()must be called (e.g., inonMounted) to prevent memory leaks and ensure event handling works correctly.🔎 Add JSDoc documentation
+ /** + * Binds asset download event listeners. + * MUST be called once when the consumer component mounts (e.g., in onMounted). + * VueUse's useEventListener handles automatic cleanup on unmount. + */ function setup() { useEventListener(api, 'asset_download', handleAssetDownload) }
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (16)
src/composables/useFeatureFlags.tssrc/locales/en/main.jsonsrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/platform/remoteConfig/types.tssrc/schemas/apiSchema.tssrc/scripts/api.tssrc/stores/assetDownloadStore.tssrc/views/GraphView.vue
🧰 Additional context used
📓 Path-based instructions (15)
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/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/views/GraphView.vuesrc/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/views/GraphView.vuesrc/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/views/GraphView.vuesrc/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3.5+ with TypeScript in.vuefiles, exclusively using Composition API with<script setup lang="ts">syntax
Use Tailwind 4 for styling in Vue components; avoid<style>blocks
Name Vue components using PascalCase (e.g.,MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not usewithDefaultsor runtime props declaration
Prefercomputed()overrefwithwatchwhen deriving values
PreferuseModelover separately defining prop and emit for two-way binding
Usevue-i18nin composition API for string literals; place new translation entries insrc/locales/en/main.json
Usecn()utility function from@/utils/tailwindUtilfor merging Tailwind class names; do not use:class="[]"syntax
Do not use thedark:Tailwind variant; use semantic values from thestyle.csstheme instead (e.g.,bg-node-component-surface)
Do not use!importantor the!important prefix for Tailwind classes; find and correct interfering!importantclasses instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
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/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not useanytype oras anytype assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code
Files:
src/views/GraphView.vuesrc/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
**/*.{ts,tsx,vue,js,jsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width
Files:
src/views/GraphView.vuesrc/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/locales/en/main.jsonsrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/composables/useFeatureFlags.tssrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Minimize the surface area (exported values) of each module and composable
Files:
src/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/composables/useFeatureFlags.tssrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.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/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.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/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/platform/assets/services/assetService.tssrc/composables/useFeatureFlags.tssrc/platform/assets/composables/useUploadModelWizard.ts
**/**/use[A-Z]*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables using the pattern
useXyz.ts
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/composables/useUploadModelWizard.ts
src/**/stores/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores
Files:
src/stores/assetDownloadStore.ts
**/*Store.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name Pinia stores using the pattern
*Store.ts
Files:
src/stores/assetDownloadStore.ts
🧠 Learnings (23)
📚 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/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/views/GraphView.vuesrc/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelFooter.vuesrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 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/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/composables/useFeatureFlags.tssrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/composables/useFeatureFlags.tssrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/composables/useFeatureFlags.tssrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().
Applied to files:
src/scripts/api.tssrc/schemas/apiSchema.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/composables/useFeatureFlags.tssrc/stores/assetDownloadStore.tssrc/platform/remoteConfig/types.tssrc/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue InlineMessage component with Message
Applied to files:
src/platform/assets/components/UploadModelUrlInput.vue
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
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:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Steps component with Stepper without panels
Applied to files:
src/platform/assets/components/UploadModelProgress.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/**/{services,composables}/**/*.{ts,tsx} : Use `api.fileURL()` for static file access instead of constructing URLs directly
Applied to files:
src/platform/assets/services/assetService.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Implement proper error handling in code
Applied to files:
src/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*Store.ts : Name Pinia stores using the pattern `*Store.ts`
Applied to files:
src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/stores/**/*.{ts,tsx} : Maintain clear public interfaces and restrict extension access in stores
Applied to files:
src/stores/assetDownloadStore.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/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/stores/**/*.{ts,tsx} : Use TypeScript for type safety in state management stores
Applied to files:
src/stores/assetDownloadStore.tssrc/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Use Vue 3.5+ with TypeScript in `.vue` files, exclusively using Composition API with `<script setup lang="ts">` syntax
Applied to files:
src/platform/assets/components/UploadModelUrlInputCivitai.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/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead
Applied to files:
src/platform/assets/components/UploadModelUrlInputCivitai.vue
🧬 Code graph analysis (5)
src/scripts/api.ts (1)
src/schemas/apiSchema.ts (1)
AssetDownloadWsMessage(168-168)
src/platform/assets/services/assetService.ts (2)
src/platform/assets/schemas/assetSchema.ts (2)
AsyncUploadResponse(89-89)asyncUploadResponseSchema(83-83)src/i18n.ts (1)
st(209-212)
src/composables/useFeatureFlags.ts (2)
src/platform/remoteConfig/remoteConfig.ts (1)
remoteConfig(22-22)src/scripts/api.ts (1)
api(1309-1309)
src/stores/assetDownloadStore.ts (3)
src/platform/updates/common/toastStore.ts (1)
useToastStore(8-39)src/schemas/apiSchema.ts (1)
AssetDownloadWsMessage(168-168)src/scripts/api.ts (1)
api(1309-1309)
src/platform/assets/composables/useUploadModelWizard.ts (4)
src/stores/assetDownloadStore.ts (1)
useAssetDownloadStore(25-139)src/stores/modelToNodeStore.ts (1)
useModelToNodeStore(22-168)src/composables/useFeatureFlags.ts (1)
useFeatureFlags(24-95)src/platform/assets/services/assetService.ts (1)
assetService(509-509)
🔇 Additional comments (26)
src/platform/remoteConfig/types.ts (1)
42-42: LGTM!The new
async_model_upload_enabledfield follows the existing naming convention (snake_case) and type pattern (optional boolean) used by other feature flags inRemoteConfig.src/views/GraphView.vue (1)
63-63: LGTM - Store integration follows existing patterns.The import and instantiation of
useAssetDownloadStorefollows the same pattern as other stores in this component (e.g.,executionStore).Also applies to: 91-91
src/platform/assets/components/UploadModelUrlInputCivitai.vue (2)
21-29: LGTM - Conditional rendering based on feature flag.Correctly hides the file size limit message when async model upload is enabled, as the async flow handles larger files via background processing.
77-79: LGTM - Feature flags integration.The
useFeatureFlagscomposable is properly imported and destructured following the established pattern in this codebase.src/platform/assets/components/AssetBrowserModal.vue (1)
136-145: LGTM - Proper refresh on download completion.The watcher correctly detects when all active downloads complete (transition from
truetofalse) and refreshes the asset list. This ensures newly downloaded models appear in the browser after background processing finishes.src/platform/assets/components/UploadModelUrlInput.vue (2)
58-66: LGTM - Consistent feature flag gating.The file size limit message is now conditionally rendered based on
asyncModelUploadEnabled, consistent with the similar change inUploadModelUrlInputCivitai.vue.
80-82: LGTM - Feature flags integration.Properly imports and destructures
useFeatureFlagsfollowing the established pattern.src/scripts/api.ts (2)
20-20: LGTM - Type-safe WebSocket message handling.The
AssetDownloadWsMessagetype is properly imported and added to theBackendApiCallsinterface, ensuring type safety for the new WebSocket event.Also applies to: 157-157
669-670: LGTM - WebSocket message dispatch.The
asset_downloadcase follows the established pattern for dispatching WebSocket messages, consistent with other message types likenotificationandlogs.src/platform/assets/components/UploadModelFooter.vue (2)
84-96: LGTM! Processing state properly integrated.The addition of the 'processing' state allows the upload dialog to be closed while downloads continue in the background. The conditional rendering and button labeling logic correctly handle the new state.
129-129: No action needed. UploadModelDialog.vue already explicitly passes:upload-status="uploadStatus"to UploadModelFooter, and the component safely handles the optional prop through strict equality checks at lines 85–86 and 93 that gracefully return false if undefined. The change from required to optional does not introduce any issues with the sole caller.src/platform/assets/schemas/assetSchema.ts (1)
61-70: LGTM! Status enum mismatch resolved.The async upload schemas are well-structured. The status enum now correctly uses
'running'instead of'in_progress', aligning with the AssetDownload interface and WebSocket message handler expectations. The discriminated union pattern is appropriate for distinguishing sync vs async responses.src/schemas/apiSchema.ts (1)
138-147: LGTM! WebSocket message schema is well-designed.The
zAssetDownloadWsMessageschema appropriately captures all necessary fields for tracking download progress. The status enum is consistent withzAsyncUploadTask, and the field types are suitable for the data being tracked.src/locales/en/main.json (4)
182-182: LGTM! Status localization added.The "downloading" status text appropriately complements existing status values like "completed", "failed", etc.
2273-2273: LGTM! Error message for invalid sources.Clear and concise error message for when no valid import source is detected.
2279-2280: LGTM! Background download messaging.These messages clearly communicate that downloads continue in the background after closing the dialog, setting appropriate user expectations for the async upload flow.
2332-2336: LGTM! Download status feedback.The download status group provides clear, specific feedback for each stage. The
inProgressmessage using{assetName}parameter gives users visibility into which asset is downloading.src/composables/useFeatureFlags.ts (2)
18-18: LGTM! Feature flag enum member added.The
ASYNC_MODEL_UPLOAD_ENABLEDenum member follows the established naming convention.
77-85: LGTM! Feature flag getter implementation.The
asyncModelUploadEnabledgetter correctly follows the established pattern of checking remote config first and falling back to the API feature flag with a sensible default.src/platform/assets/services/assetService.ts (1)
51-51: LGTM: Endpoint constant follows existing pattern.The new
ASSETS_DOWNLOAD_ENDPOINTconstant is consistent with the existingASSETS_ENDPOINTpattern and clearly defines the async download endpoint.src/platform/assets/components/UploadModelProgress.vue (2)
83-89: LGTM: Props follow Vue 3.5 best practices.The props are correctly defined using Vue 3.5 destructuring with proper TypeScript types. The
resultprop clearly defines the three states of the upload flow.
3-30: LGTM: Processing state UI is well-structured.The new processing state provides clear feedback for async uploads with appropriate i18n strings and conditional preview image rendering.
src/platform/assets/composables/useUploadModelWizard.ts (3)
13-13: LGTM: Store integration and state updates are correct.The integration of
assetDownloadStoreand the updateduploadStatustype correctly support the new async upload flow with processing, success, and error states.Also applies to: 33-33, 39-39
159-184: LGTM: Preview upload helper is well-designed.The
uploadPreviewImagehelper correctly handles preview image uploads with graceful error handling. Failures returnundefinedrather than blocking the main upload flow, which is the right design choice.
228-260: LGTM: Async and non-async upload paths are well-structured.The feature-flag-gated branching between async and non-async upload flows is clear and correct. The async path properly tracks downloads via the store when processing continues in the background, while the non-async path maintains the original synchronous flow.
src/stores/assetDownloadStore.ts (1)
42-58: LGTM: Cache refresh uses resilient error handling.The
refreshModelCachesfunction correctly usesPromise.allSettledto ensure all provider cache updates are attempted even if some fail. Individual failures are logged without blocking completion.
916f3ea to
7ab4693
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (7)
src/platform/assets/services/assetService.ts (1)
484-491: Unhandled Zod validation errors may leak internal details.Lines 487 and 490 call
asyncUploadResponseSchema.parse()without try-catch. If the backend returns an unexpected response shape, Zod will throw an error with internal schema details that may confuse end users or leak API structure.🔎 Wrap Zod parsing in try-catch with user-friendly error
const data = await res.json() + try { if (res.status === 202) { return asyncUploadResponseSchema.parse({ type: 'async', task: data }) } return asyncUploadResponseSchema.parse({ type: 'sync', asset: data }) + } catch (error) { + console.error('Invalid async upload response:', error) + throw new Error( + st( + 'assetBrowser.errorInvalidResponse', + 'Received invalid response from server. Please try again.' + ) + ) + }src/platform/assets/components/UploadModelProgress.vue (1)
12-29: Consider extracting duplicated model preview card.The model preview card structure (image + metadata display) is duplicated between the processing state (lines 12-29) and success state (lines 41-59). The only difference is the surrounding text.
🔎 Extract to a reusable component
Consider creating a shared component
ModelPreviewCard.vue:<template> <div class="flex flex-row items-center gap-3 p-4 bg-modal-card-background rounded-lg"> <img v-if="previewImage" :src="previewImage" :alt="altText" class="w-14 h-14 rounded object-cover flex-shrink-0" /> <div class="flex flex-col justify-center items-start gap-1 flex-1"> <p class="text-base-foreground m-0">{{ filename }}</p> <p class="text-sm text-muted m-0">{{ modelType }}</p> </div> </div> </template> <script setup lang="ts"> defineProps<{ previewImage?: string filename?: string altText: string modelType?: string }>() </script>Then reuse in both states to eliminate duplication.
Also applies to: 41-59
src/platform/assets/composables/useUploadModelWizard.ts (2)
186-197: Duplicate cache refresh logic with brittleness.This
refreshModelCachesfunction duplicates logic inassetDownloadStore.ts(lines 41-48). Additionally, usingPromise.allmeans if any provider fails, the entire refresh fails. The store implementation usesPromise.allSettledfor better resilience.🔎 Consolidate and use Promise.allSettled
Option 1: Delegate to store method if exposed:
async function refreshModelCaches() { if (!selectedModelType.value) return - const providers = modelToNodeStore.getAllNodeProviders( - selectedModelType.value - ) - await Promise.all( - providers.map((provider) => - assetsStore.updateModelsForNodeType(provider.nodeDef.name) - ) - ) + await assetDownloadStore.refreshModelCaches(selectedModelType.value) }Option 2: Use
Promise.allSettledlocally:async function refreshModelCaches() { if (!selectedModelType.value) return const providers = modelToNodeStore.getAllNodeProviders( selectedModelType.value ) - await Promise.all( + const results = await Promise.allSettled( providers.map((provider) => assetsStore.updateModelsForNodeType(provider.nodeDef.name) ) ) + // Log failures without blocking + results.forEach((result, index) => { + if (result.status === 'rejected') { + console.error( + `Failed to refresh ${providers[index].nodeDef.name}:`, + result.reason + ) + } + }) }
236-236: Use strict equality for consistency.Lines 236 and 270 use
!=instead of!==. The repository guidelines require strict equality operators for consistency and type safety.🔎 Use strict equality
- if (result.type === 'async' && result.task.status != 'completed') { + if (result.type === 'async' && result.task.status !== 'completed') {and
- return uploadStatus.value != 'error' + return uploadStatus.value !== 'error'Also applies to: 270-270
src/stores/assetDownloadStore.ts (3)
12-21: Consolidate duplicate AssetDownload interface to a shared types file.This interface duplicates the definition in
useAssetDownloadProgress.ts. Move it to a shared types file (e.g.,src/types/asset.ts) and import from there to maintain a single source of truth.🔎 Consolidate to shared types file
In a new or existing shared types file (e.g.,
src/types/asset.ts):export interface AssetDownload { taskId: string assetId: string assetName: string bytesTotal: number bytesDownloaded: number progress: number status: 'created' | 'running' | 'completed' | 'failed' error?: string }Then import in this file:
+import type { AssetDownload } from '@/types/asset' - -interface AssetDownload { - taskId: string - assetId: string - assetName: string - bytesTotal: number - bytesDownloaded: number - progress: number - status: 'created' | 'running' | 'completed' | 'failed' - error?: string -}
25-32: Add a reset() method for cleanup.Plain Maps and Sets (
pendingModelTypes,lastToastTime,processedTaskIds) should be clearable for scenarios like logout or app reset to prevent memory leaks.🔎 Add reset method
+ function reset() { + activeDownloads.value.clear() + pendingModelTypes.clear() + lastToastTime.clear() + processedTaskIds.clear() + } return { activeDownloads, hasActiveDownloads, downloadList, trackDownload, setup, - teardown + teardown, + reset }
127-134: Add JSDoc warnings for manual lifecycle management.Callers must remember to call
teardown()on unmount to prevent memory leaks. Document this requirement explicitly.🔎 Add JSDoc warnings
+ /** + * Initialize asset download event listeners. + * MUST call teardown() on component unmount to prevent memory leaks. + */ function setup() { stopListener = useEventListener(api, 'asset_download', handleAssetDownload) } + /** + * Remove asset download event listeners. + * MUST be called on component unmount. + */ function teardown() { stopListener?.() stopListener = undefined }
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (16)
src/composables/useFeatureFlags.tssrc/locales/en/main.jsonsrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/platform/remoteConfig/types.tssrc/schemas/apiSchema.tssrc/scripts/api.tssrc/stores/assetDownloadStore.tssrc/views/GraphView.vue
🧰 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/scripts/api.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/schemas/apiSchema.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/scripts/api.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/scripts/api.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not useanytype oras anytype assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code
Files:
src/scripts/api.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
**/*.{ts,tsx,vue,js,jsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width
Files:
src/scripts/api.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/locales/en/main.jsonsrc/platform/assets/components/UploadModelProgress.vue
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Minimize the surface area (exported values) of each module and composable
Files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/schemas/apiSchema.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.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/assets/components/UploadModelFooter.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/platform/assets/components/UploadModelFooter.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.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/platform/assets/components/UploadModelFooter.vuesrc/composables/useFeatureFlags.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3.5+ with TypeScript in.vuefiles, exclusively using Composition API with<script setup lang="ts">syntax
Use Tailwind 4 for styling in Vue components; avoid<style>blocks
Name Vue components using PascalCase (e.g.,MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not usewithDefaultsor runtime props declaration
Prefercomputed()overrefwithwatchwhen deriving values
PreferuseModelover separately defining prop and emit for two-way binding
Usevue-i18nin composition API for string literals; place new translation entries insrc/locales/en/main.json
Usecn()utility function from@/utils/tailwindUtilfor merging Tailwind class names; do not use:class="[]"syntax
Do not use thedark:Tailwind variant; use semantic values from thestyle.csstheme instead (e.g.,bg-node-component-surface)
Do not use!importantor the!important prefix for Tailwind classes; find and correct interfering!importantclasses instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
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/assets/components/UploadModelFooter.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.ts
**/**/use[A-Z]*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables using the pattern
useXyz.ts
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/composables/useUploadModelWizard.ts
src/**/stores/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores
Files:
src/stores/assetDownloadStore.ts
**/*Store.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name Pinia stores using the pattern
*Store.ts
Files:
src/stores/assetDownloadStore.ts
🧠 Learnings (24)
📚 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/scripts/api.tssrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/schemas/apiSchema.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/schemas/apiSchema.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/schemas/apiSchema.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().
Applied to files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/schemas/apiSchema.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/scripts/api.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/remoteConfig/types.tssrc/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/schemas/apiSchema.tssrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.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/assets/components/UploadModelFooter.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelProgress.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/**/{services,composables}/**/*.{ts,tsx} : Use `api.fileURL()` for static file access instead of constructing URLs directly
Applied to files:
src/platform/assets/services/assetService.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Implement proper error handling in code
Applied to files:
src/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*Store.ts : Name Pinia stores using the pattern `*Store.ts`
Applied to files:
src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/stores/**/*.{ts,tsx} : Maintain clear public interfaces and restrict extension access in stores
Applied to files:
src/stores/assetDownloadStore.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/stores/assetDownloadStore.tssrc/views/GraphView.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/**/stores/**/*.{ts,tsx} : Use TypeScript for type safety in state management stores
Applied to files:
src/stores/assetDownloadStore.tssrc/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Use Vue 3.5+ with TypeScript in `.vue` files, exclusively using Composition API with `<script setup lang="ts">` syntax
Applied to files:
src/platform/assets/components/UploadModelUrlInputCivitai.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/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead
Applied to files:
src/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/composables/useUploadModelWizard.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/views/GraphView.vue
📚 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/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue InlineMessage component with Message
Applied to files:
src/platform/assets/components/UploadModelUrlInput.vue
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
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
🧬 Code graph analysis (4)
src/scripts/api.ts (1)
src/schemas/apiSchema.ts (1)
AssetDownloadWsMessage(168-168)
src/composables/useFeatureFlags.ts (2)
src/platform/remoteConfig/remoteConfig.ts (1)
remoteConfig(22-22)src/scripts/api.ts (1)
api(1309-1309)
src/platform/assets/services/assetService.ts (3)
src/platform/assets/schemas/assetSchema.ts (2)
AsyncUploadResponse(89-89)asyncUploadResponseSchema(83-83)src/scripts/api.ts (1)
api(1309-1309)src/i18n.ts (1)
st(209-212)
src/platform/assets/composables/useUploadModelWizard.ts (4)
src/stores/assetDownloadStore.ts (1)
useAssetDownloadStore(25-144)src/stores/modelToNodeStore.ts (1)
useModelToNodeStore(22-168)src/composables/useFeatureFlags.ts (1)
useFeatureFlags(24-95)src/platform/assets/services/assetService.ts (1)
assetService(509-509)
⏰ 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). (1)
- GitHub Check: playwright-tests-chromium-sharded (2, 8)
🔇 Additional comments (16)
src/platform/assets/components/UploadModelUrlInputCivitai.vue (1)
21-21: LGTM! Feature flag integration is correct.The conditional rendering appropriately hides the max file size warning when async model upload is enabled, and the feature flag composable is properly initialized following the established pattern.
Also applies to: 77-79
src/views/GraphView.vue (1)
63-63: LGTM! Proper lifecycle management for asset download store.The asset download store is now correctly initialized with
setup()inonMountedand cleaned up withteardown()inonBeforeUnmount, following the same pattern asexecutionStore. This addresses the previous review concern about missing event listener cleanup.Also applies to: 91-91, 259-259, 276-276
src/platform/remoteConfig/types.ts (1)
42-42: LGTM! Remote config type extension is correct.The new optional
async_model_upload_enabledfield follows the established naming convention and pattern for other feature flags in theRemoteConfigtype.src/scripts/api.ts (1)
20-20: LGTM! WebSocket message type integration is correct.The
asset_downloadmessage type is properly integrated following the established pattern:
- Type imported from schema
- Added to
BackendApiCallsinterface- Handled in WebSocket message switch statement with appropriate dispatch
Also applies to: 157-157, 669-669
src/platform/assets/components/AssetBrowserModal.vue (1)
86-86: LGTM! Asset refresh on download completion is well-implemented.The watcher correctly detects when active downloads transition to completion (
hadDownloads && !hasDownloads) and triggers an asset list refresh viaexecute(). This provides good UX by automatically updating the displayed assets after downloads finish. The watcher will be automatically cleaned up on component unmount.Also applies to: 136-145
src/platform/assets/components/UploadModelUrlInput.vue (1)
58-58: LGTM! Feature flag integration is clean.The max file size message is now properly gated behind the
asyncModelUploadEnabledfeature flag. The implementation correctly usesv-else-ifto conditionally render the message only when the async upload feature is disabled, which aligns with the PR's objective of supporting async model uploads.Also applies to: 80-82
src/platform/assets/components/UploadModelFooter.vue (1)
84-96: LGTM! Status value alignment is correct.The footer properly handles the updated status values ('processing' | 'success' | 'error'), removing the old 'idle' and 'uploading' states. The button logic correctly:
- Renders for both 'success' and 'processing' states
- Shows "Close" during processing (allowing users to close the dialog while downloads continue in the background)
- Shows "Finish" after success
This aligns with the PR objective of allowing the dialog to be closed while downloads continue.
Also applies to: 129-129
src/schemas/apiSchema.ts (1)
138-147: LGTM! WebSocket message schema is well-defined.The
zAssetDownloadWsMessageschema properly defines the asset download progress tracking structure with:
- Appropriate field types for tracking download progress (bytes, task/asset IDs, status)
- Standardized status enum ('created', 'running', 'completed', 'failed') consistent with the PR's objective
- Optional error field for failure cases
- Zod v3-compatible validators (no v4-specific features)
The schema aligns with the PR's objective of implementing WebSocket-based real-time download progress tracking.
Based on learnings, Zod is on v3.x in this project.
Also applies to: 168-168
src/platform/assets/schemas/assetSchema.ts (1)
61-70: LGTM! Async upload schemas are correctly implemented.The async upload response schemas are well-structured:
zAsyncUploadTaskuses the standardized status enum ('created', 'running', 'completed', 'failed') that matchesAssetDownloadWsMessageinapiSchema.ts- The discriminated union properly handles both sync and async upload responses using the
typediscriminator- All schemas and types are correctly exported
Note: The previous status enum mismatch issue ('in_progress' vs 'running') mentioned in past reviews has been resolved - the code now consistently uses 'running' across all schemas.
Based on learnings, Zod is on v3.x in this project.
Also applies to: 83-83, 89-89
src/composables/useFeatureFlags.ts (1)
17-85: LGTM! Feature flag implementation follows established patterns.The async model upload feature flag is implemented consistently with other feature flags in this composable:
- Properly added to the
ServerFeatureFlagenum- Follows the same remote config → WebSocket fallback pattern
- Conservative default value of
false- Type-safe and reactive
src/platform/assets/services/assetService.ts (1)
451-482: LGTM! Function structure follows service patterns.The
uploadAssetAsyncfunction is well-structured:
- Uses
api.fetchApi()correctly per coding guidelines- Proper endpoint construction with
ASSETS_DOWNLOAD_ENDPOINT- Error handling uses
st()for i18n- Clear documentation of async behavior and return types
src/locales/en/main.json (1)
184-184: LGTM! Localization additions support async upload feature.The new localization keys are well-structured:
- Clear, user-friendly messages for processing, success, and failure states
- Consistent naming conventions with existing keys
- Proper placement within the asset browser section
As per coding guidelines, only English localization is required in PRs; other languages are auto-generated on release.
Also applies to: 279-279, 285-286, 338-342
src/platform/assets/components/UploadModelProgress.vue (1)
83-89: LGTM! Props interface updated for async flow.The props refactor from
statustoresultclearly distinguishes the new async-capable states:
- Removed
'idle'and'uploading'(not needed for result-based flow)- Added
'processing'to represent async downloads in progress- Added optional
previewImageprop for preview display- Follows Vue 3.5 destructuring pattern correctly
src/platform/assets/composables/useUploadModelWizard.ts (3)
159-184: LGTM! Preview upload helper is well-designed.The
uploadPreviewImagefunction provides clean encapsulation:
- Gracefully handles missing preview images by returning
undefined- Proper MIME type detection and extension mapping
- Error handling logs failures without breaking the main upload flow
- Returns asset ID for linking preview to model
This separation of concerns improves code clarity.
228-248: Async upload flow correctly implements feature-gated behavior.The async path is well-structured:
- Properly calls
uploadAssetAsyncwith all required metadata- Handles both synchronous and asynchronous responses correctly
- Tracks ongoing downloads via
assetDownloadStore.trackDownload()- Sets appropriate UI state (
'processing'vs'success')- Calls
refreshModelCaches()when completed synchronouslyThe feature flag gating allows safe rollout of the async capability.
249-260: LGTM! Non-async path maintains backward compatibility.The fallback path when the async feature flag is disabled:
- Continues using the existing
uploadAssetFromUrlmethod- Maintains the same metadata and preview structure
- Immediately refreshes caches upon success
- Provides consistent user experience for deployments without async support
This ensures graceful degradation when the feature flag is off.
src/stores/assetDownloadStore.ts
Outdated
| async function refreshModelCaches(modelType: string) { | ||
| const providers = modelToNodeStore.getAllNodeProviders(modelType) | ||
| const results = await Promise.allSettled( | ||
| providers.map((provider) => | ||
| assetsStore | ||
| .updateModelsForNodeType(provider.nodeDef.name) | ||
| .then(() => provider.nodeDef.name) | ||
| ) | ||
| ) | ||
| for (const result of results) { | ||
| if (result.status === 'rejected') { | ||
| console.error( | ||
| `Failed to refresh model cache for provider: ${result.reason}` | ||
| ) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Improve error logging to include provider name.
When a model cache refresh fails, the error message on line 55 doesn't identify which provider failed, making debugging harder.
🔎 Include provider name in error log
async function refreshModelCaches(modelType: string) {
const providers = modelToNodeStore.getAllNodeProviders(modelType)
const results = await Promise.allSettled(
- providers.map((provider) =>
- assetsStore
- .updateModelsForNodeType(provider.nodeDef.name)
- .then(() => provider.nodeDef.name)
- )
+ providers.map((provider) => ({
+ promise: assetsStore.updateModelsForNodeType(provider.nodeDef.name),
+ providerName: provider.nodeDef.name
+ }))
)
- for (const result of results) {
+ for (let i = 0; i < results.length; i++) {
+ const result = results[i]
if (result.status === 'rejected') {
console.error(
- `Failed to refresh model cache for provider: ${result.reason}`
+ `Failed to refresh model cache for ${providers[i].nodeDef.name}:`,
+ result.reason
)
}
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async function refreshModelCaches(modelType: string) { | |
| const providers = modelToNodeStore.getAllNodeProviders(modelType) | |
| const results = await Promise.allSettled( | |
| providers.map((provider) => | |
| assetsStore | |
| .updateModelsForNodeType(provider.nodeDef.name) | |
| .then(() => provider.nodeDef.name) | |
| ) | |
| ) | |
| for (const result of results) { | |
| if (result.status === 'rejected') { | |
| console.error( | |
| `Failed to refresh model cache for provider: ${result.reason}` | |
| ) | |
| } | |
| } | |
| } | |
| async function refreshModelCaches(modelType: string) { | |
| const providers = modelToNodeStore.getAllNodeProviders(modelType) | |
| const results = await Promise.allSettled( | |
| providers.map((provider) => | |
| assetsStore.updateModelsForNodeType(provider.nodeDef.name) | |
| ) | |
| ) | |
| for (let i = 0; i < results.length; i++) { | |
| const result = results[i] | |
| if (result.status === 'rejected') { | |
| console.error( | |
| `Failed to refresh model cache for ${providers[i].nodeDef.name}:`, | |
| result.reason | |
| ) | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/stores/assetDownloadStore.ts around lines 43 to 59, the current error log
on line 55 prints only the rejection reason without identifying which provider
failed; update the promise mapping so each settled result can be tied back to
its provider (e.g., resolve/reject payloads should include provider.nodeDef.name
or attach the name to the promise), then in the results loop log both the
provider name and the error (e.g., `Failed to refresh model cache for provider
<name>: <error>`). Ensure the Promise.allSettled mapping preserves provider name
for both success and failure so you can reference it when result.status ===
'rejected'.
src/stores/assetDownloadStore.ts
Outdated
| lastToastTime.delete(data.task_id) | ||
| const modelType = pendingModelTypes.get(data.task_id) | ||
| if (modelType) { | ||
| void refreshModelCaches(modelType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid floating promise; handle errors explicitly.
The void operator on line 85 discards the promise, which violates the "disallow floating promises" ESLint rule. If refreshModelCaches() fails, the error is only logged but not propagated, which could hide issues.
As per coding guidelines, implement proper error handling.
🔎 Handle the promise explicitly
Option 1: Await the promise (requires making handleAssetDownload async):
- function handleAssetDownload(e: CustomEvent<AssetDownloadWsMessage>) {
+ async function handleAssetDownload(e: CustomEvent<AssetDownloadWsMessage>) {
// ... existing code ...
if (modelType) {
- void refreshModelCaches(modelType)
+ try {
+ await refreshModelCaches(modelType)
+ } catch (error) {
+ console.error('Failed to refresh model caches:', error)
+ }
pendingModelTypes.delete(data.task_id)
}Option 2: Use .catch() to handle errors inline:
if (modelType) {
- void refreshModelCaches(modelType)
+ refreshModelCaches(modelType).catch((error) => {
+ console.error('Failed to refresh model caches:', error)
+ })
pendingModelTypes.delete(data.task_id)
}🤖 Prompt for AI Agents
In src/stores/assetDownloadStore.ts around line 85, the call "void
refreshModelCaches(modelType)" creates a floating promise and hides errors;
change this to explicitly handle the promise by either (a) making
handleAssetDownload async and awaiting refreshModelCaches(modelType) so errors
propagate, or (b) keep the function sync but attach .catch(...) to
refreshModelCaches(modelType) to log the error and, if appropriate, set error
state or rethrow; implement one of these options so ESLint's floating-promise
rule is satisfied and errors are not silently discarded.
src/stores/assetDownloadStore.ts
Outdated
| const assetsStore = useAssetsStore() | ||
| const modelToNodeStore = useModelToNodeStore() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
invert this
7ab4693 to
deffeb2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
Fix all issues with AI Agents 🤖
In @src/platform/assets/components/UploadModelProgress.vue:
- Around line 12-29: Duplicate model preview markup in UploadModelProgress.vue
should be extracted into a reusable component: create a new ModelPreviewCard (or
similar) component that accepts props previewImage, metadata and modelType and
renders the img and metadata block with the same classes and bindings (use the
same :src, :alt and text interpolations). Replace both occurrences in
UploadModelProgress.vue (the processing and success states) with the new
component and pass through previewImage, metadata and modelType to avoid
duplication while preserving existing behavior and styling.
In @src/platform/assets/composables/useUploadModelWizard.ts:
- Line 270: The return statement in useUploadModelWizard currently uses loose
inequality (return uploadStatus.value != 'error'); change it to use strict
inequality for consistency and type safety by comparing uploadStatus.value
strictly against the string 'error' (update the return in the same
function/statement that references uploadStatus.value).
- Around line 186-197: The refreshModelCaches function duplicates logic in
assetDownloadStore.ts and uses Promise.all which fails-fast; refactor by
extracting the common refresh logic into a shared helper (e.g., a new
refreshModelsForProviders utility used by both useUploadModelWizard.ts and
assetDownloadStore.ts) and replace Promise.all with Promise.allSettled when
calling
modelToNodeStore.getAllNodeProviders(selectedModelType.value).map(provider =>
assetsStore.updateModelsForNodeType(provider.nodeDef.name)), then iterate
settled results to log individual provider failures (including
provider.nodeDef.name and the rejection reason) while still resolving successes.
In @src/platform/assets/services/assetService.ts:
- Around line 484-491: Wrap the two asyncUploadResponseSchema.parse(...) calls
in a try-catch inside the function in assetService.ts that handles the upload
response; on catch, detect ZodError (or any validation error) and throw or
return a new, user-friendly error message that does not expose schema internals
(e.g., "Unexpected response format from upload API"), optionally log the
original error details to an internal logger but never surface them to the
caller; ensure you still return the parsed result for the sync path ({ type:
'sync', asset: data }) and the async path ({ type: 'async', task: data }) when
parsing succeeds.
In @src/stores/assetDownloadStore.ts:
- Around line 10-19: The AssetDownload interface is duplicated; extract the
interface named AssetDownload into a single shared type file (e.g., create
src/types/assetDownload.ts exporting interface AssetDownload) and replace local
definitions by importing AssetDownload where used (including from
stores/assetDownloadStore.ts and any other files with the duplicate). Ensure the
exported interface matches the current shape (taskId, assetId, assetName,
bytesTotal, bytesDownloaded, progress, status, error?) and update all
imports/usages to reference the new shared type so there is one source of truth.
- Around line 137-144: Add JSDoc comments to the setup() and teardown()
functions in assetDownloadStore to document their lifecycle contract: on
setup(), describe that it registers the 'asset_download' listener via
useEventListener with handleAssetDownload and must be called when the
component/module mounts or when the store is initialized; on teardown(),
document that it must be called when the component/module unmounts or the store
is disposed to call stopListener() and avoid memory leaks, and note that
stopListener will be set to undefined after invocation. Include parameter/return
annotations if applicable and a short note about potential double-calls being
no-ops.
- Around line 69-99: The completion handler can miss updates when a download
finishes before trackDownload() registers it, leaving completedDownloads and
pendingModelTypes out-of-sync; modify the handler in the block handling
data.status === 'completed' to retry or defer processing until trackDownload()
has registered the task (e.g., check pendingModelTypes and if missing schedule a
short retry/backoff that rechecks pendingModelTypes before giving up), or
alternatively emit a global event that the asset browser UI listens to so users
can manually refresh models (add a visible "Refresh Asset Models" action that
triggers the same refresh logic); ensure you continue to clear activeDownloads,
lastToastTime and processedTaskIds (using PROCESSED_TASK_CLEANUP_MS) only after
the completion has been reconciled so completedDownloads is always updated when
appropriate.
In @src/stores/assetsStore.ts:
- Around line 353-380: The watch callback on
assetDownloadStore.completedDownloads may dereference provider.nodeDef.name when
nodeDef is undefined; update the mapping over
modelToNodeStore.getAllNodeProviders(modelType) to filter or guard providers
with a truthy nodeDef before calling updateModelsForNodeType and using
provider.nodeDef.name (or skip/log providers without nodeDef), and ensure the
Promise.allSettled mapping uses only providers where provider.nodeDef?.name
exists so you never access nodeDef.name on a null/undefined value.
- Around line 354-355: The watch on assetDownloadStore.completedDownloads
currently uses a deep watch which is unnecessary and costly because
completedDownloads is replaced rather than mutated; update the watch invocation
in assetsStore (the watch call that observes
assetDownloadStore.completedDownloads) to use a shallow watch (remove or set {
deep: true } → { deep: false } or omit the deep option entirely) to improve
performance, and if you need to handle only new entries instead of the whole
array consider adding a simple tracker (e.g., lastProcessedIndex or
lastProcessedTimestamp) inside the watch callback to process only newly appended
downloads.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/platform/assets/components/UploadModelDialog.vue (1)
108-120: Consider migrating layout sizing to Tailwind utilities.Per coding guidelines, Vue components should avoid
<style>blocks and use Tailwind CSS for styling. The responsive width/height constraints could potentially be expressed using Tailwind's responsive modifiers.🔎 Potential Tailwind migration
-<style scoped> -.upload-model-dialog { - width: 90vw; - max-width: 800px; - min-height: 400px; -} - -@media (min-width: 640px) { - .upload-model-dialog { - width: auto; - min-width: 600px; - } -} -</style>Replace in template:
- <div - class="upload-model-dialog flex flex-col justify-between gap-6 p-4 pt-6 border-t border-border-default" - > + <div + class="flex flex-col justify-between gap-6 p-4 pt-6 border-t border-border-default w-[90vw] max-w-[800px] min-h-[400px] sm:w-auto sm:min-w-[600px]" + >src/platform/assets/components/UploadModelProgress.vue (1)
83-89: Unused destructured propresult.The
resultprop is destructured fromdefinePropsbut TypeScript may flag it as unused since it's only accessed via template bindings (which use the implicit prop access). In Vue 3.5+, you can safely destructure props with reactive defaults, but theresultvariable itself appears unused in the script block.🔎 Remove unnecessary destructuring if not used in script
-const { result } = defineProps<{ - result: 'processing' | 'success' | 'error' +defineProps<{ + result: 'processing' | 'success' | 'error' error?: string metadata?: AssetMetadata modelType?: string previewImage?: string }>()Alternatively, if you need
resultin the script, keep the destructuring.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (17)
src/composables/useFeatureFlags.tssrc/locales/en/main.jsonsrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/platform/remoteConfig/types.tssrc/schemas/apiSchema.tssrc/scripts/api.tssrc/stores/assetDownloadStore.tssrc/stores/assetsStore.tssrc/views/GraphView.vue
🧰 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/scripts/api.tssrc/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not useanytype oras anytype assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code
Files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
**/*.{ts,tsx,vue,js,jsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width
Files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/locales/en/main.json
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Minimize the surface area (exported values) of each module and composable
Files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.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/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3.5+ with TypeScript in.vuefiles, exclusively using Composition API with<script setup lang="ts">syntax
Use Tailwind 4 for styling in Vue components; avoid<style>blocks
Name Vue components using PascalCase (e.g.,MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not usewithDefaultsor runtime props declaration
Prefercomputed()overrefwithwatchwhen deriving values
PreferuseModelover separately defining prop and emit for two-way binding
Usevue-i18nin composition API for string literals; place new translation entries insrc/locales/en/main.json
Usecn()utility function from@/utils/tailwindUtilfor merging Tailwind class names; do not use:class="[]"syntax
Do not use thedark:Tailwind variant; use semantic values from thestyle.csstheme instead (e.g.,bg-node-component-surface)
Do not use!importantor the!important prefix for Tailwind classes; find and correct interfering!importantclasses instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
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/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
**/**/use[A-Z]*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables using the pattern
useXyz.ts
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/composables/useUploadModelWizard.ts
src/**/stores/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores
Files:
src/stores/assetsStore.tssrc/stores/assetDownloadStore.ts
**/*Store.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name Pinia stores using the pattern
*Store.ts
Files:
src/stores/assetsStore.tssrc/stores/assetDownloadStore.ts
🧠 Learnings (35)
📚 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/scripts/api.tssrc/platform/remoteConfig/types.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().
Applied to files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/scripts/api.tssrc/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/platform/assets/schemas/assetSchema.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/UploadModelUrlInput.vuesrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/stores/assetsStore.tssrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/stores/assetDownloadStore.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Implement cleanup for async operations in Vue components
Applied to files:
src/views/GraphView.vuesrc/stores/assetsStore.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/views/GraphView.vuesrc/stores/assetDownloadStore.ts
📚 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/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.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/**/{services,composables}/**/*.{ts,tsx} : Use `api.fileURL()` for static file access instead of constructing URLs directly
Applied to files:
src/platform/assets/services/assetService.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Implement proper error handling in code
Applied to files:
src/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelUrlInputCivitai.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/stores/assetsStore.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 ref/reactive for state management in Vue 3 Composition API
Applied to files:
src/stores/assetsStore.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 ref and reactive for reactive state
Applied to files:
src/stores/assetsStore.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/stores/assetsStore.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/stores/assetsStore.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Prefer `computed()` over `ref` with `watch` when deriving values
Applied to files:
src/stores/assetsStore.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/stores/assetsStore.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/stores/assetsStore.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Leverage VueUse functions for performance-enhancing styles in Vue components
Applied to files:
src/stores/assetsStore.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{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/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead
Applied to files:
src/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/stores/assetDownloadStore.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Do not use `any` type or `as any` type assertions; fix the underlying type issue instead
Applied to files:
src/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/stores/**/*.{ts,tsx} : Use TypeScript for type safety in state management stores
Applied to files:
src/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Use Vue 3.5+ with TypeScript in `.vue` files, exclusively using Composition API with `<script setup lang="ts">` syntax
Applied to files:
src/platform/assets/components/UploadModelUrlInputCivitai.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*Store.ts : Name Pinia stores using the pattern `*Store.ts`
Applied to files:
src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/stores/**/*.{ts,tsx} : Maintain clear public interfaces and restrict extension access in stores
Applied to files:
src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Prefer `useModel` over separately defining prop and emit for two-way binding
Applied to files:
src/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Steps component with Stepper without panels
Applied to files:
src/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
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
🧬 Code graph analysis (3)
src/scripts/api.ts (1)
src/schemas/apiSchema.ts (1)
AssetDownloadWsMessage(168-168)
src/platform/assets/services/assetService.ts (3)
src/platform/assets/schemas/assetSchema.ts (2)
AsyncUploadResponse(89-89)asyncUploadResponseSchema(83-83)src/scripts/api.ts (1)
api(1309-1309)src/i18n.ts (1)
st(209-212)
src/stores/assetsStore.ts (2)
src/stores/assetDownloadStore.ts (1)
useAssetDownloadStore(31-155)src/stores/modelToNodeStore.ts (1)
useModelToNodeStore(22-168)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: lint-and-format
- GitHub Check: setup
- GitHub Check: collect
- GitHub Check: test
🔇 Additional comments (23)
src/platform/assets/components/UploadModelUrlInputCivitai.vue (1)
21-29: LGTM! Feature flag integration is correct.The conditional rendering using
!flags.asyncModelUploadEnabledappropriately hides the max file size message when async upload is enabled. The feature flag composable is correctly imported and initialized following Vue 3.5 Composition API patterns.Also applies to: 77-79
src/platform/remoteConfig/types.ts (1)
42-42: LGTM! Type addition follows existing patterns.The new optional field
async_model_upload_enabled?: booleanis correctly typed and follows the established pattern for other feature flag fields in theRemoteConfigtype.src/views/GraphView.vue (1)
63-63: LGTM! Lifecycle management correctly implemented.The asset download store is properly initialized and managed with setup/teardown calls in the appropriate lifecycle hooks. The cleanup in
onBeforeUnmount(line 276) addresses the concern raised in the previous review comment about missing event listener cleanup. This follows the same pattern used forexecutionStorein this component.Also applies to: 91-91, 259-259, 276-276
src/platform/assets/components/AssetBrowserModal.vue (1)
86-86: LGTM! Download completion detection is correctly implemented.The watcher on
assetDownloadStore.hasActiveDownloadscorrectly detects when downloads complete (transition fromtruetofalse) and triggers an asset refresh by callingexecute(). The async operation is properly awaited, ensuring the refresh completes before continuing.Also applies to: 136-145
src/scripts/api.ts (1)
20-20: LGTM! WebSocket message type integration is correct.The
AssetDownloadWsMessagetype is properly imported, added to theBackendApiCallsinterface, and handled in the WebSocket message switch statement. The implementation follows the established pattern for other WebSocket message types, dispatching the event usingdispatchCustomEvent.Also applies to: 157-157, 669-670
src/platform/assets/components/UploadModelUrlInput.vue (2)
58-66: LGTM! Feature flag integration correctly hides file size limit for async uploads.The conditional rendering logic properly hides the max file size warning when async uploads are enabled, since async uploads handle large files differently through background processing.
80-82: LGTM!The feature flag composable is correctly imported and initialized following the established pattern used across the codebase.
src/platform/assets/components/UploadModelDialog.vue (1)
28-29: LGTM! Null check properly addresses the previous unsafe non-null assertion issue.The explicit
uploadStatus != nullguard ensuresUploadModelProgressonly renders whenuploadStatusis defined, preventing potential runtime errors from the previous non-null assertion (uploadStatus!).src/platform/assets/components/UploadModelFooter.vue (2)
84-96: LGTM! Button behavior correctly handles the new async upload flow.The conditional logic properly:
- Shows the finish/close button for both
'processing'and'success'states- Displays "close" during processing (allowing users to dismiss the dialog while downloads continue in background)
- Displays "finish" on success
This aligns well with the PR objectives for allowing dialog closure during background downloads.
129-129: LGTM!Making
uploadStatusoptional is appropriate since it's only relevant at step 3. The updated union type'processing' | 'success' | 'error'correctly reflects the async upload flow states.src/platform/assets/schemas/assetSchema.ts (2)
61-70: LGTM! Schema correctly implements the async upload response structure.The discriminated union pattern cleanly separates sync and async response handling. The status enum
['created', 'running', 'completed', 'failed']aligns with the standardized task statuses mentioned in the PR objectives and matches the WebSocket message schema inapiSchema.ts.
83-89: LGTM!Schema and type exports follow the established repository patterns.
src/schemas/apiSchema.ts (2)
138-148: LGTM! WebSocket message schema is well-structured.The schema correctly defines all fields needed for download progress tracking. The status enum aligns with the async upload task schema, maintaining consistency across the codebase.
168-168: LGTM!Type export follows the established pattern for WebSocket message types.
src/composables/useFeatureFlags.ts (2)
17-18: LGTM!The new enum value follows the established naming convention and is correctly positioned in the enum.
77-85: LGTM! Feature flag accessor follows established patterns.The
asyncModelUploadEnabledgetter correctly:
- Checks remote config first (
async_model_upload_enabled)- Falls back to WebSocket feature flags via
api.getServerFeature()- Defaults to
falsewhen neither source provides a valueThis is consistent with other feature flag accessors in the composable.
src/platform/assets/services/assetService.ts (1)
451-468: LGTM! Well-documented async upload function.The function signature, JSDoc, and parameter types are clear. The use of
Record<string, unknown>foruser_metadatainstead ofRecord<string, any>follows the coding guidelines for avoidinganytypes.src/locales/en/main.json (2)
2348-2352: LGTM! Well-structured localization additions.The new
downloadgroup underassetBrowserprovides clear, user-friendly messages for the async download feature. TheinProgresskey correctly uses the{assetName}interpolation placeholder.
2295-2296: LGTM! Clear processing state messaging.The
processingModelandprocessingModelDescriptionkeys provide appropriate user guidance that the download continues in the background.src/platform/assets/composables/useUploadModelWizard.ts (2)
159-184: LGTM! Clean extraction of preview upload logic.The
uploadPreviewImagehelper cleanly encapsulates the preview image upload with proper error handling. Returningundefinedon failure allows the main upload to proceed without a preview, which is appropriate graceful degradation.
228-260: LGTM! Well-structured async/sync bifurcation.The upload flow correctly handles both async (feature flag enabled) and non-async paths. The async path properly tracks downloads via
assetDownloadStoreand sets the appropriate processing status.src/stores/assetDownloadStore.ts (2)
31-36: LGTM! State management with proper cleanup mechanisms.The store correctly addresses previous memory leak concerns:
processedTaskIdsentries are cleaned up viasetTimeoutafterPROCESSED_TASK_CLEANUP_MS(lines 90-93, 104-107)completedDownloadsis capped byMAX_COMPLETED_DOWNLOADSwith FIFO trimming (lines 81-86)useEventListenerfrom VueUse provides automatic cleanup via the returned stop function
50-56: Deduplication logic handles race conditions well.The
processedTaskIdsSet with early return (lines 53-56) effectively prevents duplicate processing of completion/failure events. Combined with the delayed cleanup (lines 90-93, 104-107), this handles the race condition where completion events might arrive beforetrackDownload()is called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI Agents
In @src/stores/assetsStore.ts:
- Around line 366-368: The .then(() => provider.nodeDef.name) is unnecessary
because the returned value is unused; change the call to call
updateModelsForNodeType(provider.nodeDef.name) directly (remove the .then) so
the promise resolves to its original result that your error handling inspects
(e.g., result.status and result.reason) — locate the invocation of
updateModelsForNodeType and remove the trailing .then transformation referencing
provider.nodeDef.name.
- Around line 372-378: The log in the results loop only prints result.reason and
lacks which provider failed; modify the code that builds the refresh promises so
each settled result carries the provider name (e.g., use an array of { provider,
promise } or wrap each promise to resolve/reject with provider info), then in
the loop over results use result.reason and the associated provider (referencing
the same results variable and result.status/result.reason) to log a message like
"Failed to refresh model cache for provider <provider>: <reason>" so failures
are clearly attributed to the provider.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/stores/assetsStore.ts
🧰 Additional context used
📓 Path-based instructions (9)
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/stores/assetsStore.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/stores/assetsStore.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/stores/assetsStore.ts
src/**/stores/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores
Files:
src/stores/assetsStore.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/stores/assetsStore.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not useanytype oras anytype assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code
Files:
src/stores/assetsStore.ts
**/*Store.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name Pinia stores using the pattern
*Store.ts
Files:
src/stores/assetsStore.ts
**/*.{ts,tsx,vue,js,jsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width
Files:
src/stores/assetsStore.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Minimize the surface area (exported values) of each module and composable
Files:
src/stores/assetsStore.ts
🧠 Learnings (15)
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/stores/**/*.{ts,tsx} : Maintain clear public interfaces and restrict extension access in stores
Applied to files:
src/stores/assetsStore.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 ref/reactive for state management in Vue 3 Composition API
Applied to files:
src/stores/assetsStore.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 ref and reactive for reactive state
Applied to files:
src/stores/assetsStore.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/stores/assetsStore.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/stores/assetsStore.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().
Applied to files:
src/stores/assetsStore.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Prefer `computed()` over `ref` with `watch` when deriving values
Applied to files:
src/stores/assetsStore.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/stores/assetsStore.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/stores/assetsStore.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/stores/assetsStore.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement computed properties with computed()
Applied to files:
src/stores/assetsStore.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/stores/assetsStore.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/stores/assetsStore.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/stores/assetsStore.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/stores/assetsStore.ts
🧬 Code graph analysis (1)
src/stores/assetsStore.ts (1)
src/stores/modelToNodeStore.ts (1)
useModelToNodeStore(22-168)
⏰ 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: lint-and-format
- GitHub Check: test
- GitHub Check: collect
🔇 Additional comments (1)
src/stores/assetsStore.ts (1)
3-3: LGTM! Clean store integration.The imports and store initialization follow Vue 3 Composition API and Pinia best practices correctly.
Also applies to: 15-16, 98-99
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI Agents
In @tests-ui/tests/store/assetsStore.test.ts:
- Around line 18-20: The test setup contains unused API mocks apiURL,
addEventListener, and removeEventListener that are not referenced by assetsStore
(which uses api.getHistory(), api.internalURL(), and api.user); either remove
these three mocks from the test fixture to keep setup minimal, or add a short
comment above them explaining they are intentional placeholders for future
WebSocket/download features and add corresponding tests that assert their usage
if those features are implemented (refer to the mocks named apiURL,
addEventListener, removeEventListener and the store symbol assetsStore to locate
where to change).
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
tests-ui/tests/store/assetsStore.test.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not useanytype oras anytype assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code
Files:
tests-ui/tests/store/assetsStore.test.ts
**/*.{ts,tsx,vue,js,jsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width
Files:
tests-ui/tests/store/assetsStore.test.ts
**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
**/*.test.ts: Use unit/component tests intests-ui/orsrc/**/*.test.tswith Vitest framework
For mocking in tests, leverage Vitest utilities; keep module mocks contained and avoid global mutable state within test files
Do not write change detector tests or tests dependent on non-behavioral features like utility classes or styles
Aim for behavioral coverage of critical and new features in unit tests
Files:
tests-ui/tests/store/assetsStore.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Minimize the surface area (exported values) of each module and composable
Files:
tests-ui/tests/store/assetsStore.test.ts
🧠 Learnings (14)
📚 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/**/{services,composables}/**/*.{ts,tsx} : Use `api.fileURL()` for static file access instead of constructing URLs directly
Applied to files:
tests-ui/tests/store/assetsStore.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/**/{services,composables}/**/*.{ts,tsx} : Use `api.apiURL()` for backend endpoints instead of constructing URLs directly
Applied to files:
tests-ui/tests/store/assetsStore.test.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.test.ts : For mocking in tests, leverage Vitest utilities; keep module mocks contained and avoid global mutable state within test files
Applied to files:
tests-ui/tests/store/assetsStore.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} : Check assets/ directory for test data when writing tests
Applied to files:
tests-ui/tests/store/assetsStore.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/store/assetsStore.test.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/stores/**/*.{ts,tsx} : Maintain clear public interfaces and restrict extension access in stores
Applied to files:
tests-ui/tests/store/assetsStore.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
tests-ui/tests/store/assetsStore.test.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
tests-ui/tests/store/assetsStore.test.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
tests-ui/tests/store/assetsStore.test.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().
Applied to files:
tests-ui/tests/store/assetsStore.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.
Applied to files:
tests-ui/tests/store/assetsStore.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.
Applied to files:
tests-ui/tests/store/assetsStore.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
tests-ui/tests/store/assetsStore.test.ts
📚 Learning: 2025-12-22T21:36:38.905Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts:189-194
Timestamp: 2025-12-22T21:36:38.905Z
Learning: In tests-ui feature tests, do not stub primitive UI components or customized primitives (e.g., Button). Instead, import and register the real components in the test setup so tests reflect production behavior and component API usage. This improves test reliability and fidelity. If a test must avoid rendering the full component, justify the approach and consider higher-level mocks or integration tests rather than replacing the primitive itself.
Applied to files:
tests-ui/tests/store/assetsStore.test.ts
…handling - Update status terminology: 'pending' -> 'created' for consistency - Add periodic progress toasts (every 5s) during active downloads - Improve upload completion flow to show 'processing' state - Track downloads by task_id instead of prompt_id - Add asset_id to download tracking for future reference - Refine i18n strings for processing state 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Conditionally hide max file size message when async uploads enabled - Update button text to show "Close" for processing state vs "Finish" for completed - Improve clarity for users when download continues in background 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…rror handling - Add closable property to progress toasts so users can dismiss them - Add defensive checks to prevent duplicate task registrations - Ignore completion/failure messages for untracked tasks - Use Promise.allSettled for model cache refresh with error logging - Refactor event binding to use useEventListener composable - Call refreshModelCaches for synchronous upload paths 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add watcher in AssetBrowserModal to refresh assets when downloads finish - Fix upload wizard to only track async uploads that aren't already completed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove early return that skipped completion/failure events for untracked tasks - Add processedTaskIds set to deduplicate terminal events - Add teardown() method to properly remove event listener on unmount - Use strict equality operator in useUploadModelWizard
Previously assetDownloadStore directly called assetsStore methods, creating a dependency from lower-level to higher-level store. Now assetDownloadStore emits completedDownloads as a reactive signal, and assetsStore watches it to refresh model caches. This follows better separation of concerns and uses Vue's reactivity system. Also constrains completedDownloads array to max 10 items using FIFO eviction to prevent unbounded growth. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Changed condition to check uploadStatus != null before rendering - Removed non-null assertion operator from :result prop 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Document activeDownloads, pendingModelTypes, lastToastTime, processedTaskIds - Document trackDownload function with external usage note - Document handleAssetDownload function responsibilities - Standardize comment style to JSDoc format 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Filter providers where nodeDef?.name is falsy before accessing nodeDef.name - Remove unnecessary deep watch on completedDownloads array - Watch only the last item to automatically trigger on new downloads - Simplify logic by removing redundant Set tracking and cleanup code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add apiURL method to api mock - Add addEventListener and removeEventListener methods to api mock - Fixes TypeError: api.apiURL/addEventListener is not a function 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Rename watch callback params to currentlyActive/previouslyActive for clarity - Use safeParse instead of parse in uploadAssetAsync for better error handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
c699fb8 to
f45257c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🤖 Fix all issues with AI Agents
In @src/locales/en/main.json:
- Around line 2349-2353: The download messages are inconsistent:
"download.inProgress" uses {assetName} but "download.complete" and
"download.failed" don't; update the locale entries "download.complete" and
"download.failed" to include the {assetName} placeholder (e.g., "Download
complete: {assetName}" / "Download failed: {assetName}") so they match
"download.inProgress" and ensure translators/localization consumers are aware of
the new parameter.
In @src/platform/assets/components/UploadModelProgress.vue:
- Around line 12-29: Extract the duplicated preview card markup in
UploadModelProgress.vue into a reusable component (e.g., ModelPreviewCard) that
accepts props previewImage, metadata, and modelType and renders the image,
filename/name fallbacks, and model type; then replace the duplicated blocks (the
current markup using previewImage, metadata, and modelType at lines 12-29 and
41-59) with the new <ModelPreviewCard> and import/register it in
UploadModelProgress.vue so both the processing and success states reuse the
single component.
In @src/platform/assets/composables/useUploadModelWizard.ts:
- Line 39: The uploadStatus ref is declared without an initial value so its type
implicitly includes undefined; update the declaration for clarity by either
adding undefined to the union (e.g., Ref<'processing' | 'success' | 'error' |
undefined>) or by giving uploadStatus an explicit initial value ('processing' |
'success' | 'error') when calling ref(); modify the uploadStatus declaration in
useUploadModelWizard.ts to follow one of these patterns so the type contract is
explicit and predictable.
In @src/stores/assetDownloadStore.ts:
- Around line 10-19: The AssetDownload interface is duplicated; extract the
interface into a single shared types module (e.g. a new assetDownload types
module) and replace local declarations with an import of that shared
AssetDownload type in both assetDownloadStore and useAssetDownloadProgress (and
any other places using the same shape); update imports and remove the local
interface declarations so there is one source of truth for the AssetDownload
type.
In @src/stores/assetsStore.ts:
- Around line 366-368: Remove the unnecessary .then(() => provider.nodeDef.name)
wrapper around the promise returned by
updateModelsForNodeType(provider.nodeDef.name); instead return (or await)
updateModelsForNodeType(provider.nodeDef.name) directly so the resolved value
isn't overwritten with the provider name that isn't used—locate the call to
updateModelsForNodeType and eliminate the .then transformation.
- Around line 372-378: The error log inside the results loop lacks the failing
provider's identity; update the logging to include the provider name (e.g., from
result.reason.provider or result.reason.providerName or from whatever payload
you attached when creating the promise) so you get a message like "Failed to
refresh model cache for provider <providerName>: <error>". If the promises
passed into Promise.allSettled in this module (variables/results) don't
currently attach provider metadata on rejection, modify the code that creates
those promises to reject with an object containing { provider, error } (or
otherwise include provider in the resolved value), then change the loop logging
to reference result.reason.provider (or fallback to result.reason.providerName
or result.reason.message) alongside result.reason to provide clear provider
context.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (18)
src/composables/useFeatureFlags.tssrc/locales/en/main.jsonsrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/platform/remoteConfig/types.tssrc/schemas/apiSchema.tssrc/scripts/api.tssrc/stores/assetDownloadStore.tssrc/stores/assetsStore.test.tssrc/stores/assetsStore.tssrc/views/GraphView.vue
🧰 Additional context used
📓 Path-based instructions (16)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetsStore.test.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/platform/remoteConfig/types.tssrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/stores/assetsStore.test.tssrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetsStore.test.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetsStore.test.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not useanytype oras anytype assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code
Files:
src/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetsStore.test.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.ts
**/*.{ts,tsx,vue,js,jsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width
Files:
src/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetsStore.test.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/locales/en/main.jsonsrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Minimize the surface area (exported values) of each module and composable
Files:
src/platform/remoteConfig/types.tssrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/stores/assetsStore.test.tssrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.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/views/GraphView.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3.5+ with TypeScript in.vuefiles, exclusively using Composition API with<script setup lang="ts">syntax
Use Tailwind 4 for styling in Vue components; avoid<style>blocks
Name Vue components using PascalCase (e.g.,MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not usewithDefaultsor runtime props declaration
Prefercomputed()overrefwithwatchwhen deriving values
PreferuseModelover separately defining prop and emit for two-way binding
Usevue-i18nin composition API for string literals; place new translation entries insrc/locales/en/main.json
Usecn()utility function from@/utils/tailwindUtilfor merging Tailwind class names; do not use:class="[]"syntax
Do not use thedark:Tailwind variant; use semantic values from thestyle.csstheme instead (e.g.,bg-node-component-surface)
Do not use!importantor the!important prefix for Tailwind classes; find and correct interfering!importantclasses instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
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/views/GraphView.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
**/**/use[A-Z]*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables using the pattern
useXyz.ts
Files:
src/composables/useFeatureFlags.tssrc/platform/assets/composables/useUploadModelWizard.ts
src/**/stores/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores
Files:
src/stores/assetsStore.test.tssrc/stores/assetsStore.tssrc/stores/assetDownloadStore.ts
**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
**/*.test.ts: Use unit/component tests intests-ui/orsrc/**/*.test.tswith Vitest framework
For mocking in tests, leverage Vitest utilities; keep module mocks contained and avoid global mutable state within test files
Do not write change detector tests or tests dependent on non-behavioral features like utility classes or styles
Aim for behavioral coverage of critical and new features in unit tests
Files:
src/stores/assetsStore.test.ts
**/*Store.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name Pinia stores using the pattern
*Store.ts
Files:
src/stores/assetsStore.tssrc/stores/assetDownloadStore.ts
🧠 Learnings (55)
📓 Common learnings
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/composables/useUploadModelWizard.ts:207-219
Timestamp: 2026-01-06T19:17:04.618Z
Learning: In `src/platform/assets/composables/useUploadModelWizard.ts`, the `uploadModel()` function should have a concurrency guard at the beginning that checks if `isUploading.value` is already true and returns false early to prevent race conditions from multiple rapid invocations.
📚 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/remoteConfig/types.tssrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/stores/assetsStore.test.tssrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.
Applied to files:
src/platform/remoteConfig/types.tssrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/stores/assetsStore.test.tssrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).
Applied to files:
src/platform/remoteConfig/types.tssrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/stores/assetsStore.test.tssrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().
Applied to files:
src/platform/remoteConfig/types.tssrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/stores/assetsStore.test.tssrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.
Applied to files:
src/platform/remoteConfig/types.tssrc/views/GraphView.vuesrc/scripts/api.tssrc/composables/useFeatureFlags.tssrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/stores/assetsStore.test.tssrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/stores/assetsStore.tssrc/schemas/apiSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.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 setup() function for component logic
Applied to files:
src/views/GraphView.vuesrc/stores/assetDownloadStore.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/views/GraphView.vuesrc/stores/assetsStore.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.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/views/GraphView.vuesrc/stores/assetDownloadStore.ts
📚 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/views/GraphView.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.
Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.
Applied to files:
src/views/GraphView.vuesrc/platform/assets/components/AssetBrowserModal.vuesrc/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vue
📚 Learning: 2026-01-06T19:17:04.618Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/composables/useUploadModelWizard.ts:207-219
Timestamp: 2026-01-06T19:17:04.618Z
Learning: In `src/platform/assets/composables/useUploadModelWizard.ts`, the `uploadModel()` function should have a concurrency guard at the beginning that checks if `isUploading.value` is already true and returns false early to prevent race conditions from multiple rapid invocations.
Applied to files:
src/platform/assets/components/UploadModelFooter.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelUrlInput.vuesrc/platform/assets/schemas/assetSchema.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Prefer `useModel` over separately defining prop and emit for two-way binding
Applied to files:
src/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue InputSwitch component with ToggleSwitch
Applied to files:
src/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Steps component with Stepper without panels
Applied to files:
src/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue OverlayPanel component with Popover
Applied to files:
src/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue InlineMessage component with Message
Applied to files:
src/platform/assets/components/UploadModelDialog.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.test.ts : For mocking in tests, leverage Vitest utilities; keep module mocks contained and avoid global mutable state within test files
Applied to files:
src/stores/assetsStore.test.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/stores/**/*.{ts,tsx} : Maintain clear public interfaces and restrict extension access in stores
Applied to files:
src/stores/assetsStore.test.tssrc/stores/assetsStore.tssrc/stores/assetDownloadStore.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/**/{services,composables}/**/*.{ts,tsx} : Use `api.fileURL()` for static file access instead of constructing URLs directly
Applied to files:
src/stores/assetsStore.test.tssrc/platform/assets/services/assetService.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/**/{services,composables}/**/*.{ts,tsx} : Use `api.apiURL()` for backend endpoints instead of constructing URLs directly
Applied to files:
src/stores/assetsStore.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} : Check assets/ directory for test data when writing tests
Applied to files:
src/stores/assetsStore.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:
src/stores/assetsStore.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.
Applied to files:
src/stores/assetsStore.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.
Applied to files:
src/stores/assetsStore.test.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Use Vue 3.5+ with TypeScript in `.vue` files, exclusively using Composition API with `<script setup lang="ts">` syntax
Applied to files:
src/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/stores/assetDownloadStore.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Implement proper error handling in code
Applied to files:
src/platform/assets/components/UploadModelUrlInputCivitai.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/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead
Applied to files:
src/platform/assets/components/UploadModelUrlInputCivitai.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/stores/**/*.{ts,tsx} : Use TypeScript for type safety in state management stores
Applied to files:
src/stores/assetsStore.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.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 ref/reactive for state management in Vue 3 Composition API
Applied to files:
src/stores/assetsStore.tssrc/stores/assetDownloadStore.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 ref and reactive for reactive state
Applied to files:
src/stores/assetsStore.tssrc/stores/assetDownloadStore.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/stores/assetsStore.tssrc/stores/assetDownloadStore.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/stores/assetsStore.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Prefer `computed()` over `ref` with `watch` when deriving values
Applied to files:
src/stores/assetsStore.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/stores/assetsStore.tssrc/stores/assetDownloadStore.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/stores/assetsStore.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement computed properties with computed()
Applied to files:
src/stores/assetsStore.ts
📚 Learning: 2026-01-06T19:20:52.000Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/services/assetService.ts:484-491
Timestamp: 2026-01-06T19:20:52.000Z
Learning: In `src/platform/assets/services/assetService.ts`, prefer using `schema.safeParse()` over `schema.parse()` for validating API responses to avoid throwing ZodError with internal schema details; follow the existing pattern: call `safeParse()`, check `result.success`, and use `fromZodError(result.error)` to format error messages for logging while throwing user-friendly errors.
Applied to files:
src/schemas/apiSchema.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/stores/assetDownloadStore.tssrc/platform/assets/schemas/assetSchema.ts
📚 Learning: 2026-01-06T19:20:52.000Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/services/assetService.ts:484-491
Timestamp: 2026-01-06T19:20:52.000Z
Learning: In asset service files under src/platform/assets/services, prefer using schema.safeParse() over schema.parse() for API response validation. Follow the established pattern: call safeParse(), check result.success, and if failed, convert the error with fromZodError(result.error) for logging while throwing user-friendly errors that do not reveal internal schema details.
Applied to files:
src/platform/assets/services/assetService.ts
📚 Learning: 2025-12-12T23:02:37.473Z
Learnt from: Myestery
Repo: Comfy-Org/ComfyUI_frontend PR: 7422
File: .github/workflows/pr-update-playwright-expectations.yaml:131-135
Timestamp: 2025-12-12T23:02:37.473Z
Learning: In the `.github/workflows/pr-update-playwright-expectations.yaml` workflow in the Comfy-Org/ComfyUI_frontend repository, the snapshot update process is intentionally scoped to only add and update snapshot images. Deletions of snapshot files are handled explicitly outside this workflow and should not be suggested as part of this automation.
Applied to files:
src/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Do not use `any` type or `as any` type assertions; fix the underlying type issue instead
Applied to files:
src/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{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/platform/assets/composables/useUploadModelWizard.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*Store.ts : Name Pinia stores using the pattern `*Store.ts`
Applied to files:
src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-18T16:03:09.642Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:09.642Z
Learning: In the ComfyUI frontend queue system (src/stores/queueStore.ts), the `useQueuePendingTaskCountStore().count` includes the currently executing task. When count = 1, there is only the active/running task with no pending tasks. When count > 1, there is an active task plus pending tasks waiting in the queue. The "Clear Pending Tasks" button should only be enabled when count > 1 to avoid clearing the currently running task, which should be handled by the "Cancel current run" button instead.
Applied to files:
src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Applied to files:
src/stores/assetDownloadStore.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 lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Applied to files:
src/stores/assetDownloadStore.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/stores/assetDownloadStore.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/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement lifecycle hooks with onMounted, onUpdated, etc.
Applied to files:
src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
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
🧬 Code graph analysis (5)
src/scripts/api.ts (1)
src/schemas/apiSchema.ts (1)
AssetDownloadWsMessage(168-168)
src/composables/useFeatureFlags.ts (2)
src/platform/remoteConfig/remoteConfig.ts (1)
remoteConfig(22-22)src/scripts/api.ts (1)
api(1309-1309)
src/platform/assets/services/assetService.ts (2)
src/platform/assets/schemas/assetSchema.ts (2)
AsyncUploadResponse(89-89)asyncUploadResponseSchema(83-83)src/i18n.ts (1)
st(209-212)
src/platform/assets/composables/useUploadModelWizard.ts (1)
src/composables/useFeatureFlags.ts (1)
useFeatureFlags(24-95)
src/stores/assetDownloadStore.ts (3)
src/platform/updates/common/toastStore.ts (1)
useToastStore(8-39)src/schemas/apiSchema.ts (1)
AssetDownloadWsMessage(168-168)src/scripts/api.ts (1)
api(1309-1309)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: setup
- GitHub Check: test
- GitHub Check: lint-and-format
- GitHub Check: collect
| "download": { | ||
| "complete": "Download complete", | ||
| "failed": "Download failed", | ||
| "inProgress": "Downloading {assetName}..." | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider including asset name in complete/failed messages for consistency.
The inProgress message includes {assetName}, but complete and failed messages don't. This creates an inconsistency compared to the deletion messages above (lines 2345-2347), which include the asset name in all states.
Including the asset name in all download states would provide better user feedback, especially when multiple downloads are running simultaneously:
💡 Suggested improvement for consistency
"download": {
- "complete": "Download complete",
- "failed": "Download failed",
+ "complete": "{assetName} download complete",
+ "failed": "{assetName} download failed",
"inProgress": "Downloading {assetName}..."
},🤖 Prompt for AI Agents
In @src/locales/en/main.json around lines 2349 - 2353, The download messages are
inconsistent: "download.inProgress" uses {assetName} but "download.complete" and
"download.failed" don't; update the locale entries "download.complete" and
"download.failed" to include the {assetName} placeholder (e.g., "Download
complete: {assetName}" / "Download failed: {assetName}") so they match
"download.inProgress" and ensure translators/localization consumers are aware of
the new parameter.
| <div | ||
| class="flex flex-row items-center gap-3 p-4 bg-modal-card-background rounded-lg" | ||
| > | ||
| <img | ||
| v-if="previewImage" | ||
| :src="previewImage" | ||
| :alt="metadata?.filename || metadata?.name || 'Model preview'" | ||
| class="w-14 h-14 rounded object-cover flex-shrink-0" | ||
| /> | ||
| <div class="flex flex-col justify-center items-start gap-1 flex-1"> | ||
| <p class="text-base-foreground m-0"> | ||
| {{ metadata?.filename || metadata?.name }} | ||
| </p> | ||
| <p class="text-sm text-muted m-0"> | ||
| {{ modelType }} | ||
| </p> | ||
| </div> | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider extracting duplicated preview card markup.
The model preview card structure (image + metadata) is duplicated between the processing and success states. While functional, consider extracting this into a reusable component to follow DRY principles.
Also applies to: 41-59
🤖 Prompt for AI Agents
In @src/platform/assets/components/UploadModelProgress.vue around lines 12 - 29,
Extract the duplicated preview card markup in UploadModelProgress.vue into a
reusable component (e.g., ModelPreviewCard) that accepts props previewImage,
metadata, and modelType and renders the image, filename/name fallbacks, and
model type; then replace the duplicated blocks (the current markup using
previewImage, metadata, and modelType at lines 12-29 and 41-59) with the new
<ModelPreviewCard> and import/register it in UploadModelProgress.vue so both the
processing and success states reuse the single component.
| const isFetchingMetadata = ref(false) | ||
| const isUploading = ref(false) | ||
| const uploadStatus = ref<'idle' | 'uploading' | 'success' | 'error'>('idle') | ||
| const uploadStatus = ref<'processing' | 'success' | 'error'>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider explicit type contract for uploadStatus.
The uploadStatus ref lacks an initial value, making its type implicitly include undefined. Consider either:
- Adding
undefinedto the union type explicitly:Ref<'processing' | 'success' | 'error' | undefined> - Or providing an explicit initial value
This makes the type contract clearer and more maintainable.
🤖 Prompt for AI Agents
In @src/platform/assets/composables/useUploadModelWizard.ts at line 39, The
uploadStatus ref is declared without an initial value so its type implicitly
includes undefined; update the declaration for clarity by either adding
undefined to the union (e.g., Ref<'processing' | 'success' | 'error' |
undefined>) or by giving uploadStatus an explicit initial value ('processing' |
'success' | 'error') when calling ref(); modify the uploadStatus declaration in
useUploadModelWizard.ts to follow one of these patterns so the type contract is
explicit and predictable.
| interface AssetDownload { | ||
| taskId: string | ||
| assetId: string | ||
| assetName: string | ||
| bytesTotal: number | ||
| bytesDownloaded: number | ||
| progress: number | ||
| status: 'created' | 'running' | 'completed' | 'failed' | ||
| error?: string | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider consolidating duplicate interface.
The AssetDownload interface may be duplicated in other files (e.g., useAssetDownloadProgress.ts). Consider extracting to a shared types file (e.g., src/types/assetDownload.ts) to maintain a single source of truth.
🤖 Prompt for AI Agents
In @src/stores/assetDownloadStore.ts around lines 10 - 19, The AssetDownload
interface is duplicated; extract the interface into a single shared types module
(e.g. a new assetDownload types module) and replace local declarations with an
import of that shared AssetDownload type in both assetDownloadStore and
useAssetDownloadProgress (and any other places using the same shape); update
imports and remove the local interface declarations so there is one source of
truth for the AssetDownload type.
| updateModelsForNodeType(provider.nodeDef.name).then( | ||
| () => provider.nodeDef.name | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Remove unnecessary .then() transformation.
The .then(() => provider.nodeDef.name) transforms the promise to resolve to the provider name, but this value is never used—the error handling only checks result.status and result.reason.
🔎 Proposed simplification
const results = await Promise.allSettled(
- providers.map((provider) =>
- updateModelsForNodeType(provider.nodeDef.name).then(
- () => provider.nodeDef.name
- )
- )
+ providers.map((provider) => updateModelsForNodeType(provider.nodeDef.name))
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| updateModelsForNodeType(provider.nodeDef.name).then( | |
| () => provider.nodeDef.name | |
| ) | |
| const results = await Promise.allSettled( | |
| providers.map((provider) => updateModelsForNodeType(provider.nodeDef.name)) | |
| ) |
🤖 Prompt for AI Agents
In @src/stores/assetsStore.ts around lines 366 - 368, Remove the unnecessary
.then(() => provider.nodeDef.name) wrapper around the promise returned by
updateModelsForNodeType(provider.nodeDef.name); instead return (or await)
updateModelsForNodeType(provider.nodeDef.name) directly so the resolved value
isn't overwritten with the provider name that isn't used—locate the call to
updateModelsForNodeType and eliminate the .then transformation.
| for (const result of results) { | ||
| if (result.status === 'rejected') { | ||
| console.error( | ||
| `Failed to refresh model cache for provider: ${result.reason}` | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Improve error logging with provider context.
The error log includes result.reason but doesn't indicate which provider failed. Including the provider name would aid debugging when multiple providers are refreshed.
🔎 Proposed improvement
-for (const result of results) {
+for (let i = 0; i < results.length; i++) {
+ const result = results[i]
+ const providerName = providers[i].nodeDef.name
if (result.status === 'rejected') {
console.error(
- `Failed to refresh model cache for provider: ${result.reason}`
+ `Failed to refresh model cache for provider "${providerName}":`,
+ result.reason
)
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for (const result of results) { | |
| if (result.status === 'rejected') { | |
| console.error( | |
| `Failed to refresh model cache for provider: ${result.reason}` | |
| ) | |
| } | |
| } | |
| for (let i = 0; i < results.length; i++) { | |
| const result = results[i] | |
| const providerName = providers[i].nodeDef.name | |
| if (result.status === 'rejected') { | |
| console.error( | |
| `Failed to refresh model cache for provider "${providerName}":`, | |
| result.reason | |
| ) | |
| } | |
| } |
🤖 Prompt for AI Agents
In @src/stores/assetsStore.ts around lines 372 - 378, The error log inside the
results loop lacks the failing provider's identity; update the logging to
include the provider name (e.g., from result.reason.provider or
result.reason.providerName or from whatever payload you attached when creating
the promise) so you get a message like "Failed to refresh model cache for
provider <providerName>: <error>". If the promises passed into
Promise.allSettled in this module (variables/results) don't currently attach
provider metadata on rejection, modify the code that creates those promises to
reject with an object containing { provider, error } (or otherwise include
provider in the resolved value), then change the loop logging to reference
result.reason.provider (or fallback to result.reason.providerName or
result.reason.message) alongside result.reason to provide clear provider
context.
|
## Summary - Adds asynchronous model upload support with HTTP 202 responses - Implements WebSocket-based real-time download progress tracking via `asset_download` events - Creates `assetDownloadStore` for centralized download state management and toast notifications - Updates upload wizard UI to show "processing" state when downloads continue in background ## Changes - **Core**: New `assetDownloadStore` for managing async downloads with WebSocket events - **API**: Support for HTTP 202 async upload responses with task tracking - **UI**: Upload wizard now shows "processing" state and allows closing dialog during download - **Progress**: Periodic toast notifications (every 5s) during active downloads with completion/error toasts - **Schema**: Updated task statuses (`created`, `running`, `completed`, `failed`) and WebSocket message types ## Review Focus - WebSocket event handling and download state management in `assetDownloadStore` - Upload flow UX - users can now close the dialog and download continues in background - Toast notification frequency and timing - Schema alignment with backend async upload API Fixes #7748 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7746-feat-Add-async-model-upload-with-WebSocket-progress-tracking-2d36d73d3650811cb79ae06f470dcded) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: GitHub Action <action@github.com>
|
@luke-mino-altherr Successfully backported to #7887 |
…ogress tracking (#7887) Backport of #7746 to `cloud/1.36` Automatically created by backport workflow. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7887-backport-cloud-1-36-feat-Add-async-model-upload-with-WebSocket-progress-tracking-2e26d73d365081c4a060e6e88f33016d) by [Unito](https://www.unito.io) Co-authored-by: Luke Mino-Altherr <luke@comfy.org> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: GitHub Action <action@github.com>
Summary
asset_downloadeventsassetDownloadStorefor centralized download state management and toast notificationsChanges
assetDownloadStorefor managing async downloads with WebSocket eventscreated,running,completed,failed) and WebSocket message typesReview Focus
assetDownloadStoreFixes #7748
┆Issue is synchronized with this Notion page by Unito