[IMP] mail, *: add view model for notification list items
* = im_livechat, sms, snailmail Part of task-2728107 closes odoo/odoo#82239 X-original-commit: fadb57564209e1b9c4ee6ee993b117b288ac614d Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com> Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { NotificationList } from '@mail/components/notification_list/notification_list';
|
||||
import { patch } from 'web.utils';
|
||||
|
||||
const components = { NotificationList };
|
||||
|
||||
components.NotificationList._allowedFilters.push('livechat');
|
||||
|
||||
patch(components.NotificationList.prototype, 'im_livechat/static/src/components/notification_list/notification_list.js', {
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Override to include livechat channels.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_getThreads(props) {
|
||||
if (props.filter === 'livechat') {
|
||||
return this.messaging.models['Thread'].all(thread =>
|
||||
thread.channel_type === 'livechat' &&
|
||||
thread.isPinned &&
|
||||
thread.model === 'mail.channel'
|
||||
);
|
||||
}
|
||||
return this._super(...arguments);
|
||||
},
|
||||
|
||||
});
|
||||
+1
-1
@@ -16,7 +16,7 @@ patch(components.ThreadNeedactionPreview.prototype, 'thread_needaction_preview',
|
||||
* @override
|
||||
*/
|
||||
image(...args) {
|
||||
if (this.thread.channel_type === 'livechat') {
|
||||
if (this.threadNeedactionPreviewView.thread.channel_type === 'livechat') {
|
||||
return '/mail/static/src/img/smiley/avatar.jpg';
|
||||
}
|
||||
return this._super(...args);
|
||||
|
||||
@@ -16,7 +16,7 @@ patch(components.ThreadPreview.prototype, 'im_livechat/static/src/components/thr
|
||||
* @override
|
||||
*/
|
||||
image(...args) {
|
||||
if (this.thread.channel_type === 'livechat') {
|
||||
if (this.threadPreviewView.thread.channel_type === 'livechat') {
|
||||
return '/mail/static/src/img/smiley/avatar.jpg';
|
||||
}
|
||||
return this._super(...args);
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { patchRecordMethods } from '@mail/model/model_core';
|
||||
import { replace } from '@mail/model/model_field_command';
|
||||
import '@mail/models/notification_list_view/notification_list_view'; // ensure the model definition is loaded before the patch
|
||||
|
||||
patchRecordMethods('NotificationListView', {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_computeFilteredThreads() {
|
||||
if (this.filter === 'livechat') {
|
||||
return replace(this.messaging.models['Thread'].all(thread =>
|
||||
thread.channel_type === 'livechat' &&
|
||||
thread.isPinned &&
|
||||
thread.model === 'mail.channel'
|
||||
));
|
||||
}
|
||||
return this._super();
|
||||
},
|
||||
});
|
||||
@@ -71,10 +71,9 @@
|
||||
New Channel
|
||||
</button>
|
||||
</t>
|
||||
<NotificationList
|
||||
className="'o_Discuss_notificationList'"
|
||||
filter="discuss.activeMobileNavbarTabId"
|
||||
/>
|
||||
</t>
|
||||
<t t-if="discuss.notificationListView">
|
||||
<NotificationList className="'o_Discuss_notificationList'" localId="discuss.notificationListView.localId"/>
|
||||
</t>
|
||||
<t t-if="discuss.mobileMessagingNavbarView">
|
||||
<MobileMessagingNavbar
|
||||
|
||||
@@ -49,11 +49,9 @@
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
<NotificationList
|
||||
className="'o_MessagingMenu_notificationList'"
|
||||
classNameObj="{ 'o-mobile': messaging.device.isMobile }"
|
||||
filter="messagingMenu.activeTabId"
|
||||
/>
|
||||
<t t-if="messagingMenu.notificationListView">
|
||||
<NotificationList className="'o_MessagingMenu_notificationList'" classNameObj="{ 'o-mobile': messaging.device.isMobile }" localId="messagingMenu.notificationListView.localId"/>
|
||||
</t>
|
||||
<t t-if="messagingMenu.mobileMessagingNavbarView">
|
||||
<MobileMessagingNavbar
|
||||
className="'o_MessagingMenu_mobileNavbar'"
|
||||
|
||||
@@ -24,17 +24,17 @@ export class NotificationGroup extends Component {
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @returns {NotificationGroup}
|
||||
* @returns {NotificationGroupView}
|
||||
*/
|
||||
get group() {
|
||||
return this.messaging && this.messaging.models['NotificationGroup'].get(this.props.notificationGroupLocalId);
|
||||
get notificationGroupView() {
|
||||
return this.messaging && this.messaging.models['NotificationGroupView'].get(this.props.localId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
image() {
|
||||
if (this.group.notification_type === 'email') {
|
||||
if (this.notificationGroupView.notificationGroup.notification_type === 'email') {
|
||||
return '/mail/static/src/img/smiley/mailfailure.jpg';
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ export class NotificationGroup extends Component {
|
||||
// handled in `_onClickMarkAsRead`
|
||||
return;
|
||||
}
|
||||
this.group.openDocuments();
|
||||
this.notificationGroupView.notificationGroup.openDocuments();
|
||||
if (!this.messaging.device.isMobile) {
|
||||
this.messaging.messagingMenu.close();
|
||||
}
|
||||
@@ -64,7 +64,7 @@ export class NotificationGroup extends Component {
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickMarkAsRead(ev) {
|
||||
this.group.openCancelAction();
|
||||
this.notificationGroupView.notificationGroup.openCancelAction();
|
||||
if (!this.messaging.device.isMobile) {
|
||||
this.messaging.messagingMenu.close();
|
||||
}
|
||||
@@ -74,7 +74,7 @@ export class NotificationGroup extends Component {
|
||||
|
||||
Object.assign(NotificationGroup, {
|
||||
props: {
|
||||
notificationGroupLocalId: String,
|
||||
localId: String,
|
||||
},
|
||||
template: 'mail.NotificationGroup',
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-name="mail.NotificationGroup" owl="1">
|
||||
<div class="o_NotificationGroup" t-attf-class="{{ className }}" t-on-click="_onClick" t-ref="root">
|
||||
<t t-if="group">
|
||||
<t t-if="notificationGroupView">
|
||||
<div class="o_NotificationGroup_sidebar">
|
||||
<div class="o_NotificationGroup_imageContainer o_NotificationGroup_sidebarItem">
|
||||
<img class="o_NotificationGroup_image rounded-circle" t-att-src="image()" alt="Message delivery failure image"/>
|
||||
@@ -12,21 +12,21 @@
|
||||
<div class="o_NotificationGroup_content">
|
||||
<div class="o_NotificationGroup_header">
|
||||
<span class="o_NotificationGroup_name text-truncate">
|
||||
<t t-esc="group.res_model_name"/>
|
||||
<t t-esc="notificationGroupView.notificationGroup.res_model_name"/>
|
||||
</span>
|
||||
<span class="o_NotificationGroup_counter">
|
||||
(<t t-esc="group.notifications.length"/>)
|
||||
(<t t-esc="notificationGroupView.notificationGroup.notifications.length"/>)
|
||||
</span>
|
||||
<span class="o-autogrow"/>
|
||||
<t t-if="group.date">
|
||||
<t t-if="notificationGroupView.notificationGroup.date">
|
||||
<span class="o_NotificationGroup_date">
|
||||
<t t-esc="group.date.fromNow()"/>
|
||||
<t t-esc="notificationGroupView.notificationGroup.date.fromNow()"/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_NotificationGroup_core">
|
||||
<span class="o_NotificationGroup_coreItem o_NotificationGroup_inlineText text-truncate">
|
||||
<t t-if="group.notification_type === 'email'">
|
||||
<t t-if="notificationGroupView.notificationGroup.notification_type === 'email'">
|
||||
An error occurred when sending an email.
|
||||
</t>
|
||||
</span>
|
||||
|
||||
@@ -19,95 +19,11 @@ export class NotificationList extends Component {
|
||||
this._loadPreviews();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @returns {Object[]}
|
||||
* @returns {NotificationListView}
|
||||
*/
|
||||
get notifications() {
|
||||
if (!this.messaging) {
|
||||
return [];
|
||||
}
|
||||
const threads = this._getThreads(this.props);
|
||||
let threadNeedactionNotifications = [];
|
||||
if (this.props.filter === 'all') {
|
||||
// threads with needactions
|
||||
threadNeedactionNotifications = this.messaging.models['Thread']
|
||||
.all(t => t.model !== 'mail.box' && t.needactionMessagesAsOriginThread.length > 0)
|
||||
.sort((t1, t2) => {
|
||||
if (t1.needactionMessagesAsOriginThread.length > 0 && t2.needactionMessagesAsOriginThread.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
if (t1.needactionMessagesAsOriginThread.length === 0 && t2.needactionMessagesAsOriginThread.length > 0) {
|
||||
return 1;
|
||||
}
|
||||
if (t1.lastNeedactionMessageAsOriginThread && t2.lastNeedactionMessageAsOriginThread) {
|
||||
return t1.lastNeedactionMessageAsOriginThread.id < t2.lastNeedactionMessageAsOriginThread.id ? 1 : -1;
|
||||
}
|
||||
if (t1.lastNeedactionMessageAsOriginThread) {
|
||||
return -1;
|
||||
}
|
||||
if (t2.lastNeedactionMessageAsOriginThread) {
|
||||
return 1;
|
||||
}
|
||||
return t1.id < t2.id ? -1 : 1;
|
||||
})
|
||||
.map(thread => {
|
||||
return {
|
||||
thread,
|
||||
type: 'thread_needaction',
|
||||
uniqueId: thread.localId + '_needaction',
|
||||
};
|
||||
});
|
||||
}
|
||||
// thread notifications
|
||||
const threadNotifications = threads
|
||||
.sort((t1, t2) => {
|
||||
if (t1.localMessageUnreadCounter > 0 && t2.localMessageUnreadCounter === 0) {
|
||||
return -1;
|
||||
}
|
||||
if (t1.localMessageUnreadCounter === 0 && t2.localMessageUnreadCounter > 0) {
|
||||
return 1;
|
||||
}
|
||||
if (t1.lastMessage && t2.lastMessage) {
|
||||
return t1.lastMessage.id < t2.lastMessage.id ? 1 : -1;
|
||||
}
|
||||
if (t1.lastMessage) {
|
||||
return -1;
|
||||
}
|
||||
if (t2.lastMessage) {
|
||||
return 1;
|
||||
}
|
||||
return t1.id < t2.id ? -1 : 1;
|
||||
})
|
||||
.map(thread => {
|
||||
return {
|
||||
thread,
|
||||
type: 'thread',
|
||||
uniqueId: thread.localId,
|
||||
};
|
||||
});
|
||||
let notifications = threadNeedactionNotifications.concat(threadNotifications);
|
||||
if (this.props.filter === 'all') {
|
||||
notifications = Object.values(this.messaging.models['NotificationGroup'].all())
|
||||
.sort((group1, group2) => group1.sequence - group2.sequence)
|
||||
.map(notificationGroup => {
|
||||
return {
|
||||
notificationGroup,
|
||||
uniqueId: notificationGroup.localId,
|
||||
};
|
||||
}).concat(notifications);
|
||||
}
|
||||
// native notification request
|
||||
if (this.props.filter === 'all' && this.messaging.isNotificationPermissionDefault) {
|
||||
notifications.unshift({
|
||||
type: 'odoobotRequest',
|
||||
uniqueId: 'odoobotRequest',
|
||||
});
|
||||
}
|
||||
return notifications;
|
||||
get notificationListView() {
|
||||
return this.messaging && this.messaging.models['NotificationListView'].get(this.props.localId);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -121,78 +37,15 @@ export class NotificationList extends Component {
|
||||
* @private
|
||||
*/
|
||||
async _loadPreviews() {
|
||||
const threads = this.notifications
|
||||
.filter(notification => notification.thread && notification.thread.exists())
|
||||
.map(notification => notification.thread);
|
||||
const threads = this.notificationListView.threadPreviewViews
|
||||
.map(threadPreviewView => threadPreviewView.thread);
|
||||
this.messaging.models['Thread'].loadPreviews(threads);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} props
|
||||
* @throws {Error} in case `props.filter` is not supported
|
||||
* @returns {Thread[]}
|
||||
*/
|
||||
_getThreads(props) {
|
||||
if (props.filter === 'mailbox') {
|
||||
return 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;
|
||||
});
|
||||
} else if (props.filter === 'channel') {
|
||||
return this.messaging.models['Thread']
|
||||
.all(thread =>
|
||||
thread.channel_type === 'channel' &&
|
||||
thread.isPinned &&
|
||||
thread.model === 'mail.channel'
|
||||
)
|
||||
.sort((c1, c2) => c1.displayName < c2.displayName ? -1 : 1);
|
||||
} else if (props.filter === 'chat') {
|
||||
return this.messaging.models['Thread']
|
||||
.all(thread =>
|
||||
thread.isChatChannel &&
|
||||
thread.isPinned &&
|
||||
thread.model === 'mail.channel'
|
||||
)
|
||||
.sort((c1, c2) => c1.displayName < c2.displayName ? -1 : 1);
|
||||
} else if (props.filter === 'all') {
|
||||
// "All" filter is for channels and chats
|
||||
return this.messaging.models['Thread']
|
||||
.all(thread => thread.isPinned && thread.model === 'mail.channel')
|
||||
.sort((c1, c2) => c1.displayName < c2.displayName ? -1 : 1);
|
||||
} else {
|
||||
throw new Error(`Unsupported filter ${props.filter}`);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign(NotificationList, {
|
||||
_allowedFilters: ['all', 'mailbox', 'channel', 'chat'],
|
||||
defaultProps: {
|
||||
filter: 'all',
|
||||
},
|
||||
props: {
|
||||
filter: {
|
||||
type: String,
|
||||
validate: prop => NotificationList._allowedFilters.includes(prop),
|
||||
},
|
||||
},
|
||||
props: { localId: String },
|
||||
template: 'mail.NotificationList',
|
||||
});
|
||||
|
||||
|
||||
@@ -2,42 +2,45 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mail.NotificationList" owl="1">
|
||||
<div class="o_NotificationList" t-att-class="{ 'o-empty': notifications.length === 0 }" t-attf-class="{{ className }}" t-ref="root">
|
||||
<t t-if="notifications.length === 0">
|
||||
<div class="o_NotificationList_noConversation">
|
||||
No conversation yet...
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-foreach="notifications" t-as="notification" t-key="notification.uniqueId">
|
||||
<t t-if="notification.type === 'thread' and notification.thread">
|
||||
<ThreadPreview
|
||||
className="'o_NotificationList_preview'"
|
||||
classNameObj="{ 'o-mobile': messaging.device.isMobile }"
|
||||
threadLocalId="notification.thread.localId"
|
||||
/>
|
||||
</t>
|
||||
<t t-if="notification.type === 'thread_needaction' and notification.thread">
|
||||
<ThreadNeedactionPreview
|
||||
className="'o_NotificationList_preview'"
|
||||
classNameObj="{ 'o-mobile': messaging.device.isMobile }"
|
||||
threadLocalId="notification.thread.localId"
|
||||
/>
|
||||
</t>
|
||||
<t t-if="notification.notificationGroup">
|
||||
<NotificationGroup
|
||||
className="'o_NotificationList_group'"
|
||||
notificationGroupLocalId="notification.notificationGroup.localId"
|
||||
/>
|
||||
</t>
|
||||
<t t-if="notification.type === 'odoobotRequest'">
|
||||
<NotificationRequest
|
||||
className="'o_NotificationList_notificationRequest'"
|
||||
t-att-class="{ 'o-mobile': messaging.device.isMobile }"
|
||||
/>
|
||||
</t>
|
||||
<t t-if="!notification_last">
|
||||
<div class="o_NotificationList_separator"/>
|
||||
<div class="o_NotificationList" t-att-class="{ 'o-empty': notificationListView and notificationListView.notificationViews.length === 0 }" t-attf-class="{{ className }}" t-ref="root">
|
||||
<t t-if="notificationListView">
|
||||
<t t-if="notificationListView.notificationViews.length === 0">
|
||||
<div class="o_NotificationList_noConversation">
|
||||
No conversation yet...
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-foreach="notificationListView.notificationViews" t-as="notificationView" t-key="notificationView.localId">
|
||||
<t t-if="notificationView.constructor.name === 'ThreadPreviewView'">
|
||||
<ThreadPreview
|
||||
className="'o_NotificationList_preview'"
|
||||
classNameObj="{ 'o-mobile': messaging.device.isMobile }"
|
||||
localId="notificationView.localId"
|
||||
/>
|
||||
</t>
|
||||
<t t-if="notificationView.constructor.name === 'ThreadNeedactionPreviewView'">
|
||||
<ThreadNeedactionPreview
|
||||
className="'o_NotificationList_preview'"
|
||||
classNameObj="{ 'o-mobile': messaging.device.isMobile }"
|
||||
localId="notificationView.localId"
|
||||
/>
|
||||
</t>
|
||||
<t t-if="notificationView.constructor.name === 'NotificationGroupView'">
|
||||
<NotificationGroup
|
||||
className="'o_NotificationList_group'"
|
||||
localId="notificationView.localId"
|
||||
/>
|
||||
</t>
|
||||
<t t-if="notificationView.constructor.name === 'NotificationRequestView'">
|
||||
<NotificationRequest
|
||||
className="'o_NotificationList_notificationRequest'"
|
||||
t-att-class="{ 'o-mobile': messaging.device.isMobile }"
|
||||
localId="notificationView.localId"
|
||||
/>
|
||||
</t>
|
||||
<t t-if="!notificationView_last">
|
||||
<div class="o_NotificationList_separator"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
+18
-33
@@ -1,12 +1,6 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
afterEach,
|
||||
afterNextRender,
|
||||
beforeEach,
|
||||
createRootMessagingComponent,
|
||||
start,
|
||||
} from '@mail/utils/test_utils';
|
||||
import { afterEach, afterNextRender, beforeEach, start, } from '@mail/utils/test_utils';
|
||||
|
||||
import Bus from 'web.Bus';
|
||||
|
||||
@@ -17,23 +11,14 @@ QUnit.module('notification_list_notification_group_tests.js', {
|
||||
beforeEach() {
|
||||
beforeEach(this);
|
||||
|
||||
/**
|
||||
* @param {Object} param0
|
||||
* @param {string} [param0.filter='all']
|
||||
*/
|
||||
this.createNotificationListComponent = async ({ filter = 'all' } = {}) => {
|
||||
await createRootMessagingComponent(this, "NotificationList", {
|
||||
props: { filter },
|
||||
target: this.widget.el,
|
||||
});
|
||||
};
|
||||
|
||||
this.start = async params => {
|
||||
const { env, widget } = await start(Object.assign({}, params, {
|
||||
const res = await start(Object.assign({}, params, {
|
||||
data: this.data,
|
||||
}));
|
||||
const { env, widget } = res;
|
||||
this.env = env;
|
||||
this.widget = widget;
|
||||
return res;
|
||||
};
|
||||
},
|
||||
afterEach() {
|
||||
@@ -58,8 +43,8 @@ QUnit.test('notification group basic layout', async function (assert) {
|
||||
notification_status: 'exception', // necessary value to have a failure
|
||||
notification_type: 'email', // expected failure type for email message
|
||||
});
|
||||
await this.start();
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start();
|
||||
await createNotificationListComponent();
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_NotificationGroup',
|
||||
@@ -148,8 +133,8 @@ QUnit.test('mark as read', async function (assert) {
|
||||
"action should have the group notification length as unread_counter"
|
||||
);
|
||||
});
|
||||
await this.start({ env: { bus } });
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start({ env: { bus } });
|
||||
await createNotificationListComponent();
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_NotificationGroup_markAsRead',
|
||||
@@ -200,8 +185,8 @@ QUnit.test('grouped notifications by document', async function (assert) {
|
||||
notification_type: 'email', // expected failure type for email message
|
||||
}
|
||||
);
|
||||
await this.start({ hasChatWindow: true });
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start({ hasChatWindow: true });
|
||||
await createNotificationListComponent();
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
@@ -312,8 +297,8 @@ QUnit.test('grouped notifications by document model', async function (assert) {
|
||||
);
|
||||
});
|
||||
|
||||
await this.start({ env: { bus } });
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start({ env: { bus } });
|
||||
await createNotificationListComponent();
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
@@ -376,10 +361,10 @@ QUnit.test('different mail.channel are not grouped', async function (assert) {
|
||||
notification_type: 'email', // expected failure type for email message
|
||||
}
|
||||
);
|
||||
await this.start({
|
||||
const { createNotificationListComponent } = await this.start({
|
||||
hasChatWindow: true, // needed to assert thread.open
|
||||
});
|
||||
await this.createNotificationListComponent();
|
||||
await createNotificationListComponent();
|
||||
assert.containsN(
|
||||
document.body,
|
||||
'.o_NotificationGroup',
|
||||
@@ -451,8 +436,8 @@ QUnit.test('multiple grouped notifications by document model, sorted by the most
|
||||
notification_type: 'email', // expected failure type for email message
|
||||
}
|
||||
);
|
||||
await this.start();
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start();
|
||||
await createNotificationListComponent();
|
||||
assert.containsN(
|
||||
document.body,
|
||||
'.o_NotificationGroup',
|
||||
@@ -522,8 +507,8 @@ QUnit.test('non-failure notifications are ignored', async function (assert) {
|
||||
notification_type: 'email', // expected notification type for email message
|
||||
},
|
||||
);
|
||||
await this.start();
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start();
|
||||
await createNotificationListComponent();
|
||||
assert.containsNone(
|
||||
document.body,
|
||||
'.o_NotificationGroup',
|
||||
|
||||
+8
-23
@@ -1,12 +1,6 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
afterEach,
|
||||
afterNextRender,
|
||||
beforeEach,
|
||||
createRootMessagingComponent,
|
||||
start,
|
||||
} from '@mail/utils/test_utils';
|
||||
import { afterEach, afterNextRender, beforeEach, start } from '@mail/utils/test_utils';
|
||||
|
||||
QUnit.module('mail', {}, function () {
|
||||
QUnit.module('components', {}, function () {
|
||||
@@ -15,23 +9,14 @@ QUnit.module('notification_list_tests.js', {
|
||||
beforeEach() {
|
||||
beforeEach(this);
|
||||
|
||||
/**
|
||||
* @param {Object} param0
|
||||
* @param {string} [param0.filter='all']
|
||||
*/
|
||||
this.createNotificationListComponent = async ({ filter = 'all' }) => {
|
||||
await createRootMessagingComponent(this, "NotificationList", {
|
||||
props: { filter },
|
||||
target: this.widget.el,
|
||||
});
|
||||
};
|
||||
|
||||
this.start = async params => {
|
||||
const { env, widget } = await start(Object.assign({}, params, {
|
||||
const res = await start(Object.assign({}, params, {
|
||||
data: this.data,
|
||||
}));
|
||||
const { env, widget } = res;
|
||||
this.env = env;
|
||||
this.widget = widget;
|
||||
return res;
|
||||
};
|
||||
},
|
||||
afterEach() {
|
||||
@@ -60,8 +45,8 @@ QUnit.test('marked as read thread notifications are ordered by last message date
|
||||
res_id: 200,
|
||||
}
|
||||
);
|
||||
await this.start();
|
||||
await this.createNotificationListComponent({ filter: 'all' });
|
||||
const { createNotificationListComponent } = await this.start();
|
||||
await createNotificationListComponent({ filter: 'all' });
|
||||
assert.containsN(
|
||||
document.body,
|
||||
'.o_ThreadPreview',
|
||||
@@ -102,8 +87,8 @@ QUnit.test('thread notifications are re-ordered on receiving a new message', asy
|
||||
res_id: 200,
|
||||
}
|
||||
);
|
||||
await this.start();
|
||||
await this.createNotificationListComponent({ filter: 'all' });
|
||||
const { createNotificationListComponent } = await this.start();
|
||||
await createNotificationListComponent({ filter: 'all' });
|
||||
assert.containsN(
|
||||
document.body,
|
||||
'.o_ThreadPreview',
|
||||
|
||||
@@ -62,7 +62,7 @@ export class NotificationRequest extends Component {
|
||||
}
|
||||
|
||||
Object.assign(NotificationRequest, {
|
||||
props: {},
|
||||
props: { localId: String },
|
||||
template: 'mail.NotificationRequest',
|
||||
});
|
||||
|
||||
|
||||
+1
-14
@@ -1,12 +1,6 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
afterEach,
|
||||
afterNextRender,
|
||||
beforeEach,
|
||||
createRootMessagingComponent,
|
||||
start,
|
||||
} from '@mail/utils/test_utils';
|
||||
import { afterEach, afterNextRender, beforeEach, start } from '@mail/utils/test_utils';
|
||||
|
||||
import Bus from 'web.Bus';
|
||||
|
||||
@@ -17,13 +11,6 @@ QUnit.module('thread_needaction_preview_tests.js', {
|
||||
beforeEach() {
|
||||
beforeEach(this);
|
||||
|
||||
this.createThreadNeedactionPreviewComponent = async props => {
|
||||
await createRootMessagingComponent(this, "ThreadNeedactionPreview", {
|
||||
props,
|
||||
target: this.widget.el
|
||||
});
|
||||
};
|
||||
|
||||
this.start = async params => {
|
||||
const res = await start(Object.assign({}, params, {
|
||||
data: this.data,
|
||||
|
||||
+15
-17
@@ -31,14 +31,14 @@ export class ThreadNeedactionPreview extends Component {
|
||||
* @returns {string}
|
||||
*/
|
||||
image() {
|
||||
if (this.thread.moduleIcon) {
|
||||
return this.thread.moduleIcon;
|
||||
if (this.threadNeedactionPreviewView.thread.moduleIcon) {
|
||||
return this.threadNeedactionPreviewView.thread.moduleIcon;
|
||||
}
|
||||
if (this.thread.correspondent) {
|
||||
return this.thread.correspondent.avatarUrl;
|
||||
if (this.threadNeedactionPreviewView.thread.correspondent) {
|
||||
return this.threadNeedactionPreviewView.thread.correspondent.avatarUrl;
|
||||
}
|
||||
if (this.thread.model === 'mail.channel') {
|
||||
return `/web/image/mail.channel/${this.thread.id}/avatar_128?unique=${this.thread.avatarCacheKey}`;
|
||||
if (this.threadNeedactionPreviewView.thread.model === 'mail.channel') {
|
||||
return `/web/image/mail.channel/${this.threadNeedactionPreviewView.thread.id}/avatar_128?unique=${this.threadNeedactionPreviewView.thread.avatarCacheKey}`;
|
||||
}
|
||||
return '/mail/static/src/img/smiley/avatar.jpg';
|
||||
}
|
||||
@@ -49,17 +49,17 @@ export class ThreadNeedactionPreview extends Component {
|
||||
* @returns {string}
|
||||
*/
|
||||
get inlineLastNeedactionMessageAsOriginThreadBody() {
|
||||
if (!this.thread.lastNeedactionMessageAsOriginThread) {
|
||||
if (!this.threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread) {
|
||||
return '';
|
||||
}
|
||||
return mailUtils.htmlToTextContentInline(this.thread.lastNeedactionMessageAsOriginThread.prettyBody);
|
||||
return mailUtils.htmlToTextContentInline(this.threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread.prettyBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Thread}
|
||||
* @returns {ThreadNeedactionPreviewView}
|
||||
*/
|
||||
get thread() {
|
||||
return this.messaging && this.messaging.models['Thread'].get(this.props.threadLocalId);
|
||||
get threadNeedactionPreviewView() {
|
||||
return this.messaging && this.messaging.models['ThreadNeedactionPreviewView'].get(this.props.localId);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -76,7 +76,7 @@ export class ThreadNeedactionPreview extends Component {
|
||||
// handled in `_onClickMarkAsRead`
|
||||
return;
|
||||
}
|
||||
this.thread.open();
|
||||
this.threadNeedactionPreviewView.thread.open();
|
||||
if (!this.messaging.device.isMobile) {
|
||||
this.messaging.messagingMenu.close();
|
||||
}
|
||||
@@ -88,17 +88,15 @@ export class ThreadNeedactionPreview extends Component {
|
||||
*/
|
||||
_onClickMarkAsRead(ev) {
|
||||
this.messaging.models['Message'].markAllAsRead([
|
||||
['model', '=', this.thread.model],
|
||||
['res_id', '=', this.thread.id],
|
||||
['model', '=', this.threadNeedactionPreviewView.thread.model],
|
||||
['res_id', '=', this.threadNeedactionPreviewView.thread.id],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign(ThreadNeedactionPreview, {
|
||||
props: {
|
||||
threadLocalId: String,
|
||||
},
|
||||
props: { localId: String },
|
||||
template: 'mail.ThreadNeedactionPreview',
|
||||
});
|
||||
|
||||
|
||||
+11
-11
@@ -6,18 +6,18 @@
|
||||
The preview template is used by the discuss in mobile, and by the systray
|
||||
menu in order to show preview of threads.
|
||||
-->
|
||||
<div class="o_ThreadNeedactionPreview" t-attf-class="{{ className }}" t-on-click="_onClick" t-att-data-thread-local-id="thread ? thread.localId : undefined" t-ref="root">
|
||||
<t t-if="thread">
|
||||
<div class="o_ThreadNeedactionPreview" t-attf-class="{{ className }}" t-on-click="_onClick" t-att-data-thread-local-id="threadNeedactionPreviewView ? threadNeedactionPreviewView.thread.localId : undefined" t-ref="root">
|
||||
<t t-if="threadNeedactionPreviewView">
|
||||
<div class="o_ThreadNeedactionPreview_sidebar">
|
||||
<div class="o_ThreadNeedactionPreview_imageContainer o_ThreadNeedactionPreview_sidebarItem">
|
||||
<img class="o_ThreadNeedactionPreview_image" t-att-src="image()" alt="Thread Image"/>
|
||||
<t t-if="thread.correspondent and thread.correspondent.im_status">
|
||||
<t t-if="threadNeedactionPreviewView.thread.correspondent and threadNeedactionPreviewView.thread.correspondent.im_status">
|
||||
<PartnerImStatusIcon
|
||||
className="'o_ThreadNeedactionPreview_partnerImStatusIcon'"
|
||||
classNameObj="{
|
||||
'o-mobile': messaging.device.isMobile,
|
||||
}"
|
||||
partnerLocalId="thread.correspondent.localId"
|
||||
partnerLocalId="threadNeedactionPreviewView.thread.correspondent.localId"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
@@ -25,24 +25,24 @@
|
||||
<div class="o_ThreadNeedactionPreview_content">
|
||||
<div class="o_ThreadNeedactionPreview_header">
|
||||
<span class="o_ThreadNeedactionPreview_name text-truncate" t-att-class="{ 'o-mobile': messaging.device.isMobile }">
|
||||
<t t-esc="thread.displayName"/>
|
||||
<t t-esc="threadNeedactionPreviewView.thread.displayName"/>
|
||||
</span>
|
||||
<span class="o_ThreadNeedactionPreview_counter">
|
||||
(<t t-esc="thread.needactionMessagesAsOriginThread.length"/>)
|
||||
(<t t-esc="threadNeedactionPreviewView.thread.needactionMessagesAsOriginThread.length"/>)
|
||||
</span>
|
||||
<span class="o-autogrow"/>
|
||||
<t t-if="thread.lastNeedactionMessageAsOriginThread and thread.lastNeedactionMessageAsOriginThread.date">
|
||||
<t t-if="threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread and threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread.date">
|
||||
<span class="o_ThreadNeedactionPreview_date">
|
||||
<t t-esc="thread.lastNeedactionMessageAsOriginThread.date.fromNow()"/>
|
||||
<t t-esc="threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread.date.fromNow()"/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_ThreadNeedactionPreview_core">
|
||||
<span class="o_ThreadNeedactionPreview_coreItem o_ThreadNeedactionPreview_inlineText text-truncate" t-att-class="{ 'o-empty': inlineLastNeedactionMessageAsOriginThreadBody.length === 0 }">
|
||||
<t t-if="thread.lastNeedactionMessageAsOriginThread and thread.lastNeedactionMessageAsOriginThread.author">
|
||||
<t t-if="threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread and threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread.author">
|
||||
<MessageAuthorPrefix
|
||||
messageLocalId="thread.lastNeedactionMessageAsOriginThread.localId"
|
||||
threadLocalId="thread.localId"
|
||||
messageLocalId="threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread.localId"
|
||||
threadLocalId="threadNeedactionPreviewView.thread.localId"
|
||||
/>
|
||||
</t>
|
||||
<t t-esc="inlineLastNeedactionMessageAsOriginThreadBody"/>
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
afterEach,
|
||||
afterNextRender,
|
||||
beforeEach,
|
||||
createRootMessagingComponent,
|
||||
start,
|
||||
} from '@mail/utils/test_utils';
|
||||
import { afterEach, afterNextRender, beforeEach, start } from '@mail/utils/test_utils';
|
||||
|
||||
QUnit.module('mail', {}, function () {
|
||||
QUnit.module('components', {}, function () {
|
||||
@@ -15,19 +9,14 @@ QUnit.module('thread_preview_tests.js', {
|
||||
beforeEach() {
|
||||
beforeEach(this);
|
||||
|
||||
this.createThreadPreviewComponent = async props => {
|
||||
await createRootMessagingComponent(this, "ThreadPreview", {
|
||||
props,
|
||||
target: this.widget.el,
|
||||
});
|
||||
};
|
||||
|
||||
this.start = async params => {
|
||||
const { env, widget } = await start(Object.assign({}, params, {
|
||||
const res = await start(Object.assign({}, params, {
|
||||
data: this.data,
|
||||
}));
|
||||
const { env, widget } = res;
|
||||
this.env = env;
|
||||
this.widget = widget;
|
||||
return res;
|
||||
};
|
||||
},
|
||||
afterEach() {
|
||||
@@ -40,6 +29,7 @@ QUnit.test('mark as read', async function (assert) {
|
||||
this.data['mail.channel'].records.push({
|
||||
id: 11,
|
||||
message_unread_counter: 1,
|
||||
seen_message_id: 99,
|
||||
});
|
||||
this.data['mail.message'].records.push({
|
||||
id: 100,
|
||||
@@ -47,7 +37,7 @@ QUnit.test('mark as read', async function (assert) {
|
||||
res_id: 11,
|
||||
});
|
||||
|
||||
await this.start({
|
||||
const { click, createMessagingMenuComponent } = await this.start({
|
||||
hasChatWindow: true,
|
||||
async mockRPC(route, args) {
|
||||
if (route.includes('set_last_seen_message')) {
|
||||
@@ -56,11 +46,8 @@ QUnit.test('mark as read', async function (assert) {
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
const thread = this.messaging.models['Thread'].findFromIdentifyingData({
|
||||
id: 11,
|
||||
model: 'mail.channel',
|
||||
});
|
||||
await this.createThreadPreviewComponent({ threadLocalId: thread.localId });
|
||||
await createMessagingMenuComponent();
|
||||
await click('.o_MessagingMenu_toggler');
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_ThreadPreview_markAsRead',
|
||||
|
||||
@@ -31,10 +31,10 @@ export class ThreadPreview extends Component {
|
||||
* @returns {string}
|
||||
*/
|
||||
image() {
|
||||
if (this.thread.correspondent) {
|
||||
return this.thread.correspondent.avatarUrl;
|
||||
if (this.threadPreviewView.thread.correspondent) {
|
||||
return this.threadPreviewView.thread.correspondent.avatarUrl;
|
||||
}
|
||||
return `/web/image/mail.channel/${this.thread.id}/avatar_128?unique=${this.thread.avatarCacheKey}`;
|
||||
return `/web/image/mail.channel/${this.threadPreviewView.thread.id}/avatar_128?unique=${this.threadPreviewView.thread.avatarCacheKey}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,17 +43,17 @@ export class ThreadPreview extends Component {
|
||||
* @returns {string}
|
||||
*/
|
||||
get inlineLastMessageBody() {
|
||||
if (!this.thread.lastMessage) {
|
||||
if (!this.threadPreviewView.thread.lastMessage) {
|
||||
return '';
|
||||
}
|
||||
return mailUtils.htmlToTextContentInline(this.thread.lastMessage.prettyBody);
|
||||
return mailUtils.htmlToTextContentInline(this.threadPreviewView.thread.lastMessage.prettyBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Thread}
|
||||
* @returns {ThreadPreviewView}
|
||||
*/
|
||||
get thread() {
|
||||
return this.messaging && this.messaging.models['Thread'].get(this.props.threadLocalId);
|
||||
get threadPreviewView() {
|
||||
return this.messaging && this.messaging.models['ThreadPreviewView'].get(this.props.localId);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -70,7 +70,7 @@ export class ThreadPreview extends Component {
|
||||
// handled in `_onClickMarkAsRead`
|
||||
return;
|
||||
}
|
||||
this.thread.open();
|
||||
this.threadPreviewView.thread.open();
|
||||
if (!this.messaging.device.isMobile) {
|
||||
this.messaging.messagingMenu.close();
|
||||
}
|
||||
@@ -81,17 +81,15 @@ export class ThreadPreview extends Component {
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickMarkAsRead(ev) {
|
||||
if (this.thread.lastNonTransientMessage) {
|
||||
this.thread.markAsSeen(this.thread.lastNonTransientMessage);
|
||||
if (this.threadPreviewView.thread.lastNonTransientMessage) {
|
||||
this.threadPreviewView.thread.markAsSeen(this.threadPreviewView.thread.lastNonTransientMessage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign(ThreadPreview, {
|
||||
props: {
|
||||
threadLocalId: String,
|
||||
},
|
||||
props: { localId: String },
|
||||
template: 'mail.ThreadPreview',
|
||||
});
|
||||
|
||||
|
||||
@@ -6,55 +6,55 @@
|
||||
The preview template is used by the discuss in mobile, and by the systray
|
||||
menu in order to show preview of threads.
|
||||
-->
|
||||
<div class="o_ThreadPreview" t-att-class="{ 'o-muted': thread and thread.localMessageUnreadCounter === 0 }" t-attf-class="{{ className }}" t-on-click="_onClick" t-att-data-thread-local-id="thread ? thread.localId : undefined" t-ref="root">
|
||||
<t t-if="thread">
|
||||
<div class="o_ThreadPreview" t-att-class="{ 'o-muted': threadPreviewView and threadPreviewView.thread.localMessageUnreadCounter === 0 }" t-attf-class="{{ className }}" t-on-click="_onClick" t-att-data-thread-local-id="threadPreviewView ? threadPreviewView.thread.localId : undefined" t-ref="root">
|
||||
<t t-if="threadPreviewView">
|
||||
<div class="o_ThreadPreview_sidebar">
|
||||
<div class="o_ThreadPreview_imageContainer o_ThreadPreview_sidebarItem">
|
||||
<img class="o_ThreadPreview_image rounded-circle" t-att-src="image()" alt="Thread Image"/>
|
||||
<t t-if="thread.correspondent and thread.correspondent.im_status">
|
||||
<t t-if="threadPreviewView.thread.correspondent and threadPreviewView.thread.correspondent.im_status">
|
||||
<PartnerImStatusIcon
|
||||
className="'o_ThreadPreview_partnerImStatusIcon'"
|
||||
classNameObj="{
|
||||
'o-mobile': messaging.device.isMobile,
|
||||
'o-muted': thread.localMessageUnreadCounter === 0,
|
||||
'o-muted': threadPreviewView.thread.localMessageUnreadCounter === 0,
|
||||
}"
|
||||
partnerLocalId="thread.correspondent.localId"
|
||||
partnerLocalId="threadPreviewView.thread.correspondent.localId"
|
||||
/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_ThreadPreview_content">
|
||||
<div class="o_ThreadPreview_header align-items-baseline">
|
||||
<span class="o_ThreadPreview_name text-truncate" t-att-class="{ 'o-mobile': messaging.device.isMobile, 'o-muted': thread.localMessageUnreadCounter === 0 }">
|
||||
<t t-esc="thread.displayName"/>
|
||||
<span class="o_ThreadPreview_name text-truncate" t-att-class="{ 'o-mobile': messaging.device.isMobile, 'o-muted': threadPreviewView.thread.localMessageUnreadCounter === 0 }">
|
||||
<t t-esc="threadPreviewView.thread.displayName"/>
|
||||
</span>
|
||||
<t t-if="thread.localMessageUnreadCounter > 0">
|
||||
<span class="o_ThreadPreview_counter" t-att-class="{ 'o-muted': thread.localMessageUnreadCounter === 0 }">
|
||||
(<t t-esc="thread.localMessageUnreadCounter"/>)
|
||||
<t t-if="threadPreviewView.thread.localMessageUnreadCounter > 0">
|
||||
<span class="o_ThreadPreview_counter" t-att-class="{ 'o-muted': threadPreviewView.thread.localMessageUnreadCounter === 0 }">
|
||||
(<t t-esc="threadPreviewView.thread.localMessageUnreadCounter"/>)
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="thread.rtcSessions.length > 0">
|
||||
<span class="o_ThreadPreview_callIndicator fa fa-volume-up mx-2" t-att-class="{ 'o-isCalling': thread.rtc }"/>
|
||||
<t t-if="threadPreviewView.thread.rtcSessions.length > 0">
|
||||
<span class="o_ThreadPreview_callIndicator fa fa-volume-up mx-2" t-att-class="{ 'o-isCalling': threadPreviewView.thread.rtc }"/>
|
||||
</t>
|
||||
<span class="o-autogrow"/>
|
||||
<t t-if="thread.lastMessage and thread.lastMessage.date">
|
||||
<span class="o_ThreadPreview_date" t-att-class="{ 'o-muted': thread.localMessageUnreadCounter === 0 }">
|
||||
<t t-esc="thread.lastMessage.date.fromNow()"/>
|
||||
<t t-if="threadPreviewView.thread.lastMessage and threadPreviewView.thread.lastMessage.date">
|
||||
<span class="o_ThreadPreview_date" t-att-class="{ 'o-muted': threadPreviewView.thread.localMessageUnreadCounter === 0 }">
|
||||
<t t-esc="threadPreviewView.thread.lastMessage.date.fromNow()"/>
|
||||
</span>
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_ThreadPreview_core">
|
||||
<span class="o_ThreadPreview_coreItem o_ThreadPreview_inlineText text-truncate" t-att-class="{ 'o-empty': inlineLastMessageBody.length === 0 }">
|
||||
<t t-if="thread.lastMessage and thread.lastMessage.author">
|
||||
<t t-if="threadPreviewView.thread.lastMessage and threadPreviewView.thread.lastMessage.author">
|
||||
<MessageAuthorPrefix
|
||||
messageLocalId="thread.lastMessage.localId"
|
||||
threadLocalId="thread.localId"
|
||||
messageLocalId="threadPreviewView.thread.lastMessage.localId"
|
||||
threadLocalId="threadPreviewView.thread.localId"
|
||||
/>
|
||||
</t>
|
||||
<t t-esc="inlineLastMessageBody"/>
|
||||
</span>
|
||||
<span class="o-autogrow"/>
|
||||
<t t-if="thread.localMessageUnreadCounter > 0">
|
||||
<t t-if="threadPreviewView.thread.localMessageUnreadCounter > 0">
|
||||
<span class="o_ThreadPreview_coreItem o_ThreadPreview_markAsRead fa fa-check" title="Mark as Read" t-on-click="_onClickMarkAsRead" t-ref="markAsRead"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
@@ -299,6 +299,13 @@ registerModel({
|
||||
}
|
||||
return clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeNotificationListView() {
|
||||
return (this.messaging.device.isMobile && this.activeMobileNavbarTabId !== 'mailbox') ? insertAndReplace() : clear();
|
||||
},
|
||||
/**
|
||||
* Only pinned threads are allowed in discuss.
|
||||
*
|
||||
@@ -401,6 +408,11 @@ registerModel({
|
||||
menu_id: attr({
|
||||
default: null,
|
||||
}),
|
||||
notificationListView: one2one('NotificationListView', {
|
||||
compute: '_computeNotificationListView',
|
||||
inverse: 'discussOwner',
|
||||
isCausal: true,
|
||||
}),
|
||||
/**
|
||||
* The navbar view on the discuss app when in mobile and when not
|
||||
* replying to a message from inbox.
|
||||
|
||||
@@ -51,7 +51,7 @@ registerModel({
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {MobileMessagingNavbarView|FieldCommand}
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeMobileMessagingNavbarView() {
|
||||
if (this.messaging.device && this.messaging.device.isMobile) {
|
||||
@@ -59,6 +59,12 @@ registerModel({
|
||||
}
|
||||
return clear();
|
||||
},
|
||||
/**
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeNotificationListView() {
|
||||
return this.isOpen ? insertAndReplace() : clear();
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
/**
|
||||
@@ -88,6 +94,11 @@ registerModel({
|
||||
isOpen: attr({
|
||||
default: false,
|
||||
}),
|
||||
notificationListView: one2one('NotificationListView', {
|
||||
compute: '_computeNotificationListView',
|
||||
inverse: 'messagingMenuOwner',
|
||||
isCausal: true,
|
||||
}),
|
||||
/**
|
||||
* The navbar view on the messaging menu when in mobile.
|
||||
*/
|
||||
|
||||
@@ -127,6 +127,10 @@ registerModel({
|
||||
notifications: one2many('Notification', {
|
||||
inverse: 'notificationGroup',
|
||||
}),
|
||||
notificationGroupViews: one2many('NotificationGroupView', {
|
||||
inverse: 'notificationGroup',
|
||||
isCausal: true,
|
||||
}),
|
||||
res_id: attr({
|
||||
readonly: true,
|
||||
}),
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { many2one } from '@mail/model/model_field';
|
||||
|
||||
registerModel({
|
||||
name: 'NotificationGroupView',
|
||||
identifyingFields: ['notificationListViewOwner', 'notificationGroup'],
|
||||
fields: {
|
||||
notificationGroup: many2one('NotificationGroup', {
|
||||
inverse: 'notificationGroupViews',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
notificationListViewOwner: many2one('NotificationListView', {
|
||||
inverse: 'notificationGroupViews',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,227 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { attr, many2many, one2many, one2one } from '@mail/model/model_field';
|
||||
import { clear, insertAndReplace, replace } from '@mail/model/model_field_command';
|
||||
|
||||
registerModel({
|
||||
name: 'NotificationListView',
|
||||
identifyingFields: [['discussOwner', 'messagingMenuOwner']],
|
||||
recordMethods: {
|
||||
/**
|
||||
* @private
|
||||
* @returns {string|FieldCommand}
|
||||
*/
|
||||
_computeFilter() {
|
||||
if (this.discussOwner) {
|
||||
return this.discussOwner.activeMobileNavbarTabId;
|
||||
}
|
||||
if (this.messagingMenuOwner) {
|
||||
return this.messagingMenuOwner.activeTabId;
|
||||
}
|
||||
return clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_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 =>
|
||||
thread.channel_type === 'channel' &&
|
||||
thread.isPinned &&
|
||||
thread.model === 'mail.channel'
|
||||
)
|
||||
.sort((c1, c2) => c1.displayName < c2.displayName ? -1 : 1)
|
||||
);
|
||||
}
|
||||
case 'chat': {
|
||||
return replace(this.messaging.models['Thread']
|
||||
.all(thread =>
|
||||
thread.isChatChannel &&
|
||||
thread.isPinned &&
|
||||
thread.model === 'mail.channel'
|
||||
)
|
||||
.sort((c1, c2) => c1.displayName < c2.displayName ? -1 : 1)
|
||||
);
|
||||
}
|
||||
case 'all': {
|
||||
// "All" filter is for channels and chats
|
||||
return replace(this.messaging.models['Thread']
|
||||
.all(thread => thread.isPinned && thread.model === 'mail.channel')
|
||||
.sort((c1, c2) => c1.displayName < c2.displayName ? -1 : 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
return clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeNotificationGroupViews() {
|
||||
if (this.filter !== 'all') {
|
||||
return clear();
|
||||
}
|
||||
return insertAndReplace(
|
||||
this.models['NotificationGroup']
|
||||
.all()
|
||||
.sort((group1, group2) => group1.sequence - group2.sequence)
|
||||
.map(notificationGroup => {
|
||||
return { notificationGroup: replace(notificationGroup) };
|
||||
})
|
||||
);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeNotificationRequestView() {
|
||||
return (this.filter === 'all' && this.messaging.isNotificationPermissionDefault) ? insertAndReplace() : clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeNotificationViews() {
|
||||
const notifications = [];
|
||||
if (this.notificationRequestView) {
|
||||
notifications.push(this.notificationRequestView);
|
||||
}
|
||||
notifications.push(...this.notificationGroupViews);
|
||||
notifications.push(...this.threadNeedactionPreviewViews);
|
||||
notifications.push(...this.threadPreviewViews);
|
||||
return replace(notifications);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeThreadNeedactionPreviewViews() {
|
||||
if (this.filter !== 'all') {
|
||||
return clear();
|
||||
}
|
||||
return insertAndReplace(
|
||||
this.messaging.models['Thread']
|
||||
.all(t => t.model !== 'mail.box' && t.needactionMessagesAsOriginThread.length > 0)
|
||||
.sort((t1, t2) => {
|
||||
if (t1.needactionMessagesAsOriginThread.length > 0 && t2.needactionMessagesAsOriginThread.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
if (t1.needactionMessagesAsOriginThread.length === 0 && t2.needactionMessagesAsOriginThread.length > 0) {
|
||||
return 1;
|
||||
}
|
||||
if (t1.lastNeedactionMessageAsOriginThread && t2.lastNeedactionMessageAsOriginThread) {
|
||||
return t1.lastNeedactionMessageAsOriginThread.id < t2.lastNeedactionMessageAsOriginThread.id ? 1 : -1;
|
||||
}
|
||||
if (t1.lastNeedactionMessageAsOriginThread) {
|
||||
return -1;
|
||||
}
|
||||
if (t2.lastNeedactionMessageAsOriginThread) {
|
||||
return 1;
|
||||
}
|
||||
return t1.id < t2.id ? -1 : 1;
|
||||
})
|
||||
.map(thread => {
|
||||
return { thread: replace(thread) };
|
||||
})
|
||||
);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeThreadPreviewViews() {
|
||||
return insertAndReplace(
|
||||
this.filteredThreads
|
||||
.sort((t1, t2) => {
|
||||
if (t1.localMessageUnreadCounter > 0 && t2.localMessageUnreadCounter === 0) {
|
||||
return -1;
|
||||
}
|
||||
if (t1.localMessageUnreadCounter === 0 && t2.localMessageUnreadCounter > 0) {
|
||||
return 1;
|
||||
}
|
||||
if (t1.lastMessage && t2.lastMessage) {
|
||||
return t1.lastMessage.id < t2.lastMessage.id ? 1 : -1;
|
||||
}
|
||||
if (t1.lastMessage) {
|
||||
return -1;
|
||||
}
|
||||
if (t2.lastMessage) {
|
||||
return 1;
|
||||
}
|
||||
return t1.id < t2.id ? -1 : 1;
|
||||
})
|
||||
.map(thread => {
|
||||
return {
|
||||
thread: replace(thread),
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
discussOwner: one2one('Discuss', {
|
||||
inverse: 'notificationListView',
|
||||
readonly: true,
|
||||
}),
|
||||
filter: attr({
|
||||
compute: '_computeFilter',
|
||||
}),
|
||||
filteredThreads: many2many('Thread', {
|
||||
compute: '_computeFilteredThreads',
|
||||
}),
|
||||
messagingMenuOwner: one2one('MessagingMenu', {
|
||||
inverse: 'notificationListView',
|
||||
readonly: true,
|
||||
}),
|
||||
notificationGroupViews: one2many('NotificationGroupView', {
|
||||
compute: '_computeNotificationGroupViews',
|
||||
inverse: 'notificationListViewOwner',
|
||||
isCausal: true,
|
||||
}),
|
||||
notificationRequestView: one2one('NotificationRequestView', {
|
||||
compute: '_computeNotificationRequestView',
|
||||
inverse: 'notificationListViewOwner',
|
||||
isCausal: true,
|
||||
}),
|
||||
notificationViews: one2many('Model', {
|
||||
compute: '_computeNotificationViews',
|
||||
isCausal: true,
|
||||
}),
|
||||
threadNeedactionPreviewViews: one2many('ThreadNeedactionPreviewView', {
|
||||
compute: '_computeThreadNeedactionPreviewViews',
|
||||
inverse: 'notificationListViewOwner',
|
||||
isCausal: true,
|
||||
}),
|
||||
threadPreviewViews: one2many('ThreadPreviewView', {
|
||||
compute: '_computeThreadPreviewViews',
|
||||
inverse: 'notificationListViewOwner',
|
||||
isCausal: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { addFields, patchIdentifyingFields, patchRecordMethods } from '@mail/model/model_core';
|
||||
import { one2one } from '@mail/model/model_field';
|
||||
import '@mail/models/notification_list_view/notification_list_view'; // ensure the model definition is loaded before the patch
|
||||
|
||||
addFields('NotificationListView', {
|
||||
qunitTestOwner: one2one('QUnitTest', {
|
||||
inverse: 'notificationListView',
|
||||
readonly: true,
|
||||
}),
|
||||
});
|
||||
|
||||
patchIdentifyingFields('NotificationListView', identifyingFields => {
|
||||
identifyingFields[0].push('qunitTestOwner');
|
||||
});
|
||||
|
||||
patchRecordMethods('NotificationListView', {
|
||||
_computeFilter() {
|
||||
if (this.qunitTestOwner) {
|
||||
return this.filter;
|
||||
}
|
||||
return this._super();
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { one2one } from '@mail/model/model_field';
|
||||
|
||||
registerModel({
|
||||
name: 'NotificationRequestView',
|
||||
identifyingFields: ['notificationListViewOwner'],
|
||||
fields: {
|
||||
notificationListViewOwner: one2one('NotificationListView', {
|
||||
inverse: 'notificationRequestView',
|
||||
required: true,
|
||||
readonly: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -2421,6 +2421,14 @@ registerModel({
|
||||
todayActivities: one2many('Activity', {
|
||||
compute: '_computeTodayActivities',
|
||||
}),
|
||||
threadNeedactionPreviewViews: one2many('ThreadNeedactionPreviewView', {
|
||||
inverse: 'thread',
|
||||
isCausal: true,
|
||||
}),
|
||||
threadPreviewViews: one2many('ThreadPreviewView', {
|
||||
inverse: 'thread',
|
||||
isCausal: true,
|
||||
}),
|
||||
/**
|
||||
* Members that are currently typing something in the composer of this
|
||||
* thread, including current partner.
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { many2one } from '@mail/model/model_field';
|
||||
|
||||
registerModel({
|
||||
name: 'ThreadNeedactionPreviewView',
|
||||
identifyingFields: ['notificationListViewOwner', 'thread'],
|
||||
fields: {
|
||||
notificationListViewOwner: many2one('NotificationListView', {
|
||||
inverse: 'threadNeedactionPreviewViews',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
thread: many2one('Thread', {
|
||||
inverse: 'threadNeedactionPreviewViews',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { many2one } from '@mail/model/model_field';
|
||||
|
||||
registerModel({
|
||||
name: 'ThreadPreviewView',
|
||||
identifyingFields: ['notificationListViewOwner', 'thread'],
|
||||
fields: {
|
||||
notificationListViewOwner: many2one('NotificationListView', {
|
||||
inverse: 'threadPreviewViews',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
thread: many2one('Thread', {
|
||||
inverse: 'threadPreviewViews',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -472,6 +472,19 @@ function getCreateMessagingMenuComponent({ components, env, widget }) {
|
||||
};
|
||||
}
|
||||
|
||||
function getCreateNotificationListComponent({ components, env, modelManager, widget }) {
|
||||
return async function createNotificationListComponent({ filter = 'all' } = {}) {
|
||||
const notificationListView = modelManager.messaging.models['NotificationListView'].create({
|
||||
filter,
|
||||
qunitTestOwner: insertAndReplace(),
|
||||
});
|
||||
await createRootMessagingComponent({ components, env }, "NotificationList", {
|
||||
props: { localId: notificationListView.localId },
|
||||
target: widget.el,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function getCreateThreadViewComponent({ afterEvent, components, env, widget }) {
|
||||
return async function createThreadViewComponent(threadView, otherProps = {}, { isFixedSize = false, waitUntilMessagesLoaded = true } = {}) {
|
||||
let target;
|
||||
@@ -830,6 +843,7 @@ async function start(param0 = {}) {
|
||||
createComposerSuggestionComponent: getCreateComposerSuggestionComponent({ components, env: testEnv, modelManager, widget }),
|
||||
createMessageComponent: getCreateMessageComponent({ components, env: testEnv, modelManager, widget }),
|
||||
createMessagingMenuComponent: getCreateMessagingMenuComponent({ components, env: testEnv, widget }),
|
||||
createNotificationListComponent: getCreateNotificationListComponent({ components, env: testEnv, modelManager, widget }),
|
||||
createThreadViewComponent: getCreateThreadViewComponent({ afterEvent, components, env: testEnv, widget }),
|
||||
openDiscuss,
|
||||
};
|
||||
|
||||
@@ -18,6 +18,10 @@ registerModel({
|
||||
inverse: 'qunitTest',
|
||||
isCausal: true,
|
||||
}),
|
||||
notificationListView: one2one('NotificationListView', {
|
||||
inverse: 'qunitTestOwner',
|
||||
isCausal: true,
|
||||
}),
|
||||
threadViewer: one2one('ThreadViewer', {
|
||||
inverse: 'qunitTest',
|
||||
isCausal: true,
|
||||
|
||||
@@ -14,7 +14,7 @@ patch(NotificationGroup.prototype, 'sms/static/src/components/notification_group
|
||||
* @override
|
||||
*/
|
||||
image() {
|
||||
if (this.group.notification_type === 'sms') {
|
||||
if (this.notificationGroupView.notificationGroup.notification_type === 'sms') {
|
||||
return '/sms/static/img/sms_failure.svg';
|
||||
}
|
||||
return this._super(...arguments);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-inherit="mail.NotificationGroup" t-inherit-mode="extension">
|
||||
<xpath expr="//*[hasclass('o_NotificationGroup_inlineText')]" position="inside">
|
||||
<t t-if="group.notification_type === 'sms'">
|
||||
<t t-if="notificationGroupView.notificationGroup.notification_type === 'sms'">
|
||||
An error occurred when sending an SMS.
|
||||
</t>
|
||||
</xpath>
|
||||
|
||||
+12
-29
@@ -1,14 +1,8 @@
|
||||
odoo.define('sms/static/src/components/notification_list/notification_list_notification_group_tests.js', function (require) {
|
||||
'use strict';
|
||||
/** @odoo-module **/
|
||||
|
||||
const {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
createRootMessagingComponent,
|
||||
start,
|
||||
} = require('@mail/utils/test_utils');
|
||||
import { afterEach, beforeEach, start } from '@mail/utils/test_utils';
|
||||
|
||||
const Bus = require('web.Bus');
|
||||
import Bus from 'web.Bus';
|
||||
|
||||
QUnit.module('sms', {}, function () {
|
||||
QUnit.module('components', {}, function () {
|
||||
@@ -17,23 +11,14 @@ QUnit.module('notification_list_notification_group_tests.js', {
|
||||
beforeEach() {
|
||||
beforeEach(this);
|
||||
|
||||
/**
|
||||
* @param {Object} param0
|
||||
* @param {string} [param0.filter='all']
|
||||
*/
|
||||
this.createNotificationListComponent = async ({ filter = 'all' } = {}) => {
|
||||
await createRootMessagingComponent(this, "NotificationList", {
|
||||
props: { filter },
|
||||
target: this.widget.el,
|
||||
});
|
||||
};
|
||||
|
||||
this.start = async params => {
|
||||
const { env, widget } = await start(Object.assign({}, params, {
|
||||
const res = await start(Object.assign({}, params, {
|
||||
data: this.data,
|
||||
}));
|
||||
const { env, widget } = res;
|
||||
this.env = env;
|
||||
this.widget = widget;
|
||||
return res;
|
||||
};
|
||||
},
|
||||
afterEach() {
|
||||
@@ -81,8 +66,8 @@ QUnit.test('mark as read', async function (assert) {
|
||||
);
|
||||
});
|
||||
|
||||
await this.start({ env: { bus } });
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start({ env: { bus } });
|
||||
await createNotificationListComponent();
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
@@ -132,8 +117,8 @@ QUnit.test('notifications grouped by notification_type', async function (assert)
|
||||
notification_type: 'email', // different type from first failure
|
||||
}
|
||||
);
|
||||
await this.start();
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start();
|
||||
await createNotificationListComponent();
|
||||
|
||||
assert.containsN(
|
||||
document.body,
|
||||
@@ -272,8 +257,8 @@ QUnit.test('grouped notifications by document model', async function (assert) {
|
||||
);
|
||||
});
|
||||
|
||||
await this.start({ env: { bus } });
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start({ env: { bus } });
|
||||
await createNotificationListComponent();
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
@@ -301,5 +286,3 @@ QUnit.test('grouped notifications by document model', async function (assert) {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ patch(NotificationGroup.prototype, 'snailmail/static/src/components/notification
|
||||
* @override
|
||||
*/
|
||||
image() {
|
||||
if (this.group.notification_type === 'snail') {
|
||||
if (this.notificationGroupView.notificationGroup.notification_type === 'snail') {
|
||||
return '/snailmail/static/img/snailmail_failure.png';
|
||||
}
|
||||
return this._super(...arguments);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-inherit="mail.NotificationGroup" t-inherit-mode="extension">
|
||||
<xpath expr="//*[hasclass('o_NotificationGroup_inlineText')]" position="inside">
|
||||
<t t-if="group.notification_type === 'snail'">
|
||||
<t t-if="notificationGroupView.notificationGroup.notification_type === 'snail'">
|
||||
An error occurred when sending a letter with Snailmail.
|
||||
</t>
|
||||
</xpath>
|
||||
|
||||
+10
-24
@@ -1,11 +1,6 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {
|
||||
afterEach,
|
||||
beforeEach,
|
||||
createRootMessagingComponent,
|
||||
start,
|
||||
} from '@mail/utils/test_utils';
|
||||
import { afterEach, beforeEach, start } from '@mail/utils/test_utils';
|
||||
|
||||
import Bus from 'web.Bus';
|
||||
|
||||
@@ -16,23 +11,14 @@ QUnit.module('notification_list_notification_group_tests.js', {
|
||||
beforeEach() {
|
||||
beforeEach(this);
|
||||
|
||||
/**
|
||||
* @param {Object} param0
|
||||
* @param {string} [param0.filter='all']
|
||||
*/
|
||||
this.createNotificationListComponent = async ({ filter = 'all' } = {}) => {
|
||||
await createRootMessagingComponent(this, "NotificationList", {
|
||||
props: { filter },
|
||||
target: this.widget.el,
|
||||
});
|
||||
};
|
||||
|
||||
this.start = async params => {
|
||||
const { env, widget } = await start(Object.assign({}, params, {
|
||||
const res = await start(Object.assign({}, params, {
|
||||
data: this.data,
|
||||
}));
|
||||
const { env, widget } = res;
|
||||
this.env = env;
|
||||
this.widget = widget;
|
||||
return res;
|
||||
};
|
||||
},
|
||||
afterEach() {
|
||||
@@ -75,8 +61,8 @@ QUnit.test('mark as read', async function (assert) {
|
||||
"action should have the group notification length as unread_counter"
|
||||
);
|
||||
});
|
||||
await this.start({ env: { bus } });
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start({ env: { bus } });
|
||||
await createNotificationListComponent();
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
@@ -126,8 +112,8 @@ QUnit.test('notifications grouped by notification_type', async function (assert)
|
||||
notification_type: 'email', // different type from first failure
|
||||
}
|
||||
);
|
||||
await this.start();
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start();
|
||||
await createNotificationListComponent();
|
||||
|
||||
assert.containsN(
|
||||
document.body,
|
||||
@@ -266,8 +252,8 @@ QUnit.test('grouped notifications by document model', async function (assert) {
|
||||
);
|
||||
});
|
||||
|
||||
await this.start({ env: { bus } });
|
||||
await this.createNotificationListComponent();
|
||||
const { createNotificationListComponent } = await this.start({ env: { bus } });
|
||||
await createNotificationListComponent();
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
|
||||
Reference in New Issue
Block a user