Skip to content

Conversation

@rohan-pandeyy
Copy link
Contributor

@rohan-pandeyy rohan-pandeyy commented Jan 9, 2026

fixes #875

Description

Improves camera permission handling to prevent accidental denial and provide clear recovery guidance when denial occurs.

Implementations

Pre-Confirmation Dialog

Before triggering the OS permission prompt, users now see a warning explaining:

  • Permission will be requested next
  • Clicking "Block" may be permanent on some platforms
  • Only shown once per user (acknowledgment persisted to localStorage)

Platform-Specific Recovery UX

When permission is denied:

Platform Action Button Behavior
Windows "Learn how to fix this" Opens troubleshooting docs
macOS "Open Settings" Deep-links to System Preferences → Camera (Still needs testing)
Linux "Learn how to fix this" Troubleshoot docs need guidance for Linux

Troubleshooting Documentation

Added docs/Camera-Permission-Troubleshooting.md covering:

  • Why camera permission gets stuck (WebView2/WebKitGTK persistence)
  • Windows recovery steps (%LOCALAPPDATA%\org.aossie.pictopy\EBWebView)

Changes

  • FaceSearchDialog.tsx: Pre-confirmation dialog, platform detection, recovery dialogs
  • InfoDialog.tsx: Extended with primaryAction prop and warning variant
  • infoDialog.ts: Updated types for new dialog features
  • Cargo.toml/main.rs: Added tauri-plugin-os for platform detection
  • mkdocs.yml: Added troubleshooting section to navigation
  • docs/Camera-Permission-Troubleshooting.md: New documentation

Testing

  • Pre-confirmation dialog appears on first webcam click
  • "Continue" persists acknowledgment (dialog never shown again)
  • "Close" returns to FaceSearch dialog (no persistence)
  • Permission denial shows platform-appropriate recovery dialog
  • "Learn how to fix this" opens docs (Windows/Linux)
  • "Open Settings" deep-links to System Preferences (macOS)
  • Fallback error dialogs incase any action button fails

Screenshots

image image

Future Work

Docs require additional troubleshooting guide for MacOS and Linux. @rahulharpal1603 can we please open a separate documentation issue regarding the two? This documentation issue will ask for a proper step-wise for resetting permissions on MacOS and Linux.

Summary by CodeRabbit

  • New Features

    • Cross-platform camera permission handling with OS-specific guidance and actions
    • Enhanced dialogs: primary action support and new warning variant for clearer prompts
  • Bug Fixes / UX

    • Improved camera access workflow with clearer error messages and actionable troubleshooting options
  • Documentation

    • Added camera permission troubleshooting guide and updated docs navigation with a Troubleshooting section

✏️ Tip: You can customize this high-level summary in your review settings.

Adds a detailed troubleshooting guide for camera permissions on Windows, updates the FaceSearchDialog to handle permission denial with platform-specific dialogs and recovery actions, and enhances InfoDialog to support warnings and primary actions. Also adds the tauri-plugin-os dependency for platform detection, updates related types, and includes the new documentation in the navigation.
@github-actions github-actions bot added bug Something isn't working frontend labels Jan 9, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

Adds cross-platform camera permission recovery and UI: OS detection and tauri OS plugin integration; enhanced InfoDialog/types for primary actions and warning variant; FaceSearchDialog updated with pre-confirmation, platform-tailored permission-denied flows and handlers; Windows-specific troubleshooting doc and mkdocs nav entry.

Changes

