Optimize Notifications Rendering

This commit is contained in:
Shpuld Shpludson 2020-01-14 13:28:57 +00:00
parent dd740043c6
commit 86380f0429
5 changed files with 30 additions and 9 deletions

View file

@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Changed
- Notifications column now cleans itself up to optimize performance when tab is left open for a long time
### Fixed ### Fixed
- Single notifications left unread when hitting read on another device/tab - Single notifications left unread when hitting read on another device/tab

View file

@ -2,10 +2,12 @@ import Notification from '../notification/notification.vue'
import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js' import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js'
import { import {
notificationsFromStore, notificationsFromStore,
visibleNotificationsFromStore, filteredNotificationsFromStore,
unseenNotificationsFromStore unseenNotificationsFromStore
} from '../../services/notification_utils/notification_utils.js' } from '../../services/notification_utils/notification_utils.js'
const DEFAULT_SEEN_TO_DISPLAY_COUNT = 30
const Notifications = { const Notifications = {
props: { props: {
// Disables display of panel header // Disables display of panel header
@ -18,7 +20,11 @@ const Notifications = {
}, },
data () { data () {
return { return {
bottomedOut: false bottomedOut: false,
// How many seen notifications to display in the list. The more there are,
// the heavier the page becomes. This count is increased when loading
// older notifications, and cut back to default whenever hitting "Read!".
seenToDisplayCount: DEFAULT_SEEN_TO_DISPLAY_COUNT
} }
}, },
computed: { computed: {
@ -34,14 +40,17 @@ const Notifications = {
unseenNotifications () { unseenNotifications () {
return unseenNotificationsFromStore(this.$store) return unseenNotificationsFromStore(this.$store)
}, },
visibleNotifications () { filteredNotifications () {
return visibleNotificationsFromStore(this.$store, this.filterMode) return filteredNotificationsFromStore(this.$store, this.filterMode)
}, },
unseenCount () { unseenCount () {
return this.unseenNotifications.length return this.unseenNotifications.length
}, },
loading () { loading () {
return this.$store.state.statuses.notifications.loading return this.$store.state.statuses.notifications.loading
},
notificationsToDisplay () {
return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount)
} }
}, },
components: { components: {
@ -64,12 +73,21 @@ const Notifications = {
methods: { methods: {
markAsSeen () { markAsSeen () {
this.$store.dispatch('markNotificationsAsSeen') this.$store.dispatch('markNotificationsAsSeen')
this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT
}, },
fetchOlderNotifications () { fetchOlderNotifications () {
if (this.loading) { if (this.loading) {
return return
} }
const seenCount = this.filteredNotifications.length - this.unseenCount
if (this.seenToDisplayCount < seenCount) {
this.seenToDisplayCount = Math.min(this.seenToDisplayCount + 20, seenCount)
return
} else if (this.seenToDisplayCount > seenCount) {
this.seenToDisplayCount = seenCount
}
const store = this.$store const store = this.$store
const credentials = store.state.users.currentUser.credentials const credentials = store.state.users.currentUser.credentials
store.commit('setNotificationsLoading', { value: true }) store.commit('setNotificationsLoading', { value: true })
@ -82,6 +100,7 @@ const Notifications = {
if (notifs.length === 0) { if (notifs.length === 0) {
this.bottomedOut = true this.bottomedOut = true
} }
this.seenToDisplayCount += notifs.length
}) })
} }
} }

View file

@ -32,7 +32,7 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div <div
v-for="notification in visibleNotifications" v-for="notification in notificationsToDisplay"
:key="notification.id" :key="notification.id"
class="notification" class="notification"
:class="{&quot;unseen&quot;: !minimalMode && !notification.seen}" :class="{&quot;unseen&quot;: !minimalMode && !notification.seen}"

View file

@ -26,7 +26,7 @@ const sortById = (a, b) => {
} }
} }
export const visibleNotificationsFromStore = (store, types) => { export const filteredNotificationsFromStore = (store, types) => {
// map is just to clone the array since sort mutates it and it causes some issues // map is just to clone the array since sort mutates it and it causes some issues
let sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById) let sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById)
sortedNotifications = sortBy(sortedNotifications, 'seen') sortedNotifications = sortBy(sortedNotifications, 'seen')
@ -36,4 +36,4 @@ export const visibleNotificationsFromStore = (store, types) => {
} }
export const unseenNotificationsFromStore = store => export const unseenNotificationsFromStore = store =>
filter(visibleNotificationsFromStore(store), ({ seen }) => !seen) filter(filteredNotificationsFromStore(store), ({ seen }) => !seen)

View file

@ -1,7 +1,7 @@
import * as NotificationUtils from 'src/services/notification_utils/notification_utils.js' import * as NotificationUtils from 'src/services/notification_utils/notification_utils.js'
describe('NotificationUtils', () => { describe('NotificationUtils', () => {
describe('visibleNotificationsFromStore', () => { describe('filteredNotificationsFromStore', () => {
it('should return sorted notifications with configured types', () => { it('should return sorted notifications with configured types', () => {
const store = { const store = {
state: { state: {
@ -47,7 +47,7 @@ describe('NotificationUtils', () => {
type: 'like' type: 'like'
} }
] ]
expect(NotificationUtils.visibleNotificationsFromStore(store)).to.eql(expected) expect(NotificationUtils.filteredNotificationsFromStore(store)).to.eql(expected)
}) })
}) })