summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/components/composer_suggestion
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/mail/static/src/components/composer_suggestion
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/mail/static/src/components/composer_suggestion')
-rw-r--r--addons/mail/static/src/components/composer_suggestion/composer_suggestion.js143
-rw-r--r--addons/mail/static/src/components/composer_suggestion/composer_suggestion.scss43
-rw-r--r--addons/mail/static/src/components/composer_suggestion/composer_suggestion.xml33
-rw-r--r--addons/mail/static/src/components/composer_suggestion/composer_suggestion_canned_response_tests.js154
-rw-r--r--addons/mail/static/src/components/composer_suggestion/composer_suggestion_channel_tests.js144
-rw-r--r--addons/mail/static/src/components/composer_suggestion/composer_suggestion_command_tests.js151
-rw-r--r--addons/mail/static/src/components/composer_suggestion/composer_suggestion_partner_tests.js160
7 files changed, 828 insertions, 0 deletions
diff --git a/addons/mail/static/src/components/composer_suggestion/composer_suggestion.js b/addons/mail/static/src/components/composer_suggestion/composer_suggestion.js
new file mode 100644
index 00000000..da54ab54
--- /dev/null
+++ b/addons/mail/static/src/components/composer_suggestion/composer_suggestion.js
@@ -0,0 +1,143 @@
+odoo.define('mail/static/src/components/composer_suggestion/composer_suggestion.js', function (require) {
+'use strict';
+
+const useShouldUpdateBasedOnProps = require('mail/static/src/component_hooks/use_should_update_based_on_props/use_should_update_based_on_props.js');
+const useStore = require('mail/static/src/component_hooks/use_store/use_store.js');
+const useUpdate = require('mail/static/src/component_hooks/use_update/use_update.js');
+
+const components = {
+ PartnerImStatusIcon: require('mail/static/src/components/partner_im_status_icon/partner_im_status_icon.js'),
+};
+
+const { Component } = owl;
+
+class ComposerSuggestion extends Component {
+
+ /**
+ * @override
+ */
+ constructor(...args) {
+ super(...args);
+ useShouldUpdateBasedOnProps();
+ useStore(props => {
+ const composer = this.env.models['mail.composer'].get(this.props.composerLocalId);
+ const record = this.env.models[props.modelName].get(props.recordLocalId);
+ return {
+ composerHasToScrollToActiveSuggestion: composer && composer.hasToScrollToActiveSuggestion,
+ record: record ? record.__state : undefined,
+ };
+ });
+ useUpdate({ func: () => this._update() });
+ }
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * @returns {mail.composer}
+ */
+ get composer() {
+ return this.env.models['mail.composer'].get(this.props.composerLocalId);
+ }
+
+ get isCannedResponse() {
+ return this.props.modelName === "mail.canned_response";
+ }
+
+ get isChannel() {
+ return this.props.modelName === "mail.thread";
+ }
+
+ get isCommand() {
+ return this.props.modelName === "mail.channel_command";
+ }
+
+ get isPartner() {
+ return this.props.modelName === "mail.partner";
+ }
+
+ get record() {
+ return this.env.models[this.props.modelName].get(this.props.recordLocalId);
+ }
+
+ /**
+ * Returns a descriptive title for this suggestion. Useful to be able to
+ * read both parts when they are overflowing the UI.
+ *
+ * @returns {string}
+ */
+ title() {
+ if (this.isCannedResponse) {
+ return _.str.sprintf("%s: %s", this.record.source, this.record.substitution);
+ }
+ if (this.isChannel) {
+ return this.record.name;
+ }
+ if (this.isCommand) {
+ return _.str.sprintf("%s: %s", this.record.name, this.record.help);
+ }
+ if (this.isPartner) {
+ if (this.record.email) {
+ return _.str.sprintf("%s (%s)", this.record.nameOrDisplayName, this.record.email);
+ }
+ return this.record.nameOrDisplayName;
+ }
+ return "";
+ }
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _update() {
+ if (
+ this.composer &&
+ this.composer.hasToScrollToActiveSuggestion &&
+ this.props.isActive
+ ) {
+ this.el.scrollIntoView({
+ block: 'center',
+ });
+ this.composer.update({ hasToScrollToActiveSuggestion: false });
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onClick(ev) {
+ ev.preventDefault();
+ this.composer.update({ activeSuggestedRecord: [['link', this.record]] });
+ this.composer.insertSuggestion();
+ this.composer.closeSuggestions();
+ this.trigger('o-composer-suggestion-clicked');
+ }
+
+}
+
+Object.assign(ComposerSuggestion, {
+ components,
+ defaultProps: {
+ isActive: false,
+ },
+ props: {
+ composerLocalId: String,
+ isActive: Boolean,
+ modelName: String,
+ recordLocalId: String,
+ },
+ template: 'mail.ComposerSuggestion',
+});
+
+return ComposerSuggestion;
+
+});
diff --git a/addons/mail/static/src/components/composer_suggestion/composer_suggestion.scss b/addons/mail/static/src/components/composer_suggestion/composer_suggestion.scss
new file mode 100644
index 00000000..4083c149
--- /dev/null
+++ b/addons/mail/static/src/components/composer_suggestion/composer_suggestion.scss
@@ -0,0 +1,43 @@
+// ------------------------------------------------------------------
+// Layout
+// ------------------------------------------------------------------
+
+.o_ComposerSuggestion {
+ display: flex;
+ width: map-get($sizes, 100);
+ padding: map-get($spacers, 2) map-get($spacers, 4);
+}
+
+.o_ComposerSuggestion_part1 {
+ // avoid shrinking part 1 because it is more important than part 2
+ // because no shrink, ensure it cannot overflow with a max-width
+ flex: 0 0 auto;
+ max-width: 100%;
+ overflow: hidden;
+ padding-inline-end: map-get($spacers, 2);
+ text-overflow: ellipsis;
+}
+
+.o_ComposerSuggestion_part2 {
+ // shrink part 2 to properly ensure it cannot overflow
+ flex: 0 1 auto;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.o_ComposerSuggestion_partnerImStatusIcon {
+ flex: 0 0 auto;
+}
+
+// ------------------------------------------------------------------
+// Style
+// ------------------------------------------------------------------
+
+.o_ComposerSuggestion_part1 {
+ font-weight: $font-weight-bold;
+}
+
+.o_ComposerSuggestion_part2 {
+ font-style: italic;
+ color: $gray-600;
+}
diff --git a/addons/mail/static/src/components/composer_suggestion/composer_suggestion.xml b/addons/mail/static/src/components/composer_suggestion/composer_suggestion.xml
new file mode 100644
index 00000000..787b5aed
--- /dev/null
+++ b/addons/mail/static/src/components/composer_suggestion/composer_suggestion.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates xml:space="preserve">
+
+ <t t-name="mail.ComposerSuggestion" owl="1">
+ <a class="o_ComposerSuggestion dropdown-item" t-att-class="{ 'active': props.isActive }" href="#" t-att-title="title()" role="menuitem" t-on-click="_onClick">
+ <t t-if="record">
+ <t t-if="isCannedResponse">
+ <span class="o_ComposerSuggestion_part1"><t t-esc="record.source"/></span>
+ <span class="o_ComposerSuggestion_part2"><t t-esc="record.substitution"/></span>
+ </t>
+ <t t-if="isChannel">
+ <span class="o_ComposerSuggestion_part1"><t t-esc="record.name"/></span>
+ </t>
+ <t t-if="isCommand">
+ <span class="o_ComposerSuggestion_part1"><t t-esc="record.name"/></span>
+ <span class="o_ComposerSuggestion_part2"><t t-esc="record.help"/></span>
+ </t>
+ <t t-if="isPartner">
+ <PartnerImStatusIcon
+ class="o_ComposerSuggestion_partnerImStatusIcon"
+ hasBackground="false"
+ partnerLocalId="record.localId"
+ />
+ <span class="o_ComposerSuggestion_part1"><t t-esc="record.nameOrDisplayName"/></span>
+ <t t-if="record.email">
+ <span class="o_ComposerSuggestion_part2">(<t t-esc="record.email"/>)</span>
+ </t>
+ </t>
+ </t>
+ </a>
+ </t>
+
+</templates>
diff --git a/addons/mail/static/src/components/composer_suggestion/composer_suggestion_canned_response_tests.js b/addons/mail/static/src/components/composer_suggestion/composer_suggestion_canned_response_tests.js
new file mode 100644
index 00000000..0e0f8685
--- /dev/null
+++ b/addons/mail/static/src/components/composer_suggestion/composer_suggestion_canned_response_tests.js
@@ -0,0 +1,154 @@
+odoo.define('mail/static/src/components/composer_suggestion/composer_suggestion_canned_response_tests.js', function (require) {
+'use strict';
+
+const components = {
+ ComposerSuggestion: require('mail/static/src/components/composer_suggestion/composer_suggestion.js'),
+};
+const {
+ afterEach,
+ beforeEach,
+ createRootComponent,
+ start,
+} = require('mail/static/src/utils/test_utils.js');
+
+QUnit.module('mail', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('composer_suggestion', {}, function () {
+QUnit.module('composer_suggestion_canned_response_tests.js', {
+ beforeEach() {
+ beforeEach(this);
+
+ this.createComposerSuggestion = async props => {
+ await createRootComponent(this, components.ComposerSuggestion, {
+ props,
+ target: this.widget.el,
+ });
+ };
+
+ this.start = async params => {
+ const { env, widget } = await start(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ afterEach(this);
+ },
+});
+
+QUnit.test('canned response suggestion displayed', async function (assert) {
+ assert.expect(1);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const cannedResponse = this.env.models['mail.canned_response'].create({
+ id: 7,
+ source: 'hello',
+ substitution: "Hello, how are you?",
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.canned_response',
+ recordLocalId: cannedResponse.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ `.o_ComposerSuggestion`,
+ "Canned response suggestion should be present"
+ );
+});
+
+QUnit.test('canned response suggestion correct data', async function (assert) {
+ assert.expect(5);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const cannedResponse = this.env.models['mail.canned_response'].create({
+ id: 7,
+ source: 'hello',
+ substitution: "Hello, how are you?",
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.canned_response',
+ recordLocalId: cannedResponse.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion',
+ "Canned response suggestion should be present"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion_part1',
+ "Canned response source should be present"
+ );
+ assert.strictEqual(
+ document.querySelector(`.o_ComposerSuggestion_part1`).textContent,
+ "hello",
+ "Canned response source should be displayed"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion_part2',
+ "Canned response substitution should be present"
+ );
+ assert.strictEqual(
+ document.querySelector(`.o_ComposerSuggestion_part2`).textContent,
+ "Hello, how are you?",
+ "Canned response substitution should be displayed"
+ );
+});
+
+QUnit.test('canned response suggestion active', async function (assert) {
+ assert.expect(2);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const cannedResponse = this.env.models['mail.canned_response'].create({
+ id: 7,
+ source: 'hello',
+ substitution: "Hello, how are you?",
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.canned_response',
+ recordLocalId: cannedResponse.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion',
+ "Canned response suggestion should be displayed"
+ );
+ assert.hasClass(
+ document.querySelector('.o_ComposerSuggestion'),
+ 'active',
+ "should be active initially"
+ );
+});
+
+});
+});
+});
+
+});
diff --git a/addons/mail/static/src/components/composer_suggestion/composer_suggestion_channel_tests.js b/addons/mail/static/src/components/composer_suggestion/composer_suggestion_channel_tests.js
new file mode 100644
index 00000000..7a211483
--- /dev/null
+++ b/addons/mail/static/src/components/composer_suggestion/composer_suggestion_channel_tests.js
@@ -0,0 +1,144 @@
+odoo.define('mail/static/src/components/composer_suggestion/composer_suggestion_channel_tests.js', function (require) {
+'use strict';
+
+const components = {
+ ComposerSuggestion: require('mail/static/src/components/composer_suggestion/composer_suggestion.js'),
+};
+const {
+ afterEach,
+ beforeEach,
+ createRootComponent,
+ start,
+} = require('mail/static/src/utils/test_utils.js');
+
+QUnit.module('mail', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('composer_suggestion', {}, function () {
+QUnit.module('composer_suggestion_channel_tests.js', {
+ beforeEach() {
+ beforeEach(this);
+
+ this.createComposerSuggestion = async props => {
+ await createRootComponent(this, components.ComposerSuggestion, {
+ props,
+ target: this.widget.el,
+ });
+ };
+
+ this.start = async params => {
+ const { env, widget } = await start(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ afterEach(this);
+ },
+});
+
+QUnit.test('channel mention suggestion displayed', async function (assert) {
+ assert.expect(1);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const channel = this.env.models['mail.thread'].create({
+ id: 7,
+ name: "General",
+ model: 'mail.channel',
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.thread',
+ recordLocalId: channel.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ `.o_ComposerSuggestion`,
+ "Channel mention suggestion should be present"
+ );
+});
+
+QUnit.test('channel mention suggestion correct data', async function (assert) {
+ assert.expect(3);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const channel = this.env.models['mail.thread'].create({
+ id: 7,
+ name: "General",
+ model: 'mail.channel',
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.thread',
+ recordLocalId: channel.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion',
+ "Channel mention suggestion should be present"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion_part1',
+ "Channel name should be present"
+ );
+ assert.strictEqual(
+ document.querySelector(`.o_ComposerSuggestion_part1`).textContent,
+ "General",
+ "Channel name should be displayed"
+ );
+});
+
+QUnit.test('channel mention suggestion active', async function (assert) {
+ assert.expect(2);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const channel = this.env.models['mail.thread'].create({
+ id: 7,
+ name: "General",
+ model: 'mail.channel',
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.thread',
+ recordLocalId: channel.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion',
+ "Channel mention suggestion should be displayed"
+ );
+ assert.hasClass(
+ document.querySelector('.o_ComposerSuggestion'),
+ 'active',
+ "should be active initially"
+ );
+});
+
+});
+});
+});
+
+});
diff --git a/addons/mail/static/src/components/composer_suggestion/composer_suggestion_command_tests.js b/addons/mail/static/src/components/composer_suggestion/composer_suggestion_command_tests.js
new file mode 100644
index 00000000..8bbb3d45
--- /dev/null
+++ b/addons/mail/static/src/components/composer_suggestion/composer_suggestion_command_tests.js
@@ -0,0 +1,151 @@
+odoo.define('mail/static/src/components/composer_suggestion/composer_suggestion_command_tests.js', function (require) {
+'use strict';
+
+const components = {
+ ComposerSuggestion: require('mail/static/src/components/composer_suggestion/composer_suggestion.js'),
+};
+const {
+ afterEach,
+ beforeEach,
+ createRootComponent,
+ start,
+} = require('mail/static/src/utils/test_utils.js');
+
+QUnit.module('mail', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('composer_suggestion', {}, function () {
+QUnit.module('composer_suggestion_command_tests.js', {
+ beforeEach() {
+ beforeEach(this);
+
+ this.createComposerSuggestion = async props => {
+ await createRootComponent(this, components.ComposerSuggestion, {
+ props,
+ target: this.widget.el,
+ });
+ };
+
+ this.start = async params => {
+ const { env, widget } = await start(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ afterEach(this);
+ },
+});
+
+QUnit.test('command suggestion displayed', async function (assert) {
+ assert.expect(1);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const command = this.env.models['mail.channel_command'].create({
+ name: 'whois',
+ help: "Displays who it is",
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.channel_command',
+ recordLocalId: command.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ `.o_ComposerSuggestion`,
+ "Command suggestion should be present"
+ );
+});
+
+QUnit.test('command suggestion correct data', async function (assert) {
+ assert.expect(5);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const command = this.env.models['mail.channel_command'].create({
+ name: 'whois',
+ help: "Displays who it is",
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.channel_command',
+ recordLocalId: command.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion',
+ "Command suggestion should be present"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion_part1',
+ "Command name should be present"
+ );
+ assert.strictEqual(
+ document.querySelector(`.o_ComposerSuggestion_part1`).textContent,
+ "whois",
+ "Command name should be displayed"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion_part2',
+ "Command help should be present"
+ );
+ assert.strictEqual(
+ document.querySelector(`.o_ComposerSuggestion_part2`).textContent,
+ "Displays who it is",
+ "Command help should be displayed"
+ );
+});
+
+QUnit.test('command suggestion active', async function (assert) {
+ assert.expect(2);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const command = this.env.models['mail.channel_command'].create({
+ name: 'whois',
+ help: "Displays who it is",
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.channel_command',
+ recordLocalId: command.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion',
+ "Command suggestion should be displayed"
+ );
+ assert.hasClass(
+ document.querySelector('.o_ComposerSuggestion'),
+ 'active',
+ "should be active initially"
+ );
+});
+
+});
+});
+});
+
+});
diff --git a/addons/mail/static/src/components/composer_suggestion/composer_suggestion_partner_tests.js b/addons/mail/static/src/components/composer_suggestion/composer_suggestion_partner_tests.js
new file mode 100644
index 00000000..548fd6d7
--- /dev/null
+++ b/addons/mail/static/src/components/composer_suggestion/composer_suggestion_partner_tests.js
@@ -0,0 +1,160 @@
+odoo.define('mail/static/src/components/composer_suggestion/composer_suggestion_partner_tests.js', function (require) {
+'use strict';
+
+const components = {
+ ComposerSuggestion: require('mail/static/src/components/composer_suggestion/composer_suggestion.js'),
+};
+const {
+ afterEach,
+ beforeEach,
+ createRootComponent,
+ start,
+} = require('mail/static/src/utils/test_utils.js');
+
+QUnit.module('mail', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('composer_suggestion', {}, function () {
+QUnit.module('composer_suggestion_partner_tests.js', {
+ beforeEach() {
+ beforeEach(this);
+
+ this.createComposerSuggestion = async props => {
+ await createRootComponent(this, components.ComposerSuggestion, {
+ props,
+ target: this.widget.el,
+ });
+ };
+
+ this.start = async params => {
+ const { env, widget } = await start(Object.assign({}, params, {
+ data: this.data,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ afterEach(this);
+ },
+});
+
+QUnit.test('partner mention suggestion displayed', async function (assert) {
+ assert.expect(1);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const partner = this.env.models['mail.partner'].create({
+ id: 7,
+ im_status: 'online',
+ name: "Demo User",
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.partner',
+ recordLocalId: partner.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ `.o_ComposerSuggestion`,
+ "Partner mention suggestion should be present"
+ );
+});
+
+QUnit.test('partner mention suggestion correct data', async function (assert) {
+ assert.expect(6);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const partner = this.env.models['mail.partner'].create({
+ email: "demo_user@odoo.com",
+ id: 7,
+ im_status: 'online',
+ name: "Demo User",
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.partner',
+ recordLocalId: partner.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion',
+ "Partner mention suggestion should be present"
+ );
+ assert.strictEqual(
+ document.querySelectorAll(`.o_PartnerImStatusIcon`).length,
+ 1,
+ "Partner's im_status should be displayed"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion_part1',
+ "Partner's name should be present"
+ );
+ assert.strictEqual(
+ document.querySelector(`.o_ComposerSuggestion_part1`).textContent,
+ "Demo User",
+ "Partner's name should be displayed"
+ );
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion_part2',
+ "Partner's email should be present"
+ );
+ assert.strictEqual(
+ document.querySelector(`.o_ComposerSuggestion_part2`).textContent,
+ "(demo_user@odoo.com)",
+ "Partner's email should be displayed"
+ );
+});
+
+QUnit.test('partner mention suggestion active', async function (assert) {
+ assert.expect(2);
+
+ this.data['mail.channel'].records.push({ id: 20 });
+ await this.start();
+ const thread = this.env.models['mail.thread'].findFromIdentifyingData({
+ id: 20,
+ model: 'mail.channel',
+ });
+ const partner = this.env.models['mail.partner'].create({
+ id: 7,
+ im_status: 'online',
+ name: "Demo User",
+ });
+ await this.createComposerSuggestion({
+ composerLocalId: thread.composer.localId,
+ isActive: true,
+ modelName: 'mail.partner',
+ recordLocalId: partner.localId,
+ });
+
+ assert.containsOnce(
+ document.body,
+ '.o_ComposerSuggestion',
+ "Partner mention suggestion should be displayed"
+ );
+ assert.hasClass(
+ document.querySelector('.o_ComposerSuggestion'),
+ 'active',
+ "should be active initially"
+ );
+});
+
+});
+});
+});
+
+});