feat: Add camera preview functionality and recording controls to VisionSystem

This commit is contained in:
Alireza Vaezi
2025-07-29 12:31:03 -04:00
parent 0d20fe189d
commit 1f47e89a4d

View File

@@ -15,6 +15,7 @@ import {
} from '../lib/visionApi' } from '../lib/visionApi'
import { useAuth } from '../hooks/useAuth' import { useAuth } from '../hooks/useAuth'
import { CameraConfigModal } from './CameraConfigModal' import { CameraConfigModal } from './CameraConfigModal'
import { CameraPreviewModal } from './CameraPreviewModal'
// Memoized components to prevent unnecessary re-renders // Memoized components to prevent unnecessary re-renders
const SystemOverview = memo(({ systemStatus }: { systemStatus: SystemStatus }) => ( const SystemOverview = memo(({ systemStatus }: { systemStatus: SystemStatus }) => (
@@ -458,6 +459,10 @@ export function VisionSystem() {
const [selectedCamera, setSelectedCamera] = useState<string | null>(null) const [selectedCamera, setSelectedCamera] = useState<string | null>(null)
const [notification, setNotification] = useState<{ type: 'success' | 'error', message: string } | null>(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<string | null>(null)
const intervalRef = useRef<NodeJS.Timeout | null>(null) const intervalRef = useRef<NodeJS.Timeout | null>(null)
const clearAutoRefresh = useCallback(() => { const clearAutoRefresh = useCallback(() => {
@@ -586,6 +591,50 @@ export function VisionSystem() {
setTimeout(() => setNotification(null), 5000) 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) => { const getStatusColor = (status: string, isRecording: boolean = false) => {
// If camera is recording, always show red regardless of status // If camera is recording, always show red regardless of status
if (isRecording) { if (isRecording) {
@@ -741,7 +790,15 @@ export function VisionSystem() {
{/* Cameras Status */} {/* Cameras Status */}
{systemStatus && <CamerasStatus systemStatus={systemStatus} onConfigureCamera={handleConfigureCamera} />} {systemStatus && (
<CamerasStatus
systemStatus={systemStatus}
onConfigureCamera={handleConfigureCamera}
onStartRecording={handleStartRecording}
onStopRecording={handleStopRecording}
onPreviewCamera={handlePreviewCamera}
/>
)}
{/* Machines Status */} {/* Machines Status */}
{systemStatus && Object.keys(systemStatus.machines).length > 0 && ( {systemStatus && Object.keys(systemStatus.machines).length > 0 && (
@@ -812,6 +869,18 @@ export function VisionSystem() {
/> />
)} )}
{/* Camera Preview Modal */}
{previewCamera && (
<CameraPreviewModal
cameraName={previewCamera}
isOpen={previewModalOpen}
onClose={() => {
setPreviewModalOpen(false)
setPreviewCamera(null)
}}
/>
)}
{/* Notification */} {/* Notification */}
{notification && ( {notification && (
<div className={`fixed top-4 right-4 z-50 p-4 rounded-md shadow-lg ${notification.type === 'success' <div className={`fixed top-4 right-4 z-50 p-4 rounded-md shadow-lg ${notification.type === 'success'