Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
290 changes: 290 additions & 0 deletions bus_record_events/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
=================
Bus Record Events
=================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:edc60b3b2e2697b562ea36d30a90695ed3b1d0422d04df07a09eb76890efae66
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
:target: https://github.com/OCA/web/tree/17.0/bus_record_events
:alt: OCA/web
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/web-17-0/web-17-0-bus_record_events
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=17.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module provides an efficient and secure mechanism to notify CRUD
events (Create, Write, Unlink) in real-time via the Odoo Bus.

**Key Features:**

- **Server Efficiency**: Uses Odoo's native ``bus.bus`` system to avoid
table locking and minimize performance impact.
- **Granular Security**: Implements a permission system in
``ir.websocket`` ensuring users can only subscribe to record or model
channels for which they have read permissions (Access Rights and
Record Rules).

**Table of contents**

.. contents::
:local:

Use Cases / Context
===================

This module was designed to provide real-time capabilities to Odoo views
without heavy polling.

Installation
============

This module depends on the ``bus`` and ``web`` modules.

Configuration
=============

No specific configuration is required.

Usage
=====

For Developers
--------------

To enable notifications on a model, simply inherit from the
``bus.record.event.mixin`` mixin:

.. code:: python

class MyModel(models.Model):
_name = 'my.model'
_inherit = ['my.model', 'bus.record.event.mixin']

Subscription Channels
~~~~~~~~~~~~~~~~~~~~~

The module manages two types of channels for client-side subscriptions
(OWL/JS):

1. **Model Events (``create``)**:

- Channel: ``record_events:{model_name}``
- Example: ``record_events:res.partner``
- Requires: Read permissions at the model level.

2. **Record Events (``write``, ``unlink``)**:

- Channel: ``record_events:{model_name}:{record_id}``
- Example: ``record_events:res.partner:15``
- Requires: Read permissions on the specific record (record rules
applied).

Reactive Views
--------------

The module includes extended view controllers that automatically listen
for these events and update the interface or notify the user.

To use these reactive views, you must specify the ``js_class`` attribute
in the XML view definition.

Available Views
~~~~~~~~~~~~~~~

+--------------+-------------------------------+---------------------------+
| View Type | js_class | Behavior |
+==============+===============================+===========================+
| **Form** | ``bus_record_event_form`` | Notifies if the record |
| | | has been modified or |
| | | deleted by another user |
| | | while editing. If there |
| | | are no unsaved changes, |
| | | it automatically reloads |
| | | the data. |
+--------------+-------------------------------+---------------------------+
| **Kanban** | ``bus_record_event_kanban`` | Automatically reloads the |
| | | view upon receiving |
| | | create, update, or delete |
| | | events in the model. |
+--------------+-------------------------------+---------------------------+
| **Pivot** | ``bus_record_event_pivot`` | Automatically reloads the |
| | | view upon changes in the |
| | | model. |
+--------------+-------------------------------+---------------------------+
| **Graph** | ``bus_record_event_graph`` | Automatically reloads the |
| | | view upon changes in the |
| | | model. |
+--------------+-------------------------------+---------------------------+
| **Calendar** | ``bus_record_event_calendar`` | Automatically reloads the |
| | | view upon changes in the |
| | | model. |
+--------------+-------------------------------+---------------------------+
| **List** | ``bus_record_event_list`` | Automatically reloads the |
| | | view upon changes in the |
| | | model. |
+--------------+-------------------------------+---------------------------+

Usage Example (XML)
~~~~~~~~~~~~~~~~~~~

.. code:: xml

<record id="view_my_model_form" model="ir.ui.view">
<field name="name">my.model.form</field>
<field name="model">my.model</field>
<field name="arch" type="xml">
<form js_class="bus_record_event_form">
<!-- ... -->
</form>
</field>
</record>

<record id="view_my_model_kanban" model="ir.ui.view">
<field name="name">my.model.kanban</field>
<field name="model">my.model</field>
<field name="arch" type="xml">
<kanban js_class="bus_record_event_kanban">
<!-- ... -->
</kanban>
</field>
</record>

