mirror of https://github.com/OCA/web.git
[12.0] web_notify: improve popup UI (#1231)
* [ADD]: all available bootstrap notifications (success/danger/warning/info/default) * [IMP] use black color for text for default notification. * [FIX] reverted require string for `bus.Longpolling` and rename `on_message_received` to `on_message` to prevent collisions.pull/2381/head
parent
af2656ba00
commit
3db7072296
|
@ -30,8 +30,11 @@ Send instant notification messages to the user in live.
|
||||||
This technical module allows you to send instant notification messages from the server to the user in live.
|
This technical module allows you to send instant notification messages from the server to the user in live.
|
||||||
Two kinds of notification are supported.
|
Two kinds of notification are supported.
|
||||||
|
|
||||||
* Warning: Displayed in a red flying popup div
|
* Success: Displayed in a `success` theme color flying popup div
|
||||||
* Information: Displayed in a light yellow flying popup div
|
* Danger: Displayed in a `danger` theme color flying popup div
|
||||||
|
* Warning: Displayed in a `warning` theme color flying popup div
|
||||||
|
* Information: Displayed in a `info` theme color flying popup div
|
||||||
|
* Default: Displayed in a `default` theme color flying popup div
|
||||||
|
|
||||||
**Table of contents**
|
**Table of contents**
|
||||||
|
|
||||||
|
@ -49,6 +52,24 @@ Usage
|
||||||
|
|
||||||
To send a notification to the user you just need to call one of the new methods defined on res.users:
|
To send a notification to the user you just need to call one of the new methods defined on res.users:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
self.env.user.notify_success(message='My success message')
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
self.env.user.notify_danger(message='My danger message')
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
self.env.user.notify_warning(message='My warning message')
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
self.env.user.notify_info(message='My information message')
|
self.env.user.notify_info(message='My information message')
|
||||||
|
@ -57,7 +78,7 @@ or
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
self.env.user.notify_warning(message='My marning message')
|
self.env.user.notify_default(message='My default message')
|
||||||
|
|
||||||
.. figure:: https://raw.githubusercontent.com/OCA/web/12.0/web_notify/static/description/notifications_screenshot.png
|
.. figure:: https://raw.githubusercontent.com/OCA/web/12.0/web_notify/static/description/notifications_screenshot.png
|
||||||
:scale: 80 %
|
:scale: 80 %
|
||||||
|
@ -95,6 +116,7 @@ Contributors
|
||||||
* Laurent Mignon <laurent.mignon@acsone.eu>
|
* Laurent Mignon <laurent.mignon@acsone.eu>
|
||||||
* Serpent Consulting Services Pvt. Ltd.<jay.vora@serpentcs.com>
|
* Serpent Consulting Services Pvt. Ltd.<jay.vora@serpentcs.com>
|
||||||
* Aitor Bouzas <aitor.bouzas@adaptivecity.com>
|
* Aitor Bouzas <aitor.bouzas@adaptivecity.com>
|
||||||
|
* Shepilov Vladislav <shepilov.v@protonmail.com>
|
||||||
|
|
||||||
Maintainers
|
Maintainers
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# pylint: disable=missing-docstring
|
||||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# pylint: disable=missing-docstring
|
||||||
# Copyright 2016 ACSONE SA/NV
|
# Copyright 2016 ACSONE SA/NV
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
@ -6,7 +7,6 @@
|
||||||
'summary': """
|
'summary': """
|
||||||
Send notification messages to user""",
|
Send notification messages to user""",
|
||||||
'version': '12.0.1.0.0',
|
'version': '12.0.1.0.0',
|
||||||
'description': 'Web Notify',
|
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'author': 'ACSONE SA/NV,'
|
'author': 'ACSONE SA/NV,'
|
||||||
'AdaptiveCity,'
|
'AdaptiveCity,'
|
||||||
|
|
|
@ -14,32 +14,80 @@ msgstr ""
|
||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
#. module: web_notify
|
#. module: web_notify
|
||||||
#: code:addons/web_notify/models/res_users.py:23
|
#: code:addons/web_notify/models/res_users.py:44
|
||||||
|
#, python-format
|
||||||
|
msgid "Danger"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_notify
|
||||||
|
#: code:addons/web_notify/models/res_users.py:60
|
||||||
|
#, python-format
|
||||||
|
msgid "Default"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_notify
|
||||||
|
#: code:addons/web_notify/models/res_users.py:54
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Information"
|
msgid "Information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_notify
|
||||||
|
#: model:ir.model.fields,field_description:web_notify.field_res_users__notify_danger_channel_name
|
||||||
|
msgid "Notify Danger Channel Name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_notify
|
||||||
|
#: model:ir.model.fields,field_description:web_notify.field_res_users__notify_default_channel_name
|
||||||
|
msgid "Notify Default Channel Name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_notify
|
#. module: web_notify
|
||||||
#: model:ir.model.fields,field_description:web_notify.field_res_users__notify_info_channel_name
|
#: model:ir.model.fields,field_description:web_notify.field_res_users__notify_info_channel_name
|
||||||
msgid "Notify Info Channel Name"
|
msgid "Notify Info Channel Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_notify
|
||||||
|
#: model:ir.model.fields,field_description:web_notify.field_res_users__notify_success_channel_name
|
||||||
|
msgid "Notify Success Channel Name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_notify
|
#. module: web_notify
|
||||||
#: model:ir.model.fields,field_description:web_notify.field_res_users__notify_warning_channel_name
|
#: model:ir.model.fields,field_description:web_notify.field_res_users__notify_warning_channel_name
|
||||||
msgid "Notify Warning Channel Name"
|
msgid "Notify Warning Channel Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_notify
|
#. module: web_notify
|
||||||
#: code:addons/web_notify/models/res_users.py:37
|
#: code:addons/web_notify/models/res_users.py:75
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Sending a notification to another user is forbidden."
|
msgid "Sending a notification to another user is forbidden."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_notify
|
||||||
|
#: code:addons/web_notify/models/res_users.py:38
|
||||||
|
#, python-format
|
||||||
|
msgid "Success"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_notify
|
||||||
|
#: model_terms:ir.ui.view,arch_db:web_notify.view_users_form_simple_modif_inherit
|
||||||
|
msgid "Test danger notification"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_notify
|
||||||
|
#: model_terms:ir.ui.view,arch_db:web_notify.view_users_form_simple_modif_inherit
|
||||||
|
msgid "Test default notification"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_notify
|
#. module: web_notify
|
||||||
#: model_terms:ir.ui.view,arch_db:web_notify.view_users_form_simple_modif_inherit
|
#: model_terms:ir.ui.view,arch_db:web_notify.view_users_form_simple_modif_inherit
|
||||||
msgid "Test info notification"
|
msgid "Test info notification"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_notify
|
||||||
|
#: model_terms:ir.ui.view,arch_db:web_notify.view_users_form_simple_modif_inherit
|
||||||
|
msgid "Test success notification"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_notify
|
#. module: web_notify
|
||||||
#: model_terms:ir.ui.view,arch_db:web_notify.view_users_form_simple_modif_inherit
|
#: model_terms:ir.ui.view,arch_db:web_notify.view_users_form_simple_modif_inherit
|
||||||
msgid "Test warning notification"
|
msgid "Test warning notification"
|
||||||
|
@ -56,7 +104,7 @@ msgid "Users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_notify
|
#. module: web_notify
|
||||||
#: code:addons/web_notify/models/res_users.py:29
|
#: code:addons/web_notify/models/res_users.py:50
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Warning"
|
msgid "Warning"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# pylint: disable=missing-docstring
|
||||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from . import res_users
|
from . import res_users
|
||||||
|
|
|
@ -1,46 +1,87 @@
|
||||||
|
# pylint: disable=missing-docstring
|
||||||
# Copyright 2016 ACSONE SA/NV
|
# Copyright 2016 ACSONE SA/NV
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from odoo import api, exceptions, fields, models, _
|
from odoo import _, api, exceptions, fields, models
|
||||||
|
|
||||||
|
DEFAULT_MESSAGE = "Default message"
|
||||||
|
|
||||||
|
SUCCESS = "success"
|
||||||
|
DANGER = "danger"
|
||||||
|
WARNING = "warning"
|
||||||
|
INFO = "info"
|
||||||
|
DEFAULT = "default"
|
||||||
|
|
||||||
|
|
||||||
class ResUsers(models.Model):
|
class ResUsers(models.Model):
|
||||||
_inherit = 'res.users'
|
_inherit = "res.users"
|
||||||
|
|
||||||
@api.depends('create_date')
|
@api.depends("create_date")
|
||||||
def _compute_channel_names(self):
|
def _compute_channel_names(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
res_id = record.id
|
res_id = record.id
|
||||||
record.notify_info_channel_name = 'notify_info_%s' % res_id
|
record.notify_success_channel_name = "notify_success_%s" % res_id
|
||||||
record.notify_warning_channel_name = 'notify_warning_%s' % res_id
|
record.notify_danger_channel_name = "notify_danger_%s" % res_id
|
||||||
|
record.notify_warning_channel_name = "notify_warning_%s" % res_id
|
||||||
|
record.notify_info_channel_name = "notify_info_%s" % res_id
|
||||||
|
record.notify_default_channel_name = "notify_default_%s" % res_id
|
||||||
|
|
||||||
notify_info_channel_name = fields.Char(
|
notify_success_channel_name = fields.Char(compute="_compute_channel_names")
|
||||||
compute='_compute_channel_names')
|
notify_danger_channel_name = fields.Char(compute="_compute_channel_names")
|
||||||
notify_warning_channel_name = fields.Char(
|
notify_warning_channel_name = fields.Char(compute="_compute_channel_names")
|
||||||
compute='_compute_channel_names')
|
notify_info_channel_name = fields.Char(compute="_compute_channel_names")
|
||||||
|
notify_default_channel_name = fields.Char(compute="_compute_channel_names")
|
||||||
|
|
||||||
|
def notify_success(
|
||||||
|
self, message="Default message", title=None, sticky=False
|
||||||
|
):
|
||||||
|
title = title or _("Success")
|
||||||
|
self._notify_channel(SUCCESS, message, title, sticky)
|
||||||
|
|
||||||
|
def notify_danger(
|
||||||
|
self, message="Default message", title=None, sticky=False
|
||||||
|
):
|
||||||
|
title = title or _("Danger")
|
||||||
|
self._notify_channel(DANGER, message, title, sticky)
|
||||||
|
|
||||||
|
def notify_warning(
|
||||||
|
self, message="Default message", title=None, sticky=False
|
||||||
|
):
|
||||||
|
title = title or _("Warning")
|
||||||
|
self._notify_channel(WARNING, message, title, sticky)
|
||||||
|
|
||||||
def notify_info(self, message="Default message", title=None, sticky=False):
|
def notify_info(self, message="Default message", title=None, sticky=False):
|
||||||
title = title or _('Information')
|
title = title or _("Information")
|
||||||
self._notify_channel(
|
self._notify_channel(INFO, message, title, sticky)
|
||||||
'notify_info_channel_name', message, title, sticky)
|
|
||||||
|
|
||||||
def notify_warning(self, message="Default message",
|
def notify_default(
|
||||||
title=None, sticky=False):
|
self, message="Default message", title=None, sticky=False
|
||||||
title = title or _('Warning')
|
):
|
||||||
self._notify_channel(
|
title = title or _("Default")
|
||||||
'notify_warning_channel_name', message, title, sticky)
|
self._notify_channel(DEFAULT, message, title, sticky)
|
||||||
|
|
||||||
def _notify_channel(self, channel_name_field, message, title, sticky):
|
def _notify_channel(
|
||||||
if (not self.env.user._is_admin()
|
self,
|
||||||
and any(user.id != self.env.uid for user in self)):
|
type_message=DEFAULT,
|
||||||
|
message=DEFAULT_MESSAGE,
|
||||||
|
title=None,
|
||||||
|
sticky=False,
|
||||||
|
):
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
if not self.env.user._is_admin() and any(
|
||||||
|
user.id != self.env.uid for user in self
|
||||||
|
):
|
||||||
raise exceptions.UserError(
|
raise exceptions.UserError(
|
||||||
_('Sending a notification to another user is forbidden.')
|
_("Sending a notification to another user is forbidden.")
|
||||||
)
|
)
|
||||||
|
channel_name_field = "notify_{}_channel_name".format(type_message)
|
||||||
bus_message = {
|
bus_message = {
|
||||||
'message': message,
|
"type": type_message,
|
||||||
'title': title,
|
"message": message,
|
||||||
'sticky': sticky
|
"title": title,
|
||||||
|
"sticky": sticky,
|
||||||
}
|
}
|
||||||
notifications = [(record[channel_name_field], bus_message)
|
notifications = [
|
||||||
for record in self]
|
(record[channel_name_field], bus_message) for record in self
|
||||||
self.env['bus.bus'].sendmany(notifications)
|
]
|
||||||
|
self.env["bus.bus"].sendmany(notifications)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
* Laurent Mignon <laurent.mignon@acsone.eu>
|
* Laurent Mignon <laurent.mignon@acsone.eu>
|
||||||
* Serpent Consulting Services Pvt. Ltd.<jay.vora@serpentcs.com>
|
* Serpent Consulting Services Pvt. Ltd.<jay.vora@serpentcs.com>
|
||||||
* Aitor Bouzas <aitor.bouzas@adaptivecity.com>
|
* Aitor Bouzas <aitor.bouzas@adaptivecity.com>
|
||||||
|
* Shepilov Vladislav <shepilov.v@protonmail.com>
|
||||||
|
|
|
@ -3,5 +3,8 @@ Send instant notification messages to the user in live.
|
||||||
This technical module allows you to send instant notification messages from the server to the user in live.
|
This technical module allows you to send instant notification messages from the server to the user in live.
|
||||||
Two kinds of notification are supported.
|
Two kinds of notification are supported.
|
||||||
|
|
||||||
* Warning: Displayed in a red flying popup div
|
* Success: Displayed in a `success` theme color flying popup div
|
||||||
* Information: Displayed in a light yellow flying popup div
|
* Danger: Displayed in a `danger` theme color flying popup div
|
||||||
|
* Warning: Displayed in a `warning` theme color flying popup div
|
||||||
|
* Information: Displayed in a `info` theme color flying popup div
|
||||||
|
* Default: Displayed in a `default` theme color flying popup div
|
||||||
|
|
|
@ -1,6 +1,24 @@
|
||||||
|
|
||||||
To send a notification to the user you just need to call one of the new methods defined on res.users:
|
To send a notification to the user you just need to call one of the new methods defined on res.users:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
self.env.user.notify_success(message='My success message')
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
self.env.user.notify_danger(message='My danger message')
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
self.env.user.notify_warning(message='My warning message')
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
self.env.user.notify_info(message='My information message')
|
self.env.user.notify_info(message='My information message')
|
||||||
|
@ -9,7 +27,7 @@ or
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
self.env.user.notify_warning(message='My marning message')
|
self.env.user.notify_default(message='My default message')
|
||||||
|
|
||||||
.. figure:: static/description/notifications_screenshot.png
|
.. figure:: static/description/notifications_screenshot.png
|
||||||
:scale: 80 %
|
:scale: 80 %
|
||||||
|
|
|
@ -372,8 +372,11 @@ ul.auto-toc {
|
||||||
<p>This technical module allows you to send instant notification messages from the server to the user in live.
|
<p>This technical module allows you to send instant notification messages from the server to the user in live.
|
||||||
Two kinds of notification are supported.</p>
|
Two kinds of notification are supported.</p>
|
||||||
<ul class="simple">
|
<ul class="simple">
|
||||||
<li>Warning: Displayed in a red flying popup div</li>
|
<li>Success: Displayed in a <cite>success</cite> theme color flying popup div</li>
|
||||||
<li>Information: Displayed in a light yellow flying popup div</li>
|
<li>Danger: Displayed in a <cite>danger</cite> theme color flying popup div</li>
|
||||||
|
<li>Warning: Displayed in a <cite>warning</cite> theme color flying popup div</li>
|
||||||
|
<li>Information: Displayed in a <cite>info</cite> theme color flying popup div</li>
|
||||||
|
<li>Default: Displayed in a <cite>default</cite> theme color flying popup div</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p><strong>Table of contents</strong></p>
|
<p><strong>Table of contents</strong></p>
|
||||||
<div class="contents local topic" id="contents">
|
<div class="contents local topic" id="contents">
|
||||||
|
@ -397,11 +400,23 @@ Two kinds of notification are supported.</p>
|
||||||
<h1><a class="toc-backref" href="#id2">Usage</a></h1>
|
<h1><a class="toc-backref" href="#id2">Usage</a></h1>
|
||||||
<p>To send a notification to the user you just need to call one of the new methods defined on res.users:</p>
|
<p>To send a notification to the user you just need to call one of the new methods defined on res.users:</p>
|
||||||
<pre class="code python literal-block">
|
<pre class="code python literal-block">
|
||||||
|
<span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">notify_success</span><span class="p">(</span><span class="n">message</span><span class="o">=</span><span class="s1">'My success message'</span><span class="p">)</span>
|
||||||
|
</pre>
|
||||||
|
<p>or</p>
|
||||||
|
<pre class="code python literal-block">
|
||||||
|
<span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">notify_danger</span><span class="p">(</span><span class="n">message</span><span class="o">=</span><span class="s1">'My danger message'</span><span class="p">)</span>
|
||||||
|
</pre>
|
||||||
|
<p>or</p>
|
||||||
|
<pre class="code python literal-block">
|
||||||
|
<span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">notify_warning</span><span class="p">(</span><span class="n">message</span><span class="o">=</span><span class="s1">'My warning message'</span><span class="p">)</span>
|
||||||
|
</pre>
|
||||||
|
<p>or</p>
|
||||||
|
<pre class="code python literal-block">
|
||||||
<span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">notify_info</span><span class="p">(</span><span class="n">message</span><span class="o">=</span><span class="s1">'My information message'</span><span class="p">)</span>
|
<span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">notify_info</span><span class="p">(</span><span class="n">message</span><span class="o">=</span><span class="s1">'My information message'</span><span class="p">)</span>
|
||||||
</pre>
|
</pre>
|
||||||
<p>or</p>
|
<p>or</p>
|
||||||
<pre class="code python literal-block">
|
<pre class="code python literal-block">
|
||||||
<span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">notify_warning</span><span class="p">(</span><span class="n">message</span><span class="o">=</span><span class="s1">'My marning message'</span><span class="p">)</span>
|
<span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">notify_default</span><span class="p">(</span><span class="n">message</span><span class="o">=</span><span class="s1">'My default message'</span><span class="p">)</span>
|
||||||
</pre>
|
</pre>
|
||||||
<div class="figure">
|
<div class="figure">
|
||||||
<img alt="Sample notifications" src="https://raw.githubusercontent.com/OCA/web/12.0/web_notify/static/description/notifications_screenshot.png" />
|
<img alt="Sample notifications" src="https://raw.githubusercontent.com/OCA/web/12.0/web_notify/static/description/notifications_screenshot.png" />
|
||||||
|
@ -435,6 +450,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
|
||||||
<li>Laurent Mignon <<a class="reference external" href="mailto:laurent.mignon@acsone.eu">laurent.mignon@acsone.eu</a>></li>
|
<li>Laurent Mignon <<a class="reference external" href="mailto:laurent.mignon@acsone.eu">laurent.mignon@acsone.eu</a>></li>
|
||||||
<li>Serpent Consulting Services Pvt. Ltd.<<a class="reference external" href="mailto:jay.vora@serpentcs.com">jay.vora@serpentcs.com</a>></li>
|
<li>Serpent Consulting Services Pvt. Ltd.<<a class="reference external" href="mailto:jay.vora@serpentcs.com">jay.vora@serpentcs.com</a>></li>
|
||||||
<li>Aitor Bouzas <<a class="reference external" href="mailto:aitor.bouzas@adaptivecity.com">aitor.bouzas@adaptivecity.com</a>></li>
|
<li>Aitor Bouzas <<a class="reference external" href="mailto:aitor.bouzas@adaptivecity.com">aitor.bouzas@adaptivecity.com</a>></li>
|
||||||
|
<li>Shepilov Vladislav <<a class="reference external" href="mailto:shepilov.v@protonmail.com">shepilov.v@protonmail.com</a>></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="maintainers">
|
<div class="section" id="maintainers">
|
||||||
|
|
|
@ -1,44 +1,53 @@
|
||||||
odoo.define('web_notify.WebClient', function (require) {
|
odoo.define('web_notify.WebClient', function (require) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var WebClient = require('web.WebClient');
|
var WebClient = require('web.WebClient');
|
||||||
var base_bus = require('bus.Longpolling');
|
var base_bus = require('bus.Longpolling');
|
||||||
var session = require('web.session');
|
var session = require('web.session');
|
||||||
require('bus.BusService');
|
require('bus.BusService');
|
||||||
|
|
||||||
|
|
||||||
WebClient.include({
|
WebClient.include({
|
||||||
show_application: function() {
|
show_application: function () {
|
||||||
var res = this._super();
|
var res = this._super();
|
||||||
this.start_polling();
|
this.start_polling();
|
||||||
return res
|
return res;
|
||||||
},
|
},
|
||||||
start_polling: function() {
|
start_polling: function () {
|
||||||
|
this.channel_success = 'notify_success_' + session.uid;
|
||||||
|
this.channel_danger = 'notify_danger_' + session.uid;
|
||||||
this.channel_warning = 'notify_warning_' + session.uid;
|
this.channel_warning = 'notify_warning_' + session.uid;
|
||||||
this.channel_info = 'notify_info_' + session.uid;
|
this.channel_info = 'notify_info_' + session.uid;
|
||||||
|
this.channel_default = 'notify_default_' + session.uid;
|
||||||
|
this.call('bus_service', 'addChannel', this.channel_success);
|
||||||
|
this.call('bus_service', 'addChannel', this.channel_danger);
|
||||||
this.call('bus_service', 'addChannel', this.channel_warning);
|
this.call('bus_service', 'addChannel', this.channel_warning);
|
||||||
this.call('bus_service', 'addChannel', this.channel_info);
|
this.call('bus_service', 'addChannel', this.channel_info);
|
||||||
this.call('bus_service', 'on', 'notification', this, this.bus_notification);
|
this.call('bus_service', 'addChannel', this.channel_default);
|
||||||
|
this.call(
|
||||||
|
'bus_service', 'on', 'notification',
|
||||||
|
this, this.bus_notification);
|
||||||
this.call('bus_service', 'startPolling');
|
this.call('bus_service', 'startPolling');
|
||||||
},
|
},
|
||||||
bus_notification: function(notifications) {
|
bus_notification: function (notifications) {
|
||||||
var self = this;
|
var self = this;
|
||||||
_.each(notifications, function (notification) {
|
_.each(notifications, function (notification) {
|
||||||
var channel = notification[0];
|
// Not used: var channel = notification[0];
|
||||||
var message = notification[1];
|
var message = notification[1];
|
||||||
if (channel === self.channel_warning) {
|
self.on_message(message);
|
||||||
self.on_message_warning(message);
|
|
||||||
} else if (channel === self.channel_info) {
|
|
||||||
self.on_message_info(message);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
on_message_warning: function(message){
|
on_message: function (message) {
|
||||||
this.do_warn(message.title, message.message, message.sticky);
|
return this.call(
|
||||||
},
|
'notification', 'notify', {
|
||||||
on_message_info: function(message){
|
type: message.type,
|
||||||
this.do_notify(message.title, message.message, message.sticky);
|
title: message.title,
|
||||||
|
message: message.message,
|
||||||
|
sticky: message.sticky,
|
||||||
|
className: message.className,
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
odoo.define('web_notify.Notification', function (require) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Notification = require('web.Notification');
|
||||||
|
|
||||||
|
Notification.include({
|
||||||
|
icon_mapping: {
|
||||||
|
'success': 'fa-thumbs-up',
|
||||||
|
'danger': 'fa-exclamation-triangle',
|
||||||
|
'warning': 'fa-exclamation',
|
||||||
|
'info': 'fa-info',
|
||||||
|
'default': 'fa-lightbulb-o',
|
||||||
|
},
|
||||||
|
init: function () {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
// Delete default classes
|
||||||
|
this.className = this.className.replace(' o_error', '');
|
||||||
|
// Add custom icon and custom class
|
||||||
|
this.icon = (this.type in this.icon_mapping) ?
|
||||||
|
this.icon_mapping[this.type] :
|
||||||
|
this.icon_mapping['default'];
|
||||||
|
this.className += ' o_' + this.type;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,24 @@
|
||||||
|
.o_notification_manager {
|
||||||
|
.o_notification {
|
||||||
|
&.o_success {
|
||||||
|
color: white;
|
||||||
|
background-color: theme-color('success');
|
||||||
|
}
|
||||||
|
&.o_danger {
|
||||||
|
color: white;
|
||||||
|
background-color: theme-color('danger');
|
||||||
|
}
|
||||||
|
&.o_warning {
|
||||||
|
color: white;
|
||||||
|
background-color: theme-color('warning');
|
||||||
|
}
|
||||||
|
&.o_info {
|
||||||
|
color: white;
|
||||||
|
background-color: theme-color('info');
|
||||||
|
}
|
||||||
|
&.o_default {
|
||||||
|
color: black;
|
||||||
|
background-color: theme-color('default');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,49 +1,106 @@
|
||||||
# Copyright 2016 ACSONE SA/NV
|
# Copyright 2016 ACSONE SA/NV
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from odoo import exceptions
|
|
||||||
from odoo.tests import common
|
|
||||||
from odoo.addons.bus.models.bus import json_dump
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
from odoo import exceptions
|
||||||
|
from odoo.addons.bus.models.bus import json_dump
|
||||||
|
from ..models.res_users import SUCCESS, DANGER, WARNING, INFO, DEFAULT
|
||||||
|
from odoo.tests import common
|
||||||
|
|
||||||
|
|
||||||
class TestResUsers(common.TransactionCase):
|
class TestResUsers(common.TransactionCase):
|
||||||
|
def test_notify_success(self):
|
||||||
def test_notify_info(self):
|
bus_bus = self.env["bus.bus"]
|
||||||
bus_bus = self.env['bus.bus']
|
|
||||||
domain = [
|
domain = [
|
||||||
('channel', '=',
|
(
|
||||||
json_dump(self.env.user.notify_info_channel_name))
|
"channel",
|
||||||
|
"=",
|
||||||
|
json_dump(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}
|
||||||
self.env.user.notify_info(**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))
|
||||||
self.assertEqual(test_msg, json.loads(news.message))
|
test_msg.update({"type": SUCCESS})
|
||||||
|
self.assertDictEqual(test_msg, json.loads(news.message))
|
||||||
|
|
||||||
def test_notify_warning(self):
|
def test_notify_danger(self):
|
||||||
bus_bus = self.env['bus.bus']
|
bus_bus = self.env["bus.bus"]
|
||||||
domain = [
|
domain = [
|
||||||
('channel', '=',
|
(
|
||||||
json_dump(self.env.user.notify_warning_channel_name))
|
"channel",
|
||||||
|
"=",
|
||||||
|
json_dump(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}
|
||||||
|
self.env.user.notify_danger(**test_msg)
|
||||||
|
news = bus_bus.search(domain) - existing
|
||||||
|
self.assertEqual(1, len(news))
|
||||||
|
test_msg.update({"type": DANGER})
|
||||||
|
self.assertDictEqual(test_msg, json.loads(news.message))
|
||||||
|
|
||||||
|
def test_notify_warning(self):
|
||||||
|
bus_bus = self.env["bus.bus"]
|
||||||
|
domain = [
|
||||||
|
(
|
||||||
|
"channel",
|
||||||
|
"=",
|
||||||
|
json_dump(self.env.user.notify_warning_channel_name),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
existing = bus_bus.search(domain)
|
||||||
|
test_msg = {"message": "message", "title": "title", "sticky": True}
|
||||||
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))
|
||||||
self.assertEqual(test_msg, json.loads(news.message))
|
test_msg.update({"type": WARNING})
|
||||||
|
self.assertDictEqual(test_msg, json.loads(news.message))
|
||||||
|
|
||||||
|
def test_notify_info(self):
|
||||||
|
bus_bus = self.env["bus.bus"]
|
||||||
|
domain = [
|
||||||
|
("channel", "=", json_dump(self.env.user.notify_info_channel_name))
|
||||||
|
]
|
||||||
|
existing = bus_bus.search(domain)
|
||||||
|
test_msg = {"message": "message", "title": "title", "sticky": True}
|
||||||
|
self.env.user.notify_info(**test_msg)
|
||||||
|
news = bus_bus.search(domain) - existing
|
||||||
|
self.assertEqual(1, len(news))
|
||||||
|
test_msg.update({"type": INFO})
|
||||||
|
self.assertDictEqual(test_msg, json.loads(news.message))
|
||||||
|
|
||||||
|
def test_notify_default(self):
|
||||||
|
bus_bus = self.env["bus.bus"]
|
||||||
|
domain = [
|
||||||
|
(
|
||||||
|
"channel",
|
||||||
|
"=",
|
||||||
|
json_dump(self.env.user.notify_default_channel_name),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
existing = bus_bus.search(domain)
|
||||||
|
test_msg = {"message": "message", "title": "title", "sticky": True}
|
||||||
|
self.env.user.notify_default(**test_msg)
|
||||||
|
news = bus_bus.search(domain) - existing
|
||||||
|
self.assertEqual(1, len(news))
|
||||||
|
test_msg.update({"type": DEFAULT})
|
||||||
|
self.assertDictEqual(test_msg, json.loads(news.message))
|
||||||
|
|
||||||
def test_notify_many(self):
|
def test_notify_many(self):
|
||||||
# check that the notification of a list of users is done with
|
# check that the notification of a list of users is done with
|
||||||
# a single call to the bus
|
# a single call to the bus
|
||||||
with mock.patch('odoo.addons.bus.models.bus.ImBus.sendmany'
|
with mock.patch(
|
||||||
|
"odoo.addons.bus.models.bus.ImBus.sendmany"
|
||||||
) as mockedSendMany:
|
) as mockedSendMany:
|
||||||
users = self.env.user.search([(1, "=", 1)])
|
users = self.env.user.search([(1, "=", 1)])
|
||||||
self.assertTrue(len(users) > 1)
|
self.assertTrue(len(users) > 1)
|
||||||
users.notify_warning(message='message')
|
users.notify_warning(message="message")
|
||||||
|
|
||||||
self.assertEqual(1, mockedSendMany.call_count)
|
self.assertEqual(1, mockedSendMany.call_count)
|
||||||
|
|
||||||
|
@ -58,11 +115,11 @@ class TestResUsers(common.TransactionCase):
|
||||||
self.assertEqual(len(users), len(first_pos_call_args))
|
self.assertEqual(len(users), len(first_pos_call_args))
|
||||||
|
|
||||||
def test_notify_other_user(self):
|
def test_notify_other_user(self):
|
||||||
other_user = self.env.ref('base.user_demo')
|
other_user = self.env.ref("base.user_demo")
|
||||||
other_user_model = self.env['res.users'].sudo(other_user)
|
other_user_model = self.env["res.users"].sudo(other_user)
|
||||||
with self.assertRaises(exceptions.UserError):
|
with self.assertRaises(exceptions.UserError):
|
||||||
other_user_model.browse(self.env.uid).notify_info(message='hello')
|
other_user_model.browse(self.env.uid).notify_info(message="hello")
|
||||||
|
|
||||||
def test_notify_admin_allowed_other_user(self):
|
def test_notify_admin_allowed_other_user(self):
|
||||||
other_user = self.env.ref('base.user_demo')
|
other_user = self.env.ref("base.user_demo")
|
||||||
other_user.notify_info(message='hello')
|
other_user.notify_info(message="hello")
|
||||||
|
|
|
@ -11,9 +11,15 @@
|
||||||
<page string="Test web notify" name="test_web_notify">
|
<page string="Test web notify" name="test_web_notify">
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<button name="notify_info"
|
<button name="notify_success"
|
||||||
type="object"
|
type="object"
|
||||||
string="Test info notification"
|
string="Test success notification"
|
||||||
|
class="oe_highlight"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<button name="notify_danger"
|
||||||
|
type="object"
|
||||||
|
string="Test danger notification"
|
||||||
class="oe_highlight"/>
|
class="oe_highlight"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
|
@ -22,6 +28,18 @@
|
||||||
string="Test warning notification"
|
string="Test warning notification"
|
||||||
class="oe_highlight"/>
|
class="oe_highlight"/>
|
||||||
</group>
|
</group>
|
||||||
|
<group>
|
||||||
|
<button name="notify_info"
|
||||||
|
type="object"
|
||||||
|
string="Test info notification"
|
||||||
|
class="oe_highlight"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<button name="notify_default"
|
||||||
|
type="object"
|
||||||
|
string="Test default notification"
|
||||||
|
class="oe_highlight"/>
|
||||||
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<template id="assets_backend" name="web_notify assets" inherit_id="web.assets_backend">
|
<template id="assets_backend" name="web_notify assets" inherit_id="web.assets_backend">
|
||||||
|
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/webclient.scss" position="after">
|
||||||
|
<link rel="stylesheet" type="text/scss" href="/web_notify/static/src/scss/webclient.scss"/>
|
||||||
|
</link>
|
||||||
<xpath expr="." position="inside">
|
<xpath expr="." position="inside">
|
||||||
<script type="text/javascript" src="/web_notify/static/src/js/web_client.js"/>
|
<script type="text/javascript" src="/web_notify/static/src/js/web_client.js"/>
|
||||||
|
<script type="text/javascript" src="/web_notify/static/src/js/widgets/notification.js"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
Loading…
Reference in New Issue