Skip to content

Commit 8d628ac

Browse files
committed
[IMP] web_refresh_from_backend U
- Coalesce notifications in case multiple notifications are sent in a short period of time. This allows to avoid multiple refreshes of the same view and potential UI glitches. - Use explicitly created users in tests. Using demo data was a bad idea, sorry. Task: 5286
1 parent ad84f8e commit 8d628ac

File tree

4 files changed

+76
-70
lines changed

4 files changed

+76
-70
lines changed

web_refresh_from_backend/static/src/views/form/form_controller_patch.esm.js

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,63 +30,61 @@ patch(FormController.prototype, {
3030
},
3131

3232
/**
33-
* Handle bus notification for view refresh.
34-
* Listens for notifications with type "web.refresh_view" and delegates
35-
* processing to _handleViewRefresh.
33+
* Handle bus notification batch for view refresh.
34+
* Coalesces the batch: if any notification matches, refreshes once.
3635
*
3736
* @param {Event} event - Bus notification event
3837
*/
3938
async _onBusNotification({detail: notifications}) {
4039
if (!this.model || !this.model.root) {
4140
return;
4241
}
43-
44-
for (const {payload, type} of notifications) {
45-
if (type === "web.refresh_view") {
46-
await this._handleViewRefresh(payload);
47-
}
42+
const shouldRefresh = notifications.some(
43+
({type, payload}) =>
44+
type === "web.refresh_view" && this._shouldRefreshView(payload)
45+
);
46+
if (shouldRefresh) {
47+
await this.refreshForm();
4848
}
4949
},
5050

5151
/**
52-
* Handle view refresh notification.
52+
* Check whether a refresh notification is relevant to this form.
5353
*
54-
* Only refreshes when:
54+
* Returns true when all of the following hold:
5555
* - model matches current form model
56-
* - requested view types include "form" (if specified)
57-
* - record id matches current record (if specified)
56+
* - requested view types include "form" (or none specified)
57+
* - record id matches current record (or none specified)
58+
* - form is not inside a dialog / wizard
5859
*
59-
* @param {Object} notification - Notification payload
60+
* @param {Object} payload - Notification payload
61+
* @returns {Boolean}
6062
*/
61-
async _handleViewRefresh(notification) {
62-
const {model, view_types = [], rec_ids = []} = notification;
63+
_shouldRefreshView(payload) {
64+
const {model, view_types = [], rec_ids = []} = payload;
6365

6466
if (this.props.resModel !== model) {
65-
return;
67+
return false;
6668
}
67-
6869
if (view_types.length > 0 && !view_types.includes("form")) {
69-
return;
70+
return false;
7071
}
71-
7272
const currentResId = this.model && this.model.root && this.model.root.resId;
7373
if (rec_ids.length > 0 && (!currentResId || !rec_ids.includes(currentResId))) {
74-
return;
74+
return false;
7575
}
76-
7776
// Skip refresh when form is in a dialog or when a wizard is on top
7877
// of the stack. Refreshing in that context can leave wizard/confirmation
7978
// dialogs stuck open (e.g. confirm="..." in wizard view).
8079
if (this.env.inDialog) {
81-
return;
80+
return false;
8281
}
8382
const currentController = this.actionService.currentController;
8483
const currentAction = currentController && currentController.action;
8584
if (currentAction && currentAction.target === "new") {
86-
return;
85+
return false;
8786
}
88-
89-
await this.refreshForm();
87+
return true;
9088
},
9189

9290
/**

web_refresh_from_backend/static/src/views/kanban/kanban_controller_patch.esm.js

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,48 +26,51 @@ patch(KanbanController.prototype, {
2626
},
2727

2828
/**
29-
* Handle bus notification for view refresh.
29+
* Handle bus notification batch for view refresh.
30+
* Coalesces the batch: if any notification matches, refreshes once.
3031
*
3132
* @param {Event} event - Bus notification event
3233
*/
3334
async _onBusNotification({detail: notifications}) {
3435
if (!this.model || !this.model.root) {
3536
return;
3637
}
37-
38-
for (const {payload, type} of notifications) {
39-
if (type === "web.refresh_view") {
40-
await this._handleViewRefresh(payload);
41-
}
38+
const shouldRefresh = notifications.some(
39+
({type, payload}) =>
40+
type === "web.refresh_view" && this._shouldRefreshView(payload)
41+
);
42+
if (shouldRefresh) {
43+
await this.refreshList();
4244
}
4345
},
4446

4547
/**
46-
* Handle view refresh notification.
48+
* Check whether a refresh notification is relevant to this kanban.
49+
*
50+
* Returns true when all of the following hold:
51+
* - model matches current kanban model
52+
* - requested view types include "kanban" (or none specified)
53+
* - at least one loaded record id is in rec_ids (or none specified)
4754
*
48-
* @param {Object} notification - Notification payload
55+
* @param {Object} payload - Notification payload
56+
* @returns {Boolean}
4957
*/
50-
async _handleViewRefresh(notification) {
51-
const {model, view_types = [], rec_ids = []} = notification;
58+
_shouldRefreshView(payload) {
59+
const {model, view_types = [], rec_ids = []} = payload;
5260

5361
if (this.props.resModel !== model) {
54-
return;
62+
return false;
5563
}
56-
5764
if (view_types.length > 0 && !view_types.includes("kanban")) {
58-
return;
65+
return false;
5966
}
60-
6167
if (rec_ids.length > 0) {
6268
const loadedIds = this.getLoadedRecordIds();
63-
const shouldReload = loadedIds.some((id) => rec_ids.includes(id));
64-
65-
if (!shouldReload) {
66-
return;
69+
if (!loadedIds.some((id) => rec_ids.includes(id))) {
70+
return false;
6771
}
6872
}
69-
70-
await this.refreshList();
73+
return true;
7174
},
7275

7376
/**

web_refresh_from_backend/static/src/views/list/list_controller_patch.esm.js

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,52 +27,55 @@ patch(ListController.prototype, {
2727
},
2828

2929
/**
30-
* Handle bus notification for view refresh.
30+
* Handle bus notification batch for view refresh.
31+
* Coalesces the batch: if any notification matches, refreshes once.
3132
*
3233
* @param {Event} event - Bus notification event
3334
*/
3435
async _onBusNotification({detail: notifications}) {
3536
if (!this.model || !this.model.root) {
3637
return;
3738
}
38-
39-
for (const {payload, type} of notifications) {
40-
if (type === "web.refresh_view") {
41-
await this._handleViewRefresh(payload);
42-
}
39+
const shouldRefresh = notifications.some(
40+
({type, payload}) =>
41+
type === "web.refresh_view" && this._shouldRefreshView(payload)
42+
);
43+
if (shouldRefresh) {
44+
await this.refreshList();
4345
}
4446
},
4547

4648
/**
47-
* Handle view refresh notification.
49+
* Check whether a refresh notification is relevant to this list.
50+
*
51+
* Returns true when all of the following hold:
52+
* - model matches current list model
53+
* - requested view types include "list" or "tree" (or none specified)
54+
* - at least one loaded record id is in rec_ids (or none specified)
4855
*
49-
* @param {Object} notification - Notification payload
56+
* @param {Object} payload - Notification payload
57+
* @returns {Boolean}
5058
*/
51-
async _handleViewRefresh(notification) {
52-
const {model, view_types = [], rec_ids = []} = notification;
59+
_shouldRefreshView(payload) {
60+
const {model, view_types = [], rec_ids = []} = payload;
5361

5462
if (this.props.resModel !== model) {
55-
return;
63+
return false;
5664
}
57-
5865
if (
5966
view_types.length > 0 &&
6067
!view_types.includes("list") &&
6168
!view_types.includes("tree")
6269
) {
63-
return;
70+
return false;
6471
}
65-
6672
if (rec_ids.length > 0) {
6773
const loadedIds = this.getLoadedRecordIds();
68-
const shouldReload = loadedIds.some((id) => rec_ids.includes(id));
69-
70-
if (!shouldReload) {
71-
return;
74+
if (!loadedIds.some((id) => rec_ids.includes(id))) {
75+
return false;
7276
}
7377
}
74-
75-
await this.refreshList();
78+
return true;
7679
},
7780

7881
/**

web_refresh_from_backend/tests/test_reload_views.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,21 @@
44
from unittest.mock import patch
55

66
from odoo.tests import tagged
7-
from odoo.tests.common import TransactionCase
7+
8+
from odoo.addons.base.tests.common import BaseCommon
89

910

1011
@tagged("post_install", "-at_install")
11-
class TestReloadViews(TransactionCase):
12+
class TestReloadViews(BaseCommon):
1213
@classmethod
1314
def setUpClass(cls):
1415
super().setUpClass()
1516
cls.user_admin = cls.env.ref("base.user_admin")
16-
cls.user_demo = cls.env.ref("base.user_demo")
17-
cls.partner = cls.env["res.partner"].create(
17+
cls.user_demo = cls.env["res.users"].create(
1818
{
19-
"name": "Test Partner",
19+
"name": "Test User",
20+
"login": "test_refresh_user",
21+
"email": "test_refresh@example.com",
2022
}
2123
)
2224

0 commit comments

Comments
 (0)