mirror of https://github.com/OCA/web.git
Add web_fix_modules_load
parent
795ef060fe
commit
119c67e976
|
@ -0,0 +1 @@
|
||||||
|
../../../../web_fix_modules_load
|
|
@ -0,0 +1,6 @@
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
setuptools.setup(
|
||||||
|
setup_requires=['setuptools-odoo'],
|
||||||
|
odoo_addon=True,
|
||||||
|
)
|
|
@ -0,0 +1 @@
|
||||||
|
bot, please!
|
|
@ -0,0 +1,2 @@
|
||||||
|
from . import controllers
|
||||||
|
from . import models
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Copyright 2022 Camptocamp SA
|
||||||
|
# @author Simone Orsi <simahawk@gmail.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
{
|
||||||
|
"name": "Fix translation loading",
|
||||||
|
"summary": "Fix translations loading from frontend with many modules",
|
||||||
|
"version": "14.0.1.0.0",
|
||||||
|
"category": "Hidden",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"development_status": "Alpha",
|
||||||
|
"website": "https://github.com/OCA/web",
|
||||||
|
"author": "Camptocamp,Odoo Community Association (OCA)",
|
||||||
|
"maintainers": ["simahawk"],
|
||||||
|
"depends": [
|
||||||
|
"web",
|
||||||
|
],
|
||||||
|
"data": ["templates/assets.xml"],
|
||||||
|
"installable": True,
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
from . import main
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Copyright 2022 Camptocamp SA
|
||||||
|
# @author Simone Orsi <simahawk@gmail.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import http
|
||||||
|
|
||||||
|
from odoo.addons.web.controllers.main import WebClient
|
||||||
|
|
||||||
|
|
||||||
|
class WebClientPatched(WebClient):
|
||||||
|
"""Handle conversions of modules' ids to their names."""
|
||||||
|
|
||||||
|
def _get_mod_names(self, mods):
|
||||||
|
"""Retrieve module names from their IDs in any form."""
|
||||||
|
mod_names = mods
|
||||||
|
model = http.request.env["ir.module.module"].sudo()
|
||||||
|
if isinstance(mods, str):
|
||||||
|
mods = [int(x.strip()) for x in mods.split(",") if x.strip().isdigit()]
|
||||||
|
if mods and isinstance(mods[0], int):
|
||||||
|
mod_names = model.browse(mods).mapped("name")
|
||||||
|
return mod_names
|
||||||
|
|
||||||
|
@http.route()
|
||||||
|
def qweb(self, unique, mods=None, db=None):
|
||||||
|
# Here `mods` comes as 1,2,3,4 string
|
||||||
|
mods = self._get_mod_names(mods)
|
||||||
|
return super().qweb(unique, mods=mods, db=db)
|
||||||
|
|
||||||
|
@http.route()
|
||||||
|
def bootstrap_translations(self, mods):
|
||||||
|
mods = self._get_mod_names(mods)
|
||||||
|
return super().bootstrap_translations(mods)
|
||||||
|
|
||||||
|
@http.route()
|
||||||
|
def csslist(self, mods=None):
|
||||||
|
mods = self._get_mod_names(mods)
|
||||||
|
return super().csslist(mods=mods)
|
||||||
|
|
||||||
|
@http.route()
|
||||||
|
def jslist(self, mods=None):
|
||||||
|
mods = self._get_mod_names(mods)
|
||||||
|
return super().jslist(mods=mods)
|
||||||
|
|
||||||
|
@http.route()
|
||||||
|
def translations(self, unique, mods=None, lang=None):
|
||||||
|
mods = self._get_mod_names(mods)
|
||||||
|
mods = ",".join(mods)
|
||||||
|
return super().translations(unique, mods, lang)
|
|
@ -0,0 +1,2 @@
|
||||||
|
from . import ir_module
|
||||||
|
from . import ir_translation
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Copyright 2022 Camptocamp SA
|
||||||
|
# @author Simone Orsi <simahawk@gmail.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from odoo import models
|
||||||
|
|
||||||
|
from odoo.addons.web.controllers.main import module_boot
|
||||||
|
|
||||||
|
|
||||||
|
class IrModule(models.Model):
|
||||||
|
_inherit = "ir.module.module"
|
||||||
|
|
||||||
|
def _session_modules_info(self):
|
||||||
|
"""Load modules info and return their mapping."""
|
||||||
|
module_names = module_boot(self.env.cr.dbname)
|
||||||
|
modules = self.sudo().search([("name", "in", module_names)])
|
||||||
|
data = {mod.name: {"id": mod.id} for mod in modules}
|
||||||
|
return json.dumps(data)
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Copyright 2022 Camptocamp SA
|
||||||
|
# @author Simone Orsi <simahawk@gmail.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
|
||||||
|
from odoo import models
|
||||||
|
|
||||||
|
|
||||||
|
class IrTranslation(models.Model):
|
||||||
|
_inherit = "ir.translation"
|
||||||
|
|
||||||
|
def get_translations_for_webclient(self, mods, lang):
|
||||||
|
# Intercept call to load translations from modules' ids instead of names.
|
||||||
|
if mods and isinstance(mods[0], int):
|
||||||
|
model = self.env["ir.module.module"].sudo()
|
||||||
|
mods = model.browse(mods).mapped("name")
|
||||||
|
return super().get_translations_for_webclient(mods, lang)
|
|
@ -0,0 +1 @@
|
||||||
|
* Simone Orsi <simone.orsi@camptocamp.com>
|
|
@ -0,0 +1,7 @@
|
||||||
|
Odoo loads translations and module info using their names.
|
||||||
|
When you have a lot of modules installed (eg: 500+)
|
||||||
|
this can lead to very big GET requests (more than 12k) which, in most of the cases,
|
||||||
|
will be blocked by the web server (eg: nginx) because they are too big.
|
||||||
|
|
||||||
|
This module tries to fix this by using modules' ids instead of names
|
||||||
|
reducing dramatically the size of such requests.
|
|
@ -0,0 +1,127 @@
|
||||||
|
odoo.define("web_load_translations_fix.Session", function (require) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Session = require("web.Session");
|
||||||
|
var core = require("web.core");
|
||||||
|
var _t = core._t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override session manager to change how modules' are loaded: use ids instead of names.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Session.include({
|
||||||
|
_modules_info: function () {
|
||||||
|
return odoo._modules_info;
|
||||||
|
},
|
||||||
|
_module_ids: function (names) {
|
||||||
|
const mod_names = names ? names : this.module_list;
|
||||||
|
const info = this._modules_info();
|
||||||
|
const ids = [];
|
||||||
|
_.each(mod_names, function (name) {
|
||||||
|
if (info[name]) {
|
||||||
|
ids.push(info[name].id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.debug("Session: load module names", mod_names);
|
||||||
|
return ids;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Full override due to no available hook.
|
||||||
|
* The whole code is taken as-is from Odoo core (comments included).
|
||||||
|
* Only the call to `load_translations` has been modified to use `_module_ids`.
|
||||||
|
* @returns: Promise
|
||||||
|
*/
|
||||||
|
load_translations: function () {
|
||||||
|
var lang = this.user_context.lang;
|
||||||
|
/* We need to get the website lang at this level.
|
||||||
|
The only way is to get it is to take the HTML tag lang
|
||||||
|
Without it, we will always send undefined if there is no lang
|
||||||
|
in the user_context. */
|
||||||
|
var html = document.documentElement,
|
||||||
|
htmlLang = html.getAttribute("lang");
|
||||||
|
if (!this.user_context.lang && htmlLang) {
|
||||||
|
lang = htmlLang.replace("-", "_");
|
||||||
|
}
|
||||||
|
return _t.database.load_translations(
|
||||||
|
this,
|
||||||
|
this._module_ids(),
|
||||||
|
lang,
|
||||||
|
this.translationURL
|
||||||
|
);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Full override due to no available hook.
|
||||||
|
* The whole code is taken as-is from Odoo core (comments included).
|
||||||
|
* Only the call to `load_qweb` and `bootstrap_translations` have been modified to use `_module_ids`.
|
||||||
|
* @returns: Promise
|
||||||
|
*/
|
||||||
|
session_init: function () {
|
||||||
|
var self = this;
|
||||||
|
var prom = this.session_reload();
|
||||||
|
|
||||||
|
if (this.is_frontend) {
|
||||||
|
return prom.then(function () {
|
||||||
|
return self.load_translations();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return prom.then(function () {
|
||||||
|
var promise = self.load_qweb(self._module_ids().join(","));
|
||||||
|
if (self.session_is_valid()) {
|
||||||
|
return promise.then(function () {
|
||||||
|
return self.load_modules();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.all([
|
||||||
|
promise,
|
||||||
|
self
|
||||||
|
.rpc("/web/webclient/bootstrap_translations", {
|
||||||
|
mods: self._module_ids(),
|
||||||
|
})
|
||||||
|
.then(function (trans) {
|
||||||
|
_t.database.set_bundle(trans);
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Full override due to no available hook.
|
||||||
|
* The whole code is taken as-is from Odoo core (comments included).
|
||||||
|
* Only the call to `csslist` and `jslist` have been modified to use `_module_ids`.
|
||||||
|
* @returns: Promise
|
||||||
|
*/
|
||||||
|
load_modules: function () {
|
||||||
|
var self = this;
|
||||||
|
var modules = odoo._modules;
|
||||||
|
var all_modules = _.uniq(self.module_list.concat(modules));
|
||||||
|
var to_load = _.difference(modules, self.module_list).join(",");
|
||||||
|
this.module_list = all_modules;
|
||||||
|
var loaded = Promise.resolve(self.load_translations());
|
||||||
|
var locale = "/web/webclient/locale/" + self.user_context.lang || "en_US";
|
||||||
|
var file_list = [locale];
|
||||||
|
if (to_load.length) {
|
||||||
|
loaded = Promise.all([
|
||||||
|
loaded,
|
||||||
|
self
|
||||||
|
.rpc("/web/webclient/csslist", {
|
||||||
|
mods: self._module_ids(to_load),
|
||||||
|
})
|
||||||
|
.then(self.load_css.bind(self)),
|
||||||
|
self.load_qweb(to_load),
|
||||||
|
self
|
||||||
|
.rpc("/web/webclient/jslist", {mods: self._module_ids(to_load)})
|
||||||
|
.then(function (files) {
|
||||||
|
file_list = file_list.concat(files);
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return loaded
|
||||||
|
.then(function () {
|
||||||
|
return self.load_js(file_list);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
self._configureLocale();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<template id="assets_backend" inherit_id="web.assets_backend">
|
||||||
|
<xpath expr="//t[@t-raw='get_modules_order()']/.." position="after">
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
odoo._modules_info = <t
|
||||||
|
t-raw="request.env['ir.module.module']._session_modules_info()"
|
||||||
|
/>;
|
||||||
|
</script>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="assets_common" inherit_id="web.assets_common">
|
||||||
|
<xpath expr="//script[last()]" position="after">
|
||||||
|
<script src="/web_fix_modules_load/static/src/js/session.js" />
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</odoo>
|
Loading…
Reference in New Issue