diff options
| author | Mathieu Duckerts-Antoine <dam@odoo.com> | 2020-02-21 12:28:46 +0000 |
|---|---|---|
| committer | Mathieu Duckerts-Antoine <dam@odoo.com> | 2020-02-25 15:30:04 +0000 |
| commit | c7851add36575ce3f34a692a53acfdf4432a4d0c (patch) | |
| tree | e5e55c92052749e2dc1df7e7e36326e66b2422fe /addons/web/static/src/js/views/graph/graph_model.js | |
| parent | a39cc6bc00df1a72cb12cfaa9c56cbe9fafaee83 (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.js | 51 |
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. * |
