diff --git a/app/scripts/directives/notifications/notificationDrawerWrapper.js b/app/scripts/directives/notifications/notificationDrawerWrapper.js index e0b8ea8da7..63face88aa 100644 --- a/app/scripts/directives/notifications/notificationDrawerWrapper.js +++ b/app/scripts/directives/notifications/notificationDrawerWrapper.js @@ -86,7 +86,6 @@ return _.filter(notifications, 'unread'); }; - var countUnreadNotifications = function() { _.each(drawer.notificationGroups, function(group) { group.totalUnread = unread(group.notifications).length; @@ -99,12 +98,29 @@ _.each(drawer.notificationGroups, function(group) { _.remove(group.notifications, { uid: notification.uid, namespace: notification.namespace }); }); - delete notificationsMap[$routeParams.project][notification.uid]; + }; + + var remove = function(notification) { + // remove the notification from the underlying maps. + // this ensures no ghost notifications linger. + if(notificationsMap[$routeParams.project]) { + delete notificationsMap[$routeParams.project][notification.uid]; + } + if(apiEventsMap[$routeParams.project]) { + delete apiEventsMap[$routeParams.project][notification.uid]; + } + // then remove it from the map that is rendered to UI. + removeNotificationFromGroup(notification); + }; + + var removeAllForProject = function() { + apiEventsMap[$routeParams.project] = {}; + notificationsMap[$routeParams.project] = {}; }; var formatAPIEvents = function(apiEvents) { - return _.map(apiEvents, function(event) { - return { + return _.reduce(apiEvents, function(result, event) { + result[event.metadata.uid] = { actions: null, uid: event.metadata.uid, trackByID: event.metadata.uid, @@ -114,7 +130,8 @@ firstTimestamp: event.firstTimestamp, event: event }; - }); + return result; + }, {}); }; var filterAPIEvents = function(events) { @@ -246,9 +263,9 @@ notification.unread = false; EventsService.markRead(notification.uid); EventsService.markCleared(notification.uid); + }); - apiEventsMap[$routeParams.project] = {}; - notificationsMap[$routeParams.project] = {}; + removeAllForProject(); render(); $rootScope.$emit('NotificationDrawerWrapper.onMarkAllRead'); }, @@ -257,14 +274,16 @@ notificationBodyInclude: 'views/directives/notifications/notification-body.html', customScope: { clear: function(notification, index, group) { + EventsService.markRead(notification.uid); EventsService.markCleared(notification.uid); group.notifications.splice(index, 1); - countUnreadNotifications(); + remove(notification); + render(); }, markRead: function(notification) { notification.unread = false; EventsService.markRead(notification.uid); - countUnreadNotifications(); + render(); }, close: function() { drawer.drawerHidden = true; @@ -277,7 +296,6 @@ } }); - var initWatches = function() { if($routeParams.project) { reset(); @@ -307,7 +325,7 @@ // event to signal the drawer to clear a notification rootScopeWatches.push($rootScope.$on('NotificationDrawerWrapper.clear', function(event, notification) { EventsService.markCleared(notification.uid); - removeNotificationFromGroup(notification); + remove(notification); drawer.countUnreadNotifications(); })); }; diff --git a/dist/scripts/scripts.js b/dist/scripts/scripts.js index 237554eb3a..2214115f85 100644 --- a/dist/scripts/scripts.js +++ b/dist/scripts/scripts.js @@ -14581,44 +14581,48 @@ _.remove(t.notifications, { uid: e.uid, namespace: e.namespace }); -}), delete v[r.project][e.uid]; +}); }, P = function(e) { -return _.map(e, function(e) { -return { +v[r.project] && delete v[r.project][e.uid], g[r.project] && delete g[r.project][e.uid], j(e); +}, R = function() { +g[r.project] = {}, v[r.project] = {}; +}, I = function(e) { +return _.reduce(e, function(e, t) { +return e[t.metadata.uid] = { actions: null, -uid: e.metadata.uid, -trackByID: e.metadata.uid, -unread: !c.isRead(e.metadata.uid), -type: e.type, -lastTimestamp: e.lastTimestamp, -firstTimestamp: e.firstTimestamp, -event: e -}; -}); -}, R = function(e) { +uid: t.metadata.uid, +trackByID: t.metadata.uid, +unread: !c.isRead(t.metadata.uid), +type: t.type, +lastTimestamp: t.lastTimestamp, +firstTimestamp: t.firstTimestamp, +event: t +}, e; +}, {}); +}, E = function(e) { return _.reduce(e, function(e, t) { return c.isImportantAPIEvent(t) && !c.isCleared(t.metadata.uid) && (e[t.metadata.uid] = t), e; }, {}); -}, I = function(e, t) { +}, T = function(e, t) { var n = r.project; return _.assign({}, e[n], t[n]); -}, E = function(e) { +}, N = function(e) { return _.orderBy(e, [ "event.lastTimestamp", "event.firstTimestamp" ], [ "desc", "desc" ]); -}, T = function() { +}, D = function() { o.$evalAsync(function() { -p.notificationGroups = [ C(r.project, E(I(g, v))) ], k(); +p.notificationGroups = [ C(r.project, N(T(g, v))) ], k(); }); -}, N = function() { +}, A = function() { _.each(f, function(e) { e(); }), f = []; -}, D = function() { +}, $ = function() { u && (s.unwatch(u), u = null); -}, A = function() { +}, B = function() { l && l(), l = null; -}, $ = function(e) { -g[r.project] = P(R(e.by("metadata.name"))), T(); -}, B = function(e, t) { +}, L = function(e) { +g[r.project] = I(E(e.by("metadata.name"))), D(); +}, U = function(e, t) { var n = t.namespace || r.project, a = t.id ? n + "/" + t.id : _.uniqueId("notification_") + Date.now(); t.showInDrawer && !c.isCleared(a) && (v[n] = v[n] || {}, v[n][a] = { actions: t.actions, @@ -14632,18 +14636,18 @@ isHTML: t.isHTML, details: t.details, namespace: n, links: t.links -}, T()); -}, L = function(e, t) { -D(), e && (u = s.watch("events", { +}, D()); +}, O = function(e, t) { +$(), e && (u = s.watch("events", { namespace: e }, _.debounce(t, 400), { skipDigest: !0 })); -}, U = _.once(function(e, t) { -A(), l = o.$on("NotificationsService.onNotificationAdded", t); -}), O = function() { +}, F = _.once(function(e, t) { +B(), l = o.$on("NotificationsService.onNotificationAdded", t); +}), x = function() { S(r.project).then(function() { -L(r.project, $), U(r.project, B), y(r.project), T(); +O(r.project, L), F(r.project, U), y(r.project), D(); }); }; angular.extend(p, { @@ -14660,22 +14664,22 @@ p.drawerHidden = !0; onMarkAllRead: function(e) { _.each(e.notifications, function(e) { e.unread = !1, c.markRead(e.uid); -}), T(), o.$emit("NotificationDrawerWrapper.onMarkAllRead"); +}), D(), o.$emit("NotificationDrawerWrapper.onMarkAllRead"); }, onClearAll: function(e) { _.each(e.notifications, function(e) { e.unread = !1, c.markRead(e.uid), c.markCleared(e.uid); -}), g[r.project] = {}, v[r.project] = {}, T(), o.$emit("NotificationDrawerWrapper.onMarkAllRead"); +}), R(), D(), o.$emit("NotificationDrawerWrapper.onMarkAllRead"); }, notificationGroups: [], headingInclude: "views/directives/notifications/header.html", notificationBodyInclude: "views/directives/notifications/notification-body.html", customScope: { clear: function(e, t, n) { -c.markCleared(e.uid), n.notifications.splice(t, 1), k(); +c.markRead(e.uid), c.markCleared(e.uid), n.notifications.splice(t, 1), P(e), D(); }, markRead: function(e) { -e.unread = !1, c.markRead(e.uid), k(); +e.unread = !1, c.markRead(e.uid), D(); }, close: function() { p.drawerHidden = !0; @@ -14686,21 +14690,21 @@ e.onClick(), p.drawerHidden = !0; countUnreadNotifications: k } }); -var F = function() { -r.project && O(), f.push(o.$on("$routeChangeSuccess", function(e, t, n) { -b(t, n) && (p.customScope.projectName = r.project, O()); +var V = function() { +r.project && x(), f.push(o.$on("$routeChangeSuccess", function(e, t, n) { +b(t, n) && (p.customScope.projectName = r.project, x()); })), f.push(o.$on("NotificationDrawerWrapper.toggle", function() { p.drawerHidden = !p.drawerHidden; })), f.push(o.$on("NotificationDrawerWrapper.hide", function() { p.drawerHidden = !0; })), f.push(o.$on("NotificationDrawerWrapper.clear", function(e, t) { -c.markCleared(t.uid), j(t), p.countUnreadNotifications(); +c.markCleared(t.uid), P(t), p.countUnreadNotifications(); })); }; p.$onInit = function() { -d || m || F(); +d || m || V(); }, p.$onDestroy = function() { -A(), D(), N(); +B(), $(), A(); }; } ] });