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
index 047fc997b49..7a211483e59 100644
--- 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
@@ -104,7 +104,7 @@ QUnit.test('channel mention suggestion correct data', async function (assert) {
);
});
-QUnit.test('partner mention suggestion active', async function (assert) {
+QUnit.test('channel mention suggestion active', async function (assert) {
assert.expect(2);
this.data['mail.channel'].records.push({ id: 20 });
diff --git a/addons/mail/static/src/components/discuss/tests/discuss_sidebar_tests.js b/addons/mail/static/src/components/discuss/tests/discuss_sidebar_tests.js
new file mode 100644
index 00000000000..23d74c5cbe3
--- /dev/null
+++ b/addons/mail/static/src/components/discuss/tests/discuss_sidebar_tests.js
@@ -0,0 +1,145 @@
+odoo.define('mail/static/src/components/discuss/tests/discuss_sidebar_tests.js', function (require) {
+'use strict';
+
+const { makeDeferred } = require('mail/static/src/utils/deferred/deferred.js');
+const {
+ afterEach,
+ afterNextRender,
+ beforeEach,
+ nextAnimationFrame,
+ start,
+} = require('mail/static/src/utils/test_utils.js');
+
+QUnit.module('mail', {}, function () {
+QUnit.module('components', {}, function () {
+QUnit.module('discuss', {}, function () {
+QUnit.module('discuss_sidebar_tests.js', {
+ beforeEach() {
+ beforeEach(this);
+
+ this.start = async params => {
+ const { env, widget } = await start(Object.assign({}, params, {
+ autoOpenDiscuss: true,
+ data: this.data,
+ hasDiscuss: true,
+ }));
+ this.env = env;
+ this.widget = widget;
+ };
+ },
+ afterEach() {
+ afterEach(this);
+ },
+});
+
+QUnit.test('sidebar find shows channels matching search term', async function (assert) {
+ assert.expect(3);
+
+ this.data['mail.channel'].records.push({
+ channel_partner_ids: [],
+ channel_type: 'channel',
+ id: 20,
+ members: [],
+ name: 'test',
+ public: 'public',
+ });
+ const searchReadDef = makeDeferred();
+ await this.start({
+ async mockRPC(route, args) {
+ const res = await this._super(...arguments);
+ if (args.method === 'search_read') {
+ searchReadDef.resolve();
+ }
+ return res;
+ },
+ });
+ await afterNextRender(() =>
+ document.querySelector(`.o_DiscussSidebar_groupHeaderItemAdd`).click()
+ );
+ document.querySelector(`.o_DiscussSidebar_itemNew`).focus();
+ document.execCommand('insertText', false, "test");
+ document.querySelector(`.o_DiscussSidebar_itemNew`)
+ .dispatchEvent(new window.KeyboardEvent('keydown'));
+ document.querySelector(`.o_DiscussSidebar_itemNew`)
+ .dispatchEvent(new window.KeyboardEvent('keyup'));
+
+ await searchReadDef;
+ await nextAnimationFrame(); // ensures search_read rpc is rendered.
+ const results = document.querySelectorAll('.ui-autocomplete .ui-menu-item a');
+ assert.ok(
+ results,
+ "should have autocomplete suggestion after typing on 'find or create channel' input"
+ );
+ assert.strictEqual(
+ results.length,
+ // When searching for a single existing channel, the results list will have at least 3 lines:
+ // One for the existing channel itself
+ // One for creating a public channel with the search term
+ // One for creating a private channel with the search term
+ 3
+ );
+ assert.strictEqual(
+ results[0].textContent,
+ "test",
+ "autocomplete suggestion should target the channel matching search term"
+ );
+});
+
+QUnit.test('sidebar find shows channels matching search term even when user is member', async function (assert) {
+ assert.expect(3);
+
+ this.data['mail.channel'].records.push({
+ channel_partner_ids: [this.data.currentPartnerId],
+ channel_type: 'channel',
+ id: 20,
+ members: [this.data.currentPartnerId],
+ name: 'test',
+ public: 'public',
+ });
+ const searchReadDef = makeDeferred();
+ await this.start({
+ async mockRPC(route, args) {
+ const res = await this._super(...arguments);
+ if (args.method === 'search_read') {
+ searchReadDef.resolve();
+ }
+ return res;
+ },
+ });
+ await afterNextRender(() =>
+ document.querySelector(`.o_DiscussSidebar_groupHeaderItemAdd`).click()
+ );
+ document.querySelector(`.o_DiscussSidebar_itemNew`).focus();
+ document.execCommand('insertText', false, "test");
+ document.querySelector(`.o_DiscussSidebar_itemNew`)
+ .dispatchEvent(new window.KeyboardEvent('keydown'));
+ document.querySelector(`.o_DiscussSidebar_itemNew`)
+ .dispatchEvent(new window.KeyboardEvent('keyup'));
+
+ await searchReadDef;
+ await nextAnimationFrame();
+ const results = document.querySelectorAll('.ui-autocomplete .ui-menu-item a');
+ assert.ok(
+ results,
+ "should have autocomplete suggestion after typing on 'find or create channel' input"
+ );
+ assert.strictEqual(
+ results.length,
+ // When searching for a single existing channel, the results list will have at least 3 lines:
+ // One for the existing channel itself
+ // One for creating a public channel with the search term
+ // One for creating a private channel with the search term
+ 3
+ );
+ assert.strictEqual(
+ results[0].textContent,
+ "test",
+ "autocomplete suggestion should target the channel matching search term even if user is member"
+ );
+});
+
+});
+});
+});
+
+});
diff --git a/addons/mail/static/src/models/discuss/discuss.js b/addons/mail/static/src/models/discuss/discuss.js
index c3b94fc0f01..efa956c8691 100644
--- a/addons/mail/static/src/models/discuss/discuss.js
+++ b/addons/mail/static/src/models/discuss/discuss.js
@@ -79,10 +79,18 @@ function factory(dependencies) {
const value = req.term;
const escapedValue = owl.utils.escape(value);
this.update({ addingChannelValue: value });
+ const domain = [
+ ['channel_type', '=', 'channel'],
+ ['name', 'ilike', value],
+ ];
+ const fields = ['channel_type', 'name', 'public', 'uuid'];
const result = await this.async(() => this.env.services.rpc({
- model: 'mail.channel',
- method: 'channel_search_to_join',
- args: [value],
+ model: "mail.channel",
+ method: "search_read",
+ kwargs: {
+ domain,
+ fields,
+ },
}));
const items = result.map(data => {
let escapedName = owl.utils.escape(data.name);
diff --git a/addons/mail/static/tests/helpers/mock_models.js b/addons/mail/static/tests/helpers/mock_models.js
index c2617b6108e..873b5b0be70 100644
--- a/addons/mail/static/tests/helpers/mock_models.js
+++ b/addons/mail/static/tests/helpers/mock_models.js
@@ -68,6 +68,8 @@ class MockModels {
'mail.channel': {
fields: {
channel_type: { string: "Channel Type", type: "selection", default: 'channel' },
+ // Equivalent to members but required due to some RPC giving this field in domain.
+ channel_partner_ids: { string: "Channel Partner Ids", type: 'many2many', relation: 'res.partner' },
// In python this belongs to mail.channel.partner. Here for simplicity.
custom_channel_name: { string: "Custom channel name", type: 'char' },
fetched_message_id: { string: "Last Fetched", type: 'many2one', relation: 'mail.message' },
diff --git a/addons/mail/views/assets.xml b/addons/mail/views/assets.xml
index 69a46cc7a9a..7b4ca4dafe1 100644
--- a/addons/mail/views/assets.xml
+++ b/addons/mail/views/assets.xml
@@ -287,6 +287,7 @@
+