-
Notifications
You must be signed in to change notification settings - Fork 549
Confirmation Dialog & Troubleshoot Guide to Tackle Webcam Permission Permanent Denial #1005
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Confirmation Dialog & Troubleshoot Guide to Tackle Webcam Permission Permanent Denial #1005
Conversation
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.
📝 WalkthroughWalkthroughAdds 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
⏰ 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)
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. Comment |
There was a problem hiding this 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.2ensures 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 tofalseinhandleWebCamClick(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
⛔ Files ignored due to path filters (1)
frontend/src-tauri/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (7)
docs/Camera-Permission-Troubleshooting.mdfrontend/src-tauri/Cargo.tomlfrontend/src-tauri/src/main.rsfrontend/src/components/Dialog/FaceSearchDialog.tsxfrontend/src/components/Dialog/InfoDialog.tsxfrontend/src/types/infoDialog.tsmkdocs.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.mdrelative to thedocs/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
isWebViewPermissionappropriately distinguishes between Windows WebView2 permission handling and macOS/Linux OS-level permissions.
337-358: Permission denied dialog with platform-aware actions.The conditional
primaryActionlogic correctly prioritizessettingsUrl(macOS) overtroubleshootUrl(Windows) with a fallback toundefined(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
onClosehandler correctly reopens the main dialog for navigation.
29-38: Type definition and constants are well-structured.The
PlatformSettingsinterface clearly defines the platform-specific configuration shape, and externalizingTROUBLESHOOT_URLas 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.
| ``` | ||
| %LOCALAPPDATA%\org.aossie.pictopy | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| <DialogDescription | ||
| className={messageColor} | ||
| asChild={typeof message !== 'string'} | ||
| > | ||
| {typeof message === 'string' ? message : <div>{message}</div>} | ||
| </DialogDescription> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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 3Repository: 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 3Repository: 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.tsxRepository: 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.tsxRepository: 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 -5Repository: 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.
There was a problem hiding this 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/apito 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/apito 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
⛔ Files ignored due to path filters (1)
frontend/package-lock.jsonis 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)
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:
Platform-Specific Recovery UX
When permission is denied:
Troubleshooting Documentation
Added
docs/Camera-Permission-Troubleshooting.mdcovering:%LOCALAPPDATA%\org.aossie.pictopy\EBWebView)Changes
FaceSearchDialog.tsx: Pre-confirmation dialog, platform detection, recovery dialogsInfoDialog.tsx: Extended withprimaryActionprop andwarningvariantinfoDialog.ts: Updated types for new dialog featuresCargo.toml/main.rs: Addedtauri-plugin-osfor platform detectionmkdocs.yml: Added troubleshooting section to navigationdocs/Camera-Permission-Troubleshooting.md: New documentationTesting
Screenshots
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
Bug Fixes / UX
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.