spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1import { ExternalLink } from 'lucide-react';2import Link from 'next/link';3import { ConfidenceBadge, OriginBadge, StatusBadge } from '@/components/ui/badges';4import { KV, Row } from '@/components/ui/key-value';5import { fmtDateTime, pathOf } from '@/lib/format';6import { routes, SURFACE_LABELS } from '@/lib/site';7import type { Event, EventSource } from '@/lib/types';89/**10 * Evidence block shared by the drawer and `/events/[id]`: the careful-language contract (spec §165–171).11 * Every source is listed with its detection time; old/new values are shown verbatim; LLM origin shows model + prompt.12 */13export function EventEvidence({ event, sources, compact = false }: { event: Event; sources: EventSource[] | undefined; compact?: boolean }) {14 const list = sources && sources.length ? sources : event.source_url ? [{ source_url: event.source_url, surface: event.surface, detected_at: event.detected_at, kind: 'primary', sensor_id: event.sensor_id }] : [];15 const llm = event.origin === 'llm' || event.origin === 'hybrid';16 return (17 <div className="space-y-4 text-sm">18 {event.status !== 'active' && (19 <p className="border-l-2 border-danger pl-3 text-xs text-danger" role="status">20 {event.status === 'retracted' ? 'This event was retracted after review. It is kept for auditability and is not counted in metrics.' : event.status === 'duplicate' ? 'This event was merged into another canonical event.' : 'This event is awaiting human review.'}21 </p>22 )}23 {(event.old_value || event.new_value) && (24 <div className="grid gap-2 sm:grid-cols-2">25 <div className="min-w-0 border border-rule p-2.5">26 <p className="eyebrow">Before</p>27 <p className="mt-1 break-words text-[13px] text-ink-2">{event.old_value ?? <span className="text-ink-3">not previously observed</span>}</p>28 </div>29 <div className="min-w-0 border border-rule p-2.5">30 <p className="eyebrow">After</p>31 <p className="mt-1 break-words text-[13px] text-ink">{event.new_value ?? <span className="text-ink-3">no longer observed</span>}</p>32 </div>33 </div>34 )}35 <KV className={compact ? '[&>div]:grid-cols-[6.5rem_minmax(0,1fr)]' : undefined}>36 <Row k="Confidence">37 <ConfidenceBadge label={event.confidence_label} value={event.confidence} withValue />38 </Row>39 <Row k="Importance">40 <span className="tnum">{Math.round(event.importance > 1 ? event.importance : event.importance * 100)} / 100</span>41 </Row>42 <Row k="Detected">43 <span className="tnum">{fmtDateTime(event.detected_at)}</span>44 </Row>45 {event.effective_at && (46 <Row k="Effective">47 <span className="tnum">{fmtDateTime(event.effective_at)}</span>48 </Row>49 )}50 {event.published_at && (51 <Row k="Published">52 <span className="tnum">{fmtDateTime(event.published_at)}</span>53 </Row>54 )}55 {event.surface && <Row k="Surface">{SURFACE_LABELS[event.surface] ?? event.surface}</Row>}56 <Row k="Origin">57 <OriginBadge origin={event.origin} model={event.model_name} prompt={event.prompt_version} />58 {llm && (59 <span className="ml-2 text-xs text-ink-3">60 {event.model_name ?? 'model'}61 {event.prompt_version ? ` · prompt ${event.prompt_version}` : ''} — LLM-enriched interpretation of a deterministic change62 </span>63 )}64 </Row>65 {event.status !== 'active' && (66 <Row k="Status">67 <StatusBadge status={event.status} />68 </Row>69 )}70 {event.tags.length > 0 && (71 <Row k="Tags">72 <span className="flex flex-wrap gap-1">73 {[...new Set(event.tags)].map((t) => (74 <span key={t} className="mono rounded-[3px] bg-surface-2 px-1 text-[11px] text-ink-2">75 {t}76 </span>77 ))}78 </span>79 </Row>80 )}81 </KV>8283 <div>84 <p className="eyebrow">85 Sources <span className="tnum normal-case tracking-normal text-ink-3">({list.length})</span>86 </p>87 {list.length === 0 ? (88 <p className="mt-1 text-xs text-ink-3">The monitored source for this event is not available any more; the observation is kept.</p>89 ) : (90 <ul className="mt-1.5 divide-y divide-rule border-y border-rule">91 {list.map((s, i) => (92 <li key={`${s.source_url}-${i}`} className="flex flex-wrap items-baseline gap-x-3 gap-y-0.5 py-2 text-[13px]">93 <a href={s.source_url} target="_blank" rel="noopener noreferrer" className="link inline-flex min-w-0 max-w-full items-center gap-1 break-all">94 {pathOf(s.source_url)} <ExternalLink className="size-3 shrink-0" aria-hidden />95 </a>96 <span className="text-xs text-ink-3">97 {s.surface ? (SURFACE_LABELS[s.surface] ?? s.surface) : s.kind} · detected <span className="tnum">{fmtDateTime(s.detected_at)}</span>98 </span>99 {s.sensor_id && (100 <Link href={routes.sensor(s.sensor_id)} className="mono text-[11px] text-ink-3 hover:text-accent">101 sensor {s.sensor_id.slice(0, 12)}…102 </Link>103 )}104 </li>105 ))}106 </ul>107 )}108 </div>109110 <div className="flex flex-wrap gap-x-4 gap-y-1.5 text-xs">111 {event.change_id && (112 <Link href={routes.change(event.change_id)} className="link">113 View block-level change diff →114 </Link>115 )}116 {event.sensor_id && (117 <Link href={routes.sensor(event.sensor_id)} className="link">118 Sensor119 </Link>120 )}121 <Link href={routes.company(event.company.slug, 'timeline')} className="link">122 Company timeline123 </Link>124 </div>125 <p className="mono break-all text-[11px] text-ink-3">126 event {event.id}127 {event.cluster_id ? ` · cluster ${event.cluster_id}` : ''}128 {event.change_id ? ` · change ${event.change_id}` : ''}129 {event.sensor_id ? ` · sensor ${event.sensor_id}` : ''}130 </p>131 </div>132 );133}134