mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-06 15:39:41 +02:00
feat: add multi-layer browser notification system
Implement a 4-layer notification system for alerting users when Claude Code sessions need attention: 1. Notification Drawer - persistent in-page log with bell icon + badge 2. Tab Title Updates - flashing title with unread count when unfocused 3. Web Notifications - browser push notifications when tab hidden 4. Audio Alerts - Web Audio API beep for critical events Notification triggers: - Critical: session errors, crashes (non-zero exit), agent failures/timeouts - Warning: Ralph loop completions, budget warnings, stuck sessions (idle >10min) - Info: auto-accepts, auto-clears, agent completions Features: - NotificationManager class with debouncing/grouping (5s window) - Settings tab in App Settings with per-layer/per-urgency toggles - Configurable idle threshold for stuck session detection - Click notification to switch to relevant session - Notification permission request flow - Rate-limited browser notifications (max 1/3s) - Idle timer cleanup on session delete Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,10 @@
|
||||
<span class="stat-value" id="statMem">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-icon-header btn-notifications" onclick="app.toggleNotifications()" title="Notifications">
|
||||
🔔
|
||||
<span class="notification-badge" id="notifBadge" style="display:none;">0</span>
|
||||
</button>
|
||||
<button class="btn-icon-header btn-settings" onclick="app.openAppSettings()" title="App Settings">⚙</button>
|
||||
<div class="header-tokens" id="headerTokens" title="Total tokens across all sessions">0 tokens</div>
|
||||
</div>
|
||||
@@ -467,6 +471,7 @@
|
||||
<button class="modal-tab-btn active" data-tab="settings-display">Display</button>
|
||||
<button class="modal-tab-btn" data-tab="settings-claude">Claude CLI</button>
|
||||
<button class="modal-tab-btn" data-tab="settings-paths">Paths</button>
|
||||
<button class="modal-tab-btn" data-tab="settings-notifications">Notifications</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Display Tab -->
|
||||
@@ -542,6 +547,66 @@
|
||||
<span class="form-hint">Default directory for new sessions.</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Notifications Tab -->
|
||||
<div class="modal-tab-content hidden" id="settings-notifications">
|
||||
<div class="form-row form-row-switch">
|
||||
<label>Enable Notifications</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="appSettingsNotifEnabled" checked>
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="form-hint">Master toggle for all notification layers</span>
|
||||
</div>
|
||||
<div class="form-row form-row-switch">
|
||||
<label>Browser Notifications</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="appSettingsNotifBrowser">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="form-hint">Show OS-level notifications when tab is hidden</span>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<button class="btn-toolbar btn-sm" onclick="app.notificationManager?.requestPermission()">Request Permission</button>
|
||||
<span class="form-hint" id="notifPermissionStatus">Status: unknown</span>
|
||||
</div>
|
||||
<div class="form-row form-row-switch">
|
||||
<label>Audio Alerts</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="appSettingsNotifAudio">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="form-hint">Play a short beep for critical events</span>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Idle Threshold (minutes)</label>
|
||||
<input type="number" id="appSettingsNotifStuckMins" value="10" min="1" max="120" style="width: 80px;">
|
||||
<span class="form-hint">Notify when a session is idle longer than this</span>
|
||||
</div>
|
||||
<div class="form-row form-row-switch">
|
||||
<label>Critical Notifications</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="appSettingsNotifCritical" checked>
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="form-hint">Errors, crashes, agent failures</span>
|
||||
</div>
|
||||
<div class="form-row form-row-switch">
|
||||
<label>Warning Notifications</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="appSettingsNotifWarning" checked>
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="form-hint">Completions, budget warnings, stuck sessions</span>
|
||||
</div>
|
||||
<div class="form-row form-row-switch">
|
||||
<label>Info Notifications</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="appSettingsNotifInfo" checked>
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="form-hint">Auto-accepts, auto-clears, agent completions</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button class="btn-toolbar" onclick="app.closeAppSettings()">Cancel</button>
|
||||
@@ -623,6 +688,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notification Drawer -->
|
||||
<div class="notification-drawer" id="notifDrawer">
|
||||
<div class="notif-drawer-header">
|
||||
<span class="notif-drawer-title">Notifications</span>
|
||||
<div class="notif-drawer-actions">
|
||||
<button class="btn-notif-action" onclick="app.notificationManager?.markAllRead()" title="Mark all read">✓</button>
|
||||
<button class="btn-notif-action" onclick="app.notificationManager?.clearAll()" title="Clear all">🗑</button>
|
||||
<button class="btn-notif-action" onclick="app.toggleNotifications()" title="Close">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="notif-drawer-list" id="notifList"></div>
|
||||
<div class="notif-drawer-empty" id="notifEmpty">No notifications</div>
|
||||
</div>
|
||||
|
||||
<!-- Help Button -->
|
||||
<button class="help-btn" onclick="app.showHelp()" title="Keyboard shortcuts (Ctrl+?)">?</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user