summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorParth Choksi <pch@odoo.com>2019-10-23 11:17:03 +0000
committerAlexandre Kühn <aku@odoo.com>2020-01-02 13:38:47 +0000
commite1f4205ef3accbfdcf771ebc9ecb4afd22cbf084 (patch)
treee0998173efa41041b79eabaf139fcf4f7ef8d3cc /addons
parentdc55cc6468bf9d2fddc47cb5f135af7016ed2a50 (diff)
[FIX] mail: reset suggested partner when record saved
Before this commit, when "Send message" composer was open with some suggested recipients, and then editing and saving data related to the suggested recipients, the suggested recipients were not updated on composer until some user interactions like page reload. Steps to reproduce: - Open an opportunity in CRM; - Open "Send message" composer; - Change "Email" field; - Save changes; > Suggested recipient above composer textarea is not updated with newly saved email adress. It becomes updated only after some user interactions, such as toggle "Log note" then "Send message" or with a page reload. This commit fixes the issue by updating the suggested recipients on the composer in real-time when clicking on "Save". Task-Id 2089816 closes odoo/odoo#40033 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com> Co-authored-by: Mohammed Shekha <msh@odoo.com> Co-authored-by: Alexandre Kühn <aku@odoo.com>
Diffstat (limited to 'addons')
-rw-r--r--addons/mail/static/src/js/chatter.js102
-rw-r--r--addons/mail/static/src/js/composers/chatter_composer.js15
-rw-r--r--addons/mail/static/src/js/form_controller.js16
-rw-r--r--addons/mail/static/src/xml/chatter.xml59
-rw-r--r--addons/mail/static/tests/chatter_tests.js56
5 files changed, 176 insertions, 72 deletions
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;
}
},
/**
@@ -265,6 +278,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
+ */
_openAttachmentBox: function () {
if (this.fields.attachments) {
this._closeAttachments();
@@ -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
@@ -14,6 +14,22 @@ FormController.include({
}),
//--------------------------------------------------------------------------
+ // 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
@@ -38,6 +38,38 @@
</div>
<!--
+ Chatter Suggested Partners
+ -->
+ <t t-name="mail.chatter.ComposerSuggestedPartners">
+ <!-- List of followers -->
+ <div class="o_composer_suggested_partners">
+ <t t-foreach='widget.suggestedPartners' t-as='recipient'>
+ <div t-attf-title="Add as recipient and follower (reason: {{recipient.reason}})" t-att-class="recipient_index > 2 ? 'o_suggested_toggle o_hidden' : ''">
+ <div class="custom-control custom-checkbox">
+ <input type="checkbox"
+ class="custom-control-input"
+ t-attf-id="o_composer_suggested_partners_p{{recipient_index}}"
+ t-att-checked="recipient.checked ? 'checked' : undefined"
+ t-att-data-fullname="recipient.full_name"/>
+ <label t-attf-for="o_composer_suggested_partners_p{{recipient_index}}" class="custom-control-label">
+ <t t-esc="recipient.name"/>
+ <t t-if="recipient.email_address">(<t t-esc="recipient.email_address"/>)</t>
+ </label>
+ </div>
+ </div>
+ </t>
+ <t t-if='widget.suggestedPartners.length > 3'>
+ <a href="#" class='o_suggested_show_more_less o_suggested_toggle'>
+ Show <t t-esc="widget.suggestedPartners.length - 3"/> more
+ </a>
+ <a href="#" class='o_suggested_show_more_less o_suggested_toggle o_hidden'>
+ Show <t t-esc="widget.suggestedPartners.length - 3"/> less
+ </a>
+ </t>
+ </div>
+ </t>
+
+ <!--
Chatter composer
@param {mail.composer.Chatter} widget
@@ -61,32 +93,7 @@
</t>
</b>
</small>
- <!-- List of followers -->
- <div class="o_composer_suggested_partners">
- <t t-foreach='widget.suggestedPartners' t-as='recipient'>
- <div t-attf-title="Add as recipient and follower (reason: #{recipient.reason})" t-att-class="recipient_index > 2 ? 'o_suggested_toggle o_hidden' : ''">
- <div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- t-attf-id="o_composer_suggested_partners_p#{recipient_index}"
- t-att-checked="recipient.checked ? 'checked' : undefined"
- t-att-data-fullname="recipient.full_name"/>
- <label t-attf-for="o_composer_suggested_partners_p#{recipient_index}" class="custom-control-label">
- <t t-esc="recipient.name"/>
- <t t-if="recipient.email_address">(<t t-esc="recipient.email_address"/>)</t>
- </label>
- </div>
- </div>
- </t>
- <t t-if='widget.suggestedPartners.length > 3'>
- <a href="#" class='o_suggested_show_more_less o_suggested_toggle'>
- Show <t t-esc="widget.suggestedPartners.length - 3"/> more
- </a>
- <a href="#" class='o_suggested_show_more_less o_suggested_toggle o_hidden'>
- Show <t t-esc="widget.suggestedPartners.length - 3"/> less
- </a>
- </t>
- </div>
+ <t t-call="mail.chatter.ComposerSuggestedPartners"/>
</t>
</t>
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: `
+ <form string="Partners">
+ <sheet>
+ <field name="foo"/>
+ </sheet>
+ <div class="oe_chatter">
+ <field name="message_ids" widget="mail_thread"/>
+ </div>
+ </form>`,
+ 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 = {