import React, { useEffect, useRef, useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, } from "@/components/ui/dialog"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { AlertTriangle, CheckCircle, Loader2, Play, VideoOff } from "lucide-react"; import { RobotRecord } from "@/hooks/useRobots"; import { useApi } from "@/contexts/ApiContext"; import { useToast } from "@/hooks/use-toast"; import { useNavigate } from "react-router-dom"; import { JobCheckpoint, PolicyConfigSummary, getCheckpointPolicyConfig, listJobCheckpoints, } from "@/lib/checkpointsApi"; import { startInference } from "@/lib/inferenceApi"; import CheckpointDropdown from "@/components/jobs/CheckpointDropdown"; interface AvailableCamera { index: number; name: string; deviceId: string; available: boolean; } const CameraPreview: React.FC<{ deviceId: string; paused: boolean }> = ({ deviceId, paused, }) => { const videoRef = useRef(null); const [error, setError] = useState(false); useEffect(() => { if (paused || !deviceId) { if (!deviceId) setError(true); return; } let cancelled = false; let stream: MediaStream | null = null; setError(false); (async () => { try { stream = await navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: deviceId } }, }); if (cancelled) { stream.getTracks().forEach((t) => t.stop()); return; } if (videoRef.current) { videoRef.current.srcObject = stream; await videoRef.current.play().catch(() => {}); } } catch { setError(true); } })(); return () => { cancelled = true; if (stream) stream.getTracks().forEach((t) => t.stop()); }; }, [deviceId, paused]); if (paused || error || !deviceId) { return (
{paused ? "Released" : "No preview"}
); } return (