Holger Brunn
7 years ago
No known key found for this signature in database
GPG Key ID: 1C9760FECA3AE18
6 changed files with 336 additions and 3 deletions
-
3mail_activity/__manifest__.py
-
64mail_activity/static/src/css/mail_activity.css
-
171mail_activity/static/src/js/mail_activity.js
-
80mail_activity/static/src/xml/mail_activity.xml
-
12mail_activity/views/res_partner.xml
-
9mail_activity/views/templates.xml
@ -0,0 +1,64 @@ |
|||
.o_mail_activity #o_chatter_planned_activities .o_thread_message .o_thread_message_sidebar .o_avatar_stack img { |
|||
width: 31px; |
|||
height: 31px; |
|||
} |
|||
#o_chatter_planned_activities .o_thread_message .o_thread_message_sidebar .o_avatar_stack .o_avatar_icon { |
|||
position: absolute; |
|||
top: auto; |
|||
left: auto; |
|||
bottom: -5px; |
|||
right: -5px; |
|||
width: 25px; |
|||
height: 25px; |
|||
padding: 6px 5px; |
|||
text-align: center; |
|||
line-height: 1.2; |
|||
color: white; |
|||
border-radius: 100%; |
|||
border: 2px solid white; |
|||
} |
|||
.o_mail_activity .o_thread_message { |
|||
display: -ms-flexbox; |
|||
display: -moz-box; |
|||
display: -webkit-box; |
|||
display: -webkit-flex; |
|||
display: flex; |
|||
padding: 4px 16px; |
|||
margin-bottom: 0px; |
|||
} |
|||
.o_mail_activity .o_thread_message .o_thread_message_sidebar { |
|||
-ms-flex: 0 0 36px; |
|||
-moz-flex: 0 0 36px; |
|||
-webkit-box-flex: 0; |
|||
-webkit-flex: 0 0 36px; |
|||
flex: 0 0 36px; |
|||
margin-right: 10px; |
|||
margin-top: 2px; |
|||
text-align: center; |
|||
font-size: smaller; |
|||
} |
|||
.o_mail_activity .o_thread_message .o_thread_message_core { |
|||
-ms-flex: 1 1 auto; |
|||
-moz-flex: 1 1 auto; |
|||
-webkit-box-flex: 1; |
|||
-webkit-flex: 1 1 auto; |
|||
flex: 1 1 auto; |
|||
min-width: 0; |
|||
max-width: 100%; |
|||
word-wrap: break-word; |
|||
} |
|||
.o_mail_activity .o_thread_date_separator.o_border_dashed[data-toggle="collapse"] { |
|||
cursor: pointer; |
|||
} |
|||
.o_mail_activity .o_thread_date_separator.o_border_dashed { |
|||
border-bottom-style: dashed; |
|||
} |
|||
.o_mail_activity .o_thread_date_separator { |
|||
margin-top: 15px; |
|||
margin-bottom: 30px; |
|||
border-bottom: 1px solid #d9d7d7; |
|||
text-align: center; |
|||
} |
|||
.o_mail_activity.o_form_field { |
|||
display: block; |
|||
} |
@ -1,7 +1,172 @@ |
|||
//-*- coding: utf-8 -*-
|
|||
//© 2017 Therp BV <http://therp.nl>
|
|||
//© 2017-2018 Therp BV <http://therp.nl>
|
|||
//License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|||
|
|||
openerp.mail_activity = function(instance) |
|||
odoo.define('mail.Activity', function(require) |
|||
{ |
|||
}; |
|||
"use strict"; |
|||
var Chatter = require('mail.Chatter'), |
|||
Model = require('web.Model'), |
|||
form_common = require('web.form_common'), |
|||
core = require('web.core'), |
|||
_t = core._t; |
|||
Chatter.include({ |
|||
init: function() { |
|||
this._super.apply(this, arguments); |
|||
this.schedule_activity_btn = !!this.view.fields.activity_ids |
|||
}, |
|||
start: function() { |
|||
this.$('button.o_chatter_button_schedule_activity').click( |
|||
this.proxy('_onScheduleActivity') |
|||
); |
|||
this.activity = this.view.fields.activity_ids; |
|||
if(this.activity) { |
|||
this.$('.o_chatter_topbar').after(this.activity.$el); |
|||
} |
|||
return this._super.apply(this, arguments); |
|||
}, |
|||
_onScheduleActivity: function() { |
|||
return this.view.fields.activity_ids._scheduleActivity(false); |
|||
}, |
|||
}); |
|||
|
|||
/** |
|||
* Set the 'label_delay' entry in activity data according to the deadline date |
|||
* @param {Array} activities list of activity Object |
|||
* @return {Array} : list of modified activity Object |
|||
*/ |
|||
var setDelayLabel = function(activities) { |
|||
var today = moment().startOf('day'); |
|||
_.each(activities, function(activity){ |
|||
var to_display = ''; |
|||
var deadline = moment(activity.date_deadline + ' 00:00:00'); |
|||
var diff = deadline.diff(today, 'days', true); // true means no rounding
|
|||
if(diff === 0){ |
|||
to_display = _t('Today'); |
|||
}else{ |
|||
if(diff < 0){ // overdue
|
|||
if(diff === -1){ |
|||
to_display = _t('Yesterday'); |
|||
}else{ |
|||
to_display = _.str.sprintf(_t('%d days overdue'), Math.abs(diff)); |
|||
} |
|||
}else{ // due
|
|||
if(diff === 1){ |
|||
to_display = _t('Tomorrow'); |
|||
}else{ |
|||
to_display = _.str.sprintf(_t('Due in %d days'), Math.abs(diff)); |
|||
} |
|||
} |
|||
} |
|||
activity.label_delay = to_display; |
|||
}); |
|||
return activities; |
|||
}; |
|||
|
|||
var Activity = form_common.AbstractField.extend({ |
|||
className: 'o_mail_activity', |
|||
events: { |
|||
'click .o_activity_edit': '_onEditActivity', |
|||
'click .o_activity_unlink': '_onUnlinkActivity', |
|||
'click .o_activity_done': '_onMarkActivityDone', |
|||
}, |
|||
render_value: function() { |
|||
return $.when( |
|||
this._super.apply(this, arguments), |
|||
this._readActivities(), |
|||
).then(this.proxy('_render_value')); |
|||
}, |
|||
_render_value: function() { |
|||
var activities = setDelayLabel(this.activities); |
|||
if (activities.length) { |
|||
var nbActivities = _.countBy(activities, 'state'); |
|||
this.$el.html(core.qweb.render('mail.activity_items', { |
|||
activities: activities, |
|||
nbPlannedActivities: nbActivities.planned, |
|||
nbTodayActivities: nbActivities.today, |
|||
nbOverdueActivities: nbActivities.overdue, |
|||
})); |
|||
} else { |
|||
this.$el.empty(); |
|||
} |
|||
}, |
|||
_readActivities: function() { |
|||
var self = this; |
|||
return new Model('mail.activity') |
|||
.query([]) |
|||
.filter([['id', 'in', this.get('value')]]) |
|||
.all() |
|||
.then(function(activities) { |
|||
self.activities = activities; |
|||
}); |
|||
}, |
|||
_scheduleActivity: function (id, previous_activity_type_id, callback) { |
|||
var self = this, |
|||
action = { |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'mail.activity', |
|||
view_mode: 'form', |
|||
view_type: 'form', |
|||
views: [[false, 'form']], |
|||
target: 'new', |
|||
context: { |
|||
default_res_id: this.view.datarecord.id, |
|||
default_res_model: this.view.dataset.model, |
|||
default_previous_activity_type_id: |
|||
previous_activity_type_id || false, |
|||
}, |
|||
res_id: id || false, |
|||
}; |
|||
return this.do_action(action, { |
|||
on_close: function() { |
|||
if(callback) { |
|||
callback(); |
|||
} |
|||
return self.field_manager.reload() |
|||
}, |
|||
}) |
|||
}, |
|||
// handlers
|
|||
_onEditActivity: function (event, options) { |
|||
event.preventDefault(); |
|||
var self = this; |
|||
var activity_id = $(event.currentTarget).data('activity-id'); |
|||
var action = _.defaults(options || {}, { |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'mail.activity', |
|||
view_mode: 'form', |
|||
view_type: 'form', |
|||
views: [[false, 'form']], |
|||
target: 'new', |
|||
context: { |
|||
default_res_id: this.view.datarecord.id, |
|||
default_res_model: this.view.dataset.model, |
|||
}, |
|||
res_id: activity_id, |
|||
}); |
|||
return this.do_action(action, { |
|||
on_close: function () { |
|||
self._render_value(); |
|||
}, |
|||
}); |
|||
}, |
|||
_onUnlinkActivity: function (event, options) { |
|||
event.preventDefault(); |
|||
var activity_id = $(event.currentTarget).data('activity-id'); |
|||
options = _.defaults(options || {}, { |
|||
model: 'mail.activity', |
|||
args: [[activity_id]], |
|||
}); |
|||
return new Model('mail.activity') |
|||
.call('unlink', [activity_id]) |
|||
.then(this.render_value.bind(this)); |
|||
}, |
|||
_onMarkActivityDone: function (event) { |
|||
//TODO: this should open a wizard to write a comment and call action_feedback
|
|||
}, |
|||
}); |
|||
|
|||
core.form_widget_registry.add('mail_activity', Activity); |
|||
|
|||
return Activity; |
|||
}); |
@ -0,0 +1,80 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<templates> |
|||
<t t-extend="mail.Chatter"> |
|||
<t t-jquery="button.o_chatter_button_log_note" t-operation="after"> |
|||
<button t-if="widget.schedule_activity_btn" class="btn btn-sm btn-link o_chatter_button_schedule_activity" title="Log or schedule an activity"> |
|||
<i class="fa fa-clock-o"/> Schedule activity |
|||
</button> |
|||
</t> |
|||
</t> |
|||
<t t-name="mail.activity_items"> |
|||
<div class="o_thread_date_separator o_border_dashed" data-toggle="collapse" data-target="#o_chatter_planned_activities"> |
|||
<span class="o_thread_date btn"> |
|||
<i class="fa fa-fw fa-caret-down"/> |
|||
Planned activities |
|||
<small class="o_chatter_planned_activities_summary ml8"> |
|||
<span class="label img-circle label-danger"><t t-esc="nbOverdueActivities"/></span> |
|||
<span class="label img-circle label-warning"><t t-esc="nbTodayActivities"/></span> |
|||
<span class="label img-circle label-success"><t t-esc="nbPlannedActivities"/></span> |
|||
</small> |
|||
</span> |
|||
</div> |
|||
<div id="o_chatter_planned_activities" class="collapse in"> |
|||
<t t-foreach="activities" t-as="activity"> |
|||
<div class="o_thread_message" style="margin-bottom: 10px"> |
|||
<div class="o_thread_message_sidebar"> |
|||
<div class="o_avatar_stack"> |
|||
<img t-attf-src="/web/image#{activity.user_id[0] >= 0 ? ('/res.users/' + activity.user_id[0] + '/image_small') : ''}" class="o_thread_message_avatar img-circle mb8" t-att-title="activity.create_uid[1]"/> |
|||
<i t-att-class="'o_avatar_icon fa ' + activity.icon + ' bg-' + (activity.state == 'planned'? 'success' : (activity.state == 'today'? 'warning' : 'danger')) + '-full'" |
|||
t-att-title="activity.activity_type_id[1]"/> |
|||
</div> |
|||
</div> |
|||
<div class="o_thread_message_core"> |
|||
<div class="o_mail_info"> |
|||
<strong><span t-attf-class="o_activity_date o_activity_color_#{activity.state}"><t t-esc="activity.label_delay" /></span></strong>: |
|||
<strong t-if="activity.summary"> “<t t-esc="activity.summary"/>”</strong> |
|||
<strong t-if="!activity.summary"> <t t-esc="activity.activity_type_id[1]" /></strong> |
|||
<em> for </em> |
|||
<t t-esc="activity.user_id[1]" /> |
|||
<a class="btn btn-link btn-info text-muted collapsed o_activity_info ml4" role="button" data-toggle="collapse" t-attf-data-target="#o_chatter_activity_info_#{activity.id}"> |
|||
<i class="fa fa-info-circle"></i> |
|||
</a> |
|||
<div class="o_thread_message_collapse collapse" t-attf-id="o_chatter_activity_info_#{activity.id}"> |
|||
<dl class="dl-horizontal well"> |
|||
<dt>Activity type</dt> |
|||
<dd class="mb8"> |
|||
<t t-esc="activity.activity_type_id[1]"/> |
|||
</dd> |
|||
<dt>Created on</dt> |
|||
<dd class="mb8"> |
|||
<t t-esc="moment(activity.create_date)"/> |
|||
</dd> |
|||
<dt>Assigned to</dt> |
|||
<dd class="mb8"> |
|||
<img t-attf-src="/web/image#{activity.user_id[0] >= 0 ? ('/res.users/' + activity.user_id[0] + '/image_small') : ''}" height="18" width="18" class="img-circle mr4" t-att-title="activity.create_uid[1]"/> |
|||
<b><t t-esc="activity.user_id[1]"/></b> |
|||
<em>, due on </em><span t-attf-class="o_activity_color_#{activity.state}"><t t-esc="moment(activity.date_deadline)"/></span> |
|||
</dd> |
|||
</dl> |
|||
</div> |
|||
</div> |
|||
<div t-if="activity.note" class="o_thread_message_note small"> |
|||
<t t-raw="activity.note"/> |
|||
</div> |
|||
<div class="o_thread_message_tools btn-group"> |
|||
<a href="#" class="btn btn-link btn-success text-muted btn-sm o_activity_done o_activity_link mr8" t-att-data-activity-id="activity.id" t-att-data-previous-activity-type-id="activity.activity_type_id[0]" data-toggle="popover"> |
|||
<i class="fa fa-check"/> Mark Done |
|||
</a> |
|||
<a href="#" class="btn btn-link btn-default text-muted btn-sm o_activity_edit o_activity_link" t-att-data-activity-id="activity.id"> |
|||
<i class="fa fa-pencil"/> Edit |
|||
</a> |
|||
<a href="#" class="btn btn-link btn-sm btn-danger text-muted o_activity_unlink o_activity_link" t-att-data-activity-id="activity.id"> |
|||
<i class="fa fa-times"/> Cancel |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</div> |
|||
</t> |
|||
</templates> |
@ -0,0 +1,12 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<odoo> |
|||
<record id="view_partner_form" model="ir.ui.view"> |
|||
<field name="model">res.partner</field> |
|||
<field name="inherit_id" ref="mail.view_emails_partner_info_form" /> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//div[@class='oe_chatter']/field[@name='message_follower_ids']" position="after"> |
|||
<field name="activity_ids" widget="mail_activity" /> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,9 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<odoo> |
|||
<template id="assets_backend" name="mail_activity assets" inherit_id="web.assets_backend"> |
|||
<xpath expr="." position="inside"> |
|||
<script type="text/javascript" src="/mail_activity/static/src/js/mail_activity.js"></script> |
|||
<link rel="stylesheet" href="/mail_activity/static/src/css/mail_activity.css"/> |
|||
</xpath> |
|||
</template> |
|||
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue