diff --git a/frontend/openchat-service-worker/src/service_worker.ts b/frontend/openchat-service-worker/src/service_worker.ts index 5efdedb48a..a4bb0183f6 100644 --- a/frontend/openchat-service-worker/src/service_worker.ts +++ b/frontend/openchat-service-worker/src/service_worker.ts @@ -169,6 +169,9 @@ function toUint8Array(base64String: string): Uint8Array { return Uint8Array.from(atob(base64String), (c) => c.charCodeAt(0)); } +const MAX_NOTIFICATIONS = 50; +const MAX_NOTIFICATIONS_PER_GROUP = 20; + async function showNotification(n: Notification, id: string): Promise { let icon = "/_/raw/icon.png"; let image = undefined; @@ -240,25 +243,30 @@ async function showNotification(n: Notification, id: string): Promise { } const path = notificationPath(n); - const tag = path; + let tag: string | undefined = undefined; - // If true, we close existing notifications where the `path` matches, this ensures this new notification will - // trigger an alert. If false, and there is already at least one notification with a matching path, then this new - // notification will be silent if (isMessageNotification(n)) { if (icon === undefined && n.messageType === "File") { icon = FILE_ICON; } + } else { + tag = path; + } + + const existing = await self.registration.getNotifications(); + const matching = existing.filter((n) => n.data.path === path); + const closed = closeExcessNotifications(matching, MAX_NOTIFICATIONS_PER_GROUP); - // We need to close any existing notifications for the same tag otherwise the new notification will not be shown - const existing = await self.registration.getNotifications({ tag }); - existing.forEach((n) => n.close()); + if (existing.length - closed >= MAX_NOTIFICATIONS) { + const existing = await self.registration.getNotifications(); + closeExcessNotifications(existing, MAX_NOTIFICATIONS); } const toShow = { body, icon, image, + renotify: tag !== undefined, tag, timestamp: Number(n.timestamp), data: { @@ -271,6 +279,17 @@ async function showNotification(n: Notification, id: string): Promise { await self.registration.showNotification(title, toShow); } +function closeExcessNotifications( + notifications: globalThis.Notification[], + maxCount: number, +): number { + const toClose = Math.max(notifications.length + 1 - maxCount, 0); + if (toClose > 0) { + notifications.slice(0, toClose).forEach((n) => n.close()); + } + return toClose; +} + function messageText( messageText: string | undefined, messageType: string,