[FIX] {im, website}_livechat: fix discuss sidebar test
Since [1], the test that ensures live chat threads are sorted according to their last interrest date is broken. Indeed, the sort was moved from `im_livechat` to `website_livechat`. This is incorrect. Also, most of the compare functions used to sort by datetime were incorrect: those datetimes can be undefined in which case the result of the compare function would be `NaN`. This PR moves back the sort function in the correct module and introduce a standard way to compare by datetime which handles undefined datetimes correctly. [1]: https://github.com/odoo/odoo/pull/143382 fixes runbot-47784 closes odoo/odoo#146805 Related: odoo/enterprise#53065 Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
+4
-1
@@ -2,6 +2,7 @@
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { DiscussAppCategory } from "@mail/core/common/discuss_app_category_model";
|
||||
import { compareDatetime } from "@mail/utils/common/misc";
|
||||
|
||||
patch(DiscussAppCategory.prototype, {
|
||||
/**
|
||||
@@ -10,7 +11,9 @@ patch(DiscussAppCategory.prototype, {
|
||||
*/
|
||||
sortThreads(t1, t2) {
|
||||
if (this.id === "livechat") {
|
||||
return t2.lastInterestDateTime?.ts - t1.lastInterestDateTime?.ts;
|
||||
return (
|
||||
compareDatetime(t2.lastInterestDateTime, t1.lastInterestDateTime) || t2.id - t1.id
|
||||
);
|
||||
}
|
||||
return super.sortThreads(t1, t2);
|
||||
},
|
||||
@@ -1,6 +1,7 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { ThreadService } from "@mail/core/common/thread_service";
|
||||
import { compareDatetime } from "@mail/utils/common/misc";
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
@@ -33,7 +34,8 @@ patch(ThreadService.prototype, {
|
||||
super.sortChannels();
|
||||
// Live chats are sorted by most recent interest date time in the sidebar.
|
||||
this.store.discuss.livechat.threads.sort(
|
||||
(t1, t2) => t2.lastInterestDateTime?.ts - t1.lastInterestDateTime?.ts
|
||||
(t1, t2) =>
|
||||
compareDatetime(t2.lastInterestDateTime, t1.lastInterestDateTime) || t2.id - t1.id
|
||||
);
|
||||
},
|
||||
|
||||
@@ -43,7 +45,11 @@ patch(ThreadService.prototype, {
|
||||
goToOldestUnreadLivechatThread() {
|
||||
const oldestUnreadThread = this.store.discuss.livechat.threads
|
||||
.filter((thread) => thread.isUnread)
|
||||
.sort((t1, t2) => t1.lastInterestDateTime?.ts - t2.lastInterestDateTime?.ts)[0];
|
||||
.sort(
|
||||
(t1, t2) =>
|
||||
compareDatetime(t1.lastInterestDateTime, t2.lastInterestDateTime) ||
|
||||
t1.id - t2.id
|
||||
)[0];
|
||||
if (!oldestUnreadThread) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { compareDatetime } from "@mail/utils/common/misc";
|
||||
import { Record } from "./record";
|
||||
|
||||
export class DiscussAppCategory extends Record {
|
||||
@@ -22,7 +23,9 @@ export class DiscussAppCategory extends Record {
|
||||
return String.prototype.localeCompare.call(t1.name, t2.name);
|
||||
}
|
||||
if (this.id === "chats") {
|
||||
return t2.lastInterestDateTime.ts - t1.lastInterestDateTime.ts;
|
||||
return (
|
||||
compareDatetime(t2.lastInterestDateTime, t1.lastInterestDateTime) || t2.id - t1.id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { registry } from "@web/core/registry";
|
||||
import { useSequential } from "@mail/utils/common/hooks";
|
||||
import { markRaw } from "@odoo/owl";
|
||||
import { compareDatetime } from "@mail/utils/common/misc";
|
||||
|
||||
export const DEFAULT_AVATAR = "/mail/static/src/img/smiley/avatar.jpg";
|
||||
|
||||
@@ -83,19 +84,10 @@ export class PersonaService {
|
||||
getRecentChatPartnerIds() {
|
||||
return Object.values(this.store.Thread.records)
|
||||
.filter((thread) => thread.type === "chat")
|
||||
.sort((a, b) => {
|
||||
const [a_dt , b_dt] = [a.lastInterestDateTime, b.lastInterestDateTime]
|
||||
if (!a_dt && !b_dt) {
|
||||
return 0;
|
||||
}
|
||||
if (a_dt && !b_dt) {
|
||||
return -1;
|
||||
}
|
||||
if (!a_dt && b_dt) {
|
||||
return 1;
|
||||
}
|
||||
return b_dt.ts - a_dt.ts;
|
||||
})
|
||||
.sort(
|
||||
(a, b) =>
|
||||
compareDatetime(b.lastInterestDateTime, a.lastInterestDateTime) || b.id - a.id
|
||||
)
|
||||
.map((thread) => thread.chatPartner?.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { registry } from "@web/core/registry";
|
||||
import { memoize } from "@web/core/utils/functions";
|
||||
import { url } from "@web/core/utils/urls";
|
||||
import { escape } from "@web/core/utils/strings";
|
||||
import { compareDatetime } from "@mail/utils/common/misc";
|
||||
|
||||
const FETCH_LIMIT = 30;
|
||||
|
||||
@@ -429,7 +430,8 @@ export class ThreadService {
|
||||
String.prototype.localeCompare.call(t1.name, t2.name)
|
||||
);
|
||||
this.store.discuss.chats.threads.sort(
|
||||
(t1, t2) => t2.lastInterestDateTime.ts - t1.lastInterestDateTime.ts
|
||||
(t1, t2) =>
|
||||
compareDatetime(t2.lastInterestDateTime, t1.lastInterestDateTime) || t2.id - t1.id
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { parseEmail } from "@mail/js/utils";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { Record } from "@mail/core/common/record";
|
||||
import { compareDatetime } from "@mail/utils/common/misc";
|
||||
|
||||
let nextId = 1;
|
||||
|
||||
@@ -241,18 +242,10 @@ patch(ThreadService.prototype, {
|
||||
getRecentChannels() {
|
||||
return Object.values(this.store.Thread.records)
|
||||
.filter((thread) => thread.model === "discuss.channel")
|
||||
.sort((a, b) => {
|
||||
if (a.lastInterestDateTime?.ts !== b.lastInterestDateTime?.ts) {
|
||||
if (!b.lastInterestDateTime) {
|
||||
return -1;
|
||||
}
|
||||
if (!a.lastInterestDateTime) {
|
||||
return 1;
|
||||
}
|
||||
return b.lastInterestDateTime.ts - a.lastInterestDateTime.ts;
|
||||
}
|
||||
return a.id - b.id;
|
||||
});
|
||||
.sort(
|
||||
(a, b) =>
|
||||
compareDatetime(b.lastInterestDateTime, a.lastInterestDateTime) || b.id - a.id
|
||||
);
|
||||
},
|
||||
getNeedactionChannels() {
|
||||
return this.getRecentChannels().filter((channel) => this.getCounter(channel) > 0);
|
||||
|
||||
@@ -69,3 +69,24 @@ export function onChange(target, key, callback) {
|
||||
export function closeStream(stream) {
|
||||
stream?.getTracks?.().forEach((track) => track.stop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two Luxon datetime.
|
||||
*
|
||||
* @param {import("@web/core/l10n/dates").NullableDateTime} date1
|
||||
* @param {import("@web/core/l10n/dates").NullableDateTime} date2
|
||||
* @returns {number} Negative if date1 is less than date2, positive if date1 is
|
||||
* greater than date2, and 0 if they are equal.
|
||||
*/
|
||||
export function compareDatetime(date1, date2) {
|
||||
if (date1?.ts === date2?.ts) {
|
||||
return 0;
|
||||
}
|
||||
if (!date1) {
|
||||
return -1;
|
||||
}
|
||||
if (!date2) {
|
||||
return 1;
|
||||
}
|
||||
return date1.ts - date2.ts;
|
||||
}
|
||||
|
||||
@@ -78,12 +78,16 @@ QUnit.test("Sort partner suggestions by recent chats", async () => {
|
||||
{ partner_id: partner_3 },
|
||||
]);
|
||||
pyEnv["discuss.channel"].create([
|
||||
{ name: "General", channel_type: "channel", channel_member_ids: [
|
||||
Command.create({ partner_id: pyEnv.currentPartnerId }),
|
||||
Command.create({ partner_id: partner_1 }),
|
||||
Command.create({ partner_id: partner_2 }),
|
||||
Command.create({ partner_id: partner_3 }),
|
||||
]},
|
||||
{
|
||||
name: "General",
|
||||
channel_type: "channel",
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: pyEnv.currentPartnerId }),
|
||||
Command.create({ partner_id: partner_1 }),
|
||||
Command.create({ partner_id: partner_2 }),
|
||||
Command.create({ partner_id: partner_3 }),
|
||||
],
|
||||
},
|
||||
{
|
||||
channel_member_ids: [
|
||||
Command.create({
|
||||
@@ -126,8 +130,8 @@ QUnit.test("Sort partner suggestions by recent chats", async () => {
|
||||
await insertText(".o-mail-Composer-input", "User");
|
||||
await contains(".o-mail-Composer-suggestion strong", { count: 3 });
|
||||
await contains(":nth-child(1 of .o-mail-Composer-suggestion) strong", { text: "User 2" });
|
||||
await contains(":nth-child(2 of .o-mail-Composer-suggestion) strong", { text: "User 1" });
|
||||
await contains(":nth-child(3 of .o-mail-Composer-suggestion) strong", { text: "User 3" });
|
||||
await contains(":nth-child(2 of .o-mail-Composer-suggestion) strong", { text: "User 3" });
|
||||
await contains(":nth-child(3 of .o-mail-Composer-suggestion) strong", { text: "User 1" });
|
||||
});
|
||||
|
||||
QUnit.test("mention suggestion are shown after deleting a character", async () => {
|
||||
|
||||
@@ -59,10 +59,10 @@ QUnit.test("open the chatWindow of a channel from the command palette", async ()
|
||||
await insertText(".o_command_palette_search input", "#");
|
||||
advanceTime(commandSetupRegistry.get("#").debounceDelay);
|
||||
await contains(".o_command", { count: 2 });
|
||||
await contains(".o_command", { text: "general", before: [".o_command", { text: "project" }] });
|
||||
await contains(".o_command", { text: "project", before: [".o_command", { text: "general" }] });
|
||||
await contains(".o_command.focused");
|
||||
await click(".o_command.focused", { text: "general" });
|
||||
await contains(".o-mail-ChatWindow", { text: "general" });
|
||||
await click(".o_command.focused", { text: "project" });
|
||||
await contains(".o-mail-ChatWindow", { text: "project" });
|
||||
});
|
||||
|
||||
QUnit.test("Channel mentions in the command palette of Discuss app with @", async () => {
|
||||
|
||||
Reference in New Issue
Block a user