Skip to content

Announce a new memory with a native desktop notification - #1440

Open
rohan-pandeyy wants to merge 13 commits into
AOSSIE-Org:mainfrom
rohan-pandeyy:feat/memories-notification-support
Open

Announce a new memory with a native desktop notification#1440
rohan-pandeyy wants to merge 13 commits into
AOSSIE-Org:mainfrom
rohan-pandeyy:feat/memories-notification-support

Conversation

@rohan-pandeyy

@rohan-pandeyy rohan-pandeyy commented Jul 31, 2026

Copy link
Copy Markdown
Member

Closes #1439.

Depends on #1438. This branch sits on top of it, so until that merges the diff below also carries its 6 settings commits. It cleans itself up once #1438 lands. The notification work is the last 5 commits, starting at chore(memories): add the Tauri notification plugin.

What this does

Memories only got curated when an import or a sync happened to trigger it, and nothing ever told you a new one was ready. This adds a background task in the desktop shell that asks for a run on launch, then announces the result through the operating system's own notification centre.

Acting on the notification takes you to the memory in the story viewer.

How it works

frontend/src-tauri/src/memories.rs holds the whole task:

  1. Bounded wait on /health, since the backend is spawned alongside the window
  2. GET /memories/status, and stop here if the user has memories turned off
  3. Poll every 20s while indexing_busy, up to 30 minutes
  4. POST /memories/generate
  5. Follow the run to a terminal state
  6. GET /memories/today, then emit, notify, and PATCH {notified: true}

A few decisions that are not obvious from the code:

The generate response decides how to wait, not just run_started_at. A queued: false response means today's run is either already complete or already someone else's. Only our own run can be told apart by its start time, so waiting on that value to change in either of those cases would burn the full 30 minute timeout on every launch. Not queued and running gets waited out without the check; not queued and complete skips straight to reading status.

Never curate mid-index. A run that starts while indexing is in progress scores a library whose labels are only half written, so the task waits for it to settle rather than racing it.

notified_at is what stops a memory being announced twice across launches, and notifications_enabled is re-read after the run settles so toggling it mid-run is honoured.

Focus re-runs the check, throttled to once every 6 hours and guarded by an AtomicBool. That covers the app being left open across midnight, which matters because anniversary memories are written with surface_date = today and are never generated retroactively.

Routing the user to the memory

Desktop notification click callbacks are not dependable in Tauri v2, so the OS notification is announcement only. Rust emits memory:pending whether or not it notified, and MemoryNotificationListener renders an in-app card from it. The card mounts inside the router in App.tsx, so a memory opens from any page.

Clicking the card goes through the open_memory command, which unminimizes and focuses the window before emitting memory:open. That keeps a single entry point for routing, and the card falls back to routing locally if the command is unavailable, as it is outside the desktop shell.

Turning on Desktop Notifications in settings now also calls requestPermission(), since macOS and Linux gate on an OS prompt and the switch is the only moment a user expects one. The preference saves either way and Rust re-checks the permission before every notification.

Notes for reviewers

  • notify-rust is pinned to 4.17.0 in Cargo.lock. 4.18 raised its MSRV to rustc 1.89, so on 1.88 the resolver refuses to build. A bare cargo update will undo the pin.
  • Nothing goes under plugins in tauri.conf.json. The notification plugin's config type is (), so even "notification": {} panics at startup with invalid type: map, expected unit. The "notification:default" entry in capabilities/migrated.json is the whole of the wiring.
  • src-tauri has no #[cfg(test)] anywhere, so no Rust test harness was invented for this. The task itself was verified by hand.

Verification

cd frontend && npx tsc --noEmit
cd frontend && npx jest --maxWorkers=2      # 307 passed, 34 suites
cd frontend/src-tauri && cargo fmt --check && cargo clippy

cargo clippy reports nothing in the new file. The two warnings it does emit are pre-existing in main.rs and were left alone.

Summary by CodeRabbit

  • New Features

    • Added automatic daily memory curation with in-app and optional desktop notifications.
    • Added memory controls to General Settings, including generation, notifications, slide duration, and photo limits.
    • Memory notifications can open the relevant memory directly.
  • Improvements

    • Desktop memory notifications are now disabled by default.
    • Preference updates are queued, applied optimistically, and safely rolled back if they fail.
    • Memory settings now link to General Settings.

