[FIX] web: reimplement group_by_tooltip option in kanban

This option hadn't been implemented in the new views.
It allows to display informative explanations as tooltips on column over.

It can be set on a many2one field in the kanban view, e.g.:

```<field name="stage_id" options='{"group_by_tooltip":
    {"<tooltipFieldOnStageModel>": "<ABeautifulTitle>"}
}'/>
```

An extra RPC needs to be done on the many2one relation to fetch these additional
fields and the data are stored in the datapoint under the key `tooltipData`.
This commit is contained in:
Martin Geubelle
2017-06-15 13:22:07 +02:00
parent 46751de506
commit d88d1abcf0
5 changed files with 107 additions and 8 deletions
@@ -44,7 +44,6 @@ var KanbanColumn = Widget.extend({
this.folded = !data.isOpen;
this.has_active_field = 'active' in data.fields;
this.size = data.count;
this.values = data.values;
this.fields = data.fields;
this.records = [];
this.modelName = data.model;
@@ -62,13 +61,12 @@ var KanbanColumn = Widget.extend({
this.record_options = _.clone(recordOptions);
if (data.options && data.options.group_by_tooltip) {
var self = this;
this.tooltip_info = _.map(data.options.group_by_tooltip, function (key, value) {
return (self.values && self.values[value] && "<div>" +key + "<br>" + self.values[value] + "</div>") || '';
if (options.group_by_tooltip) {
this.tooltipInfo = _.map(options.group_by_tooltip, function (help, field) {
return (data.tooltipData && data.tooltipData[field] && "<div>" + help + "<br>" + data.tooltipData[field] + "</div>") || '';
}).join('');
} else {
this.tooltip_info = "";
this.tooltipInfo = "";
}
},
/**
@@ -216,7 +214,7 @@ var KanbanColumn = Widget.extend({
this.$el.toggleClass('o_column_folded', this.folded);
var tooltip = this.size + _t(' records');
tooltip = '<p>' + tooltip + '</p>' + this.tooltip_info;
tooltip = '<p>' + tooltip + '</p>' + this.tooltipInfo;
this.$header.tooltip({html: true}).attr('data-original-title', tooltip);
if (!this.remaining) {
this.$('.o_kanban_load_more').remove();
@@ -89,6 +89,21 @@ var KanbanModel = BasicModel.extend({
return newGroup.id;
});
},
/**
* Add the key `tooltipData` (kanban specific) when performing a `geŧ`.
*
* @override
* @see _readTooltipFields
* @returns {Object}
*/
get: function () {
var result = this._super.apply(this, arguments);
var dp = result && this.localData[result.id];
if (dp && dp.tooltipData) {
result.tooltipData = $.extend(true, {}, dp.tooltipData);
}
return result;
},
/**
* @override
*/
@@ -203,10 +218,55 @@ var KanbanModel = BasicModel.extend({
* @param {Object} list valid resource object
*/
_readGroup: function (list) {
var self = this;
if (list.groupedBy.length > 1) {
list.groupedBy = [list.groupedBy[0]];
}
return this._super.apply(this, arguments);
return this._super.apply(this, arguments).then(function (result) {
return self._readTooltipFields(list).then(_.constant(result));
});
},
/**
* Fetches tooltip specific fields on the group by relation and stores it in
* the column datapoint in a special key `tooltipData`.
* Data for the tooltips (group_by_tooltip) are fetched in batch for all
* groups, to avoid doing multiple calls.
* Data are stored in a special key `tooltipData` on the datapoint.
* Note that the option `group_by_tooltip` is only for m2o fields.
*
* @private
* @param {Object} list a list of groups
* @returns {Deferred}
*/
_readTooltipFields: function (list) {
var self = this;
var groupedByField = list.fields[list.groupedBy[0]];
if (groupedByField.type !== 'many2one') {
return $.when();
}
var groupIds = _.map(list.data, function (id) {
return self.get(id, {raw: true}).res_id;
});
var tooltipFields = [];
var groupedByFieldInfo = list.fieldsInfo.kanban[list.groupedBy[0]];
if (groupedByFieldInfo && groupedByFieldInfo.options) {
tooltipFields = Object.keys(groupedByFieldInfo.options.group_by_tooltip || {});
}
if (groupIds.length && tooltipFields.length) {
var fieldNames = _.union(['display_name'], tooltipFields);
return this._rpc({
model: groupedByField.relation,
method: 'read',
args: [groupIds, fieldNames],
context: list.context,
}).then(function (result) {
_.each(list.data, function (id) {
var dp = self.localData[id];
dp.tooltipData = _.findWhere(result, {id: dp.res_id});
});
});
}
return $.when();
},
});
@@ -188,6 +188,7 @@ var KanbanRenderer = BasicRenderer.extend({
_renderGrouped: function (fragment) {
var self = this;
var groupByFieldAttrs = this.state.fields[this.state.groupedBy[0]];
var groupByFieldInfo = this.state.fieldsInfo.kanban[this.state.groupedBy[0]];
// Deactivate the drag'n'drop if the groupedBy field:
// - is a date or datetime since we group by month or
// - is readonly
@@ -201,8 +202,10 @@ var KanbanRenderer = BasicRenderer.extend({
}
var groupedByM2O = groupByFieldAttrs && (groupByFieldAttrs.type === 'many2one');
var grouped_by_field = groupedByM2O && groupByFieldAttrs.relation;
var groupByTooltip = groupByFieldInfo && groupByFieldInfo.options.group_by_tooltip;
this.columnOptions = _.extend(this.columnOptions, {
draggable: draggable,
group_by_tooltip: groupByTooltip,
grouped_by_m2o: groupedByM2O,
relation: grouped_by_field,
});
@@ -55,6 +55,7 @@ QUnit.module('Views', {
limit: 40,
modelName: 'partner',
openGroupByDefault: true,
viewType: 'kanban',
};
}
}, function () {
@@ -1491,6 +1491,43 @@ QUnit.module('Views', {
"Create button should now be highlighted");
kanban.destroy();
});
QUnit.test('group_by_tooltip option when grouping on a many2one', function (assert) {
assert.expect(5);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '<kanban default_group_by="bar">' +
'<field name="bar"/>' +
'<field name="product_id" '+
'options=\'{"group_by_tooltip": {"name": "Kikou"}}\'/>' +
'<templates><t t-name="kanban-box">' +
'<div><field name="foo"/></div>' +
'</t></templates></kanban>',
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/product/read') {
assert.strictEqual(args.args[0].length, 2,
"read on two groups");
assert.deepEqual(args.args[1], ['display_name', 'name'],
"should read on specified fields on the group by relation");
}
return this._super.apply(this, arguments);
},
});
assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have " + 2 + " columns");
// simulate an update coming from the searchview, with another groupby given
kanban.update({groupBy: ['product_id']});
assert.ok(kanban.$('.o_kanban_group:first span.o_column_title:contains(hello)').length,
"first column should have a title with a value from the many2one");
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_header').data('original-title'),
"<p>2 records</p><div>Kikou<br>hello</div>",
"first column should have a tooltip with the number of records, the group_by_tooltip title and many2one field value");
kanban.destroy();
});
});
});