diff options
Diffstat (limited to 'addons/mail/static/src/models/thread_cache/thread_cache.js')
| -rw-r--r-- | addons/mail/static/src/models/thread_cache/thread_cache.js | 211 |
1 files changed, 114 insertions, 97 deletions
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 e6147fd68a0..d909fb88984 100644 --- a/addons/mail/static/src/models/thread_cache/thread_cache.js +++ b/addons/mail/static/src/models/thread_cache/thread_cache.js @@ -2,9 +2,7 @@ odoo.define('mail/static/src/models/thread_cache/thread_cache.js', function (req 'use strict'; const { registerNewModel } = require('mail/static/src/model/model_core.js'); -const { attr, many2many, many2one } = require('mail/static/src/model/model_field.js'); - -const MESSAGE_FETCH_LIMIT = 30; +const { attr, many2many, many2one, one2many } = require('mail/static/src/model/model_field.js'); function factory(dependencies) { @@ -15,79 +13,49 @@ function factory(dependencies) { //---------------------------------------------------------------------- /** - * Load this thread cache, by fetching the most recent messages in this - * conversation. + * @returns {mail.message[]|undefined} */ - async loadMessages() { - if (this.isLoaded && this.isLoading) { + async loadMoreMessages() { + if (this.isAllHistoryLoaded || this.isLoading) { return; } - const searchDomain = JSON.parse(this.stringifiedDomain); - let domain = searchDomain.length ? searchDomain : []; - domain = this._extendMessageDomain(domain); - this.update({ isLoading: true }); - let messagesData = []; - if (!this.thread.isTemporary) { - messagesData = await this.async(() => this.env.services.rpc({ - model: 'mail.message', - method: 'message_fetch', - args: [domain], - kwargs: this._getFetchMessagesKwargs(), - }, { shadow: true })); - } - this._handleMessagesLoaded(messagesData); - } - - async loadMoreMessages() { - const searchDomain = JSON.parse(this.stringifiedDomain); - let domain = searchDomain.length ? searchDomain : []; - domain = this._extendMessageDomain(domain); - if (this.isAllHistoryLoaded && this.isLoadingMore) { + if (!this.isLoaded) { + this.update({ hasToLoadMessages: true }); return; } this.update({ isLoadingMore: true }); - const minMessageId = Math.min( - ...this.fetchedMessages.map(message => message.id) - ); - domain = [['id', '<', minMessageId]].concat(domain); - const messagesData = await this.async(() => this.env.services.rpc({ - model: 'mail.message', - method: 'message_fetch', - args: [domain], - kwargs: this._getFetchMessagesKwargs(), - }, { shadow: true })); - for (const threadView of this.thread.threadViews) { + const messageIds = this.fetchedMessages.map(message => message.id); + const limit = 30; + const fetchedMessages = await this.async(() => this._loadMessages({ + extraDomain: [['id', '<', Math.min(...messageIds)]], + limit, + })); + for (const threadView of this.threadViews) { threadView.addComponentHint('more-messages-loaded'); } - this._handleMessagesLoaded(messagesData); + this.update({ isLoadingMore: false }); + if (fetchedMessages.length < limit) { + this.update({ isAllHistoryLoaded: true }); + } + return fetchedMessages; } + /** + * @returns {mail.message[]|undefined} + */ async loadNewMessages() { if (this.isLoading) { return; } if (!this.isLoaded) { - await this.async(() => this.loadMessages()); + this.update({ hasToLoadMessages: true }); return; } const messageIds = this.fetchedMessages.map(message => message.id); - const searchDomain = JSON.parse(this.stringifiedDomain); - let domain = searchDomain.length ? searchDomain : []; - domain = this._extendMessageDomain(domain); - if (messageIds.length > 0) { - const lastMessageId = Math.max(...messageIds); - domain = [['id', '>', lastMessageId]].concat(domain); - } - this.update({ isLoading: true }); - const messageFetchKwargs = this._getFetchMessagesKwargs(); - messageFetchKwargs.limit = false; - const messagesData = await this.async(() => this.env.services.rpc({ - model: 'mail.message', - method: 'message_fetch', - args: [domain], - kwargs: messageFetchKwargs, - }, { shadow: true })); - this._handleMessagesLoaded(messagesData); + return this._loadMessages({ + extraDomain: [['id', '>', Math.max(...messageIds)]], + limit: false, + }); } //---------------------------------------------------------------------- @@ -207,6 +175,20 @@ function factory(dependencies) { /** * @private + * @returns {boolean} + */ + _computeHasToLoadMessages() { + return ( + this.thread && + !this.thread.isTemporary && + this.threadViews.length > 0 && + !this.isLoaded && + !this.isLoading + ); + } + + /** + * @private * @returns {mail.message[]} */ _computeUncheckedMessages() { @@ -247,54 +229,53 @@ function factory(dependencies) { /** * @private - * @returns {Object} + * @param {Object} [param0={}] + * @param {Array[]} [param0.extraDomain] + * @param {integer} [param0.limit=30] + * @returns {mail.message[]} */ - _getFetchMessagesKwargs() { - const thread = this.thread; - let kwargs = { - limit: MESSAGE_FETCH_LIMIT, - context: this.env.session.user_context, - }; - if (thread.moderation) { - // thread is a channel - kwargs.moderated_channel_ids = [thread.id]; + async _loadMessages({ extraDomain, limit = 30 } = {}) { + this.update({ isLoading: true }); + const searchDomain = JSON.parse(this.stringifiedDomain); + let domain = searchDomain.length ? searchDomain : []; + domain = this._extendMessageDomain(domain); + if (extraDomain) { + domain = extraDomain.concat(domain); + } + const context = this.env.session.user_context; + const moderated_channel_ids = this.thread.moderation + ? [this.thread.id] + : undefined; + const messages = await this.async(() => + this.env.models['mail.message'].performRpcMessageFetch( + domain, + limit, + moderated_channel_ids, + context, + ) + ); + this.update({ + fetchedMessages: [['link', messages]], + isLoaded: true, + isLoading: false, + }); + if (!extraDomain && messages.length < limit) { + this.update({ isAllHistoryLoaded: true }); } - return kwargs; + return messages; } /** + * Loads this thread cache, by fetching the most recent messages in this + * conversation. + * * @private - * @param {Object[]} messageData */ - _handleMessagesLoaded(messagesData) { - const messages = this.env.models['mail.message'].insert(messagesData.map( - messageData => this.env.models['mail.message'].convertData(messageData) - )); - - if (!this.thread) { + _onHasToLoadMessagesChanged() { + if (!this.hasToLoadMessages) { return; } - this.thread.update({ - messageSeenIndicators: [[ - 'insert', - messagesData.map(messageData => { - return { - id: this.env.models['mail.message_seen_indicator'].computeId(messageData.id, this.thread.id), - message: [['insert', { id: messageData.id }]], - }; - }) - ]], - }); - this.update({ - fetchedMessages: [['link', messages]], - isAllHistoryLoaded: messagesData.length < MESSAGE_FETCH_LIMIT, - isLoaded: true, - isLoading: false, - isLoadingMore: false, - }); - for (const threadView of this.thread.threadViews) { - threadView.handleThreadCacheLoaded(this); - } + this._loadMessages(); } } @@ -329,6 +310,19 @@ function factory(dependencies) { compute: '_computeFetchedMessages', dependencies: ['threadMessages'], }), + /** + * Determines whether `this` should load initial messages. + */ + hasToLoadMessages: attr({ + compute: '_computeHasToLoadMessages', + dependencies: [ + 'isLoaded', + 'isLoading', + 'thread', + 'threadIsTemporary', + 'threadViews', + ], + }), isAllHistoryLoaded: attr({ default: false, }), @@ -370,6 +364,17 @@ function factory(dependencies) { ], }), /** + * Loads initial messages from `this`. + * This is not a "real" field, its compute function is used to trigger + * the load of messages at the right time. + */ + onHasToLoadMessagesChanged: attr({ + compute: '_onHasToLoadMessagesChanged', + dependencies: [ + 'hasToLoadMessages', + ], + }), + /** * Ordered list of messages that have been fetched by this cache. * * This DOES NOT necessarily includes all messages linked to this thread @@ -393,9 +398,21 @@ function factory(dependencies) { thread: many2one('mail.thread', { inverse: 'caches', }), + /** + * Serves as compute dependency. + */ + threadIsTemporary: attr({ + related: 'thread.isTemporary', + }), threadMessages: many2many('mail.message', { related: 'thread.messages', }), + /** + * States the 'mail.thread_view' that are currently displaying `this`. + */ + threadViews: one2many('mail.thread_view', { + inverse: 'threadCache', + }), uncheckedMessages: many2many('mail.message', { compute: '_computeUncheckedMessages', dependencies: [ |