Cohort / File(s) Summary
Documentation & Site Config
docs/Camera-Permission-Troubleshooting.md, mkdocs.yml
New Windows-specific camera permission troubleshooting doc (WebView2 data-folder recovery); mkdocs.yml restructured and new Troubleshooting nav entry + social links.
Tauri OS Plugin
frontend/src-tauri/Cargo.toml, frontend/src-tauri/src/main.rs, frontend/package.json
Added tauri-plugin-os / @tauri-apps/plugin-os dependency and initialized plugin in Tauri builder.
Dialog Types & Component
frontend/src/types/infoDialog.ts, frontend/src/components/Dialog/InfoDialog.tsx
Extended InfoDialog: new warning variant; message accepts ReactNode; added InfoDialogAction/primaryAction; onClose support and primaryAction rendering.
Feature: Face Search / Camera Handling
frontend/src/components/Dialog/FaceSearchDialog.tsx
Added OS detection, platformSettings (macOS/Windows/Linux), pre-permission confirmation dialog, permission-denied dialog with platform-specific actions (open settings, troubleshooting link), and detailed error handling for NotAllowedError / NotFoundError / other camera errors.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant FaceSearchDialog
    participant InfoDialog
    participant OS as OS/Browser
    participant Settings as OS Settings / Troubleshoot URL

    User->>FaceSearchDialog: Click "Use Webcam"
    FaceSearchDialog->>FaceSearchDialog: Detect OS + platformSettings
    FaceSearchDialog->>InfoDialog: Show pre-confirmation
    User->>InfoDialog: Confirm
    InfoDialog->>FaceSearchDialog: Trigger camera request
    FaceSearchDialog->>OS: Request camera access

    alt Permission Granted
        OS-->>FaceSearchDialog: MediaStream
        FaceSearchDialog->>User: Start webcam face detection
    else Permission Denied (NotAllowedError)
        OS-->>FaceSearchDialog: NotAllowedError
        FaceSearchDialog->>InfoDialog: Show permission-denied (platform content)
        User->>InfoDialog: Choose "Open Settings" or "Learn How to Fix"
        InfoDialog->>Settings: Open OS settings or troubleshooting URL
    else No Camera (NotFoundError)
        OS-->>FaceSearchDialog: NotFoundError
        FaceSearchDialog->>InfoDialog: Show "No camera found" message
    else Other Error
        OS-->>FaceSearchDialog: Error
        FaceSearchDialog->>InfoDialog: Show generic camera error
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

enhancement, documentation

Suggested reviewers

  • rahulharpal1603

Poem

🐰 I hopped through dialogs, settings, and more,
Guided users back to the camera door.
Windows, Mac, Linux — each gets a clue,
No more trapped states, retries anew.
Hooray for recovery — a joyful chew! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 clearly and specifically describes the main change: adding a confirmation dialog and troubleshooting guide to handle permanent webcam permission denial.
Linked Issues check ✅ Passed The PR comprehensively addresses all coding requirements from issue #875: pre-confirmation dialog before permission prompt, platform-specific recovery dialogs with actionable options, troubleshooting documentation, platform detection, and informative error states replacing the terminal error modal.
Out of Scope Changes check ✅ Passed All changes directly support the primary objective of preventing permanent webcam permission denial: UI components for confirmation/recovery dialogs, type definitions for enhanced dialogs, platform detection via tauri-plugin-os, documentation, and configuration updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92b64ef and c0daf2f.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • frontend/package.json
⏰ 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). (3)
  • 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)

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: 3

