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 -*-
|
//-*- 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).
|
//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