[IMP] mail, *: introduce Mailbox model for mail.box threads

This commit will simplify the code of Thread by properly splitting all
behaviors exclusive to mail.box threads.

* = test_mail_full

closes odoo/odoo#97996

Related: odoo/enterprise#30402
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Louis Wicket (wil)
2022-08-12 17:06:08 +02:00
parent 1a3517a572
commit 090c558452
35 changed files with 377 additions and 320 deletions
@@ -9,7 +9,7 @@ patchRecordMethods('ComposerView', {
* @override
*/
_computeDropZoneView() {
if (this.composer.thread && this.composer.thread.channel && this.composer.thread.channel.channel_type === 'livechat') {
if (this.composer && this.composer.thread && this.composer.thread.channel && this.composer.thread.channel.channel_type === 'livechat') {
return clear();
}
return this._super();
@@ -33,7 +33,7 @@
<span class="cursor-pointer" t-on-click="composerView.onClickReplyingToMessage">
Replying to <b t-esc="composerView.threadView.replyingToMessageView.message.authorName"/>
</span>
<i t-if="composerView.threadView.thread !== messaging.inbox" class="o_Composer_cancelReply fa fa-lg fa-times-circle rounded-circle p-0 ms-1 cursor-pointer" title="Stop replying" t-on-click="composerView.onClickStopReplying"/>
<i t-if="composerView.threadView.thread !== messaging.inbox.thread" class="o_Composer_cancelReply fa fa-lg fa-times-circle rounded-circle p-0 ms-1 cursor-pointer" title="Stop replying" t-on-click="composerView.onClickStopReplying"/>
</t>
<t t-if="composerView.hasThreadName">
<span class="o_Composer_threadName">
@@ -3,7 +3,7 @@
<t t-name="mail.DiscussMobileMailboxSelection" owl="1">
<div class="o_DiscussMobileMailboxSelection d-flex" t-attf-class="{{ className }}" t-ref="root">
<t t-foreach="discussView.discuss.orderedMailboxes" t-as="mailbox" t-key="mailbox.localId">
<t t-foreach="discussView.orderedMailboxes" t-as="mailbox" t-key="mailbox.localId">
<DiscussMobileMailboxSelectionItem discussView="discussView" mailbox="mailbox"/>
</t>
</div>
@@ -18,7 +18,7 @@ export class DiscussMobileMailboxSelectionItem extends Component {
}
/**
* @returns {Thread}
* @returns {Mailbox}
*/
get mailbox() {
return this.props.mailbox;
@@ -4,7 +4,7 @@
<t t-name="mail.DiscussMobileMailboxSelectionItem" owl="1">
<button class="o_DiscussMobileMailboxSelectionItem btn btn-secondary flex-grow-1 p-2"
t-att-class="{
'active o-active shadow-none': discussView.discuss.thread === mailbox,
'active o-active shadow-none': discussView.discuss.thread === mailbox.thread,
}" t-attf-class="{{ className }}" t-on-click="() => discussView.onClickMobileMailboxSelectionItem(mailbox)" t-att-data-mailbox-local-id="mailbox.localId" type="button" t-ref="root"
>
<t t-esc="mailbox.name"/>
@@ -3,15 +3,15 @@
<t t-name="mail.DiscussSidebarMailbox" owl="1">
<button class="o_DiscussSidebarMailbox btn d-flex align-items-center py-1 px-0 border-0 rounded-0 fw-normal text-dark"
t-att-class="{
'bg-100': discussSidebarMailboxView.mailbox !== messaging.discuss.thread,
'o-active bg-200': discussSidebarMailboxView.mailbox === messaging.discuss.thread,
'bg-100': discussSidebarMailboxView.mailbox.thread !== messaging.discuss.thread,
'o-active bg-200': discussSidebarMailboxView.mailbox.thread === messaging.discuss.thread,
'o-starred-box': discussSidebarMailboxView.mailbox === messaging.starred,
}" t-attf-class="{{ className }}" t-on-click="discussSidebarMailboxView.mailbox.onClick" t-att-data-thread-local-id="discussSidebarMailboxView.mailbox.localId" t-att-data-thread-name="discussSidebarMailboxView.mailbox.displayName"
}" t-attf-class="{{ className }}" t-on-click="discussSidebarMailboxView.mailbox.thread.onClick" t-att-data-mailbox-local-id="discussSidebarMailboxView.mailbox.localId" t-att-data-mailbox-name="discussSidebarMailboxView.mailbox.name"
t-ref="root"
>
<ThreadIcon className="'o_DiscussSidebarMailbox_item ms-4 me-2'" thread="discussSidebarMailboxView.mailbox"/>
<ThreadIcon className="'o_DiscussSidebarMailbox_item ms-4 me-2'" thread="discussSidebarMailboxView.mailbox.thread"/>
<div class="o_DiscussSidebarMailbox_item o_DiscussSidebarMailbox_name me-2 text-truncate">
<t t-esc="discussSidebarMailboxView.mailbox.displayName"/>
<t t-esc="discussSidebarMailboxView.mailbox.name"/>
</div>
<div t-attf-class="o_DiscussSidebarMailbox_item flex-grow-1 {{ discussSidebarMailboxView.mailbox.counter === 0 ? 'me-3': '' }}"/>
<t t-if="discussSidebarMailboxView.mailbox.counter > 0">
@@ -7,19 +7,19 @@
<!-- No result messages -->
<t t-if="messageListView.threadViewOwner.threadCache.orderedNonEmptyMessages.length === 0">
<div class="o_MessageList_empty o_MessageList_item d-flex flex-grow-1 flex-column align-items-center justify-content-center align-self-center w-100 h-100 p-4 text-center text-muted fst-italic">
<t t-if="messageListView.threadViewOwner.thread === messaging.inbox">
<t t-if="messageListView.threadViewOwner.thread === messaging.inbox.thread">
<h4 class="o_MessageList_emptyTitle mb-3 fw-bolder">
Congratulations, your inbox is empty
</h4>
New messages appear here.
</t>
<t t-elif="messageListView.threadViewOwner.thread === messaging.starred">
<t t-elif="messageListView.threadViewOwner.thread === messaging.starred.thread">
<h4 class="o_MessageList_emptyTitle mb-3 fw-bolder">
No starred messages
</h4>
You can mark any message as 'starred', and it shows up in this mailbox.
</t>
<t t-elif="messageListView.threadViewOwner.thread === messaging.history">
<t t-elif="messageListView.threadViewOwner.thread === messaging.history.thread">
<img src="/web/static/img/neutral_face.svg" alt="History"/>
<h4 class="o_MessageList_emptyTitle mb-3 fw-bolder">
No history messages
@@ -45,7 +45,7 @@
<t t-if="!messageListView.threadViewOwner.threadCache.hasLoadingFailed and messageListView.threadViewOwner.order === 'asc'">
<t t-call="mail.MessageList.loadMore"/>
</t>
<div t-if="messageListView.threadViewOwner.order === 'asc' and messageListView.threadViewOwner.threadCache.orderedNonEmptyMessages.length !== 0 and !(messageListView.threadViewOwner.thread and messageListView.threadViewOwner.thread.model === 'mail.box')" class="flex-grow-1"/>
<div t-if="messageListView.threadViewOwner.order === 'asc' and messageListView.threadViewOwner.threadCache.orderedNonEmptyMessages.length !== 0 and !(messageListView.threadViewOwner.thread and messageListView.threadViewOwner.thread.mailbox)" class="flex-grow-1"/>
<!-- MESSAGES -->
<t t-set="current_day" t-value="0"/>
<t t-foreach="messageListView.messageListViewMessageViewItems" t-as="messageListViewMessageViewItem" t-key="messageListViewMessageViewItem.localId">
@@ -42,14 +42,14 @@
<t t-elif="thread.channel and thread.channel.channel_type === 'group'">
<div class="o_ThreadIcon fa fa-fw fa-users" title="Grouped Chat"/>
</t>
<t t-elif="thread.model === 'mail.box'">
<t t-if="thread === messaging.inbox">
<t t-elif="thread.mailbox">
<t t-if="thread.mailbox === messaging.inbox">
<div class="o_ThreadIcon_mailboxInbox fa fa-fw fa-inbox"/>
</t>
<t t-elif="thread === messaging.starred">
<t t-elif="thread.mailbox === messaging.starred">
<div class="o_ThreadIcon_mailboxStarred fa fa-fw fa-star-o"/>
</t>
<t t-elif="thread === messaging.history">
<t t-elif="thread.mailbox === messaging.history">
<div class="o_ThreadIcon_mailboxHistory fa fa-fw fa-history"/>
</t>
</t>
@@ -43,10 +43,10 @@
</t>
</div>
<div class="o_ThreadViewTopbar_actions d-flex align-items-center ms-1">
<t t-if="threadViewTopbar.thread and threadViewTopbar.thread === messaging.inbox">
<t t-if="threadViewTopbar.thread and threadViewTopbar.thread === messaging.inbox.thread">
<button class="o_ThreadViewTopbar_markAllReadButton btn btn-secondary" t-att-disabled="threadViewTopbar.threadView.messages.length === 0" t-on-click="threadViewTopbar.onClickInboxMarkAllAsRead">Mark all read</button>
</t>
<t t-if="threadViewTopbar.thread and threadViewTopbar.thread === messaging.starred">
<t t-if="threadViewTopbar.thread and threadViewTopbar.thread === messaging.starred.thread">
<button class="o_ThreadViewTopbar_unstarAllButton btn btn-secondary" t-att-disabled="threadViewTopbar.threadView.messages.length === 0" t-on-click="threadViewTopbar.onClickUnstarAll">Unstar all</button>
</t>
<t t-if="threadViewTopbar.thread and threadViewTopbar.thread.hasCallFeature and threadViewTopbar.thread.rtcSessions.length === 0">
@@ -54,7 +54,7 @@ registerModel({
}
if (this.threadView && this.threadView.replyingToMessageView) {
const { threadView } = this;
if (this.threadView.thread === this.messaging.inbox) {
if (this.threadView.thread === this.messaging.inbox.thread) {
this.delete();
}
threadView.update({ replyingToMessageView: clear() });
@@ -585,7 +585,7 @@ registerModel({
params.context = { mail_post_autofollow: this.composer.activeThread.hasWriteAccess };
}
}
if (this.threadView && this.threadView.replyingToMessageView && this.threadView.thread !== this.messaging.inbox) {
if (this.threadView && this.threadView.replyingToMessageView && this.threadView.thread !== this.messaging.inbox.thread) {
postData.parent_id = this.threadView.replyingToMessageView.message.id;
}
const { threadView = {} } = this;
@@ -621,7 +621,7 @@ registerModel({
}
}
if (threadViewThread) {
if (threadViewThread === messaging.inbox) {
if (threadViewThread === messaging.inbox.thread) {
messaging.notify({
message: sprintf(messaging.env._t(`Message posted on "%s"`), message.originThread.displayName),
type: 'info',
@@ -794,7 +794,7 @@ registerModel({
return clear();
}
if (this.threadView.threadViewer.discuss) {
return this.threadView.threadViewer.discuss.thread === this.messaging.inbox;
return this.threadView.threadViewer.discuss.thread === this.messaging.inbox.thread;
}
return clear();
},
@@ -1019,7 +1019,7 @@ registerModel({
this.messaging.device.isSmall ||
(
this.messaging.discuss.threadView === this.threadView &&
this.messaging.discuss.thread === this.messaging.inbox
this.messaging.discuss.thread === this.messaging.inbox.thread
)
) {
return ['ctrl-enter', 'meta-enter'];
+12 -37
View File
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr, many, one } from '@mail/model/model_field';
import { attr, one } from '@mail/model/model_field';
import { clear, insertAndReplace, replace } from '@mail/model/model_field_command';
import { escape, sprintf } from '@web/core/utils/strings';
@@ -236,7 +236,7 @@ registerModel({
this.messaging.device.isSmall &&
(
this.activeMobileNavbarTabId !== 'mailbox' ||
this.thread.model !== 'mail.box'
!this.thread.mailbox
)
) {
return false;
@@ -285,44 +285,22 @@ registerModel({
return (this.messaging.device.isSmall && this.activeMobileNavbarTabId !== 'mailbox') ? insertAndReplace() : clear();
},
/**
* @private
* @returns {FieldCommand}
*/
_computeOrderedMailboxes() {
if (!this.messaging) {
return clear();
}
const orderedMailboxes = this.messaging.models['Thread']
.all(thread => thread.isPinned && thread.model === 'mail.box')
.sort((mailbox1, mailbox2) => {
if (mailbox1 === this.messaging.inbox) {
return -1;
}
if (mailbox2 === this.messaging.inbox) {
return 1;
}
if (mailbox1 === this.messaging.starred) {
return -1;
}
if (mailbox2 === this.messaging.starred) {
return 1;
}
const mailbox1Name = mailbox1.displayName;
const mailbox2Name = mailbox2.displayName;
return mailbox1Name < mailbox2Name ? -1 : 1;
});
return replace(orderedMailboxes);
},
/**
* Only pinned threads are allowed in discuss.
* Only mailboxes and pinned channels are allowed in Discuss.
*
* @private
* @returns {Thread|undefined}
* @returns {FieldCommand|undefined}
*/
_computeThread() {
if (!this.thread || !this.thread.isPinned) {
if (!this.thread) {
return clear();
}
if (this.thread.channel && this.thread.isPinned) {
return undefined;
}
if (this.thread.mailbox) {
return undefined;
}
return clear();
},
/**
* @private
@@ -442,9 +420,6 @@ registerModel({
inverse: 'discuss',
isCausal: true,
}),
orderedMailboxes: many('Thread', {
compute: '_computeOrderedMailboxes',
}),
/**
* Quick search input value in the discuss sidebar (desktop). Useful
* to filter channels and chats based on this input content.
@@ -10,7 +10,7 @@ registerModel({
recordMethods: {
/**
* @private
* @returns {Thread}
* @returns {Mailbox}
*/
_computeMailbox() {
if (this.discussViewOwnerAsHistory) {
@@ -38,7 +38,7 @@ registerModel({
inverse: 'starredView',
readonly: true,
}),
mailbox: one('Thread', {
mailbox: one('Mailbox', {
compute: '_computeMailbox',
readonly: true,
required: true,
+16 -3
View File
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr, one } from '@mail/model/model_field';
import { attr, many, one } from '@mail/model/model_field';
import { clear, insertAndReplace } from '@mail/model/model_field_command';
import { OnChange } from '@mail/model/model_onchange';
@@ -58,13 +58,13 @@ registerModel({
/**
* Called when clicking on a mailbox selection item.
*
* @param {Thread} mailbox
* @param {Mailbox} mailbox
*/
onClickMobileMailboxSelectionItem(mailbox) {
if (!mailbox.exists()) {
return;
}
mailbox.open();
mailbox.thread.open();
},
/**
* @param {Event} ev
@@ -119,6 +119,15 @@ registerModel({
active_id: this.discuss.activeId,
});
},
/**
* @private
* @returns {Array[]}
*/
_sortMailboxes() {
return [
['smaller-first', 'sequence'],
];
},
},
fields: {
/**
@@ -146,6 +155,10 @@ registerModel({
inverse: 'discussViewOwnerAsMobileAddItemHeader',
isCausal: true,
}),
orderedMailboxes: many('Mailbox', {
related: 'messaging.allMailboxes',
sort: '_sortMailboxes',
}),
/**
* Reference of the quick search input. Useful to filter channels and
* chats based on this input content.
@@ -76,7 +76,7 @@ registerModel({
if (this.chatterOwner) {
return replace(this.chatterOwner.thread);
}
if (this.composerView) {
if (this.composerView && this.composerView.composer) {
return replace(this.composerView.composer.activeThread);
}
return clear();
+153
View File
@@ -0,0 +1,153 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr, one } from '@mail/model/model_field';
import { clear, insertAndReplace, replace } from '@mail/model/model_field_command';
import { OnChange } from '@mail/model/model_onchange';
registerModel({
name: 'Mailbox',
identifyingFields: [['messagingAsHistory', 'messagingAsInbox', 'messagingAsStarred']],
recordMethods: {
/**
* @returns {string|FieldCommand}
*/
_computeFetchMessagesUrl() {
switch (this) {
case this.messaging.history:
return '/mail/history/messages';
case this.messaging.inbox:
return '/mail/inbox/messages';
case this.messaging.starred:
return '/mail/starred/messages';
default:
return clear();
}
},
/**
* @returns {FieldCommand}
*/
_computeMessagingAsAnyMailbox() {
if (!this.messaging) {
return clear();
}
return replace(this.messaging);
},
/**
* @returns {string|FieldCommand}
*/
_computeName() {
switch (this) {
case this.messaging.history:
return this.env._t("History");
case this.messaging.inbox:
return this.env._t("Inbox");
case this.messaging.starred:
return this.env._t("Starred");
default:
return clear();
}
},
/**
* @returns {integer|FieldCommand}
*/
_computeSequence() {
switch (this) {
case this.messaging.history:
return 2;
case this.messaging.inbox:
return 0;
case this.messaging.starred:
return 1;
default:
return clear();
}
},
/**
* @returns {FieldCommand}
*/
_computeThread() {
const threadId = (() => {
switch (this) {
case this.messaging.history:
return 'history';
case this.messaging.inbox:
return 'inbox';
case this.messaging.starred:
return 'starred';
}
})();
if (!threadId) {
return clear();
}
return insertAndReplace({
id: threadId,
model: 'mail.box',
});
},
_onChangeCounter() {
if (this !== this.messaging.inbox) {
return;
}
if (
this.thread.threadViews.length > 0 &&
this.previousValueOfInboxCounter > 0 && this.counter === 0
) {
this.env.services.effect.add({
message: this.env._t("Congratulations, your inbox is empty!"),
type: 'rainbow_man',
});
}
this.update({ previousValueOfInboxCounter: this.counter });
},
},
fields: {
counter: attr({
default: 0,
}),
fetchMessagesUrl: attr({
compute: '_computeFetchMessagesUrl',
}),
/**
* Useful to fill its inverse `Messaging/allMailboxes`.
*/
messagingAsAnyMailbox: one('Messaging', {
compute: '_computeMessagingAsAnyMailbox',
inverse: 'allMailboxes',
}),
messagingAsHistory: one('Messaging', {
inverse: 'history',
readonly: true,
}),
messagingAsInbox: one('Messaging', {
inverse: 'inbox',
readonly: true,
}),
messagingAsStarred: one('Messaging', {
inverse: 'starred',
readonly: true,
}),
name: attr({
compute: '_computeName',
}),
/**
* Useful to display rainbow man on inbox.
*/
previousValueOfInboxCounter: attr({
default: 0,
}),
sequence: attr({
compute: '_computeSequence',
}),
thread: one('Thread', {
compute: '_computeThread',
inverse: 'mailbox',
}),
},
onChanges: [
new OnChange({
dependencies: ['counter'],
methodName: '_onChangeCounter',
}),
],
});
+3 -3
View File
@@ -602,13 +602,13 @@ registerModel({
_computeThreads() {
const threads = [];
if (this.isHistory && this.messaging.history) {
threads.push(this.messaging.history);
threads.push(this.messaging.history.thread);
}
if (this.isNeedaction && this.messaging.inbox) {
threads.push(this.messaging.inbox);
threads.push(this.messaging.inbox.thread);
}
if (this.isStarred && this.messaging.starred) {
threads.push(this.messaging.starred);
threads.push(this.messaging.starred.thread);
}
if (this.originThread) {
threads.push(this.originThread);
@@ -123,7 +123,7 @@ registerModel({
return Boolean(
this.messaging && this.messaging.inbox &&
this.messageView && this.messageView.messageListViewMessageViewItemOwner && this.messageView.messageListViewMessageViewItemOwner.messageListViewOwner.threadViewOwner.thread &&
this.messageView.messageListViewMessageViewItemOwner.messageListViewOwner.threadViewOwner.thread === this.messaging.inbox
this.messageView.messageListViewMessageViewItemOwner.messageListViewOwner.threadViewOwner.thread === this.messaging.inbox.thread
);
},
/**
@@ -135,8 +135,8 @@ registerModel({
this.messaging && this.messaging.inbox &&
this.message && !this.message.isTemporary && !this.message.isTransient &&
this.messageView && this.messageView.messageListViewMessageViewItemOwner && this.messageView.messageListViewMessageViewItemOwner.messageListViewOwner.threadViewOwner.thread && (
this.messageView.messageListViewMessageViewItemOwner.messageListViewOwner.threadViewOwner.thread === this.messaging.inbox ||
this.messageView.messageListViewMessageViewItemOwner.messageListViewOwner.threadViewOwner.thread.model === 'mail.channel'
this.messageView.messageListViewMessageViewItemOwner.messageListViewOwner.threadViewOwner.thread === this.messaging.inbox.thread ||
this.messageView.messageListViewMessageViewItemOwner.messageListViewOwner.threadViewOwner.thread.channel
)
);
},
+18 -13
View File
@@ -322,6 +322,9 @@ registerModel({
},
},
fields: {
allMailboxes: many('Mailbox', {
inverse: 'messagingAsAnyMailbox',
}),
/**
* Inverse of the messaging field present on all models. This field
* therefore contains all existing records.
@@ -383,14 +386,16 @@ registerModel({
fetchImStatusTimerDuration: attr({
default: 50 * 1000,
}),
/**
* Mailbox History.
*/
history: one('Thread'),
/**
* Mailbox Inbox.
*/
inbox: one('Thread'),
history: one('Mailbox', {
default: insertAndReplace(),
inverse: 'messagingAsHistory',
isCausal: true,
}),
inbox: one('Mailbox', {
default: insertAndReplace(),
inverse: 'messagingAsInbox',
isCausal: true,
}),
/**
* Promise that will be resolved when messaging is initialized.
*/
@@ -447,7 +452,6 @@ registerModel({
messagingMenu: one('MessagingMenu', {
default: insertAndReplace(),
isCausal: true,
readonly: true,
}),
notificationHandler: one('MessagingNotificationHandler', {
compute: '_computeNotificationHandler',
@@ -489,10 +493,11 @@ registerModel({
isCausal: true,
readonly: true,
}),
/**
* Mailbox Starred.
*/
starred: one('Thread'),
starred: one('Mailbox', {
default: insertAndReplace(),
inverse: 'messagingAsStarred',
isCausal: true,
}),
userNotificationManager: one('UserNotificationManager', {
default: insertAndReplace(),
isCausal: true,
@@ -2,7 +2,7 @@
import { registerModel } from '@mail/model/model_core';
import { executeGracefully } from '@mail/utils/utils';
import { link, insert, insertAndReplace, replace } from '@mail/model/model_field_command';
import { link, insert, replace } from '@mail/model/model_field_command';
registerModel({
name: 'MessagingInitializer',
@@ -21,26 +21,6 @@ registerModel({
* the current user. This includes pinned channels for instance.
*/
async start() {
this.messaging.update({
history: insertAndReplace({
id: 'history',
isServerPinned: true,
model: 'mail.box',
name: this.env._t("History"),
}),
inbox: insertAndReplace({
id: 'inbox',
isServerPinned: true,
model: 'mail.box',
name: this.env._t("Inbox"),
}),
starred: insertAndReplace({
id: 'starred',
isServerPinned: true,
model: 'mail.box',
name: this.env._t("Starred"),
}),
});
this.messaging.device.start();
const discuss = this.messaging.discuss;
const data = await this.performInitRpc();
@@ -100,7 +100,7 @@ registerModel({
this.messaging.refreshIsNotificationPermissionDefault();
if (this.isOpen) {
// populate some needaction messages on threads.
this.messaging.inbox.cache.update({ isCacheRefreshRequested: true });
this.messaging.inbox.thread.cache.update({ isCacheRefreshRequested: true });
}
},
/**
@@ -514,11 +514,11 @@ registerModel({
// kept for compatibility in stable
inbox.update({ counter: decrement(message_ids.length) });
}
if (inbox.counter > inbox.cache.fetchedMessages.length) {
if (inbox.counter > inbox.thread.cache.fetchedMessages.length) {
// Force refresh Inbox because depending on what was marked as
// read the cache might become empty even though there are more
// messages on the server.
inbox.cache.update({ hasToLoadMessages: true });
inbox.thread.cache.update({ hasToLoadMessages: true });
}
},
/**
@@ -19,9 +19,9 @@ registerModel({
this.discuss.update({ activeMobileNavbarTabId: tabId });
if (
this.discuss.activeMobileNavbarTabId === 'mailbox' &&
(!this.discuss.thread || this.discuss.thread.model !== 'mailbox')
(!this.discuss.thread || !this.discuss.thread.mailbox)
) {
this.discuss.update({ thread: replace(this.messaging.inbox) });
this.discuss.update({ thread: replace(this.messaging.inbox.thread) });
}
if (this.discuss.activeMobileNavbarTabId !== 'mailbox') {
this.discuss.update({ thread: clear() });
@@ -32,28 +32,6 @@ registerModel({
*/
_computeFilteredThreads() {
switch (this.filter) {
case 'mailbox': {
return replace(this.messaging.models['Thread']
.all(thread => thread.isPinned && thread.model === 'mail.box')
.sort((mailbox1, mailbox2) => {
if (mailbox1 === this.messaging.inbox) {
return -1;
}
if (mailbox2 === this.messaging.inbox) {
return 1;
}
if (mailbox1 === this.messaging.starred) {
return -1;
}
if (mailbox2 === this.messaging.starred) {
return 1;
}
const mailbox1Name = mailbox1.displayName;
const mailbox2Name = mailbox2.displayName;
mailbox1Name < mailbox2Name ? -1 : 1;
})
);
}
case 'channel': {
return replace(this.messaging.models['Thread']
.all(thread =>
@@ -132,7 +110,7 @@ registerModel({
}
return insertAndReplace(
this.messaging.models['Thread']
.all(t => t.model !== 'mail.box' && t.needactionMessagesAsOriginThread.length > 0)
.all(t => !t.mailbox && t.needactionMessagesAsOriginThread.length > 0)
.sort((t1, t2) => {
if (t1.needactionMessagesAsOriginThread.length > 0 && t2.needactionMessagesAsOriginThread.length === 0) {
return -1;
+15 -42
View File
@@ -815,7 +815,7 @@ registerModel({
async open({ expanded = false, focus } = {}) {
const discuss = this.messaging.discuss;
// check if thread must be opened in form view
if (!['mail.box', 'mail.channel'].includes(this.model)) {
if (!this.channel && !this.mailbox) {
if (expanded || discuss.discussView) {
// Close chat window because having the same thread opened
// both in chat window and as main document does not look
@@ -831,7 +831,7 @@ registerModel({
// check if thread must be opened in discuss
if (
(!this.messaging.device.isSmall && (discuss.discussView || expanded)) ||
this.model === 'mail.box'
this.mailbox
) {
return discuss.openThread(this, {
focus: focus !== undefined ? focus : !this.messaging.device.isMobileDevice,
@@ -1061,7 +1061,7 @@ registerModel({
* @returns {FieldCommand}
*/
_computeComposer() {
if (this.model === 'mail.box') {
if (this.mailbox) {
return clear();
}
return insertAndReplace();
@@ -1138,6 +1138,9 @@ registerModel({
const guestNames = this.guestMembers.map(guest => guest.name);
return [...partnerNames, ...guestNames].join(this.env._t(", "));
}
if (this.mailbox) {
return this.mailbox.name;
}
return this.name;
},
/**
@@ -1145,12 +1148,12 @@ registerModel({
* @returns {Object}
*/
_computeFetchMessagesParams() {
if (this.model === 'mail.box') {
return {};
}
if (this.model === 'mail.channel') {
return { 'channel_id': this.id };
}
if (this.mailbox) {
return {};
}
return {
'thread_id': this.id,
'thread_model': this.model,
@@ -1161,17 +1164,12 @@ registerModel({
* @returns {string}
*/
_computeFetchMessagesUrl() {
switch (this) {
case this.messaging.inbox:
return '/mail/inbox/messages';
case this.messaging.history:
return '/mail/history/messages';
case this.messaging.starred:
return '/mail/starred/messages';
}
if (this.model === 'mail.channel') {
return `/mail/channel/messages`;
}
if (this.mailbox) {
return this.mailbox.fetchMessagesUrl;
}
return `/mail/thread/messages`;
},
/**
@@ -1636,23 +1634,6 @@ registerModel({
forceNotifyNextCurrentPartnerTypingStatus: false,
});
},
/**
* @private
*/
_onChangeCounter() {
if (this === this.messaging.inbox) {
if (
this.threadViews.length > 0 &&
this.lastCounter > 0 && this.counter === 0
) {
this.env.services.effect.add({
message: this.env._t("Congratulations, your inbox is empty!"),
type: 'rainbow_man',
});
}
this.update({ lastCounter: this.counter });
}
},
/**
* @private
*/
@@ -1813,9 +1794,6 @@ registerModel({
compute: '_computeCorrespondentOfDmChat',
inverse: 'dmChatWithCurrentPartner',
}),
counter: attr({
default: 0,
}),
creator: one('User'),
/**
* Timer of current partner that was currently typing something, but
@@ -2093,10 +2071,6 @@ registerModel({
compute: '_computeLastSeenByCurrentPartnerMessageId',
default: 0,
}),
/**
* Useful to display rainbow man on inbox.
*/
lastCounter: attr(),
/**
* Local value of message unread counter, that means it is based on initial server value and
* updated with interface updates.
@@ -2104,6 +2078,9 @@ registerModel({
localMessageUnreadCounter: attr({
compute: '_computeLocalMessageUnreadCounter',
}),
mailbox: one('Mailbox', {
inverse: 'thread',
}),
mainAttachment: one('Attachment'),
/**
* States the number of members in this thread according to the server.
@@ -2408,10 +2385,6 @@ registerModel({
dependencies: ['lastSeenByCurrentPartnerMessageId'],
methodName: '_onChangeLastSeenByCurrentPartnerMessageId',
}),
new OnChange({
dependencies: ['counter'],
methodName: '_onChangeCounter',
}),
new OnChange({
dependencies: ['isServerPinned'],
methodName: '_onIsServerPinnedChanged',
+3 -3
View File
@@ -107,7 +107,7 @@ registerModel({
* @returns {FieldCommand}
*/
_computeComposerView() {
if (!this.thread || this.thread.model === 'mail.box') {
if (!this.thread || this.thread.mailbox) {
return clear();
}
if (this.threadViewer && this.threadViewer.chatter) {
@@ -121,7 +121,7 @@ registerModel({
*/
_computeHasComposerThreadName() {
if (this.threadViewer.discuss) {
return this.threadViewer.discuss.thread === this.messaging.inbox;
return this.threadViewer.discuss.thread === this.messaging.inbox.thread;
}
return clear();
},
@@ -140,7 +140,7 @@ registerModel({
* @returns {boolean}
*/
_computeHasSquashCloseMessages() {
return Boolean(this.threadViewer && !this.threadViewer.chatter && this.thread && this.thread.model !== 'mail.box');
return Boolean(this.threadViewer && !this.threadViewer.chatter && this.thread && !this.thread.mailbox);
},
/**
* @private
@@ -34,7 +34,7 @@ QUnit.test('select another mailbox', async function (assert) {
);
assert.strictEqual(
document.querySelector('.o_Discuss_thread').dataset.threadLocalId,
messaging.inbox.localId,
messaging.inbox.thread.localId,
"inbox mailbox should be opened initially"
);
assert.containsOnce(
@@ -55,7 +55,7 @@ QUnit.test('select another mailbox', async function (assert) {
);
assert.strictEqual(
document.querySelector('.o_Discuss_thread').dataset.threadLocalId,
messaging.starred.localId,
messaging.starred.thread.localId,
"starred mailbox should be opened after clicking on it"
);
});
@@ -35,7 +35,7 @@ QUnit.test('reply: discard on pressing escape', async function (assert) {
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click, insertText, openDiscuss } = await start();
const { afterEvent, click, insertText, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -43,8 +43,7 @@ QUnit.test('reply: discard on pressing escape', async function (assert) {
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -134,7 +133,7 @@ QUnit.test('reply: discard on discard button click', async function (assert) {
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click, openDiscuss } = await start();
const { afterEvent, click, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -142,8 +141,7 @@ QUnit.test('reply: discard on discard button click', async function (assert) {
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -192,7 +190,7 @@ QUnit.test('reply: discard on reply button toggle', async function (assert) {
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click, openDiscuss } = await start();
const { afterEvent, click, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -200,8 +198,7 @@ QUnit.test('reply: discard on reply button toggle', async function (assert) {
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -244,7 +241,7 @@ QUnit.test('reply: discard on click away', async function (assert) {
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click, openDiscuss } = await start();
const { afterEvent, click, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -252,8 +249,7 @@ QUnit.test('reply: discard on click away', async function (assert) {
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -325,7 +321,7 @@ QUnit.test('"reply to" composer should log note if message replied to is a note'
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click, insertText, openDiscuss } = await start({
const { afterEvent, click, insertText, messaging, openDiscuss } = await start({
async mockRPC(route, args) {
if (route === '/mail/message/post') {
assert.step('/mail/message/post');
@@ -349,8 +345,7 @@ QUnit.test('"reply to" composer should log note if message replied to is a note'
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -392,7 +387,7 @@ QUnit.test('"reply to" composer should send message if message replied to is not
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click, insertText, openDiscuss } = await start({
const { afterEvent, click, insertText, messaging, openDiscuss } = await start({
async mockRPC(route, args) {
if (route === '/mail/message/post') {
assert.step('/mail/message/post');
@@ -416,8 +411,7 @@ QUnit.test('"reply to" composer should send message if message replied to is not
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -494,7 +488,7 @@ QUnit.test('show subject of message in Inbox', async function (assert) {
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, openDiscuss } = await start();
const { afterEvent, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -502,8 +496,7 @@ QUnit.test('show subject of message in Inbox', async function (assert) {
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -541,7 +534,7 @@ QUnit.test('show subject of message in history', async function (assert) {
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, openDiscuss } = await start({
const { afterEvent, messaging, openDiscuss } = await start({
discuss: {
params: {
default_active_id: 'mail.box_history',
@@ -555,8 +548,7 @@ QUnit.test('show subject of message in history', async function (assert) {
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'history'
threadViewer.thread === messaging.history.thread
);
},
});
@@ -595,7 +587,7 @@ QUnit.test('click on (non-channel/non-partner) origin thread link should redirec
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, env, openDiscuss } = await start();
const { afterEvent, env, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -603,8 +595,7 @@ QUnit.test('click on (non-channel/non-partner) origin thread link should redirec
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -675,7 +666,7 @@ QUnit.test('subject should not be shown when subject is the same as the thread n
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, openDiscuss } = await start();
const { afterEvent, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -683,8 +674,7 @@ QUnit.test('subject should not be shown when subject is the same as the thread n
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -713,7 +703,7 @@ QUnit.test('subject should not be shown when subject is the same as the thread n
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, openDiscuss } = await start();
const { afterEvent, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -721,8 +711,7 @@ QUnit.test('subject should not be shown when subject is the same as the thread n
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -751,7 +740,7 @@ QUnit.test('subject should not be shown when subject differs from thread name on
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, openDiscuss } = await start();
const { afterEvent, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -759,8 +748,7 @@ QUnit.test('subject should not be shown when subject differs from thread name on
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -789,7 +777,7 @@ QUnit.test('subject should not be shown when subject differs from thread name on
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, openDiscuss } = await start();
const { afterEvent, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -797,8 +785,7 @@ QUnit.test('subject should not be shown when subject differs from thread name on
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -827,7 +814,7 @@ QUnit.test('subject should be shown when the thread name has an extra prefix com
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, openDiscuss } = await start();
const { afterEvent, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -835,8 +822,7 @@ QUnit.test('subject should be shown when the thread name has an extra prefix com
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -865,7 +851,7 @@ QUnit.test('subject should not be shown when subject differs from thread name on
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, openDiscuss } = await start();
const { afterEvent, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -873,8 +859,7 @@ QUnit.test('subject should not be shown when subject differs from thread name on
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -903,7 +888,7 @@ QUnit.test('subject should not be shown when subject differs from thread name on
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, openDiscuss } = await start();
const { afterEvent, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -911,8 +896,7 @@ QUnit.test('subject should not be shown when subject differs from thread name on
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -19,7 +19,7 @@ QUnit.test('sidebar: pinned channel 1: init with one pinned channel', async func
await openDiscuss();
assert.containsOnce(
document.body,
`.o_Discuss_thread[data-thread-local-id="${messaging.inbox.localId}"]`,
`.o_Discuss_thread[data-thread-local-id="${messaging.inbox.thread.localId}"]`,
"The Inbox is opened in discuss"
);
assert.containsOnce(
@@ -121,7 +121,7 @@ QUnit.test('sidebar: unpin channel from bus', async function (assert) {
assert.containsOnce(
document.body,
`.o_Discuss_thread[data-thread-local-id="${messaging.inbox.localId}"]`,
`.o_Discuss_thread[data-thread-local-id="${messaging.inbox.thread.localId}"]`,
"The Inbox is opened in discuss"
);
assert.containsOnce(
@@ -414,7 +414,7 @@ QUnit.test('channel - states: the active category item should be visble even if
'the active channel item should remain even if the category is folded'
);
await click(`.o_DiscussSidebarMailbox[data-thread-local-id="${
await click(`.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]`);
assert.containsNone(
@@ -803,7 +803,7 @@ QUnit.test('chat - states: the active category item should be visble even if the
'the active chat item should remain even if the category is folded'
);
await click(`.o_DiscussSidebarMailbox[data-thread-local-id="${
await click(`.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]`);
assert.containsNone(
@@ -163,7 +163,7 @@ QUnit.test('basic rendering: sidebar', async function (assert) {
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebar_categoryMailbox
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`).length,
@@ -173,7 +173,7 @@ QUnit.test('basic rendering: sidebar', async function (assert) {
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebar_categoryMailbox
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
`).length,
@@ -183,7 +183,7 @@ QUnit.test('basic rendering: sidebar', async function (assert) {
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebar_categoryMailbox
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`).length,
@@ -263,7 +263,7 @@ QUnit.test('sidebar: basic mailbox rendering', async function (assert) {
await openDiscuss();
const inbox = document.querySelector(`
.o_DiscussSidebar_categoryMailbox
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`);
@@ -289,7 +289,7 @@ QUnit.test('sidebar: basic mailbox rendering', async function (assert) {
);
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -306,7 +306,7 @@ QUnit.test('sidebar: default active inbox', async function (assert) {
await openDiscuss();
const inbox = document.querySelector(`
.o_DiscussSidebar_categoryMailbox
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`);
@@ -323,7 +323,7 @@ QUnit.test('sidebar: change item', async function (assert) {
await openDiscuss();
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`).classList.contains('o-active'),
@@ -331,7 +331,7 @@ QUnit.test('sidebar: change item', async function (assert) {
);
assert.notOk(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
`).classList.contains('o-active'),
@@ -339,13 +339,13 @@ QUnit.test('sidebar: change item', async function (assert) {
);
await click(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
`);
assert.notOk(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`).classList.contains('o-active'),
@@ -353,7 +353,7 @@ QUnit.test('sidebar: change item', async function (assert) {
);
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
`).classList.contains('o-active'),
@@ -369,7 +369,7 @@ QUnit.test('sidebar: inbox with counter', async function (assert) {
await openDiscuss();
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -379,7 +379,7 @@ QUnit.test('sidebar: inbox with counter', async function (assert) {
);
assert.strictEqual(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -874,7 +874,7 @@ QUnit.test('default thread rendering', async function (assert) {
await openDiscuss();
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`).length,
@@ -883,7 +883,7 @@ QUnit.test('default thread rendering', async function (assert) {
);
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
`).length,
@@ -892,7 +892,7 @@ QUnit.test('default thread rendering', async function (assert) {
);
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`).length,
@@ -913,7 +913,7 @@ QUnit.test('default thread rendering', async function (assert) {
);
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`).classList.contains('o-active'),
@@ -934,13 +934,13 @@ QUnit.test('default thread rendering', async function (assert) {
);
await click(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
`);
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
`).classList.contains('o-active'),
@@ -961,13 +961,13 @@ QUnit.test('default thread rendering', async function (assert) {
);
await click(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`);
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`).classList.contains('o-active'),
@@ -1051,7 +1051,7 @@ QUnit.test('default select thread in discuss params', async function (assert) {
await openDiscuss();
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
`).classList.contains('o-active'),
@@ -1072,7 +1072,7 @@ QUnit.test('auto-select thread in discuss context', async function (assert) {
await openDiscuss();
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
`).classList.contains('o-active'),
@@ -1458,8 +1458,7 @@ QUnit.test('inbox messages are never squashed', async function (assert) {
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -2237,7 +2236,7 @@ QUnit.test('basic top bar rendering', async function (assert) {
);
await click(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
`);
@@ -2315,7 +2314,7 @@ QUnit.test('inbox: mark all messages as read', async function (assert) {
await openDiscuss();
assert.strictEqual(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -2350,7 +2349,7 @@ QUnit.test('inbox: mark all messages as read', async function (assert) {
await afterNextRender(() => markAllReadButton.click());
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -2401,7 +2400,7 @@ QUnit.test('starred: unstar all', async function (assert) {
await openDiscuss();
assert.strictEqual(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -2423,7 +2422,7 @@ QUnit.test('starred: unstar all', async function (assert) {
await afterNextRender(() => unstarAllButton.click());
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -2473,7 +2472,7 @@ QUnit.test('toggle_star message', async function (assert) {
await openDiscuss();
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -2502,7 +2501,7 @@ QUnit.test('toggle_star message', async function (assert) {
assert.verifySteps(['rpc:toggle_message_starred']);
assert.strictEqual(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -2525,7 +2524,7 @@ QUnit.test('toggle_star message', async function (assert) {
assert.verifySteps(['rpc:toggle_message_starred']);
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.starred.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -2859,7 +2858,7 @@ QUnit.test('rendering of inbox message', async function (assert) {
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, openDiscuss } = await start();
const { afterEvent, messaging, openDiscuss } = await start();
await afterEvent({
eventName: 'o-thread-view-hint-processed',
func: openDiscuss,
@@ -2867,8 +2866,7 @@ QUnit.test('rendering of inbox message', async function (assert) {
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'inbox'
threadViewer.thread === messaging.inbox.thread
);
},
});
@@ -3000,7 +2998,7 @@ QUnit.test('receive new needaction messages', async function (assert) {
await openDiscuss();
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`),
@@ -3008,7 +3006,7 @@ QUnit.test('receive new needaction messages', async function (assert) {
);
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`).classList.contains('o-active'),
@@ -3016,7 +3014,7 @@ QUnit.test('receive new needaction messages', async function (assert) {
);
assert.notOk(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -3041,7 +3039,7 @@ QUnit.test('receive new needaction messages', async function (assert) {
});
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -3050,7 +3048,7 @@ QUnit.test('receive new needaction messages', async function (assert) {
);
assert.strictEqual(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -3081,7 +3079,7 @@ QUnit.test('receive new needaction messages', async function (assert) {
});
assert.strictEqual(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
.o_DiscussSidebarMailbox_counter
@@ -3274,7 +3272,7 @@ QUnit.test('messages marked as read move to "History" mailbox', async function (
await openDiscuss();
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`).classList.contains('o-active'),
@@ -3287,13 +3285,13 @@ QUnit.test('messages marked as read move to "History" mailbox', async function (
);
await click(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`);
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`).classList.contains('o-active'),
@@ -3313,7 +3311,7 @@ QUnit.test('messages marked as read move to "History" mailbox', async function (
await click('.o_ThreadViewTopbar_markAllReadButton');
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`).classList.contains('o-active'),
@@ -3326,13 +3324,13 @@ QUnit.test('messages marked as read move to "History" mailbox', async function (
);
await click(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`);
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`).classList.contains('o-active'),
@@ -3388,7 +3386,7 @@ QUnit.test('mark a single message as read should only move this message to "Hist
await openDiscuss();
assert.hasClass(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`),
@@ -3402,13 +3400,13 @@ QUnit.test('mark a single message as read should only move this message to "Hist
);
await click(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`);
assert.hasClass(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.inbox.localId
}"]
`),
@@ -3446,13 +3444,13 @@ QUnit.test('mark a single message as read should only move this message to "Hist
);
await click(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`);
assert.hasClass(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`),
@@ -3497,9 +3495,7 @@ QUnit.test('all messages in "Inbox" in "History" after marked all as read', asyn
predicate: ({ orderedMessages, scrollTop, thread }) => {
const messageList = document.querySelector(`.o_Discuss_thread .o_ThreadView_messageList`);
return (
thread &&
thread.model === 'mail.box' &&
thread.id === 'inbox' &&
thread === messaging.inbox.thread &&
orderedMessages.length === 30 &&
isScrolledToBottom(messageList)
);
@@ -3517,7 +3513,7 @@ QUnit.test('all messages in "Inbox" in "History" after marked all as read', asyn
eventName: 'o-component-message-list-scrolled',
func: () => {
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-local-id="${
.o_DiscussSidebarMailbox[data-mailbox-local-id="${
messaging.history.localId
}"]
`).click();
@@ -3527,8 +3523,8 @@ QUnit.test('all messages in "Inbox" in "History" after marked all as read', asyn
const messageList = document.querySelector('.o_MessageList');
return (
thread &&
thread.model === 'mail.box' &&
thread.id === 'history' &&
thread.mailbox &&
thread.mailbox === messaging.history &&
orderedMessages.length === 30 &&
isScrolledToBottom(messageList)
);
@@ -3543,8 +3539,8 @@ QUnit.test('all messages in "Inbox" in "History" after marked all as read', asyn
predicate: ({ hint, threadViewer }) => {
return (
hint.type === 'more-messages-loaded' &&
threadViewer.thread.model === 'mail.box' &&
threadViewer.thread.id === 'history'
threadViewer.thread.mailbox &&
threadViewer.thread.mailbox === messaging.history
);
},
});
@@ -3712,14 +3708,14 @@ QUnit.test('auto-focus composer on opening thread', async function (assert) {
await openDiscuss();
assert.strictEqual(
document.querySelectorAll(`
.o_DiscussSidebarMailbox[data-thread-name="Inbox"]
.o_DiscussSidebarMailbox[data-mailbox-name="Inbox"]
`).length,
1,
"should have mailbox 'Inbox' in the sidebar"
);
assert.ok(
document.querySelector(`
.o_DiscussSidebarMailbox[data-thread-name="Inbox"]
.o_DiscussSidebarMailbox[data-mailbox-name="Inbox"]
`).classList.contains('o-active'),
"mailbox 'Inbox' should be active initially"
);
@@ -25,7 +25,7 @@ QUnit.test('mark as read', async function (assert) {
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click } = await start({
const { afterEvent, click, messaging } = await start({
async mockRPC(route, args) {
if (route.includes('mark_all_as_read')) {
assert.step('mark_all_as_read');
@@ -45,7 +45,7 @@ QUnit.test('mark as read', async function (assert) {
func: () => document.querySelector('.o_MessagingMenu_toggler').click(),
message: "should wait until inbox loaded initial needaction messages",
predicate: ({ threadCache }) => {
return threadCache.thread.model === 'mail.box' && threadCache.thread.id === 'inbox';
return threadCache.thread === messaging.inbox.thread;
},
}));
assert.containsOnce(
@@ -83,13 +83,13 @@ QUnit.test('click on preview should mark as read and open the thread', async fun
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click } = await start();
const { afterEvent, click, messaging } = await start();
await afterNextRender(() => afterEvent({
eventName: 'o-thread-cache-loaded-messages',
func: () => document.querySelector('.o_MessagingMenu_toggler').click(),
message: "should wait until inbox loaded initial needaction messages",
predicate: ({ threadCache }) => {
return threadCache.thread.model === 'mail.box' && threadCache.thread.id === 'inbox';
return threadCache.thread === messaging.inbox.thread;
},
}));
assert.containsOnce(
@@ -134,7 +134,7 @@ QUnit.test('click on expand from chat window should close the chat window and op
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click, env } = await start();
const { afterEvent, click, env, messaging } = await start();
patchWithCleanup(env.services.action, {
doAction(action) {
assert.step('do_action');
@@ -155,7 +155,7 @@ QUnit.test('click on expand from chat window should close the chat window and op
func: () => document.querySelector('.o_MessagingMenu_toggler').click(),
message: "should wait until inbox loaded initial needaction messages",
predicate: ({ threadCache }) => {
return threadCache.thread.model === 'mail.box' && threadCache.thread.id === 'inbox';
return threadCache.thread === messaging.inbox.thread;
},
}));
assert.containsOnce(
@@ -207,7 +207,7 @@ QUnit.test('[technical] opening a non-channel chat window should not call channe
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click } = await start({
const { afterEvent, click, messaging } = await start({
async mockRPC(route, args) {
if (route.includes('channel_fold')) {
const message = "should not call channel_fold when opening a non-channel chat window";
@@ -222,7 +222,7 @@ QUnit.test('[technical] opening a non-channel chat window should not call channe
func: () => document.querySelector('.o_MessagingMenu_toggler').click(),
message: "should wait until inbox loaded initial needaction messages",
predicate: ({ threadCache }) => {
return threadCache.thread.model === 'mail.box' && threadCache.thread.id === 'inbox';
return threadCache.thread === messaging.inbox.thread;
},
}));
assert.containsOnce(
@@ -271,13 +271,13 @@ QUnit.test('preview should display last needaction message preview even if there
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent } = await start();
const { afterEvent, messaging } = await start();
await afterNextRender(() => afterEvent({
eventName: 'o-thread-cache-loaded-messages',
func: () => document.querySelector('.o_MessagingMenu_toggler').click(),
message: "should wait until inbox loaded initial needaction messages",
predicate: ({ threadCache }) => {
return threadCache.thread.model === 'mail.box' && threadCache.thread.id === 'inbox';
return threadCache.thread === messaging.inbox.thread;
},
}));
assert.containsOnce(
@@ -311,13 +311,13 @@ QUnit.test('chat window header should not have unread counter for non-channel th
notification_type: 'inbox',
res_partner_id: pyEnv.currentPartnerId,
});
const { afterEvent, click } = await start();
const { afterEvent, click, messaging } = await start();
await afterNextRender(() => afterEvent({
eventName: 'o-thread-cache-loaded-messages',
func: () => document.querySelector('.o_MessagingMenu_toggler').click(),
message: "should wait until inbox loaded initial needaction messages",
predicate: ({ threadCache }) => {
return threadCache.thread.model === 'mail.box' && threadCache.thread.id === 'inbox';
return threadCache.thread === messaging.inbox.thread;
},
}));
await click('.o_ThreadNeedactionPreview');
@@ -70,9 +70,9 @@ QUnit.test('create', async function (assert) {
}))
);
// from partnerId being in needaction_partner_ids
assert.ok(message.threads.includes(messaging.inbox));
assert.ok(message.threads.includes(messaging.inbox.thread));
// from partnerId being in starred_partner_ids
assert.ok(message.threads.includes(messaging.starred));
assert.ok(message.threads.includes(messaging.starred.thread));
const attachment = messaging.models['Attachment'].findFromIdentifyingData({ id: 750 });
assert.ok(attachment);
assert.strictEqual(attachment.filename, "test.txt");
@@ -15,13 +15,13 @@ QUnit.test('inbox & starred mailboxes', async function (assert) {
const mailboxStarred = messaging.starred;
assert.ok(mailboxInbox, "should have mailbox inbox");
assert.ok(mailboxStarred, "should have mailbox starred");
assert.strictEqual(mailboxInbox.model, 'mail.box');
assert.strictEqual(mailboxInbox.thread.model, 'mail.box');
assert.strictEqual(mailboxInbox.counter, 0);
assert.strictEqual(mailboxInbox.id, 'inbox');
assert.strictEqual(mailboxInbox.thread.id, 'inbox');
assert.strictEqual(mailboxInbox.name, "Inbox"); // language-dependent
assert.strictEqual(mailboxStarred.model, 'mail.box');
assert.strictEqual(mailboxStarred.thread.model, 'mail.box');
assert.strictEqual(mailboxStarred.counter, 0);
assert.strictEqual(mailboxStarred.id, 'starred');
assert.strictEqual(mailboxStarred.thread.id, 'starred');
assert.strictEqual(mailboxStarred.name, "Starred"); // language-dependent
});
@@ -30,13 +30,13 @@ QUnit.test('rating value displayed on the thread needaction preview', async func
rating_image_url: "/rating/static/src/img/rating_5.png",
rating_text: "top",
}]);
const { afterEvent } = await start();
const { afterEvent, messaging } = await start();
await afterNextRender(() => afterEvent({
eventName: 'o-thread-cache-loaded-messages',
func: () => document.querySelector('.o_MessagingMenu_toggler').click(),
message: "should wait until inbox loaded initial needaction messages",
predicate: ({ threadCache }) => {
return threadCache.thread.model === 'mail.box' && threadCache.thread.id === 'inbox';
return threadCache.thread === messaging.inbox.thread;
},
}));
assert.strictEqual(
@@ -21,13 +21,13 @@ QUnit.test('rating value displayed on the thread preview', async function (asser
rating_image_url: "/rating/static/src/img/rating_5.png",
rating_text: "top",
});
const { afterEvent } = await start();
const { afterEvent, messaging } = await start();
await afterNextRender(() => afterEvent({
eventName: 'o-thread-cache-loaded-messages',
func: () => document.querySelector('.o_MessagingMenu_toggler').click(),
message: "should wait until inbox loaded initial needaction messages",
predicate: ({ threadCache }) => {
return threadCache.thread.model === 'mail.box' && threadCache.thread.id === 'inbox';
return threadCache.thread === messaging.inbox.thread;
},
}));
assert.strictEqual(