// ======================================== // InsightDetailPanel Component // ======================================== // Display detailed view of a single insight with patterns, suggestions, and metadata import { useIntl } from 'react-intl'; import { cn } from '@/lib/utils'; import { X, Sparkles, Bot, Code2, Cpu, Trash2, AlertTriangle, Lightbulb, Clock, FileText, } from 'lucide-react'; import type { InsightHistory, Pattern, Suggestion } from '@/lib/api'; import { Button } from '@/components/ui/Button'; export interface InsightDetailPanelProps { /** Insight to display (null = panel hidden) */ insight: InsightHistory | null; /** Called when close button clicked */ onClose: () => void; /** Called when delete button clicked */ onDelete?: (insightId: string) => void; /** Is delete operation in progress */ isDeleting?: boolean; /** Optional className */ className?: string; } // Tool icon mapping const toolConfig = { gemini: { icon: Sparkles, color: 'text-blue-500', bgColor: 'bg-blue-500/10', label: 'Gemini', }, qwen: { icon: Bot, color: 'text-purple-500', bgColor: 'bg-purple-500/10', label: 'Qwen', }, codex: { icon: Code2, color: 'text-green-500', bgColor: 'bg-green-500/10', label: 'Codex', }, default: { icon: Cpu, color: 'text-gray-500', bgColor: 'bg-gray-500/10', label: 'CLI', }, }; // Severity configuration const severityConfig = { error: { badge: 'bg-red-500/10 text-red-500 border-red-500/20', border: 'border-l-red-500', dot: 'bg-red-500', }, warning: { badge: 'bg-yellow-500/10 text-yellow-600 border-yellow-500/20', border: 'border-l-yellow-500', dot: 'bg-yellow-500', }, info: { badge: 'bg-blue-500/10 text-blue-500 border-blue-500/20', border: 'border-l-blue-500', dot: 'bg-blue-500', }, default: { badge: 'bg-gray-500/10 text-gray-500 border-gray-500/20', border: 'border-l-gray-500', dot: 'bg-gray-500', }, }; // Suggestion type configuration const suggestionTypeConfig = { refactor: { badge: 'bg-purple-500/10 text-purple-500 border-purple-500/20', icon: 'refactor', }, optimize: { badge: 'bg-green-500/10 text-green-500 border-green-500/20', icon: 'optimize', }, fix: { badge: 'bg-red-500/10 text-red-500 border-red-500/20', icon: 'fix', }, document: { badge: 'bg-blue-500/10 text-blue-500 border-blue-500/20', icon: 'document', }, }; /** * Format timestamp to relative time */ function formatRelativeTime(timestamp: string, locale: string): string { const date = new Date(timestamp); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (locale === 'zh') { if (diffMins < 1) return '刚刚'; if (diffMins < 60) return `${diffMins}分钟前`; if (diffHours < 24) return `${diffHours}小时前`; return `${diffDays}天前`; } if (diffMins < 1) return 'just now'; if (diffMins < 60) return `${diffMins}m ago`; if (diffHours < 24) return `${diffHours}h ago`; return `${diffDays}d ago`; } /** * PatternItem component for displaying a single pattern */ function PatternItem({ pattern }: { pattern: Pattern; locale: string }) { const severity = pattern.severity ?? 'info'; const config = severityConfig[severity] ?? severityConfig.default; return (
{pattern.description}
{pattern.example && ({pattern.example}
{suggestion.description}
{suggestion.code && ({suggestion.code}