-
Notifications
You must be signed in to change notification settings - Fork 448
feat: display and upload Civitai preview images in model upload flow #7274
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: display and upload Civitai preview images in model upload flow #7274
Conversation
📝 WalkthroughWalkthroughAdds optional preview-image support to the model upload flow: schema, wizard state, a base64 asset upload helper, preview upload and preview_id propagation during main asset upload, and UI components updated to accept and render the preview image. Changes
Sequence DiagramsequenceDiagram
participant UI as Upload Dialog UI
participant Wizard as useUploadModelWizard
participant Service as Asset Service
participant API as Backend API
UI->>Wizard: request metadata for model URL
Wizard->>API: GET /assets/metadata
API-->>Wizard: metadata (may include preview_image)
Wizard->>Wizard: store previewImage
alt preview_image present
Wizard->>Service: uploadAssetFromBase64(previewImage, name)
Service->>API: POST /assets (FormData with file)
API-->>Service: preview asset response (id)
Service-->>Wizard: preview_id
else no preview_image
Wizard->>Wizard: preview_id = null
end
Wizard->>Service: uploadAssetFromUrl(asset_url, preview_id?)
Service->>API: POST /assets (payload includes preview_id if set)
API-->>Service: asset response
Service-->>Wizard: upload result
Wizard-->>UI: update progress/state (include previewImage)
Possibly related PRs
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (6)
🧰 Additional context used📓 Path-based instructions (11)src/**/*.vue📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
src/**/*.{vue,ts}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
src/**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/**/{composables,components}/**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/**/*.{vue,ts,tsx}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/**/{components,composables}/**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
**/*.vue📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,js,jsx,vue,json}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (AGENTS.md)
Files:
src/**/*.ts📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
src/**/{services,composables}/**/*.{ts,tsx}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
🧠 Learnings (16)📚 Learning: 2025-12-09T03:49:52.828ZApplied to files:
📚 Learning: 2025-12-09T21:40:12.361ZApplied to files:
📚 Learning: 2025-12-09T03:39:54.501ZApplied to files:
📚 Learning: 2025-11-24T19:47:34.324ZApplied to files:
📚 Learning: 2025-11-24T19:47:34.324ZApplied to files:
📚 Learning: 2025-11-24T19:47:45.616ZApplied to files:
📚 Learning: 2025-11-24T19:47:02.860ZApplied to files:
📚 Learning: 2025-12-09T20:22:23.581ZApplied to files:
📚 Learning: 2025-11-24T19:47:45.616ZApplied to files:
📚 Learning: 2025-12-09T20:22:23.581ZApplied to files:
📚 Learning: 2025-11-24T19:47:02.860ZApplied to files:
📚 Learning: 2025-12-09T20:22:23.581ZApplied to files:
📚 Learning: 2025-12-09T20:22:23.581ZApplied to files:
📚 Learning: 2025-11-24T19:47:45.616ZApplied to files:
📚 Learning: 2025-11-24T19:47:02.860ZApplied to files:
📚 Learning: 2025-12-09T20:22:23.581ZApplied to files:
🧬 Code graph analysis (1)src/platform/assets/services/assetService.ts (2)
⏰ 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)
🔇 Additional comments (9)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 12/09/2025, 11:45:18 PM UTC 🔗 Links🎉 Your Storybook is ready for review! |
🎭 Playwright Test Results⏰ Completed at: 12/10/2025, 12:30:15 AM 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.22 MB (baseline 3.22 MB) • 🔴 +968 BMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 988 kB (baseline 988 kB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 1 added / 1 removed Panels & Settings — 298 kB (baseline 298 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 6 added / 6 removed UI Components — 178 kB (baseline 176 kB) • 🔴 +1.98 kBReusable component library chunks
Status: 6 added / 6 removed Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 2 added / 2 removed Utilities & Hooks — 3.18 kB (baseline 3.18 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 3.81 MB (baseline 3.81 MB) • ⚪ 0 BBundles that do not match a named category
Status: 17 added / 17 removed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/platform/assets/composables/useUploadModelWizard.ts (1)
138-165: Sequential preview → model upload flow is correct; consider two small refinementsThe sequencing and error handling look good:
- Preview is uploaded first when
wizardData.previewImageis present.- On success,
previewIdis captured and passed aspreview_idtouploadAssetFromUrl.- If preview upload fails, you log the error and still proceed with the model upload, which matches the non‑blocking requirement.
Two optional refinements to consider:
File name vs. content type
You always name the preview
${filename}_preview.png, even though the underlyingBlobMIME type comes from the data URL. If you care about extensions matching content, you could derive an extension fromwizardData.previewImage:const ext = wizardData.value.previewImage.startsWith('data:image/jpeg') ? 'jpg' : 'png' const previewName = `${filename}_preview.${ext}`Awareness of orphan previews
If the model upload fails after a successful preview upload, you’ll end up with an unreferenced preview asset. This is a reasonable tradeoff for now, but it’s worth being aware of in case you later add cleanup or retry logic.
Overall, the implementation meets the stated behavior.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
src/platform/assets/components/UploadModelConfirmation.vue(2 hunks)src/platform/assets/components/UploadModelDialog.vue(2 hunks)src/platform/assets/components/UploadModelProgress.vue(2 hunks)src/platform/assets/composables/useUploadModelWizard.ts(5 hunks)src/platform/assets/schemas/assetSchema.ts(1 hunks)src/platform/assets/services/assetService.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
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/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.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/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/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
src/**/*.{ts,tsx,vue}: Write expressive and self-documenting code to reduce the need for comments; clean redundant comments as you go
Consider if there is a simpler way to introduce functionality before writing code; choose the simpler approach when possible
Use refactoring to make complex code simpler
Keep functions short and functional
Minimize nesting in code (e.g.,if () { ... }orfor () { ... }) to avoid arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions (especially testable ones)
Watch out for code smells and refactor to avoid them
Implement proper error handling in code
If a complex type definition is inlined in multiple related places, extract and name it for reuse
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelDialog.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/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/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/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vue
**/*.{js,ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively (no new JavaScript)
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelDialog.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3 SFCs with Composition API only (.vuefiles)
Use Tailwind 4 styling and avoid<style>blocks in Vue components
Use<script setup lang="ts">for component logic in Vue components
Use Vue 3.5 TypeScript style of default prop declaration with reactive props destructuring
Do not usewithDefaultsor runtime props declaration in Vue components
PreferuseModelto separately defining a prop and emit in Vue components
Usereffor reactive state in Vue components
Implement computed properties withcomputed()instead of usingrefandwatch
UsewatchandwatchEffectfor side effects in Vue components
Useprovide/injectfor dependency injection only when simpler alternatives (Store or composable) are not suitable
Do not use thedark:Tailwind variant; use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Useimport { cn } from '@/utils/tailwindUtil'to merge class names instead of:class="[]"
Avoid new usage of PrimeVue components
Use VueUse functions for performance-enhancing styles in Vue components
Do not import Vue macros unnecessarily in components
Be judicious with addition of new refs or other state; prefer using props or composables when possible
Do not add acomputedif it's possible to use arefor prop directly
Do not use awatchif acomputedwould work instead
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/components/UploadModelDialog.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Do not useanytype in TypeScript code
Do not useas anytype assertions in TypeScript code; fix the underlying type issue
Style formatting: 2 space indent, single quotes, no trailing semicolons, 80 character width
Import statements should be sorted and grouped by plugin; runpnpm formatbefore committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/platform/assets/components/UploadModelDialog.vue
**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use vue-i18n in Composition API for string literals and place new translation entries in
src/locales/en/main.json
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.tssrc/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
src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions
Files:
src/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.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.ts
🧠 Learnings (2)
📚 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/UploadModelProgress.vuesrc/platform/assets/components/UploadModelConfirmation.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/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/services/assetService.ts
🧬 Code graph analysis (2)
src/platform/assets/composables/useUploadModelWizard.ts (1)
src/platform/assets/services/assetService.ts (1)
assetService(459-459)
src/platform/assets/services/assetService.ts (3)
src/platform/assets/schemas/assetSchema.ts (1)
AssetItem(74-74)src/scripts/api.ts (1)
api(1289-1289)src/i18n.ts (1)
st(208-210)
⏰ 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: test
- GitHub Check: setup
- GitHub Check: collect
🔇 Additional comments (3)
src/platform/assets/components/UploadModelDialog.vue (1)
17-18: Preview image wiring looks correct
wizardData.previewImageis correctly passed to both confirmation and progress steps viapreview-imageand matches the children’spreviewImage?: string | nullprops, so the data flow is sound.Also applies to: 27-28
src/platform/assets/schemas/assetSchema.ts (1)
49-59: Schema extension forpreview_imageis straightforward and type-safeAdding
preview_image: z.string().optional()cleanly extendsAssetMetadataand aligns with how the wizard consumes it as an optional string.If the backend spec guarantees this is always a data URL (vs. arbitrary string), it might be worth documenting that in a comment for future maintainers, but it’s not required for correctness.
src/platform/assets/composables/useUploadModelWizard.ts (1)
8-14: Wizard data and metadata mapping forpreviewImageare consistentAdding
previewImage: string | nulltoWizardData, initializing it tonull, and then assigningmetadata.preview_image || nullinfetchMetadatagives you a clean, well-typed flow from the backend schema into the wizard state. This also ensures old previews are cleared when new metadata lacks a preview.No issues here.
Also applies to: 28-34, 92-94
ddc1ff9 to
e05b960
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: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
src/platform/assets/components/UploadModelConfirmation.vue(2 hunks)src/platform/assets/components/UploadModelDialog.vue(2 hunks)src/platform/assets/components/UploadModelProgress.vue(2 hunks)src/platform/assets/composables/useUploadModelWizard.ts(5 hunks)src/platform/assets/schemas/assetSchema.ts(1 hunks)src/platform/assets/services/assetService.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
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/UploadModelProgress.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.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/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/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
src/**/*.{ts,tsx,vue}: Write expressive and self-documenting code to reduce the need for comments; clean redundant comments as you go
Consider if there is a simpler way to introduce functionality before writing code; choose the simpler approach when possible
Use refactoring to make complex code simpler
Keep functions short and functional
Minimize nesting in code (e.g.,if () { ... }orfor () { ... }) to avoid arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions (especially testable ones)
Watch out for code smells and refactor to avoid them
Implement proper error handling in code
If a complex type definition is inlined in multiple related places, extract and name it for reuse
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/schemas/assetSchema.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/UploadModelProgress.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/schemas/assetSchema.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
**/*.{js,ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively (no new JavaScript)
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/schemas/assetSchema.ts
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3 SFCs with Composition API only (.vuefiles)
Use Tailwind 4 styling and avoid<style>blocks in Vue components
Use<script setup lang="ts">for component logic in Vue components
Use Vue 3.5 TypeScript style of default prop declaration with reactive props destructuring
Do not usewithDefaultsor runtime props declaration in Vue components
PreferuseModelto separately defining a prop and emit in Vue components
Usereffor reactive state in Vue components
Implement computed properties withcomputed()instead of usingrefandwatch
UsewatchandwatchEffectfor side effects in Vue components
Useprovide/injectfor dependency injection only when simpler alternatives (Store or composable) are not suitable
Do not use thedark:Tailwind variant; use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Useimport { cn } from '@/utils/tailwindUtil'to merge class names instead of:class="[]"
Avoid new usage of PrimeVue components
Use VueUse functions for performance-enhancing styles in Vue components
Do not import Vue macros unnecessarily in components
Be judicious with addition of new refs or other state; prefer using props or composables when possible
Do not add acomputedif it's possible to use arefor prop directly
Do not use awatchif acomputedwould work instead
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Do not useanytype in TypeScript code
Do not useas anytype assertions in TypeScript code; fix the underlying type issue
Style formatting: 2 space indent, single quotes, no trailing semicolons, 80 character width
Import statements should be sorted and grouped by plugin; runpnpm formatbefore committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vuesrc/platform/assets/schemas/assetSchema.ts
**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use vue-i18n in Composition API for string literals and place new translation entries in
src/locales/en/main.json
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.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
src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions
Files:
src/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.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/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.ts
🧠 Learnings (4)
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Implement proper props and emits definitions in Vue components
Applied to files:
src/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/UploadModelProgress.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.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/platform/assets/services/assetService.tssrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/schemas/assetSchema.ts
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Prefer `useModel` to separately defining a prop and emit in Vue components
Applied to files:
src/platform/assets/components/UploadModelConfirmation.vue
🧬 Code graph analysis (2)
src/platform/assets/services/assetService.ts (2)
src/platform/assets/schemas/assetSchema.ts (1)
AssetItem(74-74)src/scripts/api.ts (1)
api(1289-1289)
src/platform/assets/composables/useUploadModelWizard.ts (1)
src/platform/assets/services/assetService.ts (1)
assetService(463-463)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: setup
- GitHub Check: collect
- GitHub Check: lint-and-format
- GitHub Check: test
🔇 Additional comments (11)
src/platform/assets/components/UploadModelConfirmation.vue (2)
7-19: Preview image rendering looks good with proper accessibility.The conditional rendering and alt text fallback are implemented correctly. The 56×56px preview with
object-coverprovides consistent visual presentation.One consideration: the
previewImageis a base64 data URL sourced from Civitai metadata. While this is a trusted source in the current flow, ensure the data URL is validated upstream (in the composable or service) to contain only expected image MIME types (data:image/png;base64,or similar) to prevent potential XSS if the source changes in the future.
51-54: Props definition follows Vue 3.5 conventions.The optional
previewImageprop is correctly typed asstring | nulland uses the modern TypeScript-first prop declaration style.src/platform/assets/components/UploadModelDialog.vue (2)
17-17: Preview image prop correctly wired to confirmation step.The binding
wizardData.previewImageis correctly passed to the child component.
27-27: Preview image prop correctly wired to progress step.Consistent with the confirmation step, the preview image is passed through to display in the success state.
src/platform/assets/schemas/assetSchema.ts (1)
57-57: Schema extension is correct and follows existing patterns.The
preview_imagefield uses the samez.string().optional()pattern as other optional fields in the schema. This correctly extendsAssetMetadatato include the base64 preview image data.src/platform/assets/components/UploadModelProgress.vue (2)
27-45: Success state preview rendering is well-implemented.The preview image block integrates cleanly with the existing success state layout. The
flex-row items-center gap-3alignment ensures proper visual flow when the image is present, and the conditionalv-if="previewImage"correctly handles the absent-image case without layout issues.
69-75: Props definition is correct and complete.All props are properly typed, and the optional
previewImagefollows the same pattern as the confirmation component.src/platform/assets/composables/useUploadModelWizard.ts (3)
10-16: WizardData interface correctly extended with preview image field.The
previewImage: string | nulltype aligns with how it's used throughout the wizard flow.
96-98: Preview image storage from metadata is correct.The nullish coalescing to
nullensures consistent typing whenpreview_imageis undefined.
159-169: Model upload correctly includes optional preview_id.The
preview_idis only included when the preview upload succeeds, which maintains backward compatibility with the API when no preview is available.src/platform/assets/services/assetService.ts (1)
458-459: Exporting uploadAssetFromBase64 from the asset service looks correctIncluding
uploadAssetFromBase64alongsideuploadAssetFromUrlin the returned service object is consistent with the existing API surface and enables clean consumption from composables.
| async function uploadAssetFromBase64(params: { | ||
| data: string | ||
| name: string | ||
| tags?: string[] | ||
| user_metadata?: Record<string, any> | ||
| }): Promise<AssetItem & { created_new: boolean }> { | ||
| // Validate that data is a data URL | ||
| if (!params.data || !params.data.startsWith('data:')) { | ||
| throw new Error( | ||
| 'Invalid data URL: expected a string starting with "data:"' | ||
| ) | ||
| } | ||
|
|
||
| // Convert base64 data URL to Blob | ||
| const blob = await fetch(params.data).then((r) => r.blob()) | ||
|
|
||
| // Create FormData and append the blob | ||
| const formData = new FormData() | ||
| formData.append('file', blob, params.name) | ||
|
|
||
| if (params.tags) { | ||
| formData.append('tags', JSON.stringify(params.tags)) | ||
| } | ||
|
|
||
| if (params.user_metadata) { | ||
| formData.append('user_metadata', JSON.stringify(params.user_metadata)) | ||
| } | ||
|
|
||
| const res = await api.fetchApi(ASSETS_ENDPOINT, { | ||
| method: 'POST', | ||
| body: formData | ||
| }) | ||
|
|
||
| if (!res.ok) { | ||
| throw new Error( | ||
| `Failed to upload asset from base64: ${res.status} ${res.statusText}` | ||
| ) | ||
| } | ||
|
|
||
| return await res.json() | ||
| } |
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
uploadAssetFromBase64 implementation is solid; align error handling & i18n with uploadAssetFromUrl
The data URL guard, Blob conversion, and FormData upload look correct. To keep UX and localization consistent with uploadAssetFromUrl, consider reusing the same localized error message (assetBrowser.errorUploadFailed) instead of hard-coded English strings and interpolated status text:
async function uploadAssetFromBase64(params: {
data: string
name: string
tags?: string[]
user_metadata?: Record<string, any>
}): Promise<AssetItem & { created_new: boolean }> {
- // Validate that data is a data URL
- if (!params.data || !params.data.startsWith('data:')) {
- throw new Error(
- 'Invalid data URL: expected a string starting with "data:"'
- )
- }
+ // Validate that data is a data URL
+ if (!params.data || !params.data.startsWith('data:')) {
+ throw new Error(
+ st(
+ 'assetBrowser.errorUploadFailed',
+ 'Failed to upload asset. Please try again.'
+ )
+ )
+ }
@@
- const res = await api.fetchApi(ASSETS_ENDPOINT, {
+ const res = await api.fetchApi(ASSETS_ENDPOINT, {
method: 'POST',
body: formData
})
- if (!res.ok) {
- throw new Error(
- `Failed to upload asset from base64: ${res.status} ${res.statusText}`
- )
- }
+ if (!res.ok) {
+ throw new Error(
+ st(
+ 'assetBrowser.errorUploadFailed',
+ 'Failed to upload asset. Please try again.'
+ )
+ )
+ }
return await res.json()
}This keeps failure behavior consistent across both upload paths and avoids leaking raw status text to end users while respecting the existing i18n pattern.
📝 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 uploadAssetFromBase64(params: { | |
| data: string | |
| name: string | |
| tags?: string[] | |
| user_metadata?: Record<string, any> | |
| }): Promise<AssetItem & { created_new: boolean }> { | |
| // Validate that data is a data URL | |
| if (!params.data || !params.data.startsWith('data:')) { | |
| throw new Error( | |
| 'Invalid data URL: expected a string starting with "data:"' | |
| ) | |
| } | |
| // Convert base64 data URL to Blob | |
| const blob = await fetch(params.data).then((r) => r.blob()) | |
| // Create FormData and append the blob | |
| const formData = new FormData() | |
| formData.append('file', blob, params.name) | |
| if (params.tags) { | |
| formData.append('tags', JSON.stringify(params.tags)) | |
| } | |
| if (params.user_metadata) { | |
| formData.append('user_metadata', JSON.stringify(params.user_metadata)) | |
| } | |
| const res = await api.fetchApi(ASSETS_ENDPOINT, { | |
| method: 'POST', | |
| body: formData | |
| }) | |
| if (!res.ok) { | |
| throw new Error( | |
| `Failed to upload asset from base64: ${res.status} ${res.statusText}` | |
| ) | |
| } | |
| return await res.json() | |
| } | |
| async function uploadAssetFromBase64(params: { | |
| data: string | |
| name: string | |
| tags?: string[] | |
| user_metadata?: Record<string, any> | |
| }): Promise<AssetItem & { created_new: boolean }> { | |
| // Validate that data is a data URL | |
| if (!params.data || !params.data.startsWith('data:')) { | |
| throw new Error( | |
| st( | |
| 'assetBrowser.errorUploadFailed', | |
| 'Failed to upload asset. Please try again.' | |
| ) | |
| ) | |
| } | |
| // Convert base64 data URL to Blob | |
| const blob = await fetch(params.data).then((r) => r.blob()) | |
| // Create FormData and append the blob | |
| const formData = new FormData() | |
| formData.append('file', blob, params.name) | |
| if (params.tags) { | |
| formData.append('tags', JSON.stringify(params.tags)) | |
| } | |
| if (params.user_metadata) { | |
| formData.append('user_metadata', JSON.stringify(params.user_metadata)) | |
| } | |
| const res = await api.fetchApi(ASSETS_ENDPOINT, { | |
| method: 'POST', | |
| body: formData | |
| }) | |
| if (!res.ok) { | |
| throw new Error( | |
| st( | |
| 'assetBrowser.errorUploadFailed', | |
| 'Failed to upload asset. Please try again.' | |
| ) | |
| ) | |
| } | |
| return await res.json() | |
| } |
🤖 Prompt for AI Agents
In src/platform/assets/services/assetService.ts around lines 406 to 446, replace
the hard-coded English error thrown on upload failure with the existing i18n
error used by uploadAssetFromUrl (assetBrowser.errorUploadFailed) so user-facing
messages are localized and consistent; do not surface raw HTTP statusText to end
users — if you need the status for diagnostics, include it in a debug/process
log or attach it to an internal error property but throw the localized message
to callers.
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.
these are internal facing errors. The current error messages give us more detail about what actually went wrong
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.
@luke-mino-altherr Understood! That makes sense for internal tooling—keeping the detailed status information (${res.status} ${res.statusText}) is valuable for debugging. I'll leave the error messages as-is. 👍
🧠 Learnings used
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: User-friendly and actionable error messages in error handling
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
♻️ Duplicate comments (1)
src/platform/assets/composables/useUploadModelWizard.ts (1)
142-158: Preview upload has good error resilience, but hardcodes PNG extension.The try-catch pattern that logs and continues on preview failure is appropriate—model upload shouldn't be blocked by preview issues.
However, the filename at line 150 still hardcodes
.pngregardless of the actual image format in the base64 data. As previously noted, this can cause MIME type mismatches if Civitai returns JPEG or WebP previews.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/platform/assets/composables/useUploadModelWizard.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
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/assets/composables/useUploadModelWizard.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions
Files:
src/platform/assets/composables/useUploadModelWizard.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.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
src/**/*.{ts,tsx,vue}: Write expressive and self-documenting code to reduce the need for comments; clean redundant comments as you go
Consider if there is a simpler way to introduce functionality before writing code; choose the simpler approach when possible
Use refactoring to make complex code simpler
Keep functions short and functional
Minimize nesting in code (e.g.,if () { ... }orfor () { ... }) to avoid arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions (especially testable ones)
Watch out for code smells and refactor to avoid them
Implement proper error handling in code
If a complex type definition is inlined in multiple related places, extract and name it for reuse
Files:
src/platform/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/composables/useUploadModelWizard.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/platform/assets/composables/useUploadModelWizard.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/platform/assets/composables/useUploadModelWizard.ts
**/*.{js,ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively (no new JavaScript)
Files:
src/platform/assets/composables/useUploadModelWizard.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Do not useanytype in TypeScript code
Do not useas anytype assertions in TypeScript code; fix the underlying type issue
Style formatting: 2 space indent, single quotes, no trailing semicolons, 80 character width
Import statements should be sorted and grouped by plugin; runpnpm formatbefore committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates
Files:
src/platform/assets/composables/useUploadModelWizard.ts
**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use vue-i18n in Composition API for string literals and place new translation entries in
src/locales/en/main.json
Files:
src/platform/assets/composables/useUploadModelWizard.ts
🧠 Learnings (1)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/platform/assets/composables/useUploadModelWizard.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: setup
- GitHub Check: collect
- GitHub Check: lint-and-format
- GitHub Check: test
🔇 Additional comments (4)
src/platform/assets/composables/useUploadModelWizard.ts (4)
15-15: LGTM! Clean type definition for preview image.The nullable string type appropriately handles the optional nature of preview images.
36-37: LGTM! Proper initialization.The previewImage field is correctly initialized to null, consistent with the interface definition.
96-97: LGTM! Clean metadata extraction.The preview image is correctly extracted from metadata with proper null handling.
168-169: LGTM! Clean integration of preview_id.The preview_id is correctly passed to the upload call, with proper handling of the undefined case when no preview exists.
| // Upload preview image first if available | ||
| if (wizardData.value.previewImage) { | ||
| try { | ||
| const baseFilename = filename.split('.')[0] |
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 more robust extension stripping.
split('.')[0] only captures text before the first dot, so my.model.safetensors becomes my. Consider using filename.replace(/\.[^.]+$/, '') or finding the last dot index to preserve the full base name.
Apply this diff to improve base filename extraction:
- const baseFilename = filename.split('.')[0]
+ const lastDotIndex = filename.lastIndexOf('.')
+ const baseFilename = lastDotIndex !== -1 ? filename.slice(0, lastDotIndex) : filename📝 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.
| const baseFilename = filename.split('.')[0] | |
| const lastDotIndex = filename.lastIndexOf('.') | |
| const baseFilename = lastDotIndex !== -1 ? filename.slice(0, lastDotIndex) : filename |
🤖 Prompt for AI Agents
In src/platform/assets/composables/useUploadModelWizard.ts around line 147, the
current extraction const baseFilename = filename.split('.')[0] only keeps text
before the first dot and breaks names like "my.model.safetensors"; replace it
with a robust method such as using filename.replace(/\.[^.]+$/, '') or using
lastDot = filename.lastIndexOf('.') and taking filename.substring(0, lastDot ===
-1 ? filename.length : lastDot) so the full base name is preserved while still
stripping only the final extension.
8c8e6cb to
0104dbc
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: 2
♻️ Duplicate comments (2)
src/platform/assets/services/assetService.ts (1)
395-446: Base64 upload helper is solid; align errors with existing i18n patternThe
uploadAssetFromBase64flow looks correct: guarding fordata:URLs, converting to aBlob, sending viaFormData, and reusing the existing endpoint.To stay consistent with
uploadAssetFromUrland the i18n guidelines, consider:
- Using the same localized failure message for non-OK responses:
if (!res.ok) { throw new Error( st( 'assetBrowser.errorUploadFailed', 'Failed to upload asset. Please try again.' ) ) }
- Similarly, for the invalid
dataguard, either:
- Throw the same localized upload-failed message, or
- Throw a more internal-facing error but ensure callers don’t surface it directly to users.
This keeps future callers of
uploadAssetFromBase64from accidentally exposing raw technical or HTTP status text to end users.Also applies to: 458-459
src/platform/assets/composables/useUploadModelWizard.ts (1)
15-16: Preview-first upload flow is correct; consider more robust base filename extractionThe wizard changes look good overall:
previewImageis correctly carried inWizardDataand populated frommetadata.preview_image.- The upload sequence sensibly uploads the preview first, captures
previewId, and then includespreview_idin the mainuploadAssetFromUrlcall.- Failure to upload the preview is handled gracefully in a
try/catchwithout blocking the main model upload.One small refinement:
const baseFilename = filename.split('.')[0]will truncate names with multiple dots (e.g.'my.model.safetensors'→'my'). Using the last dot is more robust, e.g.:const lastDotIndex = filename.lastIndexOf('.') const baseFilename = lastDotIndex !== -1 ? filename.slice(0, lastDotIndex) : filenameso the generated preview name preserves the full base model name.
Also applies to: 32-38, 96-98, 142-180
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
src/platform/assets/components/UploadModelConfirmation.vue(2 hunks)src/platform/assets/components/UploadModelDialog.vue(2 hunks)src/platform/assets/components/UploadModelProgress.vue(2 hunks)src/platform/assets/composables/useUploadModelWizard.ts(5 hunks)src/platform/assets/schemas/assetSchema.ts(1 hunks)src/platform/assets/services/assetService.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/platform/assets/services/assetService.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions
Files:
src/platform/assets/services/assetService.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/composables/useUploadModelWizard.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/services/assetService.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
src/**/*.{ts,tsx,vue}: Write expressive and self-documenting code to reduce the need for comments; clean redundant comments as you go
Consider if there is a simpler way to introduce functionality before writing code; choose the simpler approach when possible
Use refactoring to make complex code simpler
Keep functions short and functional
Minimize nesting in code (e.g.,if () { ... }orfor () { ... }) to avoid arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions (especially testable ones)
Watch out for code smells and refactor to avoid them
Implement proper error handling in code
If a complex type definition is inlined in multiple related places, extract and name it for reuse
Files:
src/platform/assets/services/assetService.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/platform/assets/services/assetService.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
**/*.{js,ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively (no new JavaScript)
Files:
src/platform/assets/services/assetService.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Do not useanytype in TypeScript code
Do not useas anytype assertions in TypeScript code; fix the underlying type issue
Style formatting: 2 space indent, single quotes, no trailing semicolons, 80 character width
Import statements should be sorted and grouped by plugin; runpnpm formatbefore committing
ESLint rules: no floating promises, no unused imports, i18n raw text restrictions in templates
Files:
src/platform/assets/services/assetService.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use vue-i18n in Composition API for string literals and place new translation entries in
src/locales/en/main.json
Files:
src/platform/assets/services/assetService.tssrc/platform/assets/schemas/assetSchema.tssrc/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.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/UploadModelProgress.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.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/UploadModelProgress.vuesrc/platform/assets/composables/useUploadModelWizard.tssrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3 SFCs with Composition API only (.vuefiles)
Use Tailwind 4 styling and avoid<style>blocks in Vue components
Use<script setup lang="ts">for component logic in Vue components
Use Vue 3.5 TypeScript style of default prop declaration with reactive props destructuring
Do not usewithDefaultsor runtime props declaration in Vue components
PreferuseModelto separately defining a prop and emit in Vue components
Usereffor reactive state in Vue components
Implement computed properties withcomputed()instead of usingrefandwatch
UsewatchandwatchEffectfor side effects in Vue components
Useprovide/injectfor dependency injection only when simpler alternatives (Store or composable) are not suitable
Do not use thedark:Tailwind variant; use semantic values fromstyle.csstheme instead (e.g.,bg-node-component-surface)
Useimport { cn } from '@/utils/tailwindUtil'to merge class names instead of:class="[]"
Avoid new usage of PrimeVue components
Use VueUse functions for performance-enhancing styles in Vue components
Do not import Vue macros unnecessarily in components
Be judicious with addition of new refs or other state; prefer using props or composables when possible
Do not add acomputedif it's possible to use arefor prop directly
Do not use awatchif acomputedwould work instead
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/platform/assets/components/UploadModelProgress.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
🧠 Learnings (5)
📚 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/platform/assets/services/assetService.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.
Applied to files:
src/platform/assets/services/assetService.tssrc/platform/assets/schemas/assetSchema.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 : Define proper props and emits definitions in Vue components
Applied to files:
src/platform/assets/components/UploadModelProgress.vue
📚 Learning: 2025-12-09T02:44:38.234Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-09T02:44:38.234Z
Learning: Applies to **/*.vue : Implement proper props and emits definitions in Vue components
Applied to files:
src/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/UploadModelProgress.vuesrc/platform/assets/components/UploadModelDialog.vuesrc/platform/assets/components/UploadModelConfirmation.vue
🧬 Code graph analysis (2)
src/platform/assets/services/assetService.ts (2)
src/platform/assets/schemas/assetSchema.ts (1)
AssetItem(74-74)src/scripts/api.ts (1)
api(1289-1289)
src/platform/assets/composables/useUploadModelWizard.ts (1)
src/platform/assets/services/assetService.ts (1)
assetService(463-463)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: deploy-and-comment
- GitHub Check: setup
- GitHub Check: test
- GitHub Check: lint-and-format
- GitHub Check: collect
🔇 Additional comments (2)
src/platform/assets/schemas/assetSchema.ts (1)
49-58: AssetMetadata preview_image field is consistent with usageAdding
preview_image: z.string().optional()cleanly models the new metadata field and aligns with how it’s consumed in the wizard (metadata.preview_image || null).src/platform/assets/components/UploadModelDialog.vue (1)
13-28: Forwarding previewImage through dialog steps is correctBinding
wizardData.previewImageinto bothUploadModelConfirmationandUploadModelProgressviapreview-imagecleanly propagates the preview data without affecting existing behavior.
| <div | ||
| class="flex items-center gap-3 bg-secondary-background p-3 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" | ||
| /> | ||
| <p class="m-0 text-base-foreground"> | ||
| {{ metadata?.filename || metadata?.name }} | ||
| </p> | ||
| </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.
Preview thumbnail wiring looks good; localize fallback alt text
The preview block and previewImage prop are correctly integrated and handle the optional image well. To comply with the i18n guidelines, consider replacing the hard-coded 'Model preview' fallback in the alt binding with a localized string, e.g.:
:alt="
metadata?.filename ||
metadata?.name ||
$t('assetBrowser.modelPreviewAlt', 'Model preview')
"and add assetBrowser.modelPreviewAlt to src/locales/en/main.json.
Also applies to: 51-54
🤖 Prompt for AI Agents
In src/platform/assets/components/UploadModelConfirmation.vue around lines 7-19
(and similarly at lines 51-54), replace the hard-coded fallback alt text 'Model
preview' with a localized lookup using $t('assetBrowser.modelPreviewAlt', 'Model
preview') so the alt binding becomes: metadata?.filename || metadata?.name ||
$t('assetBrowser.modelPreviewAlt', 'Model preview'); then add the key
"assetBrowser.modelPreviewAlt": "Model preview" to src/locales/en/main.json to
provide the English default.
| 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" | ||
| /> |
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.
Success preview behavior is good; localize alt fallback
The success-state preview image is correctly wired and optional, and the new previewImage prop is well-scoped. As in the confirmation step, the hard-coded 'Model preview' fallback in the alt binding should be localized, for example:
:alt="
metadata?.filename ||
metadata?.name ||
$t('assetBrowser.modelPreviewAlt', 'Model preview')
"with assetBrowser.modelPreviewAlt added to src/locales/en/main.json.
Also applies to: 69-75
🤖 Prompt for AI Agents
In src/platform/assets/components/UploadModelProgress.vue around lines 28-35
(and also update the similar occurrence around lines 69-75), the img alt binding
currently falls back to the hard-coded string 'Model preview'; replace that
literal with a localized fallback using the translation helper, e.g.
:alt="metadata?.filename || metadata?.name || $t('assetBrowser.modelPreviewAlt',
'Model preview')", and add the key "assetBrowser.modelPreviewAlt": "Model
preview" to src/locales/en/main.json so the fallback is localized.
| <div | ||
| class="flex items-center gap-3 bg-secondary-background p-3 rounded-lg" | ||
| > | ||
| <img |
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.
If you want a stretch goal: https://vueuse.org/core/useImage/#component-usage
| error?: string | ||
| metadata: AssetMetadata | null | ||
| modelType: string | undefined | ||
| previewImage?: string | null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| previewImage?: string | null | |
| previewImage?: 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.
For all of these, I think we should have a single "absent" value.
bce3934 to
5774a90
Compare
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Add descriptive alt text to preview images in UploadModelConfirmation and UploadModelProgress components - Add data URL validation in uploadAssetFromBase64 to fail fast with descriptive error - Replace generic localized errors with specific technical error messages for better debugging 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Prevents double extensions like "model.safetensors_preview.png" by extracting the base filename before appending "_preview.png" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Replace `null` types with optional `undefined` types in upload model wizard for consistency with TypeScript best practices. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
5774a90 to
3db5fff
Compare
…7274) ## Summary Stores and displays base64-encoded preview images from Civitai during the model upload flow, uploading the preview as a separate asset linked to the model. ## Changes - **Schema**: Added `preview_image` field to `AssetMetadata` schema - **Service**: Added `uploadAssetFromBase64` method to convert base64 data to blob and upload via FormData - **Upload Flow**: Modified wizard to first upload preview image as asset, then link it to model via `preview_id` - **UI**: Display 56x56px preview thumbnail alongside model filename in confirmation and success steps ## Review Focus - Base64 to blob conversion and FormData upload implementation - Sequential upload flow (preview first, then model with preview_id reference) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7274-feat-display-and-upload-Civitai-preview-images-in-model-upload-flow-2c46d73d365081ff9b74c1791d23f6dd) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude <[email protected]>
|
@luke-mino-altherr Successfully backported to #7301 |
…omfy-Org#7274) ## Summary Stores and displays base64-encoded preview images from Civitai during the model upload flow, uploading the preview as a separate asset linked to the model. ## Changes - **Schema**: Added `preview_image` field to `AssetMetadata` schema - **Service**: Added `uploadAssetFromBase64` method to convert base64 data to blob and upload via FormData - **Upload Flow**: Modified wizard to first upload preview image as asset, then link it to model via `preview_id` - **UI**: Display 56x56px preview thumbnail alongside model filename in confirmation and success steps ## Review Focus - Base64 to blob conversion and FormData upload implementation - Sequential upload flow (preview first, then model with preview_id reference) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7274-feat-display-and-upload-Civitai-preview-images-in-model-upload-flow-2c46d73d365081ff9b74c1791d23f6dd) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude <[email protected]>
… in model upload flow (#7301) Backport of #7274 to `cloud/1.34` Automatically created by backport workflow. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7301-backport-cloud-1-34-feat-display-and-upload-Civitai-preview-images-in-model-upload-flo-2c56d73d3650814caedbc0b64480cb9c) by [Unito](https://www.unito.io) Co-authored-by: Luke Mino-Altherr <[email protected]> Co-authored-by: Claude <[email protected]>
Summary
Stores and displays base64-encoded preview images from Civitai during the model upload flow, uploading the preview as a separate asset linked to the model.
Changes
preview_imagefield toAssetMetadataschemauploadAssetFromBase64method to convert base64 data to blob and upload via FormDatapreview_idReview Focus
┆Issue is synchronized with this Notion page by Unito