diff options
| author | Xavier Dubuc <xdu@odoo.com> | 2020-09-03 16:24:19 +0000 |
|---|---|---|
| committer | Sébastien Theys <seb@odoo.com> | 2020-09-04 14:59:01 +0000 |
| commit | 8d3413ff647de8d98c6858062dd07dde4160af95 (patch) | |
| tree | 3dc134e83c874d5c7f7bf739f13a88ab986ddb1b /addons/mail/static/src/models/thread_view/thread_view.js | |
| parent | a5ab687be4e7890262ce9429e18dd011021513d5 (diff) | |
[FIX] mail, sms, snailmail: prevent message_fetch for hidden threads
Automatically load messages from a thread cache only if the thread cache is used
in at least one thread view.
Ensure thread viewer don't keep thread view records alive when they are not
displayed.
This change is particularly important for performance, to avoid spamming RPC at
init if many threads are opened in chat windows.
task-2310623
closes odoo/odoo#57061
X-original-commit: dd6981c7812134e0588f80a157eaba45512cd68e
Related: odoo/enterprise#12936
Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
Diffstat (limited to 'addons/mail/static/src/models/thread_view/thread_view.js')
| -rw-r--r-- | addons/mail/static/src/models/thread_view/thread_view.js | 200 |
1 files changed, 99 insertions, 101 deletions
diff --git a/addons/mail/static/src/models/thread_view/thread_view.js b/addons/mail/static/src/models/thread_view/thread_view.js index f0075314561..d7ea1508067 100644 --- a/addons/mail/static/src/models/thread_view/thread_view.js +++ b/addons/mail/static/src/models/thread_view/thread_view.js @@ -13,7 +13,7 @@ function factory(dependencies) { * @override */ _willDelete() { - this._stopLoading(); + this.env.browser.clearTimeout(this._loaderTimeout); return super._willDelete(...arguments); } @@ -41,16 +41,6 @@ function factory(dependencies) { } /** - * @param {mail.thread_cache} threadCache - */ - handleThreadCacheLoaded(threadCache) { - if (threadCache !== this.threadCache) { - return; - } - this._stopLoading(); - } - - /** * @param {Object} hint */ markComponentHintProcessed(hint) { @@ -77,33 +67,19 @@ function factory(dependencies) { } } - /** - * @param {string} scrollTop - */ - saveThreadCacheScrollPositionsAsInitial(scrollTop) { - if (!this.threadCache) { - return; - } - this.update({ - threadCacheInitialScrollPositions: Object.assign({}, this.threadCacheInitialScrollPositions, { - [this.threadCache.localId]: scrollTop, - }), - }); - } - //---------------------------------------------------------------------- // Private //---------------------------------------------------------------------- /** * @private - * @returns {mail.thread_cache|undefined} + * @returns {integer|undefined} */ - _computeThreadCache() { - if (!this.thread) { - return []; + _computeThreadCacheInitialScrollPosition() { + if (!this.threadCache) { + return; } - return [['link', this.thread.cache(this.stringifiedDomain)]]; + return this.threadCacheInitialScrollPositions[this.threadCache.localId]; } /** @@ -131,75 +107,37 @@ function factory(dependencies) { /** * @private - * @returns {integer|undefined} - */ - _computeThreadCacheInitialScrollPosition() { - if (!this.threadCache) { - return undefined; - } - return this.threadCacheInitialScrollPositions[this.threadCache.localId]; - } - - /** - * @private */ - _prepareLoading() { - this._isPreparingLoading = true; - this._loaderTimeout = setTimeout(() => { - this.isShowingLoading = true; - this._isPreparingLoading = false; - }, 400); + _onThreadCacheChanged() { + this.addComponentHint('change-of-thread-cache'); } /** * @private */ - _stopLoading() { - clearTimeout(this._loaderTimeout); - this._loaderTimeout = null; - this.isShowingLoading = false; - this._isPreparingLoading = false; - } - - /** - * @override - */ - _updateAfter(previous) { - if (this.thread && this.thread !== previous.thread) { - this._stopLoading(); - if (!this.threadCache.isLoaded && !this.threadCache.isLoading) { - this.threadCache.loadMessages(); + _onThreadCacheIsLoadingChanged() { + if (this.threadCache && this.threadCache.isLoading) { + if (!this.isLoading && !this.isPreparingLoading) { + this.update({ isPreparingLoading: true }); + this.async(() => + new Promise(resolve => { + this._loaderTimeout = this.env.browser.setTimeout(resolve, 400); + } + )).then(() => { + const isLoading = this.threadCache + ? this.threadCache.isLoading + : false; + this.update({ isLoading, isPreparingLoading: false }); + }); } + return; } - if (this.threadCache !== previous.threadCache) { - this._stopLoading(); - this.addComponentHint('change-of-thread-cache'); - } - - if ( - this.thread && this.threadCache && this.threadCache.isLoading && - !this.isShowingLoading && !this._isPreparingLoading - ) { - this._prepareLoading(); - } - } - - /** - * @override - */ - _updateBefore() { - return { - thread: this.thread, - threadCache: this.threadCache, - }; + this.env.browser.clearTimeout(this._loaderTimeout); + this.update({ isLoading: false, isPreparingLoading: false }); } - } ThreadView.fields = { - chatWindow: one2one('mail.chat_window', { - inverse: 'threadView', - }), checkedMessages: many2many('mail.message', { related: 'threadCache.checkedMessages', }), @@ -230,6 +168,31 @@ function factory(dependencies) { hasComposerFocus: attr({ related: 'composer.hasFocus', }), + /** + * States whether `this.threadCache` is currently loading messages. + * + * This field is related to `this.threadCache.isLoading` but with a + * delay on its update to avoid flickering on the UI. + * + * It is computed through `_onThreadCacheIsLoadingChanged` and it should + * otherwise be considered read-only. + */ + isLoading: attr({ + default: false, + }), + /** + * States whether `this` is aware of `this.threadCache` currently + * loading messages, but `this` is not yet ready to display that loading + * on the UI. + * + * This field is computed through `_onThreadCacheIsLoadingChanged` and + * it should otherwise be considered read-only. + * + * @see `this.isLoading` + */ + isPreparingLoading: attr({ + default: false, + }), lastMessage: many2one('mail.message', { related: 'thread.lastMessage', }), @@ -241,19 +204,48 @@ function factory(dependencies) { messages: many2many('mail.message', { related: 'threadCache.messages', }), + /** + * Not a real field, used to trigger `_onThreadCacheChanged` when one of + * the dependencies changes. + */ + onThreadCacheChanged: attr({ + compute: '_onThreadCacheChanged', + dependencies: [ + 'threadCache' + ], + }), + /** + * Not a real field, used to trigger `_onThreadCacheIsLoadingChanged` + * when one of the dependencies changes. + * + * @see `this.isLoading` + */ + onThreadCacheIsLoadingChanged: attr({ + compute: '_onThreadCacheIsLoadingChanged', + dependencies: [ + 'threadCache', + 'threadCacheIsLoading', + ], + }), + /** + * Determines the domain to apply when fetching messages for `this.thread`. + */ stringifiedDomain: attr({ - default: '[]', + related: 'threadViewer.stringifiedDomain', }), + /** + * Determines the `mail.thread` currently displayed by `this`. + */ thread: many2one('mail.thread', { inverse: 'threadViews', + related: 'threadViewer.thread', }), + /** + * States the `mail.thread_cache` currently displayed by `this`. + */ threadCache: many2one('mail.thread_cache', { - compute: '_computeThreadCache', - dependencies: [ - 'stringifiedDomain', - 'thread', - 'threadCaches', - ], + inverse: 'threadViews', + related: 'threadViewer.threadCache', }), threadCacheInitialScrollPosition: attr({ compute: '_computeThreadCacheInitialScrollPosition', @@ -263,17 +255,17 @@ function factory(dependencies) { ], }), /** + * Serves as compute dependency. + */ + threadCacheIsLoading: attr({ + related: 'threadCache.isLoading', + }), + /** * List of saved initial scroll positions of thread caches. - * Useful to restore scroll position on changing back to this - * thread cache. Note that this is only applied when opening - * the thread cache, because scroll position may change fast so - * save is already throttled */ threadCacheInitialScrollPositions: attr({ default: {}, - }), - threadCaches: many2many('mail.thread_cache', { - related: 'thread.caches', + related: 'threadViewer.threadCacheInitialScrollPositions', }), /** * Not a real field, used to trigger `thread.markAsSeen` when one of @@ -288,6 +280,12 @@ function factory(dependencies) { 'threadCache', ], }), + /** + * Determines the `mail.thread_viewer` currently managing `this`. + */ + threadViewer: one2one('mail.thread_viewer', { + inverse: 'threadView', + }), uncheckedMessages: many2many('mail.message', { related: 'threadCache.uncheckedMessages', }), |
