diff --git a/web/src/app/Poller.js b/web/src/app/Poller.js index 9f3ff6a0..5c7d2e2d 100644 --- a/web/src/app/Poller.js +++ b/web/src/app/Poller.js @@ -1,4 +1,5 @@ import api from "./Api"; +import prefs from "./Prefs"; import subscriptionManager from "./SubscriptionManager"; const delayMillis = 2000; // 2 seconds @@ -42,14 +43,21 @@ class Poller { const since = subscription.last; const notifications = await api.poll(subscription.baseUrl, subscription.topic, since); - const latestBySid = this.latestNotificationsBySid(notifications); - // Delete all existing notifications with a deleted sequence ID + // Filter out notifications older than the prune threshold + const deleteAfterSeconds = await prefs.deleteAfter(); + const pruneThresholdTimestamp = deleteAfterSeconds > 0 ? Math.round(Date.now() / 1000) - deleteAfterSeconds : 0; + const recentNotifications = pruneThresholdTimestamp > 0 ? notifications.filter((n) => n.time >= pruneThresholdTimestamp) : notifications; + + // Find the latest notification for each sequence ID + const latestBySid = this.latestNotificationsBySid(recentNotifications); + + // Delete all existing notifications for which the latest notification is marked as deleted const deletedSids = Object.entries(latestBySid) .filter(([, notification]) => notification.deleted) .map(([sid]) => sid); if (deletedSids.length > 0) { - console.log(`[Poller] Deleting notifications with deleted sequence IDs for ${subscription.id}`); + console.log(`[Poller] Deleting notifications with deleted sequence IDs for ${subscription.id}`, deletedSids); await Promise.all(deletedSids.map((sid) => subscriptionManager.deleteNotificationBySid(subscription.id, sid))); } diff --git a/web/src/app/SubscriptionManager.js b/web/src/app/SubscriptionManager.js index 40cc475a..4a4c6f54 100644 --- a/web/src/app/SubscriptionManager.js +++ b/web/src/app/SubscriptionManager.js @@ -15,7 +15,7 @@ class SubscriptionManager { return Promise.all( subscriptions.map(async (s) => ({ ...s, - new: await this.db.notifications.where({ subscriptionId: s.id, new: 1 }).count(), + new: await this.db.notifications.where({ subscriptionId: s.id, new: 1 }).count() })) ); } @@ -83,7 +83,7 @@ class SubscriptionManager { baseUrl, topic, mutedUntil: 0, - last: null, + last: null }; await this.db.subscriptions.put(subscription); @@ -101,7 +101,7 @@ class SubscriptionManager { const local = await this.add(remote.base_url, remote.topic, { displayName: remote.display_name, // May be undefined - reservation, // May be null! + reservation // May be null! }); return local.id; @@ -171,21 +171,6 @@ class SubscriptionManager { .toArray(); } - // Collapse notification updates based on sids, keeping only the latest version - // Filters out notifications where the latest in the sequence is deleted - groupNotificationsBySID(notifications) { - const latestBySid = {}; - notifications.forEach((notification) => { - const key = `${notification.subscriptionId}:${notification.sid}`; - // Keep only the first (latest by time) notification for each sid - if (!(key in latestBySid)) { - latestBySid[key] = notification; - } - }); - // Filter out notifications where the latest is deleted - return Object.values(latestBySid).filter((n) => !n.deleted); - } - /** Adds notification, or returns false if it already exists */ async addNotification(subscriptionId, notification) { const exists = await this.db.notifications.get(notification.id); @@ -200,13 +185,13 @@ class SubscriptionManager { await this.db.notifications.add({ ...messageWithSID(notification), subscriptionId, - new: 1, // New marker (used for bubble indicator); cannot be boolean; Dexie index limitation + new: 1 // New marker (used for bubble indicator); cannot be boolean; Dexie index limitation }); // FIXME consider put() for double tab // Update subscription last message id (for ?since=... queries) await this.db.subscriptions.update(subscriptionId, { - last: notification.id, + last: notification.id }); } catch (e) { console.error(`[SubscriptionManager] Error adding notification`, e); @@ -222,7 +207,7 @@ class SubscriptionManager { const lastNotificationId = notifications.at(-1).id; await this.db.notifications.bulkPut(notificationsWithSubscriptionId); await this.db.subscriptions.update(subscriptionId, { - last: lastNotificationId, + last: lastNotificationId }); } @@ -265,19 +250,19 @@ class SubscriptionManager { async setMutedUntil(subscriptionId, mutedUntil) { await this.db.subscriptions.update(subscriptionId, { - mutedUntil, + mutedUntil }); } async setDisplayName(subscriptionId, displayName) { await this.db.subscriptions.update(subscriptionId, { - displayName, + displayName }); } async setReservation(subscriptionId, reservation) { await this.db.subscriptions.update(subscriptionId, { - reservation, + reservation }); } diff --git a/web/src/components/Notifications.jsx b/web/src/components/Notifications.jsx index 53c9085f..449b238b 100644 --- a/web/src/components/Notifications.jsx +++ b/web/src/components/Notifications.jsx @@ -240,22 +240,12 @@ const NotificationItem = (props) => { const otherTags = unmatchedTags(notification.tags); const tags = otherTags.length > 0 ? otherTags.join(", ") : null; const handleDelete = async () => { - if (notification.sid) { - console.log(`[Notifications] Deleting all notifications with sid ${notification.sid}`); - await subscriptionManager.deleteNotificationBySid(notification.subscriptionId, notification.sid); - } else { - console.log(`[Notifications] Deleting notification ${notification.id}`); - await subscriptionManager.deleteNotification(notification.id); - } + console.log(`[Notifications] Deleting notification ${notification.id}`); + await subscriptionManager.deleteNotification(notification.id); }; const handleMarkRead = async () => { - if (notification.sid) { - console.log(`[Notifications] Marking notification with sid ${notification.sid} as read`); - await subscriptionManager.markNotificationReadBySid(notification.subscriptionId, notification.sid); - } else { - console.log(`[Notifications] Marking notification ${notification.id} as read`); - await subscriptionManager.markNotificationRead(notification.id); - } + console.log(`[Notifications] Marking notification ${notification.id} as read`); + await subscriptionManager.markNotificationRead(notification.id); }; const handleCopy = (s) => { copyToClipboard(s);