[FIX] website: prefer requested action url over last url

Before this commit, there was a conflict between 2 of the ways to open
the WebsitePreview iframe.

First, introduced with [1], when a user click on the 'edit in backend'
systray button, the URL he was on is stored to be used later if the user
click on the "Website Preview" breadcrumb. When he will click on that
breadcrumb entry, we want him to go back to where he was, not on the
homepage.

Second, some records in form views have a "Go to website" stat button
that will go to the website preview action, loading the iframe with the
URL of the record from the form view.

Before this commit, the second flow was not working if the user
previously click on "Edit in backend" on a record (first flow
described).
Indeed, if that "last url" was set, it would always be used, ignoring
the requested one from the second flow.

Step to reproduce:
- Go to a record in the website preview, like a product
- Click on edit in backend
- You land on the product form view, and that url was saved in JS
- From there, navigate to another record through the form view, like a
  m2o relation or a stat button, or by whatever other mean, but don't
  hard reload the page (F5)
- For the example, let's say you landed on a blog post record
- Click on "Go to website" on that blog post form view
-> You land on the product page you were initially, not on the requested
   blog post page.

Courtesy of @rdeodoo

[1]: https://github.com/odoo/odoo/commit/31cc10b91dc7762e23b4bde9b945be0c4ce3fe3b

task-2687506

closes odoo/odoo#103010

X-original-commit: 7cd55e8a1d9516a6f457320064160328a49210f9
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
Younn Olivier
2022-10-11 14:10:09 +02:00
committed by Romain Derie
parent 957b1b5ca0
commit d3a3397c4d
3 changed files with 32 additions and 38 deletions
@@ -35,6 +35,10 @@ export class WebsitePreview extends Component {
isBlocked: false,
showLoader: false,
});
// The params used to configure the context should be ignored when the
// action is restored (example: click on the breadcrumb).
this.isRestored = this.props.action.jsId === this.websiteService.actionJsId;
this.websiteService.actionJsId = this.props.action.jsId;
useBus(this.websiteService.bus, 'BLOCK', (event) => this.block(event.detail));
useBus(this.websiteService.bus, 'UNBLOCK', () => this.unblock());
@@ -57,12 +61,7 @@ export class WebsitePreview extends Component {
useEffect(() => {
this.websiteService.currentWebsiteId = this.websiteId;
// The params used to configure the context should be ignored when
// the action is restored (example: click on the breadcrumb).
const isRestored = this.props.action.jsId === this.websiteService.actionJsId;
this.websiteService.actionJsId = this.props.action.jsId;
if (isRestored) {
if (this.isRestored) {
return;
}
this.websiteService.context.showNewContentModal = this.props.action.context.params && this.props.action.context.params.display_new_content;
@@ -95,6 +94,8 @@ export class WebsitePreview extends Component {
this.env.services.messaging.modelManager.messagingCreatedPromise.then(() => {
this.env.services.messaging.modelManager.messaging.update({ isWebsitePreviewOpen: false });
});
const { pathname, search, hash } = this.iframe.el.contentWindow.location;
this.websiteService.lastUrl = `${pathname}${search}${hash}`;
this.websiteService.currentWebsiteId = null;
this.websiteService.websiteRootInstance = undefined;
this.websiteService.pageDocument = null;
@@ -189,28 +190,27 @@ export class WebsitePreview extends Component {
}
get path() {
let path = this.websiteService.editedObjectPath;
if (!path) {
path = this.props.action.context.params && this.props.action.context.params.path;
if (path) {
const url = new URL(path, window.location.origin);
if (this._isTopWindowURL(url)) {
// If the client action is initialized with a path that
// should not be opened inside the iframe (= something we
// would want to open on the top window), we consider that
// this is not a valid flow. Instead of trying to open it on
// the top window, we initialize the iframe with the
// website homepage...
path = '/';
} else {
// ... otherwise, the path still needs to be normalized (as
// it would be if the given path was used as an href of a
// <a/> element).
path = url.pathname + url.search + url.hash;
}
} else {
let path = this.isRestored
? this.websiteService.lastUrl
: this.props.action.context.params && this.props.action.context.params.path;
if (path) {
const url = new URL(path, window.location.origin);
if (this._isTopWindowURL(url)) {
// If the client action is initialized with a path that should
// not be opened inside the iframe (= something we would want to
// open on the top window), we consider that this is not a valid
// flow. Instead of trying to open it on the top window, we
// initialize the iframe with the website homepage...
path = '/';
} else {
// ... otherwise, the path still needs to be normalized (as it
// would be if the given path was used as an href of a <a/>
// element).
path = url.pathname + url.search + url.hash;
}
} else {
path = '/';
}
return path;
}
@@ -32,7 +32,7 @@ export const websiteService = {
let fullscreen;
let pageDocument;
let contentWindow;
let editedObjectPath;
let lastUrl;
let websiteRootInstance;
let Wysiwyg;
let isRestrictedEditor;
@@ -151,11 +151,11 @@ export const websiteService = {
websiteRootInstance = rootInstance;
context.isPublicRootReady = !!rootInstance;
},
set editedObjectPath(path) {
editedObjectPath = path;
set lastUrl(url) {
lastUrl = url;
},
get editedObjectPath() {
return editedObjectPath;
get lastUrl() {
return lastUrl;
},
get isRestrictedEditor() {
return isRestrictedEditor === true;
@@ -3,7 +3,7 @@
import { registry } from "@web/core/registry";
import { useService, useBus } from "@web/core/utils/hooks";
const { Component, onWillStart, onMounted, useState } = owl;
const { Component, onWillStart, useState } = owl;
const websiteSystrayRegistry = registry.category('website_systray');
@@ -15,16 +15,10 @@ export class EditInBackendSystray extends Component {
onWillStart(this._updateMainObjectName);
useBus(websiteSystrayRegistry, 'CONTENT-UPDATED', this._updateMainObjectName);
onMounted(() => {
this.websiteService.editedObjectPath = null;
});
}
editInBackend() {
const { metadata: { mainObject } } = this.websiteService.currentWebsite;
const location = this.websiteService.contentWindow.location;
this.websiteService.editedObjectPath = location.pathname + location.search + location.hash;
this.actionService.doAction({
res_model: mainObject.model,
res_id: mainObject.id,