diff --git a/addons/mail/static/src/composer/composer.js b/addons/mail/static/src/composer/composer.js
index ed9c6c11f10..ccb5df65041 100644
--- a/addons/mail/static/src/composer/composer.js
+++ b/addons/mail/static/src/composer/composer.js
@@ -217,77 +217,79 @@ export class Composer extends Component {
}
get hasSuggestions() {
- return this.suggestion?.state.items.length > 0;
+ return Boolean(this.suggestion?.state.items);
}
get navigableListProps() {
- return {
+ const props = {
anchorRef: this.ref.el,
position: "top",
+ placeholder: _t("Loading"),
onSelect: (ev, option) => {
this.suggestion.insert(option);
markEventHandled(ev, "composer.selectSuggestion");
},
- sources: this.suggestion.state.items.map((mainOrExtraSuggestions) => {
- switch (mainOrExtraSuggestions.type) {
- case "Partner":
- return {
- placeholder: "Loading",
- optionTemplate: "mail.Composer.suggestionPartner",
- options: mainOrExtraSuggestions.suggestions.map((suggestion) => {
- return {
- label: suggestion.name,
- partner: suggestion,
- classList:
- "o-composer-suggestion o-composer-suggestion-partner",
- };
- }),
- };
- case "Thread":
- return {
- placeholder: "Loading",
- optionTemplate: "mail.Composer.suggestionThread",
- options: mainOrExtraSuggestions.suggestions.map((suggestion) => {
- return {
- label: suggestion.displayName,
- thread: suggestion,
- classList: "o-composer-suggestion o-composer-suggestion-thread",
- };
- }),
- };
- case "ChannelCommand":
- return {
- placeholder: "Loading",
- optionTemplate: "mail.Composer.suggestionChannelCommand",
- options: mainOrExtraSuggestions.suggestions.map((suggestion) => {
- return {
- label: suggestion.name,
- help: suggestion.help,
- classList:
- "o-composer-suggestion o-composer-suggestion-channel-command",
- };
- }),
- };
- case "CannedResponse":
- return {
- placeholder: "Loading",
- optionTemplate: "mail.Composer.suggestionCannedResponse",
- options: mainOrExtraSuggestions.suggestions.map((suggestion) => {
- return {
- name: suggestion.name,
- label: suggestion.substitution,
- classList:
- "o-composer-suggestion o-composer-suggestion-canned-response",
- };
- }),
- };
- default:
- return {
- options: [],
- };
- }
- }),
+ options: [],
};
+ if (!this.hasSuggestions) {
+ return props;
+ }
+ const suggestions = Array(
+ ...this.suggestion.state.items.mainSuggestions,
+ ...this.suggestion.state.items.extraSuggestions
+ );
+ switch (this.suggestion.state.items.type) {
+ case "Partner":
+ return {
+ ...props,
+ optionTemplate: "mail.Composer.suggestionPartner",
+ options: suggestions.map((suggestion) => {
+ return {
+ label: suggestion.name,
+ partner: suggestion,
+ classList: "o-mail-Composer-suggestion",
+ };
+ }),
+ };
+ case "Thread":
+ return {
+ ...props,
+ optionTemplate: "mail.Composer.suggestionThread",
+ options: suggestions.map((suggestion) => {
+ return {
+ label: suggestion.displayName,
+ thread: suggestion,
+ classList: "o-mail-Composer-suggestion",
+ };
+ }),
+ };
+ case "ChannelCommand":
+ return {
+ ...props,
+ optionTemplate: "mail.Composer.suggestionChannelCommand",
+ options: suggestions.map((suggestion) => {
+ return {
+ label: suggestion.name,
+ help: suggestion.help,
+ classList: "o-mail-Composer-suggestion",
+ };
+ }),
+ };
+ case "CannedResponse":
+ return {
+ ...props,
+ optionTemplate: "mail.Composer.suggestionCannedResponse",
+ options: suggestions.map((suggestion) => {
+ return {
+ name: suggestion.name,
+ label: suggestion.substitution,
+ classList: "o-mail-Composer-suggestion",
+ };
+ }),
+ };
+ default:
+ return props;
+ }
}
/**
diff --git a/addons/mail/static/src/composer/composer.xml b/addons/mail/static/src/composer/composer.xml
index efb72af3ae5..da632acf4e4 100644
--- a/addons/mail/static/src/composer/composer.xml
+++ b/addons/mail/static/src/composer/composer.xml
@@ -10,7 +10,7 @@
t-att-class="{
'px-3 py-4 o-extended': extended,
'p-3': normal,
- 'o-hasSelfAvatar px-3': !this.env.inChatWindow and thread,
+ 'o-hasSelfAvatar px-3': !env.inChatWindow and thread,
}">
![Avatar of user]()
@@ -82,7 +82,7 @@
t-att-disabled="isSendButtonDisabled"
aria-label="Send"
>
-
+
Send
@@ -99,7 +99,7 @@
escape to cancel, enter to save
-
+
diff --git a/addons/mail/static/src/composer/navigable_list.js b/addons/mail/static/src/composer/navigable_list.js
index 8b13eca79de..d91a523a69b 100644
--- a/addons/mail/static/src/composer/navigable_list.js
+++ b/addons/mail/static/src/composer/navigable_list.js
@@ -20,33 +20,22 @@ export class NavigableList extends Component {
static template = "mail.NavigableList";
static props = {
anchorRef: {},
- position: { type: String, optional: true },
- onSelect: { type: Function },
- sources: {
- type: Array,
- element: {
- type: Object,
- shape: {
- placeholder: { type: String, optional: true },
- optionTemplate: { type: String, optional: true },
- options: [Array, Promise],
- },
- },
- },
class: { type: String, optional: true },
+ onSelect: { type: Function },
+ options: { type: [Array, Promise] },
+ optionTemplate: { type: String, optional: true },
+ placeholder: { type: String, optional: true },
+ position: { type: String, optional: true },
};
static defaultProps = { position: "bottom" };
setup() {
- this.nextOptionId = 0;
- this.nextSourceId = 0;
this.rootRef = useRef("root");
- this.sources = [];
this.state = useState({
- activeSourceOption: null,
- navigationRev: 0,
+ activeOption: null,
+ isLoading: false,
open: false,
- optionsRev: 0,
+ options: [],
});
this.hotkey = useService("hotkey");
this.hotkeysToRemove = [];
@@ -78,88 +67,49 @@ export class NavigableList extends Component {
});
}
- get isOpened() {
- return this.state.open;
- }
-
- get hasOptions() {
- for (const source of this.sources) {
- if (source.isLoading || source.options.length) {
- return true;
- }
- }
- return false;
+ get show() {
+ return Boolean(this.state.open && (this.state.isLoading || this.state.options.length));
}
open() {
- this.loadSources();
+ this.load().then(() => {
+ this.state.open = true;
+ this.navigate("first");
+ });
}
close() {
this.state.open = false;
- this.state.activeSourceOption = null;
+ this.state.activeOption = null;
}
- loadSources() {
- this.sources = [];
- const proms = [];
- for (const pSource of this.props.sources) {
- if (pSource.options.length === 0) {
- continue;
- }
- const source = this.makeSource(pSource);
- this.sources.push(source);
- const options = pSource.options;
- if (options instanceof Promise) {
- source.isLoading = true;
- const prom = options.then((options) => {
- source.options = options.map((option) => this.makeOption(option));
- source.isLoading = false;
- if (source.options.length === 0) {
- this.sources = this.sources.filter((s) => s !== source);
- }
- this.state.optionsRev++;
- });
- proms.push(prom);
- } else {
- source.options = options.map((option) => this.makeOption(option));
- }
- }
- Promise.all(proms).then(() => {
- this.navigate(0);
- });
- if (this.sources.length === 0) {
- return;
- }
- this.state.open = true;
- }
-
- makeOption(option) {
- return Object.assign(Object.create(option), {
- id: ++this.nextOptionId,
- });
- }
-
- makeSource(source) {
- return {
- id: ++this.nextSourceId,
- options: [],
- isLoading: false,
- placeholder: source.placeholder,
- optionTemplate: source.optionTemplate,
+ async load() {
+ this.state.options = [];
+ const makeOption = (opt) => {
+ return Object.assign(Object.create(opt), {
+ id: this.state.options.length,
+ });
};
+ if (this.props.options instanceof Promise) {
+ this.state.isLoading = true;
+ return this.props.options.then((opts) => {
+ opts.forEach((opt) => this.state.options.push(makeOption(opt)));
+ this.state.isLoading = false;
+ });
+ }
+ if (this.props.options instanceof Array) {
+ if (this.props.options.length === 0) {
+ return;
+ }
+ this.props.options.forEach((opt) => this.state.options.push(makeOption(opt)));
+ }
}
- isActiveSourceOption([sourceIndex, optionIndex]) {
- return (
- this.state.activeSourceOption &&
- this.state.activeSourceOption[0] === sourceIndex &&
- this.state.activeSourceOption[1] === optionIndex
- );
+ isActiveOption(option) {
+ return this.state.activeOption?.id === option.id;
}
- selectOption(ev, indices, params = {}) {
- const option = this.sources[indices[0]].options[indices[1]];
+ selectOption(ev, option, params = {}) {
if (option.unselectable) {
this.close();
return;
@@ -171,85 +121,67 @@ export class NavigableList extends Component {
}
navigate(direction) {
- let step = Math.sign(direction);
- if (!step) {
- this.state.activeSourceOption = null;
- step = 1;
- } else {
- this.state.navigationRev++;
- }
- if (this.state.activeSourceOption) {
- let [sourceIndex, optionIndex] = this.state.activeSourceOption;
- let source = this.sources[sourceIndex];
- optionIndex += step;
- if (0 > optionIndex || optionIndex >= source.options.length) {
- sourceIndex += step;
- source = this.sources[sourceIndex];
- while (source && source.isLoading) {
- sourceIndex += step;
- source = this.sources[sourceIndex];
+ const activeOptionId = this.state.activeOption ? this.state.activeOption.id : -1;
+ let targetId = undefined;
+ switch (direction) {
+ case "first":
+ targetId = 0;
+ break;
+ case "last":
+ targetId = this.state.options.length - 1;
+ break;
+ case "previous":
+ targetId = activeOptionId - 1;
+ if (targetId < 0) {
+ this.navigate("last");
+ return;
}
- if (source) {
- optionIndex = step < 0 ? source.options.length - 1 : 0;
+ break;
+ case "next":
+ targetId = activeOptionId + 1;
+ if (targetId > this.state.options.length - 1) {
+ this.navigate("first");
+ return;
}
- }
- if (source) {
- this.state.activeSourceOption = [sourceIndex, optionIndex];
- } else {
- this.state.activeSourceOption =
- direction > 0
- ? [0, 0]
- : [
- this.sources.length - 1,
- this.sources[this.sources.length - 1].options.length - 1,
- ];
- }
- } else {
- let sourceIndex = step < 0 ? this.sources.length - 1 : 0;
- let source = this.sources[sourceIndex];
- while (source && source.isLoading) {
- sourceIndex += step;
- source = this.sources[sourceIndex];
- }
- if (source) {
- const optionIndex = step < 0 ? source.options.length - 1 : 0;
- this.state.activeSourceOption = [sourceIndex, optionIndex];
- }
+ break;
+ default:
+ return;
}
+ this.state.activeOption = this.state.options.find((o) => o.id === targetId);
}
onKeydown(ev) {
const hotkey = getActiveHotkey(ev);
switch (hotkey) {
case "enter":
- if (!this.isOpened || !this.state.activeSourceOption) {
+ if (!this.show || !this.state.activeOption) {
return;
}
markEventHandled(ev, "NavigableList.select");
- this.selectOption(ev, this.state.activeSourceOption);
+ this.selectOption(ev, this.state.activeOption);
break;
case "escape":
- if (!this.isOpened) {
+ if (!this.show) {
return;
}
markEventHandled(ev, "NavigableList.close");
this.close();
break;
case "tab":
- this.navigate(+1);
- if (!this.isOpened) {
+ this.navigate("next");
+ if (!this.show) {
this.open();
}
break;
case "arrowup":
- this.navigate(-1);
- if (!this.isOpened) {
+ this.navigate("previous");
+ if (!this.show) {
this.open();
}
break;
case "arrowdown":
- this.navigate(+1);
- if (!this.isOpened) {
+ this.navigate("next");
+ if (!this.show) {
this.open();
}
break;
@@ -259,15 +191,7 @@ export class NavigableList extends Component {
ev.preventDefault();
}
- onOptionMouseEnter(indices) {
- this.state.activeSourceOption = indices;
- }
-
- onOptionMouseLeave() {
- this.state.activeSourceOption = null;
- }
-
- onOptionClick(ev, indices) {
- this.selectOption(ev, indices);
+ onOptionMouseEnter(option) {
+ this.state.activeOption = option;
}
}
diff --git a/addons/mail/static/src/composer/navigable_list.xml b/addons/mail/static/src/composer/navigable_list.xml
index 7e846de7a25..8a2488cc62f 100644
--- a/addons/mail/static/src/composer/navigable_list.xml
+++ b/addons/mail/static/src/composer/navigable_list.xml
@@ -3,29 +3,26 @@
-
-
-
diff --git a/addons/mail/static/src/composer/suggestion_hook.js b/addons/mail/static/src/composer/suggestion_hook.js
index b7418f5de1e..260aad4f25b 100644
--- a/addons/mail/static/src/composer/suggestion_hook.js
+++ b/addons/mail/static/src/composer/suggestion_hook.js
@@ -17,7 +17,7 @@ export function useSuggestion() {
position: undefined,
term: undefined,
});
- self.state.items.length = 0;
+ self.state.items = undefined;
},
detect() {
const selectionEnd = comp.props.composer.selection.end;
@@ -113,7 +113,7 @@ export function useSuggestion() {
},
state: useState({
count: 0,
- items: [],
+ items: undefined,
}),
update() {
if (!self.search.delimiter || !comp.props.composer.thread) {
@@ -127,16 +127,16 @@ export function useSuggestion() {
if (!suggestions) {
return;
}
- const [main, extra = { suggestions: [] }] = suggestions;
+ const { type, mainSuggestions, extraSuggestions = [] } = suggestions;
// arbitrary limit to avoid displaying too many elements at once
// ideally a load more mechanism should be introduced
const limit = 8;
- main.suggestions.length = Math.min(main.suggestions.length, limit);
- extra.suggestions.length = Math.min(
- extra.suggestions.length,
- limit - main.suggestions.length
+ mainSuggestions.length = Math.min(mainSuggestions.length, limit);
+ extraSuggestions.length = Math.min(
+ extraSuggestions.length,
+ limit - mainSuggestions.length
);
- self.state.items = [main, extra];
+ self.state.items = { type, mainSuggestions, extraSuggestions };
},
};
useEffect(
diff --git a/addons/mail/static/src/composer/suggestion_service.js b/addons/mail/static/src/composer/suggestion_service.js
index f926472680c..e2267268205 100644
--- a/addons/mail/static/src/composer/suggestion_service.js
+++ b/addons/mail/static/src/composer/suggestion_service.js
@@ -99,16 +99,11 @@ class SuggestionService {
case "/":
return this.searchChannelCommand(cleanedSearchTerm, thread, sort);
}
- return [
- {
- type: undefined,
- suggestions: [],
- },
- {
- type: undefined,
- suggestions: [],
- },
- ];
+ return {
+ type: undefined,
+ mainSuggestions: [],
+ extraSuggestions: [],
+ };
}
searchChannelCommand(cleanedSearchTerm, thread, sort) {
@@ -164,12 +159,10 @@ class SuggestionService {
}
return c1.id - c2.id;
};
- return [
- {
- type: "ChannelCommand",
- suggestions: sort ? commands.sort(sortFunc) : commands,
- },
- ];
+ return {
+ type: "ChannelCommand",
+ mainSuggestions: sort ? commands.sort(sortFunc) : commands,
+ };
}
searchPartnerSuggestions(cleanedSearchTerm, thread, sort) {
@@ -285,16 +278,11 @@ class SuggestionService {
}
return p1.id - p2.id;
};
- return [
- {
- type: "Partner",
- suggestions: sort ? mainSuggestionList.sort(sortFunc) : mainSuggestionList,
- },
- {
- type: "Partner",
- suggestions: sort ? extraSuggestionList.sort(sortFunc) : extraSuggestionList,
- },
- ];
+ return {
+ type: "Partner",
+ mainSuggestions: sort ? mainSuggestionList.sort(sortFunc) : mainSuggestionList,
+ extraSuggestions: sort ? extraSuggestionList.sort(sortFunc) : extraSuggestionList,
+ };
}
searchCannedResponseSuggestions(cleanedSearchTerm, sort) {
@@ -332,12 +320,10 @@ class SuggestionService {
}
return c1.id - c2.id;
};
- return [
- {
- type: "CannedResponse",
- suggestions: sort ? cannedResponses.sort(sortFunc) : cannedResponses,
- },
- ];
+ return {
+ type: "CannedResponse",
+ mainSuggestions: sort ? cannedResponses.sort(sortFunc) : cannedResponses,
+ };
}
searchChannelSuggestions(cleanedSearchTerm, thread, sort) {
@@ -400,12 +386,10 @@ class SuggestionService {
}
return c1.id - c2.id;
};
- return [
- {
- type: "Thread",
- suggestions: sort ? suggestionList.sort(sortFunc) : suggestionList,
- },
- ];
+ return {
+ type: "Thread",
+ mainSuggestions: sort ? suggestionList.sort(sortFunc) : suggestionList,
+ };
}
}
diff --git a/addons/mail/static/src/discuss/channel_selector.js b/addons/mail/static/src/discuss/channel_selector.js
index 9aa4615f01b..918c68481f9 100644
--- a/addons/mail/static/src/discuss/channel_selector.js
+++ b/addons/mail/static/src/discuss/channel_selector.js
@@ -179,16 +179,12 @@ export class ChannelSelector extends Component {
anchorRef: this.rootRef.el,
position: "bottom",
onSelect: (ev, option) => this.onSelect(option),
- sources: [
- {
- placeholder: "Loading",
- optionTemplate:
- this.props.category.id === "channels"
- ? "mail.ChannelSelector.channel"
- : "mail.ChannelSelector.chat",
- options: this.fetchSuggestions(this.state.value),
- },
- ],
+ placeholder: _t("Loading"),
+ optionTemplate:
+ this.props.category.id === "channels"
+ ? "mail.ChannelSelector.channel"
+ : "mail.ChannelSelector.chat",
+ options: this.fetchSuggestions(this.state.value),
};
}
}
diff --git a/addons/mail/static/tests/composer/composer_tests.js b/addons/mail/static/tests/composer/composer_tests.js
index 9d4879db6e5..5419686f27b 100644
--- a/addons/mail/static/tests/composer/composer_tests.js
+++ b/addons/mail/static/tests/composer/composer_tests.js
@@ -364,7 +364,7 @@ QUnit.test(
});
await openDiscuss(channelId);
await insertText(".o-mail-Composer-input", "/");
- await click(".o-composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
await insertText(".o-mail-Composer-input", " is user?");
assert.verifySteps([], "No rpc done");
}
@@ -378,10 +378,10 @@ QUnit.test("add an emoji after a command", async (assert) => {
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion-list .o-open");
+ assert.containsNone($, ".o-mail-Composer-suggestionList .o-open");
assert.strictEqual($(".o-mail-Composer-input").val(), "");
await insertText(".o-mail-Composer-input", "/");
- await click(".o-composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
assert.strictEqual(
$(".o-mail-Composer-input").val().replace(/\s/, " "),
"/who ",
@@ -404,11 +404,11 @@ QUnit.test("add an emoji after a canned response", async (assert) => {
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion");
+ assert.containsNone($, ".o-mail-Composer-suggestion");
assert.strictEqual($(".o-mail-Composer-input").val(), "");
await insertText(".o-mail-Composer-input", ":");
- assert.containsOnce($, ".o-composer-suggestion");
- await click(".o-composer-suggestion");
+ assert.containsOnce($, ".o-mail-Composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
assert.strictEqual(
$(".o-mail-Composer-input").val().replace(/\s/, " "),
"Hello! How are you? ",
@@ -438,12 +438,12 @@ QUnit.test("add an emoji after a partner mention", async (assert) => {
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion");
+ assert.containsNone($, ".o-mail-Composer-suggestion");
assert.strictEqual($(".o-mail-Composer-input").val(), "");
await insertText(".o-mail-Composer-input", "@");
await insertText(".o-mail-Composer-input", "T");
await insertText(".o-mail-Composer-input", "e");
- await click(".o-composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
assert.strictEqual($(".o-mail-Composer-input").val().replace(/\s/, " "), "@TestPartner ");
await click("button[aria-label='Emojis']");
@@ -459,7 +459,7 @@ QUnit.test("mention a channel after some text", async (assert) => {
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion");
+ assert.containsNone($, ".o-mail-Composer-suggestion");
assert.strictEqual($(".o-mail-Composer-input").val(), "");
await insertText(".o-mail-Composer-input", "bluhbluh ");
assert.strictEqual(
@@ -468,8 +468,8 @@ QUnit.test("mention a channel after some text", async (assert) => {
"text content of composer should have content"
);
await insertText(".o-mail-Composer-input", "#");
- assert.containsOnce($, ".o-composer-suggestion");
- await click(".o-composer-suggestion");
+ assert.containsOnce($, ".o-mail-Composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
assert.strictEqual(
$(".o-mail-Composer-input").val().replace(/\s/, " "),
"bluhbluh #General ",
@@ -485,11 +485,11 @@ QUnit.test("add an emoji after a channel mention", async (assert) => {
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion");
+ assert.containsNone($, ".o-mail-Composer-suggestion");
assert.strictEqual($(".o-mail-Composer-input").val(), "");
await insertText(".o-mail-Composer-input", "#");
- assert.containsOnce($, ".o-composer-suggestion");
- await click(".o-composer-suggestion");
+ assert.containsOnce($, ".o-mail-Composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
assert.strictEqual(
$(".o-mail-Composer-input").val().replace(/\s/, " "),
"#General ",
diff --git a/addons/mail/static/tests/discuss/inbox_tests.js b/addons/mail/static/tests/discuss/inbox_tests.js
index fe679542831..d45e0fea0ff 100644
--- a/addons/mail/static/tests/discuss/inbox_tests.js
+++ b/addons/mail/static/tests/discuss/inbox_tests.js
@@ -112,9 +112,9 @@ QUnit.test("reply: discard on pressing escape", async (assert) => {
// Escape on suggestion prompt does not stop replying
await insertText(".o-mail-Composer-input", "@");
- assert.containsOnce($, ".o-composer-suggestion-list .o-open");
+ assert.containsOnce($, ".o-mail-Composer-suggestionList .o-open");
await afterNextRender(() => triggerHotkey("Escape"));
- assert.containsNone($, ".o-composer-suggestion-list .o-open");
+ assert.containsNone($, ".o-mail-Composer-suggestionList .o-open");
assert.containsOnce($, ".o-mail-Composer");
click(".o-mail-Composer-input").catch(() => {});
diff --git a/addons/mail/static/tests/message/message_tests.js b/addons/mail/static/tests/message/message_tests.js
index 3b2e59ad3c2..ed13e821c7c 100644
--- a/addons/mail/static/tests/message/message_tests.js
+++ b/addons/mail/static/tests/message/message_tests.js
@@ -1170,7 +1170,7 @@ QUnit.test("Chat with partner should be opened after clicking on their mention",
await insertText(".o-mail-Composer-input", "@");
await insertText(".o-mail-Composer-input", "T");
await insertText(".o-mail-Composer-input", "e");
- await click(".o-composer-suggestion:contains(Test Partner)");
+ await click(".o-mail-Composer-suggestion:contains(Test Partner)");
await click(".o-mail-Composer-send");
await click(".o_mail_redirect");
assert.containsOnce($, ".o-mail-ChatWindow-content");
@@ -1216,7 +1216,7 @@ QUnit.test("Channel should be opened after clicking on its mention", async (asse
await openFormView("res.partner", partnerId);
await click("button:contains(Send message)");
await insertText(".o-mail-Composer-input", "#");
- await click(".o-composer-suggestion:contains(my-channel)");
+ await click(".o-mail-Composer-suggestion:contains(my-channel)");
await click(".o-mail-Composer-send");
await click(".o_channel_redirect");
assert.containsOnce($, ".o-mail-ChatWindow-content");
diff --git a/addons/mail/static/tests/suggestion/suggestion_tests.js b/addons/mail/static/tests/suggestion/suggestion_tests.js
index 3686bd92a30..bff5f6a4561 100644
--- a/addons/mail/static/tests/suggestion/suggestion_tests.js
+++ b/addons/mail/static/tests/suggestion/suggestion_tests.js
@@ -41,10 +41,10 @@ QUnit.test('display partner mention suggestions on typing "@"', async (assert) =
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion");
+ assert.containsNone($, ".o-mail-Composer-suggestion");
await insertText(".o-mail-Composer-input", "@");
- assert.containsN($, ".o-composer-suggestion", 3);
+ assert.containsN($, ".o-mail-Composer-suggestion", 3);
});
QUnit.test(
@@ -70,13 +70,13 @@ QUnit.test(
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion");
+ assert.containsNone($, ".o-mail-Composer-suggestion");
await insertText(".o-mail-Composer-input", "first message");
triggerHotkey("Enter");
await nextTick();
await insertText(".o-mail-Composer-input", "@");
- assert.containsN($, ".o-composer-suggestion", 3);
+ assert.containsN($, ".o-mail-Composer-suggestion", 3);
}
);
@@ -85,9 +85,9 @@ QUnit.test('display partner mention suggestions on typing "@" in chatter', async
const { openFormView } = await start();
await openFormView("res.partner", pyEnv.currentPartnerId);
await click("button:contains(Send message)");
- assert.containsNone($, ".o-composer-suggestion");
+ assert.containsNone($, ".o-mail-Composer-suggestion");
await insertText(".o-mail-Composer-input", "@");
- assert.containsOnce($, ".o-composer-suggestion:contains(Mitchell Admin)");
+ assert.containsOnce($, ".o-mail-Composer-suggestion:contains(Mitchell Admin)");
});
QUnit.test("show other channel member in @ mention", async (assert) => {
@@ -106,7 +106,7 @@ QUnit.test("show other channel member in @ mention", async (assert) => {
const { openDiscuss } = await start();
await openDiscuss(channelId);
await insertText(".o-mail-Composer-input", "@");
- assert.containsOnce($, ".o-composer-suggestion:contains(TestPartner)");
+ assert.containsOnce($, ".o-mail-Composer-suggestion:contains(TestPartner)");
});
QUnit.test("select @ mention insert mention text in composer", async (assert) => {
@@ -125,7 +125,7 @@ QUnit.test("select @ mention insert mention text in composer", async (assert) =>
const { openDiscuss } = await start();
await openDiscuss(channelId);
await insertText(".o-mail-Composer-input", "@");
- await click(".o-composer-suggestion:contains(TestPartner)");
+ await click(".o-mail-Composer-suggestion:contains(TestPartner)");
assert.strictEqual($(".o-mail-Composer-input").val().trim(), "@TestPartner");
});
@@ -137,9 +137,9 @@ QUnit.test('display command suggestions on typing "/"', async (assert) => {
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion-list .o-open");
+ assert.containsNone($, ".o-mail-Composer-suggestionList .o-open");
await insertText(".o-mail-Composer-input", "/");
- assert.containsOnce($, ".o-composer-suggestion-list .o-open");
+ assert.containsOnce($, ".o-mail-Composer-suggestionList .o-open");
});
QUnit.test("use a command for a specific channel type", async (assert) => {
@@ -147,10 +147,10 @@ QUnit.test("use a command for a specific channel type", async (assert) => {
const channelId = pyEnv["mail.channel"].create({ channel_type: "chat" });
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion-list .o-open");
+ assert.containsNone($, ".o-mail-Composer-suggestionList .o-open");
assert.strictEqual($(".o-mail-Composer-input").val(), "");
await insertText(".o-mail-Composer-input", "/");
- await click(".o-composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
assert.strictEqual(
$(".o-mail-Composer-input").val().replace(/\s/, " "),
"/who ",
@@ -168,12 +168,12 @@ QUnit.test(
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion-list .o-open");
+ assert.containsNone($, ".o-mail-Composer-suggestionList .o-open");
assert.strictEqual($(".o-mail-Composer-input").val(), "");
await insertText(".o-mail-Composer-input", "bluhbluh ");
assert.strictEqual($(".o-mail-Composer-input").val(), "bluhbluh ");
await insertText(".o-mail-Composer-input", "/");
- assert.containsNone($, ".o-composer-suggestion-list .o-open");
+ assert.containsNone($, ".o-mail-Composer-suggestionList .o-open");
}
);
@@ -186,9 +186,9 @@ QUnit.test('display canned response suggestions on typing ":"', async (assert) =
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion-list .o-open");
+ assert.containsNone($, ".o-mail-Composer-suggestionList .o-open");
await insertText(".o-mail-Composer-input", ":");
- assert.containsOnce($, ".o-composer-suggestion-list .o-open");
+ assert.containsOnce($, ".o-mail-Composer-suggestionList .o-open");
});
QUnit.test("use a canned response", async (assert) => {
@@ -200,11 +200,11 @@ QUnit.test("use a canned response", async (assert) => {
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion-list .o-open");
+ assert.containsNone($, ".o-mail-Composer-suggestionList .o-open");
assert.strictEqual($(".o-mail-Composer-input").val(), "");
await insertText(".o-mail-Composer-input", ":");
- assert.containsOnce($, ".o-composer-suggestion");
- await click(".o-composer-suggestion");
+ assert.containsOnce($, ".o-mail-Composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
assert.strictEqual(
$(".o-mail-Composer-input").val().replace(/\s/, " "),
"Hello! How are you? ",
@@ -221,13 +221,13 @@ QUnit.test("use a canned response some text", async (assert) => {
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion");
+ assert.containsNone($, ".o-mail-Composer-suggestion");
assert.strictEqual($(".o-mail-Composer-input").val(), "");
await insertText(".o-mail-Composer-input", "bluhbluh ");
assert.strictEqual($(".o-mail-Composer-input").val(), "bluhbluh ");
await insertText(".o-mail-Composer-input", ":");
- assert.containsOnce($, ".o-composer-suggestion");
- await click(".o-composer-suggestion");
+ assert.containsOnce($, ".o-mail-Composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
assert.strictEqual(
$(".o-mail-Composer-input").val().replace(/\s/, " "),
"bluhbluh Hello! How are you? ",
@@ -243,9 +243,9 @@ QUnit.test('display channel mention suggestions on typing "#"', async (assert) =
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion-list .o-open");
+ assert.containsNone($, ".o-mail-Composer-suggestionList .o-open");
await insertText(".o-mail-Composer-input", "#");
- assert.containsOnce($, ".o-composer-suggestion-list .o-open");
+ assert.containsOnce($, ".o-mail-Composer-suggestionList .o-open");
});
QUnit.test("mention a channel", async (assert) => {
@@ -256,11 +256,11 @@ QUnit.test("mention a channel", async (assert) => {
});
const { openDiscuss } = await start();
await openDiscuss(channelId);
- assert.containsNone($, ".o-composer-suggestion-list .o-open");
+ assert.containsNone($, ".o-mail-Composer-suggestionList .o-open");
assert.strictEqual($(".o-mail-Composer-input").val(), "");
await insertText(".o-mail-Composer-input", "#");
- assert.containsOnce($, ".o-composer-suggestion");
- await click(".o-composer-suggestion");
+ assert.containsOnce($, ".o-mail-Composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
assert.strictEqual(
$(".o-mail-Composer-input").val().replace(/\s/, " "),
"#General ",
diff --git a/addons/mail/static/tests/thread/thread_tests.js b/addons/mail/static/tests/thread/thread_tests.js
index ca20a8c14bd..f5f48958722 100644
--- a/addons/mail/static/tests/thread/thread_tests.js
+++ b/addons/mail/static/tests/thread/thread_tests.js
@@ -210,7 +210,7 @@ QUnit.test("mention a channel with space in the name", async (assert) => {
const { openDiscuss } = await start();
await openDiscuss(channelId);
await insertText(".o-mail-Composer-input", "#");
- await click(".o-composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
await click(".o-mail-Composer-send");
assert.containsOnce($(".o-mail-Message-body"), ".o_channel_redirect");
assert.strictEqual($(".o_channel_redirect").text(), "#General good boy");
@@ -222,7 +222,7 @@ QUnit.test('mention a channel with "&" in the name', async (assert) => {
const { openDiscuss } = await start();
await openDiscuss(channelId);
await insertText(".o-mail-Composer-input", "#");
- await click(".o-composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
await click(".o-mail-Composer-send");
assert.containsOnce($(".o-mail-Message-body"), ".o_channel_redirect");
assert.strictEqual($(".o_channel_redirect").text(), "#General & good");
@@ -545,7 +545,7 @@ QUnit.test("Mention a partner with special character (e.g. apostrophe ')", async
await openDiscuss(channelId);
await insertText(".o-mail-Composer-input", "@");
await insertText(".o-mail-Composer-input", "Pyn");
- await click(".o-composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
await click(".o-mail-Composer-send");
assert.containsOnce(
$(".o-mail-Message-body"),
@@ -577,10 +577,10 @@ QUnit.test("mention 2 different partners that have the same name", async (assert
await openDiscuss(channelId);
await insertText(".o-mail-Composer-input", "@");
await insertText(".o-mail-Composer-input", "Te");
- await click(".o-composer-suggestion:eq(0)");
+ await click(".o-mail-Composer-suggestion:eq(0)");
await insertText(".o-mail-Composer-input", "@");
await insertText(".o-mail-Composer-input", "Te");
- await click(".o-composer-suggestion:eq(1)");
+ await click(".o-mail-Composer-suggestion:eq(1)");
await click(".o-mail-Composer-send");
assert.containsOnce($, ".o-mail-Message-body");
assert.containsOnce(
@@ -600,7 +600,7 @@ QUnit.test("mention a channel on a second line when the first line contains #",
await openDiscuss(channelId);
await insertText(".o-mail-Composer-input", "#blabla\n");
await insertText(".o-mail-Composer-input", "#");
- await click(".o-composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
await click(".o-mail-Composer-send");
assert.containsOnce($(".o-mail-Message-body"), ".o_channel_redirect");
assert.strictEqual($(".o_channel_redirect").text(), "#General good");
@@ -614,7 +614,7 @@ QUnit.test(
const { openDiscuss } = await start();
await openDiscuss(channelId);
await insertText(".o-mail-Composer-input", "#");
- await click(".o-composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
const text = $(".o-mail-Composer-input").val();
$(".o-mail-Composer-input").val(text.slice(0, -1));
await insertText(".o-mail-Composer-input", ", test");
@@ -641,10 +641,10 @@ QUnit.test("mention 2 different channels that have the same name", async (assert
await openDiscuss(channelId_1);
await insertText(".o-mail-Composer-input", "#");
await insertText(".o-mail-Composer-input", "m");
- await click(".o-composer-suggestion:eq(0)");
+ await click(".o-mail-Composer-suggestion:eq(0)");
await insertText(".o-mail-Composer-input", "#");
await insertText(".o-mail-Composer-input", "m");
- await click(".o-composer-suggestion:eq(1)");
+ await click(".o-mail-Composer-suggestion:eq(1)");
await click(".o-mail-Composer-send");
assert.containsOnce($, ".o-mail-Message-body");
assert.containsOnce(
@@ -677,7 +677,7 @@ QUnit.test(
await insertText(".o-mail-Composer-input", "email@odoo.com\n");
await insertText(".o-mail-Composer-input", "@");
await insertText(".o-mail-Composer-input", "Te");
- await click(".o-composer-suggestion");
+ await click(".o-mail-Composer-suggestion");
await click(".o-mail-Composer-send");
assert.containsOnce(
$(".o-mail-Message-body"),