import { Alert, Box, Divider, IconButton, Typography } from '@mui/material' import { X } from 'lucide-react' import { AIOutputStatusBadge } from './AIOutputStatusBadge' import { PromptVersionBadge } from './PromptVersionBadge' import { AIErrorBadge } from './AIErrorBadge' import { AIReviewActionToolbar } from './AIReviewActionToolbar' import type { AIOutput, AIOutputType } from '../../domain/aiOutput' import type { ReviewStatus } from '../../domain/enums' const TYPE_LABELS: Record = { NEED_PARSE: 'Bedarf-Parsing', FOLLOW_UP_QUESTIONS: 'Rückfragen', MATCH_EXPLANATION: 'Match-Begründung', COMPARE_SUMMARY: 'Vergleich', DECISION_BRIEF: 'Entscheidungs-Brief', DATA_QUALITY_SUMMARY: 'Datenqualität', } const ERROR_TYPE_LABELS: Record = { SCHEMA_VALIDATION: 'Schema-Validierungsfehler', PROVIDER_TIMEOUT: 'Provider-Timeout', INVALID_JSON: 'Ungültiges JSON', EMPTY_RESPONSE: 'Leere Antwort', RATE_LIMIT: 'Rate-Limit erreicht', } const MODEL_LABELS: Record = { 'claude-3-5-sonnet-20241022': 'Claude 3.5 Sonnet', 'claude-3-haiku-20240307': 'Claude 3 Haiku', 'claude-3-opus-20240229': 'Claude 3 Opus', } const ENTITY_TYPE_LABELS: Record = { NEED: 'Gesuch', MATCH: 'Match', PROPERTY: 'Objekt', SIGNAL: 'Signal', } interface Props { output: AIOutput onClose: () => void onUpdateStatus: (status: ReviewStatus) => void isSubmitting?: boolean } function MetaRow({ label, children }: { label: string; children: React.ReactNode }) { return ( {label} {children} ) } export function AIOutputDetailPanel({ output, onClose, onUpdateStatus, isSubmitting }: Props) { const handleCopyJson = () => { navigator.clipboard.writeText(output.outputPreview).catch(() => {}) } return ( {/* Header */} {output.error && } {TYPE_LABELS[output.type] ?? output.type} {/* Scrollable body */} {/* Metadata */} {output.id} {new Date(output.createdAt).toLocaleString('de-CH', { dateStyle: 'medium', timeStyle: 'short' })} {MODEL_LABELS[output.model] ?? output.model} {output.provider} {output.inputHash} {ENTITY_TYPE_LABELS[output.relatedEntityType] ?? output.relatedEntityType}{' '} {output.relatedEntityId} {output.latencyMs != null && ( 5000 ? '#c0392b' : '#334155', fontWeight: output.latencyMs > 5000 ? 700 : 400 }}> {(output.latencyMs / 1000).toFixed(2)}s )} {output.costEstimate != null && ( ${output.costEstimate.toFixed(4)} )} {/* Error details */} {output.error && ( {ERROR_TYPE_LABELS[output.error.type] ?? output.error.type}
{output.error.message} {output.error.recoverable && ( Wiederholbar — kann erneut ausgelöst werden. )}
)} {/* Output preview */} Output-Vorschau {output.outputPreview || '(kein Output)'} {/* Actions */}
) }