[IMP] mail: compute messaging menu counter with dependencies
It was the last remaining usage of the deprecated `_updateAfter` which is therefore removed too. Part of task-2258617 closes odoo/odoo#70170 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
@@ -37,7 +37,7 @@ class NotificationAlert extends Component {
|
||||
return (
|
||||
windowNotification &&
|
||||
windowNotification.permission !== "granted" &&
|
||||
!this.env.messaging.isNotificationPermissionDefault()
|
||||
!this.env.messaging.isNotificationPermissionDefault
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ class NotificationList extends Component {
|
||||
}).concat(notifications);
|
||||
}
|
||||
// native notification request
|
||||
if (props.filter === 'all' && this.env.messaging.isNotificationPermissionDefault()) {
|
||||
if (props.filter === 'all' && this.env.messaging.isNotificationPermissionDefault) {
|
||||
notifications.unshift({
|
||||
type: 'odoobotRequest',
|
||||
uniqueId: 'odoobotRequest',
|
||||
|
||||
@@ -52,8 +52,7 @@ class NotificationRequest extends Component {
|
||||
* @param {string} value
|
||||
*/
|
||||
_handleResponseNotificationPermission(value) {
|
||||
// manually force recompute because the permission is not in the store
|
||||
this.env.messaging.messagingMenu.update();
|
||||
this.env.messaging.refreshIsNotificationPermissionDefault();
|
||||
if (value !== 'granted') {
|
||||
this.env.services['bus_service'].sendNotification({
|
||||
message: this.env._t("Odoo will not have the permission to send native notifications on this device."),
|
||||
|
||||
@@ -70,12 +70,6 @@ class ModelManager {
|
||||
* O(1) reads/writes.
|
||||
*/
|
||||
this._toComputeFields = new Map();
|
||||
/**
|
||||
* Map of "update after" on records that have been registered.
|
||||
* These are processed after any explicit update and computed/related
|
||||
* fields.
|
||||
*/
|
||||
this._toUpdateAfters = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -583,6 +577,7 @@ class ModelManager {
|
||||
});
|
||||
// Ensure X2many relations are Set initially (other fields can stay undefined).
|
||||
for (const field of Model.__fieldList) {
|
||||
record.__values[field.fieldName] = undefined;
|
||||
if (field.fieldType === 'relation') {
|
||||
if (['one2many', 'many2many'].includes(field.relationType)) {
|
||||
record.__values[field.fieldName] = new Set();
|
||||
@@ -644,10 +639,9 @@ class ModelManager {
|
||||
this._hasAnyChangeDuringCycle = true;
|
||||
// TODO ideally deleting the record should be done at the top of the
|
||||
// method, and it shouldn't be needed to manually remove
|
||||
// _toComputeFields and _toUpdateAfters, but it is not possible until
|
||||
// related are also properly unlinked during `set`
|
||||
// _toComputeFields, but it is not possible until related are also
|
||||
// properly unlinked during `set`.
|
||||
this._toComputeFields.delete(record);
|
||||
this._toUpdateAfters.delete(record);
|
||||
delete Model.__records[record.localId];
|
||||
}
|
||||
|
||||
@@ -685,19 +679,6 @@ class ModelManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Execution of _updateAfter
|
||||
while (this._toUpdateAfters.size > 0) {
|
||||
for (const [record, previous] of this._toUpdateAfters) {
|
||||
// delete at every step to avoid recursion, indeed _updateAfter
|
||||
// might trigger an update cycle itself
|
||||
this._toUpdateAfters.delete(record);
|
||||
if (!record.exists()) {
|
||||
throw Error(`Cannot _updateAfter for already deleted record ${record.localId}.`);
|
||||
}
|
||||
record._updateAfter(previous);
|
||||
}
|
||||
}
|
||||
|
||||
// Execution of _created
|
||||
while (this._createdRecords.size > 0) {
|
||||
for (const record of this._createdRecords) {
|
||||
@@ -1081,11 +1062,6 @@ class ModelManager {
|
||||
throw Error(`Cannot update already deleted record ${record.localId}.`);
|
||||
}
|
||||
const { allowWriteReadonly = false } = options;
|
||||
if (!this._toUpdateAfters.has(record)) {
|
||||
// queue updateAfter before calling field.set to ensure previous
|
||||
// contains the value at the start of update cycle
|
||||
this._toUpdateAfters.set(record, record._updateBefore());
|
||||
}
|
||||
const Model = record.constructor;
|
||||
let hasChanged = false;
|
||||
for (const fieldName of Object.keys(data)) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { registerNewModel } from '@mail/model/model_core';
|
||||
import { attr, many2many, many2one, one2many, one2one } from '@mail/model/model_field';
|
||||
import { create } from '@mail/model/model_field_command';
|
||||
import { create, replace } from '@mail/model/model_field_command';
|
||||
|
||||
function factory(dependencies) {
|
||||
|
||||
@@ -33,16 +33,6 @@ function factory(dependencies) {
|
||||
// Public
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isNotificationPermissionDefault() {
|
||||
const windowNotification = this.env.browser.Notification;
|
||||
return windowNotification
|
||||
? windowNotification.permission === 'default'
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the form view of the record with provided id and model.
|
||||
* Gets the chat with the provided person and returns it.
|
||||
@@ -143,10 +133,43 @@ function factory(dependencies) {
|
||||
return this.env.messaging.openDocument({ id, model });
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the value of `isNotificationPermissionDefault`.
|
||||
*
|
||||
* Must be called in flux-specific way because the browser does not
|
||||
* provide an API to detect when this value changes.
|
||||
*/
|
||||
refreshIsNotificationPermissionDefault() {
|
||||
this.update({ isNotificationPermissionDefault: this._computeIsNotificationPermissionDefault() });
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Private
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeAllChannels() {
|
||||
return replace(this.allThreads.filter(thread => thread.model === 'mail.channel'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeAllPinnedChannels() {
|
||||
return replace(this.allChannels.filter(channel => channel.isPinned));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_computeIsNotificationPermissionDefault() {
|
||||
const browserNotification = this.env.browser.Notification;
|
||||
return browserNotification ? browserNotification.permission === 'default' : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -160,6 +183,47 @@ function factory(dependencies) {
|
||||
}
|
||||
|
||||
Messaging.fields = {
|
||||
/**
|
||||
* States all known channels.
|
||||
*/
|
||||
allChannels: one2many('mail.thread', {
|
||||
compute: '_computeAllChannels',
|
||||
dependencies: [
|
||||
'allThreads',
|
||||
'allThreadsModel',
|
||||
],
|
||||
readonly: true,
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
allChannelsIsPinned: attr({
|
||||
related: 'allChannels.isPinned',
|
||||
}),
|
||||
/**
|
||||
* States all known pinned channels.
|
||||
*/
|
||||
allPinnedChannels: one2many('mail.thread', {
|
||||
compute: '_computeAllPinnedChannels',
|
||||
dependencies: [
|
||||
'allChannels',
|
||||
'allChannelsIsPinned',
|
||||
],
|
||||
readonly: true,
|
||||
}),
|
||||
/**
|
||||
* States all known threads.
|
||||
*/
|
||||
allThreads: one2many('mail.thread', {
|
||||
inverse: 'messaging',
|
||||
readonly: true,
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
allThreadsModel: attr({
|
||||
related: 'allThreads.model',
|
||||
}),
|
||||
cannedResponses: one2many('mail.canned_response'),
|
||||
chatWindowManager: one2one('mail.chat_window_manager', {
|
||||
default: create(),
|
||||
@@ -203,6 +267,14 @@ function factory(dependencies) {
|
||||
isInitialized: attr({
|
||||
default: false,
|
||||
}),
|
||||
/**
|
||||
* States whether browser Notification Permission is currently in its
|
||||
* 'default' state. This means it is allowed to make a request to the
|
||||
* user to enable notifications.
|
||||
*/
|
||||
isNotificationPermissionDefault: attr({
|
||||
compute: '_computeIsNotificationPermissionDefault',
|
||||
}),
|
||||
locale: one2one('mail.locale', {
|
||||
default: create(),
|
||||
isCausal: true,
|
||||
|
||||
@@ -223,8 +223,6 @@ function factory(dependencies) {
|
||||
}
|
||||
}));
|
||||
this.messaging.notificationGroupManager.computeGroups();
|
||||
// manually force recompute of counter (after computing the groups)
|
||||
this.messaging.messagingMenu.update();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerNewModel } from '@mail/model/model_core';
|
||||
import { attr, one2one } from '@mail/model/model_field';
|
||||
import { attr, one2many, one2one } from '@mail/model/model_field';
|
||||
|
||||
function factory(dependencies) {
|
||||
|
||||
@@ -31,6 +31,7 @@ function factory(dependencies) {
|
||||
*/
|
||||
toggleOpen() {
|
||||
this.update({ isOpen: !this.isOpen });
|
||||
this.env.messaging.refreshIsNotificationPermissionDefault();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -56,45 +57,39 @@ function factory(dependencies) {
|
||||
* @private
|
||||
* @returns {integer}
|
||||
*/
|
||||
_updateCounter() {
|
||||
_computeCounter() {
|
||||
if (!this.env.messaging) {
|
||||
return 0;
|
||||
}
|
||||
const inboxMailbox = this.env.messaging.inbox;
|
||||
const unreadChannels = this.env.models['mail.thread'].all(thread =>
|
||||
thread.localMessageUnreadCounter > 0 &&
|
||||
thread.model === 'mail.channel' &&
|
||||
thread.isPinned
|
||||
);
|
||||
let counter = unreadChannels.length;
|
||||
if (inboxMailbox) {
|
||||
counter += inboxMailbox.counter;
|
||||
}
|
||||
if (this.messaging.notificationGroupManager) {
|
||||
counter += this.messaging.notificationGroupManager.groups.reduce(
|
||||
const inboxCounter = this.env.messaging.inbox ? this.env.messaging.inbox.counter : 0;
|
||||
const unreadChannelsCounter = this.env.messaging.allPinnedChannels.filter(
|
||||
channel => channel.localMessageUnreadCounter > 0
|
||||
).length;
|
||||
const notificationGroupsCounter = this.messaging.notificationGroupManager
|
||||
? this.messaging.notificationGroupManager.groups.reduce(
|
||||
(total, group) => total + group.notifications.length,
|
||||
0
|
||||
);
|
||||
}
|
||||
if (this.messaging.isNotificationPermissionDefault()) {
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_updateAfter(previous) {
|
||||
const counter = this._updateCounter();
|
||||
if (this.counter !== counter) {
|
||||
this.update({ counter });
|
||||
}
|
||||
)
|
||||
: 0;
|
||||
const notificationPemissionCounter = this.messaging.isNotificationPermissionDefault ? 1 : 0;
|
||||
return inboxCounter + unreadChannelsCounter + notificationGroupsCounter + notificationPemissionCounter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MessagingMenu.fields = {
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
allPinnedChannels: one2many('mail.thread', {
|
||||
related: 'messaging.allPinnedChannels',
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
allPinnedChannelsLocalMessageUnreadCounter: attr({
|
||||
related: 'allPinnedChannels.localMessageUnreadCounter',
|
||||
}),
|
||||
/**
|
||||
* Tab selected in the messaging menu.
|
||||
* Either 'all', 'chat' or 'channel'.
|
||||
@@ -102,8 +97,24 @@ function factory(dependencies) {
|
||||
activeTabId: attr({
|
||||
default: 'all',
|
||||
}),
|
||||
/**
|
||||
* States the counter of this messaging menu. The counter is an integer
|
||||
* value to give to the current user an estimate of how many things
|
||||
* (unread threads, notifications, ...) are yet to be processed by him.
|
||||
*/
|
||||
counter: attr({
|
||||
default: 0,
|
||||
compute: '_computeCounter',
|
||||
dependencies: [
|
||||
'allPinnedChannels',
|
||||
'allPinnedChannelsLocalMessageUnreadCounter',
|
||||
'messaging',
|
||||
'messagingInbox',
|
||||
'messagingInboxCounter',
|
||||
'messagingIsNotificationPermissionDefault',
|
||||
'messagingNotificationGroupManager',
|
||||
'messagingNotificationGroupManagerGroups',
|
||||
'messagingNotificationGroupManagerGroupsNotifications',
|
||||
],
|
||||
}),
|
||||
/**
|
||||
* Dummy field to automatically load messages of inbox when messaging
|
||||
@@ -132,15 +143,54 @@ function factory(dependencies) {
|
||||
isOpen: attr({
|
||||
default: false,
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
messaging: one2one('mail.messaging', {
|
||||
inverse: 'messagingMenu',
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
messagingInbox: one2one('mail.thread', {
|
||||
related: 'messaging.inbox',
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
messagingInboxCounter: attr({
|
||||
related: 'messagingInbox.counter',
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
messagingIsNotificationPermissionDefault: attr({
|
||||
related: 'messaging.isNotificationPermissionDefault',
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
messagingInboxMainCache: one2one('mail.thread_cache', {
|
||||
related: 'messagingInbox.mainCache',
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
messagingNotificationGroupManager: one2one('mail.notification_group_manager', {
|
||||
related: 'messaging.notificationGroupManager',
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
messagingNotificationGroupManagerGroups: one2many('mail.notification_group', {
|
||||
related: 'messagingNotificationGroupManager.groups'
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
messagingNotificationGroupManagerGroupsNotifications: one2many('mail.notification', {
|
||||
related: 'messagingNotificationGroupManagerGroups.notifications'
|
||||
}),
|
||||
};
|
||||
|
||||
MessagingMenu.modelName = 'mail.messaging_menu';
|
||||
|
||||
-18
@@ -271,8 +271,6 @@ function factory(dependencies) {
|
||||
if (!wasChannelExisting) {
|
||||
return;
|
||||
}
|
||||
// manually force recompute of counter
|
||||
this.messaging.messagingMenu.update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,8 +323,6 @@ function factory(dependencies) {
|
||||
// FIXME force the computing of message values (cf task-2261221)
|
||||
this.env.models['mail.message_seen_indicator'].recomputeSeenValues(channel);
|
||||
}
|
||||
// manually force recompute of counter
|
||||
this.messaging.messagingMenu.update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,8 +378,6 @@ function factory(dependencies) {
|
||||
if (originThread && message.isNeedaction) {
|
||||
originThread.update({ message_needaction_counter: increment() });
|
||||
}
|
||||
// manually force recompute of counter
|
||||
this.messaging.messagingMenu.update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -487,8 +481,6 @@ function factory(dependencies) {
|
||||
});
|
||||
}
|
||||
// a new thread with unread messages could have been added
|
||||
// manually force recompute of counter
|
||||
this.messaging.messagingMenu.update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -512,8 +504,6 @@ function factory(dependencies) {
|
||||
}
|
||||
// deleting message might have deleted notifications, force recompute
|
||||
this.messaging.notificationGroupManager.computeGroups();
|
||||
// manually force recompute of counter (after computing the groups)
|
||||
this.messaging.messagingMenu.update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -532,8 +522,6 @@ function factory(dependencies) {
|
||||
}
|
||||
}
|
||||
this.messaging.notificationGroupManager.computeGroups();
|
||||
// manually force recompute of counter (after computing the groups)
|
||||
this.messaging.messagingMenu.update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -577,8 +565,6 @@ function factory(dependencies) {
|
||||
// messages on the server.
|
||||
inbox.mainCache.update({ hasToLoadMessages: true });
|
||||
}
|
||||
// manually force recompute of counter
|
||||
this.messaging.messagingMenu.update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -594,8 +580,6 @@ function factory(dependencies) {
|
||||
if (moderationMailbox) {
|
||||
moderationMailbox.update({ counter: increment() });
|
||||
}
|
||||
// manually force recompute of counter
|
||||
this.messaging.messagingMenu.update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -641,8 +625,6 @@ function factory(dependencies) {
|
||||
isTransient: true,
|
||||
}));
|
||||
this._notifyThreadViewsMessageReceived(message);
|
||||
// manually force recompute of counter
|
||||
this.messaging.messagingMenu.update();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -231,38 +231,6 @@ function factory() {
|
||||
return _.uniqueId(`${this.modelName}_`);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when this record has been explicitly updated
|
||||
* with `.update()` or static method `.create()`, at the end of an
|
||||
* record update cycle. This is a backward-compatible behaviour that
|
||||
* is deprecated: you should use computed fields instead.
|
||||
*
|
||||
* @deprecated
|
||||
* @abstract
|
||||
* @private
|
||||
* @param {Object} previous contains data that have been stored by
|
||||
* `_updateBefore()`. Useful to make extra update decisions based on
|
||||
* previous data.
|
||||
*/
|
||||
_updateAfter(previous) {}
|
||||
|
||||
/**
|
||||
* This function is called just at the beginning of an explicit update
|
||||
* on this function, with `.update()` or static method `.create()`. This
|
||||
* is useful to remember previous values of fields in `_updateAfter`.
|
||||
* This is a backward-compatible behaviour that is deprecated: you
|
||||
* should use computed fields instead.
|
||||
*
|
||||
* @deprecated
|
||||
* @abstract
|
||||
* @private
|
||||
* @param {Object} data
|
||||
* @returns {Object}
|
||||
*/
|
||||
_updateBefore() {
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -411,8 +411,6 @@ function factory(dependencies) {
|
||||
const channels = this.env.models['mail.thread'].insert(
|
||||
channelInfos.map(channelInfo => this.env.models['mail.thread'].convertData(channelInfo))
|
||||
);
|
||||
// manually force recompute of counter
|
||||
this.env.messaging.messagingMenu.update();
|
||||
return channels;
|
||||
}
|
||||
|
||||
@@ -2015,8 +2013,14 @@ function factory(dependencies) {
|
||||
inverse: 'thread',
|
||||
isCausal: true,
|
||||
}),
|
||||
/**
|
||||
* States the current messaging instance. Not useful by itself because
|
||||
* messaging is already in the env. But this allows the inverse relation
|
||||
* to contain all known threads. It also serves as compute dependency.
|
||||
*/
|
||||
messaging: many2one('mail.messaging', {
|
||||
compute: '_computeMessaging',
|
||||
inverse: 'allThreads',
|
||||
}),
|
||||
messagingCurrentPartner: many2one('mail.partner', {
|
||||
related: 'messaging.currentPartner',
|
||||
|
||||
Reference in New Issue
Block a user