Collapsible group beside Video Tagging, holding the generate and desktop
notification toggles plus dropdowns for seconds per photo and the photo
count bounds. The min and max pair still cross-clamps, since a value saved
by the old sliders can fall outside these options.
Its controls now live in the settings page, so the page, the
memories/settings route and ROUTES.MEMORIES_SETTINGS all go. The gear
buttons on the grid and in the story viewer point at /settings instead.
Alerts are opt-in now; the memory is waiting on the page either way.
Flipped in MemoriesPreferences, the MemoryStatusData echo and the frontend
defaults, with openapi.json regenerated to match.
The switches already did this, the three dropdown triggers did not. Rapid
selections could overlap, and each mutation rolls back to its own snapshot,
so an out-of-order failure could leave the min/max pair inconsistent.
Every write snapshotted and restored the whole preferences object, so two
overlapping saves would have the later one roll back over the earlier one.
Writes now queue, each builds from the state that actually landed before it,
and each sends only the keys it changed so the server merge cannot clobber a
concurrent edit either. Drops the unused updatePreference, which was the
whole-object path.
Both directions of the min and max cross-clamp, a stored value that is not
one of the dropdown options, and every control disabled while a save runs.
reqwest gains the json feature and tokio gains time, both needed by the
curation task. notify-rust is pinned to 4.17.0 because 4.18 needs rustc 1.89.
Nothing goes under plugins in tauri.conf.json: the plugin takes no config and
even an empty map panics at startup.
The backend only curates when asked, so nothing surfaced on a day with no
import. This waits for the backend and for indexing to settle, requests a run,
then raises a native notification for the memory it produced.

The generate response decides how to wait: run_started_at only identifies our
own run, so a run that was already queued or complete would otherwise burn the
full timeout on every launch. Focus re-runs the check at most every 6 hours,
which covers the app being left open across midnight.
Rust emits memory:pending whether or not it notified, because desktop
notification clicks are not dependable across platforms, so the in-app card is
the path that always works. Clicking it goes through the open_memory command,
which focuses the window and emits memory:open.

Lives inside the router so a memory opens from any page.
…d on

macOS and Linux gate notifications behind an OS prompt, and the switch is the
only moment a user expects one. The preference saves either way; the desktop
task re-checks the permission before every notification.
Card, dismissal, both events, and the fallback when the command is missing.
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PR adds automatic daily memory curation with native and in-app notifications. It moves memory controls into general settings, serializes preference updates with rollback isolation, removes the dedicated memory settings route, and changes notification defaults to opt-in.

Changes

Smart Memories desktop flow

Layer / File(s) Summary
Opt-in notification defaults
backend/app/schemas/memories.py, backend/app/schemas/user_preferences.py, backend/tests/test_user_preferences.py, docs/backend/backend_python/openapi.json
Memory notification defaults are now disabled in backend schemas, tests, and OpenAPI documentation.
Serialized preference updates with rollback
frontend/src/hooks/useUserPreferences.tsx, frontend/src/hooks/__tests__/useUserPreferences.test.tsx
Preference writes use a serialized queue. Each write derives from current state, applies optimistically, rolls back on failure, and sends only changed fields. Memories updates preserve nested weight patches. Failed writes do not block subsequent writes.
Memory controls in general settings
frontend/src/pages/SettingsPage/components/UserPreferencesCard.tsx, frontend/src/pages/SettingsPage/components/__tests__/UserPreferencesCard.test.tsx
Memory controls for generation, desktop notifications, slide duration, and photo bounds now live in the general settings card. Notification toggling requests OS permission when enabled. Min/max normalization keeps bounds valid during updates.
Remove dedicated memory settings route
frontend/src/components/Memories/MemoryStoryViewer.tsx, frontend/src/pages/Memories/Memories.tsx, frontend/src/routes/AppRoutes.tsx
Navigation to memory settings now points to the general settings route. The dedicated MEMORIES_SETTINGS route is removed.
Install and register native notification plugin
frontend/package.json, frontend/src-tauri/Cargo.toml, frontend/src-tauri/capabilities/migrated.json, frontend/src-tauri/src/main.rs
The Tauri app adds the notification plugin and registers it. Dependencies enable reqwest json and tokio time features. The main window focus event triggers throttled memory resume checks.
Desktop memory curation task
frontend/src-tauri/src/memories.rs
A background task launches and resumes on window focus. It waits for backend health and indexing completion, generates or observes the daily memory run, retrieves the completed memory, emits an in-app event unconditionally, optionally sends an OS notification, and persists the notification flag. HTTP, decode, and timeout failures are logged; events and notifications proceed independently.
Frontend memory notification listener
frontend/src/App.tsx, frontend/src/components/Memories/MemoryNotificationListener.tsx, frontend/src/components/Memories/__tests__/MemoryNotificationListener.test.tsx, frontend/jest.setup.ts
A React listener displays pending memories in an in-app notification. It invokes the open_memory Tauri command with fallback to local routing, invalidates the memories list query, and unsubscribes from events on unmount. Jest mocks the notification plugin.

