Skip to content

Fix notification-permission flow and onboarding copy for system test notifications#1024

Merged
senamakel merged 4 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/system-notification
Apr 29, 2026
Merged

Fix notification-permission flow and onboarding copy for system test notifications#1024
senamakel merged 4 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/system-notification

Conversation

@YellowSnnowmann
Copy link
Copy Markdown
Contributor

@YellowSnnowmann YellowSnnowmann commented Apr 29, 2026

Summary

  • Added explicit native notification delivery result handling in Tauri bridge:

    • delivered
    • reason
    • error
    • Enables accurate UI success/failure states
  • Separated permission logic:

    • Permission state check
    • Permission request
    • Prevents OS prompts on modal open
  • Updated onboarding modal flow:

    • Prompt only on user action
    • Show actionable guidance when permission is denied
    • Provide clear instructions if user doesn’t see notifications
  • Added Vitest coverage:

    • Permission granted
    • Permission denied
    • Send failure
    • Retry-after-grant behavior
  • Updated test expectations to match final success messaging


Problem

  • Modal opening triggered request_permission prematurely:

    • Unexpected OS prompts
    • Confusing UX
  • UI states not aligned with real outcomes:

    • Permission denied vs send failure not clearly distinguished
  • Tests were outdated:

    • Did not match updated success messaging
    • Increased regression risk

Solution

  • Refactor permission handling:

    • getNotificationPermissionState({ requestIfNeeded: false })
    • Used on modal mount to avoid auto prompts
  • Keep permission request explicit:

    • ensureNotificationPermission() triggered on user click
  • Improve send flow:

    • showNativeNotification() returns structured result
    • Map results to clear UI states
  • Improve UX messaging:

    • Guide users to:
      • Allow notifications
      • Enable persistent banner style if needed
  • Expand test coverage:

    • Cover all major decision branches
    • Include retry flow after permission grant

Submission Checklist

  • Unit tests

    • Vitest (app/) and/or cargo test (core) for updated logic
  • E2E / Integration

    • For flows crossing:
      • UI → Tauri → sidecar → JSON-RPC
    • Use:
      • app/test/e2e
      • mock backend
      • tests/json_rpc_e2e.rs
  • N/A

    • If not applicable, document reason
  • Doc comments

    • Rust: /// / //!
    • TypeScript: JSDoc or module/file headers
  • Inline comments

    • Add where logic or edge cases need clarification
    • Keep concise and grep-friendly

Impact

  • Runtime / Platform

    • Affects desktop notification onboarding flow (Tauri)
    • No impact on mobile or CLI
  • Compatibility

    • Backward-compatible TS bridge changes
    • Existing callers benefit from richer result handling
  • Security / Privacy

    • Improved UX by avoiding unsolicited permission prompts
  • Performance

    • Negligible impact
    • Mostly UI/control-flow improvements

Related

Summary by CodeRabbit

  • Bug Fixes
    • Removed timed "queued" notification flow for faster feedback
    • Better detection of OS notification permission and clearer guidance when permission is denied or prompt
    • Improved handling and messaging for delivery failures and non-desktop environments (immediate error)
    • Prevents duplicate sends while a test is in progress; updates button labels and success/error copy for clarity

… tests

- Updated notification permission management to include new states: 'unknown', 'prompt', and 'not_tauri'.
- Improved user feedback for notification permission status in the UI.
- Added tests for notification permission flow, including success, denial, and retry scenarios.
- Refactored notification sending logic to handle errors more gracefully.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

📝 Walkthrough
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 accurately captures the main change: refactoring the notification-permission flow and updating onboarding copy for system test notifications, which aligns with the primary objective of the PR.
Linked Issues check ✅ Passed The PR addresses all acceptance criteria from #990: returns structured delivery results, implements permission state checks, provides clear success/failure states, supports retry flow, and adds comprehensive tests covering required scenarios.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the notification-permission flow: bridge improvements, modal logic updates, test coverage, and re-exporting isTauri for public use—all necessary for the fix.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Review rate limit: 4/5 reviews remaining, refill in 12 minutes.

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

