summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/views/graph/graph_model.js
diff options
context:
space:
mode:
authorMathieu Duckerts-Antoine <dam@odoo.com>2020-02-21 12:28:46 +0000
committerMathieu Duckerts-Antoine <dam@odoo.com>2020-02-25 15:30:04 +0000
commitc7851add36575ce3f34a692a53acfdf4432a4d0c (patch)
treee5e55c92052749e2dc1df7e7e36326e66b2422fe /addons/web/static/src/js/views/graph/graph_model.js
parenta39cc6bc00df1a72cb12cfaa9c56cbe9fafaee83 (diff)
[FIX] web: graph renders only finer date groupby option
Rendering a graph view with several options selected for a given date groupby can take too much time and block the page. Since grouping on the same date/datetime field several times barely makes sense in a graph view, we choose to use only the finer option, e.g. 'week' is prefered to 'quarter'. Task ID: 2198846 X-original-commit: 7e36bee14e18ca17e15de1bacb7ff26010d0b372
Diffstat (limited to 'addons/web/static/src/js/views/graph/graph_model.js')
-rw-r--r--addons/web/static/src/js/views/graph/graph_model.js51
1 files changed, 47 insertions, 4 deletions
diff --git a/addons/web/static/src/js/views/graph/graph_model.js b/addons/web/static/src/js/views/graph/graph_model.js
index cf17e7267ab..b09d0a464d9 100644
--- a/addons/web/static/src/js/views/graph/graph_model.js
+++ b/addons/web/static/src/js/views/graph/graph_model.js
@@ -2,8 +2,14 @@ odoo.define('web.GraphModel', function (require) {
"use strict";
var core = require('web.core');
+const { DEFAULT_INTERVAL, INTERVAL_OPTIONS } = require('web.controlPanelViewParameters');
+
var _t = core._t;
+function rank(oId) {
+ return INTERVAL_OPTIONS.findIndex(o => o.optionId === oId);
+}
+
/**
* The graph model is responsible for fetching and processing data from the
* server. It basically just do a(some) read_group(s) and format/normalize data.
@@ -84,6 +90,7 @@ return AbstractModel.extend({
timeRange: params.timeRange,
timeRangeDescription: params.timeRangeDescription,
};
+ this.chart.processedGroupBy = this._processGroupBy(this.chart.groupBy);
return this._loadGraph(this._getDomains());
},
/**
@@ -135,6 +142,7 @@ return AbstractModel.extend({
if ('measure' in params) {
this.chart.measure = params.measure;
}
+ this.chart.processedGroupBy = this._processGroupBy(this.chart.groupBy);
if ('mode' in params) {
this.chart.mode = params.mode;
return Promise.resolve();
@@ -155,7 +163,7 @@ return AbstractModel.extend({
* @returns {number}
*/
_getComparisonFieldIndex: function () {
- var groupBys = this.chart.groupBy.map(function (gb) {
+ var groupBys = this.chart.processedGroupBy.map(function (gb) {
return gb.split(":")[0];
});
return groupBys.indexOf(this.chart.comparisonField);
@@ -186,7 +194,7 @@ return AbstractModel.extend({
_loadGraph: function (domains) {
var self = this;
this.chart.dataPoints = [];
- var groupBy = this.chart.groupBy;
+ var groupBy = this.chart.processedGroupBy;
var fields = _.map(groupBy, function (groupBy) {
return groupBy.split(':')[0];
});
@@ -235,13 +243,13 @@ return AbstractModel.extend({
var labels;
function getLabels (dataPt) {
- return self.chart.groupBy.map(function (field) {
+ return self.chart.processedGroupBy.map(function (field) {
return self._sanitizeValue(dataPt[field], field.split(":")[0]);
});
}
rawData.forEach(function (dataPt){
labels = getLabels(dataPt);
- var count = dataPt.__count || dataPt[self.chart.groupBy[0]+'_count'] || 0;
+ var count = dataPt.__count || dataPt[self.chart.processedGroupBy[0]+'_count'] || 0;
var value = isCount ? count : dataPt[self.chart.measure];
if (value instanceof Array) {
// when a many2one field is used as a measure AND as a grouped
@@ -262,6 +270,41 @@ return AbstractModel.extend({
});
},
/**
+ * Process the groupBy parameter in order to keep only the finer interval option for
+ * elements based on date/datetime field (e.g. 'date:year'). This means that
+ * 'week' is prefered to 'month'. The field stays at the place of its first occurence.
+ * For instance,
+ * ['foo', 'date:month', 'bar', 'date:week'] becomes ['foo', 'date:week', 'bar'].
+ *
+ * @private
+ * @param {string[]} groupBy
+ * @returns {string[]}
+ */
+ _processGroupBy: function(groupBy) {
+ const groupBysMap = new Map();
+ for (const gb of groupBy) {
+ let [fieldName, interval] = gb.split(':');
+ const field = this.fields[fieldName];
+ if (['date', 'datetime'].includes(field.type)) {
+ interval = interval || DEFAULT_INTERVAL;
+ }
+ if (groupBysMap.has(fieldName)) {
+ const registeredInterval = groupBysMap.get(fieldName);
+ if (rank(registeredInterval) < rank(interval)) {
+ groupBysMap.set(fieldName, interval);
+ }
+ } else {
+ groupBysMap.set(fieldName, interval);
+ }
+ }
+ return [...groupBysMap].map(([fieldName, interval]) => {
+ if (interval) {
+ return `${fieldName}:${interval}`;
+ }
+ return fieldName;
+ });
+ },
+ /**
* Helper function (for _processData), turns various values in a usable
* string form, that we can display in the interface.
*