[IMP] mail: automatically compute notification groups

Part of task-2258617

closes odoo/odoo#79789

Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
Sébastien Theys
2021-11-16 11:34:33 +00:00
parent 2706f6d7af
commit 09ad04cebc
10 changed files with 85 additions and 96 deletions
@@ -82,8 +82,7 @@ export class NotificationList extends Component {
});
let notifications = threadNeedactionNotifications.concat(threadNotifications);
if (this.props.filter === 'all') {
const notificationGroups = this.messaging.notificationGroupManager.groups;
notifications = Object.values(notificationGroups)
notifications = Object.values(this.messaging.models['mail.notification_group'].all())
.sort((group1, group2) => group1.sequence - group2.sequence)
.map(notificationGroup => {
return {
@@ -389,9 +389,7 @@ function factory(dependencies) {
* @returns {boolean}
*/
_computeFailureNotifications() {
return replace(this.notifications.filter(notifications =>
['exception', 'bounce'].includes(notifications.notification_status)
));
return replace(this.notifications.filter(notifications => notifications.isFailure));
}
/**
@@ -570,9 +568,7 @@ function factory(dependencies) {
attachments: many2many('mail.attachment', {
inverse: 'messages',
}),
author: many2one('mail.partner', {
inverse: 'messagesAsAuthor',
}),
author: many2one('mail.partner'),
/**
* This value is meant to be returned by the server
* (and has been sanitized before stored into db).
@@ -375,11 +375,6 @@ function factory(dependencies) {
isCausal: true,
readonly: true,
}),
notificationGroupManager: one2one('mail.notification_group_manager', {
default: insertAndReplace(),
isCausal: true,
readonly: true,
}),
notificationHandler: one2one('mail.messaging_notification_handler', {
default: insertAndReplace(),
isCausal: true,
@@ -224,7 +224,6 @@ function factory(dependencies) {
message.update({ author: link(this.messaging.currentPartner) });
}
}));
this.messaging.notificationGroupManager.computeGroups();
}
/**
@@ -56,12 +56,10 @@ function factory(dependencies) {
channel.isPinned &&
channel.localMessageUnreadCounter > 0
)).length;
const notificationGroupsCounter = this.messaging.notificationGroupManager
? this.messaging.notificationGroupManager.groups.reduce(
(total, group) => total + group.notifications.length,
0
)
: 0;
const notificationGroupsCounter = this.messaging.models['mail.notification_group'].all().reduce(
(total, group) => total + group.notifications.length,
0
);
const notificationPemissionCounter = this.messaging.isNotificationPermissionDefault ? 1 : 0;
return inboxCounter + unreadChannelsCounter + notificationGroupsCounter + notificationPemissionCounter;
}
@@ -524,8 +524,6 @@ function factory(dependencies) {
message.delete();
}
}
// deleting message might have deleted notifications, force recompute
this.messaging.notificationGroupManager.computeGroups();
}
/**
@@ -543,7 +541,6 @@ function factory(dependencies) {
message.update({ author: link(this.messaging.currentPartner) });
}
}
this.messaging.notificationGroupManager.computeGroups();
}
/**
@@ -2,7 +2,7 @@
import { registerNewModel } from '@mail/model/model_core';
import { attr, many2one } from '@mail/model/model_field';
import { insert, unlinkAll } from '@mail/model/model_field_command';
import { clear, insert, insertAndReplace, unlinkAll } from '@mail/model/model_field_command';
function factory(dependencies) {
@@ -44,6 +44,46 @@ function factory(dependencies) {
return data2;
}
/**
* @private
* @returns {boolean}
*/
_computeIsFailure() {
return ['exception', 'bounce'].includes(this.notification_status);
}
/**
* @private
* @returns {boolean|FieldCommand}
*/
_computeIsFromCurrentUser() {
if (!this.messaging || !this.messaging.currentPartner || !this.message || !this.message.author) {
return clear();
}
return this.messaging.currentPartner === this.message.author;
}
/**
* @private
* @returns {FieldCommand}
*/
_computeNotificationGroup() {
if (!this.isFailure || !this.isFromCurrentUser) {
return clear();
}
const thread = this.message.originThread;
// Notifications are grouped by model and notification_type.
// Except for channel where they are also grouped by id because
// we want to open the actual channel in discuss or chat window
// and not its kanban/list/form view.
return insertAndReplace({
notification_type: this.notification_type,
res_id: thread.model === 'mail.channel' ? thread.id : null,
res_model: thread.model,
res_model_name: thread.model_name,
});
}
}
Notification.fields = {
@@ -52,9 +92,19 @@ function factory(dependencies) {
readonly: true,
required: true,
}),
isFailure: attr({
compute: '_computeIsFailure',
}),
isFromCurrentUser: attr({
compute: '_computeIsFromCurrentUser',
}),
message: many2one('mail.message', {
inverse: 'notifications',
}),
notificationGroup: many2one('mail.notification_group', {
compute: '_computeNotificationGroup',
inverse: 'notifications',
}),
notification_status: attr(),
notification_type: attr(),
partner: many2one('mail.partner'),
@@ -3,6 +3,7 @@
import { registerNewModel } from '@mail/model/model_core';
import { attr, many2one, one2many } from '@mail/model/model_field';
import { clear, insert, unlink } from '@mail/model/model_field_command';
import { OnChange } from '@mail/model/model_onchange';
function factory(dependencies) {
@@ -90,6 +91,15 @@ function factory(dependencies) {
return -Math.max(...this.notifications.map(notification => notification.message.id));
}
/**
* @private
*/
_onChangeNotifications() {
if (this.notifications.length === 0) {
this.delete();
}
}
/**
* Opens the view that displays all the records of the group.
*
@@ -127,13 +137,18 @@ function factory(dependencies) {
date: attr({
compute: '_computeDate',
}),
id: attr({
notification_type: attr({
readonly: true,
}),
notifications: one2many('mail.notification', {
inverse: 'notificationGroup',
}),
res_id: attr({
readonly: true,
}),
res_model: attr({
readonly: true,
required: true,
}),
notification_type: attr(),
notifications: one2many('mail.notification'),
res_model: attr(),
res_model_name: attr(),
/**
* States the position of the group inside the notification list.
@@ -149,7 +164,13 @@ function factory(dependencies) {
compute: '_computeThread',
})
};
NotificationGroup.identifyingFields = ['id'];
NotificationGroup.identifyingFields = ['res_model', 'res_id', 'notification_type'];
NotificationGroup.onChanges = [
new OnChange({
dependencies: ['notifications'],
methodName: '_onChangeNotifications',
}),
];
NotificationGroup.modelName = 'mail.notification_group';
return NotificationGroup;
@@ -1,60 +0,0 @@
/** @odoo-module **/
import { registerNewModel } from '@mail/model/model_core';
import { one2many } from '@mail/model/model_field';
import { link } from '@mail/model/model_field_command';
function factory(dependencies) {
class NotificationGroupManager extends dependencies['mail.model'] {
//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
computeGroups() {
// not supported for guests
if (this.messaging.isCurrentUserGuest) {
return;
}
for (const group of this.groups) {
group.delete();
}
const groups = [];
// TODO batch insert, better logic task-2258605
this.messaging.currentPartner.failureNotifications.forEach(notification => {
const thread = notification.message.originThread;
// Notifications are grouped by model and notification_type.
// Except for channel where they are also grouped by id because
// we want to open the actual channel in discuss or chat window
// and not its kanban/list/form view.
const channelId = thread.model === 'mail.channel' ? thread.id : null;
const id = `${thread.model}/${channelId}/${notification.notification_type}`;
const group = this.messaging.models['mail.notification_group'].insert({
id,
notification_type: notification.notification_type,
res_model: thread.model,
res_model_name: thread.model_name,
});
group.update({ notifications: link(notification) });
// avoid linking the same group twice when adding a notification
// to an existing group
if (!groups.includes(group)) {
groups.push(group);
}
});
this.update({ groups: link(groups) });
}
}
NotificationGroupManager.fields = {
groups: one2many('mail.notification_group'),
};
NotificationGroupManager.identifyingFields = ['messaging'];
NotificationGroupManager.modelName = 'mail.notification_group_manager';
return NotificationGroupManager;
}
registerNewModel('mail.notification_group_manager', factory);
@@ -450,9 +450,6 @@ function factory(dependencies) {
default: "",
}),
email: attr(),
failureNotifications: one2many('mail.notification', {
related: 'messagesAsAuthor.failureNotifications',
}),
/**
* Whether an attempt was already made to fetch the user corresponding
* to this partner. This prevents doing the same RPC multiple times.
@@ -477,9 +474,6 @@ function factory(dependencies) {
memberThreads: many2many('mail.thread', {
inverse: 'members',
}),
messagesAsAuthor: one2many('mail.message', {
inverse: 'author',
}),
model: attr({
default: 'res.partner',
}),