feat: per-user notification preference toggles

Add per-namespace notification preferences so users can choose which
event types trigger push notifications (permission requests, session
ready, task notifications, session completion). Adds the
notification_preferences table (schema v20), GET/PUT
/api/notification-preferences, POST /api/push/test for test pushes, and
a Notifications settings page in the web app with a confirm dialog for
disabling permission requests. Defaults keep all event types enabled.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-05 11:16:08 +08:00
co-authored by HAPI Claude
parent 27bc6bade3
commit dd1cd24a46
24 changed files with 869 additions and 13 deletions
+20
View File
@@ -916,6 +916,26 @@ export default {
'settings.companion.copyLink': 'Copy link',
'settings.companion.copied': 'Copied!',
'settings.companion.hide': 'Hide',
'settings.notifications.title': 'Notifications',
'settings.notifications.description': 'Choose which events trigger push notifications on your devices.',
'settings.notifications.summary': 'Push notification preferences',
'settings.notifications.section': 'Notification types',
'settings.notifications.permissionRequests': 'Permission requests',
'settings.notifications.permissionRequestsDescription': 'When an agent needs your approval to run a tool.',
'settings.notifications.sessionReady': 'Session ready',
'settings.notifications.sessionReadyDescription': 'When an agent is waiting for your input.',
'settings.notifications.taskNotifications': 'Task notifications',
'settings.notifications.taskNotificationsDescription': 'When a task completes or fails.',
'settings.notifications.sessionCompletion': 'Session completion',
'settings.notifications.sessionCompletionDescription': 'When a session finishes.',
'settings.notifications.disablePermissionTitle': 'Turn off permission request notifications?',
'settings.notifications.disablePermissionDescription': 'You will no longer be notified on your phone when an agent needs your approval. Pending requests will only be visible in the web app.',
'settings.notifications.disablePermissionConfirm': 'Turn off anyway',
'settings.notifications.testPush': 'Send test push',
'settings.notifications.testPushSending': 'Sending…',
'settings.notifications.testPushSent': 'Test notification sent!',
'settings.notifications.testPushError': 'Failed to send test notification',
'settings.notifications.saveError': 'Failed to save preferences',
'settings.machines.title': 'Machines',
'settings.machines.description': 'Give your machines names of your own. Only machines that are currently online are listed.',
'settings.machines.section': 'Your machines',
+20
View File
@@ -915,6 +915,26 @@ export default {
'settings.companion.copyLink': '复制链接',
'settings.companion.copied': '已复制!',
'settings.companion.hide': '隐藏',
'settings.notifications.title': '通知',
'settings.notifications.description': '选择哪些事件会触发推送到你设备的通知。',
'settings.notifications.summary': '推送通知偏好',
'settings.notifications.section': '通知类型',
'settings.notifications.permissionRequests': '权限请求',
'settings.notifications.permissionRequestsDescription': '当 Agent 需要你批准执行某个工具时。',
'settings.notifications.sessionReady': '会话就绪',
'settings.notifications.sessionReadyDescription': '当 Agent 等待你的输入时。',
'settings.notifications.taskNotifications': '任务通知',
'settings.notifications.taskNotificationsDescription': '当任务完成或失败时。',
'settings.notifications.sessionCompletion': '会话完成',
'settings.notifications.sessionCompletionDescription': '当会话结束时。',
'settings.notifications.disablePermissionTitle': '关闭权限请求通知?',
'settings.notifications.disablePermissionDescription': '关闭后,当 Agent 需要你批准时手机将不再收到通知,待处理的请求只能通过网页查看。',
'settings.notifications.disablePermissionConfirm': '仍然关闭',
'settings.notifications.testPush': '发送测试推送',
'settings.notifications.testPushSending': '发送中…',
'settings.notifications.testPushSent': '测试通知已发送!',
'settings.notifications.testPushError': '发送测试通知失败',
'settings.notifications.saveError': '保存偏好设置失败',
'settings.machines.title': '设备',
'settings.machines.description': '给设备起自己的名字。这里只列出当前在线的设备。',
'settings.machines.section': '我的设备',
+1
View File
@@ -4,6 +4,7 @@ export const queryKeys = {
messages: (sessionId: string) => ['messages', sessionId] as const,
machines: ['machines'] as const,
sqliteStorage: ['sqlite-storage'] as const,
notificationPreferences: ['notification-preferences'] as const,
usageSummary: (range: string, timeZone: string) => ['usage-summary', range, timeZone] as const,
machineCodexModels: (machineId: string) => ['machine-codex-models', machineId] as const,
gitStatus: (sessionId: string) => ['git-status', sessionId] as const,