// ======================================== // Model Card Component // ======================================== // Individual model display card with actions import { useState } from 'react'; import { useIntl } from 'react-intl'; import { Download, Trash2, Package, HardDrive, X, Loader2, } from 'lucide-react'; import { Card } from '@/components/ui/Card'; import { Button } from '@/components/ui/Button'; import { Badge } from '@/components/ui/Badge'; import { Progress } from '@/components/ui/Progress'; import { Input } from '@/components/ui/Input'; import type { CodexLensModel } from '@/lib/api'; import { cn } from '@/lib/utils'; // ========== Types ========== export interface ModelCardProps { model: CodexLensModel; isDownloading?: boolean; downloadProgress?: number; isDeleting?: boolean; onDownload: (profile: string) => void; onDelete: (profile: string) => void; onCancelDownload?: () => void; } // ========== Helper Functions ========== function getModelTypeVariant(type: 'embedding' | 'reranker'): 'default' | 'secondary' { return type === 'embedding' ? 'default' : 'secondary'; } function formatSize(size?: string): string { if (!size) return '-'; return size; } // ========== Component ========== export function ModelCard({ model, isDownloading = false, downloadProgress = 0, isDeleting = false, onDownload, onDelete, onCancelDownload, }: ModelCardProps) { const { formatMessage } = useIntl(); const handleDownload = () => { onDownload(model.profile); }; const handleDelete = () => { if (confirm(formatMessage({ id: 'codexlens.models.deleteConfirm' }, { modelName: model.name }))) { onDelete(model.profile); } }; return ( {/* Header */}
{model.installed ? ( ) : ( )}
{model.name} {model.type} {model.installed ? formatMessage({ id: 'codexlens.models.status.downloaded' }) : formatMessage({ id: 'codexlens.models.status.available' }) }
{model.dimensions && {model.dimensions}d} {formatSize(model.size)} {model.recommended && ( Rec )}
{model.description && (

{model.description}

)}
{/* Action Buttons */}
{isDownloading ? ( ) : model.installed ? ( ) : ( )}
{/* Download Progress */} {isDownloading && (
{formatMessage({ id: 'codexlens.models.downloading' })} {downloadProgress}%
)}
); } // ========== Custom Model Input ========== export interface CustomModelInputProps { isDownloading: boolean; onDownload: (modelName: string, modelType: 'embedding' | 'reranker') => void; } export function CustomModelInput({ isDownloading, onDownload }: CustomModelInputProps) { const { formatMessage } = useIntl(); const [modelName, setModelName] = useState(''); const [modelType, setModelType] = useState<'embedding' | 'reranker'>('embedding'); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (modelName.trim()) { onDownload(modelName.trim(), modelType); setModelName(''); } }; return (

{formatMessage({ id: 'codexlens.models.custom.title' })}

setModelName(e.target.value)} disabled={isDownloading} className="flex-1" />

{formatMessage({ id: 'codexlens.models.custom.description' })}

); } export default ModelCard;