diff --git a/addons/web/static/src/js/core/misc.js b/addons/web/static/src/js/core/misc.js index 6260a4ab583..31f625ff0c5 100644 --- a/addons/web/static/src/js/core/misc.js +++ b/addons/web/static/src/js/core/misc.js @@ -176,6 +176,17 @@ function logout() { } core.action_registry.add("logout", logout); +/** + * @param {ActionManager} parent + * @param {Object} action + * @param {Object} action.params notification params + * @see ServiceMixin.displayNotification + */ +function displayNotification(parent, action) { + parent.displayNotification(action.params); +} +core.action_registry.add("display_notification", displayNotification); + /** * Client action to refresh the session context (making sure * HTTP requests will have the right one) then reload the diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index e4e8458a9e7..af214a26203 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -2,6 +2,7 @@ odoo.define('web.action_manager_tests', function (require) { "use strict"; var ReportClientAction = require('report.client_action'); +var Notification = require('web.Notification'); var NotificationService = require('web.NotificationService'); var AbstractAction = require('web.AbstractAction'); var AbstractStorageService = require('web.AbstractStorageService'); @@ -1898,6 +1899,64 @@ QUnit.module('ActionManager', { delete core.action_registry.map.HelloWorldTest; }); + QUnit.test('test display_notification client action', async function (assert) { + assert.expect(6); + + testUtils.mock.patch(Notification, { + _animation: false, + }); + + const actionManager = await createActionManager({ + actions: this.actions, + archs: this.archs, + data: this.data, + services: { + notification: NotificationService, + }, + }); + + await actionManager.doAction(1); + assert.containsOnce(actionManager, '.o_kanban_view'); + + await actionManager.doAction({ + type: 'ir.actions.client', + tag: 'display_notification', + params: { + title: 'title', + message: 'message', + sticky: true, + } + }); + const notificationSelector = '.o_notification_manager .o_notification'; + + assert.containsOnce(document.body, notificationSelector, + 'a notification should be present'); + + const notificationElement = document.body.querySelector(notificationSelector); + assert.strictEqual( + notificationElement.querySelector('.o_notification_title').textContent, + 'title', + "the notification should have the correct title" + ); + assert.strictEqual( + notificationElement.querySelector('.o_notification_content').textContent, + 'message', + "the notification should have the correct message" + ); + + assert.containsOnce(actionManager, '.o_kanban_view'); + + await testUtils.dom.click( + notificationElement.querySelector('.o_notification_close') + ); + + assert.containsNone(document.body, notificationSelector, + "the notification should be destroy "); + + actionManager.destroy(); + testUtils.mock.unpatch(Notification); + }); + QUnit.module('Server actions'); QUnit.test('can execute server actions from db ID', async function (assert) { diff --git a/doc/reference/javascript_reference.rst b/doc/reference/javascript_reference.rst index f724485f86a..6a1dbdd7599 100644 --- a/doc/reference/javascript_reference.rst +++ b/doc/reference/javascript_reference.rst @@ -1213,6 +1213,10 @@ The notification system in Odoo is designed with the following components: destroy notifications whenever a request is done (with a custom_event). Note that the web client is a service provider. +- a client action *display_notification*: this allows to trigger the display + of a notification from python (e.g. in the method called when the user + clicked on a button of type object). + - two helper functions in *ServiceMixin*: *do_notify* and *do_warn* @@ -1260,6 +1264,21 @@ Here are two examples on how to use these methods: this.do_warn(_t("Error"), _t("Filter name is required.")); +Here an example in python: + +.. code-block:: python + + # note that we call _(string) on the text to make sure it is properly translated. + def show_notification(self): + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': _('Success'), + 'message': _('Your signature request has been sent.'), + 'sticky': False, + } + } Systray =======