[FIX] website, *: redirect to the WebsitePreview using ir.actions.client

*: website_forum, website_hr_recruitment, website_sale

Before this commit, most of the backend redirections to the
WebsitePreview, introduced in [1], were using ir.actions.url with the
get_client_action_url util, which was not optimal.

This commit changes that to use a new get_client_action method, which
returns the ir.actions.client record. It will execute the action
directly, avoid to redirect the router before, and improve performances.
Also, it allows to solve bugs, as:
- The back navigation from the WebsitePreview to the ListViews.
Going through the /web controller would add an entry in the history, and
going back on it would reload the client action.

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

task-2687506

closes odoo/odoo#102991

X-original-commit: 30fb11e479fb7b3db3649e55fcbdb06bfcdb398c
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
Younn Olivier
2022-10-11 08:07:46 +02:00
committed by qsm-odoo
parent 2f53a7e7b5
commit d6bf2c0cbf
11 changed files with 56 additions and 55 deletions
+2 -2
View File
@@ -399,8 +399,8 @@ class IrModuleModule(models.Model):
result = active_todo.action_launch()
else:
result = website.button_go_website(mode_edit=True)
if result.get('url') and 'enable_editor' in result['url']:
result['url'] = result['url'].replace('enable_editor', 'with_loader=1&enable_editor')
if result.get('tag') == 'website_preview' and result.get('context', {}).get('params', {}).get('enable_editor'):
result['context']['params']['with_loader'] = True
return result
def button_remove_theme(self):
+11 -14
View File
@@ -200,12 +200,7 @@ class WebsitePublishedMixin(models.AbstractModel):
return self.write({'website_published': not self.website_published})
def open_website_url(self):
url = self.env['website'].get_client_action_url(self.website_url)
return {
'type': 'ir.actions.act_url',
'url': url,
'target': 'self',
}
return self.env['website'].get_client_action(self.website_url)
@api.model_create_multi
def create(self, vals_list):
@@ -283,16 +278,18 @@ class WebsitePublishedMultiMixin(WebsitePublishedMixin):
return is_published
def open_website_url(self):
client_action_url = self.env['website'].get_client_action_url(self.website_url)
website_id = False
if self.website_id:
client_action_url = f'{client_action_url}&website_id={self.website_id.id}'
website_id = self.website_id.id
if self.website_id.domain:
client_action_url = url_join(self.website_id.domain, client_action_url)
return {
'type': 'ir.actions.act_url',
'url': client_action_url,
'target': 'self',
}
client_action_url = self.env['website'].get_client_action_url(self.website_url)
client_action_url = f'{client_action_url}&website_id={website_id}'
return {
'type': 'ir.actions.act_url',
'url': url_join(self.website_id.domain, client_action_url),
'target': 'self',
}
return self.env['website'].get_client_action(self.website_url, False, website_id)
class WebsiteSearchableMixin(models.AbstractModel):
+12 -6
View File
@@ -1301,18 +1301,24 @@ class Website(models.Model):
action_params["enable_editor"] = 1
return "/web#" + urls.url_encode(action_params)
def get_client_action(self, url, mode_edit=False, website_id=False):
action = self.env["ir.actions.actions"]._for_xml_id("website.website_preview")
action['context'] = {
'params': {
'path': url,
'enable_editor': mode_edit,
'website_id': website_id,
}
}
return action
def button_go_website(self, path='/', mode_edit=False):
self._force()
if mode_edit:
# If the user gets on a translated page (e.g /fr) the editor will
# never start. Forcing the default language fixes this issue.
path = url_for(path, self.default_lang_id.url_code)
path = self.get_client_action_url(path, True)
return {
'type': 'ir.actions.act_url',
'url': path,
'target': 'self',
}
return self.get_client_action(path, mode_edit)
def _get_canonical_url_localized(self, lang, canonical_params):
"""Returns the canonical URL for the current request with translatable
@@ -127,6 +127,7 @@ export class WebsitePreview extends Component {
}, () => []);
useEffect(() => {
let leftOnBackNavigation = false;
// When reaching a "regular" url of the webclient's router, an
// hashchange event should be dispatched to properly display the
// content of the previous URL before reaching the client action,
@@ -136,12 +137,18 @@ export class WebsitePreview extends Component {
window.dispatchEvent(new HashChangeEvent('hashchange', {
newURL: window.location.href.toString()
}));
leftOnBackNavigation = true;
}
};
window.addEventListener('popstate', handleBackNavigation);
return () => {
history.pushState({}, null, this.backendUrl);
window.removeEventListener('popstate', handleBackNavigation);
// When leaving the client action, its original url is pushed
// so that the router can replay the action on back navigation
// from other screens.
if (!leftOnBackNavigation) {
history.pushState({}, null, this.backendUrl);
}
};
}, () => []);
@@ -20,6 +20,7 @@ export const PageControllerMixin = (component) => class extends component {
super.setup();
this.website = useService('website');
this.dialog = useService('dialog');
this.rpc = useService('rpc');
this.websiteSelection = [{id: 0, name: this.env._t("All Websites")}];
@@ -37,14 +38,15 @@ export const PageControllerMixin = (component) => class extends component {
* Adds the new 'website content' record depending on the targeted model and
* 'create_action' passed in context.
*/
createWebsiteContent() {
async createWebsiteContent() {
if (this.props.resModel === 'website.page') {
return this.dialog.add(AddPageDialog, {selectWebsite: true});
}
const action = this.props.context.create_action;
if (action) {
if (/^\//.test(action)) {
window.location.replace(action);
const url = await this.rpc(action);
this.website.goToWebsite({ path: url, edition: true });
return;
}
this.actionService.doAction(action, {
@@ -28,10 +28,17 @@ export function useLoaderOnClick() {
try {
const resParams = params.getResParams();
const callback = await orm.silent.call(resParams.resModel, name, [[resParams.resId]]);
let keepLoader = false;
if (callback) {
callback.target = 'main';
await action.doAction(callback);
if (callback.tag === 'website_preview' && callback.context.params.with_loader) {
keepLoader = true;
}
}
if (!keepLoader) {
website.hideLoader();
}
website.hideLoader();
} catch (error) {
website.hideLoader();
throw error;
@@ -27,9 +27,5 @@ class BaseLanguageInstall(models.TransientModel):
params = self._context.get('params', {})
if 'url_return' in params:
url = params['url_return'].replace('[lang]', self.first_lang_id.code)
return {
'url': self.env['website'].get_client_action_url(url),
'type': 'ir.actions.act_url',
'target': 'self'
}
return self.env['website'].get_client_action(url)
return action
+2 -10
View File
@@ -252,11 +252,7 @@ class Forum(models.Model):
def go_to_website(self):
self.ensure_one()
return {
'type': 'ir.actions.act_url',
'target': 'self',
'url': self.env['website'].get_client_action_url(self._compute_website_url()),
}
return self.env['website'].get_client_action(self._compute_website_url())
@api.model
def _update_website_count(self):
@@ -974,11 +970,7 @@ class Post(models.Model):
def go_to_website(self):
self.ensure_one()
return {
'type': 'ir.actions.act_url',
'target': 'self',
'url': self.env['website'].get_client_action_url(self.website_url),
}
return self.env['website'].get_client_action(self.website_url)
@api.model
def _search_get_detail(self, website, order, options):
@@ -85,13 +85,13 @@ class WebsiteHrRecruitment(http.Controller):
'contract_type_id': contract_type_id,
})
@http.route('/jobs/add', type='http', auth="user", website=True)
@http.route('/jobs/add', type='json', auth="user", website=True)
def jobs_add(self, **kwargs):
# avoid branding of website_description by setting rendering_bundle in context
job = request.env['hr.job'].with_context(rendering_bundle=True).create({
'name': _('Job Title'),
})
return request.redirect(request.env["website"].get_client_action_url(f"/jobs/detail/{slug(job)}", True))
return f"/jobs/detail/{slug(job)}"
@http.route('''/jobs/detail/<model("hr.job"):job>''', type='http', auth="public", website=True, sitemap=True)
def jobs_detail(self, job, **kwargs):
@@ -12,7 +12,9 @@ patch(NewContentModal.prototype, 'website_hr_recruitment_new_content', {
newJobElement.status = MODULE_STATUS.INSTALLED;
},
createNewJob() {
window.location.replace('/jobs/add');
async createNewJob() {
const url = await this.rpc('/jobs/add');
this.website.goToWebsite({ path: url, edition: true });
this.websiteContext.showNewContentModal = false;
}
});
@@ -125,19 +125,11 @@ class ResConfigSettings(models.TransientModel):
def action_update_terms(self):
self.ensure_one()
return {
'type': 'ir.actions.act_url',
'url': self.env["website"].get_client_action_url('/terms', True),
'target': 'self',
}
return self.env["website"].get_client_action('/terms', True)
def action_open_extra_info(self):
self.ensure_one()
return {
'type': 'ir.actions.act_url',
'url': self.env["website"].get_client_action_url('/shop/extra_info', True),
'target': 'self',
}
return self.env["website"].get_client_action('/shop/extra_info', True)
def action_open_sale_mail_templates(self):
return {