Estimated code review effort: 4 (Complex) | ~50 minutes

Possibly related PRs

  • AOSSIE-Org/PictoPy#1433: Shares memory settings consolidation, notification default changes, and preference hook updates with this PR.
  • AOSSIE-Org/PictoPy#1438: Introduces the memory settings migration and consolidated preferences UI used as a foundation here.

Suggested labels: Python, TypeScript/JavaScript, Rust, Documentation

Poem

A rabbit wakes to find the treasure near,
A daily memory drawing ever clear.
The desktop calls with gentle chime,
Your photos wait—the perfect time.
Opt-in bells ring soft and true.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The preference write queue and removal of the dedicated memory settings page extend beyond issue #1439 and are identified as dependent work. Move preference queue and memory settings page changes to the dependent issue, or document why they are required for #1439.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: native desktop notifications for new memories.
Linked Issues check ✅ Passed The changes implement the linked issue requirements for notification integration, curation, permissions, duplicate prevention, and reliable memory navigation.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@socket-security

socket-security Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​tauri-apps/​plugin-notification@​2.3.310010010087100
Addedcargo/​tauri-plugin-notification@​2.3.390100100100100

View full report

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (3)
frontend/src/components/Memories/MemoryStoryViewer.tsx (1)

292-299: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

aria-label still says "Memory settings" after the route consolidation.

The button now navigates to ROUTES.SETTINGS (the general Settings page), but aria-label="Memory settings" at Line 295 still describes it as memory-specific settings. This finding shares one root cause with the same mismatch in Memories.tsx; see the consolidated comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/Memories/MemoryStoryViewer.tsx` around lines 292 -
299, Update the settings navigation button in MemoryStoryViewer so its
aria-label describes the general ROUTES.SETTINGS destination rather than
memory-specific settings. Change only the accessible label while preserving the
existing onClick navigation and styling.
frontend/src/pages/Memories/Memories.tsx (1)

108-116: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

aria-label still says "Memory settings" after the route consolidation.

Same issue as MemoryStoryViewer.tsx Line 295: the button now navigates to ROUTES.SETTINGS, but the label still reads "Memory settings". See the consolidated comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/Memories/Memories.tsx` around lines 108 - 116, Update the
settings navigation Button in Memories.tsx to use an aria-label that reflects
the consolidated general settings destination instead of “Memory settings”; keep
its existing ROUTES.SETTINGS navigation and styling unchanged.
frontend/src/hooks/useUserPreferences.tsx (1)

51-66: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Serialize external refetch() into the preference write model.

refetch reaches UserPreferencesCard directly via Model Manager close and window focus. Its success applies its fetched data through applyPreferences, bypassing writeQueue. If a queued write is in flight when the refetch stores newer values, a later write failure restores the write queue’s pre-write snapshot and discards the refetch result without a diagnostic. Either funnel refetched state through writeQueue or make rollback restore only the failed write’s own keys.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/hooks/useUserPreferences.tsx` around lines 51 - 66, The
preferencesQuery refetch path currently applies fetched preferences directly
through applyPreferences, bypassing writeQueue and allowing rollback to
overwrite newer refetched state. Update the useUserPreferences flow so external
refetch results are serialized through writeQueue, or constrain rollback to
restore only the failed write’s keys; preserve queued writes while retaining
newer refetched values and emit diagnostics for failures.
🧹 Nitpick comments (2)
frontend/src/pages/SettingsPage/components/UserPreferencesCard.tsx (1)

84-100: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add test coverage for the notification permission request.

toggleMemoryNotifications checks isPermissionGranted() and calls requestPermission() when the user enables desktop notifications. This is a core requirement from the linked issue. The companion test file only verifies that the switch is disabled when memory generation is off; no test clicks the switch to true and asserts isPermissionGranted/requestPermission are called, or that a warning is logged when the permission call fails.

Do you want me to draft a test that mocks @tauri-apps/plugin-notification and asserts this flow?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/SettingsPage/components/UserPreferencesCard.tsx` around
lines 84 - 100, Add tests for UserPreferencesCard’s toggleMemoryNotifications
flow: mock `@tauri-apps/plugin-notification`, enable the switch, and assert
isPermissionGranted is checked and requestPermission is called only when
permission is absent; also cover the rejected permission request and verify
console.warn is emitted.
frontend/src-tauri/src/memories.rs (1)

123-378: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Add Rust test coverage for the curation state machine.

