[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:
@@ -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,
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user