From 66214478ff67d06e6960eb935429576b9393fc91 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 24 Jan 2026 03:37:40 +0100 Subject: [PATCH] fix: browser notifications now fire correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three issues fixed: - Default browserNotifications to true (was false, never fired) - Remove tab-visibility gate for critical/warning notifications (monitoring dashboard should alert regardless of tab focus) - Auto-request Notification permission on first attempt instead of silently failing (re-sends the notification after permission granted) - Migrate existing localStorage prefs from v1 default (false → true) Co-Authored-By: Claude Opus 4.5 --- src/web/public/app.js | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/web/public/app.js b/src/web/public/app.js index 1edc0623..ff9f4d7a 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -33,19 +33,30 @@ class NotificationManager { } loadPreferences() { - try { - const saved = localStorage.getItem('claudeman-notification-prefs'); - if (saved) return JSON.parse(saved); - } catch (_e) { /* ignore */ } - return { + const defaults = { enabled: true, - browserNotifications: false, + browserNotifications: true, audioAlerts: false, stuckThresholdMs: 600000, muteCritical: false, muteWarning: false, muteInfo: false, + _version: 2, }; + try { + const saved = localStorage.getItem('claudeman-notification-prefs'); + if (saved) { + const prefs = JSON.parse(saved); + // Migrate: v1 had browserNotifications defaulting to false + if (!prefs._version || prefs._version < 2) { + prefs.browserNotifications = true; + prefs._version = 2; + localStorage.setItem('claudeman-notification-prefs', JSON.stringify(prefs)); + } + return { ...defaults, ...prefs }; + } + } catch (_e) { /* ignore */ } + return defaults; } savePreferences() { @@ -104,8 +115,8 @@ class NotificationManager { this.updateTabTitle(); } - // Layer 3: Browser notification (when tab hidden, critical/warning only) - if (!this.isTabVisible && (urgency === 'critical' || urgency === 'warning')) { + // Layer 3: Browser notification (critical/warning always, info only when tab hidden) + if (urgency === 'critical' || urgency === 'warning' || !this.isTabVisible) { this.sendBrowserNotif(title, message, category, sessionId); } @@ -184,6 +195,16 @@ class NotificationManager { sendBrowserNotif(title, body, tag, sessionId) { if (!this.preferences.browserNotifications) return; if (typeof Notification === 'undefined') return; + if (Notification.permission === 'default') { + // Auto-request on first notification attempt + Notification.requestPermission().then(result => { + if (result === 'granted') { + // Re-send this notification now that we have permission + this.sendBrowserNotif(title, body, tag, sessionId); + } + }); + return; + } if (Notification.permission !== 'granted') return; // Rate limit: max 1 per 3 seconds