From 21659b9e545ed926d8392eb02717b6c2bc7d26e9 Mon Sep 17 00:00:00 2001 From: Matt O'Keefe Date: Thu, 21 Aug 2025 13:41:18 -0500 Subject: [PATCH 01/16] [IMP] web_refresher: add auto refresh on interval --- web_refresher/__manifest__.py | 2 +- web_refresher/static/src/js/refresher.esm.js | 49 ++++++++++++++++++-- web_refresher/static/src/xml/refresher.xml | 31 ++++++++++--- 3 files changed, 70 insertions(+), 12 deletions(-) diff --git a/web_refresher/__manifest__.py b/web_refresher/__manifest__.py index dccde6e64684..5115eeda1b8d 100644 --- a/web_refresher/__manifest__.py +++ b/web_refresher/__manifest__.py @@ -1,6 +1,6 @@ { "name": "Web Refresher", - "version": "18.0.1.0.0", + "version": "18.0.2.0.0", "author": "Compassion Switzerland, Tecnativa, Odoo Community Association (OCA)", "license": "AGPL-3", "website": "https://github.com/OCA/web", diff --git a/web_refresher/static/src/js/refresher.esm.js b/web_refresher/static/src/js/refresher.esm.js index b8aadcea9538..08ad74137e37 100644 --- a/web_refresher/static/src/js/refresher.esm.js +++ b/web_refresher/static/src/js/refresher.esm.js @@ -13,10 +13,10 @@ export function useRefreshAnimation(timeout) { /** * @returns {DOMTokenList|null} - */ - function contentClassList() { - const content = document.querySelector(".o_content"); - return content ? content.classList : null; + */ + function contentClassList() { + const content = document.querySelector(".o_content"); + return content ? content.classList : null; } function clearAnimationTimeout() { @@ -39,11 +39,15 @@ export function useRefreshAnimation(timeout) { } export class Refresher extends Component { + setup() { super.setup(); this.action = useService("action"); this.refreshAnimation = useRefreshAnimation(1000); this.onClickRefresh = useDebounced(this.onClickRefresh, 200); + this.onChangeAutoRefreshInterval = this.onChangeAutoRefreshInterval.bind(this); + this.refreshInterval = -1; + this.runningRefresherId = null; } /** @@ -81,6 +85,16 @@ export class Refresher extends Component { if (!updated) { updated = this._searchModelRefresh(); } + // Check the refreshInterval is greater than 0 and start a timer for the next refresh + if (this.refreshInterval > 0) { + // always attempt to clear a running timeout in case the refresh was done manually + if (typeof this.runningRefresherId === 'number') { + clearTimeout(this.runningRefresherId); + } + this.runningRefresherId = setTimeout(() => { + this.refresh(); + }, this.refreshInterval); + } return updated; } @@ -111,6 +125,33 @@ export class Refresher extends Component { this.refreshAnimation(); } } + + onChangeAutoRefreshInterval(clickedOption) { + const newInterval = parseInt(clickedOption.value ?? clickedOption.target.value) ?? null; + this.refreshInterval = newInterval; + this._setIntervalButtonText(); + if (this.runningRefresherId) { + clearTimeout(this.runningRefresherId); + } + this.refresh(); + } + + _setIntervalButtonText() { + let intervalValue; + if (!this.refreshInterval || this.refreshInterval <= 0) { + intervalValue = "Off"; + document.getElementById('manual-refresh-icon').classList.remove('fa-spin'); + } else { + const intervalInSeconds = this.refreshInterval / 1000; + if (intervalInSeconds >= 60) { + intervalValue = `${Math.floor(intervalInSeconds / 60)}min`; + } else { + intervalValue = `${intervalInSeconds}s`; + } + document.getElementById('manual-refresh-icon').classList.add('fa-spin'); + } + document.getElementById('auto-refresh-dd').textContent = `Auto Refresh: ${intervalValue}`; + } } Object.assign(Refresher, { diff --git a/web_refresher/static/src/xml/refresher.xml b/web_refresher/static/src/xml/refresher.xml index 4827c5a656b1..8b526c070193 100644 --- a/web_refresher/static/src/xml/refresher.xml +++ b/web_refresher/static/src/xml/refresher.xml @@ -5,13 +5,30 @@ From e0da3975660548855011cac5d1e80b8d03898a92 Mon Sep 17 00:00:00 2001 From: Matt O'Keefe Date: Thu, 21 Aug 2025 13:53:32 -0500 Subject: [PATCH 02/16] [FIX] web_refresher: linting --- web_refresher/static/src/js/refresher.esm.js | 23 ++++----- web_refresher/static/src/xml/refresher.xml | 49 ++++++++++++++++---- 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/web_refresher/static/src/js/refresher.esm.js b/web_refresher/static/src/js/refresher.esm.js index 08ad74137e37..3156eacaba4b 100644 --- a/web_refresher/static/src/js/refresher.esm.js +++ b/web_refresher/static/src/js/refresher.esm.js @@ -13,10 +13,10 @@ export function useRefreshAnimation(timeout) { /** * @returns {DOMTokenList|null} - */ - function contentClassList() { - const content = document.querySelector(".o_content"); - return content ? content.classList : null; + */ + function contentClassList() { + const content = document.querySelector(".o_content"); + return content ? content.classList : null; } function clearAnimationTimeout() { @@ -39,7 +39,6 @@ export function useRefreshAnimation(timeout) { } export class Refresher extends Component { - setup() { super.setup(); this.action = useService("action"); @@ -87,8 +86,8 @@ export class Refresher extends Component { } // Check the refreshInterval is greater than 0 and start a timer for the next refresh if (this.refreshInterval > 0) { - // always attempt to clear a running timeout in case the refresh was done manually - if (typeof this.runningRefresherId === 'number') { + // Always attempt to clear a running timeout in case the refresh was done manually + if (typeof this.runningRefresherId === "number") { clearTimeout(this.runningRefresherId); } this.runningRefresherId = setTimeout(() => { @@ -127,7 +126,8 @@ export class Refresher extends Component { } onChangeAutoRefreshInterval(clickedOption) { - const newInterval = parseInt(clickedOption.value ?? clickedOption.target.value) ?? null; + const newInterval = + parseInt(clickedOption.value ?? clickedOption.target.value) ?? null; this.refreshInterval = newInterval; this._setIntervalButtonText(); if (this.runningRefresherId) { @@ -140,7 +140,7 @@ export class Refresher extends Component { let intervalValue; if (!this.refreshInterval || this.refreshInterval <= 0) { intervalValue = "Off"; - document.getElementById('manual-refresh-icon').classList.remove('fa-spin'); + document.getElementById("manual-refresh-icon").classList.remove("fa-spin"); } else { const intervalInSeconds = this.refreshInterval / 1000; if (intervalInSeconds >= 60) { @@ -148,9 +148,10 @@ export class Refresher extends Component { } else { intervalValue = `${intervalInSeconds}s`; } - document.getElementById('manual-refresh-icon').classList.add('fa-spin'); + document.getElementById("manual-refresh-icon").classList.add("fa-spin"); } - document.getElementById('auto-refresh-dd').textContent = `Auto Refresh: ${intervalValue}`; + document.getElementById("auto-refresh-dd").textContent = + `Auto Refresh: ${intervalValue}`; } } diff --git a/web_refresher/static/src/xml/refresher.xml b/web_refresher/static/src/xml/refresher.xml index 8b526c070193..b3e7d7ab218b 100644 --- a/web_refresher/static/src/xml/refresher.xml +++ b/web_refresher/static/src/xml/refresher.xml @@ -7,16 +7,46 @@ From db951f680c69e17fdb36a1d31beb477c99cd6020 Mon Sep 17 00:00:00 2001 From: Matt O'Keefe Date: Thu, 21 Aug 2025 14:04:18 -0500 Subject: [PATCH 03/16] [CHORE] web_refresher: one more lint fix --- web_refresher/static/src/js/refresher.esm.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web_refresher/static/src/js/refresher.esm.js b/web_refresher/static/src/js/refresher.esm.js index 3156eacaba4b..7916e91629c3 100644 --- a/web_refresher/static/src/js/refresher.esm.js +++ b/web_refresher/static/src/js/refresher.esm.js @@ -127,7 +127,7 @@ export class Refresher extends Component { onChangeAutoRefreshInterval(clickedOption) { const newInterval = - parseInt(clickedOption.value ?? clickedOption.target.value) ?? null; + parseInt(clickedOption.value ?? clickedOption.target.value) ?? -1; this.refreshInterval = newInterval; this._setIntervalButtonText(); if (this.runningRefresherId) { @@ -137,7 +137,7 @@ export class Refresher extends Component { } _setIntervalButtonText() { - let intervalValue; + let intervalValue = 'Off'; if (!this.refreshInterval || this.refreshInterval <= 0) { intervalValue = "Off"; document.getElementById("manual-refresh-icon").classList.remove("fa-spin"); From 888ab62f06eebf4742bc85ac8254e5b3cae35858 Mon Sep 17 00:00:00 2001 From: Matt O'Keefe Date: Mon, 1 Sep 2025 07:18:18 -0500 Subject: [PATCH 04/16] [CHORE] web_refresher: one more lint fix --- web_refresher/static/src/js/refresher.esm.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web_refresher/static/src/js/refresher.esm.js b/web_refresher/static/src/js/refresher.esm.js index 7916e91629c3..a24a58cd9936 100644 --- a/web_refresher/static/src/js/refresher.esm.js +++ b/web_refresher/static/src/js/refresher.esm.js @@ -39,13 +39,15 @@ export function useRefreshAnimation(timeout) { } export class Refresher extends Component { + autoRefreshIntervalKey = "autoRefreshInterval"; setup() { super.setup(); this.action = useService("action"); this.refreshAnimation = useRefreshAnimation(1000); this.onClickRefresh = useDebounced(this.onClickRefresh, 200); this.onChangeAutoRefreshInterval = this.onChangeAutoRefreshInterval.bind(this); - this.refreshInterval = -1; + this.refreshInterval = localStorage.getItem(this.autoRefreshIntervalKey) ?? -1; + this._setIntervalButtonText(); this.runningRefresherId = null; } @@ -128,6 +130,7 @@ export class Refresher extends Component { onChangeAutoRefreshInterval(clickedOption) { const newInterval = parseInt(clickedOption.value ?? clickedOption.target.value) ?? -1; + localStorage.setItem(this.autoRefreshIntervalKey, newInterval); this.refreshInterval = newInterval; this._setIntervalButtonText(); if (this.runningRefresherId) { From 756622274b9f621d39aa02cca660102e3830d214 Mon Sep 17 00:00:00 2001 From: Matt O'Keefe Date: Mon, 1 Sep 2025 07:23:00 -0500 Subject: [PATCH 05/16] [IMP] web_refresher: make the interval text cleaner --- web_refresher/static/src/js/refresher.esm.js | 13 +++---------- web_refresher/static/src/xml/refresher.xml | 2 +- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/web_refresher/static/src/js/refresher.esm.js b/web_refresher/static/src/js/refresher.esm.js index a24a58cd9936..335731e4faa0 100644 --- a/web_refresher/static/src/js/refresher.esm.js +++ b/web_refresher/static/src/js/refresher.esm.js @@ -131,8 +131,9 @@ export class Refresher extends Component { const newInterval = parseInt(clickedOption.value ?? clickedOption.target.value) ?? -1; localStorage.setItem(this.autoRefreshIntervalKey, newInterval); + const newIntervalText = clickedOption.textContent ?? clickedOption.target.textContent; this.refreshInterval = newInterval; - this._setIntervalButtonText(); + this._setIntervalButtonText(newIntervalText); if (this.runningRefresherId) { clearTimeout(this.runningRefresherId); } @@ -142,19 +143,11 @@ export class Refresher extends Component { _setIntervalButtonText() { let intervalValue = 'Off'; if (!this.refreshInterval || this.refreshInterval <= 0) { - intervalValue = "Off"; document.getElementById("manual-refresh-icon").classList.remove("fa-spin"); } else { - const intervalInSeconds = this.refreshInterval / 1000; - if (intervalInSeconds >= 60) { - intervalValue = `${Math.floor(intervalInSeconds / 60)}min`; - } else { - intervalValue = `${intervalInSeconds}s`; - } document.getElementById("manual-refresh-icon").classList.add("fa-spin"); } - document.getElementById("auto-refresh-dd").textContent = - `Auto Refresh: ${intervalValue}`; + document.getElementById("auto-refresh-interval-text").textContent = intervalText; } } diff --git a/web_refresher/static/src/xml/refresher.xml b/web_refresher/static/src/xml/refresher.xml index b3e7d7ab218b..cac20be924f8 100644 --- a/web_refresher/static/src/xml/refresher.xml +++ b/web_refresher/static/src/xml/refresher.xml @@ -14,7 +14,7 @@ data-bs-toggle="dropdown" aria-expanded="false" > - Auto Refresh: Off + Auto Refresh: Off +