summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/models/thread_cache/thread_cache.js
diff options
context:
space:
mode:
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.js211
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: [