Skip to content

Conversation

@rohan-pandeyy
Copy link
Contributor

@rohan-pandeyy rohan-pandeyy commented Nov 9, 2025

Closes #621

Introduces a camera selection dropdown to the webcam face search feature, allowing users to choose from multiple available video devices.

Also includes several fixes and refactoring improvements to enhance the component's robustness and maintainability.

What's new:

  • A dropdown menu is now displayed above the "Capture picture" button, listing all available cameras. The user's preference is saved to localStorage for subsequent visits.
  • The component now correctly handles cases where a screenshot fails (getScreenshot() returns null), showing an error instead of a blank UI.
  • A cleanup function in useEffect now correctly prevents state updates on unmounted components when enumerating devices.
  • Type Safety: The usePictoMutation hook and the fetchSearchedFacesBase64 API function are now strongly typed, removing the need for as Image[] type assertions.

Screenshots:

The placement of the dropdown:

image

What the dropdown displays:

image

In case capture fails:

image

Summary by CodeRabbit

  • New Features

    • Multi-camera support with a dropdown to select and persist the active camera.
    • Inline messages for "no camera detected" and a dialog when image capture fails.
  • Improvements

    • More reliable capture-and-search flow with improved device detection and clearer error handling.

Update WebCamComponent to support multiple camera devices, allowing users to select their preferred camera. Updated related API and hook types to use BackendRes and Image[], and improved error handling and device enumeration logic.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 9, 2025

Walkthrough

Adds camera enumeration and a selectable camera dropdown to the webcam face-search UI, refactors the face search API function to return BackendRes<Image[]>, and exports the BackendRes interface for reuse.

Changes

Cohort / File(s) Summary
API response typing
frontend/src/api/api-functions/face_clusters.ts, frontend/src/hooks/useQueryExtension.ts
fetchSearchedFacesBase64 now returns Promise<BackendRes<Image[]>> and the POST call is typed accordingly; BackendRes interface is exported from useQueryExtension.ts; Image type imported for payload typing.
Webcam camera selection & capture flow
frontend/src/components/WebCam/WebCamComponent.tsx
Adds device enumeration, device selection dropdown with labels and Camera icon, persists selected device to localStorage, computes video constraints from selected device, integrates typed mutation (searchByFaceMutation), adds capture error handling and fallback UI for no cameras, and updates capture/upload/search flow.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant WC as WebCamComponent
    participant Browser as MediaDevices API
    participant Storage as localStorage
    participant Mut as searchByFaceMutation
    participant API as Backend API

    User->>WC: open webcam dialog
    WC->>Browser: enumerateDevices()
    Browser-->>WC: video input devices[]
    WC->>Storage: read selectedDeviceId
    Storage-->>WC: selectedDeviceId (or null)
    WC->>WC: set devices & selectedDeviceId

    alt multiple devices
        User->>WC: open dropdown & choose device
        WC->>Storage: persist selectedDeviceId
        WC->>WC: update videoConstraints
        WC-->>User: preview updates
    else single/no device
        WC-->>User: show "No other cameras detected" message
    end

    User->>WC: click "Capture Photo"
    WC->>Browser: capture frame with selected constraints
    alt capture success
        Browser-->>WC: base64 image
        WC->>Mut: uploadImage(base64)
        Mut->>API: POST /search (typed BackendRes<Image[]>)
        API-->>Mut: results
        Mut-->>WC: onSuccess(results)
        WC-->>User: close dialog & show results
    else capture fail
        Browser-->>WC: error
        WC-->>User: show capture failure notification
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay special attention to:
    • lifecycle/timing around device enumeration and selectedDeviceId persistence in WebCamComponent.tsx (race conditions, permissions).
    • ensuring all callers of fetchSearchedFacesBase64 accept BackendRes<Image[]> and that Image typing matches backend payload.
    • mutation integration and correct error/success handling in the component.

Poem

🐇 I hopped to find each camera bright,
Dropdown open, choose left or right.
A snap, a search — the pixels cheer,
Bunny grins, results appear! 📷✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Enhancement: Add Camera Selection to Webcam Component' directly and accurately summarizes the main change - adding a camera selection dropdown feature to the webcam component.
Linked Issues check ✅ Passed All coding requirements from issue #621 are met: camera selection dropdown implemented, available devices enumerated and listed, dynamic switching with immediate preview updates, localStorage persistence, and error handling for failed captures.
Out of Scope Changes check ✅ Passed All changes align with the linked issue scope: WebCamComponent receives dropdown UI and device selection logic, face_clusters.ts and useQueryExtension.ts changes provide necessary type improvements supporting the feature.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe2f98d and 1ad9ee0.

📒 Files selected for processing (3)
  • frontend/src/api/api-functions/face_clusters.ts (2 hunks)
  • frontend/src/components/WebCam/WebCamComponent.tsx (6 hunks)
  • frontend/src/hooks/useQueryExtension.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/src/api/api-functions/face_clusters.ts (2)
