summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/models/thread_view/thread_view.js
diff options
context:
space:
mode:
authorXavier Dubuc <xdu@odoo.com>2020-09-03 16:24:19 +0000
committerSébastien Theys <seb@odoo.com>2020-09-04 14:59:01 +0000
commit8d3413ff647de8d98c6858062dd07dde4160af95 (patch)
tree3dc134e83c874d5c7f7bf739f13a88ab986ddb1b /addons/mail/static/src/models/thread_view/thread_view.js
parenta5ab687be4e7890262ce9429e18dd011021513d5 (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.js200
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',
}),