diff --git a/addons/mail/static/src/components/chatter/chatter.xml b/addons/mail/static/src/components/chatter/chatter.xml
index f630eaf7634..ad5751cdbb0 100644
--- a/addons/mail/static/src/components/chatter/chatter.xml
+++ b/addons/mail/static/src/components/chatter/chatter.xml
@@ -17,7 +17,6 @@
hasTextInputSendOnEnterEnabled="false"
isCompact="false"
isExpandable="true"
- isLog="chatter.isComposerLog"
t-on-o-message-posted="_onComposerMessagePosted"
t-ref="composer"
/>
diff --git a/addons/mail/static/src/components/chatter_topbar/chatter_topbar.js b/addons/mail/static/src/components/chatter_topbar/chatter_topbar.js
index c4b088b7709..37b28b4970e 100644
--- a/addons/mail/static/src/components/chatter_topbar/chatter_topbar.js
+++ b/addons/mail/static/src/components/chatter_topbar/chatter_topbar.js
@@ -23,6 +23,7 @@ class ChatterTopbar extends Component {
return {
areThreadAttachmentsLoaded: thread && thread.areAttachmentsLoaded,
chatter: chatter ? chatter.__state : undefined,
+ composer: chatter && chatter.composer ? chatter.composer.__state : undefined,
threadAttachmentsAmount: threadAttachments.length,
};
});
@@ -66,7 +67,10 @@ class ChatterTopbar extends Component {
* @param {MouseEvent} ev
*/
_onClickLogNote(ev) {
- if (this.chatter.isComposerVisible && this.chatter.isComposerLog) {
+ if (!this.chatter.composer) {
+ return;
+ }
+ if (this.chatter.isComposerVisible && this.chatter.composer.isLog) {
this.chatter.update({ isComposerVisible: false });
} else {
this.chatter.showLogNote();
@@ -106,7 +110,10 @@ class ChatterTopbar extends Component {
* @param {MouseEvent} ev
*/
_onClickSendMessage(ev) {
- if (this.chatter.isComposerVisible && !this.chatter.isComposerLog) {
+ if (!this.chatter.composer) {
+ return;
+ }
+ if (this.chatter.isComposerVisible && !this.chatter.composer.isLog) {
this.chatter.update({ isComposerVisible: false });
} else {
this.chatter.showSendMessage();
diff --git a/addons/mail/static/src/components/chatter_topbar/chatter_topbar.xml b/addons/mail/static/src/components/chatter_topbar/chatter_topbar.xml
index 67dfe4ea844..3512f93332e 100644
--- a/addons/mail/static/src/components/chatter_topbar/chatter_topbar.xml
+++ b/addons/mail/static/src/components/chatter_topbar/chatter_topbar.xml
@@ -9,7 +9,7 @@
diff --git a/addons/mail/static/src/components/composer/composer_tests.js b/addons/mail/static/src/components/composer/composer_tests.js
index e506e99a48e..c62242360a6 100644
--- a/addons/mail/static/src/components/composer/composer_tests.js
+++ b/addons/mail/static/src/components/composer/composer_tests.js
@@ -58,12 +58,87 @@ QUnit.module('composer_tests.js', {
},
});
-QUnit.test('composer text input: basic rendering', async function (assert) {
+QUnit.test('composer text input: basic rendering when posting a message', async function (assert) {
assert.expect(5);
await this.start();
- const composer = this.env.models['mail.composer'].create();
- await this.createComposerComponent(composer);
+ const thread = this.env.models['mail.thread'].create({
+ composer: [['create', { isLog: false }]],
+ id: 20,
+ model: 'res.partner',
+ });
+ await this.createComposerComponent(thread.composer);
+ assert.strictEqual(
+ document.querySelectorAll('.o_Composer').length,
+ 1,
+ "should have composer in discuss thread"
+ );
+ assert.strictEqual(
+ document.querySelectorAll('.o_Composer_textInput').length,
+ 1,
+ "should have text input inside discuss thread composer"
+ );
+ assert.ok(
+ document.querySelector('.o_Composer_textInput').classList.contains('o_ComposerTextInput'),
+ "composer text input of composer should be a ComposerTextIput component"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_ComposerTextInput_textarea`).length,
+ 1,
+ "should have editable part inside composer text input"
+ );
+ assert.strictEqual(
+ document.querySelector(`.o_ComposerTextInput_textarea`).placeholder,
+ "Send a message to followers...",
+ "should have 'Send a message to followers...' as placeholder composer text input"
+ );
+});
+
+QUnit.test('composer text input: basic rendering when logging note', async function (assert) {
+ assert.expect(5);
+
+ await this.start();
+ const thread = this.env.models['mail.thread'].create({
+ composer: [['create', { isLog: true }]],
+ id: 20,
+ model: 'res.partner',
+ });
+ await this.createComposerComponent(thread.composer);
+ assert.strictEqual(
+ document.querySelectorAll('.o_Composer').length,
+ 1,
+ "should have composer in discuss thread"
+ );
+ assert.strictEqual(
+ document.querySelectorAll('.o_Composer_textInput').length,
+ 1,
+ "should have text input inside discuss thread composer"
+ );
+ assert.ok(
+ document.querySelector('.o_Composer_textInput').classList.contains('o_ComposerTextInput'),
+ "composer text input of composer should be a ComposerTextIput component"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_ComposerTextInput_textarea`).length,
+ 1,
+ "should have editable part inside composer text input"
+ );
+ assert.strictEqual(
+ document.querySelector(`.o_ComposerTextInput_textarea`).placeholder,
+ "Log an internal note...",
+ "should have 'Log an internal note...' as placeholder in composer text input if composer is log"
+ );
+});
+
+QUnit.test('composer text input: basic rendering when linked thread is a mail.channel', async function (assert) {
+ assert.expect(5);
+
+ await this.start();
+ const thread = this.env.models['mail.thread'].create({
+ id: 20,
+ model: 'mail.channel',
+ });
+ await this.createComposerComponent(thread.composer);
assert.strictEqual(
document.querySelectorAll('.o_Composer').length,
1,
@@ -86,7 +161,7 @@ QUnit.test('composer text input: basic rendering', async function (assert) {
assert.strictEqual(
document.querySelector(`.o_ComposerTextInput_textarea`).placeholder,
"Write something...",
- "should have placeholder in note editable of composer text input"
+ "should have 'Write something...' as placeholder in composer text input if composer is for a 'mail.channel'"
);
});
diff --git a/addons/mail/static/src/components/composer_text_input/composer_text_input.js b/addons/mail/static/src/components/composer_text_input/composer_text_input.js
index 1be0e77a98b..279d5a6ae93 100644
--- a/addons/mail/static/src/components/composer_text_input/composer_text_input.js
+++ b/addons/mail/static/src/components/composer_text_input/composer_text_input.js
@@ -65,6 +65,22 @@ class ComposerTextInput extends Component {
return this.env.models['mail.composer'].get(this.props.composerLocalId);
}
+ /**
+ * @returns {string}
+ */
+ get textareaPlaceholder() {
+ if (!this.composer) {
+ return "";
+ }
+ if (this.composer.thread && this.composer.thread.model !== 'mail.channel') {
+ if (this.composer.isLog) {
+ return this.env._t("Log an internal note...");
+ }
+ return this.env._t("Send a message to followers...");
+ }
+ return this.env._t("Write something...");
+ }
+
focusout() {
this.saveStateInStore();
this._textareaRef.el.blur();
diff --git a/addons/mail/static/src/components/composer_text_input/composer_text_input.xml b/addons/mail/static/src/components/composer_text_input/composer_text_input.xml
index 949f1065a56..dfeae27fc61 100644
--- a/addons/mail/static/src/components/composer_text_input/composer_text_input.xml
+++ b/addons/mail/static/src/components/composer_text_input/composer_text_input.xml
@@ -36,7 +36,7 @@
-
+
diff --git a/addons/mail/static/src/models/chatter/chatter.js b/addons/mail/static/src/models/chatter/chatter.js
index 59f197ded1c..59ba524f23b 100644
--- a/addons/mail/static/src/models/chatter/chatter.js
+++ b/addons/mail/static/src/models/chatter/chatter.js
@@ -2,7 +2,7 @@ odoo.define('mail/static/src/models/chatter/chatter.js', function (require) {
'use strict';
const { registerNewModel } = require('mail/static/src/model/model_core.js');
-const { attr, one2many, one2one } = require('mail/static/src/model/model_field.js');
+const { attr, many2one, one2many, one2one } = require('mail/static/src/model/model_field.js');
function factory(dependencies) {
@@ -72,19 +72,19 @@ function factory(dependencies) {
}
showLogNote() {
- this.update({
- isComposerLog: true,
- isComposerVisible: true,
+ this.update({ isComposerVisible: true });
+ this.thread.composer.update({
+ isDoFocus: true,
+ isLog: true,
});
- this.thread.composer.update({ isDoFocus: true });
}
showSendMessage() {
- this.update({
- isComposerLog: false,
- isComposerVisible: true,
+ this.update({ isComposerVisible: true });
+ this.thread.composer.update({
+ isDoFocus: true,
+ isLog: false,
});
- this.thread.composer.update({ isDoFocus: true });
}
toggleActivityBoxVisibility() {
@@ -249,6 +249,9 @@ function factory(dependencies) {
activitiesState: attr({
related: 'activities.state',
}),
+ composer: many2one('mail.composer', {
+ related: 'thread.composer',
+ }),
context: attr({
default: {},
}),
@@ -280,9 +283,6 @@ function factory(dependencies) {
isAttachmentBoxVisible: attr({
default: false,
}),
- isComposerLog: attr({
- default: true,
- }),
isComposerVisible: attr({
default: false,
}),
@@ -301,7 +301,7 @@ function factory(dependencies) {
compute: '_computeOverdueActivities',
dependencies: ['activitiesState'],
}),
- thread: one2one('mail.thread', {
+ thread: many2one('mail.thread', {
related: 'threadViewer.thread',
}),
threadAttachmentCount: attr({
diff --git a/addons/mail/static/src/models/composer/composer.js b/addons/mail/static/src/models/composer/composer.js
index fa6e2698eb0..86dfe78aa5e 100644
--- a/addons/mail/static/src/models/composer/composer.js
+++ b/addons/mail/static/src/models/composer/composer.js
@@ -85,40 +85,11 @@ function factory(dependencies) {
}
/**
- * Post a message in provided composer's thread with given data.
- *
- * @param {Object} data
- * @param {string[]} data.attachments
- * @param {*[]} data.canned_response_ids
- * @param {integer[]} data.channel_ids
- * @param {boolean} [data.isLog=false]
- * @param {string} data.subject
- * @param {integer} [data.subtype_id]
- * @param {string} [data.subtype_xmlid='mail.mt_comment']
- * @param {Object} [options]
- * @param {integer} options.res_id
- * @param {string} options.res_model
+ * Post a message in provided composer's thread based on current composer fields values.
*/
- async postMessage(data, options) {
+ async postMessage() {
const thread = this.thread;
this.thread.unregisterCurrentPartnerIsTyping({ immediateNotify: true });
- if (thread.model === 'mail.box') {
- const { res_id, res_model } = options;
- const otherThread = this.env.models['mail.thread'].find(thread =>
- thread.id === res_id &&
- thread.model === res_model
- );
- return otherThread.composer.postMessage(Object.assign({}, data));
- }
- const {
- canned_response_ids,
- channel_ids = [],
- context,
- isLog = false,
- subject,
- subtype_id,
- // subtype_xmlid='mail.mt_comment',
- } = data;
const escapedAndCompactContent = escapeAndCompactTextContent(this.textInputContent);
let body = escapedAndCompactContent.replace(/ /g, ' ').trim();
// This message will be received from the mail composer as html content
@@ -151,16 +122,7 @@ function factory(dependencies) {
}));
} else {
Object.assign(postData, {
- channel_ids: channel_ids.map(channelId => [4, channelId, false]),
- canned_response_ids
- });
- if (subject) {
- postData.subject = subject;
- }
- Object.assign(postData, {
- context,
- subtype_id,
- subtype_xmlid: isLog ? 'mail.mt_note' : 'mail.mt_comment',
+ subtype_xmlid: this.isLog ? 'mail.mt_note' : 'mail.mt_comment',
});
messageId = await this.async(() => this.env.services.rpc({
model: thread.model,
@@ -567,6 +529,12 @@ function factory(dependencies) {
isDoFocus: attr({
default: false,
}),
+ /**
+ * If true composer will log a note, else a comment will be posted.
+ */
+ isLog: attr({
+ default: false,
+ }),
mainSuggestedPartners: many2many('mail.partner'),
mentionedPartners: many2many('mail.partner', {
compute: '_computeMentionedPartners',