[FIX] mail: fix inbox mark all as read on thread view
task-2426357 task-2426366 closes odoo/odoo#65060 X-original-commit: 12f11e0daf7e459bfee518b312e144d78e5a5759 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
+4
-2
@@ -107,7 +107,6 @@ class ThreadNeedactionPreview extends Component {
|
||||
// handled in `_onClickMarkAsRead`
|
||||
return;
|
||||
}
|
||||
this.thread.markNeedactionMessagesAsOriginThreadAsRead();
|
||||
this.thread.open();
|
||||
if (!this.env.messaging.device.isMobile) {
|
||||
this.env.messaging.messagingMenu.close();
|
||||
@@ -119,7 +118,10 @@ class ThreadNeedactionPreview extends Component {
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickMarkAsRead(ev) {
|
||||
this.thread.markNeedactionMessagesAsOriginThreadAsRead();
|
||||
this.env.models['mail.message'].markAllAsRead([
|
||||
['model', '=', this.thread.model],
|
||||
['res_id', '=', this.thread.id],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+25
-9
@@ -44,7 +44,7 @@ QUnit.module('thread_needaction_preview_tests.js', {
|
||||
});
|
||||
|
||||
QUnit.test('mark as read', async function (assert) {
|
||||
assert.expect(4);
|
||||
assert.expect(5);
|
||||
|
||||
this.data['mail.message'].records.push({
|
||||
id: 21,
|
||||
@@ -63,8 +63,16 @@ QUnit.test('mark as read', async function (assert) {
|
||||
hasChatWindow: true,
|
||||
hasMessagingMenu: true,
|
||||
async mockRPC(route, args) {
|
||||
if (route.includes('set_message_done')) {
|
||||
assert.step('set_message_done');
|
||||
if (route.includes('mark_all_as_read')) {
|
||||
assert.step('mark_all_as_read');
|
||||
assert.deepEqual(
|
||||
args.kwargs.domain,
|
||||
[
|
||||
['model', '=', 'res.partner'],
|
||||
['res_id', '=', 11],
|
||||
],
|
||||
"should mark all as read the correct thread"
|
||||
);
|
||||
}
|
||||
return this._super(...arguments);
|
||||
},
|
||||
@@ -87,8 +95,8 @@ QUnit.test('mark as read', async function (assert) {
|
||||
document.querySelector('.o_ThreadNeedactionPreview_markAsRead').click()
|
||||
);
|
||||
assert.verifySteps(
|
||||
['set_message_done'],
|
||||
"should have marked the message as read"
|
||||
['mark_all_as_read'],
|
||||
"should have marked the thread as read"
|
||||
);
|
||||
assert.containsNone(
|
||||
document.body,
|
||||
@@ -98,7 +106,7 @@ QUnit.test('mark as read', async function (assert) {
|
||||
});
|
||||
|
||||
QUnit.test('click on preview should mark as read and open the thread', async function (assert) {
|
||||
assert.expect(5);
|
||||
assert.expect(6);
|
||||
|
||||
this.data['mail.message'].records.push({
|
||||
id: 21,
|
||||
@@ -117,8 +125,16 @@ QUnit.test('click on preview should mark as read and open the thread', async fun
|
||||
hasChatWindow: true,
|
||||
hasMessagingMenu: true,
|
||||
async mockRPC(route, args) {
|
||||
if (route.includes('set_message_done')) {
|
||||
assert.step('set_message_done');
|
||||
if (route.includes('mark_all_as_read')) {
|
||||
assert.step('mark_all_as_read');
|
||||
assert.deepEqual(
|
||||
args.kwargs.domain,
|
||||
[
|
||||
['model', '=', 'res.partner'],
|
||||
['res_id', '=', 11],
|
||||
],
|
||||
"should mark all as read the correct thread"
|
||||
);
|
||||
}
|
||||
return this._super(...arguments);
|
||||
},
|
||||
@@ -146,7 +162,7 @@ QUnit.test('click on preview should mark as read and open the thread', async fun
|
||||
document.querySelector('.o_ThreadNeedactionPreview').click()
|
||||
);
|
||||
assert.verifySteps(
|
||||
['set_message_done'],
|
||||
['mark_all_as_read'],
|
||||
"should have marked the message as read on clicking on the preview"
|
||||
);
|
||||
assert.containsOnce(
|
||||
|
||||
@@ -1484,9 +1484,6 @@ function factory(dependencies) {
|
||||
if (this.channel_type === 'chat' && !this.areFollowersLoaded) {
|
||||
this.refreshFollowers();
|
||||
}
|
||||
if (this.needactionMessagesAsOriginThread.length > 0) {
|
||||
this.markNeedactionMessagesAsOriginThreadAsRead();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -307,6 +307,44 @@ function factory(dependencies) {
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls "mark all as read" when this thread becomes displayed in a
|
||||
* view (which is notified by `isMarkAllAsReadRequested` being `true`),
|
||||
* but delays the call until some other conditions are met, such as the
|
||||
* messages being loaded.
|
||||
* The reason to wait until messages are loaded is to avoid a race
|
||||
* condition because "mark all as read" will change the state of the
|
||||
* messages in parallel to fetch reading them.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onChangeMarkAllAsRead() {
|
||||
if (
|
||||
!this.isMarkAllAsReadRequested ||
|
||||
!this.thread ||
|
||||
!this.thread.mainCache ||
|
||||
!this.isLoaded ||
|
||||
this.isLoading
|
||||
) {
|
||||
// wait for change of state before deciding what to do
|
||||
return;
|
||||
}
|
||||
this.update({ isMarkAllAsReadRequested: false });
|
||||
if (
|
||||
this.thread.isTemporary ||
|
||||
this.thread.model === 'mail.box' ||
|
||||
this.thread.mainCache !== this ||
|
||||
this.threadViews.length === 0
|
||||
) {
|
||||
// ignore the request
|
||||
return;
|
||||
}
|
||||
this.env.models['mail.message'].markAllAsRead([
|
||||
['model', '=', this.thread.model],
|
||||
['res_id', '=', this.thread.id],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads this thread cache, by fetching the most recent messages in this
|
||||
* conversation.
|
||||
@@ -413,6 +451,16 @@ function factory(dependencies) {
|
||||
isCacheRefreshRequested: attr({
|
||||
default: false,
|
||||
}),
|
||||
/**
|
||||
* Determines whether this cache should consider calling "mark all as
|
||||
* read" on this thread.
|
||||
*
|
||||
* This field is a hint that may or may not lead to an actual call.
|
||||
* @see `_onChangeMarkAllAsRead`
|
||||
*/
|
||||
isMarkAllAsReadRequested: attr({
|
||||
default: false,
|
||||
}),
|
||||
/**
|
||||
* Last message that has been fetched by this thread cache.
|
||||
*
|
||||
@@ -458,6 +506,23 @@ function factory(dependencies) {
|
||||
'messagesAreEmpty',
|
||||
],
|
||||
}),
|
||||
/**
|
||||
* Not a real field, used to trigger its compute method when one of the
|
||||
* dependencies changes.
|
||||
*/
|
||||
onChangeMarkAllAsRead: attr({
|
||||
compute: '_onChangeMarkAllAsRead',
|
||||
dependencies: [
|
||||
'isLoaded',
|
||||
'isLoading',
|
||||
'isMarkAllAsReadRequested',
|
||||
'thread',
|
||||
'threadIsTemporary',
|
||||
'threadMainCache',
|
||||
'threadModel',
|
||||
'threadViews',
|
||||
],
|
||||
}),
|
||||
/**
|
||||
* Loads initial messages from `this`.
|
||||
* This is not a "real" field, its compute function is used to trigger
|
||||
@@ -520,6 +585,12 @@ function factory(dependencies) {
|
||||
threadMessages: many2many('mail.message', {
|
||||
related: 'thread.messages',
|
||||
}),
|
||||
/**
|
||||
* Serves as compute dependency.
|
||||
*/
|
||||
threadModel: attr({
|
||||
related: 'thread.model',
|
||||
}),
|
||||
/**
|
||||
* States the 'mail.thread_view' that are currently displaying `this`.
|
||||
*/
|
||||
|
||||
@@ -138,7 +138,10 @@ function factory(dependencies) {
|
||||
this.update({ componentHintList: clear() });
|
||||
this.addComponentHint('change-of-thread-cache');
|
||||
if (this.threadCache) {
|
||||
this.threadCache.update({ isCacheRefreshRequested: true });
|
||||
this.threadCache.update({
|
||||
isCacheRefreshRequested: true,
|
||||
isMarkAllAsReadRequested: true,
|
||||
});
|
||||
}
|
||||
this.update({ lastVisibleMessage: [['unlink']] });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user