🤖 Fix all issues with AI agents
In @docs/Camera-Permission-Troubleshooting.md:
- Around line 34-36: The fenced code block that shows the path
"%LOCALAPPDATA%\org.aossie.pictopy" lacks a language identifier; update the
markdown by adding a language tag (e.g., "text") after the opening triple
backticks for that code block so it becomes ```text and enables proper syntax
highlighting for the shown path.

In @frontend/src/components/Dialog/FaceSearchDialog.tsx:
- Line 24: The component FaceSearchDialog.tsx imports '@tauri-apps/plugin-os'
but the package is missing from frontend dependencies; add
@tauri-apps/plugin-os@^2.0.0 to frontend/package.json by running the install
command (npm add @tauri-apps/plugin-os@^2.0.0) so the import in
FaceSearchDialog.tsx resolves and the project builds.

In @frontend/src/components/Dialog/InfoDialog.tsx:
- Around line 77-82: The DialogDescription usage passes a non-functional asChild
prop — remove the asChild prop and its conditional logic since
DialogPrimitive.Description ignores it; instead render the message directly
inside DialogDescription (use {typeof message === 'string' ? message : message}
or, if you need to support passing custom child elements, implement the Slot
pattern like other components such as Button/Badge and have DialogDescription
accept/render a Slot) so the extra <div> wrapper and asChild check are
eliminated and children render correctly.
🧹 Nitpick comments (2)
frontend/src-tauri/Cargo.toml (1)

38-38: Consider pinning to a specific minor/patch version for reproducible builds.

The version specifier "2" allows any 2.x version (currently up to 2.3.2), which can introduce unexpected updates. Pinning to a specific version like 2.3.2 ensures reproducible builds across environments.

frontend/src/components/Dialog/FaceSearchDialog.tsx (1)

195-226: Camera permission flow handles error types appropriately.

Good categorization of NotAllowedError, NotFoundError, and generic errors with distinct user messaging. The stream tracks are properly stopped after permission verification.

One minor observation: Line 205 setIsDialogOpen(false) is redundant since it was already set to false in handleWebCamClick (line 177) before this function is called.

Optional: Remove redundant state update
      const err = error as DOMException;
      if (err.name === 'NotAllowedError') {
        // Permission explicitly denied. Shows recovery dialog
-       setIsDialogOpen(false);
        setShowPermissionDeniedDialog(true);
      } else if (err.name === 'NotFoundError') {
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3af96c and 92b64ef.

⛔ Files ignored due to path filters (1)
  • frontend/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • docs/Camera-Permission-Troubleshooting.md
  • frontend/src-tauri/Cargo.toml
  • frontend/src-tauri/src/main.rs
  • frontend/src/components/Dialog/FaceSearchDialog.tsx
  • frontend/src/components/Dialog/InfoDialog.tsx
  • frontend/src/types/infoDialog.ts
  • mkdocs.yml
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/components/Dialog/InfoDialog.tsx (4)
frontend/src/types/infoDialog.ts (1)
  • InfoDialogProps (12-19)
frontend/src/features/infoDialogSlice.ts (1)
  • hideInfoDialog (31-37)
frontend/src/components/ui/dialog.tsx (3)
  • DialogDescription (136-136)
  • DialogHeader (138-138)
  • DialogFooter (137-137)
frontend/src/components/ui/button.tsx (1)
  • Button (59-59)
🪛 GitHub Actions: PR Check Build
frontend/src/components/Dialog/FaceSearchDialog.tsx

[error] 24-24: Cannot find module '@tauri-apps/plugin-os' or its corresponding type declarations. (TS2307) - during npm run tauri build

🪛 LanguageTool
docs/Camera-Permission-Troubleshooting.md

[style] ~14-~14: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 1424 characters long)
Context: ... --- ## Recovery Steps ### Windows: !!! warning "This is a destructive workarou...

(EN_EXCESSIVE_EXCLAMATION)

🪛 markdownlint-cli2 (0.18.1)
docs/Camera-Permission-Troubleshooting.md

34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ 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). (1)
  • GitHub Check: Backend Tests
🔇 Additional comments (17)
frontend/src-tauri/src/main.rs (1)

11-11: LGTM!

The OS plugin initialization is properly placed in the Tauri builder chain and enables platform detection for the camera permission recovery flow.

docs/Camera-Permission-Troubleshooting.md (1)

1-56: Well-structured troubleshooting documentation.

The documentation clearly explains the camera permission issue on Windows and provides actionable recovery steps. The warning about the destructive nature of the workaround is prominently displayed, which is important for user awareness.

frontend/src/types/infoDialog.ts (1)

1-19: LGTM! Well-structured type definitions.

The type definitions properly support the enhanced dialog functionality with:

  • Expanded variant types including 'warning'
  • New InfoDialogAction interface for primary actions with optional icon and disabled state
  • Support for ReactNode messages enabling rich content
  • All new properties are appropriately optional
frontend/src/components/Dialog/InfoDialog.tsx (4)

16-18: Good extension of the InfoDialogProps interface.

The ExtendedInfoDialogProps interface properly extends the base props to support custom close handlers, enabling flexible dialog behavior when used in different contexts.


31-37: Correct priority handling for close callbacks.

The handleClose logic correctly prioritizes the custom onClose handler when provided, falling back to the Redux action. This enables both standalone usage (with custom onClose) and Redux-integrated usage (with dispatch).


47-52: LGTM! Appropriate warning variant styling.

The warning variant uses appropriate visual cues (yellow color, AlertTriangle icon) to distinguish it from info and error states, supporting the camera permission pre-confirmation use case.


84-107: Well-implemented primaryAction support.

The DialogFooter correctly:

  • Renders the primaryAction button with optional icon and disabled state
  • Adjusts the Close button variant to 'outline' when a primaryAction exists (better visual hierarchy)
  • Maintains proper spacing with flex-row and gap classes
  • Preserves the existing showCloseButton conditional behavior
mkdocs.yml (2)

74-75: LGTM - Troubleshooting navigation entry added.

The new Troubleshooting section correctly references the Camera Permission documentation. MkDocs will resolve Camera-Permission-Troubleshooting.md relative to the docs/ directory.


78-93: LGTM - Social links section well structured.

The social links are properly formatted with appropriate icons, URLs, and accessible names.

frontend/src/components/Dialog/FaceSearchDialog.tsx (8)

79-95: Defensive storage access pattern is appropriate.

The nested try/catch fallback from localStorage to sessionStorage handles restricted storage environments (e.g., private browsing). The pattern is acceptable for this use case.


105-112: OS detection effect is correctly structured.

The empty dependency array ensures one-time initialization, and the fallback to default platform settings on error is appropriate.


114-142: Well-structured external link handlers with appropriate error recovery.

Both handlers include null checks, proper async/await usage, and user-friendly error dialogs with manual instructions as fallback.


239-274: Clear platform-specific permission denial messaging.

The conditional rendering based on isWebViewPermission appropriately distinguishes between Windows WebView2 permission handling and macOS/Linux OS-level permissions.


337-358: Permission denied dialog with platform-aware actions.

The conditional primaryAction logic correctly prioritizes settingsUrl (macOS) over troubleshootUrl (Windows) with a fallback to undefined (Linux/default). The nested ternary is acceptable given the clear platform hierarchy.


360-388: Pre-confirmation dialog provides appropriate user warning.

The amber-colored warning about permanent permission blocking is important UX for preventing accidental denials. The onClose handler correctly reopens the main dialog for navigation.


29-38: Type definition and constants are well-structured.

The PlatformSettings interface clearly defines the platform-specific configuration shape, and externalizing TROUBLESHOOT_URL as a constant improves maintainability.


40-71: Platform settings correctly configured for different OS behaviors.

The macOS deep link URL format (x-apple.systempreferences:com.apple.preference.security?Privacy_Camera) is valid for opening System Preferences Camera privacy settings. Windows correctly identifies WebView2-based permission storage, and the default fallback provides generic guidance.

Comment on lines +34 to +36
```
%LOCALAPPDATA%\org.aossie.pictopy
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add language identifier to the fenced code block.

