WIP: integrate-old-refactors-of-github #1
@@ -688,6 +688,29 @@ class APIServer:
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to add video routes: {e}")
|
||||
|
||||
@self.app.get("/debug/camera-manager")
|
||||
async def debug_camera_manager():
|
||||
"""Debug endpoint to check camera manager state"""
|
||||
try:
|
||||
if not self.camera_manager:
|
||||
return {"error": "Camera manager not available"}
|
||||
|
||||
return {
|
||||
"available_cameras": len(self.camera_manager.available_cameras),
|
||||
"camera_recorders": list(self.camera_manager.camera_recorders.keys()),
|
||||
"camera_streamers": list(self.camera_manager.camera_streamers.keys()),
|
||||
"streamer_states": {
|
||||
name: {
|
||||
"exists": streamer is not None,
|
||||
"is_streaming": streamer.is_streaming() if streamer else False,
|
||||
"streaming": getattr(streamer, 'streaming', False) if streamer else False
|
||||
}
|
||||
for name, streamer in self.camera_manager.camera_streamers.items()
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
def _setup_event_subscriptions(self):
|
||||
"""Setup event subscriptions for WebSocket broadcasting"""
|
||||
|
||||
|
||||
@@ -460,12 +460,16 @@ class CameraManager:
|
||||
|
||||
def _initialize_streamers(self) -> None:
|
||||
"""Initialize camera streamers for configured cameras"""
|
||||
self.logger.info("Starting camera streamer initialization...")
|
||||
with self._lock:
|
||||
for camera_config in self.config.cameras:
|
||||
if not camera_config.enabled:
|
||||
self.logger.debug(f"Skipping disabled camera: {camera_config.name}")
|
||||
continue
|
||||
|
||||
try:
|
||||
self.logger.info(f"Initializing streamer for camera: {camera_config.name}")
|
||||
|
||||
# Find matching physical camera
|
||||
device_info = self._find_camera_device(camera_config.name)
|
||||
if device_info is None:
|
||||
@@ -481,6 +485,10 @@ class CameraManager:
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error initializing streamer for {camera_config.name}: {e}")
|
||||
import traceback
|
||||
self.logger.error(f"Traceback: {traceback.format_exc()}")
|
||||
|
||||
self.logger.info(f"Camera streamer initialization complete. Created {len(self.camera_streamers)} streamers: {list(self.camera_streamers.keys())}")
|
||||
|
||||
def get_camera_streamer(self, camera_name: str) -> Optional[CameraStreamer]:
|
||||
"""Get camera streamer for a specific camera"""
|
||||
|
||||
@@ -172,14 +172,37 @@ class CameraMonitor:
|
||||
if not device_info:
|
||||
return "disconnected", "Camera device not found", None
|
||||
|
||||
# ALWAYS check our streamer state first, before doing any camera availability tests
|
||||
streamer = self.camera_manager.camera_streamers.get(camera_name)
|
||||
self.logger.info(f"Checking streamer for {camera_name}: {streamer}")
|
||||
if streamer and streamer.is_streaming():
|
||||
self.logger.info(f"Camera {camera_name} is streaming - setting status to streaming")
|
||||
return "streaming", "Camera streaming (live preview)", self._get_device_info_dict(device_info)
|
||||
|
||||
# Also check if our recorder is active
|
||||
recorder = self.camera_manager.camera_recorders.get(camera_name)
|
||||
if recorder and recorder.hCamera and recorder.recording:
|
||||
self.logger.info(f"Camera {camera_name} is recording - setting status to available")
|
||||
return "available", "Camera recording (in use by system)", self._get_device_info_dict(device_info)
|
||||
|
||||
# Check if camera is already opened by another process
|
||||
if mvsdk.CameraIsOpened(device_info):
|
||||
# Camera is opened - check if it's our recorder that's currently recording
|
||||
recorder = self.camera_manager.camera_recorders.get(camera_name)
|
||||
if recorder and recorder.hCamera and recorder.recording:
|
||||
return "available", "Camera recording (in use by system)", self._get_device_info_dict(device_info)
|
||||
else:
|
||||
try:
|
||||
self.logger.info(f"Checking if camera {camera_name} is opened...")
|
||||
is_opened = mvsdk.CameraIsOpened(device_info)
|
||||
self.logger.info(f"CameraIsOpened result for {camera_name}: {is_opened}")
|
||||
|
||||
if is_opened:
|
||||
self.logger.info(f"Camera {camera_name} is opened by another process - setting status to busy")
|
||||
return "busy", "Camera opened by another process", self._get_device_info_dict(device_info)
|
||||
else:
|
||||
self.logger.info(f"Camera {camera_name} is not opened, will try initialization")
|
||||
# Camera is not opened, so we can try to initialize it
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
self.logger.warning(f"CameraIsOpened failed for {camera_name}: {e}")
|
||||
# If we can't determine the status, try to initialize to see what happens
|
||||
self.logger.info(f"CameraIsOpened failed for {camera_name}, will try initialization: {e}")
|
||||
|
||||
# Try to initialize camera briefly to test availability
|
||||
try:
|
||||
|
||||
@@ -28,6 +28,7 @@ class CameraStatus(Enum):
|
||||
UNKNOWN = "unknown"
|
||||
AVAILABLE = "available"
|
||||
BUSY = "busy"
|
||||
STREAMING = "streaming" # New status for when camera is streaming
|
||||
ERROR = "error"
|
||||
DISCONNECTED = "disconnected"
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ services:
|
||||
web:
|
||||
image: node:20-alpine
|
||||
working_dir: /app
|
||||
env_file:
|
||||
- ./management-dashboard-web-app/.env
|
||||
volumes:
|
||||
- ./management-dashboard-web-app:/app
|
||||
environment:
|
||||
|
||||
0
management-dashboard-web-app/.env.example
Normal file → Executable file
0
management-dashboard-web-app/.env.example
Normal file → Executable file
0
management-dashboard-web-app/.gitignore
vendored
Normal file → Executable file
0
management-dashboard-web-app/.gitignore
vendored
Normal file → Executable file
0
management-dashboard-web-app/.vscode/extensions.json
vendored
Normal file → Executable file
0
management-dashboard-web-app/.vscode/extensions.json
vendored
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/AI_AGENT_VIDEO_INTEGRATION_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/AI_AGENT_VIDEO_INTEGRATION_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/API_CHANGES_SUMMARY.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/API_CHANGES_SUMMARY.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/API_DOCUMENTATION.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/API_DOCUMENTATION.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/API_QUICK_REFERENCE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/API_QUICK_REFERENCE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/CURRENT_CONFIGURATION.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/CURRENT_CONFIGURATION.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/MP4_FORMAT_UPDATE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/MP4_FORMAT_UPDATE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/PROJECT_COMPLETE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/PROJECT_COMPLETE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/REACT_INTEGRATION_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/REACT_INTEGRATION_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/README.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/README.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/VIDEO_STREAMING.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/VIDEO_STREAMING.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/WEB_AI_AGENT_VIDEO_INTEGRATION.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/WEB_AI_AGENT_VIDEO_INTEGRATION.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/api/CAMERA_CONFIG_API.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/api/CAMERA_CONFIG_API.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/camera/BLOWER_CAMERA_CONFIG.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/camera/BLOWER_CAMERA_CONFIG.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/camera/CONVEYOR_CAMERA_CONFIG.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/camera/CONVEYOR_CAMERA_CONFIG.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/camera/PREVIEW_ENHANCEMENT.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/camera/PREVIEW_ENHANCEMENT.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/features/AUTO_RECORDING_FEATURE_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/features/AUTO_RECORDING_FEATURE_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/guides/CAMERA_RECOVERY_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/guides/CAMERA_RECOVERY_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/guides/MQTT_LOGGING_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/guides/MQTT_LOGGING_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/guides/STREAMING_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/guides/STREAMING_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/01README.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/01README.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/IMPLEMENTATION_SUMMARY.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/IMPLEMENTATION_SUMMARY.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/README.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/README.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/README_SYSTEM.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/README_SYSTEM.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/TIMEZONE_SETUP_SUMMARY.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/TIMEZONE_SETUP_SUMMARY.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/VIDEO_RECORDER_README.md
Normal file → Executable file
0
management-dashboard-web-app/API Documentations/docs/legacy/VIDEO_RECORDER_README.md
Normal file → Executable file
210
management-dashboard-web-app/CAMERA_ROUTE_IMPLEMENTATION.md
Executable file
210
management-dashboard-web-app/CAMERA_ROUTE_IMPLEMENTATION.md
Executable file
@@ -0,0 +1,210 @@
|
||||
# 🎥 Camera Route Implementation Guide
|
||||
|
||||
This document explains the implementation of the new public camera live view routes (`/camera#/live`) that don't require authentication.
|
||||
|
||||
## 🚀 What Was Implemented
|
||||
|
||||
### 1. **LiveCameraView Component** (`src/components/LiveCameraView.tsx`)
|
||||
- Displays live camera feed without authentication requirements
|
||||
- Handles streaming start/stop automatically
|
||||
- Provides error handling and loading states
|
||||
- Full-screen live view with camera label and status indicator
|
||||
|
||||
### 2. **CameraRoute Component** (`src/components/CameraRoute.tsx`)
|
||||
- Validates camera route parameters
|
||||
- Ensures only valid camera numbers (camera1, camera2, etc.) are accepted
|
||||
- Renders the LiveCameraView for valid routes
|
||||
|
||||
### 3. **Updated App.tsx**
|
||||
- Added route pattern matching for `/camera#/live`
|
||||
- Integrated camera routes into existing authentication flow
|
||||
- Maintains backward compatibility with existing functionality
|
||||
|
||||
### 4. **Test Page** (`public/camera-test.html`)
|
||||
- Simple HTML page to test camera routes
|
||||
- Provides links to test different camera numbers
|
||||
- Explains expected behavior
|
||||
|
||||
## 📋 Required Dependencies
|
||||
|
||||
The following packages need to be installed to complete the implementation:
|
||||
|
||||
```bash
|
||||
# Install React Router
|
||||
npm install react-router-dom
|
||||
|
||||
# Install TypeScript types
|
||||
npm install --save-dev @types/react-router-dom
|
||||
```
|
||||
|
||||
**Note:** Due to permission issues, these packages couldn't be installed automatically. You'll need to resolve the permissions or install them manually.
|
||||
|
||||
## 🔧 How to Complete the Setup
|
||||
|
||||
### Option 1: Fix Permissions and Install
|
||||
```bash
|
||||
# Fix node_modules permissions
|
||||
sudo chown -R $USER:$USER node_modules
|
||||
sudo chmod -R 755 node_modules
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
```
|
||||
|
||||
### Option 2: Manual Installation
|
||||
```bash
|
||||
# Remove problematic node_modules
|
||||
rm -rf node_modules
|
||||
|
||||
# Reinstall everything
|
||||
npm install
|
||||
```
|
||||
|
||||
### Option 3: Use Yarn Instead
|
||||
```bash
|
||||
# Install yarn if not available
|
||||
npm install -g yarn
|
||||
|
||||
# Install dependencies with yarn
|
||||
yarn install
|
||||
```
|
||||
|
||||
## 🧪 Testing the Implementation
|
||||
|
||||
### 1. **Start the Development Server**
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 2. **Test Camera Routes**
|
||||
Open these URLs in your browser:
|
||||
- `http://localhost:5173/camera1/live` - Live view of camera1
|
||||
- `http://localhost:5173/camera2/live` - Live view of camera2
|
||||
- `http://localhost:5173/camera3/live` - Live view of camera3
|
||||
|
||||
### 3. **Use the Test Page**
|
||||
Open `http://localhost:5173/camera-test.html` to access the test interface.
|
||||
|
||||
### 4. **Expected Behavior**
|
||||
- ✅ **Valid routes** should show live camera feed
|
||||
- ❌ **Invalid routes** should show error message
|
||||
- 🔒 **Protected routes** should redirect to login
|
||||
|
||||
## 🏗️ Architecture Details
|
||||
|
||||
### Route Pattern
|
||||
```
|
||||
/camera{number}/live
|
||||
```
|
||||
- `{number}` must be a positive integer
|
||||
- Examples: `/camera1/live`, `/camera2/live`, `/camera10/live`
|
||||
- Invalid: `/camera/live`, `/camera0/live`, `/camera-1/live`
|
||||
|
||||
### Component Flow
|
||||
```
|
||||
App.tsx → Route Detection → CameraRoute → LiveCameraView
|
||||
```
|
||||
|
||||
### API Integration
|
||||
The LiveCameraView component integrates with existing camera API endpoints:
|
||||
- `POST /cameras/{camera_name}/start-stream` - Start streaming
|
||||
- `GET /cameras/{camera_name}/stream` - Get MJPEG stream
|
||||
- `POST /cameras/{camera_name}/stop-stream` - Stop streaming
|
||||
|
||||
## 🎯 Key Features
|
||||
|
||||
### ✅ **Public Access**
|
||||
- No authentication required
|
||||
- Anyone can view live camera feeds
|
||||
- Perfect for monitoring displays
|
||||
|
||||
### ✅ **Non-Blocking Streaming**
|
||||
- Uses existing CameraStreamer infrastructure
|
||||
- Separate camera connections for streaming vs. recording
|
||||
- Doesn't interfere with recording operations
|
||||
|
||||
### ✅ **Real-time Video**
|
||||
- MJPEG format for low latency
|
||||
- Automatic stream management
|
||||
- Error handling and retry functionality
|
||||
|
||||
### ✅ **Responsive Design**
|
||||
- Full-screen live view
|
||||
- Camera identification labels
|
||||
- Live status indicators
|
||||
|
||||
## 🔍 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. **Permission Errors During Installation**
|
||||
```bash
|
||||
# Fix ownership
|
||||
sudo chown -R $USER:$USER .
|
||||
|
||||
# Fix permissions
|
||||
sudo chmod -R 755 .
|
||||
```
|
||||
|
||||
#### 2. **Camera Stream Not Loading**
|
||||
- Check if camera API is running (`http://localhost:8000`)
|
||||
- Verify camera configuration in `config.compose.json`
|
||||
- Check browser console for errors
|
||||
|
||||
#### 3. **Route Not Working**
|
||||
- Ensure React app is running
|
||||
- Check browser console for routing errors
|
||||
- Verify component imports are correct
|
||||
|
||||
#### 4. **TypeScript Errors**
|
||||
- Install missing type definitions
|
||||
- Check import paths
|
||||
- Verify component interfaces
|
||||
|
||||
### Debug Steps
|
||||
1. Check browser console for errors
|
||||
2. Verify API endpoints are accessible
|
||||
3. Test camera streaming directly via API
|
||||
4. Check component rendering in React DevTools
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
### Immediate
|
||||
1. Install required dependencies
|
||||
2. Test basic functionality
|
||||
3. Verify camera streaming works
|
||||
|
||||
### Future Enhancements
|
||||
1. **Add React Router** for better routing
|
||||
2. **Implement URL-based navigation** between cameras
|
||||
3. **Add camera selection interface**
|
||||
4. **Implement stream quality controls**
|
||||
5. **Add recording controls** (if needed)
|
||||
|
||||
### Production Considerations
|
||||
1. **Security**: Consider adding rate limiting
|
||||
2. **Performance**: Optimize for multiple concurrent viewers
|
||||
3. **Monitoring**: Add analytics and usage tracking
|
||||
4. **Access Control**: Implement optional authentication if needed
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- [Camera API Documentation](../camera-management-api/docs/API_DOCUMENTATION.md)
|
||||
- [Streaming Guide](../camera-management-api/docs/guides/STREAMING_GUIDE.md)
|
||||
- [Vision System README](VISION_SYSTEM_README.md)
|
||||
|
||||
## 🤝 Support
|
||||
|
||||
If you encounter issues:
|
||||
1. Check the troubleshooting section above
|
||||
2. Review browser console for error messages
|
||||
3. Verify camera API is running and accessible
|
||||
4. Test API endpoints directly with curl or Postman
|
||||
|
||||
---
|
||||
|
||||
**Implementation Status**: ✅ Components Created | ⚠️ Dependencies Pending | <20><> Ready for Testing
|
||||
|
||||
|
||||
|
||||
|
||||
0
management-dashboard-web-app/README.md
Normal file → Executable file
0
management-dashboard-web-app/README.md
Normal file → Executable file
0
management-dashboard-web-app/VISION_SYSTEM_README.md
Normal file → Executable file
0
management-dashboard-web-app/VISION_SYSTEM_README.md
Normal file → Executable file
0
management-dashboard-web-app/api-endpoints.http
Normal file → Executable file
0
management-dashboard-web-app/api-endpoints.http
Normal file → Executable file
0
management-dashboard-web-app/docs/AUTO_RECORDING_SETUP.md
Normal file → Executable file
0
management-dashboard-web-app/docs/AUTO_RECORDING_SETUP.md
Normal file → Executable file
0
management-dashboard-web-app/docs/MODULAR_ARCHITECTURE_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/docs/MODULAR_ARCHITECTURE_GUIDE.md
Normal file → Executable file
0
management-dashboard-web-app/docs/MP4_FRONTEND_IMPLEMENTATION_STATUS.md
Normal file → Executable file
0
management-dashboard-web-app/docs/MP4_FRONTEND_IMPLEMENTATION_STATUS.md
Normal file → Executable file
0
management-dashboard-web-app/docs/VIDEO_STREAMING_INTEGRATION.md
Normal file → Executable file
0
management-dashboard-web-app/docs/VIDEO_STREAMING_INTEGRATION.md
Normal file → Executable file
0
management-dashboard-web-app/docs/VIDEO_STREAMING_INTEGRATION_COMPLETE.md
Normal file → Executable file
0
management-dashboard-web-app/docs/VIDEO_STREAMING_INTEGRATION_COMPLETE.md
Normal file → Executable file
0
management-dashboard-web-app/eslint.config.js
Normal file → Executable file
0
management-dashboard-web-app/eslint.config.js
Normal file → Executable file
0
management-dashboard-web-app/index.html
Normal file → Executable file
0
management-dashboard-web-app/index.html
Normal file → Executable file
75
management-dashboard-web-app/package-lock.json
generated
Normal file → Executable file
75
management-dashboard-web-app/package-lock.json
generated
Normal file → Executable file
@@ -13,19 +13,21 @@
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-router-dom": "^6.28.0",
|
||||
"tailwindcss": "^4.1.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.30.1",
|
||||
"@types/react": "^19.1.8",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@vitejs/plugin-react": "^4.6.0",
|
||||
"eslint": "^9.30.1",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^16.3.0",
|
||||
"typescript": "~5.8.3",
|
||||
"typescript-eslint": "^8.35.1",
|
||||
"typescript-eslint": "^8.28.1",
|
||||
"vite": "^7.0.4"
|
||||
}
|
||||
},
|
||||
@@ -1054,6 +1056,15 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz",
|
||||
"integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-beta.19",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz",
|
||||
@@ -1709,6 +1720,13 @@
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/history": {
|
||||
"version": "4.7.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
|
||||
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
@@ -1751,6 +1769,29 @@
|
||||
"@types/react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router": {
|
||||
"version": "5.1.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz",
|
||||
"integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/history": "^4.7.11",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router-dom": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz",
|
||||
"integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/history": "^4.7.11",
|
||||
"@types/react": "*",
|
||||
"@types/react-router": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
@@ -3562,6 +3603,38 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.30.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.1.tgz",
|
||||
"integrity": "sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "6.30.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz",
|
||||
"integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.23.0",
|
||||
"react-router": "6.30.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
|
||||
8
management-dashboard-web-app/package.json
Normal file → Executable file
8
management-dashboard-web-app/package.json
Normal file → Executable file
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -15,19 +15,21 @@
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-router-dom": "^6.28.0",
|
||||
"tailwindcss": "^4.1.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.30.1",
|
||||
"@types/react": "^19.1.8",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@vitejs/plugin-react": "^4.6.0",
|
||||
"eslint": "^9.30.1",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^16.3.0",
|
||||
"typescript": "~5.8.3",
|
||||
"typescript-eslint": "^8.35.1",
|
||||
"typescript-eslint": "^8.28.1",
|
||||
"vite": "^7.0.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
0
management-dashboard-web-app/phase_2_experimental_run_sheet.csv
Normal file → Executable file
0
management-dashboard-web-app/phase_2_experimental_run_sheet.csv
Normal file → Executable file
119
management-dashboard-web-app/public/camera-test.html
Executable file
119
management-dashboard-web-app/public/camera-test.html
Executable file
@@ -0,0 +1,119 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Camera Route Test</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.test-links {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.test-links h2 {
|
||||
color: #333;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.test-links a {
|
||||
display: inline-block;
|
||||
margin: 10px 10px 10px 0;
|
||||
padding: 10px 20px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.test-links a:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
.info {
|
||||
background: #e7f3ff;
|
||||
border: 1px solid #b3d9ff;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.info h3 {
|
||||
margin-top: 0;
|
||||
color: #0066cc;
|
||||
}
|
||||
|
||||
.note {
|
||||
background: #fff3cd;
|
||||
border: 1px solid #ffeaa7;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>🎥 Camera Route Test</h1>
|
||||
|
||||
<div class="info">
|
||||
<h3>Test the New Camera Routes</h3>
|
||||
<p>This page helps you test the new camera live view routes that don't require authentication.</p>
|
||||
<p><strong>Note:</strong> Make sure the React app is running and the camera API is accessible.</p>
|
||||
</div>
|
||||
|
||||
<div class="test-links">
|
||||
<h2>Test Camera Routes</h2>
|
||||
<p>Click the links below to test different camera routes:</p>
|
||||
|
||||
<a href="/camera1/live" target="_blank">Camera 1 Live View</a>
|
||||
<a href="/camera2/live" target="_blank">Camera 2 Live View</a>
|
||||
<a href="/camera3/live" target="_blank">Camera 3 Live View</a>
|
||||
<a href="/camera10/live" target="_blank">Camera 10 Live View</a>
|
||||
</div>
|
||||
|
||||
<div class="note">
|
||||
<h3>Expected Behavior</h3>
|
||||
<ul>
|
||||
<li>✅ <strong>Valid routes</strong> (like /camera1/live) should show the live camera feed</li>
|
||||
<li>❌ <strong>Invalid routes</strong> (like /camera/live) should show an error message</li>
|
||||
<li>🔒 <strong>Protected routes</strong> (like /) should redirect to login if not authenticated</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<h3>API Endpoints</h3>
|
||||
<p>The camera routes use these backend API endpoints:</p>
|
||||
<ul>
|
||||
<li><code>POST /cameras/{camera_name}/start-stream</code> - Start streaming</li>
|
||||
<li><code>GET /cameras/{camera_name}/stream</code> - Get MJPEG stream</li>
|
||||
<li><code>POST /cameras/{camera_name}/stop-stream</code> - Stop streaming</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Add click tracking for analytics
|
||||
document.querySelectorAll('.test-links a').forEach(link => {
|
||||
link.addEventListener('click', function () {
|
||||
console.log('Testing camera route:', this.href);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
0
management-dashboard-web-app/public/vite.svg
Normal file → Executable file
0
management-dashboard-web-app/public/vite.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
0
management-dashboard-web-app/src/App.css
Normal file → Executable file
0
management-dashboard-web-app/src/App.css
Normal file → Executable file
21
management-dashboard-web-app/src/App.tsx
Normal file → Executable file
21
management-dashboard-web-app/src/App.tsx
Normal file → Executable file
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react'
|
||||
import { supabase } from './lib/supabase'
|
||||
import { Login } from './components/Login'
|
||||
import { Dashboard } from './components/Dashboard'
|
||||
import { CameraRoute } from './components/CameraRoute'
|
||||
|
||||
function App() {
|
||||
const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null)
|
||||
@@ -84,6 +85,18 @@ function App() {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if current route is a camera live route
|
||||
const isCameraLiveRoute = (route: string) => {
|
||||
const cameraRoutePattern = /^\/camera(\d+)\/live$/
|
||||
return cameraRoutePattern.test(route)
|
||||
}
|
||||
|
||||
// Extract camera number from route
|
||||
const getCameraNumber = (route: string) => {
|
||||
const match = route.match(/^\/camera(\d+)\/live$/)
|
||||
return match ? `camera${match[1]}` : null
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
||||
@@ -107,6 +120,14 @@ function App() {
|
||||
)
|
||||
}
|
||||
|
||||
// Handle camera live routes (no authentication required)
|
||||
if (isCameraLiveRoute(currentRoute)) {
|
||||
const cameraNumber = getCameraNumber(currentRoute)
|
||||
if (cameraNumber) {
|
||||
return <CameraRoute cameraNumber={cameraNumber} />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isAuthenticated ? (
|
||||
|
||||
0
management-dashboard-web-app/src/assets/react.svg
Normal file → Executable file
0
management-dashboard-web-app/src/assets/react.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
0
management-dashboard-web-app/src/components/AutoRecordingStatus.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/AutoRecordingStatus.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/AutoRecordingTest.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/AutoRecordingTest.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/CameraConfigModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/CameraConfigModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/CameraPreviewModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/CameraPreviewModal.tsx
Normal file → Executable file
25
management-dashboard-web-app/src/components/CameraRoute.tsx
Executable file
25
management-dashboard-web-app/src/components/CameraRoute.tsx
Executable file
@@ -0,0 +1,25 @@
|
||||
import { LiveCameraView } from './LiveCameraView'
|
||||
|
||||
interface CameraRouteProps {
|
||||
cameraNumber: string
|
||||
}
|
||||
|
||||
export function CameraRoute({ cameraNumber }: CameraRouteProps) {
|
||||
// Validate camera number (only allow camera1, camera2, etc.)
|
||||
if (!cameraNumber || !/^camera\d+$/.test(cameraNumber)) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-900">
|
||||
<div className="text-center text-white">
|
||||
<h1 className="text-2xl font-bold mb-4">Invalid Camera</h1>
|
||||
<p className="text-gray-300">Camera number must be in format: camera1, camera2, etc.</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return <LiveCameraView cameraName={cameraNumber} />
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
0
management-dashboard-web-app/src/components/CreateUserModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/CreateUserModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/Dashboard.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/Dashboard.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/DashboardHome.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/DashboardHome.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/DashboardLayout.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/DashboardLayout.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/DataEntry.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/DataEntry.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/DataEntryInterface.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/DataEntryInterface.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/DraftManager.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/DraftManager.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/ExperimentForm.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/ExperimentForm.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/ExperimentModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/ExperimentModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/Experiments.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/Experiments.tsx
Normal file → Executable file
134
management-dashboard-web-app/src/components/LiveCameraView.tsx
Executable file
134
management-dashboard-web-app/src/components/LiveCameraView.tsx
Executable file
@@ -0,0 +1,134 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
|
||||
interface LiveCameraViewProps {
|
||||
cameraName: string
|
||||
}
|
||||
|
||||
export function LiveCameraView({ cameraName }: LiveCameraViewProps) {
|
||||
const [isStreaming, setIsStreaming] = useState(false)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const imgRef = useRef<HTMLImageElement>(null)
|
||||
|
||||
const API_BASE = import.meta.env.VITE_VISION_API_URL || 'http://localhost:8000'
|
||||
|
||||
useEffect(() => {
|
||||
startStreaming()
|
||||
return () => stopStreaming()
|
||||
}, [cameraName])
|
||||
|
||||
const startStreaming = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
// Start the stream
|
||||
const response = await fetch(`${API_BASE}/cameras/${cameraName}/start-stream`, {
|
||||
method: 'POST'
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
setIsStreaming(true)
|
||||
// Set the stream source with timestamp to prevent caching
|
||||
if (imgRef.current) {
|
||||
imgRef.current.src = `${API_BASE}/cameras/${cameraName}/stream?t=${Date.now()}`
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Failed to start stream: ${response.statusText}`)
|
||||
}
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : 'Failed to start stream'
|
||||
setError(errorMessage)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const stopStreaming = async () => {
|
||||
try {
|
||||
if (isStreaming) {
|
||||
await fetch(`${API_BASE}/cameras/${cameraName}/stop-stream`, {
|
||||
method: 'POST'
|
||||
})
|
||||
setIsStreaming(false)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error stopping stream:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const handleImageError = () => {
|
||||
setError('Failed to load camera stream')
|
||||
}
|
||||
|
||||
const handleImageLoad = () => {
|
||||
setError(null)
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-900">
|
||||
<div className="text-center text-white">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-white mx-auto"></div>
|
||||
<p className="mt-4">Starting camera stream...</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-900">
|
||||
<div className="text-center text-white">
|
||||
<div className="bg-red-600 rounded-full w-16 h-16 flex items-center justify-center mx-auto mb-4">
|
||||
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</div>
|
||||
<h2 className="text-xl font-semibold mb-2">Stream Error</h2>
|
||||
<p className="text-gray-300 mb-4">{error}</p>
|
||||
<button
|
||||
onClick={startStreaming}
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-md"
|
||||
>
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-900 flex items-center justify-center">
|
||||
<div className="relative">
|
||||
{/* Camera Label */}
|
||||
<div className="absolute top-4 left-4 z-10">
|
||||
<div className="bg-black bg-opacity-75 text-white px-3 py-1 rounded-md text-sm font-medium">
|
||||
{cameraName} - Live View
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Live Stream */}
|
||||
<img
|
||||
ref={imgRef}
|
||||
alt={`Live stream from ${cameraName}`}
|
||||
className="max-w-full max-h-screen object-contain"
|
||||
onError={handleImageError}
|
||||
onLoad={handleImageLoad}
|
||||
/>
|
||||
|
||||
{/* Status Indicator */}
|
||||
<div className="absolute bottom-4 right-4 z-10">
|
||||
<div className="flex items-center space-x-2 bg-black bg-opacity-75 text-white px-3 py-1 rounded-md">
|
||||
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
|
||||
<span className="text-sm">LIVE</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
0
management-dashboard-web-app/src/components/Login.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/Login.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/PhaseDataEntry.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/PhaseDataEntry.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/PhaseDraftManager.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/PhaseDraftManager.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/PhaseSelector.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/PhaseSelector.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/RepetitionDataEntryInterface.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/RepetitionDataEntryInterface.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/RepetitionLockManager.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/RepetitionLockManager.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/RepetitionPhaseSelector.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/RepetitionPhaseSelector.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/RepetitionScheduleModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/RepetitionScheduleModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/ScheduleModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/ScheduleModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/Sidebar.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/Sidebar.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/TopNavbar.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/TopNavbar.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/UserManagement.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/components/UserManagement.tsx
Normal file → Executable file
27
management-dashboard-web-app/src/components/VisionSystem.tsx
Normal file → Executable file
27
management-dashboard-web-app/src/components/VisionSystem.tsx
Normal file → Executable file
@@ -196,9 +196,10 @@ const CamerasStatus = memo(({
|
||||
const hasSerial = !!camera.device_info?.serial_number
|
||||
|
||||
// Determine if camera is connected based on status
|
||||
const isConnected = camera.status === 'available' || camera.status === 'connected'
|
||||
const isConnected = camera.status === 'available' || camera.status === 'connected' || camera.status === 'streaming'
|
||||
const hasError = camera.status === 'error'
|
||||
const statusText = camera.status || 'unknown'
|
||||
const isStreaming = camera.status === 'streaming'
|
||||
|
||||
return (
|
||||
<div key={cameraName} className="border border-gray-200 rounded-lg p-4">
|
||||
@@ -209,11 +210,12 @@ const CamerasStatus = memo(({
|
||||
<span className="text-gray-500 text-sm font-normal ml-2">({cameraName})</span>
|
||||
)}
|
||||
</h4>
|
||||
<div className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${isConnected ? 'bg-green-100 text-green-800' :
|
||||
hasError ? 'bg-yellow-100 text-yellow-800' :
|
||||
'bg-red-100 text-red-800'
|
||||
<div className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${isStreaming ? 'bg-blue-100 text-blue-800' :
|
||||
isConnected ? 'bg-green-100 text-green-800' :
|
||||
hasError ? 'bg-yellow-100 text-yellow-800' :
|
||||
'bg-red-100 text-red-800'
|
||||
}`}>
|
||||
{isConnected ? 'Connected' : hasError ? 'Error' : 'Disconnected'}
|
||||
{isStreaming ? 'Streaming' : isConnected ? 'Connected' : hasError ? 'Error' : 'Disconnected'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -224,7 +226,8 @@ const CamerasStatus = memo(({
|
||||
hasError ? 'text-yellow-600' :
|
||||
'text-red-600'
|
||||
}`}>
|
||||
{statusText.charAt(0).toUpperCase() + statusText.slice(1)}
|
||||
{isStreaming ? 'Streaming' :
|
||||
statusText.charAt(0).toUpperCase() + statusText.slice(1)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -238,6 +241,16 @@ const CamerasStatus = memo(({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isStreaming && (
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-500">Streaming:</span>
|
||||
<span className="text-blue-600 font-medium flex items-center">
|
||||
<div className="w-2 h-2 bg-blue-500 rounded-full mr-2 animate-pulse"></div>
|
||||
Live
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{hasDeviceInfo && (
|
||||
<>
|
||||
{camera.device_info.model && (
|
||||
@@ -923,7 +936,7 @@ export function VisionSystem() {
|
||||
|
||||
{/* 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-[999999] p-4 rounded-md shadow-lg ${notification.type === 'success'
|
||||
? 'bg-green-50 border border-green-200 text-green-800'
|
||||
: 'bg-red-50 border border-red-200 text-red-800'
|
||||
}`}>
|
||||
|
||||
0
management-dashboard-web-app/src/features/video-streaming/VideoStreamingPage.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/VideoStreamingPage.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/ApiStatusIndicator.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/ApiStatusIndicator.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/Pagination.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/Pagination.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/PerformanceDashboard.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/PerformanceDashboard.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoCard.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoCard.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoDebugger.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoDebugger.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoErrorBoundary.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoErrorBoundary.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoList.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoList.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoModal.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoPlayer.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoPlayer.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoThumbnail.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/VideoThumbnail.tsx
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/index.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/components/index.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/hooks/index.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/hooks/index.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/hooks/useVideoInfo.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/hooks/useVideoInfo.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/hooks/useVideoList.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/hooks/useVideoList.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/hooks/useVideoPlayer.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/hooks/useVideoPlayer.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/index.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/index.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/services/videoApi.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/services/videoApi.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/types/index.ts
Normal file → Executable file
0
management-dashboard-web-app/src/features/video-streaming/types/index.ts
Normal file → Executable file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user