Skip to content
Permalink
Browse files

[IMP] web, *: share and improve notification system

* calendar, partner_autocomplete

Make the notification system better, using bootstrap toast component,
and make it available in the frontend.

task-1970731
  • Loading branch information...
qsm-odoo committed Apr 18, 2019
1 parent ed3f6f2 commit 5e5f916ff773f8df3653bf476644620052583b9b
@@ -2,13 +2,13 @@ odoo.define('base_calendar.base_calendar', function (require) {
"use strict";

var BasicModel = require('web.BasicModel');
var field_registry = require('web.field_registry');
var fieldRegistry = require('web.field_registry');
var Notification = require('web.Notification');
var relational_fields = require('web.relational_fields');
var relationalFields = require('web.relational_fields');
var session = require('web.session');
var WebClient = require('web.WebClient');

var FieldMany2ManyTags = relational_fields.FieldMany2ManyTags;
var FieldMany2ManyTags = relationalFields.FieldMany2ManyTags;


var CalendarNotification = Notification.extend({
@@ -155,6 +155,6 @@ var Many2ManyAttendee = FieldMany2ManyTags.extend({
},
});

field_registry.add('many2manyattendee', Many2ManyAttendee);
fieldRegistry.add('many2manyattendee', Many2ManyAttendee);

});
@@ -80,13 +80,8 @@ odoo.define('partner_autocomplete.tests', function (require) {
_getClearbitSuggestions: function (value) {
return this._getOdooSuggestions(value);
},
do_notify: function (title, message, sticky, className) {
return this.call('notification', 'notify', {
title: title,
message: message,
sticky: true,
className: 'o_partner_autocomplete_test_notify'
});
do_notify: function (title, message, type, sticky, className) {
return this.displayNotification(title, message, 'warning', true, 'o_partner_autocomplete_test_notify');
},
});
});
@@ -222,11 +222,37 @@ var ServicesMixin = {
});
});
},
/**
* Displays a notification.
*
* @param {string} title
* @param {string} [message]
* @param {string} [type='warning'] 'info', 'warning', 'danger' or ''
* @param {boolean} [sticky=false]
* @param {string} [className]
*/
displayNotification: function (title, message, type, sticky, className) {
return this.call('notification', 'notify', {
type: type,
title: title,
message: message,
sticky: sticky,
className: className,
});
},
/**
* @deprecated will be removed as soon as the notification system is reviewed
* @see displayNotification
*/
do_notify: function (title, message, sticky, className) {
return this.call('notification', 'notify', {title: title, message: message, sticky: sticky, className: className});
return this.displayNotification(title, message, 'warning', sticky, className);
},
/**
* @deprecated will be removed as soon as the notification system is reviewed
* @see displayNotification
*/
do_warn: function (title, message, sticky, className) {
return this.call('notification', 'notify', {type: 'warning', title: title, message: message, sticky: sticky, className: className});
return this.displayNotification(title, message, 'danger', sticky, className);
},
};

