[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:
@@ -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'],
|
||||
|
||||
Reference in New Issue
Block a user