[REF] web, website, *: make wowl services available in frontend

*: http_routing

When rewriting the webclient, a new environment was created, as well as
a new type of service and a new mechanism to start those services. This
environment and the services that go with it were not made available in
the frontend however.

This commit adapts the setup code for the frontend's root widget (and
the website specific equivalent, WebsiteRoot) so that the new
environment exists, and some of the calls to the legacy services are
redirected to the new services. The point is to allow removing some
legacy services whose code is currently only needed by the frontent
because of the lack of availability of this new env and services

Part of #72675
This commit is contained in:
Samuel Degueldre
2021-07-14 07:34:16 +00:00
parent 838a1daef3
commit db7b485d98
10 changed files with 93 additions and 67 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ from odoo.addons.web.controllers.main import WebClient, Home
class Routing(Home):
@http.route('/website/translations/<string:unique>', type='http', auth="public", website=True)
def get_website_translations(self, unique, lang, mods=None):
def get_website_translations(self, unique, lang=None, mods=None):
IrHttp = request.env['ir.http'].sudo()
modules = IrHttp.get_translation_frontend_modules()
if mods:
@@ -14,35 +14,35 @@ tour.register('test_error_website', {
trigger: 'a[href="/test_user_error_json"]',
}, {
content: "rpc user error modal has message",
extra_trigger: 'div.toast-body:contains("This is a user rpc test")',
extra_trigger: 'div.o_notification_content:contains("This is a user rpc test")',
trigger: 'button.o_notification_close',
}, {
content: "trigger rpc access error",
trigger: 'a[href="/test_access_error_json"]',
}, {
content: "rpc access error modal has message",
extra_trigger: 'div.toast-body:contains("This is an access rpc test")',
extra_trigger: 'div.o_notification_content:contains("This is an access rpc test")',
trigger: 'button.o_notification_close',
}, {
content: "trigger validation rpc error",
trigger: 'a[href="/test_validation_error_json"]',
}, {
content: "rpc validation error modal has message",
extra_trigger: 'div.toast-body:contains("This is a validation rpc test")',
extra_trigger: 'div.o_notification_content:contains("This is a validation rpc test")',
trigger: 'button.o_notification_close',
}, {
content: "trigger rpc missing error",
trigger: 'a[href="/test_missing_error_json"]',
}, {
content: "rpc missing error modal has message",
extra_trigger: 'div.toast-body:contains("This is a missing rpc test")',
extra_trigger: 'div.o_notification_content:contains("This is a missing rpc test")',
trigger: 'button.o_notification_close',
}, {
content: "trigger rpc error 403",
trigger: 'a[href="/test_access_denied_json"]',
}, {
content: "rpc error 403 modal has message",
extra_trigger: 'div.toast-body:contains("This is an access denied rpc test")',
extra_trigger: 'div.o_notification_content:contains("This is an access denied rpc test")',
trigger: 'button.o_notification_close',
}, {
content: "trigger rpc error 500",
+9 -1
View File
@@ -195,10 +195,16 @@ This module provides the core of the Odoo Web Client.
('include', 'web._assets_frontend_helpers'),
'web/static/lib/bootstrap/scss/_variables.scss',
'web/static/lib/luxon/luxon.js',
('include', 'web._assets_bootstrap'),
'web/static/src/core/registry.js',
'web/static/src/env.js',
'web/static/src/core/utils/transitions.scss', # included early because used by other files
'web/static/src/core/**/*',
# TODO: split debug files correctly when converting frontend debug
# manager so we don't need action-service and stuff
('remove', 'web/static/src/core/debug/**/*'),
'web/static/src/legacy/scss/base_frontend.scss',
'web/static/src/legacy/scss/lazyloader.scss',
@@ -206,6 +212,8 @@ This module provides the core of the Odoo Web Client.
('include', 'web.assets_frontend_minimal'),
'web/static/src/legacy/utils.js',
'web/static/src/legacy/js/owl_compatibility.js',
'web/static/src/legacy/js/services/session.js',
'web/static/src/legacy/js/public/public_env.js',
'web/static/src/legacy/js/public/public_root.js',
+1 -1
View File
@@ -99,7 +99,7 @@ const loadCSS = memoize(function loadCSS(url) {
* @returns {Promise<XMLDocument>} A Promise of an XML document containing the
* owl templates.
*/
const loadBundleTemplates = memoize(async function loadBundleTemplates(name) {
export const loadBundleTemplates = memoize(async function loadBundleTemplates(name) {
// TODO: quid of the "unique" in the URL? We can"t have one cache_hash
// for each and every bundle I"m guessing.
const bundleURL = new URL(`/web/webclient/qweb/${Date.now()}`, window.location.origin);
@@ -13,7 +13,8 @@ export const localizationService = {
const cacheHashes = session.cache_hashes;
const translationsHash = cacheHashes.translations || new Date().getTime().toString();
const lang = user.lang || null;
let url = `/web/webclient/translations/${translationsHash}`;
const translationURL = session.translationURL || "/web/webclient/translations";
let url = `${translationURL}/${translationsHash}`;
if (lang) {
url += `?lang=${lang}`;
}
@@ -22,6 +23,7 @@ export const localizationService = {
if (!response.ok) {
throw new Error("Error while fetching translations");
}
const { lang_parameters: userLocalization, modules: modules } = await response.json();
// FIXME We flatten the result of the python route.
@@ -70,7 +70,9 @@ var TranslationDataBase = Class.extend(/** @lends instance.TranslationDataBase#
if (modules) {
paramsGet.modules = modules.join(',');
}
paramsGet.lang = lang || null;
if (lang) {
paramsGet.lang = lang;
}
return $.get(url, paramsGet).then(function (trans) {
self.set_bundle(trans);
});
@@ -8,6 +8,23 @@ import utils from 'web.utils';
import publicWidget from 'web.public.widget';
import { registry } from '@web/core/registry';
import AbstractService from "web.AbstractService";
import legacyEnv from "web.public_env";
import lazyloader from "web.public.lazyloader";
import {
makeLegacyNotificationService,
makeLegacyRpcService,
makeLegacySessionService,
makeLegacyDialogMappingService,
} from "../../utils";
import { ComponentAdapter } from "web.OwlCompatibility";
import { loadBundleTemplates } from "@web/core/assets";
import { makeEnv, startServices } from "@web/env";
import { MainComponentsContainer } from "@web/core/main_components_container";
const serviceRegistry = registry.category("services");
// Load localizations outside the PublicRoot to not wait for DOM ready (but
// wait for them in PublicRoot)
function getLang() {
@@ -23,7 +40,7 @@ var localeDef = ajax.loadJS('/web/webclient/locale/' + lang.replace('-', '_'));
* this Class instance. Its main role will be to retrieve RPC demands from its
* children and handle them.
*/
var PublicRoot = publicWidget.RootWidget.extend({
export const PublicRoot = publicWidget.RootWidget.extend({
events: _.extend({}, publicWidget.RootWidget.prototype.events || {}, {
'submit .js_website_submit_form': '_onWebsiteFormSubmit',
'click .js_disable_on_click': '_onDisableOnClick',
@@ -240,11 +257,14 @@ var PublicRoot = publicWidget.RootWidget.extend({
}
} else if (payload.service === 'ajax' && payload.method === 'loadLibs') {
args[1] = _computeContext.call(this, args[1]);
} else {
return;
}
const service = this.env.services[payload.service];
const result = service[payload.method].apply(service, args);
payload.callback(result);
ev.stopPropagation();
},
/**
* Called when someone asked for the global public context.
@@ -328,6 +348,46 @@ var PublicRoot = publicWidget.RootWidget.extend({
},
});
export default {
PublicRoot: PublicRoot,
};
const { Component, mount } = owl;
/**
* Configure Owl with the public env
*/
owl.config.mode = legacyEnv.isDebug() ? "dev" : "prod";
owl.Component.env = legacyEnv;
/**
* This widget is important, because the tour manager needs a root widget in
* order to work. The root widget must be a service provider with the ajax
* service, so that the tour manager can let the server know when tours have
* been consumed.
*/
export async function createPublicRoot(RootWidget) {
await lazyloader.allScriptsLoaded;
AbstractService.prototype.deployServices(legacyEnv);
// add a bunch of mapping services that will redirect service calls from the legacy env
// to the wowl env
serviceRegistry.add("legacy_rpc", makeLegacyRpcService(legacyEnv));
serviceRegistry.add("legacy_session", makeLegacySessionService(legacyEnv, session));
serviceRegistry.add("legacy_notification", makeLegacyNotificationService(legacyEnv));
serviceRegistry.add("legacy_crash_manager", makeLegacyCrashManagerService(legacyEnv));
serviceRegistry.add("legacy_dialog_mapping", makeLegacyDialogMappingService(legacyEnv));
await Promise.all([owl.utils.whenReady(), session.is_bound]);
const wowlEnv = makeEnv();
wowlEnv.qweb.addTemplates(await loadBundleTemplates("web.assets_frontend"));
await startServices(wowlEnv);
const adapter = new ComponentAdapter(null, { Component }); // Used for _trigger_up compat layer
const publicRoot = new RootWidget(adapter);
await Promise.all([
mount(MainComponentsContainer, {
target: document.body,
env: wowlEnv,
}),
publicRoot.attachTo(document.body),
]);
return publicRoot;
}
export default { PublicRoot, createPublicRoot };
@@ -1,30 +1,4 @@
/** @odoo-module alias=root.widget */
import { PublicRoot, createPublicRoot } from "./public_root";
import AbstractService from 'web.AbstractService';
import env from 'web.public_env';
import lazyloader from 'web.public.lazyloader';
import rootData from 'web.public.root';
/**
* Configure Owl with the public env
*/
owl.config.mode = env.isDebug() ? "dev" : "prod";
owl.Component.env = env;
/**
* Deploy services in the env
*/
AbstractService.prototype.deployServices(env);
/**
* This widget is important, because the tour manager needs a root widget in
* order to work. The root widget must be a service provider with the ajax
* service, so that the tour manager can let the server know when tours have
* been consumed.
*/
var publicRoot = new rootData.PublicRoot(null);
export default lazyloader.allScriptsLoaded.then(function () {
return publicRoot.attachTo(document.body).then(function () {
return publicRoot;
});
});
export default createPublicRoot(PublicRoot);
@@ -8,7 +8,7 @@ import publicRootData from 'web.public.root';
import "web.zoomodoo";
import { FullscreenIndication } from '@website/js/widgets/fullscreen_indication';
var WebsiteRoot = publicRootData.PublicRoot.extend(KeyboardNavigationMixin, {
export const WebsiteRoot = publicRootData.PublicRoot.extend(KeyboardNavigationMixin, {
events: _.extend({}, KeyboardNavigationMixin.events, publicRootData.PublicRoot.prototype.events || {}, {
'click .js_change_lang': '_onLangChangeClick',
'click .js_publish_management .js_publish_btn': '_onPublishBtnClick',
@@ -1,26 +1,6 @@
odoo.define('root.widget', function (require) {
'use strict';
/** @odoo-module alias=root.widget */
const AbstractService = require('web.AbstractService');
const env = require('web.public_env');
var lazyloader = require('web.public.lazyloader');
var websiteRootData = require('website.root');
import { createPublicRoot } from "@web/legacy/js/public/public_root";
import { WebsiteRoot } from "./website_root";
/**
* Configure Owl with the public env
*/
owl.config.mode = env.isDebug() ? "dev" : "prod";
owl.Component.env = env;
/**
* Deploy services in the env
*/
AbstractService.prototype.deployServices(env);
var websiteRoot = new websiteRootData.WebsiteRoot(null);
return lazyloader.allScriptsLoaded.then(function () {
return websiteRoot.attachTo(document.body).then(function () {
return websiteRoot;
});
});
});
export default createPublicRoot(WebsiteRoot);