This file introduces a non-trivial async orchestration flow: backend readiness polling, indexing wait, run-completion polling with dedup logic, permission gating, and notification dedup. None of this is covered by unit tests in the diff. Consider extracting the pure decision logic (e.g., is_ours/settled computation in wait_for_run, the guard in surface) into small, directly-testable functions, and add tests around the HTTP layer using a mockable client trait or a local test server.

As per path instructions, **/*: "Ensure that test code is automated, comprehensive, and follows testing best practices" and "Verify that all critical functionality is covered by tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src-tauri/src/memories.rs` around lines 123 - 378, Add automated
Rust tests covering the curation state machine in run, wait_while_indexing,
wait_for_run, surface, and notification deduplication. Extract pure decisions
such as wait_for_run’s is_ours/settled logic and surface’s notification guard
into testable helpers, and exercise HTTP polling/error paths through a mockable
client or local test server while preserving existing behavior.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src-tauri/src/memories.rs`:
- Around line 178-206: Update surface so the notifications_enabled and
memory.notified_at guard runs before emitting memory:pending, preventing
repeated cards and honoring the preference. After the card is emitted or the OS
notification is shown, persist notified_at via mark_notified regardless of
whether notify succeeds, ensuring both delivery paths are deduplicated.
- Around line 208-246: Move the synchronous has_permission check in notify into
tauri::async_runtime::spawn_blocking, await its result before proceeding to
build and show the notification, and return false when permission is unavailable
or the blocking task fails. Keep the notification construction and show flow
unchanged, while ensuring permission_state and request_permission no longer run
directly on the async runtime worker.

---

Outside diff comments:
In `@frontend/src/components/Memories/MemoryStoryViewer.tsx`:
- Around line 292-299: Update the settings navigation button in
MemoryStoryViewer so its aria-label describes the general ROUTES.SETTINGS
destination rather than memory-specific settings. Change only the accessible
label while preserving the existing onClick navigation and styling.

In `@frontend/src/hooks/useUserPreferences.tsx`:
- Around line 51-66: The preferencesQuery refetch path currently applies fetched
preferences directly through applyPreferences, bypassing writeQueue and allowing
rollback to overwrite newer refetched state. Update the useUserPreferences flow
so external refetch results are serialized through writeQueue, or constrain
rollback to restore only the failed write’s keys; preserve queued writes while
retaining newer refetched values and emit diagnostics for failures.

In `@frontend/src/pages/Memories/Memories.tsx`:
- Around line 108-116: Update the settings navigation Button in Memories.tsx to
use an aria-label that reflects the consolidated general settings destination
instead of “Memory settings”; keep its existing ROUTES.SETTINGS navigation and
styling unchanged.

---

Nitpick comments:
In `@frontend/src-tauri/src/memories.rs`:
- Around line 123-378: Add automated Rust tests covering the curation state
machine in run, wait_while_indexing, wait_for_run, surface, and notification
deduplication. Extract pure decisions such as wait_for_run’s is_ours/settled
logic and surface’s notification guard into testable helpers, and exercise HTTP
polling/error paths through a mockable client or local test server while
preserving existing behavior.

In `@frontend/src/pages/SettingsPage/components/UserPreferencesCard.tsx`:
- Around line 84-100: Add tests for UserPreferencesCard’s
toggleMemoryNotifications flow: mock `@tauri-apps/plugin-notification`, enable the
switch, and assert isPermissionGranted is checked and requestPermission is
called only when permission is absent; also cover the rejected permission
request and verify console.warn is emitted.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7e6f2249-ae37-4051-be36-85e2bfa98ec8

📥 Commits

Reviewing files that changed from the base of the PR and between c7323dc and 96af5ba.

⛔ Files ignored due to path filters (2)
  • frontend/package-lock.json is excluded by !**/package-lock.json
  • frontend/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • backend/app/schemas/memories.py
  • backend/app/schemas/user_preferences.py
  • backend/tests/test_user_preferences.py
  • docs/backend/backend_python/openapi.json
  • frontend/jest.setup.ts
  • frontend/package.json
  • frontend/src-tauri/Cargo.toml
  • frontend/src-tauri/capabilities/migrated.json
  • frontend/src-tauri/src/main.rs
  • frontend/src-tauri/src/memories.rs
  • frontend/src/App.tsx
  • frontend/src/components/Memories/MemoryNotificationListener.tsx
  • frontend/src/components/Memories/MemoryStoryViewer.tsx
  • frontend/src/components/Memories/__tests__/MemoryNotificationListener.test.tsx
  • frontend/src/constants/routes.ts
  • frontend/src/hooks/__tests__/useUserPreferences.test.tsx
  • frontend/src/hooks/useUserPreferences.tsx
  • frontend/src/pages/Memories/Memories.tsx
  • frontend/src/pages/Memories/MemorySettings.tsx
  • frontend/src/pages/SettingsPage/components/UserPreferencesCard.tsx
  • frontend/src/pages/SettingsPage/components/__tests__/UserPreferencesCard.test.tsx
  • frontend/src/routes/AppRoutes.tsx
