[FIX] web: fix data in view graph for concurrent groupby

- Go to any graph view (i.e. in CRM)
- Change "Group By" 2 times very very quickly
(In Chrome, you can set Throttling to "Slow 3G" in Network tab of devtools)
Data from first groupby will be mixed with data from the second one.

A graph reload is performing the following steps:
  * clean previous data
  * fetch data
  * set data
The issue happens when a second reload is performed while the previous one
has not set its data yet and the cleaning step of the second one is performed
before the setting step of the first one.

The solution will be to ignore the setting step of all previous reloads if
there is a more recent one.

opw-2460145

closes odoo/odoo#76304

X-original-commit: 79335d298126b523f6ff9768e219822789d99620
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Signed-off-by: Anh Thao PHAM <kitan191@users.noreply.github.com>
This commit is contained in:
Anh Thao Pham (pta)
2021-09-10 09:58:13 +00:00
parent 485273b914
commit 11eb4542ab
2 changed files with 32 additions and 6 deletions
@@ -195,6 +195,8 @@ return AbstractModel.extend({
var fields = _.map(groupBy, function (groupBy) {
return groupBy.split(':')[0];
});
const loadId = this.loadId ? ++this.loadId : 1;
this.loadId = loadId;
if (this.chart.measure !== '__count__') {
if (this.fields[this.chart.measure].type === 'many2one') {
@@ -217,7 +219,7 @@ return AbstractModel.extend({
fields: fields,
groupBy: groupBy,
lazy: false,
}).then(self._processData.bind(self, originIndex)));
}).then(self._processData.bind(self, originIndex, loadId)));
});
return Promise.all(proms);
},
@@ -226,15 +228,14 @@ return AbstractModel.extend({
* depending of some input, we have to normalize the result.
* Each group coming from the read_group produces a dataPoint
*
* @todo This is not good for race conditions. The processing should get
* the object this.chart in argument, or an array or something. We want to
* avoid writing on a this.chart object modified by a subsequent read_group
*
* @private
* @param {number} originIndex
* @param {any} rawData result from the read_group
*/
_processData: function (originIndex, rawData) {
_processData: function (originIndex, loadId, rawData) {
if (loadId < this.loadId) {
return;
}
var self = this;
var isCount = this.chart.measure === '__count__';
var labels;
@@ -685,6 +685,31 @@ QUnit.module('Views', {
graph.destroy();
});
QUnit.test('only process most recent data for concurrent groupby', async function (assert) {
assert.expect(4);
const graph = await createView({
View: GraphView,
model: 'foo',
data: this.data,
arch: `
<graph>
<field name="product_id" type="row"/>
<field name="foo" type="measure"/>
</graph>`,
});
checkLabels(assert, graph, [['xphone'], ['xpad']]);
checkDatasets(assert, graph, 'data', {data: [82, 157]});
testUtils.graph.reload(graph, {groupBy: ['color_id']});
await testUtils.graph.reload(graph, {groupBy: ['date:month']});
checkLabels(assert, graph, [['January 2016'], ['March 2016'], ['May 2016'], ['Undefined'], ['April 2016']]);
checkDatasets(assert, graph, 'data', {data: [56, 26, 4, 105, 48]});
graph.destroy();
});
QUnit.test('use a many2one as a measure should work (without groupBy)', async function (assert) {
assert.expect(4);