[IMP] mail: add a progress bar by column in activity view

At the top of each column of the activity view, a progress bar is now
displayed below the activity type name based on activities scheduled.

Note that the progress bar widget is an extension of the kanban progress
bar as both have a very similar behavior.

Task 1894990
This commit is contained in:
Hiral Bhavsar
2019-05-03 10:19:40 +00:00
committed by Martin Geubelle
parent a02d273ebc
commit ff6415b63c
3 changed files with 101 additions and 24 deletions
@@ -5,6 +5,7 @@ var AbstractRenderer = require('web.AbstractRenderer');
var ActivityRecord = require('mail.ActivityRecord');
var core = require('web.core');
var field_registry = require('web.field_registry');
var KanbanColumnProgressBar = require('web.KanbanColumnProgressBar');
var qweb = require('web.QWeb');
var session = require('web.session');
var utils = require('web.utils');
@@ -15,6 +16,9 @@ var QWeb = core.qweb;
var ActivityRenderer = AbstractRenderer.extend({
className: 'o_activity_view',
custom_events: {
'set_progress_bar_state': '_onSetProgressBarState',
},
events: {
'click .o_send_mail_template': '_onSenMailTemplateClicked',
'click .o_activity_empty_cell': '_onEmptyCell',
@@ -115,22 +119,39 @@ var ActivityRenderer = AbstractRenderer.extend({
* @returns {jQueryElement} a jquery element <thead>
*/
_renderHeader: function () {
var $tr = $('<tr>')
.append($('<th>')) //empty cell for name
.append(_.map(this.state.activity_types, this._renderHeaderCell.bind(this)));
return $('<thead>').append($tr);
var self = this;
var activityTypeIds = _.unique(_.flatten(_.map(this.state.grouped_activities, function (act) { return _.keys(act); })));
var $thead = $(QWeb.render('mail.ActivityViewHeader', {
types: this.state.activity_types,
activityTypeIDs: _.map(activityTypeIds, Number),
}));
activityTypeIds.forEach(function (typeId) {
self._renderProgressBar($thead, typeId);
});
return $thead;
},
/**
* @private
* @param {Object} activity_type
* @returns {jQueryElement} a <th> element
*/
_renderHeaderCell: function (activity_type) {
return QWeb.render('mail.ActivityViewHeaderCell', {
id: activity_type[0],
name: activity_type[1],
template_list: activity_type[2] || [],
_renderProgressBar: function ($thead, typeId) {
var counts = { planned: 0, today: 0, overdue: 0 };
_.each(this.state.grouped_activities, function (act) {
if (_.contains(_.keys(act), typeId.toString())) {
counts[act[typeId].state] += 1;
}
});
var progressBar = new KanbanColumnProgressBar(this, {
columnID: typeId,
progressBarStates: {},
}, {
count: _.reduce(_.values(counts), function (x, y) { return x + y; }),
progressBarValues: {
field: 'activity_state',
colors: { planned: 'success', today: 'warning', overdue: 'danger' },
counts: counts,
},
});
progressBar.appendTo($thead.find('th[data-activity-type-id=' + typeId + ']'));
},
/**
* @private
@@ -155,6 +176,7 @@ var ActivityRenderer = AbstractRenderer.extend({
resId: resId,
activityGroup: activity_group,
activityTypeId: activity_type_id,
widget: self,
}));
if (activity_group.state) {
var record = self.getKanbanActivityData(activity_group, resId);
@@ -180,7 +202,7 @@ var ActivityRenderer = AbstractRenderer.extend({
}
return $td;
});
var $tr = $('<tr/>', {class: 'o_data_row'})
var $tr = $('<tr/>', {class: 'o_data_row'}).attr('data-res-id', resId)
.append($nameTD)
.append($cells);
return $tr;
@@ -223,6 +245,35 @@ var ActivityRenderer = AbstractRenderer.extend({
templateID: templateID,
});
},
/**
* Rearrange body part of table based on active filter.
*
* @private
* @param {OdooEvent} ev
*/
_onSetProgressBarState: function (ev) {
var self = this;
this.$('th[class*="o_activity_filter_"]').attr('class', 'o_activity_type_cell');
this.$('.o_kanban_counter_progress div').removeClass('active progress-bar-striped');
var data = ev.data;
var arrangedRecords = this.state.activity_res_ids;
this.activeFilter = data.values.activeFilter;
if (this.activeFilter) {
var filteredResIds = _.map(_.keys(_.pick(this.state.grouped_activities, function (act) {
return act[data.columnID] && act[data.columnID].state === self.activeFilter;
})), Number);
arrangedRecords = _.union(_.intersection(this.state.activity_res_ids, filteredResIds), this.state.activity_res_ids);
this.filteredResIDs = filteredResIds;
}
this.$('tbody').html(_.map(arrangedRecords, this._renderRow.bind(this)));
if (this.activeFilter) {
var $header = this.$('th.o_activity_type_cell[data-activity-type-id=' + data.columnID + ']');
$header.addClass('o_activity_filter_' + this.activeFilter);
}
},
});
return ActivityRenderer;
@@ -89,6 +89,15 @@
display: block;
}
}
.o_activity_filter_planned {
background-color: mix(theme-color('success'), $o-webclient-background-color, 5%);
}
.o_activity_filter_today {
background-color: mix(theme-color('warning'), $o-webclient-background-color, 5%);
}
.o_activity_filter_overdue {
background-color: mix(theme-color('danger'), $o-webclient-background-color, 5%);
}
.o_record_selector {
color: $o-enterprise-primary-color;
}
@@ -107,5 +116,14 @@
color: theme-color('success');
}
}
.o_kanban_counter {
margin: 5px 0 0 0;
> .o_kanban_counter_progress {
width: 100%;
> div.active {
border: 1px solid;
}
}
}
}
}
+20 -12
View File
@@ -1,23 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.ActivityViewHeaderCell">
<th class="o_activity_type_cell" t-att-data-activity-type-id="id">
<span><t t-esc="name"/></span>
<span t-if="template_list.length > 0" class="dropdown pull-right">
<i class="fa fa-ellipsis-v fa-fw" data-toggle="dropdown"/>
<div class="dropdown-menu">
<div t-foreach="template_list" t-as="template" title="This action will send an email." class="o_template_element o_send_mail_template" t-att-data-template-id="template.id">
<i class="fa fa-envelope fa-fw"/> <t t-esc="template.name"/>
<t t-name="mail.ActivityViewHeader">
<thead>
<tr>
<th></th>
<th t-foreach="types" t-as="type" class="o_activity_type_cell" t-att-data-activity-type-id="type[0]" t-attf-width="#{100/types.length}%">
<div>
<span><t t-esc="type[1]"/></span>
<span t-if="type[2].length > 0" class="dropdown pull-right">
<i class="fa fa-ellipsis-v fa-fw" data-toggle="dropdown"/>
<div class="dropdown-menu">
<div t-foreach="type[2]" t-as="template" title="This action will send an email." class="o_template_element o_send_mail_template" t-att-data-template-id="template.id">
<i class="fa fa-envelope fa-fw"/> <t t-esc="template.name"/>
</div>
</div>
</span>
</div>
</div>
</span>
</th>
<div t-if="activityTypeIDs.length and !_.contains(activityTypeIDs, type[0])" class="mt24"/>
</th>
</tr>
</thead>
</t>
<t t-name="mail.ActivityViewRow">
<td t-att-data-res-id="resId" t-att-data-activity-type-id="activityTypeId"
t-attf-class="o_activity_summary_cell #{activityGroup.state ? activityGroup.state : 'o_activity_empty_cell'}">
t-attf-class="o_activity_summary_cell #{activityGroup.state ? activityGroup.state : 'o_activity_empty_cell'} #{_.contains(widget.filteredResIDs, resId) ? 'o_activity_filter_' + widget.activeFilter : ''}">
<i t-if="!activityGroup.state" title="Create" class="text-center fa fa-plus"/>
</td>
</t>