JavaScript API
--------------

Service: ``bus_record_event_service``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The module provides a service to manage subscriptions to record events.

.. code:: javascript

const busRecordEventService = useService("bus_record_event_service");

// Add a channel to listen to
busRecordEventService.addChannel("record_events:res.partner:1");

// Subscribe to notifications
const unsubscribe = busRecordEventService.subscribe((payload) => {
console.log("Received event:", payload);
});

// Clean up
unsubscribe();

Hook: ``useRecordStream``
~~~~~~~~~~~~~~~~~~~~~~~~~

For OWL components, it is recommended to use the ``useRecordStream``
hook. It handles the lifecycle of the subscription (adding channels on
start, unsubscribing on unmount).

.. code:: javascript

import { useRecordStream } from "@bus_record_events/js/hooks/use_record_stream.esm";

setup() {
useRecordStream("res.partner", {
id: this.props.resId, // Optional: Listen to a specific record
onReload: async () => {
// Callback to reload the view/component
await this.model.load();
},
onUpdate: async (payload) => {
// Optional: Custom handling of the event
},
filter: (payload) => {
// Optional: Filter events before processing
return true;
}
});
}

Known issues / Roadmap
======================

- No known issues.
- **Data Optimization**: Notification payloads compressed using ``zlib``
and encoded in ``base64``. (Discarded for now: Tested but with
thousands of messages it generated too many ``blob:...`` threads in
the client browser, making it unable to manage all messages).
- **Permission Revocation Handling**: Currently, if a client loses
permission to a record they are already subscribed to, they might
continue receiving updates. It would be beneficial to find a
server-side mechanism to force-unsubscribe a client from a specific
channel when their permissions change.

Changelog
=========

17.0.1.0.0 (2023-12-16)

::


* Initial release.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/web/issues/new?body=module:%20bus_record_events%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Heligrafics Fotogrametria S.L.

Contributors
------------

- Heligrafics Fotogrametria S.L. <http://www.heligrafics.net/>:

- Jose Zambudio <jzambudio@heligrafics.net>

Other credits
-------------

The development of this module has been financially supported by:

- Heligrafics Fotogrametria S.L.

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/web <https://github.com/OCA/web/tree/17.0/bus_record_events>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions bus_record_events/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
38 changes: 38 additions & 0 deletions bus_record_events/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "Bus Record Events",
"version": "17.0.1.0.0",
"category": "Web",
"summary": "Broadcast CRUD operations (Create, Write, Unlink) via Odoo "
"Bus for OWL reactivity.",
"author": "Heligrafics Fotogrametria S.L., Odoo Community Association (OCA)",
"website": "https://github.com/OCA/web",
"license": "AGPL-3",
"depends": [
"base",
"bus",
"web",
],
"data": [],
"assets": {
"web.assets_backend": [
"bus_record_events/static/src/js/services/*.js",
"bus_record_events/static/src/js/hooks/*.js",
"bus_record_events/static/src/js/views/form/*.js",
"bus_record_events/static/src/js/views/kanban/*.js",
"bus_record_events/static/src/js/views/pivot/*.js",
"bus_record_events/static/src/js/views/graph/*.js",
"bus_record_events/static/src/js/views/calendar/*.js",
"bus_record_events/static/src/js/views/list/*.js",
],
"web.qunit_suite_tests": [
"web/static/src/legacy/utils.js",
"web/static/src/legacy/js/**/*",
("remove", "web/static/src/legacy/js/libs/**/*"),
("remove", "web/static/src/legacy/js/public/**/*"),
"bus_record_events/static/tests/unit/hooks/*.js",
"bus_record_events/static/tests/unit/services/*.js",
"bus_record_events/static/tests/unit/views/*.js",
],
},
"installable": True,
}
2 changes: 2 additions & 0 deletions bus_record_events/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import bus_event_mixin
from . import ir_websocket
Loading