diff --git a/addons/hr_holidays/tests/test_out_of_office.py b/addons/hr_holidays/tests/test_out_of_office.py index a4c89cb1920..8850e2c765e 100644 --- a/addons/hr_holidays/tests/test_out_of_office.py +++ b/addons/hr_holidays/tests/test_out_of_office.py @@ -50,7 +50,7 @@ class TestOutOfOffice(TestHrHolidaysCommon): }) channel_info = channel._channel_info()[0] # shape of channelMembers is [('ADD', data...)], [0][1] accesses the data - members_data = channel_info['channel']['channelMembers'][0][1] + members_data = channel_info['channelMembers'][0][1] self.assertEqual(len(members_data), 2, "Channel info should get info for the 2 members") partner_info = next(member for member in members_data if member['persona']['email'] == partner.email) partner2_info = next(member for member in members_data if member['persona']['email'] == partner2.email) diff --git a/addons/im_livechat/models/discuss_channel.py b/addons/im_livechat/models/discuss_channel.py index fb5424d061a..bab7313d9ae 100644 --- a/addons/im_livechat/models/discuss_channel.py +++ b/addons/im_livechat/models/discuss_channel.py @@ -51,8 +51,8 @@ class DiscussChannel(models.Model): for channel in self: if channel.chatbot_current_step_id: channel_infos_dict[channel.id]["chatbot_script_id"] = channel.chatbot_current_step_id.chatbot_script_id.id - channel_infos_dict[channel.id]['channel']['anonymous_name'] = channel.anonymous_name - channel_infos_dict[channel.id]['channel']['anonymous_country'] = { + channel_infos_dict[channel.id]['anonymous_name'] = channel.anonymous_name + channel_infos_dict[channel.id]['anonymous_country'] = { 'code': channel.country_id.code, 'id': channel.country_id.id, 'name': channel.country_id.name, diff --git a/addons/im_livechat/static/src/composer/suggestion_service_patch.js b/addons/im_livechat/static/src/composer/suggestion_service_patch.js index 9fa578b849f..f312cf2bbd7 100644 --- a/addons/im_livechat/static/src/composer/suggestion_service_patch.js +++ b/addons/im_livechat/static/src/composer/suggestion_service_patch.js @@ -3,7 +3,6 @@ import { SuggestionService } from "@mail/core/common/suggestion_service"; import { cleanTerm } from "@mail/utils/common/format"; -import { _t } from "@web/core/l10n/translation"; import { patch } from "@web/core/utils/patch"; patch(SuggestionService.prototype, { @@ -31,20 +30,14 @@ patch(SuggestionService.prototype, { }, searchCannedResponseSuggestions(cleanedSearchTerm, sort) { - const cannedResponses = Object.values(this.store.CannedResponse.records) - .filter((cannedResponse) => { - return cleanTerm(cannedResponse.name).includes(cleanedSearchTerm); - }) - .map(({ id, name, substitution }) => { - return { - id, - name, - substitution: _t(substitution), - }; - }); + const cannedResponses = Object.values(this.store.CannedResponse.records).filter( + (cannedResponse) => { + return cleanTerm(cannedResponse.source).includes(cleanedSearchTerm); + } + ); const sortFunc = (c1, c2) => { - const cleanedName1 = cleanTerm(c1.name); - const cleanedName2 = cleanTerm(c2.name); + const cleanedName1 = cleanTerm(c1.source); + const cleanedName2 = cleanTerm(c2.source); if ( cleanedName1.startsWith(cleanedSearchTerm) && !cleanedName2.startsWith(cleanedSearchTerm) diff --git a/addons/im_livechat/static/src/core/@types/models.d.ts b/addons/im_livechat/static/src/core/@types/models.d.ts index f7bed8977b6..c53e11abc92 100644 --- a/addons/im_livechat/static/src/core/@types/models.d.ts +++ b/addons/im_livechat/static/src/core/@types/models.d.ts @@ -3,6 +3,8 @@ declare module "models" { livechat: DiscussAppCategory, } export interface Thread { + anonymous_country: Object, + anonymous_name: String, operator: Persona, } } diff --git a/addons/im_livechat/static/src/core/channel_member_list_patch.xml b/addons/im_livechat/static/src/core/channel_member_list_patch.xml index b905d651d61..a0fc7fe4cd3 100644 --- a/addons/im_livechat/static/src/core/channel_member_list_patch.xml +++ b/addons/im_livechat/static/src/core/channel_member_list_patch.xml @@ -9,9 +9,9 @@ - + - + diff --git a/addons/im_livechat/static/src/core/thread_model_patch.js b/addons/im_livechat/static/src/core/thread_model_patch.js index fbea6d3c9ed..d183a4a1c97 100644 --- a/addons/im_livechat/static/src/core/thread_model_patch.js +++ b/addons/im_livechat/static/src/core/thread_model_patch.js @@ -2,7 +2,7 @@ import { Record } from "@mail/core/common/record"; import { Thread } from "@mail/core/common/thread_model"; -import { assignDefined } from "@mail/utils/common/misc"; +import { assignIn } from "@mail/utils/common/misc"; import { patch } from "@web/core/utils/patch"; @@ -10,9 +10,7 @@ patch(Thread, { insert(data) { const thread = super.insert(data); if (thread.type === "livechat") { - if (data?.channel) { - assignDefined(thread, data.channel, ["anonymous_name"]); - } + assignIn(thread, data, ["anonymous_name", "anonymous_country"]); if (data?.operator_pid) { thread.operator = { type: "partner", @@ -69,10 +67,8 @@ patch(Thread.prototype, { if (!this.correspondent.is_public && this.correspondent.country) { return `${this.getMemberName(this.correspondent)} (${this.correspondent.country.name})`; } - if (this.channel?.anonymous_country) { - return `${this.getMemberName(this.correspondent)} (${ - this.channel.anonymous_country.name - })`; + if (this.anonymous_country) { + return `${this.getMemberName(this.correspondent)} (${this.anonymous_country.name})`; } return this.getMemberName(this.correspondent); }, diff --git a/addons/im_livechat/static/src/core/web/livechat_core_web_service.js b/addons/im_livechat/static/src/core/web/livechat_core_web_service.js index 6ded0c0c2eb..981cccef403 100644 --- a/addons/im_livechat/static/src/core/web/livechat_core_web_service.js +++ b/addons/im_livechat/static/src/core/web/livechat_core_web_service.js @@ -20,11 +20,10 @@ export class LivechatCoreWeb { if (data.current_user_settings?.is_discuss_sidebar_category_livechat_open) { this.store.discuss.livechat.isOpen = true; } - this.busService.subscribe("mail.record/insert", (payload) => { - const { "res.users.settings": settings } = payload; - if (settings) { + this.busService.subscribe("res.users.settings", (payload) => { + if (payload) { this.store.discuss.livechat.isOpen = - settings.is_discuss_sidebar_category_livechat_open ?? + payload.is_discuss_sidebar_category_livechat_open ?? this.store.discuss.livechat.isOpen; } }); diff --git a/addons/im_livechat/static/src/embed/core/livechat_service.js b/addons/im_livechat/static/src/embed/core/livechat_service.js index 853e0aa08c2..ed3092ce524 100644 --- a/addons/im_livechat/static/src/embed/core/livechat_service.js +++ b/addons/im_livechat/static/src/embed/core/livechat_service.js @@ -1,5 +1,6 @@ /* @odoo-module */ +import { Record } from "@mail/core/common/record"; import { reactive } from "@odoo/owl"; import { browser } from "@web/core/browser/browser"; @@ -106,6 +107,9 @@ export class LivechatService { * @param {Object} values */ updateSession(values) { + if (Record.isRecord(values?.channel)) { + values.channel = values.channel.toData(); + } const session = JSON.parse(cookie.get(this.SESSION_COOKIE) ?? "{}"); Object.assign(session, { visitor_uid: this.visitorUid, diff --git a/addons/im_livechat/static/src/embed/core/thread_model_patch.js b/addons/im_livechat/static/src/embed/core/thread_model_patch.js index 25d618ee9e7..93e8efb8286 100644 --- a/addons/im_livechat/static/src/embed/core/thread_model_patch.js +++ b/addons/im_livechat/static/src/embed/core/thread_model_patch.js @@ -26,7 +26,7 @@ patch(Thread, { livechatService.updateSession({ state: thread.state, seen_message_id: thread.seen_message_id, - channel: thread.channel, + channel: thread, allow_public_upload: thread.allow_public_upload, }); } diff --git a/addons/im_livechat/static/tests/helpers/mock_server/models/discuss_channel.js b/addons/im_livechat/static/tests/helpers/mock_server/models/discuss_channel.js index 4f6dc0d7792..36c1c4f08d4 100644 --- a/addons/im_livechat/static/tests/helpers/mock_server/models/discuss_channel.js +++ b/addons/im_livechat/static/tests/helpers/mock_server/models/discuss_channel.js @@ -13,7 +13,7 @@ patch(MockServer.prototype, { const channelInfos = super._mockDiscussChannelChannelInfo(...arguments); for (const channelInfo of channelInfos) { const channel = this.getRecords("discuss.channel", [["id", "=", channelInfo.id]])[0]; - channelInfo["channel"]["anonymous_name"] = channel.anonymous_name; + channelInfo["anonymous_name"] = channel.anonymous_name; // add the last message date if (channel.channel_type === "livechat") { // add the operator id diff --git a/addons/im_livechat/static/tests/sidebar_patch_tests.js b/addons/im_livechat/static/tests/sidebar_patch_tests.js index 1f963bcc4cd..7b546c7cebd 100644 --- a/addons/im_livechat/static/tests/sidebar_patch_tests.js +++ b/addons/im_livechat/static/tests/sidebar_patch_tests.js @@ -182,11 +182,9 @@ QUnit.test("Open from the bus", async () => { await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel", { count: 0, }); - pyEnv["bus.bus"]._sendone(pyEnv.currentPartner, "mail.record/insert", { - "res.users.settings": { - id: settingsId, - is_discuss_sidebar_category_livechat_open: true, - }, + pyEnv["bus.bus"]._sendone(pyEnv.currentPartner, "res.users.settings", { + id: settingsId, + is_discuss_sidebar_category_livechat_open: true, }); await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); }); @@ -210,11 +208,9 @@ QUnit.test("Close from the bus", async () => { const { openDiscuss } = await start(); openDiscuss(); await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); - pyEnv["bus.bus"]._sendone(pyEnv.currentPartner, "mail.record/insert", { - "res.users.settings": { - id: settingsId, - is_discuss_sidebar_category_livechat_open: false, - }, + pyEnv["bus.bus"]._sendone(pyEnv.currentPartner, "res.users.settings", { + id: settingsId, + is_discuss_sidebar_category_livechat_open: false, }); await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel", { count: 0, diff --git a/addons/im_livechat/tests/test_get_discuss_channel.py b/addons/im_livechat/tests/test_get_discuss_channel.py index 49a3bac3f59..ba8d3f36c13 100644 --- a/addons/im_livechat/tests/test_get_discuss_channel.py +++ b/addons/im_livechat/tests/test_get_discuss_channel.py @@ -36,12 +36,12 @@ class TestGetDiscussChannel(TestImLivechatCommon): 'country_id': belgium.id, }, ) - self.assertEqual(channel_info['channel']['anonymous_name'], "Visitor 22") - self.assertEqual(channel_info['channel']['anonymous_country'], {'code': 'BE', 'id': belgium.id, 'name': 'Belgium'}) + self.assertEqual(channel_info['anonymous_name'], "Visitor 22") + self.assertEqual(channel_info['anonymous_country'], {'code': 'BE', 'id': belgium.id, 'name': 'Belgium'}) # ensure member info are hidden (in particular email and real name when livechat username is present) # shape of channelMembers is [('ADD', data...)], [0][1] accesses the data - self.assertEqual(sorted((m['persona'] for m in channel_info['channel']['channelMembers'][0][1]), key=lambda m: m['id']), sorted([{ + self.assertEqual(sorted((m['persona'] for m in channel_info['channelMembers'][0][1]), key=lambda m: m['id']), sorted([{ 'id': self.env['discuss.channel'].browse(channel_info['id']).channel_member_ids.filtered(lambda m: m.guest_id)[0].guest_id.id, 'name': 'Visitor', 'im_status': 'offline', @@ -64,11 +64,11 @@ class TestGetDiscussChannel(TestImLivechatCommon): 'user_id': test_user.id, 'channel_id': self.livechat_channel.id, }) - self.assertFalse(channel_info['channel']['anonymous_name']) - self.assertEqual(channel_info['channel']['anonymous_country'], {'code': 'BE', 'id': belgium.id, 'name': 'Belgium'}) - self.assertEqual(channel_info['channel']['channelMembers'], [['ADD', [ + self.assertFalse(channel_info['anonymous_name']) + self.assertEqual(channel_info['anonymous_country'], {'code': 'BE', 'id': belgium.id, 'name': 'Belgium'}) + self.assertEqual(channel_info['channelMembers'], [['ADD', [ { - 'channel': {'id': channel_info['id']}, + 'thread': {'id': channel_info['id'], 'model': "discuss.channel"}, 'id': self.env['discuss.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', '=', operator.partner_id.id)]).id, 'persona': { 'active': True, @@ -81,7 +81,7 @@ class TestGetDiscussChannel(TestImLivechatCommon): }, }, { - 'channel': {'id': channel_info['id']}, + 'thread': {'id': channel_info['id'], 'model': "discuss.channel"}, 'id': self.env['discuss.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', '=', test_user.partner_id.id)]).id, 'persona': { 'active': True, @@ -109,11 +109,11 @@ class TestGetDiscussChannel(TestImLivechatCommon): 'channel_id': self.livechat_channel.id, }) self.assertEqual(channel_info['operator_pid'], [operator.partner_id.id, "Michel Operator"]) - self.assertFalse(channel_info['channel']['anonymous_name']) - self.assertEqual(channel_info['channel']['anonymous_country'], False) - self.assertEqual(channel_info['channel']['channelMembers'], [['ADD', [ + self.assertFalse(channel_info['anonymous_name']) + self.assertEqual(channel_info['anonymous_country'], False) + self.assertEqual(channel_info['channelMembers'], [['ADD', [ { - 'channel': {'id': channel_info['id']}, + 'thread': {'id': channel_info['id'], 'model': "discuss.channel"}, 'id': self.env['discuss.channel.member'].search([('channel_id', '=', channel_info['id']), ('partner_id', '=', operator.partner_id.id)]).id, 'persona': { 'active': True, diff --git a/addons/im_livechat/tests/test_message.py b/addons/im_livechat/tests/test_message.py index 57386ef54fa..95a12d3533d 100644 --- a/addons/im_livechat/tests/test_message.py +++ b/addons/im_livechat/tests/test_message.py @@ -53,7 +53,7 @@ class TestImLivechatMessage(HttpCase): rating_id=record_rating.id, ) self.assertEqual(message.message_format(), [{ - 'attachment_ids': [], + 'attachments': [], 'author': { 'id': self.users[1].partner_id.id, 'is_company': self.users[1].partner_id.is_company, @@ -75,7 +75,7 @@ class TestImLivechatMessage(HttpCase): 'is_note': True, 'linkPreviews': [], 'message_type': 'notification', - 'messageReactionGroups': [], + 'reactions': [], 'model': 'discuss.channel', 'module_icon': '/mail/static/description/icon.png', 'needaction_partner_ids': [], diff --git a/addons/mail/models/discuss/discuss_channel.py b/addons/mail/models/discuss/discuss_channel.py index cdcfbedf96c..d5c9e2e8219 100644 --- a/addons/mail/models/discuss/discuss_channel.py +++ b/addons/mail/models/discuss/discuss_channel.py @@ -295,9 +295,10 @@ class Channel(models.Model): if 'image_128' in vals: for channel in self: notifications.append([channel, 'mail.record/insert', { - 'Channel': { + 'Thread': { 'avatarCacheKey': channel._get_avatar_cache_key(), 'id': channel.id, + 'model': "discuss.channel", } }]) self.env['bus.bus']._sendmany(notifications) @@ -355,10 +356,11 @@ class Channel(models.Model): # post 'channel left' message as root since the partner just unsubscribed from the channel self.sudo().message_post(body=notification, subtype_xmlid="mail.mt_comment", author_id=partner.id) self.env['bus.bus']._sendone(self, 'mail.record/insert', { - 'Channel': { + 'Thread': { 'channelMembers': [('DELETE', {'id': member_id})], 'id': self.id, 'memberCount': self.member_count, + 'model': "discuss.channel", } }) @@ -431,10 +433,11 @@ class Channel(models.Model): 'channel': member.channel_id.sudo()._channel_info()[0], })) notifications.append((channel, 'mail.record/insert', { - 'Channel': { + 'Thread': { 'channelMembers': [('ADD', list(new_members._discuss_channel_member_format().values()))], 'id': channel.id, 'memberCount': channel.member_count, + 'model': "discuss.channel", } })) if existing_members: @@ -442,10 +445,11 @@ class Channel(models.Model): # In particular this fixes issues where the current user is not aware of its own member in the following case: # create channel from form view, and then join from discuss without refreshing the page. notifications.append((current_partner or current_guest, 'mail.record/insert', { - 'Channel': { + 'Thread': { 'channelMembers': [('ADD', list(existing_members._discuss_channel_member_format().values()))], 'id': channel.id, 'memberCount': channel.member_count, + 'model': "discuss.channel", } })) if invite_to_rtc_call: @@ -690,7 +694,7 @@ class Channel(models.Model): allowed_company_ids=user_id.company_ids.ids ) for channel_info in user_channels._channel_info(): - notifications.append((partner, 'discuss.channel/legacy_insert', channel_info)) + notifications.append((partner, 'mail.record/insert', {"Thread": channel_info})) return notifications def _channel_message_notifications(self, message, message_format=False): @@ -809,7 +813,6 @@ class Channel(models.Model): return [] channel_infos = [] rtc_sessions_by_channel = self.sudo().rtc_session_ids._mail_rtc_session_format_by_channel() - channel_last_message_ids = dict((r['id'], r['message_id']) for r in self._channel_last_message_ids()) current_partner, current_guest = self.env["res.partner"]._get_current_persona() self.env['discuss.channel'].flush_model() self.env['discuss.channel.member'].flush_model() @@ -843,13 +846,10 @@ class Channel(models.Model): if (current_partner and member.partner_id == current_partner) or (current_guest and member.guest_id == current_guest): member_of_current_user_by_channel[member.channel_id] = member for channel in self: - channel_data = { + info = { 'avatarCacheKey': channel._get_avatar_cache_key(), 'channel_type': channel.channel_type, - 'id': channel.id, 'memberCount': channel.member_count, - } - info = { 'id': channel.id, 'name': channel.name, 'defaultDisplayMode': channel.default_display_mode, @@ -862,20 +862,19 @@ class Channel(models.Model): 'create_uid': channel.create_uid.id, 'authorizedGroupFullName': channel.group_public_id.full_name, 'allow_public_upload': channel.allow_public_upload, + 'model': "discuss.channel", } - # add last message preview (only used in mobile) - info['last_message_id'] = channel_last_message_ids.get(channel.id, False) # find the channel member state if current_partner or current_guest: info['message_needaction_counter'] = channel.message_needaction_counter member = member_of_current_user_by_channel.get(channel, self.env['discuss.channel.member']).with_prefetch([m.id for m in member_of_current_user_by_channel.values()]) if member: - channel_data['channelMembers'] = [('ADD', list(member._discuss_channel_member_format().values()))] + info['channelMembers'] = [('ADD', list(member._discuss_channel_member_format().values()))] info['state'] = member.fold_state or 'open' - channel_data['message_unread_counter'] = member.message_unread_counter + info['message_unread_counter'] = member.message_unread_counter info['is_minimized'] = member.is_minimized info['seen_message_id'] = member.seen_message_id.id - channel_data['custom_channel_name'] = member.custom_channel_name + info['custom_channel_name'] = member.custom_channel_name info['is_pinned'] = member.is_pinned info['last_interest_dt'] = member.last_interest_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT) if member.rtc_inviting_session_id: @@ -885,7 +884,7 @@ class Channel(models.Model): # avoid sending potentially a lot of members for big channels # exclude chat and other small channels from this optimization because they are # assumed to be smaller and it's important to know the member list for them - channel_data['channelMembers'] = [('ADD', list(members_by_channel[channel]._discuss_channel_member_format().values()))] + info['channelMembers'] = [('ADD', list(members_by_channel[channel]._discuss_channel_member_format().values()))] info['seen_partners_info'] = sorted([{ 'id': cp.id, 'partner_id': cp.partner_id.id, @@ -897,9 +896,6 @@ class Channel(models.Model): 'invitedMembers': [('ADD', list(invited_members_by_channel[channel]._discuss_channel_member_format(fields={'id': True, 'channel': {}, 'persona': {'partner': {'id', 'name', 'im_status'}, 'guest': {'id', 'name', 'im_status'}}}).values()))], 'rtcSessions': [('ADD', rtc_sessions_by_channel.get(channel, []))], }) - - info['channel'] = channel_data - channel_infos.append(info) return channel_infos @@ -925,6 +921,7 @@ class Channel(models.Model): data = {} if 'id' in fields: data['id'] = channel.id + data['model'] = "discuss.channel" channels_formatted_data[channel] = data return channels_formatted_data @@ -1012,13 +1009,11 @@ class Channel(models.Model): vals['is_minimized'] = is_minimized if vals: session_state.write(vals) - self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.record/insert', { - 'Thread': { - 'foldStateCount': state_count, - 'id': session_state.channel_id.id, - 'model': 'discuss.channel', - 'fold_state': state, - } + self.env['bus.bus']._sendone(self.env.user.partner_id, 'discuss.Thread/fold_state', { + 'foldStateCount': state_count, + 'id': session_state.channel_id.id, + 'model': 'discuss.channel', + 'fold_state': state, }) def channel_pin(self, pinned=False): @@ -1030,7 +1025,7 @@ class Channel(models.Model): if not pinned: self.env['bus.bus']._sendone(self.env.user.partner_id, 'discuss.channel/unpin', {'id': self.id}) else: - self.env['bus.bus']._sendone(self.env.user.partner_id, 'discuss.channel/legacy_insert', self._channel_info()[0]) + self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.record/insert', {"Thread": self._channel_info()[0]}) def _channel_seen(self, last_message_id=None, allow_older=False): """ @@ -1119,9 +1114,10 @@ class Channel(models.Model): member = self.env['discuss.channel.member'].search([('partner_id', '=', self.env.user.partner_id.id), ('channel_id', '=', self.id)]) member.write({'custom_channel_name': name}) self.env['bus.bus']._sendone(member.partner_id, 'mail.record/insert', { - 'Channel': { + 'Thread': { 'custom_channel_name': name, 'id': self.id, + 'model': "discuss.channel", } }) @@ -1160,7 +1156,7 @@ class Channel(models.Model): } new_channel.message_post(body=notification, message_type="notification", subtype_xmlid="mail.mt_comment") channel_info = new_channel._channel_info()[0] - self.env['bus.bus']._sendone(self.env.user.partner_id, 'discuss.channel/legacy_insert', channel_info) + self.env['bus.bus']._sendone(self.env.user.partner_id, 'mail.record/insert', {"Thread": channel_info}) return channel_info @api.model @@ -1196,10 +1192,8 @@ class Channel(models.Model): channels = self.search(domain, limit=limit) return [{ 'authorizedGroupFullName': channel.group_public_id.full_name, - 'channel': { - 'channel_type': channel.channel_type, - 'id': channel.id, - }, + 'channel_type': channel.channel_type, + 'model': "discuss.channel", 'id': channel.id, 'name': channel.name, } for channel in channels] diff --git a/addons/mail/models/discuss/discuss_channel_member.py b/addons/mail/models/discuss/discuss_channel_member.py index 78551757553..397499c2de0 100644 --- a/addons/mail/models/discuss/discuss_channel_member.py +++ b/addons/mail/models/discuss/discuss_channel_member.py @@ -152,7 +152,7 @@ class ChannelMember(models.Model): if 'id' in fields: data['id'] = member.id if 'channel' in fields: - data['channel'] = member.channel_id._channel_format(fields=fields.get('channel')).get(member.channel_id) + data['thread'] = member.channel_id._channel_format(fields=fields.get('channel')).get(member.channel_id) if 'persona' in fields: if member.partner_id: persona = member._get_partner_data(fields=fields.get('persona', {}).get('partner')) diff --git a/addons/mail/models/discuss/res_partner.py b/addons/mail/models/discuss/res_partner.py index 7d7aa529ce3..1bd21e10ed0 100644 --- a/addons/mail/models/discuss/res_partner.py +++ b/addons/mail/models/discuss/res_partner.py @@ -108,8 +108,7 @@ class ResPartner(models.Model): } partners_format = partners.mail_partner_format() for partner in partners: - partners_format.get(partner)["persona"] = { - "channelMembers": [ + partners_format.get(partner)["channelMembers"] = [ ( "ADD", member_by_partner.get(partner) @@ -122,6 +121,5 @@ class ResPartner(models.Model): ) .get(member_by_partner.get(partner)), ) - ], - } + ] return list(partners_format.values()) diff --git a/addons/mail/models/mail_link_preview.py b/addons/mail/models/mail_link_preview.py index 77deb7fa933..5aff9473f63 100644 --- a/addons/mail/models/mail_link_preview.py +++ b/addons/mail/models/mail_link_preview.py @@ -91,7 +91,7 @@ class LinkPreview(models.Model): def _link_preview_format(self): return [{ 'id': preview.id, - 'message_id': preview.message_id.id, + 'message': {'id': preview.message_id.id}, 'image_mimetype': preview.image_mimetype, 'og_description': preview.og_description, 'og_image': preview.og_image, diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index 15af41e6d95..186b3fbca0e 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -870,7 +870,7 @@ class Message(models.Model): "personas": personas, "message": {"id": self.id}, } - payload = {"Message": {"id": self.id, "messageReactionGroups": [(group_command, group_values)]}} + payload = {"Message": {"id": self.id, "reactions": [(group_command, group_values)]}} self.env["bus.bus"]._sendone(self._bus_notification_target(), "mail.record/insert", payload) # ------------------------------------------------------ @@ -918,10 +918,10 @@ class Message(models.Model): 'author': author, 'default_subject': default_subject, 'notifications': message_sudo.notification_ids._filtered_for_web_client()._notification_format(), - 'attachment_ids': sorted(message_sudo.attachment_ids._attachment_format(), key=lambda a: a["id"]), + 'attachments': sorted(message_sudo.attachment_ids._attachment_format(), key=lambda a: a["id"]), 'trackingValues': allowed_tracking_ids._tracking_value_format(), 'linkPreviews': message_sudo.link_preview_ids._link_preview_format(), - 'messageReactionGroups': reaction_groups, + 'reactions': reaction_groups, 'pinned_at': message_sudo.pinned_at, 'record_name': record_name, 'create_date': message_sudo.create_date, @@ -976,7 +976,7 @@ class Message(models.Model): 'body': HTML content of the message 'model': u'res.partner', 'record_name': u'Agrolait', - 'attachment_ids': [ + 'attachments': [ { 'file_type_icon': u'webimage', 'id': 45, @@ -1042,7 +1042,7 @@ class Message(models.Model): 'is_note': message_sudo.subtype_id.id == note_id, 'is_discussion': message_sudo.subtype_id.id == com_id, 'subtype_description': message_sudo.subtype_id.description, - 'recipients': [{'id': p.id, 'name': p.name} for p in message_sudo.partner_ids], + 'recipients': [{'id': p.id, 'name': p.name, 'type': "partner"} for p in message_sudo.partner_ids], 'scheduledDatetime': scheduled_dt_by_msg_id.get(vals['id'], False), }) if vals['model'] and self.env[vals['model']]._original_module: diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index c0a3bc396df..48a23bbd4dc 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -4139,9 +4139,9 @@ class MailThread(models.AbstractModel): 'Message': { 'id': message.id, 'body': message.body, - 'attachment_ids': message.attachment_ids.sorted("id")._attachment_format(), + 'attachments': message.attachment_ids.sorted("id")._attachment_format(), 'pinned_at': message.pinned_at, - 'recipients': [{'id': p.id, 'name': p.name} for p in message.partner_ids], + 'recipients': [{'id': p.id, 'name': p.name, 'type': "partner"} for p in message.partner_ids], 'write_date': message.write_date, } }) diff --git a/addons/mail/models/res_users_settings.py b/addons/mail/models/res_users_settings.py index af22b408c8d..7501e992795 100644 --- a/addons/mail/models/res_users_settings.py +++ b/addons/mail/models/res_users_settings.py @@ -26,7 +26,7 @@ class ResUsersSettings(models.Model): def set_res_users_settings(self, new_settings): formated = super().set_res_users_settings(new_settings) - self.env['bus.bus']._sendone(self.user_id.partner_id, 'mail.record/insert', {'res.users.settings': formated}) + self.env['bus.bus']._sendone(self.user_id.partner_id, 'res.users.settings', formated) return formated def set_volume_setting(self, partner_id, volume, guest_id=None): @@ -50,4 +50,4 @@ class ResUsersSettings(models.Model): 'partner_id': partner_id, 'guest_id': guest_id, }) - self.env['bus.bus']._sendone(self.user_id.partner_id, 'mail.record/insert', {'res.users.settings.volumes': volume_setting._discuss_users_settings_volume_format()}) + self.env['bus.bus']._sendone(self.user_id.partner_id, 'res.users.settings.volumes', volume_setting._discuss_users_settings_volume_format()) diff --git a/addons/mail/static/src/core/common/attachment_model.js b/addons/mail/static/src/core/common/attachment_model.js index fbff4c4df68..6869a2fa821 100644 --- a/addons/mail/static/src/core/common/attachment_model.js +++ b/addons/mail/static/src/core/common/attachment_model.js @@ -1,7 +1,7 @@ /* @odoo-module */ import { Record } from "@mail/core/common/record"; -import { assignDefined } from "@mail/utils/common/misc"; +import { onChange } from "@mail/utils/common/misc"; import { deserializeDateTime } from "@web/core/l10n/dates"; import { FileModelMixin } from "@web/core/file_viewer/file_model"; @@ -14,54 +14,30 @@ export class Attachment extends FileModelMixin(Record) { static get(data) { return super.get(data); } - /** - * @param {Object} data - * @returns {import("models").Attachment} - */ + /** @returns {import("models").Attachment} */ static insert(data) { if (!("id" in data)) { throw new Error("Cannot insert attachment: id is missing in data"); } + return super.insert(data); + } + static new(data) { /** @type {import("models").Attachment} */ - const attachment = this.preinsert(data); - attachment.update(data); + const attachment = super.new(data); + onChange(attachment, ["extension", "name"], () => { + if (!attachment.extension && attachment.name) { + attachment.extension = attachment.name.split(".").pop(); + } + }); return attachment; } update(data) { - assignDefined(this, data, [ - "checksum", - "create_date", - "filename", - "mimetype", - "name", - "type", - "url", - "uploading", - "extension", - "accessToken", - "tmpUrl", - "message", - "res_name", - ]); - if (!("extension" in data) && data["name"]) { - this.extension = this.name.split(".").pop(); - } - if (data.originThread !== undefined) { - const threadData = Array.isArray(data.originThread) - ? data.originThread[0][1] - : data.originThread; - this.originThread = { - model: threadData.model, - id: threadData.id, - }; - const thread = this.originThread; - thread.attachments.add(this); - thread.attachments.sort((a1, a2) => (a1.id < a2.id ? 1 : -1)); - } + super.update(data); + this.originThread?.attachments.sort((a1, a2) => (a1.id < a2.id ? 1 : -1)); } - originThread = Record.one("Thread"); + originThread = Record.one("Thread", { inverse: "attachments" }); res_name; message = Record.one("Message"); /** @type {string} */ diff --git a/addons/mail/static/src/core/common/canned_response_model.js b/addons/mail/static/src/core/common/canned_response_model.js index 43848aa5abf..d95f333d153 100644 --- a/addons/mail/static/src/core/common/canned_response_model.js +++ b/addons/mail/static/src/core/common/canned_response_model.js @@ -10,24 +10,15 @@ export class CannedResponse extends Record { static get(data) { return super.get(data); } - /** - * @param {Object} data - * @returns {import("models").CannedResponse} - */ + /** @returns {import("models").CannedResponse} */ static insert(data) { - /** @type {import("models").CannedResponse} */ - const cannedResponse = this.preinsert(data); - Object.assign(cannedResponse, { - name: data.source, - substitution: data.substitution, - }); - return cannedResponse; + return super.insert(data); } /** @type {number} */ id; /** @type {string} */ - name; + source; /** @type {string} */ substitution; } diff --git a/addons/mail/static/src/core/common/channel_member_model.js b/addons/mail/static/src/core/common/channel_member_model.js index b6838960516..3266988be77 100644 --- a/addons/mail/static/src/core/common/channel_member_model.js +++ b/addons/mail/static/src/core/common/channel_member_model.js @@ -17,35 +17,14 @@ export class ChannelMember extends Record { static get(data) { return super.get(data); } - /** - * @param {Object|Array} data - * @returns {import("models").ChannelMember} - */ + /** @returns {import("models").ChannelMember} */ static insert(data) { - /** @type {import("models").ChannelMember} */ - const member = this.preinsert(data); - member.update(data); - return member; - } - - update(data) { - this.id = data.id; - if ("persona" in data) { - this.persona = data.persona; - } - let thread = data.thread ?? this.thread; - if (!thread && data.channel?.id) { - thread = { - id: data.channel.id, - model: "discuss.channel", - }; - } - this.thread ??= thread; + return super.insert(data); } /** @type {number} */ id; - persona = Record.one("Persona"); + persona = Record.one("Persona", { inverse: "channelMembers" }); rtcSession = Record.one("RtcSession"); thread = Record.one("Thread"); diff --git a/addons/mail/static/src/core/common/composer.js b/addons/mail/static/src/core/common/composer.js index 2344c752bd4..91d68d0e075 100644 --- a/addons/mail/static/src/core/common/composer.js +++ b/addons/mail/static/src/core/common/composer.js @@ -315,7 +315,7 @@ export class Composer extends Component { options: suggestions.map((suggestion) => { return { cannedResponse: suggestion, - name: suggestion.name, + source: suggestion.source, label: suggestion.substitution, classList: "o-mail-Composer-suggestion", }; diff --git a/addons/mail/static/src/core/common/composer.xml b/addons/mail/static/src/core/common/composer.xml index 4c79bf2a0dc..d1560c8050e 100644 --- a/addons/mail/static/src/core/common/composer.xml +++ b/addons/mail/static/src/core/common/composer.xml @@ -140,7 +140,7 @@ - + diff --git a/addons/mail/static/src/core/common/composer_model.js b/addons/mail/static/src/core/common/composer_model.js index a18661b9e98..5ce1d07524f 100644 --- a/addons/mail/static/src/core/common/composer_model.js +++ b/addons/mail/static/src/core/common/composer_model.js @@ -8,27 +8,13 @@ export class Composer extends Record { static get(data) { return super.get(data); } - /** - * @param {Object} data - * @returns {import("models").Composer} - */ + /** @returns {import("models").Composer} */ static insert(data) { const { message, thread } = data; if (Boolean(message) === Boolean(thread)) { throw new Error("Composer shall have a thread xor a message."); } - /** @type {import("models").Composer} */ - const composer = this.preinsert(data); - if ("textInputContent" in data) { - composer.textInputContent = data.textInputContent; - } - if ("selection" in data) { - composer.selection = data.selection; - } - if ("mentionedPartners" in data) { - composer.mentionedPartners = data.mentionedPartners; - } - return composer; + return super.insert(data); } attachments = Record.many("Attachment"); diff --git a/addons/mail/static/src/core/common/discuss.xml b/addons/mail/static/src/core/common/discuss.xml index 16ad3ecd1a6..51c7720c670 100644 --- a/addons/mail/static/src/core/common/discuss.xml +++ b/addons/mail/static/src/core/common/discuss.xml @@ -63,7 +63,7 @@
- +
diff --git a/addons/mail/static/src/core/common/discuss_app_category_model.js b/addons/mail/static/src/core/common/discuss_app_category_model.js index 0ec6ca23532..8bc371d38c4 100644 --- a/addons/mail/static/src/core/common/discuss_app_category_model.js +++ b/addons/mail/static/src/core/common/discuss_app_category_model.js @@ -1,6 +1,5 @@ /* @odoo-module */ -import { assignDefined } from "@mail/utils/common/misc"; import { Record } from "./record"; export class DiscussAppCategory extends Record { @@ -11,10 +10,7 @@ export class DiscussAppCategory extends Record { } /** @returns {import("models").DiscussAppCategory} */ static insert(data) { - /** @type {import("models").DiscussAppCategory} */ - const category = this.preinsert(data); - assignDefined(category, data); - return category; + return super.insert(data); } /** @type {string} */ diff --git a/addons/mail/static/src/core/common/follower_model.js b/addons/mail/static/src/core/common/follower_model.js index 9c4aad8831c..284f64cdea0 100644 --- a/addons/mail/static/src/core/common/follower_model.js +++ b/addons/mail/static/src/core/common/follower_model.js @@ -12,10 +12,7 @@ export class Follower extends Record { } /** @returns {import("models").Follower} */ static insert(data) { - /** @type {import("models").Follower} */ - const follower = this.preinsert(data); - Object.assign(follower, data); - return follower; + return super.insert(data); } followedThread = Record.one("Thread"); diff --git a/addons/mail/static/src/core/common/link_preview_model.js b/addons/mail/static/src/core/common/link_preview_model.js index 801e7e95c3a..f8576e8b905 100644 --- a/addons/mail/static/src/core/common/link_preview_model.js +++ b/addons/mail/static/src/core/common/link_preview_model.js @@ -8,24 +8,14 @@ export class LinkPreview extends Record { static get(data) { return super.get(data); } - /** - * @param {Object} data - * @returns {import("models").LinkPreview} - */ + /** @returns {import("models").LinkPreview} */ static insert(data) { - const message = this.store.Message.get(data.message_id); - data.message = message; - delete data.message_id; - /** @type {import("models").LinkPreview} */ - const linkPreview = this.preinsert(data); - Object.assign(linkPreview, data); - message?.linkPreviews.add(linkPreview); - return linkPreview; + return super.insert(data); } /** @type {number} */ id; - message = Record.one("Message"); + message = Record.one("Message", { inverse: "linkPreviews" }); /** @type {string} */ image_mimetype; /** @type {string} */ @@ -58,7 +48,6 @@ export class LinkPreview extends Record { get isCard() { return !this.isImage && !this.isVideo; } - } LinkPreview.register(); diff --git a/addons/mail/static/src/core/common/mail_core_common_service.js b/addons/mail/static/src/core/common/mail_core_common_service.js index d77488dadfe..d0afd78c5cf 100644 --- a/addons/mail/static/src/core/common/mail_core_common_service.js +++ b/addons/mail/static/src/core/common/mail_core_common_service.js @@ -49,8 +49,8 @@ export class MailCoreCommon { if (!message) { continue; } - message.delete(); this.env.bus.trigger("mail.message/delete", { message }); + message.delete(); } }); this.busService.subscribe("mail.message/notification_update", (payload) => { @@ -69,7 +69,20 @@ export class MailCoreCommon { const { message_ids: messageIds, starred } = payload; for (const messageId of messageIds) { const message = this.store.Message.insert({ id: messageId }); - this.messageService.updateStarred(message, starred); + message.isStarred = starred; + const starredBox = this.store.discuss.starred; + if (starred) { + starredBox.counter++; + starredBox.messages.add(message); + } else { + starredBox.counter--; + starredBox.messages.delete(message); + } + } + }); + this.busService.subscribe("res.users.settings", (payload) => { + if (payload) { + this.userSettingsService.updateFromCommands(payload); } }); this.busService.subscribe("mail.record/insert", (payload) => { @@ -100,18 +113,10 @@ export class MailCoreCommon { } const { Message: messageData } = payload; if (messageData) { - const isStarred = this.store.Message.get(messageData.id)?.isStarred; - const message = this.store.Message.insert({ + this.store.Message.insert({ ...messageData, body: messageData.body ? markup(messageData.body) : messageData.body, }); - if (isStarred && message.isEmpty) { - this.messageService.updateStarred(message, false); - } - } - const { "res.users.settings": settings } = payload; - if (settings) { - this.userSettingsService.updateFromCommands(settings); } }); }); diff --git a/addons/mail/static/src/core/common/message.js b/addons/mail/static/src/core/common/message.js index d16b1302178..efa8b278451 100644 --- a/addons/mail/static/src/core/common/message.js +++ b/addons/mail/static/src/core/common/message.js @@ -239,8 +239,8 @@ export class Message extends Component { get showSubtypeDescription() { return ( - this.message.subtypeDescription && - this.message.subtypeDescription.toLowerCase() !== + this.message.subtype_description && + this.message.subtype_description.toLowerCase() !== htmlToTextContentInline(this.message.body || "").toLowerCase() ); } @@ -252,7 +252,7 @@ export class Message extends Component { if (this.props.message.type === "auto_comment") { return _t("Automated message"); } - if (!this.props.message.isDiscussion && this.props.message.type !== "user_notification") { + if (!this.props.message.is_discussion && this.props.message.type !== "user_notification") { return _t("Note"); } return _t("Message"); @@ -262,7 +262,7 @@ export class Message extends Component { * @returns {boolean} */ get canAddReaction() { - return Boolean(!this.message.isTransient && this.message.resId); + return Boolean(!this.message.is_transient && this.message.res_id); } get deletable() { @@ -284,7 +284,7 @@ export class Message extends Component { * @returns {boolean} */ get canToggleStar() { - return Boolean(!this.message.isTransient && this.message.resId && this.store.user); + return Boolean(!this.message.is_transient && this.message.res_id && this.store.user); } get showUnfollow() { @@ -440,7 +440,6 @@ export class Message extends Component { const messageContent = convertBrToLineBreak(this.props.message.body); this.props.message.composer = { mentionedPartners: this.props.message.recipients, - message: this.props.message, textInputContent: messageContent, selection: { start: messageContent.length, diff --git a/addons/mail/static/src/core/common/message.xml b/addons/mail/static/src/core/common/message.xml index 0b78e640906..666aa820395 100644 --- a/addons/mail/static/src/core/common/message.xml +++ b/addons/mail/static/src/core/common/message.xml @@ -18,7 +18,7 @@
- + @@ -36,7 +36,7 @@ - + - @@ -45,11 +45,11 @@ className="'ms-1'" message="props.message" thread="props.thread"/> - - + + on - + (from ) @@ -72,20 +72,20 @@ >
- +
@@ -95,7 +95,7 @@
- +
diff --git a/addons/mail/static/src/core/common/message_model.js b/addons/mail/static/src/core/common/message_model.js index 89bef68e4d1..cf87ad9dea1 100644 --- a/addons/mail/static/src/core/common/message_model.js +++ b/addons/mail/static/src/core/common/message_model.js @@ -2,7 +2,7 @@ import { Record } from "@mail/core/common/record"; import { htmlToTextContentInline } from "@mail/utils/common/format"; -import { assignDefined } from "@mail/utils/common/misc"; +import { assignDefined, assignIn, onChange } from "@mail/utils/common/misc"; import { toRaw } from "@odoo/owl"; @@ -17,14 +17,23 @@ export class Message extends Record { static id = "id"; /** @type {Object.} */ static records = {}; + static new(data) { + const message = super.new(data); + onChange(message, "isEmpty", () => { + if (message.isEmpty && message.isStarred) { + message.isStarred = false; + const starred = this.store.discuss.starred; + starred.counter--; + starred.messages.delete(message); + } + }); + return message; + } /** @returns {import("models").Message} */ static get(data) { return super.get(data); } - /** - * @param {Object} data - * @returns {import("models").Message} - */ + /** @returns {import("models").Message} */ static insert(data) { if (data.res_id) { this.store.Thread.insert({ @@ -32,46 +41,23 @@ export class Message extends Record { id: data.res_id, }); } - /** @type {import("models").Message} */ - const message = this.preinsert(data); - message.update(data); - return message; + return super.insert(data); } /** @param {Object} data */ update(data) { const { - attachment_ids: attachments = this.attachments, - default_subject: defaultSubject = this.defaultSubject, - is_discussion: isDiscussion = this.isDiscussion, - is_note: isNote = this.isNote, - is_transient: isTransient = this.isTransient, - linkPreviews = this.linkPreviews, message_type: type = this.type, - model: resModel = this.resModel, module_icon, - notifications = this.notifications, - parentMessage, - recipients = this.recipients, record_name, - res_id: resId = this.resId, res_model_name, - subtype_description: subtypeDescription = this.subtypeDescription, ...remainingData } = data; assignDefined(this, remainingData); assignDefined(this, { - defaultSubject, - isDiscussion, - isNote, isStarred: this._store.user ? this.starred_partner_ids.includes(this._store.user.id) : false, - isTransient, - parentMessage: parentMessage || undefined, - resId, - resModel, - subtypeDescription, type, }); // origin thread before other information (in particular notification insert uses it) @@ -85,13 +71,7 @@ export class Message extends Record { : record_name || undefined, }); } - this.attachments = attachments.map((attachment) => ({ message: this, ...attachment })); - if ("author" in data) { - this.author = data.author; - } - this.linkPreviews = linkPreviews.map((data) => ({ ...data, message: this })); - this.notifications = notifications.map((notif) => ({ ...notif, message: this })); - this.recipients = recipients.map((recipient) => ({ ...recipient, type: "partner" })); + assignIn(this, data, ["author", "notifications", "reactions", "recipients"]); if ("user_follower_id" in data && data.user_follower_id && this._store.self) { this.originThread.selfFollower = { followedThread: this.originThread, @@ -100,9 +80,6 @@ export class Message extends Record { partner: this._store.self, }; } - if ("messageReactionGroups" in data) { - this.reactions = data.messageReactionGroups; - } if (this.isNotification && !this.notificationType) { const parser = new DOMParser(); const htmlBody = parser.parseFromString(this.body, "text/html"); @@ -110,36 +87,36 @@ export class Message extends Record { } } - attachments = Record.many("Attachment"); + attachments = Record.many("Attachment", { inverse: "message" }); author = Record.one("Persona"); /** @type {string} */ body; - composer = Record.one("Composer", { onDelete: (r) => r.delete() }); + composer = Record.one("Composer", { inverse: "message", onDelete: (r) => r.delete() }); /** @type {string} */ - defaultSubject; + default_subject; /** @type {number|string} */ id; /** @type {boolean} */ - isDiscussion; + is_discussion; /** @type {boolean} */ - isNote; + is_note; /** @type {boolean} */ isStarred; /** @type {boolean} */ - isTransient; - linkPreviews = Record.many("LinkPreview"); + is_transient; + linkPreviews = Record.many("LinkPreview", { inverse: "message" }); /** @type {number[]} */ needaction_partner_ids = []; /** @type {number[]} */ history_partner_ids = []; parentMessage = Record.one("Message"); - reactions = Record.many("MessageReactions"); - notifications = Record.many("Notification"); + reactions = Record.many("MessageReactions", { inverse: "message" }); + notifications = Record.many("Notification", { inverse: "message" }); recipients = Record.many("Persona"); /** @type {number|string} */ - resId; + res_id; /** @type {string|undefined} */ - resModel; + model; /** @type {string} */ scheduledDatetime; /** @type {Number[]} */ @@ -147,7 +124,7 @@ export class Message extends Record { /** @type {string} */ subject; /** @type {string} */ - subtypeDescription; + subtype_description; /** @type {Object[]} */ trackingValues = []; /** @type {string} */ @@ -207,7 +184,7 @@ export class Message extends Record { } get isHighlightedFromMention() { - return this.isSelfMentioned && this.resModel === "discuss.channel"; + return this.isSelfMentioned && this.model === "discuss.channel"; } get isSelfAuthored() { @@ -222,7 +199,7 @@ export class Message extends Record { } get hasActions() { - return !this.isTransient; + return !this.is_transient; } /** @@ -236,7 +213,7 @@ export class Message extends Record { * @returns {boolean} */ get isNotification() { - return this.type === "notification" && this.resModel === "discuss.channel"; + return this.type === "notification" && this.model === "discuss.channel"; } get isSubjectSimilarToOriginThreadName() { @@ -251,17 +228,17 @@ export class Message extends Record { get isSubjectDefault() { const threadName = this.originThread?.name?.trim().toLowerCase(); - const defaultSubject = this.defaultSubject ? this.defaultSubject.toLowerCase() : ""; + const defaultSubject = this.default_subject ? this.default_subject.toLowerCase() : ""; const candidates = new Set([defaultSubject, threadName]); return candidates.has(this.subject?.toLowerCase()); } get originThread() { - return this._store.Thread.get({ model: this.resModel, id: this.resId }); + return this._store.Thread.get({ model: this.model, id: this.res_id }); } get resUrl() { - return `${url("/web")}#model=${this.resModel}&id=${this.resId}`; + return `${url("/web")}#model=${this.model}&id=${this.res_id}`; } get editDate() { @@ -277,7 +254,7 @@ export class Message extends Record { this.isBodyEmpty && this.attachments.length === 0 && this.trackingValues.length === 0 && - !this.subtypeDescription + !this.subtype_description ); } get isBodyEmpty() { diff --git a/addons/mail/static/src/core/common/message_reactions.xml b/addons/mail/static/src/core/common/message_reactions.xml index 786c1930fe6..9d671fc684a 100644 --- a/addons/mail/static/src/core/common/message_reactions.xml +++ b/addons/mail/static/src/core/common/message_reactions.xml @@ -4,9 +4,9 @@
+ t-attf-class="{{ props.message.is_discussion ? 'mt-n2' : 'mt-1' }}">