[IMP] mail: add a registry for partner suggestion sort

Before this PR there was no way to add a sort criteria to the
partner suggestions. This commit introduce a registry of compare
functions that can be arranged thanks to a sequence key. This way,
it will be very easy to add custom sort criteria.

part of task-3332872

closes odoo/odoo#128570

Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
tsm-odoo
2023-07-17 12:06:04 +02:00
committed by Alexandre Kühn
parent 4da1e0e0f0
commit 12152279a5
3 changed files with 150 additions and 94 deletions
@@ -0,0 +1,95 @@
/* @odoo-module */
import { cleanTerm } from "@mail/utils/common/format";
import { registry } from "@web/core/registry";
/**
* Registry of functions to sort partner suggestions.
* The expected value is a function with the following
* signature:
* (partner1: Partner, partner2: Partner, { env: OdooEnv, searchTerm: string, thread?: Thread }) => number|undefined
*/
export const partnerCompareRegistry = registry.category("mail.partner_compare");
partnerCompareRegistry.add(
"mail.internal-users",
(p1, p2) => {
const isAInternalUser = p1.user?.isInternalUser;
const isBInternalUser = p2.user?.isInternalUser;
if (isAInternalUser && !isBInternalUser) {
return -1;
}
if (!isAInternalUser && isBInternalUser) {
return 1;
}
},
{ sequence: 10 }
);
partnerCompareRegistry.add(
"mail.followers",
(p1, p2, { thread }) => {
if (thread) {
const followerList = [...thread.followers];
const isFollower1 = followerList.some((follower) => follower.partner === p1);
const isFollower2 = followerList.some((follower) => follower.partner === p2);
if (isFollower1 && !isFollower2) {
return -1;
}
if (!isFollower1 && isFollower2) {
return 1;
}
}
},
{ sequence: 20 }
);
partnerCompareRegistry.add(
"mail.name",
(p1, p2, { searchTerm }) => {
const cleanedName1 = cleanTerm(p1.name ?? "");
const cleanedName2 = cleanTerm(p2.name ?? "");
if (cleanedName1.startsWith(searchTerm) && !cleanedName2.startsWith(searchTerm)) {
return -1;
}
if (!cleanedName1.startsWith(searchTerm) && cleanedName2.startsWith(searchTerm)) {
return 1;
}
if (cleanedName1 < cleanedName2) {
return -1;
}
if (cleanedName1 > cleanedName2) {
return 1;
}
},
{ sequence: 25 }
);
partnerCompareRegistry.add(
"mail.email",
(p1, p2, { searchTerm }) => {
const cleanedEmail1 = cleanTerm(p1.email ?? "");
const cleanedEmail2 = cleanTerm(p2.email ?? "");
if (cleanedEmail1.startsWith(searchTerm) && !cleanedEmail1.startsWith(searchTerm)) {
return -1;
}
if (!cleanedEmail2.startsWith(searchTerm) && cleanedEmail2.startsWith(searchTerm)) {
return 1;
}
if (cleanedEmail1 < cleanedEmail2) {
return -1;
}
if (cleanedEmail1 > cleanedEmail2) {
return 1;
}
},
{ sequence: 30 }
);
partnerCompareRegistry.add(
"mail.id",
(p1, p2) => {
return p1.id - p2.id;
},
{ sequence: 50 }
);
@@ -1,11 +1,14 @@
/* @odoo-module */
import { partnerCompareRegistry } from "@mail/core/common/partner_compare";
import { cleanTerm } from "@mail/utils/common/format";
import { registry } from "@web/core/registry";
export class SuggestionService {
constructor(env, services) {
/** @type {import("@web/env").OdooEnv} env */
this.env = env;
this.orm = services.orm;
/** @type {import("@mail/core/common/store_service").Store} */
this.store = services["mail.store"];
@@ -162,103 +165,18 @@ export class SuggestionService {
*/
sortPartnerSuggestions(partners, searchTerm = "", thread = undefined) {
const cleanedSearchTerm = cleanTerm(searchTerm);
/**
* Ordering:
* - recent chat partners
* - internal users
* - channel members
* - thread followers
* - longgest match of name, alphabetically if having same length of match
* - longgest match of email, alphabetically if having same length of match
* - id
*/
const compareFunctions = partnerCompareRegistry.getAll();
return partners.sort((p1, p2) => {
const recentChatPartnerIds = this.personaService.getRecentChatPartnerIds();
const recentChatIndex_p1 = recentChatPartnerIds.findIndex(
(partnerId) => partnerId === p1.id
);
const recentChatIndex_p2 = recentChatPartnerIds.findIndex(
(partnerId) => partnerId === p2.id
);
if (recentChatIndex_p1 !== -1 && recentChatIndex_p2 === -1) {
return -1;
} else if (recentChatIndex_p1 === -1 && recentChatIndex_p2 !== -1) {
return 1;
} else if (recentChatIndex_p1 < recentChatIndex_p2) {
return -1;
} else if (recentChatIndex_p1 > recentChatIndex_p2) {
return 1;
}
const isAInternalUser = p1.user?.isInternalUser;
const isBInternalUser = p2.user?.isInternalUser;
if (isAInternalUser && !isBInternalUser) {
return -1;
}
if (!isAInternalUser && isBInternalUser) {
return 1;
}
if (thread?.model === "discuss.channel") {
const isMember1 = thread.channelMembers.some((member) => member.persona === p1);
const isMember2 = thread.channelMembers.some((member) => member.persona === p2);
if (isMember1 && !isMember2) {
return -1;
}
if (!isMember1 && isMember2) {
return 1;
for (const fn of compareFunctions) {
const result = fn(p1, p2, {
env: this.env,
searchTerms: cleanedSearchTerm,
thread,
});
if (result !== undefined) {
return result;
}
}
if (thread) {
const followerList = [...thread.followers];
const isFollower1 = followerList.some((follower) => follower.partner === p1);
const isFollower2 = followerList.some((follower) => follower.partner === p2);
if (isFollower1 && !isFollower2) {
return -1;
}
if (!isFollower1 && isFollower2) {
return 1;
}
}
const cleanedName1 = cleanTerm(p1.name ?? "");
const cleanedName2 = cleanTerm(p2.name ?? "");
if (
cleanedName1.startsWith(cleanedSearchTerm) &&
!cleanedName2.startsWith(cleanedSearchTerm)
) {
return -1;
}
if (
!cleanedName1.startsWith(cleanedSearchTerm) &&
cleanedName2.startsWith(cleanedSearchTerm)
) {
return 1;
}
if (cleanedName1 < cleanedName2) {
return -1;
}
if (cleanedName1 > cleanedName2) {
return 1;
}
const cleanedEmail1 = cleanTerm(p1.email ?? "");
const cleanedEmail2 = cleanTerm(p2.email ?? "");
if (
cleanedEmail1.startsWith(cleanedSearchTerm) &&
!cleanedEmail1.startsWith(cleanedSearchTerm)
) {
return -1;
}
if (
!cleanedEmail2.startsWith(cleanedSearchTerm) &&
cleanedEmail2.startsWith(cleanedSearchTerm)
) {
return 1;
}
if (cleanedEmail1 < cleanedEmail2) {
return -1;
}
if (cleanedEmail1 > cleanedEmail2) {
return 1;
}
return p1.id - p2.id;
});
}
@@ -0,0 +1,43 @@
/* @odoo-module */
import { partnerCompareRegistry } from "@mail/core/common/partner_compare";
partnerCompareRegistry.add(
"discuss.recent-chats",
(p1, p2, { env }) => {
const recentChatPartnerIds = env.services["mail.persona"].getRecentChatPartnerIds();
const recentChatIndex_p1 = recentChatPartnerIds.findIndex(
(partnerId) => partnerId === p1.id
);
const recentChatIndex_p2 = recentChatPartnerIds.findIndex(
(partnerId) => partnerId === p2.id
);
if (recentChatIndex_p1 !== -1 && recentChatIndex_p2 === -1) {
return -1;
} else if (recentChatIndex_p1 === -1 && recentChatIndex_p2 !== -1) {
return 1;
} else if (recentChatIndex_p1 < recentChatIndex_p2) {
return -1;
} else if (recentChatIndex_p1 > recentChatIndex_p2) {
return 1;
}
},
{ sequence: 0 }
);
partnerCompareRegistry.add(
"discuss.members",
(p1, p2, { thread }) => {
if (thread?.model === "discuss.channel") {
const isMember1 = thread.channelMembers.some((member) => member.persona === p1);
const isMember2 = thread.channelMembers.some((member) => member.persona === p2);
if (isMember1 && !isMember2) {
return -1;
}
if (!isMember1 && isMember2) {
return 1;
}
}
},
{ sequence: 15 }
);