summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/models/thread/thread.js
diff options
context:
space:
mode:
authorXavier Dubuc <xdu@odoo.com>2021-03-10 16:45:49 +0000
committerSébastien Theys <seb@odoo.com>2021-03-10 16:48:19 +0000
commitfbdec5fe29827b88ec0d1421f68716e1febefd89 (patch)
treeafbbc6fd6da16ace2af4c2992678657b814d0197 /addons/mail/static/src/models/thread/thread.js
parentf326ba2d14e4fdd811426c6381b7e5bc3c1d657b (diff)
[FIX] mail; hr: restore faster and more accurate mention suggestions
The code from v13 used to look for partners in JS before making the RPC, which was much faster, and also gave better results by returning partners that were already known and therefore more likely to be selected. The same logic is reintroduced here, and further improved to take into account all known partners and sort them according to the likeliness they will be selected based on various criteria. task-2413776 closes odoo/odoo#64161 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com> Co-authored-by: Sébastien Theys <seb@odoo.com>
Diffstat (limited to 'addons/mail/static/src/models/thread/thread.js')
-rw-r--r--addons/mail/static/src/models/thread/thread.js121
1 files changed, 121 insertions, 0 deletions
diff --git a/addons/mail/static/src/models/thread/thread.js b/addons/mail/static/src/models/thread/thread.js
index 4739e59f91e..1011eec4453 100644
--- a/addons/mail/static/src/models/thread/thread.js
+++ b/addons/mail/static/src/models/thread/thread.js
@@ -6,6 +6,7 @@ const { attr, many2many, many2one, one2many, one2one } = require('mail/static/sr
const { clear } = require('mail/static/src/model/model_field_command.js');
const throttle = require('mail/static/src/utils/throttle/throttle.js');
const Timer = require('mail/static/src/utils/timer/timer.js');
+const { cleanSearchTerm } = require('mail/static/src/utils/utils.js');
const mailUtils = require('mail.utils');
function factory(dependencies) {
@@ -274,6 +275,82 @@ function factory(dependencies) {
}
/**
+ * Fetches threads matching the given composer search state to extend
+ * the JS knowledge and to update the suggestion list accordingly.
+ * More specifically only thread of model 'mail.channel' are fetched.
+ *
+ * @static
+ * @param {string} searchTerm
+ * @param {Object} [options={}]
+ * @param {mail.thread} [options.thread] prioritize and/or restrict
+ * result in the context of given thread
+ */
+ static async fetchSuggestions(searchTerm, { thread } = {}) {
+ const channelsData = await this.env.services.rpc(
+ {
+ model: 'mail.channel',
+ method: 'get_mention_suggestions',
+ kwargs: { search: searchTerm },
+ },
+ { shadow: true },
+ );
+ this.env.models['mail.thread'].insert(channelsData.map(channelData =>
+ Object.assign(
+ { model: 'mail.channel' },
+ this.env.models['mail.thread'].convertData(channelData),
+ )
+ ));
+ }
+
+ /**
+ * Returns a sort function to determine the order of display of threads
+ * in the suggestion list.
+ *
+ * @static
+ * @param {string} searchTerm
+ * @param {Object} [options={}]
+ * @param {mail.thread} [options.thread] prioritize result in the
+ * context of given thread
+ * @returns {function}
+ */
+ static getSuggestionSortFunction(searchTerm, { thread } = {}) {
+ const cleanedSearchTerm = cleanSearchTerm(searchTerm);
+ return (a, b) => {
+ const isAPublic = a.model === 'mail.channel' && a.public === 'public';
+ const isBPublic = b.model === 'mail.channel' && b.public === 'public';
+ if (isAPublic && !isBPublic) {
+ return -1;
+ }
+ if (!isAPublic && isBPublic) {
+ return 1;
+ }
+ const isMemberOfA = a.model === 'mail.channel' && a.members.includes(this.env.messaging.currentPartner);
+ const isMemberOfB = b.model === 'mail.channel' && b.members.includes(this.env.messaging.currentPartner);
+ if (isMemberOfA && !isMemberOfB) {
+ return -1;
+ }
+ if (!isMemberOfA && isMemberOfB) {
+ return 1;
+ }
+ const cleanedAName = cleanSearchTerm(a.name || '');
+ const cleanedBName = cleanSearchTerm(b.name || '');
+ if (cleanedAName.startsWith(cleanedSearchTerm) && !cleanedBName.startsWith(cleanedSearchTerm)) {
+ return -1;
+ }
+ if (!cleanedAName.startsWith(cleanedSearchTerm) && cleanedBName.startsWith(cleanedSearchTerm)) {
+ return 1;
+ }
+ if (cleanedAName < cleanedBName) {
+ return -1;
+ }
+ if (cleanedAName > cleanedBName) {
+ return 1;
+ }
+ return a.id - b.id;
+ };
+ }
+
+ /**
* Load the previews of the specified threads. Basically, it fetches the
* last messages, since they are used to display inline content of them.
*
@@ -542,6 +619,41 @@ function factory(dependencies) {
}
}
+ /*
+ * Returns threads that match the given search term. More specially only
+ * threads of model 'mail.channel' are suggested, and if the context
+ * thread is a private channel, only itself is returned if it matches
+ * the search term.
+ *
+ * @static
+ * @param {string} searchTerm
+ * @param {Object} [options={}]
+ * @param {mail.thread} [options.thread] prioritize and/or restrict
+ * result in the context of given thread
+ * @returns {[mail.threads[], mail.threads[]]}
+ */
+ static searchSuggestions(searchTerm, { thread } = {}) {
+ let threads;
+ if (thread && thread.model === 'mail.channel' && thread.public !== 'public') {
+ // Only return the current channel when in the context of a
+ // non-public channel. Indeed, the message with the mention
+ // would appear in the target channel, so this prevents from
+ // inadvertently leaking the private message into the mentioned
+ // channel.
+ threads = [thread];
+ } else {
+ threads = this.env.models['mail.thread'].all();
+ }
+ const cleanedSearchTerm = cleanSearchTerm(searchTerm);
+ return [threads.filter(thread =>
+ !thread.isTemporary &&
+ thread.model === 'mail.channel' &&
+ thread.channel_type === 'channel' &&
+ thread.name &&
+ cleanSearchTerm(thread.name).includes(cleanedSearchTerm)
+ )];
+ }
+
/**
* @param {string} [stringifiedDomain='[]']
* @returns {mail.thread_cache}
@@ -609,6 +721,15 @@ function factory(dependencies) {
}
/**
+ * Returns the text that identifies this thread in a mention.
+ *
+ * @returns {string}
+ */
+ getMentionText() {
+ return this.name;
+ }
+
+ /**
* Load new messages on the main cache of this thread.
*/
loadNewMessages() {