💤 Files with no reviewable changes (3)
  • frontend/src/constants/routes.ts
  • frontend/src/routes/AppRoutes.tsx
  • frontend/src/pages/Memories/MemorySettings.tsx

Comment thread frontend/src-tauri/src/memories.rs Outdated
Comment thread frontend/src-tauri/src/memories.rs Outdated
memory:pending was emitted before the notified_at guard, and /today keeps
returning a memory until it is viewed or dismissed, so the in-app card came
back on every launch and every resume. The guard now covers both paths and
notified_at is recorded whenever the card goes out.

Drops the Rust permission check with it: the plugin's desktop implementation
returns Granted unconditionally, so it never did anything.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
frontend/src-tauri/src/memories.rs (1)

197-213: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Track memory-event delivery before setting notified.

MemoryNotificationListener subscribes only after App mounts, while spawn_memory_task() runs immediately after window setup and can call mark_notified(). If curation emits memory:pending before that subscription is established, the in-app card is missed but later launches see notified: true and skip it again. Use a listener-ready acknowledgement protocol, or defer emitting this event until frontend readiness is known, before persisting the notified state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src-tauri/src/memories.rs` around lines 197 - 213, Update the memory
delivery flow around the event emission and mark_notified call so the memory is
marked notified only after the frontend has acknowledged that its
MemoryNotificationListener is ready and has received the memory:pending event.
Add or reuse a listener-ready handshake, or defer emission until readiness is
confirmed; preserve notification behavior while preventing missed in-app cards
from being persisted as notified.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@frontend/src/pages/SettingsPage/components/__tests__/UserPreferencesCard.test.tsx`:
- Around line 158-174: Extend the UserPreferencesCard permission-failure tests
to cover a false isPermissionGranted result followed by a rejected
requestPermission call. Mock that sequence, click the Desktop Notifications
switch, and assert notifications_enabled remains true and console.warn is
called, while preserving the existing rejected permission-check coverage.

---

Outside diff comments:
In `@frontend/src-tauri/src/memories.rs`:
- Around line 197-213: Update the memory delivery flow around the event emission
and mark_notified call so the memory is marked notified only after the frontend
has acknowledged that its MemoryNotificationListener is ready and has received
the memory:pending event. Add or reuse a listener-ready handshake, or defer
emission until readiness is confirmed; preserve notification behavior while
preventing missed in-app cards from being persisted as notified.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5e67fcf6-38c0-4ef3-b617-e048051995f0

📥 Commits

Reviewing files that changed from the base of the PR and between 96af5ba and 3c0f445.

📒 Files selected for processing (2)
  • frontend/src-tauri/src/memories.rs
  • frontend/src/pages/SettingsPage/components/__tests__/UserPreferencesCard.test.tsx

Comment on lines +158 to +174
it('keeps the preference when the permission call fails', async () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
mockIsPermissionGranted.mockRejectedValue(new Error('unavailable'));
const user = userEvent.setup();
render(<UserPreferencesCard />);
await openPanel(user);

await user.click(
screen.getByRole('switch', { name: /Desktop Notifications/i }),
);

expect(mockUpdateMemoriesPreferences).toHaveBeenCalledWith({
notifications_enabled: true,
});
expect(warn).toHaveBeenCalled();
warn.mockRestore();
});

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Test a rejected requestPermission() call.

Line 160 rejects isPermissionGranted(). This does not test the path where the permission check returns false and requestPermission() rejects. Add that case and assert that the preference remains enabled and console.warn is called.

As per path instructions, “Ensure that test code is automated, comprehensive, and follows testing best practices.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@frontend/src/pages/SettingsPage/components/__tests__/UserPreferencesCard.test.tsx`
around lines 158 - 174, Extend the UserPreferencesCard permission-failure tests
to cover a false isPermissionGranted result followed by a rejected
requestPermission call. Mock that sequence, click the Desktop Notifications
switch, and assert notifications_enabled remains true and console.warn is
called, while preserving the existing rejected permission-check coverage.

Source: Path instructions

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Surface a new memory through a native desktop notification

1 participant