The code block should specify a language identifier for proper syntax highlighting in the documentation.

📝 Proposed fix
-```
+```text
 %LOCALAPPDATA%\org.aossie.pictopy
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

34-34: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In @docs/Camera-Permission-Troubleshooting.md around lines 34 - 36, The fenced
code block that shows the path "%LOCALAPPDATA%\org.aossie.pictopy" lacks a
language identifier; update the markdown by adding a language tag (e.g., "text")
after the opening triple backticks for that code block so it becomes ```text and
enables proper syntax highlighting for the shown path.

Comment on lines +77 to 82
<DialogDescription
className={messageColor}
asChild={typeof message !== 'string'}
>
{typeof message === 'string' ? message : <div>{message}</div>}
</DialogDescription>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the InfoDialog.tsx file to see the context
cd frontend/src/components/Dialog || cd . 
ls -la | grep -i dialog

# Find DialogDescription imports and definitions
rg -n 'DialogDescription' --type=tsx --type=ts -B 2 -A 2 | head -50

# Check for asChild usage patterns in the codebase
rg -n 'asChild' --type=tsx --type=ts -C 3

Repository: AOSSIE-Org/PictoPy

Length of output: 272


🏁 Script executed:

#!/bin/bash
# Find and read the InfoDialog.tsx file
cat -n frontend/src/components/Dialog/InfoDialog.tsx

# Search for DialogDescription in the codebase
rg 'DialogDescription' --glob='*.tsx' --glob='*.ts' -B 2 -A 2

# Check for asChild usage patterns
rg 'asChild' --glob='*.tsx' --glob='*.ts' -C 3

Repository: AOSSIE-Org/PictoPy

Length of output: 19019


🏁 Script executed:

#!/bin/bash
# Read the DialogDescription implementation
cat -n frontend/src/components/ui/dialog.tsx | head -100

# Find the complete DialogDescription function
rg -A 15 'function DialogDescription' frontend/src/components/ui/dialog.tsx

Repository: AOSSIE-Org/PictoPy

Length of output: 4360


🏁 Script executed:

#!/bin/bash
# Check if there are any node_modules or package.json to understand Radix UI version
cat -n frontend/package.json | grep -A 5 -B 5 'radix-ui'

# Also check if asChild is used anywhere else with Description-like components
rg 'Description.*asChild' --glob='*.tsx' --glob='*.ts'

Repository: AOSSIE-Org/PictoPy

Length of output: 1043


🏁 Script executed:

#!/bin/bash
# Check the Radix UI react-dialog types/exports to understand what asChild does
# First, let's see what is actually exported from DialogPrimitive
rg 'DialogPrimitive\.' frontend/src/components/ui/dialog.tsx

# Check if there's any asChild handling in the wrapper
cat frontend/src/components/ui/dialog.tsx | grep -n 'asChild'

# Search for imports that might indicate asChild support
rg 'import.*Slot' frontend/src/components/ui/dialog.tsx

Repository: AOSSIE-Org/PictoPy

Length of output: 1038


🏁 Script executed:

#!/bin/bash
# Let's check what props DialogPrimitive.Description actually accepts
# by looking at its TypeScript definitions or checking actual usage

# First, check if Slot is imported or used in dialog.tsx
cat frontend/src/components/ui/dialog.tsx

# Look for patterns of how asChild is properly implemented with Slot
rg -B 2 -A 2 'const Comp = asChild.*Slot' frontend/src/components/ui/

Repository: AOSSIE-Org/PictoPy

Length of output: 6320


🏁 Script executed:

#!/bin/bash
# Search for any Radix Dialog documentation or type hints in the codebase
rg 'DialogPrimitive.Description' --glob='*.ts' --glob='*.tsx' -B 5 -A 10

# Check if there are any TypeScript errors or type definitions that mention asChild for Description
fd -e d.ts node_modules/@radix-ui/react-dialog 2>/dev/null | head -5

Repository: AOSSIE-Org/PictoPy

Length of output: 1076


Remove the non-functional asChild prop from DialogDescription.

The asChild prop is not supported by the DialogDescription wrapper. While the prop is passed through via ...props, DialogPrimitive.Description ignores it, making the conditional logic ineffective. The <div> wrapper is always rendered regardless of the asChild value. Either remove the asChild prop entirely or implement proper support using the Slot pattern (as done in Button, Badge, and other components).

🤖 Prompt for AI Agents
In @frontend/src/components/Dialog/InfoDialog.tsx around lines 77 - 82, The
DialogDescription usage passes a non-functional asChild prop — remove the
asChild prop and its conditional logic since DialogPrimitive.Description ignores
it; instead render the message directly inside DialogDescription (use {typeof
message === 'string' ? message : message} or, if you need to support passing
custom child elements, implement the Slot pattern like other components such as
Button/Badge and have DialogDescription accept/render a Slot) so the extra <div>
wrapper and asChild check are eliminated and children render correctly.

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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/package.json (1)

42-47: Pin @tauri-apps/api to match Tauri CLI version 2.9.1.

The range ">=2.0.0-beta.0" is too broad and allows version skew. The lockfile currently resolves to v2.8.0, which is older than the Tauri CLI version (2.9.1). Tauri's versioning scheme requires @tauri-apps/api to align with the Tauri CLI major.minor version. Update to "^2.9.1" or "~2.9.1" to ensure compatibility.

Proposed fix
-    "@tauri-apps/api": ">=2.0.0-beta.0",
+    "@tauri-apps/api": "^2.9.1",
     "@tauri-apps/plugin-dialog": "^2.2.0",
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92b64ef and c0daf2f.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • frontend/package.json
⏰ 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). (3)
  • 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)

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

Labels

bug Something isn't working frontend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: Webcam permission denial permanently blocks Face Detection using Webcam

1 participant