@@ -1,9 +1,10 @@
odoo.define('web.NotificationService', function (require) {
"use strict";
'use strict';

var AbstractService = require('web.AbstractService');
var Notification = require('web.Notification');
var core = require('web.core');

var id = 0;

/**
@@ -16,9 +17,7 @@ var id = 0;
* by using this file. The proper way is to use the do_warn or do_notify
* methods on the Widget class.
*/

var NotificationService = AbstractService.extend({

custom_events: {
close: '_onCloseNotification',
},
@@ -37,8 +36,8 @@ var NotificationService = AbstractService.extend({

/**
* It may sometimes be useful to close programmatically a notification. For
* example, when there is a sticky notification that warns the user about
* some condition (connection lost), but the condition do not apply anymore.
* example, when there is a sticky notification warning the user about some
* condition (connection lost), but the condition does not apply anymore.
*
* @param {number} notificationId
* @param {boolean} [silent=false] if true, the notification does not call
@@ -105,9 +104,7 @@ var NotificationService = AbstractService.extend({
},
});


core.serviceRegistry.add('notification', NotificationService);


return NotificationService;
});
@@ -1,39 +1,38 @@
odoo.define('web.Notification', function (require) {
"use strict";
'use strict';

var Widget = require('web.Widget');

/**
* Notification
*
* This file contains the widget which is used to display a warning/information
* message in the top right of the screen.
* Widget which is used to display a warning/information message on the top
* right of the screen.
*
* If you want to display such a notification, you probably do not want to do it
* by importing this file. The proper way is to use the do_warn or do_notify
* methods on the Widget class.
*/

var Widget = require('web.Widget');

var Notification = Widget.extend({
template: 'Notification',
xmlDependencies: ['/web/static/src/xml/notification.xml'],
events: {
'click > .o_close': '_onClose',
'click .o_buttons button': '_onClickButton'
'hidden.bs.toast': '_onClose',
'click .o_notification_buttons button': '_onClickButton'
},
_autoCloseDelay: 2500,
_animationDelay: 400,
_animation: true,

/**
* @override
* @param {Widget} parent
* @param {Object} params
* @param {string} params.title notification title
* @param {string} params.message notification main message
* @param {string} params.type 'notification' or 'warning'
* @param {boolean} [params.sticky=false] if true, the notification will stay
* visible until the user clicks on it.
* @param {string} [params.className] className to add on the dom
* @param {string} params.title
* @param {string} [params.message]
* @param {string} [params.type='warning'] 'danger', 'warning', 'info' or ''
* @param {boolean} [params.sticky=false] if true, the notification will
* stay visible until the user clicks on it.
* @param {string} [params.className]
* @param {function} [params.onClose] callback when the user click on the x
* or when the notification is auto close (no sticky)
* or when the notification is auto close (no sticky)
* @param {Object[]} params.buttons
* @param {function} params.buttons[0].click callback on click
* @param {boolean} [params.buttons[0].primary] display the button as primary
@@ -46,55 +45,60 @@ var Notification = Widget.extend({
this.message = params.message;
this.buttons = params.buttons || [];
this.sticky = !!this.buttons.length || !!params.sticky;
this.type = params.type || 'notification';
this.type = params.type === undefined ? 'warning' : params.type;
this.className = params.className || '';
this._closeCallback = params.onClose;
this.icon = 'fa-lightbulb-o';

if (this.type === 'danger') {
this.icon = 'fa-exclamation';
this.className += ' bg-danger';
} else if (this.type === 'warning') {
this.icon = 'fa-lightbulb-o';
this.className += ' bg-warning';
} else if (this.type === 'info') {
this.icon = 'fa-info';
this.className += ' bg-info';
}

if (this.buttons && this.buttons.length) {
this.icon = 'fa-question-circle-o';
}
if (this.type === 'warning') {
this.icon = 'fa-exclamation';
this.className += ' o_error';
}
},
/**
* @override
*/
start: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
self.$el.animate({opacity: 1.0}, self._animationDelay, "swing", function () {
if(!self.sticky) {
setTimeout(function () {
self.close();
}, self._autoCloseDelay);
}
});
this.$el.toast({
animation: this._animation,
autohide: !this.sticky,
delay: this._autoCloseDelay,
});
void this.$el[0].offsetWidth; // Force a paint refresh before showing the toast
this.$el.toast('show');
return this._super.apply(this, arguments);
},
/**
* @override
*/
destroy: function () {
this.$el.toast('dispose');
this._super.apply(this, arguments);
},

//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------

/**
* This method is used to destroy the widget with a nice animation. We
* first perform an animation, then call the real destroy method.
* Destroys the widget with a nice animation.
*
* @private
* @param {boolean} [silent=false] if true, the notification does not call
* _closeCallback method
*/
close: function (silent) {
var self = this;
this.trigger_up('close');
if (!silent && !this._buttonClicked) {
if (this._closeCallback) {
this._closeCallback();
}
}
this.$el.animate({opacity: 0.0, height: 0}, this._animationDelay, "swing", self.destroy.bind(self));
this.silent = silent;
this.$el.toast('hide');
},

//--------------------------------------------------------------------------
@@ -120,14 +124,18 @@ var Notification = Widget.extend({
},
/**
* @private
* @param {MouseEvent} ev
* @param {Event} ev
*/
_onClose: function (ev) {
ev.preventDefault();
this.close();
this.trigger_up('close');
if (!this.silent && !this._buttonClicked) {
if (this._closeCallback) {
this._closeCallback();
}
}
this.destroy();
},
});

return Notification;

});
@@ -117,6 +117,13 @@ $nav-pills-border-radius: 0 !default;
$nav-pills-link-active-color: $white !default;
$nav-pills-link-active-bg: $o-brand-primary !default;

// Toasts

$toast-max-width: 300px !default;
$toast-padding-x: 1.5rem !default;
$toast-padding-y: 0.5rem !default;
$toast-font-size: $font-size-base !default;

// Badges

$badge-font-weight: normal !default;
@@ -41,6 +41,14 @@
}
}

.toast-header {
background-clip: border-box;
}
.toast-body {
// Same as card-body, see explanation above
@include o-bg-color(opacify($toast-background-color, 0.05));
}

// Modify modals so that their scrollable element is the modal-body (except in
// mobile).
@include media-breakpoint-up(sm) {
@@ -37,7 +37,7 @@

.o_field_invalid {
.o_signature {
outline: 3px solid $o-notification-error-bg-color;
outline: 3px solid theme-color('danger');
cursor: pointer;
}
}
@@ -0,0 +1,12 @@

.o_notification_manager {
@include o-position-absolute($nav-link-height, 0);
position: fixed;
z-index: ($zindex-modal + $zindex-popover) / 2;
width: $toast-max-width;
max-width: 100%;

.o_notification {
width: 100%;
}
}
@@ -62,9 +62,6 @@ $o-dropdown-hpadding: 20px;

$o-sheet-vpadding: 24px;

$o-notification-error-bg-color: #F16567;
$o-notification-info-bg-color: #FCFBEA;

$o-modal-lg: 980px;
$o-modal-md: 650px;

Oops, something went wrong.

0 comments on commit 5e5f916

Please sign in to comment.
You can’t perform that action at this time.