diff --git a/addons/mail/static/src/js/chatter.js b/addons/mail/static/src/js/chatter.js index f4c1b126eb7..19f7671a74b 100644 --- a/addons/mail/static/src/js/chatter.js +++ b/addons/mail/static/src/js/chatter.js @@ -63,12 +63,17 @@ var Chatter = Widget.extend({ this._disableAttachmentBox = !!options.disable_attachment_box; this._dp = new concurrency.DropPrevious(); this._isAttachmentBoxOpen = false; + this._isComposerOpen = false; // mention: get the prefetched partners and use them as mention suggestions // if there is a follower widget, the followers will be added to the // suggestions as well once fetched this._mentionPartnerSuggestions = this.call('mail_service', 'getMentionPartnerSuggestions'); this._mentionSuggestions = this._mentionPartnerSuggestions; - this._suggestedPartnersProm = undefined; + /** + * List of fetched suggested partners. This is lazy-loaded on opening + * composer. `undefined` means it should be fetched again. + */ + this._suggestedPartners = undefined; if (mailFields.mail_activity) { this.fields.activity = new Activity(this, mailFields.mail_activity, record, options); @@ -158,6 +163,13 @@ var Chatter = Widget.extend({ }); this._updateAttachmentCounter(); }, + async updateSuggestedPartners() { + this._suggestedPartners = undefined; + if (this._composer && this._isComposerOpen) { + const suggestedPartners = await this._getSuggestedPartners(); + this._composer.updateSuggestedPartners(suggestedPartners); + } + }, //-------------------------------------------------------------------------- // Private @@ -183,6 +195,7 @@ var Chatter = Widget.extend({ this.$('.o_chatter_button_new_message, .o_chatter_button_log_note').removeClass('o_active'); this._composer.do_hide(); this._composer.clearComposer(); + this._isComposerOpen = false; } }, /** @@ -262,6 +275,36 @@ var Chatter = Widget.extend({ }); }, + /** + * @private + */ + async _getSuggestedPartners() { + if (this._suggestedPartners) { + return this._suggestedPartners; + } + const result = await this._rpc({ + route: '/mail/get_suggested_recipients', + params: { + model: this.record.model, + res_ids: [this.context.default_res_id], + }, + }); + const suggestedPartners = []; + const threadRecipients = result[this.context.default_res_id] || []; + for (const recipient of threadRecipients) { + const parsedEmail = recipient[1] && mailUtils.parseEmail(recipient[1]); + suggestedPartners.push({ + checked: true, + partner_id: recipient[0], + full_name: recipient[1], + name: parsedEmail[0], + email_address: parsedEmail[1], + reason: recipient[2], + }); + } + this._suggestedPartners = suggestedPartners; + return this._suggestedPartners; + }, /** * @private */ @@ -285,14 +328,14 @@ var Chatter = Widget.extend({ /** * @private * @param {Object} options - * @param {Object[]} [options.suggested_partners=[]] + * @param {Object[]} [options.suggestedPartners=[]] * @param {boolean} [options.isLog] */ _openComposer: function (options) { var self = this; var oldComposer = this._composer; // create the new composer - this._composer = new ChatterComposer(this, this.record.model, options.suggested_partners || [], { + this._composer = new ChatterComposer(this, this.record.model, options.suggestedPartners || [], { commandsEnabled: false, context: this.context, inputMinHeight: 50, @@ -330,6 +373,7 @@ var Chatter = Widget.extend({ self._composer.on('need_refresh', self, self.trigger_up.bind(self, 'reload')); self._composer.on('close_composer', null, self._closeComposer.bind(self, true)); + self._isComposerOpen = true; self.$el.addClass('o_chatter_composer_active'); self.$('.o_chatter_button_new_message, .o_chatter_button_log_note').removeClass('o_active'); self.$('.o_chatter_button_new_message').toggleClass('o_active', !self._composer.options.isLog); @@ -406,12 +450,6 @@ var Chatter = Widget.extend({ } }).then(always).guardedCatch(always); }, - /** - * @private - */ - _resetSuggestedPartners() { - this._suggestedPartnersProm = undefined; - }, _renderButtons: function () { return QWeb.render('mail.chatter.Buttons', { newMessageButton: !!this.fields.thread, @@ -439,9 +477,9 @@ var Chatter = Widget.extend({ default_res_id: record.res_id || false, default_model: record.model || false, }; - // reset the _suggestedPartnersProm to ensure a reload of the - // suggested partners when opening the composer on another record - this._resetSuggestedPartners(); + // ensure a reload of the suggested partners when + // opening the composer on another record + this._suggestedPartners = undefined; } this.record = record; this.recordName = record.data.display_name; @@ -553,39 +591,11 @@ var Chatter = Widget.extend({ _onDiscardRecordChanges: function (ev) { this._discardChanges().then(ev.data.proceed); }, - _onOpenComposerMessage: function () { - var self = this; - if (!this._suggestedPartnersProm) { - this._suggestedPartnersProm = new Promise(function (resolve, reject) { - self._rpc({ - route: '/mail/get_suggested_recipients', - params: { - model: self.record.model, - res_ids: [self.context.default_res_id], - }, - }).then(function (result) { - if (!self._suggestedPartnersProm) { - return; // widget has been reset (e.g. we just switched to another record) - } - var suggested_partners = []; - var thread_recipients = result[self.context.default_res_id]; - _.each(thread_recipients, function (recipient) { - var parsed_email = recipient[1] && mailUtils.parseEmail(recipient[1]); - suggested_partners.push({ - checked: true, - partner_id: recipient[0], - full_name: recipient[1], - name: parsed_email[0], - email_address: parsed_email[1], - reason: recipient[2], - }); - }); - resolve(suggested_partners); - }); - }); - } - this._suggestedPartnersProm.then(function (suggested_partners) { - self._openComposer({ isLog: false, suggested_partners: suggested_partners }); + async _onOpenComposerMessage() { + const suggestedPartners = await this._getSuggestedPartners(); + this._openComposer({ + isLog: false, + suggestedPartners, }); }, /** @@ -634,7 +644,7 @@ var Chatter = Widget.extend({ */ _onResetSuggestedPartners(ev) { ev.stopPropagation(); - this._resetSuggestedPartners(); + this._suggestedPartners = undefined; }, /** * @private diff --git a/addons/mail/static/src/js/composers/chatter_composer.js b/addons/mail/static/src/js/composers/chatter_composer.js index 04a01142ff3..509212019c9 100644 --- a/addons/mail/static/src/js/composers/chatter_composer.js +++ b/addons/mail/static/src/js/composers/chatter_composer.js @@ -9,6 +9,7 @@ var core = require('web.core'); var viewDialogs = require('web.view_dialogs'); var _t = core._t; +const Qweb = core.qweb; /** * Chat Composer for the Chatter @@ -48,6 +49,20 @@ var ChatterComposer = BasicComposer.extend({ * @override */ _clearComposerOnSend: function () {}, + /** + * Updates suggested partners in DOM + * + * @param {Array} suggestedPartners list of 'recipient' partners + */ + updateSuggestedPartners(suggestedPartners) { + this.suggestedPartners = suggestedPartners; + if (!this.options.isLog) { + const $suggestedPartners = $(Qweb.render('mail.chatter.ComposerSuggestedPartners', { + widget: this, + })); + this.$('.o_composer_suggested_partners').replaceWith($suggestedPartners); + } + }, //-------------------------------------------------------------------------- // Private diff --git a/addons/mail/static/src/js/form_controller.js b/addons/mail/static/src/js/form_controller.js index a165fe850ba..0d4c03d7a64 100644 --- a/addons/mail/static/src/js/form_controller.js +++ b/addons/mail/static/src/js/form_controller.js @@ -13,6 +13,22 @@ FormController.include({ new_message: '_onNewMessage', }), + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * @override + */ + async saveRecord() { + const changedFields = await this._super(...arguments); + const chatter = this.renderer.chatter; + if (chatter) { + await chatter.updateSuggestedPartners(); + } + return changedFields; + }, + //-------------------------------------------------------------------------- // Handlers //-------------------------------------------------------------------------- diff --git a/addons/mail/static/src/xml/chatter.xml b/addons/mail/static/src/xml/chatter.xml index 715157fa43b..9b05b242d73 100644 --- a/addons/mail/static/src/xml/chatter.xml +++ b/addons/mail/static/src/xml/chatter.xml @@ -37,6 +37,38 @@ + + + +
+ +
+
+ + +
+
+
+ + + Show more + + + Show less + + +
+
+ -
- -
-
- - -
-
-
- - - Show more - - - Show less - - -
+ diff --git a/addons/mail/static/tests/chatter_tests.js b/addons/mail/static/tests/chatter_tests.js index 325f16887e9..582d2b6a4b8 100644 --- a/addons/mail/static/tests/chatter_tests.js +++ b/addons/mail/static/tests/chatter_tests.js @@ -3325,6 +3325,62 @@ QUnit.test('chatter: display suggested partners only once', async function (asse form.destroy(); }); +QUnit.test('chatter: suggested recipients reflect saved changes', async function (assert) { + assert.expect(6); + + this.data.partner.records[0].foo = "Marc"; + + let suggestedRecipients = { 2: [[2, "Marc"]] }; + + const form = await createView({ + View: FormView, + model: 'partner', + res_id: 2, + data: this.data, + services: this.services, + arch: ` +
+ + + +
+ +
+
`, + viewOptions: { mode: 'edit' }, + async mockRPC(route, args) { + if (args.model === 'partner' && args.method === 'write') { + const partnerName = args.args[1].foo; + suggestedRecipients = { 2: [[2, partnerName]] }; + } + if (route === '/mail/get_suggested_recipients') { + assert.step('get_suggested_recipients'); + return Promise.resolve(suggestedRecipients); + } + return this._super(route, args); + }, + }); + + await testUtils.dom.click(form.$('.o_chatter_button_new_message')); + assert.strictEqual( + form.$('div.o_composer_suggested_partners label').text().replace(/\s+/g, ''), + "Marc", + "should have the correct original recipient name"); + assert.verifySteps(['get_suggested_recipients'], + 'get_suggested_recipients route should be called'); + + await testUtils.fields.editInput(form.$('.o_field_char'), 'Bob'); + await testUtils.dom.click(form.$('.o_form_button_save')); + assert.verifySteps(['get_suggested_recipients'], + 'get_suggested_recipients route should be called'); + assert.strictEqual( + form.$('div.o_composer_suggested_partners label').text().replace(/\s+/g, ''), + "Bob", + "should have the correct modified recipient name"); + + form.destroy(); +}); + QUnit.module('FieldMany2ManyTagsEmail', { beforeEach: function () { this.data = {