[FIX] im_livechat, mail: broken history navigation

This PR fixes 2 issues with discuss navigation:

1. Broken backwards navigation when going back and forth from the live
chat session history.
2. Broken backwards navigation when trying to access the same thread
than the current one.

Steps to reproduce 1:
- Open the command palette
- Go to the live chat session history view
- Click on one of your channels
- History back => leads to the session history view
- History forward => leads to discuss
- History back => stays on discuss, history is broken

This occurs because the active id is not passed in the action context
when navigating backwards which leads to the URL being pushed again in
history (URL without active id is different). The active id should be
put in the context when available.

Steps to reproduce 2:
- Go to discuss
- Click on the active thread
- History back => stuck on discuss, cannot navigate backwards anymore.

We should not push in history when accessing the same thread than the
current one.

task-3422516

closes odoo/odoo#153094

X-original-commit: 029b79ad7dc28aab83289e7c3ebd4cc0dcc5d609
Signed-off-by: Matthieu Stockbauer (tsm) <tsm@odoo.com>
This commit is contained in:
tsm-odoo
2024-02-12 20:24:07 +00:00
parent df2a5d841a
commit 7d18bf0f83
10 changed files with 101 additions and 15 deletions
@@ -0,0 +1,58 @@
/** @odoo-module */
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("im_livechat_history_back_and_forth_tour", {
test: true,
steps: () => [
{
trigger: "body",
// Open Command Palette
run() {
this.$anchor[0].dispatchEvent(
new KeyboardEvent("keydown", { key: "K", ctrlKey: true, bubbles: true })
);
},
},
{
trigger: ".o_command_palette_search input",
run: "text /",
},
{
trigger: ".o_command_palette_search input",
run: "text Live Chat",
},
{
trigger: ".o_command:contains(Sessions History)",
},
{
trigger: ".o_data_cell:contains(Visitor operator)",
},
{
trigger: ".o-mail-DiscussSidebar-item:contains(Visitor).o-active",
run() {
history.back();
},
},
{
trigger: ".o_data_cell:contains(Visitor operator)",
run() {
history.forward();
},
},
{
trigger: ".o-mail-DiscussSidebar-item:contains(Visitor).o-active",
},
{
trigger: ".o-mail-DiscussSidebar-item:contains(Visitor).o-active",
run() {
history.back();
},
},
{
trigger: ".o_data_cell:contains(Visitor operator)",
run() {},
isCheck: true,
},
],
});
+1
View File
@@ -13,3 +13,4 @@ from . import test_im_livechat_support_page
from . import test_js
from . import test_message
from . import test_upload_attachment
from . import test_session_history
+1 -1
View File
@@ -46,6 +46,6 @@ class TestImLivechatCommon(HttpCase):
def _compute_available_operator_ids(channel_self):
for record in channel_self:
record.available_operator_ids = type(self).operators
record.available_operator_ids = record.user_ids
self.patch(type(self.env['im_livechat.channel']), '_compute_available_operator_ids', _compute_available_operator_ids)
@@ -0,0 +1,21 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests import new_test_user, tagged
from odoo.addons.im_livechat.tests.common import TestImLivechatCommon
@tagged("-at_install", "post_install")
class TestImLivechatSessionHistory(TestImLivechatCommon):
def test_session_history_navigation_back_and_forth(self):
operator = new_test_user(self.env, login="operator", groups="base.group_user,im_livechat.im_livechat_group_manager")
self.env["bus.presence"].create({"user_id": operator.id, "status": "online"})
self.livechat_channel.user_ids |= operator
self.authenticate(None, None)
infos = self.make_jsonrpc_request("/im_livechat/get_session", {
"channel_id": self.livechat_channel.id,
"anonymous_name": "Visitor",
"previous_operator_id": operator.partner_id.id
})
channel = self.env["discuss.channel"].browse(infos["id"])
channel.with_user(operator).message_post(body="Hello, how can I help you?")
self.start_tour("/web", "im_livechat_history_back_and_forth_tour", login="operator", step_delay=25)
@@ -70,7 +70,7 @@
</div>
</div>
</div>
<div t-if="!thread and (!ui.isSmall or store.discuss.activeTab === 'main')" class="d-flex flex-grow-1 align-items-center justify-content-center w-100 bg-view">
<div t-if="!thread and (!ui.isSmall or store.discuss.activeTab === 'main') and store.discuss.hasRestoredThread" class="d-flex flex-grow-1 align-items-center justify-content-center w-100 bg-view">
<h4 class="text-muted"><b><i>No conversation selected.</i></b></h4>
</div>
</div>
@@ -46,6 +46,7 @@ export class DiscussApp extends Record {
activeTab = "main";
chatWindows = Record.many("ChatWindow");
isActive = false;
hasRestoredThread = false;
thread = Record.one("Thread");
channels = Record.one("DiscussAppCategory");
chats = Record.one("DiscussAppCategory");
@@ -642,7 +642,10 @@ export class ThreadService {
* @param {import("models").Thread} thread
* @param {boolean} pushState
*/
setDiscussThread(thread, pushState = true) {
setDiscussThread(thread, pushState) {
if (pushState === undefined) {
pushState = thread.localId !== this.store.discuss.thread?.localId;
}
this.store.discuss.thread = thread;
const activeId =
typeof thread.id === "string"
@@ -58,8 +58,9 @@ export class DiscussClientAction extends Component {
activeThread = await this.threadService.fetchChannel(parseInt(id));
}
if (activeThread && activeThread.notEq(this.store.discuss.thread)) {
this.threadService.setDiscussThread(activeThread);
this.threadService.setDiscussThread(activeThread, false);
}
this.store.discuss.hasRestoredThread = true;
}
}
@@ -6,7 +6,6 @@ import { timings } from "@bus/misc";
import { loadEmoji } from "@web/core/emoji_picker/emoji_picker";
import { loadLamejs } from "@mail/discuss/voice_message/common/voice_message_service";
import { patchBrowserNotification } from "@mail/../tests/helpers/patch_notifications";
import { DISCUSS_ACTION_ID } from "@mail/../tests/helpers/test_constants";
import { getAdvanceTime } from "@mail/../tests/helpers/time_control";
import { getWebClientReady } from "@mail/../tests/helpers/webclient_setup";
@@ -37,7 +36,7 @@ function getOpenDiscuss(webClient, { context = {}, params = {}, ...props } = {})
return async function openDiscuss(pActiveId) {
const actionOpenDiscuss = {
context: { ...context, active_id: pActiveId },
id: DISCUSS_ACTION_ID,
id: "mail.action_discuss",
params,
tag: "mail.action_discuss",
type: "ir.actions.client",
@@ -315,9 +315,19 @@ function makeActionManager(env) {
const options = { clearBreadcrumbs: true };
let actionRequest = null;
if (state.action) {
const context = {};
if (state.active_id) {
context.active_id = state.active_id;
}
if (state.active_ids) {
context.active_ids = parseActiveIds(state.active_ids);
} else if (state.active_id) {
context.active_ids = [state.active_id];
}
// ClientAction
if (actionRegistry.contains(state.action)) {
actionRequest = {
context,
params: state,
tag: state.action,
type: "ir.actions.client",
@@ -325,15 +335,7 @@ function makeActionManager(env) {
} else {
// The action to load isn't the current one => executes it
actionRequest = state.action;
const context = { params: state };
if (state.active_id) {
context.active_id = state.active_id;
}
if (state.active_ids) {
context.active_ids = parseActiveIds(state.active_ids);
} else if (state.active_id) {
context.active_ids = [state.active_id];
}
context.params = state;
Object.assign(options, {
additionalContext: context,
viewType: state.view_type,