[FIX] bus: fix im status not updating

Odoo periodically updates the user online status. This is
done every minute and is throttled in order to ensure it won't
be triggered more than it should.

Since [1], the underscore `throttle` function has been replaced
by the `throttleForAnimation` function. This is not equivalent:
the function won't be triggered if there is no animation which
result in an outdated user status.

This issue was highlighted by the live chat: the button does
not show up when there is no available operator.

Steps to reproduce the issue:
- Log in on Odoo with live chat installed
- Go to a web page that uses the live chat widget
- Wait more that one minute and refresh the page
- The live chat button is not shown anymore: the only
operator is considered as disconnected.

This PR fixes that issue by re-introducing the underscore
throttle function: it is robust and can be needed, not all
throttles are linked to animations.

[1]: https://github.com/odoo/odoo/pull/120437.

opw-3578517

closes odoo/odoo#142160

X-original-commit: f64a7cbad3dee3ffc365b931306b1c13c8bff536
Signed-off-by: Matthieu Stockbauer (tsm) <tsm@odoo.com>
This commit is contained in:
tsm-odoo
2023-11-15 13:56:35 +00:00
parent 307a2e0363
commit c9b72f09d8
3 changed files with 72 additions and 2 deletions
+2 -2
View File
@@ -2,7 +2,7 @@
import { browser } from "@web/core/browser/browser";
import { registry } from "@web/core/registry";
import { throttleForAnimation } from "@web/core/utils/timing";
import { timings } from "@bus/misc";
export const UPDATE_BUS_PRESENCE_DELAY = 60000;
/**
@@ -18,7 +18,7 @@ export const imStatusService = {
start(env, { bus_service, multi_tab, presence }) {
const imStatusModelToIds = {};
let updateBusPresenceTimeout;
const throttledUpdateBusPresence = throttleForAnimation(function updateBusPresence() {
const throttledUpdateBusPresence = timings.throttle(function updateBusPresence() {
clearTimeout(updateBusPresenceTimeout);
if (!multi_tab.isOnMainTab()) {
return;
+65
View File
@@ -0,0 +1,65 @@
/** @odoo-module */
import { browser } from "@web/core/browser/browser";
/**
* Returns a function, that, when invoked, will only be triggered at most once
* during a given window of time. Normally, the throttled function will run
* as much as it can, without ever going more than once per `wait` duration;
* but if you'd like to disable the execution on the leading edge, pass
* `{leading: false}`. To disable execution on the trailing edge, ditto.
*
* credit to `underscore.js`
*/
function throttle(func, wait, options) {
let timeout, context, args, result;
let previous = 0;
if (!options) {
options = {};
}
const later = function () {
previous = options.leading === false ? 0 : Date.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) {
context = args = null;
}
};
const throttled = function () {
const _now = Date.now();
if (!previous && options.leading === false) {
previous = _now;
}
const remaining = wait - (_now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
browser.clearTimeout(timeout);
timeout = null;
}
previous = _now;
result = func.apply(context, args);
if (!timeout) {
context = args = null;
}
} else if (!timeout && options.trailing !== false) {
timeout = browser.setTimeout(later, remaining);
}
return result;
};
throttled.cancel = function () {
browser.clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};
return throttled;
}
export const timings = {
throttle,
};
@@ -1,6 +1,7 @@
/* @odoo-module */
import { getPyEnv } from "@bus/../tests/helpers/mock_python_environment";
import { timings } from "@bus/misc";
import { loadEmoji } from "@web/core/emoji_picker/emoji_picker";
import { loadLamejs } from "@mail/discuss/voice_message/common/voice_message_service";
@@ -139,6 +140,10 @@ async function addSwitchTabDropdownItem(rootTarget, tabTarget) {
*/
export async function start(param0 = {}) {
const { discuss = {}, hasTimeControl } = param0;
patchWithCleanup(timings, {
// make throttle instantaneous during tests
throttle: (func) => func,
});
const advanceTime = hasTimeControl ? getAdvanceTime() : undefined;
let target = param0["target"] || getFixture();
if (param0.asTab) {