[FIX] mail: fix notification partners display in popover

Handle notification creation in convertData correctly.

task-2324260

closes odoo/odoo#58013

X-original-commit: ca457e990c87cd0405a2b7416a6c8064a9a83e21
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Xavier Dubuc
2020-09-18 09:42:09 +00:00
parent e6567379ed
commit 356a5448fe
8 changed files with 263 additions and 32 deletions
@@ -335,7 +335,7 @@
}
}
.o_Message_notificationIconContainer {
.o_Message_notificationIconClickable {
color: gray('600');
cursor: pointer;
@@ -94,13 +94,13 @@
</t>
<t t-if="threadView and message.originThread and message.originThread === threadView.thread and message.notifications.length > 0">
<t t-if="message.failureNotifications.length > 0">
<span class="o_Message_notificationIconContainer o-error" t-on-click="_onClickFailure">
<span class="o_Message_notificationIconClickable o-error" t-on-click="_onClickFailure">
<i name="failureIcon" class="o_Message_notificationIcon fa fa-envelope"/>
</span>
</t>
<t t-else="">
<Popover>
<span class="o_Message_notificationIconContainer">
<span class="o_Message_notificationIconClickable">
<i name="notificationIcon" class="o_Message_notificationIcon fa fa-envelope-o"/>
</span>
<t t-set="opened">
@@ -219,7 +219,7 @@ QUnit.test('Notification Sent', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -234,7 +234,7 @@ QUnit.test('Notification Sent', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.containsOnce(
document.body,
@@ -310,7 +310,7 @@ QUnit.test('Notification Error', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -325,7 +325,7 @@ QUnit.test('Notification Error', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.verifySteps(
['do_action'],
@@ -46,9 +46,10 @@ QUnit.module('thread_view_tests.js', {
};
this.start = async params => {
const { env, widget } = await start(Object.assign({}, params, {
const { afterEvent, env, widget } = await start(Object.assign({}, params, {
data: this.data,
}));
this.afterEvent = afterEvent;
this.env = env;
this.widget = widget;
};
@@ -566,6 +567,229 @@ QUnit.test('new messages separator on receiving new message', async function (as
);
});
QUnit.test('new messages separator on posting message', async function (assert) {
assert.expect(4);
this.data['mail.channel'].records = [{
channel_type: 'channel',
id: 20,
is_pinned: true,
message_unread_counter: 0,
name: "General",
}];
await this.start();
const thread = this.env.models['mail.thread'].findFromIdentifyingData({
id: 20,
model: 'mail.channel'
});
const threadViewer = this.env.models['mail.thread_viewer'].create({
hasThreadView: true,
thread: [['link', thread]],
});
await this.createThreadViewComponent(threadViewer.threadView, { hasComposer: true });
assert.containsNone(
document.body,
'.o_MessageList_message',
"should have no messages"
);
assert.containsNone(
document.body,
'.o_MessageList_separatorNewMessages',
"should not display 'new messages' separator"
);
document.querySelector('.o_ComposerTextInput_textarea').focus();
await afterNextRender(() => document.execCommand('insertText', false, "hey !"));
await afterNextRender(() =>
document.querySelector('.o_Composer_buttonSend').click()
);
assert.containsOnce(
document.body,
'.o_Message',
"should have the message current partner just posted"
);
assert.containsNone(
document.body,
'.o_MessageList_separatorNewMessages',
"still no separator shown when current partner posted a message"
);
});
QUnit.test('new messages separator on receiving new message', async function (assert) {
assert.expect(6);
this.data['res.partner'].records.push({
id:11,
name: "Foreigner partner",
});
this.data['res.users'].records.push({
id: 42,
name: "Foreigner user",
partner_id: 11,
});
this.data['mail.channel'].records.push({
channel_type: 'channel',
id: 20,
is_pinned: true,
message_unread_counter: 0,
name: "General",
seen_message_id: 1,
uuid: 'randomuuid',
});
this.data['mail.message'].records.push({
body: "blah",
channel_ids: [20],
id: 1,
});
await this.start();
const thread = this.env.models['mail.thread'].findFromIdentifyingData({
id: 20,
model: 'mail.channel'
});
const threadViewer = this.env.models['mail.thread_viewer'].create({
hasThreadView: true,
thread: [['link', thread]],
});
await this.createThreadViewComponent(threadViewer.threadView, { hasComposer: true });
assert.containsOnce(
document.body,
'.o_MessageList_message',
"should have an initial message"
);
assert.containsNone(
document.body,
'.o_MessageList_separatorNewMessages',
"should not display 'new messages' separator"
);
document.querySelector('.o_ComposerTextInput_textarea').blur();
// simulate receiving a message
await afterNextRender(async () => this.env.services.rpc({
route: '/mail/chat_post',
params: {
context: {
mockedUserId: 42,
},
uuid: thread.uuid,
message_content: "hu",
},
}));
assert.containsN(
document.body,
'.o_Message',
2,
"should now have 2 messages after receiving a new message"
);
assert.containsOnce(
document.body,
'.o_MessageList_separatorNewMessages',
"'new messages' separator should be shown"
);
assert.containsOnce(
document.body,
`.o_MessageList_separatorNewMessages ~ .o_Message[data-message-local-id="${
this.env.models['mail.message'].findFromIdentifyingData({id: 2}).localId
}"]`,
"'new messages' separator should be shown above new message received"
);
await afterNextRender(() => document.querySelector('.o_ComposerTextInput_textarea').focus());
assert.containsNone(
document.body,
'.o_MessageList_separatorNewMessages',
"'new messages' separator should no longer be shown as last message has been seen"
);
});
QUnit.test('basic rendering of canceled notification', async function (assert) {
assert.expect(8);
this.data['mail.channel'].records.push({ id: 11 });
this.data['res.partner'].records.push({ id: 12, name: "Someone" });
this.data['mail.message'].records.push({
channel_ids: [11],
id: 10,
message_type: 'email',
model: 'mail.channel',
notification_ids: [11],
res_id: 11,
});
this.data['mail.notification'].records.push({
failure_type: 'SMTP',
id: 11,
mail_message_id: 10,
notification_status: 'canceled',
notification_type: 'email',
res_partner_id: 12,
});
await this.start();
const threadViewer = await this.env.models['mail.thread_viewer'].create({
hasThreadView: true,
thread: [['insert', {
id: 11,
model: 'mail.channel',
}]],
});
await this.afterEvent({
eventName: 'o-component-message-list-thread-cache-changed',
func: () => {
this.createThreadViewComponent(threadViewer.threadView);
},
message: "thread become loaded with messages",
predicate: ({ threadViewer }) => {
return threadViewer.thread.model === 'mail.channel' && threadViewer.thread.id === 11;
},
});
assert.containsOnce(
document.body,
'.o_Message_notificationIconClickable',
"should display the notification icon container on the message"
);
assert.containsOnce(
document.body,
'.o_Message_notificationIcon',
"should display the notification icon on the message"
);
assert.hasClass(
document.querySelector('.o_Message_notificationIcon'),
'fa-envelope-o',
"notification icon shown on the message should represent email"
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.containsOnce(
document.body,
'.o_NotificationPopover',
"notification popover should be opened after notification has been clicked"
);
assert.containsOnce(
document.body,
'.o_NotificationPopover_notificationIcon',
"an icon should be shown in notification popover"
);
assert.containsOnce(
document.body,
'.o_NotificationPopover_notificationIcon.fa.fa-trash-o',
"the icon shown in notification popover should be the canceled icon"
);
assert.containsOnce(
document.body,
'.o_NotificationPopover_notificationPartnerName',
"partner name should be shown in notification popover"
);
assert.strictEqual(
document.querySelector('.o_NotificationPopover_notificationPartnerName').textContent.trim(),
"Someone",
"partner name shown in notification popover should be the one concerned by the notification"
);
});
});
});
});
@@ -32,7 +32,7 @@ function factory(dependencies) {
data2.notification_type = data.notification_type;
}
if ('res_partner_id' in data) {
if (!data.partner_id) {
if (!data.res_partner_id) {
data2.partner = [['unlink-all']];
} else {
data2.partner = [
@@ -1079,20 +1079,27 @@ MockServer.include({
'res_model': attachment.res_model,
});
});
const notifications = this._getRecords('mail.notification', [
const allNotifications = this._getRecords('mail.notification', [
['mail_message_id', '=', message.id],
]);
const historyPartnerIds = notifications
const historyPartnerIds = allNotifications
.filter(notification => notification.is_read)
.map(notification => notification.res_partner_id);
const needactionPartnerIds = notifications
const needactionPartnerIds = allNotifications
.filter(notification => !notification.is_read)
.map(notification => notification.res_partner_id);
let notifications = this._mockMailNotification_FilteredForWebClient(
allNotifications.map(notification => notification.id)
);
notifications = this._mockMailNotification_NotificationFormat(
notifications.map(notification => notification.id)
);
return Object.assign({}, message, {
attachment_ids: formattedAttachments,
author_id: formattedAuthor,
history_partner_ids: historyPartnerIds,
needaction_partner_ids: needactionPartnerIds,
notifications,
});
});
},
@@ -75,7 +75,7 @@ QUnit.test('Notification Sent', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -90,7 +90,7 @@ QUnit.test('Notification Sent', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.containsOnce(
document.body,
@@ -166,7 +166,7 @@ QUnit.test('Notification Error', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -181,7 +181,7 @@ QUnit.test('Notification Error', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.verifySteps(
['do_action'],
@@ -74,7 +74,7 @@ QUnit.test('Sent', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -89,7 +89,7 @@ QUnit.test('Sent', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.containsOnce(
document.body,
@@ -145,7 +145,7 @@ QUnit.test('Canceled', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -160,7 +160,7 @@ QUnit.test('Canceled', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.containsOnce(
document.body,
@@ -216,7 +216,7 @@ QUnit.test('Pending', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -231,7 +231,7 @@ QUnit.test('Pending', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.containsOnce(
document.body,
@@ -295,7 +295,7 @@ QUnit.test('No Price Available', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -310,7 +310,7 @@ QUnit.test('No Price Available', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.containsOnce(
document.body,
@@ -382,7 +382,7 @@ QUnit.test('Credit Error', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -397,7 +397,7 @@ QUnit.test('Credit Error', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.containsOnce(
document.body,
@@ -474,7 +474,7 @@ QUnit.test('Trial Error', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -489,7 +489,7 @@ QUnit.test('Trial Error', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.containsOnce(
document.body,
@@ -574,7 +574,7 @@ QUnit.test('Format Error', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -589,7 +589,7 @@ QUnit.test('Format Error', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.verifySteps(
['do_action'],
@@ -650,7 +650,7 @@ QUnit.test('Missing Required Fields', async function (assert) {
);
assert.containsOnce(
document.body,
'.o_Message_notificationIconContainer',
'.o_Message_notificationIconClickable',
"should display the notification icon container"
);
assert.containsOnce(
@@ -665,7 +665,7 @@ QUnit.test('Missing Required Fields', async function (assert) {
);
await afterNextRender(() => {
document.querySelector('.o_Message_notificationIconContainer').click();
document.querySelector('.o_Message_notificationIconClickable').click();
});
assert.verifySteps(
['do_action'],