[FIX] mail: easily mention followers and employees in chatter

Revision on https://github.com/odoo/odoo/commit/cd34f6de727d5b3858420cff3c9d3c5995c4e75c

Resulting of the mail JS refactoring, the list of prefetched suggestions
has been changed as follow:

- before: list of list of mention suggestions `{Array<Object[]>}`
- after: list of mention suggestions `{Object[]}`

The change resulted in wrongly thinking that wrapping the list of
suggestions in a list was pointless, thus simplifying it as a simple
list of mention suggestions.

However, because of this change, it has become much harder to
mention employees and followers of documents from the chatter:
it now always fetches all partner suggestions at all time, whereas
before it was suggesting followers, then employees, and finally all
partners based on the input of the user.

In fact, there was a purpose of using a list of list of prefetched
mention suggestions, which is to group suggestions by "priority":
followers first, then employees, and all partners as a last resort.

This commit re-introduces prefetched mention suggestions as a list
of list of partners, so that it re-becomes easier to mention
followers and partners of a document from the chatter.

Task-ID 1910111
This commit is contained in:
Alexandre Kühn
2018-11-16 13:43:41 +00:00
parent 6f7262f508
commit 9eff26367f
6 changed files with 142 additions and 19 deletions
@@ -211,7 +211,8 @@ var BasicComposer = Widget.extend({
* displayed to the user. If none of them match, then it will fetch for more
* partner suggestions (@see _mentionFetchPartners).
*
* @param {$.Deferred<Object[]>} prefetchedPartners
* @param {$.Deferred<Object[]>} prefetchedPartners list of list of
* prefetched partners.
*/
mentionSetPrefetchedPartners: function (prefetchedPartners) {
this._mentionPrefetchedPartners = prefetchedPartners;
@@ -302,21 +303,23 @@ var BasicComposer = Widget.extend({
*/
_mentionFetchPartners: function (search) {
var self = this;
return $.when(this._mentionPrefetchedPartners).then(function (partners) {
return $.when(this._mentionPrefetchedPartners).then(function (prefetchedPartners) {
// filter prefetched partners with the given search string
var suggestions = [];
var limit = self.options.mentionFetchLimit;
var searchRegexp = new RegExp(_.str.escapeRegExp(mailUtils.unaccent(search)), 'i');
if (limit > 0) {
var filteredPartners = _.filter(partners, function (partner) {
return partner.email && searchRegexp.test(partner.email) ||
partner.name && searchRegexp.test(mailUtils.unaccent(partner.name));
});
if (filteredPartners.length) {
suggestions.push(filteredPartners.slice(0, limit));
limit -= filteredPartners.length;
_.each(prefetchedPartners, function (partners) {
if (limit > 0) {
var filteredPartners = _.filter(partners, function (partner) {
return partner.email && searchRegexp.test(partner.email) ||
partner.name && searchRegexp.test(mailUtils.unaccent(partner.name));
});
if (filteredPartners.length) {
suggestions.push(filteredPartners.slice(0, limit));
limit -= filteredPartners.length;
}
}
}
});
if (!suggestions.length && !self.options.mentionPartnersRestricted) {
// no result found among prefetched partners, fetch other suggestions
suggestions = self._mentionFetchThrottled(
@@ -179,7 +179,8 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
/**
* Get listeners of a channel
*
* @returns {$.Promise<Object[]>} resolved with list of channel listeners
* @returns {$.Promise<Array<Object[]>>} resolved with list of list of
* channel listeners.
*/
getMentionPartnerSuggestions: function () {
var self = this;
@@ -193,7 +194,7 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
})
.then(function (members) {
self._members = members;
return members;
return [members];
});
}
return this._membersDef;
@@ -37,7 +37,8 @@ var Livechat = TwoUserChannel.extend({
* display of a user that is typing.
*
* @override
* @returns {$.Promise<Object[]>} resolved with list of livechat members
* @returns {$.Promise<Array<Object[]>>} resolved with list of list of
* livechat members.
*/
getMentionPartnerSuggestions: function () {
var self = this;
@@ -49,7 +50,7 @@ var Livechat = TwoUserChannel.extend({
name: self._WEBSITE_USER_NAME,
});
}
return self._members;
return [self._members];
});
},
/**
@@ -111,7 +111,7 @@ var Thread = AbstractThread.extend(ServicesMixin, {
* By default, a thread has not listener.
*
* @abstract
* @returns {$.Promise<Object[]>}
* @returns {$.Promise<Array<Object[]>>}
*/
getMentionPartnerSuggestions: function () {
return $.when([]);
@@ -199,7 +199,7 @@ var MailManager = AbstractService.extend({
* Get partners as mentions from a chatter
* Typically all employees as partner suggestions.
*
* @returns {Array<Object[]>}
* @returns {Array<Array<Object[]>>}
*/
getMentionPartnerSuggestions: function () {
return this._mentionPartnerSuggestions;
@@ -1195,8 +1195,8 @@ var MailManager = AbstractService.extend({
*
* @private
* @param {Object} result data from server on mail/init_messaging rpc
* @param {Object[]} result.mention_partner_suggestions list of suggestions
* with all the employees
* @param {Array<Object[]>} result.mention_partner_suggestions list of
* suggestions.
* @param {integer} result.menu_id the menu ID of discuss app
*/
_updateInternalStateFromServer: function (result) {
+118
View File
@@ -2450,6 +2450,124 @@ QUnit.test('chatter: suggested partner auto-follow on message post', function (a
form.destroy();
});
QUnit.test('chatter: mention prefetched partners (followers & employees)', function (assert) {
// Note: employees are in prefeteched partner for mentions in chatter when
// the module hr is installed.
assert.expect(10);
var followerSuggestions = [{
id: 1,
name: 'FollowerUser1',
email: 'follower-user1@example.com',
}, {
id: 2,
name: 'FollowerUser2',
email: 'follower-user2@example.com',
}];
var nonFollowerSuggestions = [{
id: 3,
name: 'NonFollowerUser1',
email: 'non-follower-user1@example.com',
}, {
id: 4,
name: 'NonFollowerUser2',
email: 'non-follower-user2@example.com',
}];
// link followers
this.data.partner.records[0].message_follower_ids = [10, 20];
// prefetched partners
this.data.initMessaging = {
mention_partner_suggestions: [followerSuggestions.concat(nonFollowerSuggestions)],
};
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
services: this.services,
arch: '<form string="Partners">' +
'<sheet>' +
'<field name="foo"/>' +
'</sheet>' +
'<div class="oe_chatter">' +
'<field name="message_follower_ids" widget="mail_followers"/>' +
'<field name="message_ids" widget="mail_thread" options="{\'display_log_button\': True}"/>' +
'</div>' +
'</form>',
res_id: 2,
mockRPC: function (route, args) {
if (route === '/mail/read_followers') {
return $.when({
followers: [{
id: 10,
name: 'FollowerUser1',
email: 'follower-user1@example.com',
res_model: 'res.partner',
res_id: 1,
}, {
id: 20,
name: 'FollowerUser2',
email: 'follower-user2@example.com',
res_model: 'res.partner',
res_id: 2,
}],
subtypes: [],
});
}
if (args.method === 'message_get_suggested_recipients') {
return $.when({2: []});
}
if (args.method === 'get_mention_suggestions') {
throw new Error('should not fetch partners for mentions');
}
return this._super(route, args);
},
session: {},
});
assert.strictEqual(form.$('.o_followers_count').text(), '2',
"should have two followers of this document");
assert.strictEqual(form.$('.o_followers_list > .o_partner').text().replace(/\s+/g, ''),
'FollowerUser1FollowerUser2',
"should have correct follower names");
assert.strictEqual(form.$('.o_composer_mention_dropdown').length, 0,
"should not show the mention suggestion dropdown");
form.$('.o_chatter_button_new_message').click();
var $input = form.$('.oe_chatter .o_composer_text_field:first()');
$input.val('@');
// the cursor position must be set for the mention manager to detect that we are mentionning
$input[0].selectionStart = 1;
$input[0].selectionEnd = 1;
$input.trigger('keyup');
assert.strictEqual(form.$('.o_composer_mention_dropdown').length, 1,
"should show the mention suggestion dropdown");
assert.strictEqual(form.$('.o_mention_proposition').length, 4,
"should show 4 mention suggestions");
assert.strictEqual(form.$('.o_mention_proposition').eq(0).text().replace(/\s+/g, ''),
"FollowerUser1(follower-user1@example.com)",
"should display correct 1st mention suggestion");
assert.strictEqual(form.$('.o_mention_proposition').eq(1).text().replace(/\s+/g, ''),
"FollowerUser2(follower-user2@example.com)",
"should display correct 2nd mention suggestion");
assert.ok(form.$('.o_mention_proposition').eq(1).next().hasClass('dropdown-divider'),
"should have a mention separator after last follower mention suggestion");
assert.strictEqual(form.$('.o_mention_proposition').eq(2).text().replace(/\s+/g, ''),
"NonFollowerUser1(non-follower-user1@example.com)",
"should display correct 3rd mention suggestion");
assert.strictEqual(form.$('.o_mention_proposition').eq(3).text().replace(/\s+/g, ''),
"NonFollowerUser2(non-follower-user2@example.com)",
"should display correct 4th mention suggestion");
//cleanup
form.destroy();
});
QUnit.module('FieldMany2ManyTagsEmail', {
beforeEach: function () {
this.data = {