[REF] web: refactor notification system

This commit does some improvements on notification system:

- move notification handling logic in service
- remove use of __destroy
- simplify types

closes odoo-dev/odoo#955

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Géry Debongnie
2021-06-18 21:31:33 +02:00
committed by Aaron Bohy
parent 85dfc9cf49
commit d1b260b424
2 changed files with 58 additions and 80 deletions
@@ -1,62 +1,25 @@
/** @odoo-module **/
import { Notification as NotificationComponent } from "./notification";
import { Notification } from "./notification";
const { Component, tags } = owl;
export class NotificationContainer extends Component {
setup() {
this.notifications = [];
this.props.bus.on("ADD", this, this.add);
this.props.bus.on("REMOVE", this, this.remove);
}
__destroy() {
this.props.bus.off("ADD", this, this.add);
this.props.bus.off("REMOVE", this, this.remove);
super.__destroy();
}
/**
* @param {Object} params
* @param {number} params.id
* @param {{
* name: string;
* icon?: string;
* primary?: boolean;
* onClick: () => void
* }[]} params.buttons
* @param {string} params.className
* @param {string} params.message
* @param {boolean} params.messageIsHtml
* @param {() => void} params.onClose
* @param {string} params.title
* @param {"warning" | "danger" | "success" | "info"} params.type
*/
add(params) {
const { id, ...props } = params;
this.notifications.push({ id, props });
this.render();
}
/**
* @param {number} id
*/
remove(id) {
const index = this.notifications.findIndex((n) => n.id === id);
if (index > -1) {
this.notifications.splice(index, 1);
this.render();
}
// this works, but then this component cannot be unmounted, then
// remounted. would need a destroyed hook different from willunmount
this.props.bus.on("UPDATE", this, this.render);
}
}
NotificationContainer.template = tags.xml`
<div class="o_notification_manager">
<t t-foreach="notifications" t-as="notification" t-key="notification.id">
<NotificationComponent
<t t-foreach="props.notifications" t-as="notification" t-key="notification.id">
<Notification
t-props="notification.props"
t-transition="o_notification_fade"
t-on-close="remove(notification.id)"
t-on-close="notification.close()"
/>
</t>
</div>`;
NotificationContainer.components = { NotificationComponent };
NotificationContainer.components = { Notification };
@@ -8,50 +8,65 @@ const { EventBus } = owl.core;
const AUTOCLOSE_DELAY = 4000;
/**
* @typedef {Object} NotificationButton
* @property {string} name
* @property {string} [icon]
* @property {boolean} [primary]
* @property {() => void} onClick
*
* @typedef {Object} NotificationOptions
* @property {string} [title]
* @property {"warning" | "danger" | "success" | "info"} [type]
* @property {boolean} [sticky]
* @property {string} [className]
* @property {() => void} [onClose]
* @property {NotificationButton} [buttons]
*/
export const notificationService = {
start() {
let notifId = 0;
let notifications = [];
const bus = new EventBus();
registry.category("main_components").add("NotificationContainer", {
Component: NotificationContainer,
props: { bus },
props: { bus, notifications },
});
return {
bus,
/**
* @param {string} message
* @param {Object} [options]
* @param {{
* name: string;
* icon?: string;
* primary?: boolean;
* onClick: () => void
* }[]} [options.buttons]
* @param {string} [options.className]
* @param {boolean} [options.messageIsHtml]
* @param {() => void} [options.onClose]
* @param {boolean} [options.sticky]
* @param {string} [options.title]
* @param {"warning" | "danger" | "success" | "info"} [options.type]
*/
add(message, options = {}) {
const notif = Object.assign({}, options, {
id: ++notifId,
message,
});
const sticky = notif.sticky;
delete notif.sticky;
bus.trigger("ADD", notif);
if (!sticky) {
browser.setTimeout(() => bus.trigger("REMOVE", notif.id), AUTOCLOSE_DELAY);
}
return () => {
bus.trigger("REMOVE", notif.id);
};
},
};
/**
* @param {string} message
* @param {NotificationOptions} [options]
*/
function add(message, options = {}) {
const id = ++notifId;
const props = Object.assign({}, options, { message });
const sticky = props.sticky;
delete props.sticky;
const closeFn = () => close(id);
const notification = {
id,
props,
close: closeFn,
};
notifications.push(notification);
bus.trigger("UPDATE");
if (!sticky) {
browser.setTimeout(closeFn, AUTOCLOSE_DELAY);
}
return closeFn;
}
function close(id) {
const index = notifications.findIndex((n) => n.id === id);
if (index > -1) {
notifications.splice(index, 1);
bus.trigger("UPDATE");
}
}
return { add };
},
};