diff --git a/web_notify/README.rst b/web_notify/README.rst index 2fa24871..ab0517e5 100644 --- a/web_notify/README.rst +++ b/web_notify/README.rst @@ -30,6 +30,34 @@ or :scale: 80 % :alt: Sample notifications +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: + +.. code-block:: python + + self.env.user.notify_info('My information message', show_reload=True) + +The action can be used using the ``action`` keyword: + +.. code-block:: python + + 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, + # optional + action_link_name=_('Open Sale'), + ) + + Installation ============ @@ -64,6 +92,7 @@ Contributors * Laurent Mignon * Serpent Consulting Services Pvt. Ltd. +* Guewen Baconnier Maintainer ---------- diff --git a/web_notify/__manifest__.py b/web_notify/__manifest__.py index 858c3be9..c84ae279 100644 --- a/web_notify/__manifest__.py +++ b/web_notify/__manifest__.py @@ -6,7 +6,7 @@ 'name': 'Web Notify', 'summary': """ Send notification messages to user""", - 'version': '10.0.1.0.0', + 'version': '10.0.1.1.0', 'description': 'Web Notify', 'license': 'AGPL-3', 'author': 'ACSONE SA/NV,Odoo Community Association (OCA)', @@ -18,7 +18,8 @@ 'data': [ 'views/web_notify.xml' ], - 'demo': [ + 'qweb': [ + 'static/src/xml/*.xml', ], 'installable': True, } diff --git a/web_notify/models/res_users.py b/web_notify/models/res_users.py index 29f0eca1..718a996b 100644 --- a/web_notify/models/res_users.py +++ b/web_notify/models/res_users.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- # Copyright 2016 ACSONE SA/NV +# Copyright 2018 Camptocamp # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, fields, models, _ +from odoo.addons.web.controllers.main import clean_action class ResUsers(models.Model): @@ -23,24 +25,36 @@ class ResUsers(models.Model): compute='_compute_channel_names') @api.multi - def notify_info(self, message, title=None, sticky=False): + def notify_info(self, message, title=None, sticky=False, + show_reload=False, action=None, + action_link_name=None, **options): title = title or _('Information') self._notify_channel( - 'notify_info_channel_name', message, title, sticky) + 'notify_info_channel_name', message, title, + sticky=sticky, show_reload=show_reload, action=action, + action_link_name=action_link_name, **options + ) @api.multi - def notify_warning(self, message, title=None, sticky=False): + def notify_warning(self, message, title=None, sticky=False, + show_reload=False, action=None, + action_link_name=None, **options): title = title or _('Warning') self._notify_channel( - 'notify_warning_channel_name', message, title, sticky) + 'notify_warning_channel_name', message, title, + sticky=sticky, show_reload=show_reload, action=action, + action_link_name=action_link_name, **options + ) @api.multi - def _notify_channel(self, channel_name_field, message, title, sticky): + def _notify_channel(self, channel_name_field, message, title, **options): + if options.get('action'): + options['action'] = clean_action(options['action']) bus_message = { 'message': message, 'title': title, - 'sticky': sticky } + bus_message.update(options) notifications = [(getattr(record, channel_name_field), bus_message) for record in self] self.env['bus.bus'].sendmany(notifications) diff --git a/web_notify/static/src/css/notification.less b/web_notify/static/src/css/notification.less new file mode 100644 index 00000000..d5744132 --- /dev/null +++ b/web_notify/static/src/css/notification.less @@ -0,0 +1,5 @@ +.o_notification { + .o_notification_action { + padding: 10px; + } +} diff --git a/web_notify/static/src/js/notification.js b/web_notify/static/src/js/notification.js new file mode 100644 index 00000000..38cb87ae --- /dev/null +++ b/web_notify/static/src/js/notification.js @@ -0,0 +1,57 @@ +/* Copyright 2018 Camptocamp + * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */ +odoo.define('web_notify.notification', function (require) { + "use strict"; + + var base_notification = require('web.notification'), + WebClient = require('web.WebClient'), + Notification = base_notification.Notification; + + var InteractiveNotification = Notification.extend({ + template: 'InteractiveNotification', + events: _.extend( + {}, + Notification.prototype.events, + {'click .o_notification_reload_view': function(e){ + e.preventDefault(); + this.reload_active_view(); + }, + 'click .o_notification_do_action': function(e){ + e.preventDefault(); + this.button_do_action(); + } + } + ), + init: function(parent, title, text, options) { + this.options = options || {}; + var sticky = this.options.sticky; + this._super.apply(this, [parent, title, text, sticky]); + }, + reload_active_view: function() { + this.trigger_up('reload_active_view'); + }, + button_do_action: function() { + this.getParent().do_action(this.options.action); + } + }); + + var InteractiveWarning = InteractiveNotification.extend({ + template: 'InteractiveWarning', + }); + + base_notification.NotificationManager.include({ + interactive_notify(title, text, options) { + return this.display(new InteractiveNotification(this, title, text, options)); + }, + interactive_warn(title, text, options) { + return this.display(new InteractiveWarning(this, title, text, options)); + } + + }); + + return { + InteractiveNotification: InteractiveNotification, + InteractiveWarning: InteractiveWarning + }; + +}); diff --git a/web_notify/static/src/js/web_client.js b/web_notify/static/src/js/web_client.js index 1ee99224..d87b52ff 100644 --- a/web_notify/static/src/js/web_client.js +++ b/web_notify/static/src/js/web_client.js @@ -1,13 +1,60 @@ odoo.define('web_notify.WebClient', function (require) { "use strict"; -var WebClient = require('web.WebClient'); -var base_bus = require('bus.bus'); +var core = require('web.core'), + WebClient = require('web.WebClient'), + base_bus = require('bus.bus'), + Widget = require('web.Widget'); + + +Widget.include({ + do_interactive_notify: function(title, message, options) { + this.trigger_up( + 'interactive_notification', + {title: title, message: message, options: options}); + }, + do_interactive_warn: function(title, message, options) { + this.trigger_up( + 'interactive_warning', + {title: title, message: message, options: options}); + }, +}); + WebClient.include({ + custom_events: _.extend( + {}, + WebClient.prototype.custom_events, + {reload_active_view: 'reload_active_view', + interactive_notification: function (e) { + if(this.notification_manager) { + this.notification_manager.interactive_notify( + e.data.title, e.data.message, e.data.options + ); + } + }, + interactive_warning: function (e) { + if(this.notification_manager) { + this.notification_manager.interactive_warn( + e.data.title, e.data.message, e.data.options + ); + } + } + } + ), init: function(parent, client_options){ this._super(parent, client_options); }, + reload_active_view: function(){ + var action_manager = this.action_manager; + if(!action_manager){ + return; + } + var active_view = action_manager.inner_widget.active_view; + if(active_view) { + active_view.controller.reload(); + } + }, show_application: function() { var res = this._super(); this.start_polling(); @@ -40,12 +87,16 @@ WebClient.include({ }, on_message_warning: function(message){ if(this.notification_manager) { - this.notification_manager.do_warn(message.title, message.message, message.sticky); + this.notification_manager.do_interactive_warn( + message.title, message.message, message + ); } }, on_message_info: function(message){ if(this.notification_manager) { - this.notification_manager.do_notify(message.title, message.message, message.sticky); + this.notification_manager.do_interactive_notify( + message.title, message.message, message + ); } } }); diff --git a/web_notify/static/src/xml/notification.xml b/web_notify/static/src/xml/notification.xml new file mode 100644 index 00000000..3fbec2f1 --- /dev/null +++ b/web_notify/static/src/xml/notification.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web_notify/tests/test_res_users.py b/web_notify/tests/test_res_users.py index 72416d5e..6f4700c9 100644 --- a/web_notify/tests/test_res_users.py +++ b/web_notify/tests/test_res_users.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Copyright 2016 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import json from odoo.tests import common from odoo.addons.bus.models.bus import json_dump @@ -17,12 +18,18 @@ class TestResUsers(common.TransactionCase): ] existing = bus_bus.search(domain) self.env.user.notify_info( - message='message', title='title', sticky=True) + message='message', title='title', sticky=True, + show_reload=True, foo="bar" + ) news = bus_bus.search(domain) - existing self.assertEqual(1, len(news)) - self.assertEqual( - '{"message":"message","sticky":true,"title":"title"}', - news.message) + expected = ('{"message":"message","sticky":true,"title":"title",' + '"show_reload":true,"action":null,' + '"action_link_name":null,"foo":"bar"}') + self.assertDictEqual( + json.loads(expected), + json.loads(news.message) + ) def test_notify_warning(self): bus_bus = self.env['bus.bus'] @@ -32,12 +39,46 @@ class TestResUsers(common.TransactionCase): ] existing = bus_bus.search(domain) self.env.user.notify_warning( - message='message', title='title', sticky=True) + message='message', title='title', sticky=True, + show_reload=True, foo="bar" + ) news = bus_bus.search(domain) - existing self.assertEqual(1, len(news)) - self.assertEqual( - '{"message":"message","sticky":true,"title":"title"}', - news.message) + expected = ('{"message":"message","sticky":true,"title":"title",' + '"show_reload":true,"action":null,' + '"action_link_name":null,"foo":"bar"}') + self.assertDictEqual( + json.loads(expected), + json.loads(news.message) + ) + + def test_notify_with_action(self): + bus_bus = self.env['bus.bus'] + domain = [ + ('channel', '=', + json_dump(self.env.user.notify_info_channel_name)) + ] + existing = bus_bus.search(domain) + self.env.user.notify_info( + message='message', title='title', sticky=True, + action={ + "type": "ir.actions.act_window", + "view_mode": "form", + }, + action_link_name="Open" + ) + news = bus_bus.search(domain) - existing + self.assertEqual(1, len(news)) + # the action should be transformed by Odoo (clean_action) + expected = ('{"message":"message","sticky":true,"title":"title",' + '"show_reload":false,"action":' + '{"type": "ir.actions.act_window", "view_mode":"form",' + '"flags":{},"views":[[false, "form"]]},' + '"action_link_name":"Open"}') + self.assertDictEqual( + json.loads(expected), + json.loads(news.message) + ) def test_notify_many(self): # check that the notification of a list of users is done with diff --git a/web_notify/views/web_notify.xml b/web_notify/views/web_notify.xml index b85d2e6f..4d009595 100644 --- a/web_notify/views/web_notify.xml +++ b/web_notify/views/web_notify.xml @@ -3,7 +3,9 @@