mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 23:58:31 -05:00
FEATURE: live refresh notifications as they happen
This commit is contained in:
parent
8bc7423045
commit
a54e8f3c5e
6 changed files with 75 additions and 23 deletions
|
@ -50,10 +50,20 @@ export default Ember.Component.extend({
|
|||
// TODO: It's a bit odd to use the store in a component, but this one really
|
||||
// wants to reach out and grab notifications
|
||||
const store = this.container.lookup('store:main');
|
||||
const stale = store.findStale('notification', {recent: true, limit });
|
||||
const stale = store.findStale('notification', {recent: true, limit }, {storageKey: 'recent-notifications'});
|
||||
|
||||
if (stale.hasResults) {
|
||||
this.set('notifications', stale.results);
|
||||
const results = stale.results;
|
||||
var content = results.get('content');
|
||||
|
||||
// we have to truncate to limit, otherwise we will render too much
|
||||
if (content && (content.length > limit)) {
|
||||
content = content.splice(0, limit);
|
||||
results.set('content', content);
|
||||
results.set('totalRows', limit);
|
||||
}
|
||||
|
||||
this.set('notifications', results);
|
||||
} else {
|
||||
this.set('loadingNotifications', true);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,12 @@ export default {
|
|||
const user = container.lookup('current-user:main'),
|
||||
site = container.lookup('site:main'),
|
||||
siteSettings = container.lookup('site-settings:main'),
|
||||
bus = container.lookup('message-bus:main');
|
||||
bus = container.lookup('message-bus:main'),
|
||||
keyValueStore = container.lookup('key-value-store:main');
|
||||
|
||||
// clear old cached notifications
|
||||
// they could be a week old for all we know
|
||||
keyValueStore.remove('recent-notifications');
|
||||
|
||||
if (user) {
|
||||
|
||||
|
@ -38,6 +43,32 @@ export default {
|
|||
if (oldUnread !== data.unread_notifications || oldPM !== data.unread_private_messages) {
|
||||
user.set('lastNotificationChange', new Date());
|
||||
}
|
||||
|
||||
var stale = keyValueStore.getObject('recent-notifications');
|
||||
const lastNotification = data.last_notification && data.last_notification.notification;
|
||||
|
||||
if (stale && stale.notifications && lastNotification) {
|
||||
|
||||
const oldNotifications = stale.notifications;
|
||||
const staleIndex = _.findIndex(oldNotifications, {id: lastNotification.id});
|
||||
|
||||
if (staleIndex > -1) {
|
||||
oldNotifications.splice(staleIndex, 1);
|
||||
}
|
||||
|
||||
// this gets a bit tricky, uread pms are bumped to front
|
||||
var insertPosition = 0;
|
||||
if (lastNotification.notification_type !== 6) {
|
||||
insertPosition = _.findIndex(oldNotifications, function(n){
|
||||
return n.notification_type !== 6 || n.read;
|
||||
});
|
||||
insertPosition = insertPosition === -1 ? oldNotifications.length - 1 : insertPosition;
|
||||
}
|
||||
|
||||
oldNotifications.splice(insertPosition, 0, lastNotification);
|
||||
keyValueStore.setItem('recent-notifications', JSON.stringify(stale));
|
||||
|
||||
}
|
||||
}, user.notification_channel_position);
|
||||
|
||||
bus.subscribe("/categories", function(data) {
|
||||
|
|
|
@ -43,6 +43,13 @@ KeyValueStore.prototype = {
|
|||
get(key) {
|
||||
if (!safeLocalStorage) { return null; }
|
||||
return safeLocalStorage[this.context + key];
|
||||
},
|
||||
|
||||
getObject(key) {
|
||||
if (!safeLocalStorage) { return null; }
|
||||
try {
|
||||
return JSON.parse(safeLocalStorage[this.context + key]);
|
||||
} catch(e) {}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import StaleResult from 'discourse/lib/stale-result';
|
||||
import { hashString } from 'discourse/lib/hash';
|
||||
|
||||
var skipFirst = true;
|
||||
|
||||
// Mix this in to an adapter to provide stale caching in our key value store
|
||||
export default {
|
||||
storageKey(type, findArgs) {
|
||||
|
@ -10,17 +8,14 @@ export default {
|
|||
return `${type}_${hashedArgs}`;
|
||||
},
|
||||
|
||||
findStale(store, type, findArgs) {
|
||||
findStale(store, type, findArgs, opts) {
|
||||
const staleResult = new StaleResult();
|
||||
const key = (opts && opts.storageKey) || this.storageKey(type, findArgs)
|
||||
try {
|
||||
if (!skipFirst) {
|
||||
const stored = this.keyValueStore.getItem(this.storageKey(type, findArgs));
|
||||
if (stored) {
|
||||
const parsed = JSON.parse(stored);
|
||||
staleResult.setResults(parsed);
|
||||
}
|
||||
} else {
|
||||
skipFirst = false;
|
||||
const stored = this.keyValueStore.getItem(key);
|
||||
if (stored) {
|
||||
const parsed = JSON.parse(stored);
|
||||
staleResult.setResults(parsed);
|
||||
}
|
||||
} catch(e) {
|
||||
// JSON parsing error
|
||||
|
@ -28,9 +23,11 @@ export default {
|
|||
return staleResult;
|
||||
},
|
||||
|
||||
find(store, type, findArgs) {
|
||||
find(store, type, findArgs, opts) {
|
||||
const key = (opts && opts.storageKey) || this.storageKey(type, findArgs)
|
||||
|
||||
return this._super(store, type, findArgs).then((results) => {
|
||||
this.keyValueStore.setItem(this.storageKey(type, findArgs), JSON.stringify(results));
|
||||
this.keyValueStore.setItem(key, JSON.stringify(results));
|
||||
return results;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -71,18 +71,18 @@ export default Ember.Object.extend({
|
|||
|
||||
// See if the store can find stale data. We sometimes prefer to show stale data and
|
||||
// refresh it in the background.
|
||||
findStale(type, findArgs) {
|
||||
const stale = this.adapterFor(type).findStale(this, type, findArgs);
|
||||
findStale(type, findArgs, opts) {
|
||||
const stale = this.adapterFor(type).findStale(this, type, findArgs, opts);
|
||||
if (stale.hasResults) {
|
||||
stale.results = this._hydrateFindResults(stale.results, type, findArgs);
|
||||
}
|
||||
stale.refresh = () => this.find(type, findArgs);
|
||||
stale.refresh = () => this.find(type, findArgs, opts);
|
||||
return stale;
|
||||
},
|
||||
|
||||
find(type, findArgs) {
|
||||
return this.adapterFor(type).find(this, type, findArgs).then((result) => {
|
||||
return this._hydrateFindResults(result, type, findArgs);
|
||||
find(type, findArgs, opts) {
|
||||
return this.adapterFor(type).find(this, type, findArgs, opts).then((result) => {
|
||||
return this._hydrateFindResults(result, type, findArgs, opts);
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -306,10 +306,17 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def publish_notifications_state
|
||||
# publish last notification json with the message so we
|
||||
# can apply an update
|
||||
notification = notifications.visible.order('notifications.id desc').first
|
||||
json = NotificationSerializer.new(notification).as_json if notification
|
||||
|
||||
MessageBus.publish("/notification/#{id}",
|
||||
{unread_notifications: unread_notifications,
|
||||
unread_private_messages: unread_private_messages,
|
||||
total_unread_notifications: total_unread_notifications},
|
||||
total_unread_notifications: total_unread_notifications,
|
||||
last_notification: json
|
||||
},
|
||||
user_ids: [id] # only publish the notification to this user
|
||||
)
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue