From 09ad04cebcf7f9fc97b2d05ddaeb006efb2e0990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Mon, 15 Nov 2021 17:38:25 +0000 Subject: [PATCH] [IMP] mail: automatically compute notification groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of task-2258617 closes odoo/odoo#79789 Signed-off-by: Alexandre Kühn (aku) --- .../notification_list/notification_list.js | 3 +- .../mail/static/src/models/message/message.js | 8 +-- .../static/src/models/messaging/messaging.js | 5 -- .../messaging_initializer.js | 1 - .../models/messaging_menu/messaging_menu.js | 10 ++-- .../messaging_notification_handler.js | 3 - .../src/models/notification/notification.js | 52 +++++++++++++++- .../notification_group/notification_group.js | 33 ++++++++-- .../notification_group_manager.js | 60 ------------------- .../mail/static/src/models/partner/partner.js | 6 -- 10 files changed, 85 insertions(+), 96 deletions(-) delete mode 100644 addons/mail/static/src/models/notification_group_manager/notification_group_manager.js diff --git a/addons/mail/static/src/components/notification_list/notification_list.js b/addons/mail/static/src/components/notification_list/notification_list.js index 6bd9ba5bc42..7a3d74f519f 100644 --- a/addons/mail/static/src/components/notification_list/notification_list.js +++ b/addons/mail/static/src/components/notification_list/notification_list.js @@ -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 { diff --git a/addons/mail/static/src/models/message/message.js b/addons/mail/static/src/models/message/message.js index a992e479ea9..7d19d5ed127 100644 --- a/addons/mail/static/src/models/message/message.js +++ b/addons/mail/static/src/models/message/message.js @@ -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). diff --git a/addons/mail/static/src/models/messaging/messaging.js b/addons/mail/static/src/models/messaging/messaging.js index 256b101469d..25c4bfed2b1 100644 --- a/addons/mail/static/src/models/messaging/messaging.js +++ b/addons/mail/static/src/models/messaging/messaging.js @@ -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, diff --git a/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js b/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js index 767c69ae55e..4fd4a7ec7e2 100644 --- a/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js +++ b/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js @@ -224,7 +224,6 @@ function factory(dependencies) { message.update({ author: link(this.messaging.currentPartner) }); } })); - this.messaging.notificationGroupManager.computeGroups(); } /** diff --git a/addons/mail/static/src/models/messaging_menu/messaging_menu.js b/addons/mail/static/src/models/messaging_menu/messaging_menu.js index 2f3d79975b6..5e2aae0a4b2 100644 --- a/addons/mail/static/src/models/messaging_menu/messaging_menu.js +++ b/addons/mail/static/src/models/messaging_menu/messaging_menu.js @@ -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; } diff --git a/addons/mail/static/src/models/messaging_notification_handler/messaging_notification_handler.js b/addons/mail/static/src/models/messaging_notification_handler/messaging_notification_handler.js index 70ea9f630c1..91c82105ff5 100644 --- a/addons/mail/static/src/models/messaging_notification_handler/messaging_notification_handler.js +++ b/addons/mail/static/src/models/messaging_notification_handler/messaging_notification_handler.js @@ -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(); } /** diff --git a/addons/mail/static/src/models/notification/notification.js b/addons/mail/static/src/models/notification/notification.js index 17143778fa4..1111276e465 100644 --- a/addons/mail/static/src/models/notification/notification.js +++ b/addons/mail/static/src/models/notification/notification.js @@ -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'), diff --git a/addons/mail/static/src/models/notification_group/notification_group.js b/addons/mail/static/src/models/notification_group/notification_group.js index 58283f0065e..84a5fb07b6e 100644 --- a/addons/mail/static/src/models/notification_group/notification_group.js +++ b/addons/mail/static/src/models/notification_group/notification_group.js @@ -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; diff --git a/addons/mail/static/src/models/notification_group_manager/notification_group_manager.js b/addons/mail/static/src/models/notification_group_manager/notification_group_manager.js deleted file mode 100644 index 3e59720627c..00000000000 --- a/addons/mail/static/src/models/notification_group_manager/notification_group_manager.js +++ /dev/null @@ -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); diff --git a/addons/mail/static/src/models/partner/partner.js b/addons/mail/static/src/models/partner/partner.js index f004c034df0..852e5d1405a 100644 --- a/addons/mail/static/src/models/partner/partner.js +++ b/addons/mail/static/src/models/partner/partner.js @@ -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', }),