From aa006658ea25abaa2b8d03003f1d4f9214fb6468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Fri, 9 Oct 2020 10:55:21 +0000 Subject: [FIX] mail: fix discuss search filters and related issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - don't reset `stringifiedDomain` when changing thread (this led to the control panel displaying obsolete filters) - refresh non-main cache that are currently displayed when there is a known change of messages in the same thread's main cache - refresh non-main-cache on displaying them, to fetch potentially new messages - fix discuss "select all" conditions task-2171873 task-2282374 closes odoo/odoo#59631 X-original-commit: b89dc5f949b3ad062fc4197a4152066c207e1bf9 Related: odoo/enterprise#13958 Signed-off-by: Alexandre Kühn (aku) --- .../static/src/models/thread_cache/thread_cache.js | 107 ++++++++++++++++++--- 1 file changed, 92 insertions(+), 15 deletions(-) (limited to 'addons/mail/static/src/models/thread_cache/thread_cache.js') diff --git a/addons/mail/static/src/models/thread_cache/thread_cache.js b/addons/mail/static/src/models/thread_cache/thread_cache.js index 080040981f2..4e2bb5208e2 100644 --- a/addons/mail/static/src/models/thread_cache/thread_cache.js +++ b/addons/mail/static/src/models/thread_cache/thread_cache.js @@ -20,7 +20,7 @@ function factory(dependencies) { return; } if (!this.isLoaded) { - this.update({ hasToLoadMessages: true }); + this.update({ isCacheRefreshRequested: true }); return; } this.update({ isLoadingMore: true }); @@ -31,7 +31,7 @@ function factory(dependencies) { limit, })); for (const threadView of this.threadViews) { - threadView.addComponentHint('more-messages-loaded'); + threadView.addComponentHint('more-messages-loaded', { fetchedMessages }); } this.update({ isLoadingMore: false }); if (fetchedMessages.length < limit) { @@ -48,14 +48,18 @@ function factory(dependencies) { return; } if (!this.isLoaded) { - this.update({ hasToLoadMessages: true }); + this.update({ isCacheRefreshRequested: true }); return; } const messageIds = this.fetchedMessages.map(message => message.id); - return this._loadMessages({ + const fetchedMessages = this._loadMessages({ extraDomain: [['id', '>', Math.max(...messageIds)]], limit: false, }); + for (const threadView of this.threadViews) { + threadView.addComponentHint('new-messages-loaded', { fetchedMessages }); + } + return fetchedMessages; } //---------------------------------------------------------------------- @@ -140,8 +144,6 @@ function factory(dependencies) { } let messages = this.fetchedMessages; if (this.stringifiedDomain !== '[]') { - // AKU TODO: flag for invalidation if there are newer messages - // in thread. task-2171873 return [['replace', messages]]; } // main cache: adjust with newer messages @@ -178,13 +180,34 @@ function factory(dependencies) { * @returns {boolean} */ _computeHasToLoadMessages() { - return ( - this.thread && - !this.thread.isTemporary && - this.threadViews.length > 0 && - !this.isLoaded && - !this.isLoading - ); + if (!this.thread) { + // happens during destroy or compute executed in wrong order + return false; + } + const wasCacheRefreshRequested = this.isCacheRefreshRequested; + // mark hint as processed + this.update({ isCacheRefreshRequested: false }); + if (this.thread.isTemporary) { + // temporary threads don't exist on the server + return false; + } + if (!wasCacheRefreshRequested && this.threadViews.length === 0) { + // don't load message that won't be used + return false; + } + if (!wasCacheRefreshRequested && (this.isLoaded || this.isLoading)) { + // avoid duplicate RPC + return false; + } + const isMainCache = this.thread.mainCache === this; + if (isMainCache && (this.isLoaded || this.isLoading)) { + // Ignore request on the main cache if it is already loaded or + // loading. Indeed the main cache is automatically sync with + // server updates already, so there is never a need to refresh + // it past the first time. + return false; + } + return true; } /** @@ -279,7 +302,31 @@ function factory(dependencies) { if (!this.hasToLoadMessages) { return; } - this._loadMessages(); + this._loadMessages().then(fetchedMessages => { + for (const threadView of this.threadViews) { + threadView.addComponentHint('messages-loaded', { fetchedMessages }); + } + }); + } + + /** + * Handles change of messages on this thread cache. This is useful to + * refresh non-main caches that are currently displayed when the main + * cache receives updates. This is necessary because only the main cache + * is aware of changes in real time. + */ + _onMessagesChanged() { + if (!this.thread) { + return; + } + if (this.thread.mainCache !== this) { + return; + } + for (const threadView of this.thread.threadViews) { + if (threadView.threadCache) { + threadView.threadCache.update({ isCacheRefreshRequested: true }); + } + } } } @@ -315,15 +362,19 @@ function factory(dependencies) { dependencies: ['threadMessages'], }), /** - * Determines whether `this` should load initial messages. + * Determines whether `this` should load initial messages. This field is + * computed and should be considered read-only. + * @see `isCacheRefreshRequested` to request manual refresh of messages. */ hasToLoadMessages: attr({ compute: '_computeHasToLoadMessages', dependencies: [ + 'isCacheRefreshRequested', 'isLoaded', 'isLoading', 'thread', 'threadIsTemporary', + 'threadMainCache', 'threadViews', ], }), @@ -339,6 +390,14 @@ function factory(dependencies) { isLoadingMore: attr({ default: false, }), + /** + * Determines whether `this` should consider refreshing its messages. + * This field is a hint that may or may not lead to an actual refresh. + * @see `hasToLoadMessages` + */ + isCacheRefreshRequested: attr({ + default: false, + }), /** * Last message that has been fetched by this thread cache. * @@ -378,6 +437,18 @@ function factory(dependencies) { 'hasToLoadMessages', ], }), + /** + * Not a real field, used to trigger `_onMessagesChanged` when one of + * the dependencies changes. + */ + onMessagesChanged: attr({ + compute: '_onMessagesChanged', + dependencies: [ + 'messages', + 'thread', + 'threadMainCache', + ], + }), /** * Ordered list of messages that have been fetched by this cache. * @@ -408,6 +479,12 @@ function factory(dependencies) { threadIsTemporary: attr({ related: 'thread.isTemporary', }), + /** + * Serves as compute dependency. + */ + threadMainCache: many2one('mail.thread_cache', { + related: 'thread.mainCache', + }), threadMessages: many2many('mail.message', { related: 'thread.messages', }), -- cgit v1.2.3