From 95b2daf17b9f3301095851e855b85dcbe6fa955f Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Wed, 2 Apr 2014 09:41:22 +0200 Subject: [PATCH 1/7] [IMP] modifies the web client to be able to use the new 'lazy' parameter of the method readgroup (so now the client can requires a readgroup to be eager/lazy) (addon web) bzr revid: ged@openerp.com-20140402074122-sf52hult1qkqos81 --- addons/web/static/src/js/data.js | 44 ++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 517afa7f5c2..413d0621011 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -27,6 +27,7 @@ instance.web.Query = instance.web.Class.extend({ this._fields = fields; this._filter = []; this._context = {}; + this._lazy = true; this._limit = false; this._offset = 0; this._order_by = []; @@ -36,6 +37,7 @@ instance.web.Query = instance.web.Class.extend({ var q = new instance.web.Query(this._model, this._fields); q._context = this._context; q._filter = this._filter; + q._lazy = this._lazy; q._limit = this._limit; q._offset = this._offset; q._order_by = this._order_by; @@ -51,6 +53,7 @@ instance.web.Query = instance.web.Class.extend({ q._context = new instance.web.CompoundContext( q._context, to_set.context); break; + case 'lazy': case 'limit': case 'offset': case 'order_by': @@ -140,6 +143,7 @@ instance.web.Query = instance.web.Class.extend({ domain: this._model.domain(this._filter), context: ctx, offset: this._offset, + lazy: this._lazy, limit: this._limit, orderby: instance.web.serialize_sort(this._order_by) || false }).then(function (results) { @@ -148,8 +152,9 @@ instance.web.Query = instance.web.Class.extend({ result.__context = result.__context || {}; result.__context.group_by = result.__context.group_by || []; _.defaults(result.__context, ctx); + var grouping_fields = self._lazy ? [grouping[0]] : grouping; return new instance.web.QueryGroup( - self._model.name, grouping[0], result); + self._model.name, grouping_fields, result); }); }); }, @@ -175,6 +180,18 @@ instance.web.Query = instance.web.Class.extend({ if (!domain) { return this; } return this.clone({filter: domain}); }, + /** + * Creates a new query with the provided parameter lazy replacing the current + * query's own. + * + * @param {Boolean} lazy indicates if the read_group should return only the + * first level of groupby records, or should return the records grouped by + * all levels at once (so, it makes only 1 db request). + * @returns {openerp.web.Query} + */ + lazy: function (lazy) { + return this.clone({lazy: lazy}); + }, /** * Creates a new query with the provided limit replacing the current * query's own limit @@ -213,7 +230,7 @@ instance.web.Query = instance.web.Class.extend({ }); instance.web.QueryGroup = instance.web.Class.extend({ - init: function (model, grouping_field, read_group_group) { + init: function (model, grouping_fields, read_group_group) { // In cases where group_by_no_leaf and no group_by, the result of // read_group has aggregate fields but no __context or __domain. // Create default (empty) values for those so that things don't break @@ -221,29 +238,40 @@ instance.web.QueryGroup = instance.web.Class.extend({ {__context: {group_by: []}, __domain: []}, read_group_group); - var raw_field = grouping_field && grouping_field.split(':')[0]; + var raw_fields = _.map(grouping_fields, function (field) { + return field && field.split(':')[0]; + }); + + var aggregates = {}; _(fixed_group).each(function (value, key) { if (key.indexOf('__') === 0 - || key === raw_field - || key === raw_field + '_count') { + || _.contains(raw_fields, key) + || (key === raw_fields[0] + '_count')) { return; } aggregates[key] = value || 0; }); + this.model = new instance.web.Model( model, fixed_group.__context, fixed_group.__domain); - var group_size = fixed_group[raw_field + '_count'] || fixed_group.__count || 0; + var group_size = fixed_group[raw_fields[0] + '_count'] || fixed_group.__count || 0; var leaf_group = fixed_group.__context.group_by.length === 0; + var value = (grouping_fields.length === 1) + ? fixed_group[raw_fields[0]] + : _.map(raw_fields, function (field) { return fixed_group[field]; }); + var grouped_on = (grouping_fields.length === 1) + ? grouping_fields[0] + : grouping_fields; this.attributes = { folded: !!(fixed_group.__fold), - grouped_on: grouping_field, + grouped_on: grouped_on, // if terminal group (or no group) and group_by_no_leaf => use group.__count length: group_size, - value: fixed_group[raw_field], + value: value, // A group is open-able if it's not a leaf in group_by_no_leaf mode has_children: !(leaf_group && fixed_group.__context['group_by_no_leaf']), From c4d0299eca6941e4f38f86c7e8c4a3e9a5cf84a7 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Wed, 2 Apr 2014 09:43:41 +0200 Subject: [PATCH 2/7] [IMP] complete rewrite of the data loading code in the graph view, using the lazy/eager feature of readgroup. The code is simpler and more efficient: it only performs a fixed number of requests (well, the number is 'fixed' in the sense that it does not depend of the size of the data being displayed, but it still depends on the number of dimensions) (addon web_graph) bzr revid: ged@openerp.com-20140402074341-8cleqizqculxmkys --- addons/web_graph/static/src/js/pivot_table.js | 406 ++++++++---------- 1 file changed, 182 insertions(+), 224 deletions(-) diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index f77d49f9a1a..e8a438b3fe5 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -82,7 +82,9 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ get_values: function (id1, id2, default_values) { var cell = _.findWhere(this.cells, {x: Math.min(id1, id2), y: Math.max(id1, id2)}); - return (cell !== undefined) ? cell.values : (default_values || new Array(this.measures.length)); + return (cell !== undefined) ? + cell.values : + (default_values || new Array(this.measures.length)); }, // ---------------------------------------------------------------------- @@ -144,12 +146,16 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ get_ancestors: function (header) { var self = this; if (!header.children) return []; - return [].concat.apply([], _.map(header.children, function (c) {return self.get_ancestors_and_self(c); })); + return [].concat.apply([], _.map(header.children, function (c) { + return self.get_ancestors_and_self(c); + })); }, get_ancestors_and_self: function (header) { var self = this; - return [].concat.apply([header], _.map(header.children, function (c) { return self.get_ancestors_and_self(c); })); + return [].concat.apply([header], _.map(header.children, function (c) { + return self.get_ancestors_and_self(c); + })); }, get_total: function (header) { @@ -205,54 +211,28 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ expand: function (header_id, groupby) { var self = this, header = this.get_header(header_id), - otherRoot = this.get_other_root(header), - fields = otherRoot.groupby.concat(this.measures); + other_root = this.get_other_root(header), + this_gb = [groupby.field], + other_gbs = _.pluck(other_root.groupby, 'field'); if (header.path.length === header.root.groupby.length) { header.root.groupby.push(groupby); } - groupby = [groupby].concat(otherRoot.groupby); - - return this.get_groups(groupby, fields, header.domain).then(function (groups) { - _.each(groups.reverse(), function (group) { - // make header - var child = self.make_header(group, header); - child.expanded = false; - header.children.splice(0,0, child); - header.root.headers.splice(header.root.headers.indexOf(header) + 1, 0, child); - // make cells - _.each(self.get_ancestors_and_self(group), function (data) { - var values = _.map(self.measures, function (m) { - return data.attributes.aggregates[m.field]; - }); - var other = _.find(otherRoot.headers, function (h) { - if (header.root === self.cols) { - return _.isEqual(data.path.slice(1), h.path); - } else { - return _.isEqual(_.rest(data.path), h.path); - } - }); - if (other) { - self.add_cell(child.id, other.id, values); - } - }); + return this.perform_requests(this_gb, other_gbs, header.domain).then(function () { + var data = Array.prototype.slice.call(arguments); + data = data.slice(other_gbs.length + 1, data.length); + _.each(data, function (data_pt) { + self.make_headers_and_cell( + data_pt, header.root.headers, other_root.headers, 1, header.path); }); header.expanded = true; + header.children.forEach(function (child) { + child.expanded = false; + child.root = header.root; + }); }); }, - make_header: function (group, parent) { - var title = parent ? group.attributes.value : _t('Total'); - return { - id: _.uniqueId(), - path: parent ? parent.path.concat(title) : [], - title: title, - children: [], - domain: parent ? group.model._domain : this.domain, - root: parent ? parent.root : undefined, - }; - }, - swap_axis: function () { var temp = this.rows; this.rows = this.cols; @@ -262,206 +242,184 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ // ---------------------------------------------------------------------- // Data updating methods // ---------------------------------------------------------------------- - // Load the data from the db, using the method this.load_data // update_data will try to preserve the expand/not expanded status of each // column/row. If you want to expand all, then set this.cols.headers/this.rows.headers // to null before calling update_data. - update_data: function () { - var self = this; + update_data: function () { + var self = this; + return this.perform_requests().then (function () { + var data = Array.prototype.slice.call(arguments); + self.no_data = !data[0][0].attributes.length; + if (self.no_data) { + return; + } + var row_headers = [], + col_headers = []; + self.cells = []; - return this.load_data().then (function (result) { - if (result) { - self.no_data = false; - self[self.cols.headers ? 'update_headers' : 'expand_headers'](self.cols, result.col_headers); - self[self.rows.headers ? 'update_headers' : 'expand_headers'](self.rows, result.row_headers); - } else { - self.no_data = true; - } - }); - }, + var dim_col = self.cols.groupby.length, + i, j, index; - expand_headers: function (root, new_headers) { - root.headers = new_headers; - _.each(root.headers, function (header) { - header.root = root; - header.expanded = (header.children.length > 0); - }); - }, - - update_headers: function (root, new_headers) { - _.each(root.headers, function (header) { - var corresponding_header = _.find(new_headers, function (h) { - return _.isEqual(h.path, header.path); - }); - if (corresponding_header && header.expanded) { - corresponding_header.expanded = true; - _.each(corresponding_header.children, function (c) { - c.expanded = false; - }); - } - if (corresponding_header && (!header.expanded)) { - corresponding_header.expanded = false; - } - }); - var updated_headers = _.filter(new_headers, function (header) { - return (header.expanded !== undefined); - }); - _.each(updated_headers, function (header) { - if (!header.expanded) { - header.children = []; - } - header.root = root; - }); - root.headers = updated_headers; - }, - - // ---------------------------------------------------------------------- - // Data loading methods - // ---------------------------------------------------------------------- - - // To obtain all the values required to draw the full table, we have to do - // at least 2 + min(row.groupby.length, col.groupby.length) - // calls to readgroup. To simplify the code, we will always do - // 2 + row.groupby.length calls. For example, if row.groupby = [r1, r2, r3] - // and col.groupby = [c1, c2], then we will make the call with the following - // groupbys: [r1,r2,r3], [c1,r1,r2,r3], [c1,c2,r1,r2,r3], []. - load_data: function () { - var self = this, - cols = this.cols.groupby, - rows = this.rows.groupby, - visible_fields = rows.concat(cols, self.measures); - - if (this.measures.length === 0) { - return $.Deferred.resolve().promise(); - } - - var groupbys = _.map(_.range(cols.length + 1), function (i) { - return cols.slice(0, i).concat(rows); - }); - groupbys.push([]); - - var get_data_requests = _.map(groupbys, function (groupby) { - return self.get_groups(groupby, visible_fields, self.domain); - }); - - return $.when.apply(null, get_data_requests).then(function () { - var data = Array.prototype.slice.call(arguments), - row_data = data[0], - col_data = (cols.length !== 0) ? data[data.length - 2] : [], - has_data = data[data.length - 1][0]; - - return has_data && self.format_data(col_data, row_data, data); + for (i = 0; i < self.rows.groupby.length + 1; i++) { + for (j = 0; j < dim_col + 1; j++) { + index = i*(dim_col + 1) + j; + self.make_headers_and_cell(data[index], row_headers, col_headers, i); + } + } + self.set_headers(row_headers, self.rows); + self.set_headers(col_headers, self.cols); }); }, - get_groups: function (groupbys, fields, domain, path) { - var self = this, - groupby = (groupbys.length) ? groupbys[0] : []; - path = path || []; + make_headers_and_cell: function (data_pts, row_headers, col_headers, index, prefix) { + var self = this; + data_pts.forEach(function (data_pt) { + var row_value = (prefix || []).concat(data_pt.attributes.value.slice(0,index)); + var col_value = data_pt.attributes.value.slice(index); + + var row = self.find_or_create_header(row_headers, row_value, data_pt); + var col = self.find_or_create_header(col_headers, col_value, data_pt); - return this._query_db(groupby, fields, domain, path).then(function (groups) { - if (groupbys.length > 1) { - var get_subgroups = $.when.apply(null, _.map(groups, function (group) { - return self.get_groups(_.rest(groupbys), fields, group.model._domain, path.concat(group.attributes.value)).then(function (subgroups) { - group.children = subgroups; - }); - })); - return get_subgroups.then(function () { - return groups; - }); - } else { - return groups; + var cell_value = _.map(self.measures, function (m) { + return data_pt.attributes.aggregates[m.field]; + }); + self.cells.push({ + x: Math.min(row.id, col.id), + y: Math.max(row.id, col.id), + values: cell_value + }); + }); + }, + + make_header: function (values) { + return _.extend({ + children: [], + domain: this.domain, + expanded: undefined, + id: _.uniqueId(), + path: [], + root: undefined, + title: undefined + }, values || {}); + }, + + find_or_create_header: function (headers, path, data_pt) { + var hdr = _.find(headers, function (header) { + return _.isEqual(path, header.path); + }); + if (hdr) { + return hdr; + } + if (!path.length) { + hdr = this.make_header({title: _t('Total')}); + headers.push(hdr); + return hdr; + } + hdr = this.make_header({ + path:path, + domain:data_pt.model._domain, + title: _t(_.last(path)) + }); + parent = _.find(headers, function (header) { + return _.isEqual(header.path, _.initial(path, 1)); + }); + + var previous = parent.children.length ? _.last(parent.children) : parent; + headers.splice(headers.indexOf(previous) + 1, 0, hdr); + parent.children.push(hdr); + return hdr; + }, + + perform_requests: function (group1, group2, domain) { + var self = this, + requests = [], + row_gbs = _.pluck(this.rows.groupby, 'field'), + col_gbs = _.pluck(this.cols.groupby, 'field'), + field_list = row_gbs.concat(col_gbs, _.pluck(this.measures, 'field')), + fields = field_list.map(function (f) { return self.raw_field(f); }); + + group1 = group1 || row_gbs; + group2 = group2 || col_gbs; + + var i,j, groupbys; + for (i = 0; i < group1.length + 1; i++) { + for (j = 0; j < group2.length + 1; j++) { + groupbys = group1.slice(0,i).concat(group2.slice(0,j)); + requests.push(self.get_groups(groupbys, fields, domain || self.domain)); } - }); + } + return $.when.apply(null, requests); + }, - }, + // set the 'expanded' status of new_headers more or less like root.headers, with root as root + set_headers: function(new_headers, root) { + if (root.headers) { + _.each(root.headers, function (header) { + var corresponding_header = _.find(new_headers, function (h) { + return _.isEqual(h.path, header.path); + }); + if (corresponding_header && header.expanded) { + corresponding_header.expanded = true; + _.each(corresponding_header.children, function (c) { + c.expanded = false; + }); + } + if (corresponding_header && (!header.expanded)) { + corresponding_header.expanded = false; + } + }); + var updated_headers = _.filter(new_headers, function (header) { + return (header.expanded !== undefined); + }); + _.each(updated_headers, function (header) { + header.root = root; + }); + root.headers = updated_headers; + } else { + root.headers = new_headers; + _.each(root.headers, function (header) { + header.root = root; + header.expanded = (header.children.length > 0); + }); + } + return new_headers; + }, - _query_db: function (groupby, fields, domain, path) { - var self = this, - field_ids = _.without(_.pluck(fields, 'field'), '__count'), - fields = _.map(field_ids, function(f) { return self.raw_field(f); }); - - return this.model.query(field_ids) - .filter(domain) - .group_by(groupby.field) - .then(function (results) { - var groups = _.filter(results, function (group) { - return group.attributes.length > 0; - }); - return _.map(groups, function (g) { return self.format_group(g, path); }); - }); - }, + get_groups: function (groupbys, fields, domain) { + var self = this; + return this.model.query(_.without(fields, '__count')) + .filter(domain) + .lazy(false) + .group_by(groupbys) + .then(function (groups) { + return groups.map(function (group) { + var attrs = group.attributes, + grouped_on = attrs.grouped_on instanceof Array + ? attrs.grouped_on : [attrs.grouped_on], + raw_grouped_on = grouped_on.map(function (f) { + return self.raw_field(f); + }); + if (grouped_on.length === 1) { attrs.value = [attrs.value]} + attrs.value = _.range(grouped_on.length).map(function (i) { + if (attrs.value[i] === false) { + return _t('Undefined'); + } else if (attrs.value[i] instanceof Array) { + return attrs.value[i][1]; + } + return attrs.value[i] + }); + attrs.aggregates.__count = group.attributes.length; + attrs.grouped_on = raw_grouped_on; + return group; + }); + }); + }, // if field is a fieldname, returns field, if field is field_id:interval, retuns field_id raw_field: function (field) { return field.split(':')[0]; }, - // add the path to the group and sanitize the value... - format_group: function (group, current_path) { - var attrs = group.attributes, - value = attrs.value, - grouped_on = attrs.grouped_on ? this.raw_field(attrs.grouped_on) : false; - - if (value === false) { - group.attributes.value = _t('Undefined'); - } else if (grouped_on && this.fields[grouped_on].type === 'selection') { - var selection = this.fields[grouped_on].selection, - value_lookup = _.where(selection, {0:value}); - group.attributes.value = value_lookup ? value_lookup[0][1] : _t('Undefined'); - } else if (value instanceof Array) { - group.attributes.value = value[1]; - } - - group.path = (value !== undefined) ? (current_path || []).concat(group.attributes.value) : []; - group.attributes.aggregates.__count = group.attributes.length; - - return group; - }, - - format_data: function (col_data, row_data, cell_data) { - var self = this, - dim_row = this.rows.groupby.length, - dim_col = this.cols.groupby.length, - col_headers = this.get_ancestors_and_self(this.make_headers(col_data, dim_col)), - row_headers = this.get_ancestors_and_self(this.make_headers(row_data, dim_row)); - - this.cells = []; - _.each(cell_data, function (data, index) { - self.make_cells(data, index, [], row_headers, col_headers); - }); // not pretty. make it more functional? - - return {col_headers: col_headers, row_headers: row_headers}; - }, - - make_headers: function (data, depth, parent) { - var self = this, - main = this.make_header(data, parent); - - if (main.path.length < depth) { - main.children = _.map(data.children || data, function (data_pt) { - return self.make_headers (data_pt, depth, main); - }); - } - return main; - }, - - make_cells: function (data, index, current_path, rows, cols) { - var self = this; - _.each(data, function (group) { - var attr = group.attributes, - path = attr.grouped_on ? current_path.concat(attr.value) : current_path, - values = _.map(self.measures, function (measure) { return attr.aggregates[measure.field]; }), - row = _.find(rows, function (header) { return _.isEqual(header.path, path.slice(index)); }), - col = _.find(cols, function (header) { return _.isEqual(header.path, path.slice(0, index)); }); - - self.add_cell(row.id, col.id, values); - if (group.children) { - self.make_cells (group.children, index, path, rows, cols); - } - }); - }, - }); })(); From c138b778df3055dad9e1add03deaf5b519e7581f Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Wed, 2 Apr 2014 13:47:58 +0200 Subject: [PATCH 3/7] [FIX] correctly filters out empty groups in read_group results in the data loading code of graph view (addon web_graph) bzr revid: ged@openerp.com-20140402114758-8qfdz8j76t2p2juo --- addons/web_graph/static/src/js/pivot_table.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index e8a438b3fe5..824b41a6b25 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -392,7 +392,9 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ .lazy(false) .group_by(groupbys) .then(function (groups) { - return groups.map(function (group) { + return groups.filter(function (group) { + return group.attributes.length > 0; + }).map(function (group) { var attrs = group.attributes, grouped_on = attrs.grouped_on instanceof Array ? attrs.grouped_on : [attrs.grouped_on], From 729cd2ce023d8919aa1b250a4b51bf416cc12117 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Wed, 2 Apr 2014 17:08:17 +0200 Subject: [PATCH 4/7] [FIX] correct the expand functionality to avoid creating rows/cols in the other dimension of an unfolding action (addon web_graph) bzr revid: ged@openerp.com-20140402150817-5s8drvhbznxq0hh9 --- addons/web_graph/static/src/js/pivot_table.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 824b41a6b25..9231765c485 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -223,7 +223,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ data = data.slice(other_gbs.length + 1, data.length); _.each(data, function (data_pt) { self.make_headers_and_cell( - data_pt, header.root.headers, other_root.headers, 1, header.path); + data_pt, header.root.headers, other_root.headers, 1, header.path, true); }); header.expanded = true; header.children.forEach(function (child) { @@ -271,12 +271,15 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ }); }, - make_headers_and_cell: function (data_pts, row_headers, col_headers, index, prefix) { + make_headers_and_cell: function (data_pts, row_headers, col_headers, index, prefix, expand) { var self = this; data_pts.forEach(function (data_pt) { var row_value = (prefix || []).concat(data_pt.attributes.value.slice(0,index)); var col_value = data_pt.attributes.value.slice(index); + if (expand && !_.find(col_headers, function (hdr) {return _.isEqual(col_value, hdr.path);})) { + return; + } var row = self.find_or_create_header(row_headers, row_value, data_pt); var col = self.find_or_create_header(col_headers, col_value, data_pt); From 0d4732b5c4194c7c25a13266dfdd1aed05e534eb Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Thu, 3 Apr 2014 11:40:50 +0200 Subject: [PATCH 5/7] [FIX] makes sure the internal data structure of pivot table is correct after update_data (the children were not correct when the tree of headers was not full, after an expand for example (addon web_graph) bzr revid: ged@openerp.com-20140403094050-vjeq4dks86mejuub --- addons/web_graph/static/src/js/pivot_table.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 9231765c485..309bb103fa8 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -219,8 +219,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ header.root.groupby.push(groupby); } return this.perform_requests(this_gb, other_gbs, header.domain).then(function () { - var data = Array.prototype.slice.call(arguments); - data = data.slice(other_gbs.length + 1, data.length); + var data = Array.prototype.slice.call(arguments).slice(other_gbs.length + 1); _.each(data, function (data_pt) { self.make_headers_and_cell( data_pt, header.root.headers, other_root.headers, 1, header.path, true); @@ -369,6 +368,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ } if (corresponding_header && (!header.expanded)) { corresponding_header.expanded = false; + corresponding_header.children = []; } }); var updated_headers = _.filter(new_headers, function (header) { From 9d915db2144be0d3b8e01340495f45b4187ceb76 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Thu, 3 Apr 2014 16:35:34 +0200 Subject: [PATCH 6/7] [FIX] read_group has been changed to return the results with field:interval as key (for example, date_deadline:week), to avoid name collisions. This commit changes the web client to make sure it properly processes the new result format. No change at all for queries that do not use the field:interval format (addon web) bzr revid: ged@openerp.com-20140403143534-3jpugw9g8n966n9t --- addons/web/static/src/js/data.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 413d0621011..9d11dbcf2a8 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -238,31 +238,26 @@ instance.web.QueryGroup = instance.web.Class.extend({ {__context: {group_by: []}, __domain: []}, read_group_group); - var raw_fields = _.map(grouping_fields, function (field) { - return field && field.split(':')[0]; - }); - - + var count_key = (grouping_fields[0] && grouping_fields[0].split(':')[0]) + '_count'; var aggregates = {}; _(fixed_group).each(function (value, key) { if (key.indexOf('__') === 0 - || _.contains(raw_fields, key) - || (key === raw_fields[0] + '_count')) { + || _.contains(grouping_fields, key) + || (key === count_key)) { return; } aggregates[key] = value || 0; }); - this.model = new instance.web.Model( model, fixed_group.__context, fixed_group.__domain); - var group_size = fixed_group[raw_fields[0] + '_count'] || fixed_group.__count || 0; + var group_size = fixed_group[count_key] || fixed_group.__count || 0; var leaf_group = fixed_group.__context.group_by.length === 0; var value = (grouping_fields.length === 1) - ? fixed_group[raw_fields[0]] - : _.map(raw_fields, function (field) { return fixed_group[field]; }); + ? fixed_group[grouping_fields[0]] + : _.map(grouping_fields, function (field) { return fixed_group[field]; }); var grouped_on = (grouping_fields.length === 1) ? grouping_fields[0] : grouping_fields; From 4d797222279e361bfe6db0fe45f3ff503b87c717 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Fri, 4 Apr 2014 16:30:09 +0200 Subject: [PATCH 7/7] [FIX] add missing semicolons, add a missing 'var' statement and remove trailing whitespace (addon web_graph) bzr revid: ged@openerp.com-20140404143009-6uk7607bv4acbg4b --- addons/web_graph/static/src/js/pivot_table.js | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/addons/web_graph/static/src/js/pivot_table.js b/addons/web_graph/static/src/js/pivot_table.js index 309bb103fa8..d0867ca6d1a 100644 --- a/addons/web_graph/static/src/js/pivot_table.js +++ b/addons/web_graph/static/src/js/pivot_table.js @@ -278,26 +278,26 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ if (expand && !_.find(col_headers, function (hdr) {return _.isEqual(col_value, hdr.path);})) { return; - } + } var row = self.find_or_create_header(row_headers, row_value, data_pt); var col = self.find_or_create_header(col_headers, col_value, data_pt); - var cell_value = _.map(self.measures, function (m) { + var cell_value = _.map(self.measures, function (m) { return data_pt.attributes.aggregates[m.field]; }); self.cells.push({ - x: Math.min(row.id, col.id), - y: Math.max(row.id, col.id), + x: Math.min(row.id, col.id), + y: Math.max(row.id, col.id), values: cell_value - }); + }); }); }, make_header: function (values) { return _.extend({ - children: [], - domain: this.domain, - expanded: undefined, + children: [], + domain: this.domain, + expanded: undefined, id: _.uniqueId(), path: [], root: undefined, @@ -306,7 +306,7 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ }, find_or_create_header: function (headers, path, data_pt) { - var hdr = _.find(headers, function (header) { + var hdr = _.find(headers, function (header) { return _.isEqual(path, header.path); }); if (hdr) { @@ -318,11 +318,11 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ return hdr; } hdr = this.make_header({ - path:path, + path:path, domain:data_pt.model._domain, title: _t(_.last(path)) }); - parent = _.find(headers, function (header) { + var parent = _.find(headers, function (header) { return _.isEqual(header.path, _.initial(path, 1)); }); @@ -399,26 +399,27 @@ openerp.web_graph.PivotTable = openerp.web.Class.extend({ return group.attributes.length > 0; }).map(function (group) { var attrs = group.attributes, - grouped_on = attrs.grouped_on instanceof Array - ? attrs.grouped_on : [attrs.grouped_on], + grouped_on = attrs.grouped_on instanceof Array ? attrs.grouped_on : [attrs.grouped_on], raw_grouped_on = grouped_on.map(function (f) { return self.raw_field(f); }); - if (grouped_on.length === 1) { attrs.value = [attrs.value]} + if (grouped_on.length === 1) { + attrs.value = [attrs.value]; + } attrs.value = _.range(grouped_on.length).map(function (i) { - if (attrs.value[i] === false) { + if (attrs.value[i] === false) { return _t('Undefined'); } else if (attrs.value[i] instanceof Array) { return attrs.value[i][1]; } - return attrs.value[i] + return attrs.value[i]; }); attrs.aggregates.__count = group.attributes.length; attrs.grouped_on = raw_grouped_on; return group; }); }); - }, + }, // if field is a fieldname, returns field, if field is field_id:interval, retuns field_id raw_field: function (field) {