import type { ElementType } from 'react'; import { useTranslation } from 'react-i18next'; import { XCircle, AlertTriangle, CheckCircle2, ExternalLink, Wrench, ServerCog, Bug } from 'lucide-react'; import type { LogFinding, LogFindingCategory, SystemHealthResult } from '../api/client'; const WIKI_TROUBLESHOOTING = 'https://wiki.bambuddy.cool/reference/troubleshooting/'; const CATEGORY_META: Record = { layer8: { icon: Wrench, badgeClass: 'bg-bambu-green/15 text-bambu-green border-bambu-green/30' }, environment: { icon: ServerCog, badgeClass: 'bg-amber-500/15 text-amber-300 border-amber-500/30' }, bug: { icon: Bug, badgeClass: 'bg-red-500/15 text-red-300 border-red-500/30' }, }; /** * One detected log-health finding. Cause/fix/name text is rendered from i18n * keyed by signature_id; an unknown signature (frontend older than backend) * still renders gracefully via the defaultValue fallbacks. */ function FindingCard({ finding }: { finding: LogFinding }) { const { t } = useTranslation(); const id = finding.signature_id; const name = t(`systemHealth.signature.${id}.name`, { defaultValue: id }); const cause = t(`systemHealth.signature.${id}.cause`, { defaultValue: '' }); const fix = t(`systemHealth.signature.${id}.fix`, { defaultValue: '' }); const meta = CATEGORY_META[finding.category] ?? CATEGORY_META.bug; const CategoryIcon = meta.icon; const SeverityIcon = finding.severity === 'error' ? XCircle : AlertTriangle; const severityColor = finding.severity === 'error' ? 'text-red-400' : 'text-amber-400'; return (
{name} {t(`systemHealth.category.${finding.category}`)}
{cause &&

{cause}

}
{fix && (
{t('systemHealth.fixLabel')} {fix}
)}
{finding.sample}
{t('systemHealth.occurrences', { times: finding.count, lastSeen: finding.last_seen })} {t('systemHealth.learnMore')}
); } /** * Presentational panel for a log-health scan result. Shared by the System page * section and the bug-report bubble so both surfaces look identical. */ export function SystemHealthPanel({ result }: { result: SystemHealthResult }) { const { t } = useTranslation(); if (!result.log_available) { return (
{t('systemHealth.logUnavailable')}
); } if (result.findings.length === 0) { return (
{t('systemHealth.clean', { times: result.scanned_entries })}
); } return (
{result.findings.map((finding) => ( ))}
); }