refactor(results): support class-based detection summaries

This commit is contained in:
2026-06-26 14:55:29 +05:30
parent 8a080cb051
commit 57461a05f2
10 changed files with 193 additions and 333 deletions

View File

@@ -2,10 +2,8 @@
import { useEffect, useRef } from 'react';
import { Activity, Film, MapPin } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { ScrollArea } from '@/components/ui/scroll-area';
import { DetectionResultLog } from '@/types';
import { DETECTION_TYPES } from '@/constants/detectionModeConfig';
import { cn } from '@/lib/utils';
interface DetectionLogsProps {
@@ -34,7 +32,7 @@ const DetectionLogs = ({ logs, activeLogId, onSeek }: DetectionLogsProps) => {
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<h4 className="text-sm font-bold flex items-center gap-2">
<h4 className="flex items-center gap-2 text-sm font-bold">
<Activity className="h-4 w-4" />
Detection Logs
</h4>
@@ -43,20 +41,18 @@ const DetectionLogs = ({ logs, activeLogId, onSeek }: DetectionLogsProps) => {
<div className="space-y-3 p-4">
{logs.length === 0 ? (
<div className="flex flex-col items-center justify-center py-12 text-muted-foreground">
<Film className="h-8 w-8 mb-2 opacity-20" />
<Film className="mb-2 h-8 w-8 opacity-20" />
<p className="text-xs">No detections found</p>
</div>
) : (
logs.map((log) => {
const typeId = (log.type || '').toLowerCase();
const typeConfig = DETECTION_TYPES[typeId];
const label =
log.label || typeConfig?.label || typeId.replace(/_/g, ' ');
const timestampSeconds = log.frame.timestamp_seconds;
const { latitude, longitude } = log.location;
const isActive = activeLogId === log.id;
return (
<button
key={`${log.id}-${log.frame}`}
key={`${log.id}-${log.frame.number}`}
ref={isActive ? activeLogRef : null}
type="button"
onClick={() => onSeek(log)}
@@ -65,35 +61,35 @@ const DetectionLogs = ({ logs, activeLogId, onSeek }: DetectionLogsProps) => {
isActive && 'border-primary bg-primary/5',
)}
>
<div className="flex items-start justify-between gap-4 mb-3">
<div className="mb-3 flex items-start justify-between gap-4">
<div>
<div className="text-[13px] font-bold">
{label} ID: {log.id}
{log.detection.display_name} ID: {log.id}
</div>
<div className="text-[11px] text-muted-foreground font-medium">
Frame {log.frame}
<div className="text-[11px] font-medium text-muted-foreground">
Frame {log.frame.number}
</div>
</div>
<div className="text-right shrink-0">
<div className="shrink-0 text-right">
<div className="text-xs font-bold">
{formatVideoTime(log.timestamp_seconds)}
{formatVideoTime(timestampSeconds)}
</div>
<div className="text-[11px] text-muted-foreground">
{log.timestamp_seconds.toFixed(2)}s
{timestampSeconds.toFixed(2)}s
</div>
</div>
</div>
<div className="space-y-2 text-[12px] text-muted-foreground/90 font-medium">
{typeof log.confidence === 'number' && (
<div>Confidence: {(log.confidence * 100).toFixed(1)}%</div>
)}
{typeof log.latitude === 'number' &&
typeof log.longitude === 'number' && (
<div className="space-y-2 text-[12px] font-medium text-muted-foreground/90">
<div>
Confidence: {(log.detection.confidence * 100).toFixed(1)}%
</div>
{typeof latitude === 'number' &&
typeof longitude === 'number' && (
<div className="flex items-center gap-1.5">
<MapPin className="h-3 w-3" />
<span>
{log.latitude.toFixed(8)}, {log.longitude.toFixed(8)}
{latitude.toFixed(8)}, {longitude.toFixed(8)}
</span>
</div>
)}