Skip to content

[#1287] feat(frontend): add audible sound alert toggle and browser push notifications - #1383

Merged
Mosas2000 merged 1 commit into
StellaBridge:mainfrom
ToryMic:fix/1287-feat-frontend-add-audible-sound-alert-toggle-and-browser-push-notifications
Sep 29, 2026
Merged

Mosas2000 merged 1 commit into
StellaBridge:mainfrom
ToryMic:fix/1287-feat-frontend-add-audible-sound-alert-toggle-and-browser-push-notifications

Conversation

@ToryMic

@ToryMic ToryMic commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Summary

High and critical alerts only ever rendered inside the notifications drawer, so an operator who switched to another window never noticed a tripped circuit breaker or a reserve mismatch. This PR adds audible and out-of-tab alerting for those two priorities.

What was added

  • useAlertChime — chimes via the Web Audio API. Critical gets a descending two-tone siren, high a single blip, so the two are distinguishable without looking. A single AudioContext is created lazily and reused (browsers cap how many a page may hold), and each oscillator is disconnected on ended so nodes don't accumulate over a long shift.
  • useDesktopNotifications — native notifications via the Web Notifications API, dispatched only while the document is hidden. If the operator is already looking at the tab, a native popup would duplicate the drawer.
  • useAlertNotifier — watches the notification store and fires either channel for newly arrived high/critical alerts.
  • Drawer switches for both channels, persisted through the existing soundEnabled and notificationsEnabled user preferences, which were defined but previously unused.

Browser constraints, surfaced rather than swallowed

  • The audio switch arms the AudioContext in the same click. Browsers keep it suspended until a user gesture, so without this the first chime is silent. Until then the drawer tells the operator to tap once.
  • Notification permission is requested only on the enabling gesture — browsers reject prompts that aren't user-initiated.
  • A denied permission shows how to unblock it in browser settings.
  • If the browser has no Web Audio API, the switch is disabled with an explanation rather than silently doing nothing.

Avoiding noise

The store is seeded with existing notification ids on mount, so a page reload does not replay every historical alert as a siren. Each id fires at most once, and medium/low priorities stay silent.

Testing

  • 31 new tests: useAlertChime.test.ts (10), useAlertNotifier.test.ts (9), NotificationsDrawer.alerts.test.tsx (12)
  • All pass; the existing 10 NotificationsDrawer.test.tsx tests still pass
  • eslint and tsc --noEmit clean on every changed file

Pre-existing baseline failures (not touched here): the frontend suite on main already fails with 76 tests across 15 files. That count is identical before and after this branch, so this adds no new failures. .github/workflows/ci.yml and docker.yml also fail to parse on main (invalid ${{ runner.temp }} in job-level env and ${{ id.meta.* }}), which is an upstream issue I have left alone.

Reviewer notes

  • No backend changes: the priorities (critical / high) already exist on the notification store, so the feature needed no new data.
  • There is a second, older NotificationContext that plays /notification-sound.mp3 via new Audio(). It uses a different Notification type with no priority field and a separate storage key. I did not touch it — consolidating the two notification systems looked out of scope, but it is worth a follow-up issue since it means the two systems can disagree about what has alerted.

Closes #1287

…d browser push notifications

High and critical alerts (CIRCUIT_BREAKER_TRIPPED, RESERVE_MISMATCH, ...)
were only ever rendered in the notifications drawer, so an operator who
switched to another window never noticed them.

Adds audible and out-of-tab alerting for those two priorities:

- `useAlertChime` — plays a chime through the Web Audio API. Critical gets a
  descending two-tone siren and high gets a single blip so the two are
  distinguishable without looking. One AudioContext is created lazily and
  reused (browsers cap how many a page may hold), and each oscillator is
  disconnected on `ended` so nodes do not accumulate over a long shift.
- `useDesktopNotifications` — dispatches native notifications via the Web
  Notifications API, but only while the document is hidden: if the operator is
  already looking at the tab, a native popup would duplicate the drawer.
- `useAlertNotifier` — watches the notification store and fires either channel
  for newly arrived high/critical alerts. The store is seeded with existing
  ids on mount so a page reload does not replay every historical alert.
- Drawer switches for both channels, persisted through the existing (previously
  unused) `soundEnabled` and `notificationsEnabled` user preferences.

Browser constraints are surfaced rather than swallowed: the audio switch
arms the AudioContext in the same click, because browsers keep it suspended
until a user gesture and the first chime would otherwise be silent; permission
is only requested on the enabling gesture, since browsers reject prompts that
are not user-initiated; and a denied permission explains how to unblock it.

Adds 31 tests across the three hooks and the drawer controls. The existing 10
NotificationsDrawer tests still pass.
@drips-wave

drips-wave Bot commented Sep 29, 2026

Copy link
Copy Markdown

@ToryMic Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Mosas2000
Mosas2000 merged commit efaa2b8 into StellaBridge:main Sep 29, 2026
15 checks passed
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(frontend): add audible sound alert toggle and browser push notifications

2 participants