frontend/src/hooks/useQueryExtension.ts (1)
  • BackendRes (19-24)
frontend/src/types/Media.ts (1)
  • Image (13-22)
frontend/src/components/WebCam/WebCamComponent.tsx (6)
frontend/src/hooks/useQueryExtension.ts (2)
  • usePictoMutation (26-78)
  • BackendRes (19-24)
frontend/src/types/Media.ts (1)
  • Image (13-22)
frontend/src/api/api-functions/face_clusters.ts (1)
  • fetchSearchedFacesBase64 (60-68)
frontend/src/hooks/useMutationFeedback.tsx (1)
  • useMutationFeedback (60-135)
frontend/src/features/infoDialogSlice.ts (1)
  • showInfoDialog (16-30)
frontend/src/features/searchSlice.ts (1)
  • startSearch (17-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Tauri Build Check (windows-latest)
  • GitHub Check: Tauri Build Check (ubuntu-22.04)
  • GitHub Check: Backend Tests
  • GitHub Check: Tauri Build Check (macos-latest, --target aarch64-apple-darwin)

Leave the trigger enabled when only one camera exists, so the 'No other cameras detected' notice is visible
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ad9ee0 and fc950ae.

📒 Files selected for processing (1)
  • frontend/src/components/WebCam/WebCamComponent.tsx (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/components/WebCam/WebCamComponent.tsx (7)
frontend/src/hooks/useQueryExtension.ts (2)
  • usePictoMutation (26-78)
  • BackendRes (19-24)
frontend/src/types/Media.ts (1)
  • Image (13-22)
frontend/src/api/api-functions/face_clusters.ts (1)
  • fetchSearchedFacesBase64 (60-68)
frontend/src/hooks/useMutationFeedback.tsx (1)
  • useMutationFeedback (60-135)
frontend/src/features/infoDialogSlice.ts (1)
  • showInfoDialog (16-30)
frontend/src/features/searchSlice.ts (1)
  • startSearch (17-20)
frontend/src/components/ui/dropdown-menu.tsx (4)
  • DropdownMenu (240-240)
  • DropdownMenuTrigger (242-242)
  • DropdownMenuContent (243-243)
  • DropdownMenuItem (246-246)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Tauri Build Check (windows-latest)
  • GitHub Check: Tauri Build Check (ubuntu-22.04)
  • GitHub Check: Tauri Build Check (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: Backend Tests
🔇 Additional comments (11)
frontend/src/components/WebCam/WebCamComponent.tsx (11)

1-1: LGTM! Necessary imports for the camera selection feature.

All new imports are properly used: useEffect for device enumeration, dropdown menu components for the camera selector UI, new icons for visual elements, and type imports for improved type safety.

Also applies to: 4-4, 13-18, 26-27


37-38: LGTM! Proper state initialization for camera selection.

The state declarations correctly type the device list and selected device ID, supporting the dynamic camera selection feature.


42-51: LGTM! Excellent type safety improvement.

The mutation is now strongly typed with explicit generic parameters, eliminating the need for as Image[] assertions and providing compile-time safety for the API response structure.


53-76: LGTM! Properly integrated with the typed mutation.

The mutation feedback correctly references the new searchByFaceMutation object and accesses the typed response data through the data property of BackendRes<Image[]>.


78-126: LGTM! Robust device enumeration with proper cleanup.

The implementation correctly:

  • Guards state updates with isMounted flag to prevent updates on unmounted components (addressing the PR objective)
  • Uses the standard pattern of requesting permission before enumerating devices to get device labels
  • Handles errors gracefully by setting an empty device list, which triggers the appropriate "No camera detected" UI
  • Prevents memory leaks with cleanup in the finally block and unmount handler
  • Restores the user's saved camera preference when available

127-134: LGTM! Clean camera selection and constraints logic.

The handler properly persists the user's camera choice to localStorage, and the video constraints correctly use the exact device ID when available, falling back to browser default otherwise.


136-152: LGTM! Proper handling of capture failures.

The null check on getScreenshot() return value correctly implements the PR objective of handling failed screenshots with a user-friendly error dialog instead of a blank UI.


159-173: LGTM! Updated to use the typed mutation.

The search handler correctly triggers the strongly-typed mutation and closes the dialog, maintaining the expected flow.


181-184: LGTM! Clean helper for device label display.

The function safely retrieves the selected camera's label with an appropriate fallback.


208-226: LGTM! Clear messaging for the no-camera case.

The conditional rendering properly handles the zero-device scenario with helpful guidance about camera connection and permissions.


232-261: Past review comment has been addressed.

The dropdown trigger is now correctly disabled only when devices.length === 0, allowing users to open the dropdown when exactly one camera is available to see the "No other cameras detected" message. The conditional content logic (line 247) properly displays this message for the single-camera case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Add Camera Selection Dropdown for Webcam Face Search

1 participant