Frappe Notification Alerts

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:

[![Listed on Frappe Gems](https://frappegems.com/api/method/frappe_gems.seo.badge?app=parthf%2Ffrappe_notification_alerts)](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_bootinfoboot.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.