From 49ddcfd002d69dad48aa77161fbd7e916af4f508 Mon Sep 17 00:00:00 2001 From: salirezav Date: Mon, 2 Feb 2026 11:25:37 -0500 Subject: [PATCH] Refactor docker-compose setup and enhance scheduling components - Re-enabled Vision API and Media API services in docker-compose.yml, providing necessary configurations for development. - Improved scheduling logic in HorizontalTimelineCalendar and Scheduling components to better manage repetition visibility and database scheduling status. - Updated docker-compose-reset.sh to conditionally wait for Supabase services, enhancing the setup process for local development. - Added isScheduledInDb prop to manage UI states for scheduled repetitions, improving user experience in the scheduling interface. --- docker-compose.yml | 231 +++++++++--------- .../components/HorizontalTimelineCalendar.tsx | 34 ++- .../src/components/Scheduling.tsx | 133 ++++++---- scripts/docker-compose-reset.sh | 98 ++++---- 4 files changed, 284 insertions(+), 212 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1008918..588eecf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -299,74 +299,71 @@ services: # - usda-vision-network # restart: unless-stopped # - # ============================================================================ - # Vision API Service - DISABLED FOR DEVELOPMENT - # ============================================================================ - # api: - # container_name: usda-vision-api - # build: - # context: ./camera-management-api - # dockerfile: Dockerfile - # working_dir: /app - # restart: unless-stopped # Automatically restart container if it fails or exits - # healthcheck: - # test: ["CMD-SHELL", "python3 -c 'import urllib.request; urllib.request.urlopen(\"http://localhost:8000/health\").read()' || exit 1"] - # interval: 30s - # timeout: 10s - # retries: 3 - # start_period: 60s - # volumes: - # - ./camera-management-api:/app - # - /mnt/nfs_share:/mnt/nfs_share - # - /etc/localtime:/etc/localtime:ro - # - /etc/timezone:/etc/timezone:ro - # environment: - # - PYTHONUNBUFFERED=1 - # - LD_LIBRARY_PATH=/usr/local/lib:/lib:/usr/lib - # - PYTHONPATH=/app:/app/camera_sdk - # - TZ=America/New_York - # - MEDIAMTX_HOST=localhost - # - MEDIAMTX_RTSP_PORT=8554 - # command: > - # sh -lc " - # set -e # Exit on error - # - # # Only install system packages if not already installed (check for ffmpeg) - # if ! command -v ffmpeg &> /dev/null; then - # echo 'Installing system dependencies...'; - # apt-get update && apt-get install -y --no-install-recommends libusb-1.0-0-dev ffmpeg; - # else - # echo 'System dependencies already installed'; - # fi + api: + container_name: usda-vision-api + build: + context: ./camera-management-api + dockerfile: Dockerfile + working_dir: /app + restart: unless-stopped # Automatically restart container if it fails or exits + healthcheck: + test: ["CMD-SHELL", "python3 -c 'import urllib.request; urllib.request.urlopen(\"http://localhost:8000/health\").read()' || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + volumes: + - ./camera-management-api:/app + - /mnt/nfs_share:/mnt/nfs_share + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + environment: + - PYTHONUNBUFFERED=1 + - LD_LIBRARY_PATH=/usr/local/lib:/lib:/usr/lib + - PYTHONPATH=/app:/app/camera_sdk + - TZ=America/New_York + - MEDIAMTX_HOST=localhost + - MEDIAMTX_RTSP_PORT=8554 + command: > + sh -lc " + set -e # Exit on error + + # Only install system packages if not already installed (check for ffmpeg) + if ! command -v ffmpeg &> /dev/null; then + echo 'Installing system dependencies...'; + apt-get update && apt-get install -y --no-install-recommends libusb-1.0-0-dev ffmpeg; + else + echo 'System dependencies already installed'; + fi - # # Install camera SDK if not already installed - # if [ ! -f /lib/libMVSDK.so ] && [ -f 'camera_sdk/linuxSDK_V2.1.0.49(250108)/install.sh' ]; then - # echo 'Installing camera SDK...'; - # cd 'camera_sdk/linuxSDK_V2.1.0.49(250108)'; - # chmod +x install.sh; - # ./install.sh || echo 'Warning: Camera SDK installation may have failed'; - # cd /app; - # else - # echo 'Camera SDK already installed or install script not found'; - # fi; + # Install camera SDK if not already installed + if [ ! -f /lib/libMVSDK.so ] && [ -f 'camera_sdk/linuxSDK_V2.1.0.49(250108)/install.sh' ]; then + echo 'Installing camera SDK...'; + cd 'camera_sdk/linuxSDK_V2.1.0.49(250108)'; + chmod +x install.sh; + ./install.sh || echo 'Warning: Camera SDK installation may have failed'; + cd /app; + else + echo 'Camera SDK already installed or install script not found'; + fi; - # # Install Python dependencies (only if requirements.txt changed or packages missing) - # if [ -f requirements.txt ]; then - # pip install --no-cache-dir -r requirements.txt || echo 'Warning: Some Python packages may have failed to install'; - # else - # pip install --no-cache-dir -e . || echo 'Warning: Package installation may have failed'; - # fi; + # Install Python dependencies (only if requirements.txt changed or packages missing) + if [ -f requirements.txt ]; then + pip install --no-cache-dir -r requirements.txt || echo 'Warning: Some Python packages may have failed to install'; + else + pip install --no-cache-dir -e . || echo 'Warning: Package installation may have failed'; + fi; - # # Start the application with error handling - # echo 'Starting USDA Vision Camera System...'; - # python main.py --config config.compose.json || { - # echo 'Application exited with error code: $?'; - # echo 'Waiting 5 seconds before exit...'; - # sleep 5; - # exit 1; - # } - # " - # network_mode: host + # Start the application with error handling + echo 'Starting USDA Vision Camera System...'; + python main.py --config config.compose.json || { + echo 'Application exited with error code: $?'; + echo 'Waiting 5 seconds before exit...'; + sleep 5; + exit 1; + } + " + network_mode: host web: container_name: usda-vision-web @@ -424,31 +421,28 @@ services: networks: - usda-vision-network - # ============================================================================ - # Vision System Remote - DISABLED FOR DEVELOPMENT - # ============================================================================ - # vision-system-remote: - # container_name: usda-vision-vision-system-remote - # image: node:20-alpine - # working_dir: /app - # environment: - # - CHOKIDAR_USEPOLLING=true - # - TZ=America/New_York - # # Use environment variable with fallback to localhost - # - VITE_VISION_API_URL=${VITE_VISION_API_URL:-http://localhost:8000} - # volumes: - # - ./vision-system-remote:/app - # command: > - # sh -lc " - # npm install; - # npm run dev:watch - # " - # extra_hosts: - # - "host.docker.internal:host-gateway" - # ports: - # - "3002:3002" - # networks: - # - usda-vision-network + vision-system-remote: + container_name: usda-vision-vision-system-remote + image: node:20-alpine + working_dir: /app + environment: + - CHOKIDAR_USEPOLLING=true + - TZ=America/New_York + # Use environment variable with fallback to localhost + - VITE_VISION_API_URL=${VITE_VISION_API_URL:-http://localhost:8000} + volumes: + - ./vision-system-remote:/app + command: > + sh -lc " + npm install; + npm run dev:watch + " + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "3002:3002" + networks: + - usda-vision-network scheduling-remote: container_name: usda-vision-scheduling-remote @@ -473,36 +467,33 @@ services: networks: - usda-vision-network - # ============================================================================ - # Media API Service - DISABLED FOR DEVELOPMENT - # ============================================================================ - # media-api: - # container_name: usda-vision-media-api - # build: - # context: ./media-api - # dockerfile: Dockerfile - # environment: - # - MEDIA_VIDEOS_DIR=/mnt/nfs_share - # - MEDIA_THUMBS_DIR=/mnt/nfs_share/.thumbnails - # - MAX_CONCURRENT_TRANSCODING=2 # Limit concurrent transcoding operations - # volumes: - # - /mnt/nfs_share:/mnt/nfs_share - # ports: - # - "8090:8090" - # networks: - # - usda-vision-network - # deploy: - # resources: - # limits: - # cpus: '4' # Limit to 4 CPU cores (adjust based on your system) - # memory: 2G # Limit to 2GB RAM per container - # reservations: - # cpus: '1' # Reserve at least 1 CPU core - # memory: 512M # Reserve at least 512MB RAM - # # Alternative syntax for older Docker Compose versions: - # # cpus: '4' - # # mem_limit: 2g - # # mem_reservation: 512m + media-api: + container_name: usda-vision-media-api + build: + context: ./media-api + dockerfile: Dockerfile + environment: + - MEDIA_VIDEOS_DIR=/mnt/nfs_share + - MEDIA_THUMBS_DIR=/mnt/nfs_share/.thumbnails + - MAX_CONCURRENT_TRANSCODING=2 # Limit concurrent transcoding operations + volumes: + - /mnt/nfs_share:/mnt/nfs_share + ports: + - "8090:8090" + networks: + - usda-vision-network + deploy: + resources: + limits: + cpus: '4' # Limit to 4 CPU cores (adjust based on your system) + memory: 2G # Limit to 2GB RAM per container + reservations: + cpus: '1' # Reserve at least 1 CPU core + memory: 512M # Reserve at least 512MB RAM + # Alternative syntax for older Docker Compose versions: + # cpus: '4' + # mem_limit: 2g + # mem_reservation: 512m mediamtx: container_name: usda-vision-mediamtx diff --git a/scheduling-remote/src/components/HorizontalTimelineCalendar.tsx b/scheduling-remote/src/components/HorizontalTimelineCalendar.tsx index aefd77b..33d2235 100644 --- a/scheduling-remote/src/components/HorizontalTimelineCalendar.tsx +++ b/scheduling-remote/src/components/HorizontalTimelineCalendar.tsx @@ -67,6 +67,7 @@ function RepetitionBorder({ onScheduleRepetition, visibleMarkers, getTimePosition, + isScheduledInDb = false, children }: { left: number @@ -91,6 +92,7 @@ function RepetitionBorder({ onScheduleRepetition?: (repId: string, experimentId: string) => void visibleMarkers: Array<{ id: string; startTime: Date; assignedConductors: string[] }> getTimePosition: (time: Date) => number + isScheduledInDb?: boolean children?: React.ReactNode }) { const [isHovered, setIsHovered] = useState(false) @@ -148,6 +150,9 @@ function RepetitionBorder({ ? '8px 0 0 8px' // No radius on right side (markers extend to future) : '8px' // Full radius (default) + // Muted styling for repetitions that have been fully scheduled in DB (gray out, but don't collapse) + const isMuted = isScheduledInDb && !isHovered && !isDragging + return (
{/* Text content (non-clickable) */}
- {phaseName &&
{phaseName}
} - {experimentNumber !== undefined &&
Exp {experimentNumber}
} - {repetitionNumber !== undefined &&
Rep {repetitionNumber}
} + {isScheduledInDb ? ( + <> + {experimentNumber !== undefined &&
{`Exp ${experimentNumber}`}
} + {repetitionNumber !== undefined &&
{`Rep ${repetitionNumber}`}
} + + ) : ( + <> + {phaseName &&
{phaseName}
} + {experimentNumber !== undefined &&
Exp {experimentNumber}
} + {repetitionNumber !== undefined &&
Rep {repetitionNumber}
} + + )}
{/* Go to repetition button */} @@ -215,7 +232,7 @@ function RepetitionBorder({ )} - + {rep.scheduled_date ? ( + + ) : ( + + )}
)} diff --git a/scripts/docker-compose-reset.sh b/scripts/docker-compose-reset.sh index 8183614..853563b 100755 --- a/scripts/docker-compose-reset.sh +++ b/scripts/docker-compose-reset.sh @@ -60,57 +60,69 @@ echo "4. Rebuilding and starting all services in detached mode..." docker compose up --build -d echo "" -echo "5. Waiting for Supabase database to be ready..." -# Wait for database to be healthy -MAX_WAIT=60 -WAIT_COUNT=0 -while [ $WAIT_COUNT -lt $MAX_WAIT ]; do - if docker compose ps supabase-db | grep -q "healthy"; then - echo " ✓ Supabase database is healthy" - break - fi - echo " Waiting for database... ($WAIT_COUNT/$MAX_WAIT seconds)" - sleep 2 - WAIT_COUNT=$((WAIT_COUNT + 2)) -done +echo "5. Waiting for Supabase database to be ready (if configured)..." -if [ $WAIT_COUNT -ge $MAX_WAIT ]; then - echo " ⚠ Warning: Database may not be fully ready" +# Only wait for Supabase if the supabase-db service exists in docker-compose.yml +if docker compose config --services 2>/dev/null | grep -q "^supabase-db$"; then + # Wait for database to be healthy + MAX_WAIT=60 + WAIT_COUNT=0 + while [ $WAIT_COUNT -lt $MAX_WAIT ]; do + if docker compose ps supabase-db | grep -q "healthy"; then + echo " ✓ Supabase database is healthy" + break + fi + echo " Waiting for database... ($WAIT_COUNT/$MAX_WAIT seconds)" + sleep 2 + WAIT_COUNT=$((WAIT_COUNT + 2)) + done + + if [ $WAIT_COUNT -ge $MAX_WAIT ]; then + echo " ⚠ Warning: Database may not be fully ready" + fi +else + echo " - Supabase services are currently disabled in docker-compose.yml; skipping DB wait step." fi echo "" -echo "6. Waiting for Supabase migrations to complete..." -# Wait for migration container to complete (it has restart: "no", so it should exit when done) -MAX_WAIT=120 -WAIT_COUNT=0 -MIGRATE_CONTAINER="usda-vision-supabase-migrate" +echo "6. Waiting for Supabase migrations to complete (if configured)..." -while [ $WAIT_COUNT -lt $MAX_WAIT ]; do - # Check if container exists and its status - if docker ps -a --format "{{.Names}}\t{{.Status}}" | grep -q "^${MIGRATE_CONTAINER}"; then - CONTAINER_STATUS=$(docker ps -a --format "{{.Names}}\t{{.Status}}" | grep "^${MIGRATE_CONTAINER}" | awk '{print $2}') - - if echo "$CONTAINER_STATUS" | grep -q "Exited"; then - EXIT_CODE=$(docker inspect "$MIGRATE_CONTAINER" --format='{{.State.ExitCode}}' 2>/dev/null || echo "1") - if [ "$EXIT_CODE" = "0" ]; then - echo " ✓ Supabase migrations completed successfully" - break - else - echo " ⚠ Warning: Migrations may have failed (exit code: $EXIT_CODE)" - echo " Check logs with: docker compose logs supabase-migrate" - break +# Only wait for the migration container if the supabase-migrate service exists +if docker compose config --services 2>/dev/null | grep -q "^supabase-migrate$"; then + # Wait for migration container to complete (it has restart: "no", so it should exit when done) + MAX_WAIT=120 + WAIT_COUNT=0 + MIGRATE_CONTAINER="usda-vision-supabase-migrate" + + while [ $WAIT_COUNT -lt $MAX_WAIT ]; do + # Check if container exists and its status + if docker ps -a --format "{{.Names}}\t{{.Status}}" | grep -q "^${MIGRATE_CONTAINER}"; then + CONTAINER_STATUS=$(docker ps -a --format "{{.Names}}\t{{.Status}}" | grep "^${MIGRATE_CONTAINER}" | awk '{print $2}') + + if echo "$CONTAINER_STATUS" | grep -q "Exited"; then + EXIT_CODE=$(docker inspect "$MIGRATE_CONTAINER" --format='{{.State.ExitCode}}' 2>/dev/null || echo "1") + if [ "$EXIT_CODE" = "0" ]; then + echo " ✓ Supabase migrations completed successfully" + break + else + echo " ⚠ Warning: Migrations may have failed (exit code: $EXIT_CODE)" + echo " Check logs with: docker compose logs supabase-migrate" + break + fi fi fi - fi - - echo " Waiting for migrations... ($WAIT_COUNT/$MAX_WAIT seconds)" - sleep 2 - WAIT_COUNT=$((WAIT_COUNT + 2)) -done + + echo " Waiting for migrations... ($WAIT_COUNT/$MAX_WAIT seconds)" + sleep 2 + WAIT_COUNT=$((WAIT_COUNT + 2)) + done -if [ $WAIT_COUNT -ge $MAX_WAIT ]; then - echo " ⚠ Warning: Migration timeout - check logs with: docker compose logs supabase-migrate" - echo " Note: Migrations may still be running or the container may not have started yet" + if [ $WAIT_COUNT -ge $MAX_WAIT ]; then + echo " ⚠ Warning: Migration timeout - check logs with: docker compose logs supabase-migrate" + echo " Note: Migrations may still be running or the container may not have started yet" + fi +else + echo " - Supabase migration service is currently disabled in docker-compose.yml; skipping migration wait step." fi echo ""