@YellowSnnowmann YellowSnnowmann marked this pull request as ready for review April 29, 2026 13:06
@YellowSnnowmann YellowSnnowmann requested a review from a team April 29, 2026 13:06
Copy link
Copy Markdown
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/components/OpenhumanLinkModal.tsx`:
- Around line 221-224: The denial branch calls getNotificationPermissionState()
with default options which re-triggers a permission request; change the call in
the if (!granted) path to call getNotificationPermissionState with
requestIfNeeded: false (or the equivalent option your helper accepts) so it only
reads the current state without prompting, then pass that result to
setPermissionState; locate this change around ensureNotificationPermission,
getNotificationPermissionState, and setPermissionState in
OpenhumanLinkModal.tsx.
- Around line 213-217: Replace the direct runtime check coreIsTauri() in
OpenhumanLinkModal (the block that calls setStatus('error') / setError(...))
with the shared helper isTauri() imported from
app/src/services/webviewAccountService.ts; update the import to pull isTauri(),
use isTauri() in place of coreIsTauri(), and ensure the surrounding code (any
invoke calls) remains wrapped in try/catch if applicable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d84a6906-8051-43d8-8b28-6948bae833ed

📥 Commits

Reviewing files that changed from the base of the PR and between b11b8f3 and bf7702f.

📒 Files selected for processing (3)
  • app/src/components/OpenhumanLinkModal.tsx
  • app/src/components/__tests__/OpenhumanLinkModal.notifications.test.tsx
  • app/src/lib/nativeNotifications/tauriBridge.ts

Comment thread app/src/components/OpenhumanLinkModal.tsx Outdated
Comment thread app/src/components/OpenhumanLinkModal.tsx
Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/components/OpenhumanLinkModal.tsx`:
- Around line 220-244: When ensureNotificationPermission() resolves true you
must update the UI permission state immediately instead of only after a
successful send; call setPermissionState('granted') as soon as granted is true
(before calling showNativeNotification) so the UI distinguishes “permission
granted but send failed” from “permission denied.” In the block using
ensureNotificationPermission(), move or add setPermissionState('granted') right
after the granted check (and do the same for the similar block around
showNativeNotification at 257-272), leaving the existing error handling
(setStatus/setError) for send failures intact so send failures do not revert
permission state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5153a181-a3d8-4d87-9613-651314ea4c01

📥 Commits

Reviewing files that changed from the base of the PR and between bf7702f and a81c557.

📒 Files selected for processing (2)
  • app/src/components/OpenhumanLinkModal.tsx
  • app/src/services/webviewAccountService.ts
✅ Files skipped from review due to trivial changes (1)
  • app/src/services/webviewAccountService.ts

Comment on lines +220 to 244
const granted = await ensureNotificationPermission();
if (!granted) {
const nextState = await getNotificationPermissionState({ requestIfNeeded: false });
setPermissionState(nextState);
setStatus('error');
setError(
'Notification permission is off. Enable OpenHuman in System Settings → Notifications, then retry.'
);
return;
}
await showNativeNotification({
const sendResult = await showNativeNotification({
title: 'OpenHuman is good to go',
body: 'You will get pings here when something needs your attention.',
tag: 'welcome-notification-test',
});
if (cancelledRef.current) {
if (!sendResult.delivered) {
setStatus('error');
setError(
sendResult.error ??
'OpenHuman could not trigger a system notification. Check OS notification settings and retry.'
);
return;
}
setPermissionState('granted');
setStatus('sent');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Keep permissionState in sync even when delivery fails.

ensureNotificationPermission() returning true means OS permission is already granted, but permissionState is only set to 'granted' after a successful send. If send fails, the UI can still show the prompt guidance block, which is misleading and blurs permission-denied vs send-failed states.

Proposed fix
       const granted = await ensureNotificationPermission();
       if (!granted) {
         const nextState = await getNotificationPermissionState({ requestIfNeeded: false });
         setPermissionState(nextState);
         setStatus('error');
         setError(
-          'Notification permission is off. Enable OpenHuman in System Settings → Notifications, then retry.'
+          nextState === 'denied'
+            ? 'Notification permission is off. Enable OpenHuman in System Settings → Notifications, then retry.'
+            : 'Notification permission was not granted. Tap Send test notification and allow permission in the OS prompt.'
         );
         return;
       }
+      setPermissionState('granted');
       const sendResult = await showNativeNotification({
         title: 'OpenHuman is good to go',
         body: 'You will get pings here when something needs your attention.',
         tag: 'welcome-notification-test',
       });
       if (!sendResult.delivered) {
         setStatus('error');
         setError(
           sendResult.error ??
             'OpenHuman could not trigger a system notification. Check OS notification settings and retry.'
         );
         return;
       }
-      setPermissionState('granted');
       setStatus('sent');

Also applies to: 257-272

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/OpenhumanLinkModal.tsx` around lines 220 - 244, When
ensureNotificationPermission() resolves true you must update the UI permission
state immediately instead of only after a successful send; call
setPermissionState('granted') as soon as granted is true (before calling
showNativeNotification) so the UI distinguishes “permission granted but send
failed” from “permission denied.” In the block using
ensureNotificationPermission(), move or add setPermissionState('granted') right
after the granted check (and do the same for the similar block around
showNativeNotification at 257-272), leaving the existing error handling
(setStatus/setError) for send failures intact so send failures do not revert
permission state.

@senamakel senamakel merged commit 078a6b2 into tinyhumansai:main Apr 29, 2026
9 checks passed
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
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.

Fix test notification button not showing system notification

2 participants