[MERGE][IMP] mail, note: improve activity summary view and use
Main specifications * set mail as dependency on contacts as activity view is used in contact that does not depend on mail -> crash; * update icon on the reminders: use calendar instead of clock; * add an icon to Contact in the systray; * add the Activity icon in the upper right corner of the Contact; * sort Activities by date: from more urgent to less urgent; * on the contact name in the activity view, the name is clickable but the cursor is wrong: use the little hand as a cursor; Please see sub-commits for more details. Thanks to @alexkuhn for reviewing and @est-odoo for testing. This merge is linked to task ID 1882545 and closes PR #26797.
This commit is contained in:
@@ -1,2 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
This module gives you a quick view of your contacts directory, accessible from your home page.
|
||||
You can track your vendors, customers and other contacts.
|
||||
""",
|
||||
'depends': ['base'],
|
||||
'depends': ['base', 'mail'],
|
||||
'data': [
|
||||
'views/contact_views.xml',
|
||||
],
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import res_users
|
||||
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models, modules
|
||||
|
||||
|
||||
class Users(models.Model):
|
||||
_name = 'res.users'
|
||||
_inherit = ['res.users']
|
||||
|
||||
@api.model
|
||||
def systray_get_activities(self):
|
||||
""" Update the systray icon of res.partner activities to use the
|
||||
contact application one instead of base icon. """
|
||||
activities = super(Users, self).systray_get_activities()
|
||||
for activity in activities:
|
||||
if activity['model'] != 'res.partner':
|
||||
continue
|
||||
activity['icon'] = modules.module.get_module_icon('contacts')
|
||||
activity['actions'] = [{
|
||||
'icon': 'fa-clock-o',
|
||||
'name': 'Summary',
|
||||
'action_xmlid': 'contacts.action_contacts_summary'
|
||||
}]
|
||||
return activities
|
||||
@@ -34,6 +34,22 @@
|
||||
<field name="act_window_id" ref="action_contacts"/>
|
||||
</record>
|
||||
|
||||
<record id="action_contacts_summary" model="ir.actions.act_window">
|
||||
<field name="name">Contacts</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">res.partner</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">activity,kanban,tree,form</field>
|
||||
<field name="search_view_id" ref="base.view_res_partner_filter"/>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a contact in your address book
|
||||
</p><p>
|
||||
Odoo helps you to easily track all activities related to a customer.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem name="Contacts"
|
||||
id="menu_contacts"
|
||||
sequence="4"
|
||||
|
||||
@@ -408,16 +408,22 @@ class MailActivity(models.Model):
|
||||
def get_activity_data(self, res_model, domain):
|
||||
res = self.env[res_model].search(domain)
|
||||
activity_domain = [('res_id', 'in', res.ids), ('res_model', '=', res_model)]
|
||||
grouped_activities = self.env['mail.activity'].read_group(activity_domain, ['res_id', 'activity_type_id', 'res_name:max(res_name)', 'ids:array_agg(id)', 'date_deadline:min(date_deadline)'], ['res_id', 'activity_type_id'], lazy=False)
|
||||
grouped_activities = self.env['mail.activity'].read_group(
|
||||
activity_domain,
|
||||
['res_id', 'activity_type_id', 'res_name:max(res_name)', 'ids:array_agg(id)', 'date_deadline:min(date_deadline)'],
|
||||
['res_id', 'activity_type_id'],
|
||||
lazy=False)
|
||||
activity_type_ids = self.env['mail.activity.type']
|
||||
res_list = set()
|
||||
res_id_to_name = {}
|
||||
res_id_to_deadline = {}
|
||||
activity_data = defaultdict(dict)
|
||||
for group in grouped_activities:
|
||||
res_id = group['res_id']
|
||||
res_name = group['res_name']
|
||||
activity_type_id = group['activity_type_id'][0]
|
||||
activity_type_ids |= self.env['mail.activity.type'].browse(activity_type_id) # we will get the name when reading mail_template_ids
|
||||
res_list.add((res_id, res_name))
|
||||
res_id_to_name[res_id] = res_name
|
||||
res_id_to_deadline[res_id] = group['date_deadline'] if (res_id not in res_id_to_deadline or group['date_deadline'] < res_id_to_deadline[res_id]) else res_id_to_deadline[res_id]
|
||||
state = self._compute_state_from_date(group['date_deadline'], self.user_id.sudo().tz)
|
||||
activity_data[res_id][activity_type_id] = {
|
||||
'count': group['__count'],
|
||||
@@ -426,6 +432,7 @@ class MailActivity(models.Model):
|
||||
'state': state,
|
||||
'o_closest_deadline': group['date_deadline'],
|
||||
}
|
||||
res_ids_sorted = sorted(res_id_to_deadline, key=lambda item: res_id_to_deadline[item])
|
||||
activity_type_infos = []
|
||||
for elem in activity_type_ids:
|
||||
mail_template_info = []
|
||||
@@ -435,7 +442,7 @@ class MailActivity(models.Model):
|
||||
|
||||
return {
|
||||
'activity_types': activity_type_infos,
|
||||
'res_ids': list(res_list),
|
||||
'res_ids': [(rid, res_id_to_name[rid]) for rid in res_ids_sorted],
|
||||
'grouped_activities': activity_data,
|
||||
'model': res_model,
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ var ActivityMenu = Widget.extend({
|
||||
name: 'activity_menu',
|
||||
template:'mail.systray.ActivityMenu',
|
||||
events: {
|
||||
'click .o_mail_activity_action': '_onActivityActionClick',
|
||||
'click .o_mail_preview': '_onActivityFilterClick',
|
||||
'show.bs.dropdown': '_onActivityMenuShow',
|
||||
},
|
||||
@@ -98,6 +99,17 @@ var ActivityMenu = Widget.extend({
|
||||
// Handlers
|
||||
//------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Redirect to specific action given its xml id
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onActivityActionClick: function (ev) {
|
||||
ev.stopPropagation();
|
||||
var actionXmlid = $(ev.currentTarget).data('action_xmlid');
|
||||
this.do_action(actionXmlid);
|
||||
},
|
||||
|
||||
/**
|
||||
* Redirect to particular model view
|
||||
* @private
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
color: #008784;
|
||||
&:hover {
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
}
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -327,9 +327,19 @@
|
||||
.o_preview_title {
|
||||
display: flex;
|
||||
.o_preview_name {
|
||||
flex: 0 1 auto;
|
||||
flex: 0 0 auto;
|
||||
@include o-text-overflow;
|
||||
}
|
||||
.o_mail_activity_action_buttons {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-flow: row-reverse wrap;
|
||||
}
|
||||
.o_mail_activity_action {
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
.o_preview_counter {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
@@ -78,6 +78,17 @@
|
||||
<span class="o_preview_name">
|
||||
<t t-esc="activity.name"/>
|
||||
</span>
|
||||
<div t-if="activity.actions" class="o_mail_activity_action_buttons">
|
||||
<t t-foreach="activity.actions" t-as="action">
|
||||
<button type="button"
|
||||
t-att-title="action.name"
|
||||
t-att-class="'o_mail_activity_action btn btn-link fa ' + action.icon"
|
||||
t-att-data-action_xmlid="action.action_xmlid"
|
||||
t-att-data-res_model="activity.model"
|
||||
t-att-data-model_name="activity.name">
|
||||
</button>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div t-if="activity and activity.type == 'activity'">
|
||||
<button t-if="activity.overdue_count" type="button" class="btn btn-link o_activity_filter_button mr16" t-att-data-res_model="activity.model" t-att-data-model_name="activity.name" data-filter='overdue'><t t-esc="activity.overdue_count"/> Late </button>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
display: flex;
|
||||
p {
|
||||
flex: 1 1 auto;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
.o_note_save {
|
||||
@@ -60,4 +61,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.o_note_set_datetime {
|
||||
color: $text-muted;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<span class="o_preview_name"><strong>Add a note</strong></span>
|
||||
<div class="o_note_datetime"/>
|
||||
<span class="ml4">
|
||||
<a class="o_note_set_datetime text-muted">
|
||||
<span class="fa fa-clock-o" role="img" aria-label="Set date and time" title="Set date and time"/>
|
||||
<a class="o_note_set_datetime">
|
||||
<span class="fa fa-calendar" role="img" aria-label="Set date and time" title="Set date and time"/>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user