Frappe Notification Alerts
- Author: parthf
- Repository: https://github.com/parthf/frappe_notification_alerts
- GitHub stars: 3
- Forks: 0
- License: MIT
- Category: Other
- Maintenance: Actively Maintained
Install Frappe Notification Alerts
bench get-app https://github.com/parthf/frappe_notification_alerts
Add the Frappe Gems badge to your README
Maintain Frappe Notification Alerts? Paste this into your README:
[](https://frappegems.com/gems/apps/parthf/frappe_notification_alerts)
About Frappe Notification Alerts
Frappe Notification Alerts
Makes Frappe's standard notification bell impossible to miss: an animated bell, an unread-count badge, a short sound on arrival, and a longer attention burst when you log in with notifications already waiting.
It is a standalone, generic app. It reads Frappe's own Notification Log and
nothing else, so it covers every notification that reaches the standard bell —
system, assignment, mention, share, energy point, workflow, and anything raised by
any other installed app — without knowing anything about them.
No Frappe core file is modified.
What it does
| Situation | Behaviour |
|---|---|
| New notification arrives while you are logged in | One short sound, one bell attention burst, badge count updates |
| Notification stays unread | Bell swings from its crown, and a red disc pulses outward from it on a loop. All configurable. No repeated sound. |
| You log in with unread notifications from while you were away | Longer attention burst (default 8s), badge visible immediately on first paint. Sound off by default. |
| You read / clear all notifications | Animation stops, badge disappears, bell returns to normal |
| Several tabs open | Count stays in sync in all of them; only one tab plays the sound |
| Several notifications arrive together | Sound is throttled to one per N seconds (default 3s) |
Installation
cd /path/to/frappe-bench
# 1. Fetch the app (skip if the folder is already in apps/)
bench get-app /path/to/frappe_notification_alerts
# or: bench get-app https://github.com/parthf/frappe_notification_alerts.git
# 2. Install on a site
bench --site install-app frappe_notification_alerts
# 3. Reload the browser (hard refresh so the new JS/CSS are picked up)
After installing, restart the bench so the background workers pick up the new
doc_events, then reload the browser:
bench restart # or stop and restart `bench start` in development
If the app folder was copied into apps/ by hand
bench get-app does the registration for you. If the folder was copied in manually,
do it yourself — and clear the cache before installing:
cd /path/to/frappe-bench
./env/bin/pip install -e apps/frappe_notification_alerts
grep -qxF frappe_notification_alerts sites/apps.txt || echo frappe_notification_alerts >> sites/apps.txt
ln -sfn "$PWD/apps/frappe_notification_alerts/frappe_notification_alerts/public" sites/assets/frappe_notification_alerts
bench --site clear-cache # <-- important, see below
bench --site install-app frappe_notification_alerts
bench restart
> Why clear-cache matters. Frappe caches the bench-wide app→module map in Redis
> under the app_modules key. If that cache was populated before the app folder
> existed, install-app scans an empty module list and silently installs the app
> without creating the Notification Alert Settings DocType — no error is raised.
> The app still works (it falls back to built-in defaults), but the settings form is
> missing. If you hit this, the fix is:
>
> bash
> bench --site clear-cache
> bench --site migrate
>
No bench build is required. The JS/CSS are plain, unbundled assets served
from the sites/assets/frappe_notification_alerts symlink. (bench build is
harmless if you run it anyway.)
> Cache-busting. Frappe serves /assets through werkzeug's
> SharedDataMiddleware, which sends Cache-Control: max-age=43200 — browsers
> hold these files for 12 hours without revalidating. Frappe's own scripts
> dodge this because esbuild gives them content-hashed filenames; a plain path
> has no such escape.
>
> So hooks.py appends ?v={__version__} to both asset paths. Whenever you
> change the JS or CSS, bump __version__ in
> frappe_notification_alerts/__init__.py and run
> bench --site clear-cache. That changes the URL, so every user picks up
> the new file on their next normal reload.
>
> If you edit the assets without bumping the version, no amount of
> bench build, bench migrate or bench clear-cache will help — those are all
> server-side, and the stale copy lives in the browser. Hard refresh
> (Ctrl/Cmd + Shift + R) is the manual escape hatch.
Working defaults are applied automatically — the app is fully functional the moment the page reloads, with no configuration.
Uninstall
bench --site uninstall-app frappe_notification_alerts
Everything this app adds is namespaced (.nfa-* CSS classes, notification_alerts:*
realtime events, one Single doctype), so removing it leaves no trace.
Project layout
frappe_notification_alerts/
├── README.md
├── license.txt
├── pyproject.toml
└── frappe_notification_alerts/
├── hooks.py # every integration point, in one file
├── api.py # settings resolution, unread count, whitelisted endpoints
├── boot.py # extend_bootinfo: settings + count in frappe.boot
├── events.py # doc_events on Frappe's Notification Log
├── install.py # after_install / after_migrate defaults
├── modules.txt # "Notification Alerts"
├── public/
│ ├── js/notification_alerts.js # listener, bell animation, sound, cross-tab
│ ├── css/notification_alerts.css # badge + keyframe animations
│ └── sounds/notification.wav # bundled chime (27 KB)
└── notification_alerts/doctype/notification_alert_settings/
Configuration
Notification Alert Settings (a Single doctype, System Manager only). Open it at:
/app/notification-alert-settings
| Setting | Default | Notes |
|---|---|---|
| Enable Enhanced Notification Alerts | ✅ | Master switch; off = stock Frappe behaviour |
| Bell Animation | ||
| Enable Bell Animation | ✅ | |
| Bell Icon Style | Solid |
Solid fills the whole bell with colour (uses Frappe's own es-solid-notification); Outline keeps the stock line icon |
| Bell Icon Size | 20 px |
Frappe's stock bell is 16. Clamped to 12–32. The navbar never reflows when the unread state changes |
| Bell Animation Type | Swing |
Swing pivots at the bell's crown so the body arcs left and right, the way a real bell moves. Also Slide, Shake, Bounce, Pulse, Glow, Shake and Glow. Only the bell moves — the badge and disc stay put |
| Shake Continuously While Unread | ✅ | Animate non-stop while anything is unread. Turn off for the gentler periodic behaviour |
| Animation Duration | 2 s |
Length of one attention burst (periodic mode only) |
| Animation Interval | 20 s |
Gap between periodic bursts. Ignored in continuous mode. 0 = animate only on arrival |
| Animate Only When Tab Is Visible | ✅ | Skips bursts in background tabs |
| Highlight Bell Background | ✅ | Coloured disc behind the bell while unread. The bell icon itself always turns red |
| Highlight Style | Pulsing |
Pulsing grows the disc from radius 0 out past the bell and fades it, on a 1.8s loop. Static keeps it a constant size |
| Always Colour The Bell | ✅ | Keep the bell red even with nothing unread. Off = red only while unread |
| Sound | ||
| Enable Notification Sound | ✅ | Only on arrival — never repeated while merely unread |
| Sound Volume | 0.5 |
0–1 |
| Minimum Seconds Between Sounds | 3 s |
Absorbs bursts of notifications |
| Custom Sound URL | (blank) | Blank = bundled chime. Any playable URL, e.g. /assets/frappe/sounds/chime.mp3 |
| Respect User's Mute Sounds Setting | ✅ | Honours the per-user mute_sounds flag on User |
| Play Sound In Only One Tab | ✅ | Cross-tab de-duplication |
| Login / Offline | ||
| Enable Login Attention Alert | ✅ | |
| Login Attention Duration | 8 s |
|
| Play One Attention Sound On Login | ❌ | Off by default; see Browser autoplay below |
| Indicator | ||
| Show Unread Count Badge | ✅ | Red badge on the bell's top-right corner |
| Maximum Count To Display | 99 |
Higher counts render as 99+ |
| Show Unread Count In Browser Tab Title | ✅ | Prefixes the tab title with (n) |
| Advanced | ||
| Background Refresh Interval | 180 s |
Safety-net poll, visible tabs only. 0 disables |
| Enable Debug Logging In Browser Console | ❌ | Logs every decision the app makes |
Saving the form pushes the new settings to every open Desk session immediately — no reload needed. The form also has a Preview Alert button that fires one burst plus one sound using the values currently on screen, without saving.
How it works — the integration points
Everything below is a documented, supported Frappe extension point.
Server
| Hook | Used for |
|---|---|
app_include_js / app_include_css |
Injects the client script and stylesheet into the Desk. Plain asset paths, so no esbuild bundle and no bench build. |
extend_bootinfo → boot.boot_session |
Ships settings and the current unread count inside frappe.boot.notification_alerts. This is what makes the "logged in with notifications waiting" case instant — the bell can start alerting on the first paint, with zero extra round trips. |
doc_events on Notification Log (after_insert, on_update, on_trash) |
The single generic integration point. Every notification in the standard bell is a Notification Log row, whichever app created it, so hooking this one doctype covers all of them. Each hook publishes a realtime event carrying an authoritative unread count. |
after_install / after_migrate |
Materialises the settings Single with defaults, and back-fills fields added by later versions of this app. |
Whitelisted endpoints (frappe_notification_alerts.api):
get_state()— settings + unread count. Only used if the boot payload is missing (app installed mid-session).get_unread_count_for_current_user()— cheap recount, used by the poll.sync_unread_count()— recount and publish to every session of the current user. Called after mark-as-read interactions.
Realtime events published (all into the user's own socket.io room, except settings):
| Event | When |
|---|---|
notification_alerts:new |
A Notification Log row was inserted. Payload: unread_count, name, type, subject |
notification_alerts:refresh |
Count may have changed (row updated/deleted, or a mark-as-read sync) |
notification_alerts:settings_updated |
An admin saved the settings doc (site-wide broadcast) |
Client
| Frappe API / event | Used for |
|---|---|
frappe.boot.notification_alerts |
Initial settings + count, available before the navbar renders |
frappe.realtime.on("notification_alerts:*") |
This app's own events |
frappe.realtime.on("notification") |
Frappe's core event, used as a fallback: if this app's event has not arrived within 1.5s, the client recounts and alerts anyway. Keeps the app working even if the doc hooks cannot run. |
frappe.realtime.on("indicator_hide") |
Frappe's core "the dropdown was opened somewhere" event → triggers a recount |
$(document).on("toolbar_setup") |
Re-attaches to the bell if the navbar is re-rendered by a theme or another app |
$(document).on("page-change") |
Re-applies the (n) browser-tab title, which the router rewrites on every route change |
frappe.boot.desk_settings.notifications |
If the site has the bell disabled, this app stays completely inert |
frappe.boot.user.mute_sounds |
Honoured when Respect User's Mute Sounds Setting is on |
DOM: .navbar .dropdown-notifications .notifications-icon |
The bell button. Read only — the app appends its own badge element and toggles its own .nfa-* classes; it never modifies Frappe's markup or its .notifications-seen / .notifications-unseen logic |
Detecting "marked as read"
Frappe marks notifications read via frappe.db.set_value, which deliberately
skips document hooks — so there is no server-side
Related Other apps for Frappe & ERPNext
- Erpnext — Free and Open Source Enterprise Resource Planning (ERP)
- Helpdesk — Modern, Streamlined, Free and Open Source Customer Service Software
- Print Designer — Visual print designer for Frappe / ERPNext
- Ctr — CTR模型代码和学习笔记总结
- Whitelabel — Whitelabel ERPNext
- Fossunited — fossunited.org
- Helm — Helm Chart Repository for Frappe/ERPNext
- Frappe Attachments S3 — A frappe app to upload file attachments in doctypes to s3.