[FIX] mail: filter commands used in composer based on channel type
closes odoo/odoo#60644 Task-id: 2343850 X-original-commit: caaf436bdf1f72634bf8a83672c6f683e0013713 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
@@ -673,9 +673,20 @@ QUnit.test('add an emoji after a channel mention', async function (assert) {
|
||||
QUnit.test('display command suggestions on typing "/"', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
this.data['mail.channel'].records.push({ channel_type: 'channel', id: 20 });
|
||||
this.data['mail.channel_command'].records.push(
|
||||
{
|
||||
channel_types: ['channel'],
|
||||
help: "List users in the current channel",
|
||||
name: "who",
|
||||
},
|
||||
);
|
||||
await this.start();
|
||||
const composer = this.env.models['mail.composer'].create();
|
||||
await this.createComposerComponent(composer);
|
||||
const thread = this.env.models['mail.thread'].findFromIdentifyingData({
|
||||
id: 20,
|
||||
model: 'mail.channel',
|
||||
});
|
||||
await this.createComposerComponent(thread.composer);
|
||||
|
||||
assert.containsNone(
|
||||
document.body,
|
||||
@@ -697,12 +708,23 @@ QUnit.test('display command suggestions on typing "/"', async function (assert)
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('use a command', async function (assert) {
|
||||
QUnit.test('use a command for a specific channel type', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
this.data['mail.channel'].records.push({ channel_type: 'channel', id: 20 });
|
||||
this.data['mail.channel_command'].records.push(
|
||||
{
|
||||
channel_types: ['channel'],
|
||||
help: "List users in the current channel",
|
||||
name: "who",
|
||||
},
|
||||
);
|
||||
await this.start();
|
||||
const composer = this.env.models['mail.composer'].create();
|
||||
await this.createComposerComponent(composer);
|
||||
const thread = this.env.models['mail.thread'].findFromIdentifyingData({
|
||||
id: 20,
|
||||
model: 'mail.channel',
|
||||
});
|
||||
await this.createComposerComponent(thread.composer);
|
||||
|
||||
assert.containsNone(
|
||||
document.body,
|
||||
@@ -739,13 +761,56 @@ QUnit.test('use a command', async function (assert) {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("channel with no commands should not prompt any command suggestions on typing /", async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
this.data['mail.channel'].records.push({ channel_type: 'chat', id: 20 });
|
||||
this.data['mail.channel_command'].records.push(
|
||||
{
|
||||
channel_types: ['channel'],
|
||||
help: "bla bla bla",
|
||||
name: "who",
|
||||
},
|
||||
);
|
||||
await this.start();
|
||||
const thread = this.env.models['mail.thread'].findFromIdentifyingData({
|
||||
id: 20,
|
||||
model: 'mail.channel',
|
||||
});
|
||||
await this.createComposerComponent(thread.composer);
|
||||
await afterNextRender(() => {
|
||||
document.querySelector('.o_ComposerTextInput_textarea').focus();
|
||||
document.execCommand('insertText', false, "/");
|
||||
});
|
||||
await afterNextRender(() => {
|
||||
const composer_text_input = document.querySelector('.o_ComposerTextInput_textarea');
|
||||
composer_text_input.dispatchEvent(new window.KeyboardEvent('keydown'));
|
||||
composer_text_input.dispatchEvent(new window.KeyboardEvent('keyup'));
|
||||
});
|
||||
assert.containsNone(
|
||||
document.body,
|
||||
'.o_ComposerSuggestion',
|
||||
"should not prompt (command) suggestion after typing / (reason: no channel commands in chat channels)"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('use a command after some text', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
this.data['mail.channel'].records.push({ channel_type: 'channel', id: 20 });
|
||||
this.data['mail.channel_command'].records.push(
|
||||
{
|
||||
channel_types: ['channel'],
|
||||
help: "List users in the current channel",
|
||||
name: "who",
|
||||
},
|
||||
);
|
||||
await this.start();
|
||||
const composer = this.env.models['mail.composer'].create();
|
||||
await this.createComposerComponent(composer);
|
||||
|
||||
const thread = this.env.models['mail.thread'].findFromIdentifyingData({
|
||||
id: 20,
|
||||
model: 'mail.channel',
|
||||
});
|
||||
await this.createComposerComponent(thread.composer);
|
||||
assert.containsNone(
|
||||
document.body,
|
||||
'.o_ComposerSuggestion',
|
||||
@@ -792,9 +857,20 @@ QUnit.test('use a command after some text', async function (assert) {
|
||||
QUnit.test('add an emoji after a command', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
this.data['mail.channel'].records.push({ channel_type: 'channel', id: 20 });
|
||||
this.data['mail.channel_command'].records.push(
|
||||
{
|
||||
channel_types: ['channel'],
|
||||
help: "List users in the current channel",
|
||||
name: "who",
|
||||
},
|
||||
);
|
||||
await this.start();
|
||||
const composer = this.env.models['mail.composer'].create();
|
||||
await this.createComposerComponent(composer);
|
||||
const thread = this.env.models['mail.thread'].findFromIdentifyingData({
|
||||
id: 20,
|
||||
model: 'mail.channel',
|
||||
});
|
||||
await this.createComposerComponent(thread.composer);
|
||||
|
||||
assert.containsNone(
|
||||
document.body,
|
||||
|
||||
@@ -10,7 +10,10 @@ function factory(dependencies) {
|
||||
|
||||
ChannelCommand.fields = {
|
||||
/**
|
||||
* FIXME use this value task-2343850
|
||||
* Determines on which channel types `this` is available.
|
||||
* Type of the channel (e.g. 'chat', 'channel' or 'groups')
|
||||
* This field should contain an array when filtering is desired.
|
||||
* Otherwise, it should be undefined when all types are allowed.
|
||||
*/
|
||||
channel_types: attr(),
|
||||
/**
|
||||
|
||||
@@ -602,7 +602,15 @@ function factory(dependencies) {
|
||||
_getCommandFromText(content) {
|
||||
if (content.startsWith('/')) {
|
||||
const firstWord = content.substring(1).split(/\s/)[0];
|
||||
return this.env.messaging.commands.find(command => command.name === firstWord);
|
||||
return this.env.messaging.commands.find(command => {
|
||||
if (command.name !== firstWord) {
|
||||
return false;
|
||||
}
|
||||
if (command.channel_types) {
|
||||
return command.channel_types.includes(this.thread.channel_type);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -685,15 +693,16 @@ function factory(dependencies) {
|
||||
* @param {string} mentionKeyword
|
||||
*/
|
||||
_updateSuggestedChannelCommands(mentionKeyword) {
|
||||
this.update({
|
||||
suggestedChannelCommands: [[
|
||||
'replace',
|
||||
this.env.messaging.commands.filter(
|
||||
command => command.name.includes(mentionKeyword)
|
||||
)
|
||||
]],
|
||||
const commands = this.env.messaging.commands.filter(command => {
|
||||
if (!command.name.includes(mentionKeyword)) {
|
||||
return false;
|
||||
}
|
||||
if (command.channel_types) {
|
||||
return command.channel_types.includes(this.thread.channel_type);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
this.update({ suggestedChannelCommands: [['replace', commands]] });
|
||||
if (this.suggestedChannelCommands[0]) {
|
||||
this.update({
|
||||
activeSuggestedChannelCommand: [['link', this.suggestedChannelCommands[0]]],
|
||||
|
||||
@@ -95,6 +95,15 @@ class MockModels {
|
||||
},
|
||||
records: [],
|
||||
},
|
||||
// Fake model to simulate "hardcoded" commands from python
|
||||
'mail.channel_command': {
|
||||
fields: {
|
||||
channel_types: { type: 'binary' }, // array is expected
|
||||
help: { type: 'char' },
|
||||
name: { type: 'char' },
|
||||
},
|
||||
records: [],
|
||||
},
|
||||
'mail.followers': {
|
||||
fields: {
|
||||
channel_id: { type: 'integer' },
|
||||
|
||||
@@ -398,6 +398,8 @@ MockServer.include({
|
||||
|
||||
const shortcodes = this._getRecords('mail.shortcode', []);
|
||||
|
||||
const commands = this._getRecords('mail.channel_command', []);
|
||||
|
||||
const starredCounter = this._getRecords('mail.message', [
|
||||
['starred_partner_ids', 'in', this.currentPartnerId],
|
||||
]).length;
|
||||
@@ -408,11 +410,7 @@ MockServer.include({
|
||||
channel_direct_message: directMessageInfos,
|
||||
channel_private_group: privateGroupInfos,
|
||||
},
|
||||
commands: [{
|
||||
channel_types: ["channel", "chat"],
|
||||
help: "List users in the current channel",
|
||||
name: "who",
|
||||
}],
|
||||
commands,
|
||||
current_partner: currentPartnerFormat,
|
||||
current_user_id: this.currentUserId,
|
||||
mail_failures: mailFailures,
|
||||
|
||||
Reference in New Issue
Block a user