Skip to main content

Alerts & Notifications

A full-page view of monitoring alerts — list, filter, sort, search, resolve, assign, and download. Alerts split into two tabs: General and Device Status (offline).

  • Route: /alerts/:categoryIdAlertsPage (libs/alerts/src/AlertsPage.jsx)
  • Permission: ALERTS (gates the sidebar entry; the route isn't wrapped — see Permissions)
  • Library: libs/alerts/ is UI only; state/logic live in shared (AlertsStore, alertsController, alertsDataSource)

:categoryId selects water vs energy alerts — see Energy alerts.


Layout

Summary: Two tabs over the alert types; a left panel (month picker, a pie of this-month stats, a unit filter); and a list grouped into Today and the selected month. Clicking an alert opens the relevant monitoring page and marks it read.

AreaComponentWhat it showsOn click
TabsAlertsToggleTypeHeaderGeneral / Device Status, each with an unread badge; plus search + sortSwitch tab → refetch; search filters client-side
SortAlertsSortListSort by Date / Unresolved; a "Show Read" toggleReorders / reveals read alerts
Left panelAlertsLeftComponentMonth picker, a pie of this-month stats, and a Download buttonMonth → refetch; Download → export (see below)
FilterAlertFilterComponentA dialog of units (from your login data) to filter byPick units → filters the list
ListAlertListComponentAlerts grouped Today + monthRow → opens monitoring (new tab) + marks read; chevron expands details
Row actions(expanded row, General only)Resolve and AssignResolve → confirm snackbar; Assign → pick a user

APIs

State lives in the shared AlertsStore; calls go through apiClient:

ActionMethodPathTrigger
List alertsGETalertsPage load, tab/month change, after read/assign ({ date, alert_type, energyEnabled })
Today's unread (poll)GETalertsEvery 5 min ({ date, type: daily })
Mark readPATCHnotification/updateReadClicking an alert (and inside resolve)
Assign to userPOST/notification/assigneeThe ⋮ menu on a general alert
ResolvePATCH/notification/assigneeResolve snackbar (assign-to-self + mark read)
Download reportGETreport?… (window.open)The Download button
No dedicated "resolve" endpoint

Resolving an alert is implemented as assign-to-yourself + mark-read — there is no separate resolve flag. The download opens a report URL with the JWT in the query string.

Analytics: PAGE_VIEW, ALERTS_CLICK, ALERTS_DOWNLOAD, ALERT_ASSIGNED.


Energy alerts

The :categoryId route param chooses which alert domain the page loads. It sets exactly one store flag — energyEnabled = (categoryId === 'ENERGY_ALERTS') — and nothing else.

categoryIdReached fromLoads
WATER_ALERTS (default)The main / standalone app sidebars (/alerts/WATER_ALERTS)Water alerts
ENERGY_ALERTSThe energy monitoring nav (energyNavigationHelper/alerts/ENERGY_ALERTS)Energy alerts

API: it's the same GET alerts endpoint — energyEnabled just rides along in the params ({ date, alert_type, energyEnabled }). true returns energy alerts, false water alerts.

What's shown vs. hidden in energy mode — almost nothing differs; the flag only swaps the dataset:

AspectIn energy mode
Layout, tabs, filters, pieIdentical — same General / Device Status tabs and left panel
Alert datasetEnergy alerts (backend swaps on energyEnabled: true)
URL persistenceenergyEnabled=true is re-applied on every tab switch, so you stay in energy mode
Alert clickAn energy alert (standardCategoryId = ENERGY_CATEGORY) opens the energy monitoring page (/monitoring/energy_category/…) instead of a water page
Energy scope isn't fully wired

Only the list call passes energyEnabled. The 5-minute today-poll ({ date, type: daily }) and the download (service=alert) do not — so the tab unread badges and the exported report are not energy-scoped even in energy mode.


Edge cases & guards

CaseHandling
LoadingA loader in the list and left-panel pie
No alerts"Congratulations! You have no alerts." in the Today section
Today sectionOnly shown when the selected month is the current month
No data returnedFalls back to a PageNotFound panel
Filter / sort / searchAll applied client-side on the fetched month (no pagination)
Deep link?alertId=<id> auto-expands and scrolls to that alert
API failure⚠️ The loader can hanginit() has no try/catch, so a failed fetch never clears the spinner

Underlying libraries

PurposeLibrary
Stats piePieChartHover (Recharts-based shared component)
Date pickerAppDatePickerSelection (month mode)
Datesmoment
UI / utils@mui/material (MUI 7), @iconify/react, lodash (debounced search)

Code reference

FileRole
AlertsPage.jsxPage shell, tabs, search/sort header
components/AlertsLeftComponent.jsxMonth picker, stats pie, download
components/AlertTabView.jsxLayout + resolve snackbar
components/AlertListComponent.jsxThe grouped list + row-click navigation
components/AlertFilterComponent.jsx · AlertsSortList.jsxUnit filter + sort menu
libs/shared/src/store/AlertsStore.jsAlert state, polling, API actions