From 12152279a5d08739959d900bfd4c6936ca39d64b Mon Sep 17 00:00:00 2001 From: tsm-odoo Date: Fri, 14 Jul 2023 12:47:05 +0000 Subject: [PATCH] [IMP] mail: add a registry for partner suggestion sort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .../static/src/core/common/partner_compare.js | 95 ++++++++++++++++ .../src/core/common/suggestion_service.js | 106 ++---------------- .../discuss/core/common/partner_compare.js | 43 +++++++ 3 files changed, 150 insertions(+), 94 deletions(-) create mode 100644 addons/mail/static/src/core/common/partner_compare.js create mode 100644 addons/mail/static/src/discuss/core/common/partner_compare.js diff --git a/addons/mail/static/src/core/common/partner_compare.js b/addons/mail/static/src/core/common/partner_compare.js new file mode 100644 index 00000000000..1df99104764 --- /dev/null +++ b/addons/mail/static/src/core/common/partner_compare.js @@ -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 } +); diff --git a/addons/mail/static/src/core/common/suggestion_service.js b/addons/mail/static/src/core/common/suggestion_service.js index 32d2dc2ff3c..f9ccda4ef3c 100644 --- a/addons/mail/static/src/core/common/suggestion_service.js +++ b/addons/mail/static/src/core/common/suggestion_service.js @@ -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; }); } diff --git a/addons/mail/static/src/discuss/core/common/partner_compare.js b/addons/mail/static/src/discuss/core/common/partner_compare.js new file mode 100644 index 00000000000..3a1ef0bd48e --- /dev/null +++ b/addons/mail/static/src/discuss/core/common/partner_compare.js @@ -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 } +);