mirror of https://github.com/OCA/web.git
commit
7f0081339f
|
@ -75,13 +75,28 @@ or
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
self.env.user.notify_info(message='My information message')
|
self.env.user.notify_default(message='My default message')
|
||||||
|
|
||||||
or
|
|
||||||
|
The notifications can bring interactivity with some buttons.
|
||||||
|
|
||||||
|
* One allowing to refresh the active view
|
||||||
|
* Another allowing to send a window / client action
|
||||||
|
|
||||||
|
The reload button is activated when sending the notification with:
|
||||||
|
|
||||||
|
|
||||||
|
The action can be used using the ``action`` keyword:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
self.env.user.notify_default(message='My default message')
|
action = self.env.ref('sale.action_orders').read()[0]
|
||||||
|
action.update({
|
||||||
|
'res_id': self.id,
|
||||||
|
'views': [(False, 'form')],
|
||||||
|
})
|
||||||
|
self.env.user.notify_info('My information message', action=action)
|
||||||
|
|
||||||
|
|
||||||
.. figure:: https://raw.githubusercontent.com/OCA/web/16.0/web_notify/static/description/notifications_screenshot.gif
|
.. figure:: https://raw.githubusercontent.com/OCA/web/16.0/web_notify/static/description/notifications_screenshot.gif
|
||||||
:scale: 80 %
|
:scale: 80 %
|
||||||
|
@ -121,6 +136,7 @@ Contributors
|
||||||
* Aitor Bouzas <aitor.bouzas@adaptivecity.com>
|
* Aitor Bouzas <aitor.bouzas@adaptivecity.com>
|
||||||
* Shepilov Vladislav <shepilov.v@protonmail.com>
|
* Shepilov Vladislav <shepilov.v@protonmail.com>
|
||||||
* Kevin Khao <kevin.khao@akretion.com>
|
* Kevin Khao <kevin.khao@akretion.com>
|
||||||
|
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
|
||||||
* `Tecnativa <https://www.tecnativa.com>`_:
|
* `Tecnativa <https://www.tecnativa.com>`_:
|
||||||
|
|
||||||
* David Vidal
|
* David Vidal
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
from odoo import _, api, exceptions, fields, models
|
from odoo import _, api, exceptions, fields, models
|
||||||
|
|
||||||
from odoo.addons.bus.models.bus import channel_with_db, json_dump
|
from odoo.addons.bus.models.bus import channel_with_db, json_dump
|
||||||
|
from odoo.addons.web.controllers.main import clean_action
|
||||||
|
|
||||||
DEFAULT_MESSAGE = "Default message"
|
DEFAULT_MESSAGE = "Default message"
|
||||||
|
|
||||||
|
@ -42,34 +43,59 @@ class ResUsers(models.Model):
|
||||||
notify_default_channel_name = fields.Char(compute="_compute_channel_names")
|
notify_default_channel_name = fields.Char(compute="_compute_channel_names")
|
||||||
|
|
||||||
def notify_success(
|
def notify_success(
|
||||||
self, message="Default message", title=None, sticky=False, target=None
|
self,
|
||||||
|
message="Default message",
|
||||||
|
title=None,
|
||||||
|
sticky=False,
|
||||||
|
target=None,
|
||||||
|
action=None,
|
||||||
):
|
):
|
||||||
title = title or _("Success")
|
title = title or _("Success")
|
||||||
self._notify_channel(SUCCESS, message, title, sticky, target)
|
self._notify_channel(SUCCESS, message, title, sticky, target, action)
|
||||||
|
|
||||||
def notify_danger(
|
def notify_danger(
|
||||||
self, message="Default message", title=None, sticky=False, target=None
|
self,
|
||||||
|
message="Default message",
|
||||||
|
title=None,
|
||||||
|
sticky=False,
|
||||||
|
target=None,
|
||||||
|
action=None,
|
||||||
):
|
):
|
||||||
title = title or _("Danger")
|
title = title or _("Danger")
|
||||||
self._notify_channel(DANGER, message, title, sticky, target)
|
self._notify_channel(DANGER, message, title, sticky, target, action)
|
||||||
|
|
||||||
def notify_warning(
|
def notify_warning(
|
||||||
self, message="Default message", title=None, sticky=False, target=None
|
self,
|
||||||
|
message="Default message",
|
||||||
|
title=None,
|
||||||
|
sticky=False,
|
||||||
|
target=None,
|
||||||
|
action=None,
|
||||||
):
|
):
|
||||||
title = title or _("Warning")
|
title = title or _("Warning")
|
||||||
self._notify_channel(WARNING, message, title, sticky, target)
|
self._notify_channel(WARNING, message, title, sticky, target, action)
|
||||||
|
|
||||||
def notify_info(
|
def notify_info(
|
||||||
self, message="Default message", title=None, sticky=False, target=None
|
self,
|
||||||
|
message="Default message",
|
||||||
|
title=None,
|
||||||
|
sticky=False,
|
||||||
|
target=None,
|
||||||
|
action=None,
|
||||||
):
|
):
|
||||||
title = title or _("Information")
|
title = title or _("Information")
|
||||||
self._notify_channel(INFO, message, title, sticky, target)
|
self._notify_channel(INFO, message, title, sticky, target, action)
|
||||||
|
|
||||||
def notify_default(
|
def notify_default(
|
||||||
self, message="Default message", title=None, sticky=False, target=None
|
self,
|
||||||
|
message="Default message",
|
||||||
|
title=None,
|
||||||
|
sticky=False,
|
||||||
|
target=None,
|
||||||
|
action=None,
|
||||||
):
|
):
|
||||||
title = title or _("Default")
|
title = title or _("Default")
|
||||||
self._notify_channel(DEFAULT, message, title, sticky, target)
|
self._notify_channel(DEFAULT, message, title, sticky, target, action)
|
||||||
|
|
||||||
def _notify_channel(
|
def _notify_channel(
|
||||||
self,
|
self,
|
||||||
|
@ -78,6 +104,7 @@ class ResUsers(models.Model):
|
||||||
title=None,
|
title=None,
|
||||||
sticky=False,
|
sticky=False,
|
||||||
target=None,
|
target=None,
|
||||||
|
action=None,
|
||||||
):
|
):
|
||||||
if not (self.env.user._is_admin() or self.env.su) and any(
|
if not (self.env.user._is_admin() or self.env.su) and any(
|
||||||
user.id != self.env.uid for user in self
|
user.id != self.env.uid for user in self
|
||||||
|
@ -87,11 +114,14 @@ class ResUsers(models.Model):
|
||||||
)
|
)
|
||||||
if not target:
|
if not target:
|
||||||
target = self.partner_id
|
target = self.partner_id
|
||||||
|
if action:
|
||||||
|
action = clean_action(action, self.env)
|
||||||
bus_message = {
|
bus_message = {
|
||||||
"type": type_message,
|
"type": type_message,
|
||||||
"message": message,
|
"message": message,
|
||||||
"title": title,
|
"title": title,
|
||||||
"sticky": sticky,
|
"sticky": sticky,
|
||||||
|
"action": action,
|
||||||
}
|
}
|
||||||
|
|
||||||
notifications = [[partner, "web.notify", [bus_message]] for partner in target]
|
notifications = [[partner, "web.notify", [bus_message]] for partner in target]
|
||||||
|
|
|
@ -29,6 +29,27 @@ or
|
||||||
|
|
||||||
self.env.user.notify_default(message='My default message')
|
self.env.user.notify_default(message='My default message')
|
||||||
|
|
||||||
|
|
||||||
|
The notifications can bring interactivity with some buttons.
|
||||||
|
|
||||||
|
* One allowing to refresh the active view
|
||||||
|
* Another allowing to send a window / client action
|
||||||
|
|
||||||
|
The reload button is activated when sending the notification with:
|
||||||
|
|
||||||
|
|
||||||
|
The action can be used using the ``action`` keyword:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
action = self.env["ir.actions.act_window"]._for_xml_id('sale.action_orders')
|
||||||
|
action.update({
|
||||||
|
'res_id': self.id,
|
||||||
|
'views': [(False, 'form')],
|
||||||
|
})
|
||||||
|
self.env.user.notify_info('My information message', action=action)
|
||||||
|
|
||||||
|
|
||||||
.. figure:: static/description/notifications_screenshot.gif
|
.. figure:: static/description/notifications_screenshot.gif
|
||||||
:scale: 80 %
|
:scale: 80 %
|
||||||
:alt: Sample notifications
|
:alt: Sample notifications
|
||||||
|
|
|
@ -4,27 +4,39 @@ import {browser} from "@web/core/browser/browser";
|
||||||
import {registry} from "@web/core/registry";
|
import {registry} from "@web/core/registry";
|
||||||
|
|
||||||
export const webNotificationService = {
|
export const webNotificationService = {
|
||||||
dependencies: ["bus_service", "notification"],
|
dependencies: ["bus_service", "notification", "action"],
|
||||||
|
|
||||||
start(env, {bus_service, notification}) {
|
start(env, {bus_service, notification, action}) {
|
||||||
let webNotifTimeouts = {};
|
let webNotifTimeouts = {};
|
||||||
/**
|
/**
|
||||||
* Displays the web notification on user's screen
|
* Displays the web notification on user's screen
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function displaywebNotification(notifications) {
|
function displaywebNotification(notifications) {
|
||||||
Object.values(webNotifTimeouts).forEach((notif) =>
|
Object.values(webNotifTimeouts).forEach((notif) =>
|
||||||
browser.clearTimeout(notif)
|
browser.clearTimeout(notif)
|
||||||
);
|
);
|
||||||
webNotifTimeouts = {};
|
webNotifTimeouts = {};
|
||||||
|
|
||||||
notifications.forEach(function (notif) {
|
notifications.forEach(function (notif) {
|
||||||
browser.setTimeout(function () {
|
browser.setTimeout(function () {
|
||||||
|
let buttons = [];
|
||||||
|
|
||||||
|
if (notif.action) {
|
||||||
|
buttons = [
|
||||||
|
{
|
||||||
|
name: env._t("Open"),
|
||||||
|
primary: true,
|
||||||
|
onClick: async () => {
|
||||||
|
await action.doAction(notif.action);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
notification.add(Markup(notif.message), {
|
notification.add(Markup(notif.message), {
|
||||||
title: notif.title,
|
title: notif.title,
|
||||||
type: notif.type,
|
type: notif.type,
|
||||||
sticky: notif.sticky,
|
sticky: notif.sticky,
|
||||||
className: notif.className,
|
className: notif.className,
|
||||||
|
buttons: buttons,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,7 +14,12 @@ class TestResUsers(common.TransactionCase):
|
||||||
bus_bus = self.env["bus.bus"]
|
bus_bus = self.env["bus.bus"]
|
||||||
domain = [("channel", "=", self.env.user.notify_success_channel_name)]
|
domain = [("channel", "=", self.env.user.notify_success_channel_name)]
|
||||||
existing = bus_bus.search(domain)
|
existing = bus_bus.search(domain)
|
||||||
test_msg = {"message": "message", "title": "title", "sticky": True}
|
test_msg = {
|
||||||
|
"message": "message",
|
||||||
|
"title": "title",
|
||||||
|
"sticky": True,
|
||||||
|
"action": None,
|
||||||
|
}
|
||||||
self.env.user.notify_success(**test_msg)
|
self.env.user.notify_success(**test_msg)
|
||||||
news = bus_bus.search(domain) - existing
|
news = bus_bus.search(domain) - existing
|
||||||
self.assertEqual(1, len(news))
|
self.assertEqual(1, len(news))
|
||||||
|
@ -26,7 +31,12 @@ class TestResUsers(common.TransactionCase):
|
||||||
bus_bus = self.env["bus.bus"]
|
bus_bus = self.env["bus.bus"]
|
||||||
domain = [("channel", "=", self.env.user.notify_danger_channel_name)]
|
domain = [("channel", "=", self.env.user.notify_danger_channel_name)]
|
||||||
existing = bus_bus.search(domain)
|
existing = bus_bus.search(domain)
|
||||||
test_msg = {"message": "message", "title": "title", "sticky": True}
|
test_msg = {
|
||||||
|
"message": "message",
|
||||||
|
"title": "title",
|
||||||
|
"sticky": True,
|
||||||
|
"action": None,
|
||||||
|
}
|
||||||
self.env.user.notify_danger(**test_msg)
|
self.env.user.notify_danger(**test_msg)
|
||||||
news = bus_bus.search(domain) - existing
|
news = bus_bus.search(domain) - existing
|
||||||
self.assertEqual(1, len(news))
|
self.assertEqual(1, len(news))
|
||||||
|
@ -38,7 +48,12 @@ class TestResUsers(common.TransactionCase):
|
||||||
bus_bus = self.env["bus.bus"]
|
bus_bus = self.env["bus.bus"]
|
||||||
domain = [("channel", "=", self.env.user.notify_warning_channel_name)]
|
domain = [("channel", "=", self.env.user.notify_warning_channel_name)]
|
||||||
existing = bus_bus.search(domain)
|
existing = bus_bus.search(domain)
|
||||||
test_msg = {"message": "message", "title": "title", "sticky": True}
|
test_msg = {
|
||||||
|
"message": "message",
|
||||||
|
"title": "title",
|
||||||
|
"sticky": True,
|
||||||
|
"action": None,
|
||||||
|
}
|
||||||
self.env.user.notify_warning(**test_msg)
|
self.env.user.notify_warning(**test_msg)
|
||||||
news = bus_bus.search(domain) - existing
|
news = bus_bus.search(domain) - existing
|
||||||
self.assertEqual(1, len(news))
|
self.assertEqual(1, len(news))
|
||||||
|
@ -50,7 +65,12 @@ class TestResUsers(common.TransactionCase):
|
||||||
bus_bus = self.env["bus.bus"]
|
bus_bus = self.env["bus.bus"]
|
||||||
domain = [("channel", "=", self.env.user.notify_info_channel_name)]
|
domain = [("channel", "=", self.env.user.notify_info_channel_name)]
|
||||||
existing = bus_bus.search(domain)
|
existing = bus_bus.search(domain)
|
||||||
test_msg = {"message": "message", "title": "title", "sticky": True}
|
test_msg = {
|
||||||
|
"message": "message",
|
||||||
|
"title": "title",
|
||||||
|
"sticky": True,
|
||||||
|
"action": None,
|
||||||
|
}
|
||||||
self.env.user.notify_info(**test_msg)
|
self.env.user.notify_info(**test_msg)
|
||||||
news = bus_bus.search(domain) - existing
|
news = bus_bus.search(domain) - existing
|
||||||
self.assertEqual(1, len(news))
|
self.assertEqual(1, len(news))
|
||||||
|
@ -62,7 +82,12 @@ class TestResUsers(common.TransactionCase):
|
||||||
bus_bus = self.env["bus.bus"]
|
bus_bus = self.env["bus.bus"]
|
||||||
domain = [("channel", "=", self.env.user.notify_default_channel_name)]
|
domain = [("channel", "=", self.env.user.notify_default_channel_name)]
|
||||||
existing = bus_bus.search(domain)
|
existing = bus_bus.search(domain)
|
||||||
test_msg = {"message": "message", "title": "title", "sticky": True}
|
test_msg = {
|
||||||
|
"message": "message",
|
||||||
|
"title": "title",
|
||||||
|
"sticky": True,
|
||||||
|
"action": None,
|
||||||
|
}
|
||||||
self.env.user.notify_default(**test_msg)
|
self.env.user.notify_default(**test_msg)
|
||||||
news = bus_bus.search(domain) - existing
|
news = bus_bus.search(domain) - existing
|
||||||
self.assertEqual(1, len(news))
|
self.assertEqual(1, len(news))
|
||||||
|
|
Loading…
Reference in New Issue