From 1f47e89a4d6fcb76ae57aac7caaf994a59b3c869 Mon Sep 17 00:00:00 2001 From: Alireza Vaezi Date: Tue, 29 Jul 2025 12:31:03 -0400 Subject: [PATCH] feat: Add camera preview functionality and recording controls to VisionSystem --- src/components/VisionSystem.tsx | 71 ++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/src/components/VisionSystem.tsx b/src/components/VisionSystem.tsx index fed7469..14e70d4 100644 --- a/src/components/VisionSystem.tsx +++ b/src/components/VisionSystem.tsx @@ -15,6 +15,7 @@ import { } from '../lib/visionApi' import { useAuth } from '../hooks/useAuth' import { CameraConfigModal } from './CameraConfigModal' +import { CameraPreviewModal } from './CameraPreviewModal' // Memoized components to prevent unnecessary re-renders const SystemOverview = memo(({ systemStatus }: { systemStatus: SystemStatus }) => ( @@ -458,6 +459,10 @@ export function VisionSystem() { const [selectedCamera, setSelectedCamera] = useState(null) const [notification, setNotification] = useState<{ type: 'success' | 'error', message: string } | null>(null) + // Camera preview modal state + const [previewModalOpen, setPreviewModalOpen] = useState(false) + const [previewCamera, setPreviewCamera] = useState(null) + const intervalRef = useRef(null) const clearAutoRefresh = useCallback(() => { @@ -586,6 +591,50 @@ export function VisionSystem() { setTimeout(() => setNotification(null), 5000) } + // Recording control handlers + const handleStartRecording = async (cameraName: string) => { + try { + const timestamp = new Date().toISOString().replace(/[:.]/g, '-') + const filename = `manual_${cameraName}_${timestamp}.avi` + + const result = await visionApi.startRecording(cameraName, { filename }) + + if (result.success) { + setNotification({ type: 'success', message: `Recording started: ${result.filename}` }) + // Refresh data to update recording status + fetchData(false) + } else { + setNotification({ type: 'error', message: `Failed to start recording: ${result.message}` }) + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error' + setNotification({ type: 'error', message: `Error starting recording: ${errorMessage}` }) + } + } + + const handleStopRecording = async (cameraName: string) => { + try { + const result = await visionApi.stopRecording(cameraName) + + if (result.success) { + const duration = result.duration_seconds ? ` (${result.duration_seconds}s)` : '' + setNotification({ type: 'success', message: `Recording stopped${duration}` }) + // Refresh data to update recording status + fetchData(false) + } else { + setNotification({ type: 'error', message: `Failed to stop recording: ${result.message}` }) + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error' + setNotification({ type: 'error', message: `Error stopping recording: ${errorMessage}` }) + } + } + + const handlePreviewCamera = (cameraName: string) => { + setPreviewCamera(cameraName) + setPreviewModalOpen(true) + } + const getStatusColor = (status: string, isRecording: boolean = false) => { // If camera is recording, always show red regardless of status if (isRecording) { @@ -741,7 +790,15 @@ export function VisionSystem() { {/* Cameras Status */} - {systemStatus && } + {systemStatus && ( + + )} {/* Machines Status */} {systemStatus && Object.keys(systemStatus.machines).length > 0 && ( @@ -812,6 +869,18 @@ export function VisionSystem() { /> )} + {/* Camera Preview Modal */} + {previewCamera && ( + { + setPreviewModalOpen(false) + setPreviewCamera(null) + }} + /> + )} + {/* Notification */} {notification && (