diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 57569be8b1c..e364e38e461 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2337,29 +2337,58 @@ instance.web.form.KanbanSelection = instance.web.form.FieldChar.extend({ init: function (field_manager, node) { this._super(field_manager, node); }, + start: function () { + var self = this; + this.states = []; + this._super.apply(this, arguments); + // hook on form view content changed: recompute the states, because it may be related to the current stage + this.getParent().on('view_content_has_changed', self, function () { + self.render_value(); + }); + }, prepare_dropdown_selection: function() { var self = this; var data = []; - var selection = self.field.selection || []; - _.map(selection, function(res) { - var value = { - 'name': res[0], - 'tooltip': res[1], - 'state_name': res[1], - } - if (res[0] == 'normal') { value['state_class'] = 'oe_kanban_status'; } - else if (res[0] == 'done') { value['state_class'] = 'oe_kanban_status oe_kanban_status_green'; } - else { value['state_class'] = 'oe_kanban_status oe_kanban_status_red'; } - data.push(value); + var selection = this.field.selection || []; + var stage_id = _.isArray(this.view.datarecord.stage_id) ? this.view.datarecord.stage_id[0] : this.view.datarecord.stage_id; + var legend_field = this.options && this.options.states_legend_field || false; + var fields_to_read = _.map( + this.options && this.options.states_legend || {}, + function (value, key, list) { return value; }); + if (legend_field && fields_to_read && stage_id) { + var fetch_stage = new openerp.web.DataSet( + this, + self.view.fields[legend_field].field.relation).read_ids([stage_id], + fields_to_read); + } + else { var fetch_stage = $.Deferred().resolve(false); } + return $.when(fetch_stage).then(function (stage_data) { + _.map(selection, function(res) { + var value = { + 'name': res[0], + 'tooltip': res[1], + 'state_name': res[1], + } + if (stage_data && stage_data[0][self.options.states_legend[res[0]]]) { + value['state_name'] = stage_data[0][self.options.states_legend[res[0]]]; + } + if (res[0] == 'normal') { value['state_class'] = 'oe_kanban_status'; } + else if (res[0] == 'done') { value['state_class'] = 'oe_kanban_status oe_kanban_status_green'; } + else { value['state_class'] = 'oe_kanban_status oe_kanban_status_red'; } + data.push(value); + }); + return data; }); - return data; }, render_value: function() { var self = this; this.record_id = this.view.datarecord.id; - this.states = this.prepare_dropdown_selection();; - this.$el.html(QWeb.render("KanbanSelection", {'widget': self})); - this.$el.find('li').on('click', this.set_kanban_selection.bind(this)); + var dd_fetched = this.prepare_dropdown_selection();; + return $.when(dd_fetched).then(function (states) { + self.states = states; + self.$el.html(QWeb.render("KanbanSelection", {'widget': self})); + self.$el.find('li').on('click', this.set_kanban_selection.bind(this)); + }) }, /* setting the value: in view mode, perform an asynchronous call and reload the form view; in edit mode, use set_value to save the new value that will diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 1d2ba48ea6e..132f04e527e 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -266,9 +266,52 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ }, do_process_groups: function(groups) { var self = this; + + // Check in the arch the fields to fetch on the stage to get tooltips data. + // Fetching data is done in batch for all stages, to avoid doing multiple + // calls. The first naive implementation of group_by_tooltip made a call + // for each displayed stage and was quite limited. + // Data for the group tooltip (group_by_tooltip) and to display stage-related + // legends for kanban state management (states_legend) are fetched in + // one call. + var group_by_fields_to_read = []; + var recurse = function(node) { + if (node.tag === "field" && node.attrs && node.attrs.options) { + var options = instance.web.py_eval(node.attrs.options); + var states_fields_to_read = _.map( + options && options.states_legend || {}, + function (value, key, list) { return value; }); + var tooltip_fields_to_read = _.map( + options && options.group_by_tooltip || {}, + function (value, key, list) { return key; }); + group_by_fields_to_read = _.union( + group_by_fields_to_read, + states_fields_to_read, + tooltip_fields_to_read); + } + _.each(node.children, function(child) { + recurse(child); + }); + }; + recurse(this.fields_view.arch); + var group_ids = _.map(groups, function (elem) { return elem.attributes.value[0]}); + if (group_ids && group_by_fields_to_read) { + var group_data = new instance.web.DataSet( + this, + this.group_by_field.relation).read_ids(group_ids, _.union(['display_name'], group_by_fields_to_read)); + } + else { var group_data = $.Deferred().resolve({}); } + this.$el.find('table:first').show(); this.$el.removeClass('oe_kanban_ungrouped').addClass('oe_kanban_grouped'); - return this.add_group_mutex.exec(function() { + return $.when(group_data).then(function (results) { + _.each(results, function (group_by_data) { + var group = _.find(groups, function (elem) {return elem.attributes.value[0] == group_by_data.id}); + if (group) { + group.values = group_by_data; + } + }); + }).done( function () {return self.add_group_mutex.exec(function() { self.do_clear_groups(); self.dataset.ids = []; if (!groups.length) { @@ -300,7 +343,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ self.trigger('kanban_groups_processed'); }); }); - }); + })}); }, do_process_dataset: function() { var self = this; @@ -583,8 +626,9 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ this.dataset = dataset; this.dataset_offset = 0; this.aggregates = {}; - this.value = this.title = null; + this.value = this.title = this.values = null; if (this.group) { + this.values = group.values; this.value = group.get('value'); this.title = group.get('value'); if (this.value instanceof Array) { @@ -621,7 +665,8 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ }); }, start: function() { - var self = this; + var self = this, + def = this._super(); if (! self.view.group_by) { self.$el.addClass("oe_kanban_no_group"); self.quick = new (get_class(self.view.quick_create_class))(this, self.dataset, {}, false) @@ -678,39 +723,37 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ } }); this.is_started = true; - var def_tooltip = this.fetch_tooltip(); - return $.when(def_tooltip); + this.fetch_tooltip(); + return def; }, + /* + * Form the tooltip, based on optional group_by_tooltip on the grouping field. + * This function goes through the arch of the view, finding the declaration + * of the field used to group. If group_by_tooltip is defined, use the previously + * computed values of the group to form the tooltip. */ fetch_tooltip: function() { + var self = this; if (! this.group) - return; - var field_name = this.view.group_by; - var field = this.view.group_by_field; - var field_desc = null; + return; + var options = null; var recurse = function(node) { - if (node.tag === "field" && node.attrs.name === field_name) { - field_desc = node; + if (node.tag === "field" && node.attrs.name == self.view.group_by) { + options = instance.web.py_eval(node.attrs.options || '{}'); return; } _.each(node.children, function(child) { - if (field_desc === null) - recurse(child); + recurse(child); }); }; recurse(this.view.fields_view.arch); - if (! field_desc) - return; - var options = instance.web.py_eval(field_desc.attrs.options || '{}') - if (! options.tooltip_on_group_by) - return; - - var self = this; - if (this.value) { - return (new instance.web.Model(field.relation)).query([options.tooltip_on_group_by]) - .filter([["id", "=", this.value]]).first().then(function(res) { - self.tooltip = res[options.tooltip_on_group_by]; - self.$(".oe_kanban_group_title_text").attr("title", self.tooltip || self.title || "").tooltip(); - }); + if (options && options.group_by_tooltip) { + this.tooltip = _.union( + [this.title], + _.map( + options.group_by_tooltip, + function (key, value, list) { return self.values[value] || ''; }) + ).join('\n\n'); + this.$(".oe_kanban_group_title_text").attr("title", this.tooltip || this.title || ""); } }, compute_cards_auto_height: function() { @@ -1332,6 +1375,7 @@ instance.web_kanban.KanbanSelection = instance.web_kanban.AbstractField.extend({ this.parent = parent; }, prepare_dropdown_selection: function() { + var self = this; var data = []; _.map(this.field.selection || [], function(res) { var value = { @@ -1339,6 +1383,10 @@ instance.web_kanban.KanbanSelection = instance.web_kanban.AbstractField.extend({ 'tooltip': res[1], 'state_name': res[1], } + var leg_opt = self.options && self.options.states_legend || null; + if (leg_opt && leg_opt[res[0]] && self.parent.group.values && self.parent.group.values[leg_opt[res[0]]]) { + value['state_name'] = self.parent.group.values[leg_opt[res[0]]]; + } if (res[0] == 'normal') { value['state_class'] = 'oe_kanban_status'; } else if (res[0] == 'done') { value['state_class'] = 'oe_kanban_status oe_kanban_status_green'; } else { value['state_class'] = 'oe_kanban_status oe_kanban_status_red'; }