mirror of https://github.com/OCA/web.git
commit
6da6fe1878
|
@ -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