[FIX] mail: fix message unread counter
This PR fixes several issues with the unread counter: - Notifications being considered as unread messages (which is not the case on the server side which resulted in inconsistencies). - Counter greater than it should be when the last seen message is not loaded. - Messages not marked as read on first thread opening. task-3239957 closes odoo/odoo#116208 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { sprintf } from "@web/core/utils/strings";
|
||||
|
||||
import { ScrollPosition } from "@mail/core/scroll_position_model";
|
||||
import { createLocalId } from "../utils/misc";
|
||||
import { Deferred } from "@web/core/utils/concurrency";
|
||||
|
||||
/**
|
||||
* @typedef SeenInfo
|
||||
@@ -55,6 +56,7 @@ export class Thread {
|
||||
isAdmin = false;
|
||||
loadMore = false;
|
||||
isLoadingAttachments = false;
|
||||
isLoadedDeferred = new Deferred();
|
||||
isLoaded = false;
|
||||
/** @type {import("@mail/attachments/attachment_model").Attachment} */
|
||||
mainAttachment;
|
||||
@@ -87,6 +89,8 @@ export class Thread {
|
||||
canPostOnReadonly;
|
||||
/** @type {String} */
|
||||
last_interest_dt;
|
||||
/** @type {number} */
|
||||
lastServerMessageId;
|
||||
|
||||
constructor(store, data) {
|
||||
Object.assign(this, {
|
||||
|
||||
@@ -101,7 +101,10 @@ export class ThreadService {
|
||||
/**
|
||||
* @param {Thread} thread
|
||||
*/
|
||||
markAsRead(thread) {
|
||||
async markAsRead(thread) {
|
||||
if (!thread.isLoaded && thread.status === "loading") {
|
||||
await thread.isLoadedDeferred;
|
||||
}
|
||||
const mostRecentNonTransientMessage = thread.mostRecentNonTransientMessage;
|
||||
if (
|
||||
this.isUnread(thread) &&
|
||||
@@ -486,6 +489,7 @@ export class ThreadService {
|
||||
"last_interest_dt",
|
||||
"defaultDisplayMode",
|
||||
]);
|
||||
thread.lastServerMessageId = serverData.last_message_id ?? thread.lastServerMessageId;
|
||||
if (thread.model === "mail.channel" && serverData.channel) {
|
||||
thread.channel = assignDefined(thread.channel ?? {}, serverData.channel);
|
||||
}
|
||||
@@ -614,6 +618,7 @@ export class ThreadService {
|
||||
return thread;
|
||||
}
|
||||
let thread = new Thread(this.store, data);
|
||||
onChange(thread, "isLoaded", () => thread.isLoadedDeferred.resolve());
|
||||
onChange(thread, "channelMembers", () => this.store.updateBusSubscription());
|
||||
onChange(thread, "is_pinned", () => {
|
||||
if (!thread.is_pinned && this.store.discuss.threadLocalId === thread.localId) {
|
||||
@@ -672,7 +677,8 @@ export class ThreadService {
|
||||
.map((recipient) => recipient.persona.id);
|
||||
partner_ids?.push(...recipientIds);
|
||||
}
|
||||
const tmpId = `${thread.localId}_${new Date().valueOf()}`;
|
||||
const lastMessageId = this.messageService.getLastMessageId();
|
||||
const tmpId = lastMessageId + 0.01;
|
||||
const params = {
|
||||
post_data: {
|
||||
body: await prettifyMessageContent(body, validMentions),
|
||||
@@ -794,12 +800,12 @@ export class ThreadService {
|
||||
*/
|
||||
localMessageUnreadCounter(thread) {
|
||||
let baseCounter = thread.serverMessageUnreadCounter;
|
||||
let countFromId = thread.serverLastSeenMsgBySelf ? thread.serverLastSeenMsgBySelf : 0;
|
||||
let countFromId = thread.lastServerMessageId ? thread.lastServerMessageId : 0;
|
||||
const lastSeenMessageId = this.lastSeenBySelfMessageId(thread);
|
||||
const firstMessage = thread.messages[0];
|
||||
if (firstMessage && lastSeenMessageId && lastSeenMessageId >= firstMessage.id) {
|
||||
if (firstMessage && (lastSeenMessageId === false || lastSeenMessageId >= firstMessage.id)) {
|
||||
baseCounter = 0;
|
||||
countFromId = lastSeenMessageId;
|
||||
countFromId = lastSeenMessageId || 0;
|
||||
}
|
||||
return thread.messages.reduce((total, message) => {
|
||||
if (message.id <= countFromId || message.temporary_id) {
|
||||
|
||||
@@ -334,6 +334,9 @@ patch(MockServer.prototype, "mail/models/mail_message", {
|
||||
["is_read", "=", false],
|
||||
["mail_message_id", "in", messages.map((messages) => messages.id)],
|
||||
]);
|
||||
if (notifications.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.pyEnv["mail.notification"].write(
|
||||
notifications.map((notification) => notification.id),
|
||||
{ is_read: true }
|
||||
|
||||
@@ -269,6 +269,7 @@ QUnit.test(
|
||||
assert.verifySteps(["rpc:channel_fetch"]);
|
||||
|
||||
$(".o-mail-Composer-input")[0].focus();
|
||||
await waitUntil(".o-mail-Message");
|
||||
assert.verifySteps(["rpc:set_last_seen_message"]);
|
||||
}
|
||||
);
|
||||
@@ -951,3 +952,34 @@ QUnit.test(
|
||||
assert.verifySteps([]);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("can be marked as read while loading", async function (assert) {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Demo" });
|
||||
const channelId = pyEnv["mail.channel"].create({
|
||||
channel_member_ids: [
|
||||
[0, 0, { message_unread_counter: 1, partner_id: pyEnv.currentPartnerId }],
|
||||
[0, 0, { partner_id: partnerId }],
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
pyEnv["mail.message"].create({
|
||||
author_id: partnerId,
|
||||
body: "<p>Test</p>",
|
||||
model: "mail.channel",
|
||||
res_id: channelId,
|
||||
});
|
||||
const loadDeferred = makeDeferred();
|
||||
const { openDiscuss } = await start({
|
||||
async mockRPC(route) {
|
||||
if (route === "/mail/channel/messages") {
|
||||
await loadDeferred;
|
||||
}
|
||||
},
|
||||
});
|
||||
await openDiscuss(undefined, { waitUntilMessagesLoaded: false });
|
||||
assert.containsOnce($, ".o-mail-DiscussCategoryItem-counter:contains(1)");
|
||||
await click(".o-mail-DiscussCategoryItem:contains(Demo)");
|
||||
await afterNextRender(loadDeferred.resolve);
|
||||
assert.containsNone($, ".o-mail-DiscussCategoryItem-counter");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user