From 1ed1c7d88d542fe578f7e6f8677f43a2fa384d90 Mon Sep 17 00:00:00 2001 From: hparfr Date: Fri, 27 Apr 2018 16:03:22 +0200 Subject: [PATCH 1/6] Add web_cache_name_get module --- web_cache_name_get/README.rst | 70 +++++++++++++++++ web_cache_name_get/__init__.py | 0 web_cache_name_get/__manifest__.py | 21 +++++ web_cache_name_get/static/src/js/view_list.js | 76 +++++++++++++++++++ web_cache_name_get/views/view.xml | 10 +++ 5 files changed, 177 insertions(+) create mode 100644 web_cache_name_get/README.rst create mode 100644 web_cache_name_get/__init__.py create mode 100644 web_cache_name_get/__manifest__.py create mode 100644 web_cache_name_get/static/src/js/view_list.js create mode 100644 web_cache_name_get/views/view.xml diff --git a/web_cache_name_get/README.rst b/web_cache_name_get/README.rst new file mode 100644 index 00000000..9948e382 --- /dev/null +++ b/web_cache_name_get/README.rst @@ -0,0 +1,70 @@ +.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 + +================ +Cache name_get() +================ + +This module improves the loading time of some views: mainly sale or purchase orders +with many order lines. + +It reduce the numer of useless requests done by the user's browser. + + +This modules cache some requests to name_get() done from list views. + +For instance, if you have 40 sale order lines on a sale. All theses lines have the same tax. + +- Without this module : your browser makes about 40 time the same name_get() request. +- With this modules: your browser makes 1 request and reuse the result for all the lines. + +It works on many2many on list views. +The cache is cleaned when you navigate to other objects. + + +Usage +===== + + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/162/10.0 + +Known issues / Roadmap +====================== + +* The cache is not very aggressive, if put more globally it may catch more useless requests. + + +Credits +======= + +Contributors +------------ + +* Raphaël Reverdy + + +Funders +------- + +The development of this module has been financially supported by: + +* Akretion + + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/web_cache_name_get/__init__.py b/web_cache_name_get/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/web_cache_name_get/__manifest__.py b/web_cache_name_get/__manifest__.py new file mode 100644 index 00000000..d5a0cd44 --- /dev/null +++ b/web_cache_name_get/__manifest__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Raphaël Reverdy - Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Cache name_get", + "version": "10.0.1.0.0", + "author": "Akretion, " + "Odoo Community Association (OCA)", + "license": "AGPL-3", + "category": "Usability", + "summary": "Limit useless name_get requests", + "depends": [ + 'web', + ], + "data": [ + 'views/view.xml', + ], + 'installable': True, + "application": False, +} diff --git a/web_cache_name_get/static/src/js/view_list.js b/web_cache_name_get/static/src/js/view_list.js new file mode 100644 index 00000000..f931acd2 --- /dev/null +++ b/web_cache_name_get/static/src/js/view_list.js @@ -0,0 +1,76 @@ +odoo.define('web_cache_name_get.view_list', function(require) { + "use strict"; + + var listView = require('web.ListView'); + var Model = require('web.DataModel'); + var core = require('web.core'); + var _t = core._t; + + listView.List.include({ + /* + cache name_get of many2many in order to reduce + useless requests + first part is a copy paste of web/static/src/js/views/list_view.js + because we have hook into it and can't do much better than that. + */ + render_cell: function (record, column) { + var value; + if (column.type !== 'many2many') { + return this._super(record, column); + } else { + value = record.get(column.id); + // non-resolved (string) m2m values are arrays + if (value instanceof Array && !_.isEmpty(value) + && !record.get(column.id + '__display')) { + var ids; + // they come in two shapes: + if (value[0] instanceof Array) { + _.each(value, function(command) { + switch (command[0]) { + case 4: ids.push(command[1]); break; + case 5: ids = []; break; + case 6: ids = command[2]; break; + default: throw new Error(_.str.sprintf( _t("Unknown m2m command %s"), command[0])); + } + }); + } else { + // 2. an array of ids + ids = value; + } + // the logic starts here + + // create a cache if not already done + this.name_get_cache = this.name_get_cache || {}; + var prom = null; + var key = JSON.stringify([column.relation, ids, this.dataset.get_context()]); + + if (this.name_get_cache[key]) { + prom = this.name_get_cache[key]; + } + if (!prom) { + prom = new Model(column.relation) + .call('name_get', [ids, this.dataset.get_context()]); + this.name_get_cache[key] = prom; + } + // put placeholder at first to limit races conditions + // because of the cached answers + // promise resolution can happen before placeholder set + // and lead to "too much recursion" + + // temporary empty display name + record.set(column.id + '__display', false); + prom.done(function (names) { + // FIXME: nth horrible hack in this poor listview + record.set(column.id + '__display', + _(names).pluck(1).join(', ')); + record.set(column.id, ids); + }); + } + } + return column.format(record.toForm().data, { + model: this.dataset.model, + id: record.get('id') + }); + }, + }); +}); diff --git a/web_cache_name_get/views/view.xml b/web_cache_name_get/views/view.xml new file mode 100644 index 00000000..30c58b7d --- /dev/null +++ b/web_cache_name_get/views/view.xml @@ -0,0 +1,10 @@ + + + + + + From 2ecc3b5c92e768bb2cdebec8af1baacc5c244f44 Mon Sep 17 00:00:00 2001 From: Hpar Date: Wed, 21 Nov 2018 11:54:05 +0100 Subject: [PATCH 2/6] Update readme Rename the module --- web_cache_name_get/README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web_cache_name_get/README.rst b/web_cache_name_get/README.rst index 9948e382..781ec572 100644 --- a/web_cache_name_get/README.rst +++ b/web_cache_name_get/README.rst @@ -2,9 +2,9 @@ :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 -================ -Cache name_get() -================ +================== +Web Cache Name Get +================== This module improves the loading time of some views: mainly sale or purchase orders with many order lines. From a1393c87b1a76c8399a7b7e32e41b68075ac7cb0 Mon Sep 17 00:00:00 2001 From: Hpar Date: Wed, 21 Nov 2018 11:58:12 +0100 Subject: [PATCH 3/6] Update __manifest__ --- web_cache_name_get/__manifest__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web_cache_name_get/__manifest__.py b/web_cache_name_get/__manifest__.py index d5a0cd44..e9a65a3c 100644 --- a/web_cache_name_get/__manifest__.py +++ b/web_cache_name_get/__manifest__.py @@ -5,11 +5,13 @@ { "name": "Cache name_get", "version": "10.0.1.0.0", + "website": "https://github.com/OCA/web", "author": "Akretion, " "Odoo Community Association (OCA)", "license": "AGPL-3", "category": "Usability", "summary": "Limit useless name_get requests", + "maintainers": ["hparfr"], "depends": [ 'web', ], @@ -17,5 +19,4 @@ 'views/view.xml', ], 'installable': True, - "application": False, } From 055848a3d045e331ae23f02522d9a20eeb557afd Mon Sep 17 00:00:00 2001 From: Hpar Date: Wed, 21 Nov 2018 12:00:15 +0100 Subject: [PATCH 4/6] Remove useless key from xml --- web_cache_name_get/views/view.xml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/web_cache_name_get/views/view.xml b/web_cache_name_get/views/view.xml index 30c58b7d..dc56b5fd 100644 --- a/web_cache_name_get/views/view.xml +++ b/web_cache_name_get/views/view.xml @@ -1,10 +1,8 @@ - - - + From d1045ccb92143f45b243c16cf9d0e8a1a5536a6b Mon Sep 17 00:00:00 2001 From: Hpar Date: Wed, 21 Nov 2018 14:58:21 +0100 Subject: [PATCH 5/6] Update readme Fix typo --- web_cache_name_get/README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web_cache_name_get/README.rst b/web_cache_name_get/README.rst index 781ec572..3df0db3c 100644 --- a/web_cache_name_get/README.rst +++ b/web_cache_name_get/README.rst @@ -9,12 +9,12 @@ Web Cache Name Get This module improves the loading time of some views: mainly sale or purchase orders with many order lines. -It reduce the numer of useless requests done by the user's browser. +It reduce the number of useless requests done by the user's browser. This modules cache some requests to name_get() done from list views. -For instance, if you have 40 sale order lines on a sale. All theses lines have the same tax. +For instance, if you have 40 sale order lines on a sale. All these lines have the same tax. - Without this module : your browser makes about 40 time the same name_get() request. - With this modules: your browser makes 1 request and reuse the result for all the lines. From 865ba7b5e4b6760fdf1659c1b284c5c924d69f8b Mon Sep 17 00:00:00 2001 From: hparfr Date: Thu, 25 Apr 2019 17:12:36 +0200 Subject: [PATCH 6/6] Add support of many2one Inc vers number --- web_cache_name_get/README.rst | 4 +- web_cache_name_get/__manifest__.py | 2 +- web_cache_name_get/static/src/js/view_list.js | 79 ++++++++++++++----- 3 files changed, 64 insertions(+), 21 deletions(-) diff --git a/web_cache_name_get/README.rst b/web_cache_name_get/README.rst index 3df0db3c..84d6f443 100644 --- a/web_cache_name_get/README.rst +++ b/web_cache_name_get/README.rst @@ -19,7 +19,7 @@ For instance, if you have 40 sale order lines on a sale. All these lines have th - Without this module : your browser makes about 40 time the same name_get() request. - With this modules: your browser makes 1 request and reuse the result for all the lines. -It works on many2many on list views. +It works on many2many and many2one on list views. The cache is cleaned when you navigate to other objects. @@ -35,6 +35,8 @@ Known issues / Roadmap ====================== * The cache is not very aggressive, if put more globally it may catch more useless requests. +* some requests can be done twice in many2one, because of 'this' been erased in +other parts of the core code. Credits diff --git a/web_cache_name_get/__manifest__.py b/web_cache_name_get/__manifest__.py index e9a65a3c..475361e0 100644 --- a/web_cache_name_get/__manifest__.py +++ b/web_cache_name_get/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Cache name_get", - "version": "10.0.1.0.0", + "version": "10.0.1.0.1", "website": "https://github.com/OCA/web", "author": "Akretion, " "Odoo Community Association (OCA)", diff --git a/web_cache_name_get/static/src/js/view_list.js b/web_cache_name_get/static/src/js/view_list.js index f931acd2..6b02c6a8 100644 --- a/web_cache_name_get/static/src/js/view_list.js +++ b/web_cache_name_get/static/src/js/view_list.js @@ -3,21 +3,66 @@ odoo.define('web_cache_name_get.view_list', function(require) { var listView = require('web.ListView'); var Model = require('web.DataModel'); + var data = require('web.data'); var core = require('web.core'); var _t = core._t; listView.List.include({ + web_cache_name_get: function(key, callback) { + //will return a promise with the result of + //the name_get + //it will cache the request in order to save brandwith + //and useless requests + var prom = null; + var key = JSON.stringify(key); + //init cache if not already done + this.name_get_cache = this.name_get_cache || {}; + + if (this.name_get_cache[key]) { + //cache hit + prom = this.name_get_cache[key]; + } + if (!prom) { + //cache miss + prom = callback(); + this.name_get_cache[key] = prom + } + return prom; + }, /* - cache name_get of many2many in order to reduce + cache name_get of many2many and many2one in order to reduce useless requests - first part is a copy paste of web/static/src/js/views/list_view.js + some parts are a copy paste of web/static/src/js/views/list_view.js because we have hook into it and can't do much better than that. */ render_cell: function (record, column) { var value; - if (column.type !== 'many2many') { - return this._super(record, column); - } else { + var self = this; + if (column.type === 'many2one') { + value = record.get(column.id); + // m2o values are usually name_get formatted, [Number, String] + // pairs, but in some cases only the id is provided. In these + // cases, we need to perform a name_get call to fetch the actual + // displayable value + if (typeof value === 'number' || value instanceof Number) { + // fetch the name, set it on the record (in the right field) + // and let the various registered events handle refreshing the + // row + + // our logic starts here + prom = this.web_cache_name_get( + [this.view.model, this.view.name, column.relation, value], + function () { + return new data.DataSet(self.view, column.relation) + .name_get([value]); + } + ); + prom.done(function (names) { + if (!names.length) { return; } + record.set(column.id, names[0]); + }); + } + } else if (column.type === 'many2many') { value = record.get(column.id); // non-resolved (string) m2m values are arrays if (value instanceof Array && !_.isEmpty(value) @@ -37,21 +82,15 @@ odoo.define('web_cache_name_get.view_list', function(require) { // 2. an array of ids ids = value; } - // the logic starts here - - // create a cache if not already done - this.name_get_cache = this.name_get_cache || {}; - var prom = null; - var key = JSON.stringify([column.relation, ids, this.dataset.get_context()]); + // our logic starts here + var prom = this.web_cache_name_get( + [column.relation, ids, this.dataset.get_context()], + function () { + return new Model(column.relation) + .call('name_get', [ids, self.dataset.get_context()]) + } + ); - if (this.name_get_cache[key]) { - prom = this.name_get_cache[key]; - } - if (!prom) { - prom = new Model(column.relation) - .call('name_get', [ids, this.dataset.get_context()]); - this.name_get_cache[key] = prom; - } // put placeholder at first to limit races conditions // because of the cached answers // promise resolution can happen before placeholder set @@ -66,6 +105,8 @@ odoo.define('web_cache_name_get.view_list', function(require) { record.set(column.id, ids); }); } + } else { + return this._super(record, column); } return column.format(record.toForm().data, { model: this.dataset.model,