mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-24 06:35:49 +03:00
Persistent notifications
closes #3057 - add Notification model - update injected Notifications object to handle persistent notifications - load server notifications on setup if logged in otherwise on successful sign-in - changed all existing notifications.closeAll calls to closePassive - fixed dismissable/dismissible spelling in server API & tests - add notifications.closeNotification method so DELETE calls can be made for server-originating notifications
This commit is contained in:
parent
9214f25dee
commit
7e2e8b3376
@ -13,9 +13,9 @@ var NotificationComponent = Ember.Component.extend({
|
||||
actions: {
|
||||
closeNotification: function () {
|
||||
var self = this;
|
||||
self.notifications.removeObject(self.get('message'));
|
||||
self.notifications.closeNotification(self.get('message'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default NotificationComponent;
|
||||
export default NotificationComponent;
|
||||
|
@ -7,9 +7,8 @@ var PostController = Ember.ObjectController.extend({
|
||||
var featured = this.toggleProperty('featured'),
|
||||
self = this;
|
||||
|
||||
// @TODO This should call closePassive() to only close passive notifications
|
||||
self.notifications.closeAll();
|
||||
|
||||
self.notifications.closePassive();
|
||||
|
||||
this.get('model').save().then(function () {
|
||||
self.notifications.showSuccess('Post successfully marked as ' + (featured ? 'featured' : 'not featured') + '.');
|
||||
}).catch(function (errors) {
|
||||
@ -20,4 +19,4 @@ var PostController = Ember.ObjectController.extend({
|
||||
}
|
||||
});
|
||||
|
||||
export default PostController;
|
||||
export default PostController;
|
||||
|
@ -30,8 +30,7 @@ var SettingsGeneralController = Ember.ObjectController.extend({
|
||||
save: function () {
|
||||
var self = this;
|
||||
|
||||
// @TODO This should call closePassive() to only close passive notifications
|
||||
self.notifications.closeAll();
|
||||
self.notifications.closePassive();
|
||||
|
||||
return this.get('model').save().then(function (model) {
|
||||
self.notifications.showSuccess('Settings successfully saved.');
|
||||
|
@ -22,9 +22,8 @@ var SettingsUserController = Ember.Controller.extend({
|
||||
actions: {
|
||||
save: function () {
|
||||
var self = this;
|
||||
|
||||
// @TODO This should call closePassive() to only close passive notifications
|
||||
self.notifications.closeAll();
|
||||
|
||||
self.notifications.closePassive();
|
||||
|
||||
alert('@TODO: Saving user...');
|
||||
|
||||
@ -64,4 +63,4 @@ var SettingsUserController = Ember.Controller.extend({
|
||||
|
||||
});
|
||||
|
||||
export default SettingsUserController;
|
||||
export default SettingsUserController;
|
||||
|
@ -15,8 +15,7 @@ var SetupController = Ember.ObjectController.extend(ValidationEngine, {
|
||||
setup: function () {
|
||||
var self = this;
|
||||
|
||||
// @TODO This should call closePassive() to only close passive notifications
|
||||
self.notifications.closeAll();
|
||||
self.notifications.closePassive();
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
this.validate({ format: false }).then(function () {
|
||||
|
@ -14,8 +14,7 @@ var SignupController = Ember.ObjectController.extend(ValidationEngine, {
|
||||
signup: function () {
|
||||
var self = this;
|
||||
|
||||
// @TODO This should call closePassive() to only close passive notifications
|
||||
self.notifications.closeAll();
|
||||
self.notifications.closePassive();
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
this.validate({ format: false }).then(function () {
|
||||
|
@ -166,14 +166,14 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
|
||||
showSaveNotification: function (prevStatus, status, delay) {
|
||||
var message = this.messageMap.success.post[prevStatus][status];
|
||||
this.notifications.closeAll();
|
||||
this.notifications.closePassive();
|
||||
|
||||
this.notifications.showSuccess(message, delay);
|
||||
},
|
||||
|
||||
showErrorNotification: function (prevStatus, status, errors, delay) {
|
||||
var message = this.messageMap.errors.post[prevStatus][status];
|
||||
this.notifications.closeAll();
|
||||
this.notifications.closePassive();
|
||||
|
||||
message += '<br />' + errors[0].message;
|
||||
|
||||
@ -187,8 +187,7 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
isNew = this.get('isNew'),
|
||||
self = this;
|
||||
|
||||
// @TODO This should call closePassive() to only close passive notifications
|
||||
self.notifications.closeAll();
|
||||
self.notifications.closePassive();
|
||||
|
||||
// ensure an incomplete tag is finalised before save
|
||||
this.get('controllers.post-tags-input').send('addNewTag');
|
||||
|
13
core/client/models/notification.js
Normal file
13
core/client/models/notification.js
Normal file
@ -0,0 +1,13 @@
|
||||
var Notification = DS.Model.extend({
|
||||
dismissible: DS.attr('boolean'),
|
||||
location: DS.attr('string'),
|
||||
status: DS.attr('string'),
|
||||
type: DS.attr('string'),
|
||||
message: DS.attr('string'),
|
||||
|
||||
typeClass: function () {
|
||||
return 'notification-' + this.get('type');
|
||||
}.property('type')
|
||||
});
|
||||
|
||||
export default Notification;
|
@ -9,8 +9,7 @@ Router.reopen({
|
||||
rootURL: ghostPaths().subdir + '/ghost/', // admin interface lives under sub-directory /ghost
|
||||
|
||||
clearNotifications: function () {
|
||||
// @TODO This should call closePassive() to only close passive notifications
|
||||
this.notifications.closeAll();
|
||||
this.notifications.closePassive();
|
||||
this.notifications.displayDelayed();
|
||||
}.on('didTransition')
|
||||
});
|
||||
|
@ -33,6 +33,12 @@ var ApplicationRoute = Ember.Route.extend(Ember.SimpleAuth.ApplicationRouteMixin
|
||||
});
|
||||
}.on('init'),
|
||||
|
||||
setupController: function () {
|
||||
Ember.run.next(this, function () {
|
||||
this.send('loadServerNotifications');
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
closePopups: function () {
|
||||
this.get('popover').closePopovers();
|
||||
@ -51,6 +57,8 @@ var ApplicationRoute = Ember.Route.extend(Ember.SimpleAuth.ApplicationRouteMixin
|
||||
|
||||
this.set('user', user);
|
||||
this.set('controller.user', user);
|
||||
|
||||
this.send('loadServerNotifications', true);
|
||||
},
|
||||
|
||||
signedOut: function () {
|
||||
@ -90,6 +98,17 @@ var ApplicationRoute = Ember.Route.extend(Ember.SimpleAuth.ApplicationRouteMixin
|
||||
});
|
||||
},
|
||||
|
||||
loadServerNotifications: function (isDelayed) {
|
||||
var self = this;
|
||||
if (this.session.isAuthenticated) {
|
||||
this.store.findAll('notification').then(function (serverNotifications) {
|
||||
serverNotifications.forEach(function (notification) {
|
||||
self.notifications.handleNotification(notification, isDelayed);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
handleErrors: function (errors) {
|
||||
var self = this;
|
||||
this.notifications.clear();
|
||||
|
@ -1,7 +1,10 @@
|
||||
import Notification from 'ghost/models/notification';
|
||||
|
||||
var Notifications = Ember.ArrayProxy.extend({
|
||||
delayedNotifications: [],
|
||||
content: Ember.A(),
|
||||
timeout: 3000,
|
||||
|
||||
pushObject: function (object) {
|
||||
object.typeClass = 'notification-' + object.type;
|
||||
// This should be somewhere else.
|
||||
@ -11,6 +14,10 @@ var Notifications = Ember.ArrayProxy.extend({
|
||||
this._super(object);
|
||||
},
|
||||
handleNotification: function (message, delayed) {
|
||||
if (!message.status) {
|
||||
message.status = 'passive';
|
||||
}
|
||||
|
||||
if (!delayed) {
|
||||
this.pushObject(message);
|
||||
} else {
|
||||
@ -63,6 +70,24 @@ var Notifications = Ember.ArrayProxy.extend({
|
||||
});
|
||||
self.delayedNotifications = [];
|
||||
},
|
||||
closeNotification: function (notification) {
|
||||
var self = this;
|
||||
|
||||
if (notification instanceof Notification) {
|
||||
notification.deleteRecord();
|
||||
notification.save().then(function () {
|
||||
self.removeObject(notification);
|
||||
});
|
||||
} else {
|
||||
this.removeObject(notification);
|
||||
}
|
||||
},
|
||||
closePassive: function () {
|
||||
this.set('content', this.rejectBy('status', 'passive'));
|
||||
},
|
||||
closePersistent: function () {
|
||||
this.set('content', this.rejectBy('status', 'persistent'));
|
||||
},
|
||||
closeAll: function () {
|
||||
this.clear();
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ notifications = {
|
||||
return element.id === parseInt(options.id, 10);
|
||||
});
|
||||
|
||||
if (notification && !notification.dismissable) {
|
||||
if (notification && !notification.dismissible) {
|
||||
return when.reject(
|
||||
new errors.NoPermissionError('You do not have permission to dismiss this notification.')
|
||||
);
|
||||
@ -78,14 +78,14 @@ notifications = {
|
||||
* type: 'error', // this can be 'error', 'success', 'warn' and 'info'
|
||||
* message: 'This is an error', // A string. Should fit in one line.
|
||||
* location: 'bottom', // A string where this notification should appear. can be 'bottom' or 'top'
|
||||
* dismissable: true // A Boolean. Whether the notification is dismissable or not.
|
||||
* dismissible: true // A Boolean. Whether the notification is dismissible or not.
|
||||
* }] };
|
||||
* ```
|
||||
*/
|
||||
add: function add(object) {
|
||||
|
||||
var defaults = {
|
||||
dismissable: true,
|
||||
dismissible: true,
|
||||
location: 'bottom',
|
||||
status: 'persistent'
|
||||
},
|
||||
@ -110,4 +110,4 @@ notifications = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = notifications;
|
||||
module.exports = notifications;
|
||||
|
@ -59,7 +59,7 @@ describe('Notifications API', function () {
|
||||
should.exist(result.notifications);
|
||||
|
||||
notification = result.notifications[0];
|
||||
notification.dismissable.should.be.true;
|
||||
notification.dismissible.should.be.true;
|
||||
should.exist(notification.location);
|
||||
notification.location.should.equal('bottom');
|
||||
|
||||
@ -85,7 +85,7 @@ describe('Notifications API', function () {
|
||||
notification.id.should.not.equal(99);
|
||||
should.exist(notification.status);
|
||||
notification.status.should.equal('persistent')
|
||||
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
@ -108,4 +108,4 @@ describe('Notifications API', function () {
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -18,7 +18,7 @@ var url = require('url'),
|
||||
user: ['id', 'uuid', 'name', 'slug', 'email', 'image', 'cover', 'bio', 'website',
|
||||
'location', 'accessibility', 'status', 'language', 'meta_title', 'meta_description', 'last_login',
|
||||
'created_at', 'created_by', 'updated_at', 'updated_by'],
|
||||
notification: ['type', 'message', 'status', 'id', 'dismissable', 'location'],
|
||||
notification: ['type', 'message', 'status', 'id', 'dismissible', 'location'],
|
||||
slugs: ['slugs'],
|
||||
slug: ['slug'],
|
||||
accesstoken: ['access_token', 'refresh_token', 'expires_in', 'token_type']
|
||||
|
Loading…
Reference in New Issue
Block a user