From 241fa6c2b3c626e2f459e194ab910f4be7130e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20K=C3=BChn?= Date: Mon, 25 Apr 2022 09:45:08 +0000 Subject: [PATCH] [IMP] mail, *: introduce view models (step 4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit *: sms, snailmail, test_mail This commit introduces models that define records being 1:1 map with components, as a step to move further to having essentially all business code in models. Having code in models is desirable to have very maintainable code, thanks to robust and declarative code with an ORM-like architecture. Task-2831082 closes odoo/odoo#90320 Signed-off-by: Alexandre KΓΌhn (aku) --- .../channel_invitation_form.scss | 13 ---- .../channel_invitation_form.xml | 24 +----- ...nnel_invitation_form_selectable_partner.js | 33 +++++++++ ...el_invitation_form_selectable_partner.scss | 14 ++++ ...nel_invitation_form_selectable_partner.xml | 26 +++++++ ...hannel_invitation_form_selected_partner.js | 33 +++++++++ ...annel_invitation_form_selected_partner.xml | 10 +++ .../chat_window_hidden_menu.scss | 8 -- .../chat_window_hidden_menu.xml | 9 +-- .../chat_window_hidden_menu_item.js | 31 ++++++++ .../chat_window_hidden_menu_item.scss | 15 ++++ .../chat_window_hidden_menu_item.xml | 15 ++++ .../mail/static/src/components/emoji/emoji.js | 26 +++++++ .../static/src/components/emoji/emoji.scss | 16 ++++ .../static/src/components/emoji/emoji.xml | 10 +++ .../src/components/emoji_list/emoji_list.scss | 12 --- .../src/components/emoji_list/emoji_list.xml | 4 +- .../src/components/message/message.scss | 6 -- .../static/src/components/message/message.xml | 21 +----- .../message_in_reply_to_view.js | 4 +- .../message_notification_popover_content.js | 23 ++++++ .../message_notification_popover_content.xml | 21 ++++++ .../messaging_menu/messaging_menu.js | 73 +------------------ .../messaging_menu/messaging_menu.xml | 4 +- .../notification_group/notification_group.js | 9 --- .../notification_group/notification_group.xml | 2 +- .../notification_list/notification_list.js | 30 +------- .../notification_popover.js | 23 ------ .../notification_popover.xml | 21 ------ .../tracking_value/tracking_value.js | 14 ++++ .../tracking_value/tracking_value.scss | 6 ++ .../tracking_value/tracking_value.xml | 21 ++++++ .../mail/static/src/models/messaging_menu.js | 60 +++++++++++++++ .../src/models/notification_group_view.js | 14 ++++ .../src/models/notification_list_view.js | 16 ++++ addons/mail/static/src/models/thread.js | 2 +- .../mail/static/tests/helpers/mock_server.js | 1 + .../channel_invitation_form_tests.js | 4 +- .../components/chat_window_manager_tests.js | 4 +- .../components/composer_tests.js | 14 ++-- .../components/discuss_inbox_tests.js | 2 +- .../components/discuss_tests.js | 32 ++++++++ .../components/message_tests.js | 10 +-- .../components/thread_view_tests.js | 10 +-- addons/sms/__manifest__.py | 1 - .../notification_group/notification_group.js | 22 ------ .../src/models/notification_group_view.js | 17 +++++ .../components/message_tests.js | 10 +-- .../static/src/components/message/message.xml | 2 +- .../notification_group/notification_group.js | 22 ------ .../src/models/notification_group_view.js | 17 +++++ .../static/tests/tracking_value_tests.js | 56 +++++++------- 52 files changed, 542 insertions(+), 351 deletions(-) create mode 100644 addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.js create mode 100644 addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.scss create mode 100644 addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.xml create mode 100644 addons/mail/static/src/components/channel_invitation_form_selected_partner/channel_invitation_form_selected_partner.js create mode 100644 addons/mail/static/src/components/channel_invitation_form_selected_partner/channel_invitation_form_selected_partner.xml create mode 100644 addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.js create mode 100644 addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.scss create mode 100644 addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.xml create mode 100644 addons/mail/static/src/components/emoji/emoji.js create mode 100644 addons/mail/static/src/components/emoji/emoji.scss create mode 100644 addons/mail/static/src/components/emoji/emoji.xml create mode 100644 addons/mail/static/src/components/message_notification_popover_content/message_notification_popover_content.js create mode 100644 addons/mail/static/src/components/message_notification_popover_content/message_notification_popover_content.xml delete mode 100644 addons/mail/static/src/components/notification_popover/notification_popover.js delete mode 100644 addons/mail/static/src/components/notification_popover/notification_popover.xml create mode 100644 addons/mail/static/src/components/tracking_value/tracking_value.js create mode 100644 addons/mail/static/src/components/tracking_value/tracking_value.scss create mode 100644 addons/mail/static/src/components/tracking_value/tracking_value.xml delete mode 100644 addons/sms/static/src/components/notification_group/notification_group.js create mode 100644 addons/sms/static/src/models/notification_group_view.js delete mode 100644 addons/snailmail/static/src/components/notification_group/notification_group.js create mode 100644 addons/snailmail/static/src/models/notification_group_view.js diff --git a/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.scss b/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.scss index 01ef9ffddba..44eebe24758 100644 --- a/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.scss +++ b/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.scss @@ -2,19 +2,6 @@ // Layout // ------------------------------------------------------------------ -.o_ChannelInvitationForm_selectablePartnerAvatarContainer { - width: 32px; - height: 32px; -} - -.o_ChannelInvitationForm_selectablePartnerAvatar { - object-fit: cover; -} - -.o_ChannelInvitationForm_selectablePartnerName { - min-width: 0; -} - .o_ChannelInvitationForm_selectedPartners { max-height: 100px; } diff --git a/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.xml b/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.xml index 029fceb2fa9..c1cf302eb2c 100644 --- a/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.xml +++ b/addons/mail/static/src/components/channel_invitation_form/channel_invitation_form.xml @@ -11,25 +11,7 @@
-
-
- Avatar - - - -
- - - - -
+
No user found that is not already a member of this channel.
@@ -45,9 +27,7 @@

Selected users:

- +
diff --git a/addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.js b/addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.js new file mode 100644 index 00000000000..f894307dfb2 --- /dev/null +++ b/addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.js @@ -0,0 +1,33 @@ +/** @odoo-module **/ + +import { registerMessagingComponent } from '@mail/utils/messaging_component'; + +const { Component } = owl; + +export class ChannelInvitationFormSelectablePartner extends Component { + + /** + * @returns {ChannelInvitationForm} + */ + get channelInvitationForm() { + return this.messaging && this.messaging.models['ChannelInvitationForm'].get(this.props.channelInvitationFormLocalId); + } + + /** + * @returns {Partner} + */ + get selectablePartner() { + return this.messaging && this.messaging.models['Partner'].get(this.props.selectablePartnerLocalId); + } + +} + +Object.assign(ChannelInvitationFormSelectablePartner, { + props: { + channelInvitationFormLocalId: String, + selectablePartnerLocalId: String, + }, + template: 'mail.ChannelInvitationFormSelectablePartner', +}); + +registerMessagingComponent(ChannelInvitationFormSelectablePartner); diff --git a/addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.scss b/addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.scss new file mode 100644 index 00000000000..3815027807c --- /dev/null +++ b/addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.scss @@ -0,0 +1,14 @@ + +.o_ChannelInvitationFormSelectablePartner_avatar { + object-fit: cover; +} + +.o_ChannelInvitationFormSelectablePartner_avatarContainer { + width: 32px; + height: 32px; +} + +.o_ChannelInvitationForm_selectablePartnerName { + min-width: 0; +} + diff --git a/addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.xml b/addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.xml new file mode 100644 index 00000000000..15f0b2178bb --- /dev/null +++ b/addons/mail/static/src/components/channel_invitation_form_selectable_partner/channel_invitation_form_selectable_partner.xml @@ -0,0 +1,26 @@ + + + + +
+
+ Avatar + + + +
+ + + + +
+
+ +
diff --git a/addons/mail/static/src/components/channel_invitation_form_selected_partner/channel_invitation_form_selected_partner.js b/addons/mail/static/src/components/channel_invitation_form_selected_partner/channel_invitation_form_selected_partner.js new file mode 100644 index 00000000000..7764aafbb70 --- /dev/null +++ b/addons/mail/static/src/components/channel_invitation_form_selected_partner/channel_invitation_form_selected_partner.js @@ -0,0 +1,33 @@ +/** @odoo-module **/ + +import { registerMessagingComponent } from '@mail/utils/messaging_component'; + +const { Component } = owl; + +export class ChannelInvitationFormSelectedPartner extends Component { + + /** + * @returns {ChannelInvitationForm} + */ + get channelInvitationForm() { + return this.messaging && this.messaging.models['ChannelInvitationForm'].get(this.props.channelInvitationFormLocalId); + } + + /** + * @returns {Partner} + */ + get selectedPartner() { + return this.messaging && this.messaging.models['Partner'].get(this.props.selectedPartnerLocalId); + } + +} + +Object.assign(ChannelInvitationFormSelectedPartner, { + props: { + channelInvitationFormLocalId: String, + selectedPartnerLocalId: String, + }, + template: 'mail.ChannelInvitationFormSelectedPartner', +}); + +registerMessagingComponent(ChannelInvitationFormSelectedPartner); diff --git a/addons/mail/static/src/components/channel_invitation_form_selected_partner/channel_invitation_form_selected_partner.xml b/addons/mail/static/src/components/channel_invitation_form_selected_partner/channel_invitation_form_selected_partner.xml new file mode 100644 index 00000000000..22ef03e11aa --- /dev/null +++ b/addons/mail/static/src/components/channel_invitation_form_selected_partner/channel_invitation_form_selected_partner.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/addons/mail/static/src/components/chat_window_hidden_menu/chat_window_hidden_menu.scss b/addons/mail/static/src/components/chat_window_hidden_menu/chat_window_hidden_menu.scss index b2dedd87f9d..f3451c5cd73 100644 --- a/addons/mail/static/src/components/chat_window_hidden_menu/chat_window_hidden_menu.scss +++ b/addons/mail/static/src/components/chat_window_hidden_menu/chat_window_hidden_menu.scss @@ -6,10 +6,6 @@ z-index: $zindex-dropdown; } -.o_ChatWindowHiddenMenu_chatWindowHeader { - max-width: 200px; -} - .o_ChatWindowHiddenMenu_unreadCounter { transform: translate(50%, -50%); z-index: $zindex-tooltip; // on top of bootstrap dropup menu @@ -19,10 +15,6 @@ // Style // ------------------------------------------------------------------ -.o_ChatWindowHiddenMenu_chatWindowHeader { - opacity: 0.95; -} - .o_ChatWindowHiddenMenu_windowCounter { user-select: none; } diff --git a/addons/mail/static/src/components/chat_window_hidden_menu/chat_window_hidden_menu.xml b/addons/mail/static/src/components/chat_window_hidden_menu/chat_window_hidden_menu.xml index 38fcd0115d4..cad74f4b9aa 100644 --- a/addons/mail/static/src/components/chat_window_hidden_menu/chat_window_hidden_menu.xml +++ b/addons/mail/static/src/components/chat_window_hidden_menu/chat_window_hidden_menu.xml @@ -11,14 +11,7 @@ diff --git a/addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.js b/addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.js new file mode 100644 index 00000000000..a8ac8d809ab --- /dev/null +++ b/addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.js @@ -0,0 +1,31 @@ +/** @odoo-module **/ + +import { registerMessagingComponent } from '@mail/utils/messaging_component'; + +const { Component } = owl; + +export class ChatWindowHiddenMenuItem extends Component { + + /** + * @returns {ChatWindowHeaderView} + */ + get chatWindowHeaderView() { + return this.messaging && this.messaging.models['ChatWindowHeaderView'].get(this.props.chatWindowHeaderViewLocalId); + } +} + +Object.assign(ChatWindowHiddenMenuItem, { + defaultProps: { + isLast: false, + }, + props: { + chatWindowHeaderViewLocalId: String, + isLast: { + type: Boolean, + optional: true, + }, + }, + template: 'mail.ChatWindowHiddenMenuItem', +}); + +registerMessagingComponent(ChatWindowHiddenMenuItem); diff --git a/addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.scss b/addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.scss new file mode 100644 index 00000000000..dd085d50fb9 --- /dev/null +++ b/addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.scss @@ -0,0 +1,15 @@ +// ------------------------------------------------------------------ +// Layout +// ------------------------------------------------------------------ + +.o_ChatWindowHiddenMenu_chatWindowHeader { + max-width: 200px; +} + +// ------------------------------------------------------------------ +// Style +// ------------------------------------------------------------------ + +.o_ChatWindowHiddenMenu_chatWindowHeader { + opacity: 0.95; +} \ No newline at end of file diff --git a/addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.xml b/addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.xml new file mode 100644 index 00000000000..a4b40634498 --- /dev/null +++ b/addons/mail/static/src/components/chat_window_hidden_menu_item/chat_window_hidden_menu_item.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/addons/mail/static/src/components/emoji/emoji.js b/addons/mail/static/src/components/emoji/emoji.js new file mode 100644 index 00000000000..93206cd4879 --- /dev/null +++ b/addons/mail/static/src/components/emoji/emoji.js @@ -0,0 +1,26 @@ +/** @odoo-module **/ + +import { registerMessagingComponent } from '@mail/utils/messaging_component'; + +const { Component } = owl; + +export class Emoji extends Component { + + /** + * @returns {EmojiListView} + */ + get emojiListView() { + return this.messaging && this.messaging.models['EmojiListView'].get(this.props.emojiListViewLocalId); + } + +} + +Object.assign(Emoji, { + props: { + emoji: Object, + emojiListViewLocalId: String, + }, + template: 'mail.Emoji', +}); + +registerMessagingComponent(Emoji); diff --git a/addons/mail/static/src/components/emoji/emoji.scss b/addons/mail/static/src/components/emoji/emoji.scss new file mode 100644 index 00000000000..7d7856b7c80 --- /dev/null +++ b/addons/mail/static/src/components/emoji/emoji.scss @@ -0,0 +1,16 @@ +// ------------------------------------------------------------------ +// Layout +// ------------------------------------------------------------------ + +.o_Emoji { + font-size: 1.1em; + margin: map-get($spacers, 1); +} + +// ------------------------------------------------------------------ +// Style +// ------------------------------------------------------------------ + +.o_Emoji { + cursor: pointer; +} \ No newline at end of file diff --git a/addons/mail/static/src/components/emoji/emoji.xml b/addons/mail/static/src/components/emoji/emoji.xml new file mode 100644 index 00000000000..8767f84298b --- /dev/null +++ b/addons/mail/static/src/components/emoji/emoji.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/addons/mail/static/src/components/emoji_list/emoji_list.scss b/addons/mail/static/src/components/emoji_list/emoji_list.scss index 7dbe2b3ed29..ca0ba5af4e4 100644 --- a/addons/mail/static/src/components/emoji_list/emoji_list.scss +++ b/addons/mail/static/src/components/emoji_list/emoji_list.scss @@ -8,15 +8,3 @@ max-width: 200px; } -.o_EmojiList_emoji { - font-size: 1.1em; - margin: map-get($spacers, 1); -} - -// ------------------------------------------------------------------ -// Style -// ------------------------------------------------------------------ - -.o_EmojiList_emoji { - cursor: pointer; -} diff --git a/addons/mail/static/src/components/emoji_list/emoji_list.xml b/addons/mail/static/src/components/emoji_list/emoji_list.xml index 0d73262d361..1c3ec550593 100644 --- a/addons/mail/static/src/components/emoji_list/emoji_list.xml +++ b/addons/mail/static/src/components/emoji_list/emoji_list.xml @@ -5,9 +5,7 @@
- - - +
diff --git a/addons/mail/static/src/components/message/message.scss b/addons/mail/static/src/components/message/message.scss index 98ca0c030b6..3852efcbf01 100644 --- a/addons/mail/static/src/components/message/message.scss +++ b/addons/mail/static/src/components/message/message.scss @@ -95,12 +95,6 @@ max-width: $o-mail-message-sidebar-width; } -.o_Message_trackingValueItem { - // Could be replaced by "me-1" after the migration to BS5 - // for the backend AND the frontend - margin-inline-end: map-get($spacers, 1); -} - // ------------------------------------------------------------------ // Style // ------------------------------------------------------------------ diff --git a/addons/mail/static/src/components/message/message.xml b/addons/mail/static/src/components/message/message.xml index b1bd9c4fc63..85ce8bc9847 100644 --- a/addons/mail/static/src/components/message/message.xml +++ b/addons/mail/static/src/components/message/message.xml @@ -25,7 +25,7 @@ }" t-attf-class="{{ messageView.extraClass }} {{ className }}" t-on-click="messageView.onClick" t-on-mouseenter="messageView.onMouseenter" t-on-mouseleave="messageView.onMouseleave" t-att-data-message-local-id="messageView.message.localId" t-ref="root" > - +
@@ -122,9 +122,7 @@ - +
@@ -150,20 +148,7 @@
    -
  • -
    -
    - -
    - - None -
  • +
diff --git a/addons/mail/static/src/components/message_in_reply_to_view/message_in_reply_to_view.js b/addons/mail/static/src/components/message_in_reply_to_view/message_in_reply_to_view.js index 43ae85f72c6..4293ee3cb60 100644 --- a/addons/mail/static/src/components/message_in_reply_to_view/message_in_reply_to_view.js +++ b/addons/mail/static/src/components/message_in_reply_to_view/message_in_reply_to_view.js @@ -10,12 +10,12 @@ export class MessageInReplyToView extends Component { * @returns {MessageInReplyToView} */ get messageInReplyToView() { - return this.messaging && this.messaging.models['MessageInReplyToView'].get(this.props.messageInReplyToViewLocalId); + return this.messaging && this.messaging.models['MessageInReplyToView'].get(this.props.localId); } } Object.assign(MessageInReplyToView, { - props: { messageInReplyToViewLocalId: String }, + props: { localId: String }, template: "mail.MessageInReplyToView", }); diff --git a/addons/mail/static/src/components/message_notification_popover_content/message_notification_popover_content.js b/addons/mail/static/src/components/message_notification_popover_content/message_notification_popover_content.js new file mode 100644 index 00000000000..fd99280d29a --- /dev/null +++ b/addons/mail/static/src/components/message_notification_popover_content/message_notification_popover_content.js @@ -0,0 +1,23 @@ +/** @odoo-module **/ + +import { registerMessagingComponent } from '@mail/utils/messaging_component'; + +const { Component } = owl; + +export class MessageNotificationPopoverContent extends Component { + + /** + * @returns {MessageView} + */ + get messageView() { + return this.messaging && this.messaging.models['MessageView'].get(this.props.localId); + } + +} + +Object.assign(MessageNotificationPopoverContent, { + props: { localId: String }, + template: 'mail.MessageNotificationPopoverContent', +}); + +registerMessagingComponent(MessageNotificationPopoverContent); diff --git a/addons/mail/static/src/components/message_notification_popover_content/message_notification_popover_content.xml b/addons/mail/static/src/components/message_notification_popover_content/message_notification_popover_content.xml new file mode 100644 index 00000000000..b78159df5c7 --- /dev/null +++ b/addons/mail/static/src/components/message_notification_popover_content/message_notification_popover_content.xml @@ -0,0 +1,21 @@ + + + + + +
+ + +
+ + + + +
+
+
+
+
+
+ +
diff --git a/addons/mail/static/src/components/messaging_menu/messaging_menu.js b/addons/mail/static/src/components/messaging_menu/messaging_menu.js index fe31f84be86..955737026cf 100644 --- a/addons/mail/static/src/components/messaging_menu/messaging_menu.js +++ b/addons/mail/static/src/components/messaging_menu/messaging_menu.js @@ -3,7 +3,7 @@ import { useComponentToModel } from '@mail/component_hooks/use_component_to_model'; import { registerMessagingComponent } from '@mail/utils/messaging_component'; -const { Component, onMounted, onWillUnmount } = owl; +const { Component } = owl; export class MessagingMenu extends Component { @@ -19,20 +19,6 @@ export class MessagingMenu extends Component { * item is not considered as a click away from messaging menu in mobile. */ this.id = _.uniqueId('o_messagingMenu_'); - // bind since passed as props - this._onMobileNewMessageInputSelect = this._onMobileNewMessageInputSelect.bind(this); - this._onMobileNewMessageInputSource = this._onMobileNewMessageInputSource.bind(this); - this._onClickCaptureGlobal = this._onClickCaptureGlobal.bind(this); - onMounted(() => this._mounted()); - onWillUnmount(() => this._willUnmount()); - } - - _mounted() { - document.addEventListener('click', this._onClickCaptureGlobal, true); - } - - _willUnmount() { - document.removeEventListener('click', this._onClickCaptureGlobal, true); } //-------------------------------------------------------------------------- @@ -46,63 +32,6 @@ export class MessagingMenu extends Component { return this.messaging && this.messaging.models['MessagingMenu'].get(this.props.localId); } - //-------------------------------------------------------------------------- - // Handlers - //-------------------------------------------------------------------------- - - /** - * Closes the menu when clicking outside, if appropriate. - * - * @private - * @param {MouseEvent} ev - */ - _onClickCaptureGlobal(ev) { - if (!this.messagingMenu) { - return; - } - // ignore click inside the menu - if (!this.root.el || this.root.el.contains(ev.target)) { - return; - } - // in all other cases: close the messaging menu when clicking outside - this.messagingMenu.close(); - } - - /** - * @private - * @param {Event} ev - * @param {Object} ui - * @param {Object} ui.item - * @param {integer} ui.item.id - */ - _onMobileNewMessageInputSelect(ev, ui) { - this.messaging.openChat({ partnerId: ui.item.id }); - } - - /** - * @private - * @param {Object} req - * @param {string} req.term - * @param {function} res - */ - _onMobileNewMessageInputSource(req, res) { - const value = _.escape(req.term); - this.messaging.models['Partner'].imSearch({ - callback: partners => { - const suggestions = partners.map(partner => { - return { - id: partner.id, - value: partner.nameOrDisplayName, - label: partner.nameOrDisplayName, - }; - }); - res(_.sortBy(suggestions, 'label')); - }, - keyword: value, - limit: 10, - }); - } - } Object.assign(MessagingMenu, { diff --git a/addons/mail/static/src/components/messaging_menu/messaging_menu.xml b/addons/mail/static/src/components/messaging_menu/messaging_menu.xml index cad33636bb1..694da89c44b 100644 --- a/addons/mail/static/src/components/messaging_menu/messaging_menu.xml +++ b/addons/mail/static/src/components/messaging_menu/messaging_menu.xml @@ -44,8 +44,8 @@ customClass="id + '_mobileNewMessageInputAutocomplete'" isFocusOnMount="true" localId="messagingMenu.mobileNewMessageAutocompleteInputView.localId" - select="_onMobileNewMessageInputSelect" - source="_onMobileNewMessageInputSource" + select="messagingMenu.onMobileNewMessageInputSelect" + source="messagingMenu.onMobileNewMessageInputSource" onHide="messagingMenu.onHideMobileNewMessage" /> diff --git a/addons/mail/static/src/components/notification_group/notification_group.js b/addons/mail/static/src/components/notification_group/notification_group.js index f53d8a92008..ba430673849 100644 --- a/addons/mail/static/src/components/notification_group/notification_group.js +++ b/addons/mail/static/src/components/notification_group/notification_group.js @@ -26,15 +26,6 @@ export class NotificationGroup extends Component { return this.messaging && this.messaging.models['NotificationGroupView'].get(this.props.localId); } - /** - * @returns {string|undefined} - */ - image() { - if (this.notificationGroupView.notificationGroup.notification_type === 'email') { - return '/mail/static/src/img/smiley/mailfailure.jpg'; - } - } - } Object.assign(NotificationGroup, { diff --git a/addons/mail/static/src/components/notification_group/notification_group.xml b/addons/mail/static/src/components/notification_group/notification_group.xml index 2657754ba59..9f0a0132fc4 100644 --- a/addons/mail/static/src/components/notification_group/notification_group.xml +++ b/addons/mail/static/src/components/notification_group/notification_group.xml @@ -6,7 +6,7 @@
- Message delivery failure image + Message delivery failure image
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 0ab0f9c8ee1..df46ba3533e 100644 --- a/addons/mail/static/src/components/notification_list/notification_list.js +++ b/addons/mail/static/src/components/notification_list/notification_list.js @@ -2,22 +2,10 @@ import { registerMessagingComponent } from '@mail/utils/messaging_component'; -const { Component, onMounted } = owl; +const { Component } = owl; export class NotificationList extends Component { - /** - * @override - */ - setup() { - super.setup(); - onMounted(() => this._mounted()); - } - - _mounted() { - this._loadPreviews(); - } - /** * @returns {NotificationListView} */ @@ -25,22 +13,6 @@ export class NotificationList extends Component { return this.messaging && this.messaging.models['NotificationListView'].get(this.props.localId); } - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * Load previews of given thread. Basically consists of fetching all missing - * last messages of each thread. - * - * @private - */ - async _loadPreviews() { - const threads = this.notificationListView.threadPreviewViews - .map(threadPreviewView => threadPreviewView.thread); - this.messaging.models['Thread'].loadPreviews(threads); - } - } Object.assign(NotificationList, { diff --git a/addons/mail/static/src/components/notification_popover/notification_popover.js b/addons/mail/static/src/components/notification_popover/notification_popover.js deleted file mode 100644 index b9cda34e071..00000000000 --- a/addons/mail/static/src/components/notification_popover/notification_popover.js +++ /dev/null @@ -1,23 +0,0 @@ -/** @odoo-module **/ - -import { registerMessagingComponent } from '@mail/utils/messaging_component'; - -const { Component } = owl; - -export class NotificationPopover extends Component { - - /** - * @returns {MessageView} - */ - get messageView() { - return this.messaging && this.messaging.models['MessageView'].get(this.props.messageViewLocalId); - } - -} - -Object.assign(NotificationPopover, { - props: { messageViewLocalId: String }, - template: 'mail.NotificationPopover', -}); - -registerMessagingComponent(NotificationPopover); diff --git a/addons/mail/static/src/components/notification_popover/notification_popover.xml b/addons/mail/static/src/components/notification_popover/notification_popover.xml deleted file mode 100644 index 347676240b3..00000000000 --- a/addons/mail/static/src/components/notification_popover/notification_popover.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - -
- - -
- - - - -
-
-
-
-
-
- -
diff --git a/addons/mail/static/src/components/tracking_value/tracking_value.js b/addons/mail/static/src/components/tracking_value/tracking_value.js new file mode 100644 index 00000000000..17856fb3e33 --- /dev/null +++ b/addons/mail/static/src/components/tracking_value/tracking_value.js @@ -0,0 +1,14 @@ +/** @odoo-module **/ + +import { registerMessagingComponent } from '@mail/utils/messaging_component'; + +const { Component } = owl; + +export class TrackingValue extends Component {} + +Object.assign(TrackingValue, { + props: { value: Object }, + template: 'mail.TrackingValue', +}); + +registerMessagingComponent(TrackingValue); diff --git a/addons/mail/static/src/components/tracking_value/tracking_value.scss b/addons/mail/static/src/components/tracking_value/tracking_value.scss new file mode 100644 index 00000000000..3c0215bc542 --- /dev/null +++ b/addons/mail/static/src/components/tracking_value/tracking_value.scss @@ -0,0 +1,6 @@ + +.o_TrackingValue_item { + // Could be replaced by "me-1" after the migration to BS5 + // for the backend AND the frontend + margin-inline-end: map-get($spacers, 1); +} \ No newline at end of file diff --git a/addons/mail/static/src/components/tracking_value/tracking_value.xml b/addons/mail/static/src/components/tracking_value/tracking_value.xml new file mode 100644 index 00000000000..7990674b0ae --- /dev/null +++ b/addons/mail/static/src/components/tracking_value/tracking_value.xml @@ -0,0 +1,21 @@ + + + + +
  • +
    +
    + +
    + + None +
  • +
    + +
    \ No newline at end of file diff --git a/addons/mail/static/src/models/messaging_menu.js b/addons/mail/static/src/models/messaging_menu.js index a838d4d755d..8860b016e92 100644 --- a/addons/mail/static/src/models/messaging_menu.js +++ b/addons/mail/static/src/models/messaging_menu.js @@ -7,6 +7,14 @@ import { clear, insertAndReplace } from '@mail/model/model_field_command'; registerModel({ name: 'MessagingMenu', identifyingFields: ['messaging'], + lifecycleHooks: { + _created() { + document.addEventListener('click', this._onClickCaptureGlobal, true); + }, + _willDelete() { + document.removeEventListener('click', this._onClickCaptureGlobal, true); + }, + }, recordMethods: { /** * Close the messaging menu. Should reset its internal state. @@ -45,6 +53,38 @@ registerModel({ onHideMobileNewMessage() { this.update({ isMobileNewMessageToggled: false }); }, + /** + * @private + * @param {Event} ev + * @param {Object} ui + * @param {Object} ui.item + * @param {integer} ui.item.id + */ + onMobileNewMessageInputSelect(ev, ui) { + this.messaging.openChat({ partnerId: ui.item.id }); + }, + /** + * @param {Object} req + * @param {string} req.term + * @param {function} res + */ + onMobileNewMessageInputSource(req, res) { + const value = _.escape(req.term); + this.messaging.models['Partner'].imSearch({ + callback: partners => { + const suggestions = partners.map(partner => { + return { + id: partner.id, + value: partner.nameOrDisplayName, + label: partner.nameOrDisplayName, + }; + }); + res(_.sortBy(suggestions, 'label')); + }, + keyword: value, + limit: 10, + }); + }, /** * Toggle the visibility of the messaging menu "new message" input in * mobile. @@ -113,6 +153,26 @@ registerModel({ _computeNotificationListView() { return this.isOpen ? insertAndReplace() : clear(); }, + /** + * Closes the menu when clicking outside, if appropriate. + * + * @private + * @param {MouseEvent} ev + */ + _onClickCaptureGlobal(ev) { + if (!this.exists()) { + return; + } + if (!this.component) { + return; + } + // ignore click inside the menu + if (!this.component.root.el || this.component.root.el.contains(ev.target)) { + return; + } + // in all other cases: close the messaging menu when clicking outside + this.close(); + }, }, fields: { /** diff --git a/addons/mail/static/src/models/notification_group_view.js b/addons/mail/static/src/models/notification_group_view.js index f73db4f9fd7..379c5fbd240 100644 --- a/addons/mail/static/src/models/notification_group_view.js +++ b/addons/mail/static/src/models/notification_group_view.js @@ -2,6 +2,7 @@ import { registerModel } from '@mail/model/model_core'; import { attr, one } from '@mail/model/model_field'; +import { clear } from '@mail/model/model_field_command'; registerModel({ name: 'NotificationGroupView', @@ -30,8 +31,21 @@ registerModel({ onClickMarkAsRead(ev) { this.notificationGroup.notifyCancel(); }, + /** + * @private + * @returns {string|undefined} + */ + _computeImageSrc() { + if (this.notificationGroup.notification_type === 'email') { + return '/mail/static/src/img/smiley/mailfailure.jpg'; + } + return clear(); + }, }, fields: { + imageSrc: attr({ + compute: '_computeImageSrc', + }), /** * Reference of the "mark as read" button. Useful to disable the * top-level click handler when clicking on this specific button. diff --git a/addons/mail/static/src/models/notification_list_view.js b/addons/mail/static/src/models/notification_list_view.js index 81c03a53bce..f6d029492c4 100644 --- a/addons/mail/static/src/models/notification_list_view.js +++ b/addons/mail/static/src/models/notification_list_view.js @@ -7,6 +7,11 @@ import { clear, insertAndReplace, replace } from '@mail/model/model_field_comman registerModel({ name: 'NotificationListView', identifyingFields: [['discussOwner', 'messagingMenuOwner']], + lifecycleHooks: { + _created() { + this._loadPreviews(); + }, + }, recordMethods: { /** * @private @@ -183,6 +188,17 @@ registerModel({ }) ); }, + /** + * Load previews of given thread. Basically consists of fetching all missing + * last messages of each thread. + * + * @private + */ + async _loadPreviews() { + const threads = this.threadPreviewViews + .map(threadPreviewView => threadPreviewView.thread); + this.messaging.models['Thread'].loadPreviews(threads); + }, }, fields: { discussOwner: one('Discuss', { diff --git a/addons/mail/static/src/models/thread.js b/addons/mail/static/src/models/thread.js index b234bac0218..bb3cd4bdc57 100644 --- a/addons/mail/static/src/models/thread.js +++ b/addons/mail/static/src/models/thread.js @@ -1619,7 +1619,7 @@ registerModel({ */ _computeTypingStatusText() { if (this.orderedOtherTypingMembers.length === 0) { - return this.constructor.fields.typingStatusText.default; + return clear(); } if (this.orderedOtherTypingMembers.length === 1) { return sprintf( diff --git a/addons/mail/static/tests/helpers/mock_server.js b/addons/mail/static/tests/helpers/mock_server.js index 8c4dc8a81b9..4ad066ba732 100644 --- a/addons/mail/static/tests/helpers/mock_server.js +++ b/addons/mail/static/tests/helpers/mock_server.js @@ -1492,6 +1492,7 @@ MockServer.include({ history_partner_ids: historyPartnerIds, needaction_partner_ids: needactionPartnerIds, notifications, + parentMessage: message.parent_id ? this._mockMailMessageMessageFormat([message.parent_id])[0] : false, recipients: partners.map(p => ({ id: p.id, name: p.name })), record_name: thread && (thread.name !== undefined ? thread.name : thread.display_name), tracking_value_ids: formattedTrackingValues, diff --git a/addons/mail/static/tests/qunit_suite_tests/components/channel_invitation_form_tests.js b/addons/mail/static/tests/qunit_suite_tests/components/channel_invitation_form_tests.js index e8dea292876..21421dd2dd8 100644 --- a/addons/mail/static/tests/qunit_suite_tests/components/channel_invitation_form_tests.js +++ b/addons/mail/static/tests/qunit_suite_tests/components/channel_invitation_form_tests.js @@ -77,7 +77,7 @@ QUnit.test('should be able to search for a new user to invite from an existing c await click(`.o_ThreadViewTopbar_inviteButton`); await insertText('.o_ChannelInvitationForm_searchInput', "TestPartner2"); assert.strictEqual( - document.querySelector(`.o_ChannelInvitationForm_selectablePartnerName`).textContent, + document.querySelector(`.o_ChannelInvitationFormSelectablePartner_name`).textContent, "TestPartner2", "should display 'TestPartner2' as it matches search term", ); @@ -117,7 +117,7 @@ QUnit.test('should be able to create a new group chat from an existing chat', as await click(`.o_ThreadViewTopbar_inviteButton`); await insertText('.o_ChannelInvitationForm_searchInput', "TestPartner2"); - await click(`.o_ChannelInvitationForm_selectablePartnerCheckbox`); + await click(`.o_ChannelInvitationFormSelectablePartner_checkbox`); await click(`.o_ChannelInvitationForm_inviteButton`); assert.strictEqual( document.querySelector(`.o_ThreadViewTopbar_threadName`).textContent, diff --git a/addons/mail/static/tests/qunit_suite_tests/components/chat_window_manager_tests.js b/addons/mail/static/tests/qunit_suite_tests/components/chat_window_manager_tests.js index a1b8f6db184..5ffccc58f0f 100644 --- a/addons/mail/static/tests/qunit_suite_tests/components/chat_window_manager_tests.js +++ b/addons/mail/static/tests/qunit_suite_tests/components/chat_window_manager_tests.js @@ -2113,11 +2113,11 @@ QUnit.test('chat window does not fetch messages if hidden', async function (asse await click('.o_ChatWindowHiddenMenu_dropdownToggle'); assert.containsOnce( document.body, - '.o_ChatWindowHiddenMenu_chatWindowHeader', + '.o_ChatWindowHiddenMenuItem', "1 hidden chat window should be listed in hidden menu" ); - await click('.o_ChatWindowHiddenMenu_chatWindowHeader'); + await click('.o_ChatWindowHiddenMenuItem_chatWindowHeader'); assert.containsN( document.body, '.o_ChatWindow', diff --git a/addons/mail/static/tests/qunit_suite_tests/components/composer_tests.js b/addons/mail/static/tests/qunit_suite_tests/components/composer_tests.js index 25deefadc5c..98384436e68 100644 --- a/addons/mail/static/tests/qunit_suite_tests/components/composer_tests.js +++ b/addons/mail/static/tests/qunit_suite_tests/components/composer_tests.js @@ -207,7 +207,7 @@ QUnit.test('add an emoji', async function (assert) { }); await createComposerComponent(thread.composer); await click('.o_Composer_buttonEmojis'); - await click('.o_EmojiList_emoji[data-unicode="😊"]'); + await click('.o_Emoji[data-unicode="😊"]'); assert.strictEqual( document.querySelector(`.o_ComposerTextInput_textarea`).value, "😊", @@ -234,7 +234,7 @@ QUnit.test('add an emoji after some text', async function (assert) { ); await click('.o_Composer_buttonEmojis'); - await click('.o_EmojiList_emoji[data-unicode="😊"]'); + await click('.o_Emoji[data-unicode="😊"]'); assert.strictEqual( document.querySelector(`.o_ComposerTextInput_textarea`).value, "Blabla😊", @@ -264,7 +264,7 @@ QUnit.test('add emoji replaces (keyboard) text selection', async function (asser // simulate selection of all the content by keyboard composerTextInputTextArea.setSelectionRange(0, composerTextInputTextArea.value.length); await click('.o_Composer_buttonEmojis'); - await click('.o_EmojiList_emoji[data-unicode="😊"]'); + await click('.o_Emoji[data-unicode="😊"]'); assert.strictEqual( document.querySelector(`.o_ComposerTextInput_textarea`).value, "😊", @@ -416,7 +416,7 @@ QUnit.test('add an emoji after a canned response', async function (assert) { // select emoji await click('.o_Composer_buttonEmojis'); - await click('.o_EmojiList_emoji[data-unicode="😊"]'); + await click('.o_Emoji[data-unicode="😊"]'); assert.strictEqual( document.querySelector(`.o_ComposerTextInput_textarea`).value.replace(/\s/, " "), "Hello! How are you? 😊", @@ -564,7 +564,7 @@ QUnit.test('add an emoji after a channel mention', async function (assert) { // select emoji await click('.o_Composer_buttonEmojis'); - await click('.o_EmojiList_emoji[data-unicode="😊"]'); + await click('.o_Emoji[data-unicode="😊"]'); assert.strictEqual( document.querySelector(`.o_ComposerTextInput_textarea`).value.replace(/\s/, " "), "#General 😊", @@ -747,7 +747,7 @@ QUnit.test('add an emoji after a command', async function (assert) { // select emoji await click('.o_Composer_buttonEmojis'); - await click('.o_EmojiList_emoji[data-unicode="😊"]'); + await click('.o_Emoji[data-unicode="😊"]'); assert.strictEqual( document.querySelector(`.o_ComposerTextInput_textarea`).value.replace(/\s/, " "), "/who 😊", @@ -907,7 +907,7 @@ QUnit.test('add an emoji after a partner mention', async function (assert) { // select emoji await click('.o_Composer_buttonEmojis'); - await click('.o_EmojiList_emoji[data-unicode="😊"]'); + await click('.o_Emoji[data-unicode="😊"]'); assert.strictEqual( document.querySelector(`.o_ComposerTextInput_textarea`).value.replace(/\s/, " "), "@TestPartner 😊", diff --git a/addons/mail/static/tests/qunit_suite_tests/components/discuss_inbox_tests.js b/addons/mail/static/tests/qunit_suite_tests/components/discuss_inbox_tests.js index 413e030fea8..5d6c2cce502 100644 --- a/addons/mail/static/tests/qunit_suite_tests/components/discuss_inbox_tests.js +++ b/addons/mail/static/tests/qunit_suite_tests/components/discuss_inbox_tests.js @@ -295,7 +295,7 @@ QUnit.test('reply: discard on click away', async function (assert) { "emoji list should be opened after clicking on emojis button" ); - await click(`.o_EmojiList_emoji`); + await click(`.o_Emoji`); assert.containsNone( document.body, '.o_EmojiList', diff --git a/addons/mail/static/tests/qunit_suite_tests/components/discuss_tests.js b/addons/mail/static/tests/qunit_suite_tests/components/discuss_tests.js index 52ea33cbef4..df9e2d9b294 100644 --- a/addons/mail/static/tests/qunit_suite_tests/components/discuss_tests.js +++ b/addons/mail/static/tests/qunit_suite_tests/components/discuss_tests.js @@ -4001,5 +4001,37 @@ QUnit.test('send message only once when enter is pressed twice quickly', async f ); }); +QUnit.test('message being a replied to another message should show message being replied in the message view', async function (assert) { + assert.expect(1); + + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv['mail.channel'].create(); + const mailMessageId1 = pyEnv['mail.message'].create({ + body: "1st message", + model: 'mail.channel', + res_id: mailChannelId1, + }); + const mailMessageId2 = pyEnv['mail.message'].create({ + body: "2nd message", + model: 'mail.channel', + parent_id: mailMessageId1, + res_id: mailChannelId1, + }); + const { messaging } = await this.start({ + discuss: { + context: { + active_id: `mail.channel_${mailChannelId1}`, + }, + }, + }); + assert.containsOnce( + document.querySelector(`.o_Message[data-message-local-id="${ + messaging.models['Message'].findFromIdentifyingData({ id: mailMessageId2 }).localId + }"]`), + '.o_MessageInReplyToView', + "message being a replied to another message should show message being replied in the message view", + ); +}); + }); }); diff --git a/addons/mail/static/tests/qunit_suite_tests/components/message_tests.js b/addons/mail/static/tests/qunit_suite_tests/components/message_tests.js index fd02940883b..212442b4be6 100644 --- a/addons/mail/static/tests/qunit_suite_tests/components/message_tests.js +++ b/addons/mail/static/tests/qunit_suite_tests/components/message_tests.js @@ -145,26 +145,26 @@ QUnit.test('Notification Sent', async function (assert) { await click('.o_Message_notificationIconClickable'); assert.containsOnce( document.body, - '.o_NotificationPopover', + '.o_MessageNotificationPopoverContent', "notification popover should be open" ); assert.containsOnce( document.body, - '.o_NotificationPopover_notificationIcon', + '.o_MessageNotificationPopoverContent_notificationIcon', "popover should have one icon" ); assert.hasClass( - document.querySelector('.o_NotificationPopover_notificationIcon'), + document.querySelector('.o_MessageNotificationPopoverContent_notificationIcon'), 'fa-check', "popover should have the sent icon" ); assert.containsOnce( document.body, - '.o_NotificationPopover_notificationPartnerName', + '.o_MessageNotificationPopoverContent_notificationPartnerName', "popover should have the partner name" ); assert.strictEqual( - document.querySelector('.o_NotificationPopover_notificationPartnerName').textContent.trim(), + document.querySelector('.o_MessageNotificationPopoverContent_notificationPartnerName').textContent.trim(), "Someone", "partner name should be correct" ); diff --git a/addons/mail/static/tests/qunit_suite_tests/components/thread_view_tests.js b/addons/mail/static/tests/qunit_suite_tests/components/thread_view_tests.js index e72aefe30a6..4fb2a4e9bd8 100644 --- a/addons/mail/static/tests/qunit_suite_tests/components/thread_view_tests.js +++ b/addons/mail/static/tests/qunit_suite_tests/components/thread_view_tests.js @@ -728,26 +728,26 @@ QUnit.test('basic rendering of canceled notification', async function (assert) { await click('.o_Message_notificationIconClickable'); assert.containsOnce( document.body, - '.o_NotificationPopover', + '.o_MessageNotificationPopoverContent', "notification popover should be opened after notification has been clicked" ); assert.containsOnce( document.body, - '.o_NotificationPopover_notificationIcon', + '.o_MessageNotificationPopoverContent_notificationIcon', "an icon should be shown in notification popover" ); assert.containsOnce( document.body, - '.o_NotificationPopover_notificationIcon.fa.fa-trash-o', + '.o_MessageNotificationPopoverContent_notificationIcon.fa.fa-trash-o', "the icon shown in notification popover should be the canceled icon" ); assert.containsOnce( document.body, - '.o_NotificationPopover_notificationPartnerName', + '.o_MessageNotificationPopoverContent_notificationPartnerName', "partner name should be shown in notification popover" ); assert.strictEqual( - document.querySelector('.o_NotificationPopover_notificationPartnerName').textContent.trim(), + document.querySelector('.o_MessageNotificationPopoverContent_notificationPartnerName').textContent.trim(), "Someone", "partner name shown in notification popover should be the one concerned by the notification" ); diff --git a/addons/sms/__manifest__.py b/addons/sms/__manifest__.py index 9252e676299..29a92dfa30e 100644 --- a/addons/sms/__manifest__.py +++ b/addons/sms/__manifest__.py @@ -46,7 +46,6 @@ The service is provided by the In App Purchase Odoo platform. 'web.assets_backend': [ 'sms/static/src/js/fields_phone_widget.js', 'sms/static/src/js/fields_sms_widget.js', - 'sms/static/src/components/*/*.js', 'sms/static/src/models/*.js', ], 'web.qunit_suite_tests': [ diff --git a/addons/sms/static/src/components/notification_group/notification_group.js b/addons/sms/static/src/components/notification_group/notification_group.js deleted file mode 100644 index aa746b9bab7..00000000000 --- a/addons/sms/static/src/components/notification_group/notification_group.js +++ /dev/null @@ -1,22 +0,0 @@ -/** @odoo-module **/ - -import { NotificationGroup } from '@mail/components/notification_group/notification_group'; - -import { patch } from 'web.utils'; - -patch(NotificationGroup.prototype, 'sms/static/src/components/notification_group/notification_group.js', { - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - /** - * @override - */ - image() { - if (this.notificationGroupView.notificationGroup.notification_type === 'sms') { - return '/sms/static/img/sms_failure.svg'; - } - return this._super(...arguments); - }, -}); diff --git a/addons/sms/static/src/models/notification_group_view.js b/addons/sms/static/src/models/notification_group_view.js new file mode 100644 index 00000000000..9840fc8b96e --- /dev/null +++ b/addons/sms/static/src/models/notification_group_view.js @@ -0,0 +1,17 @@ +/** @odoo-module **/ + +import { patchRecordMethods } from '@mail/model/model_core'; +// ensure that the model definition is loaded before the patch +import '@mail/models/notification_group_view'; + +patchRecordMethods('NotificationGroupView', { + /** + * @override + */ + _computeImageSrc() { + if (this.notificationGroup.notification_type === 'sms') { + return '/sms/static/img/sms_failure.svg'; + } + return this._super(); + }, +}); diff --git a/addons/sms/static/tests/qunit_suite_tests/components/message_tests.js b/addons/sms/static/tests/qunit_suite_tests/components/message_tests.js index 868c53a5e29..e62f19bc943 100644 --- a/addons/sms/static/tests/qunit_suite_tests/components/message_tests.js +++ b/addons/sms/static/tests/qunit_suite_tests/components/message_tests.js @@ -69,26 +69,26 @@ QUnit.test('Notification Sent', async function (assert) { }); assert.containsOnce( document.body, - '.o_NotificationPopover', + '.o_MessageNotificationPopoverContent', "notification popover should be open" ); assert.containsOnce( document.body, - '.o_NotificationPopover_notificationIcon', + '.o_MessageNotificationPopoverContent_notificationIcon', "popover should have one icon" ); assert.hasClass( - document.querySelector('.o_NotificationPopover_notificationIcon'), + document.querySelector('.o_MessageNotificationPopoverContent_notificationIcon'), 'fa-check', "popover should have the sent icon" ); assert.containsOnce( document.body, - '.o_NotificationPopover_notificationPartnerName', + '.o_MessageNotificationPopoverContent_notificationPartnerName', "popover should have the partner name" ); assert.strictEqual( - document.querySelector('.o_NotificationPopover_notificationPartnerName').textContent.trim(), + document.querySelector('.o_MessageNotificationPopoverContent_notificationPartnerName').textContent.trim(), "Someone", "partner name should be correct" ); diff --git a/addons/snailmail/static/src/components/message/message.xml b/addons/snailmail/static/src/components/message/message.xml index e1537fd6669..265edb66d81 100644 --- a/addons/snailmail/static/src/components/message/message.xml +++ b/addons/snailmail/static/src/components/message/message.xml @@ -20,7 +20,7 @@ It was decided that the information displayed for snailmail messages has to be different than for standard messages, see task-1907998. --> - + diff --git a/addons/snailmail/static/src/components/notification_group/notification_group.js b/addons/snailmail/static/src/components/notification_group/notification_group.js deleted file mode 100644 index 3b71701f897..00000000000 --- a/addons/snailmail/static/src/components/notification_group/notification_group.js +++ /dev/null @@ -1,22 +0,0 @@ -/** @odoo-module **/ - -import { NotificationGroup } from '@mail/components/notification_group/notification_group'; - -import { patch } from 'web.utils'; - -patch(NotificationGroup.prototype, 'snailmail/static/src/components/notification_group/notification_group.js', { - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - /** - * @override - */ - image() { - if (this.notificationGroupView.notificationGroup.notification_type === 'snail') { - return '/snailmail/static/img/snailmail_failure.png'; - } - return this._super(...arguments); - }, -}); diff --git a/addons/snailmail/static/src/models/notification_group_view.js b/addons/snailmail/static/src/models/notification_group_view.js new file mode 100644 index 00000000000..27316a21934 --- /dev/null +++ b/addons/snailmail/static/src/models/notification_group_view.js @@ -0,0 +1,17 @@ +/** @odoo-module **/ + +import { patchRecordMethods } from '@mail/model/model_core'; +// ensure that the model definition is loaded before the patch +import '@mail/models/notification_group_view'; + +patchRecordMethods('NotificationGroupView', { + /** + * @override + */ + _computeImageSrc() { + if (this.notificationGroup.notification_type === 'snail') { + return '/snailmail/static/img/snailmail_failure.png'; + } + return this._super(); + }, +}); diff --git a/addons/test_mail/static/tests/tracking_value_tests.js b/addons/test_mail/static/tests/tracking_value_tests.js index d2c1b082937..3f047e52894 100644 --- a/addons/test_mail/static/tests/tracking_value_tests.js +++ b/addons/test_mail/static/tests/tracking_value_tests.js @@ -52,41 +52,41 @@ QUnit.test('basic rendering of tracking value (float type)', async function (ass await click('.o_form_button_save'); assert.containsOnce( document.body, - '.o_Message_trackingValue', + '.o_TrackingValue', "should display a tracking value" ); assert.containsOnce( document.body, - '.o_Message_trackingValueFieldName', + '.o_TrackingValue_fieldName', "should display the name of the tracked field" ); assert.strictEqual( - document.querySelector('.o_Message_trackingValueFieldName').textContent, + document.querySelector('.o_TrackingValue_fieldName').textContent, "Float:", "should display the correct tracked field name (Float)", ); assert.containsOnce( document.body, - '.o_Message_trackingValueOldValue', + '.o_TrackingValue_oldValue', "should display the old value" ); assert.strictEqual( - document.querySelector('.o_Message_trackingValueOldValue').textContent, + document.querySelector('.o_TrackingValue_oldValue').textContent, "12.30", "should display the correct old value (12.30)", ); assert.containsOnce( document.body, - '.o_Message_trackingValueSeparator', + '.o_TrackingValue_separator', "should display the separator" ); assert.containsOnce( document.body, - '.o_Message_trackingValueNewValue', + '.o_TrackingValue_newValue', "should display the new value" ); assert.strictEqual( - document.querySelector('.o_Message_trackingValueNewValue').textContent, + document.querySelector('.o_TrackingValue_newValue').textContent, "45.67", "should display the correct new value (45.67)", ); @@ -102,7 +102,7 @@ QUnit.test('rendering of tracked field of type float: from non-0 to 0', async fu await testUtils.fields.editInput(form.$('input[name=float_field]'), 0); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Float:1.000.00", "should display the correct content of tracked field of type float: from non-0 to 0 (Float: 1.00 -> 0.00)" ); @@ -118,7 +118,7 @@ QUnit.test('rendering of tracked field of type float: from 0 to non-0', async fu await testUtils.fields.editInput(form.$('input[name=float_field]'), 1); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Float:0.001.00", "should display the correct content of tracked field of type float: from 0 to non-0 (Float: 0.00 -> 1.00)" ); @@ -134,7 +134,7 @@ QUnit.test('rendering of tracked field of type integer: from non-0 to 0', async await testUtils.fields.editInput(form.$('input[name=integer_field]'), 0); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Integer:10", "should display the correct content of tracked field of type integer: from non-0 to 0 (Integer: 1 -> 0)" ); @@ -150,7 +150,7 @@ QUnit.test('rendering of tracked field of type integer: from 0 to non-0', async await testUtils.fields.editInput(form.$('input[name=integer_field]'), 1); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Integer:01", "should display the correct content of tracked field of type integer: from 0 to non-0 (Integer: 0 -> 1)" ); @@ -166,7 +166,7 @@ QUnit.test('rendering of tracked field of type monetary: from non-0 to 0', async await testUtils.fields.editSelect(form.$('div[name=monetary_field] > input'), 0); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Monetary:1.000.00", "should display the correct content of tracked field of type monetary: from non-0 to 0 (Monetary: 1.00 -> 0.00)" ); @@ -182,7 +182,7 @@ QUnit.test('rendering of tracked field of type monetary: from 0 to non-0', async await testUtils.fields.editSelect(form.$('div[name=monetary_field] > input'), 1); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Monetary:0.001.00", "should display the correct content of tracked field of type monetary: from 0 to non-0 (Monetary: 0.00 -> 1.00)" ); @@ -198,7 +198,7 @@ QUnit.test('rendering of tracked field of type boolean: from true to false', asy form.$('.custom-checkbox input').click(); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Boolean:YesNo", "should display the correct content of tracked field of type boolean: from true to false (Boolean: True -> False)" ); @@ -214,7 +214,7 @@ QUnit.test('rendering of tracked field of type boolean: from false to true', asy form.$('.custom-checkbox input').click(); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Boolean:NoYes", "should display the correct content of tracked field of type boolean: from false to true (Boolean: False -> True)" ); @@ -230,7 +230,7 @@ QUnit.test('rendering of tracked field of type char: from a string to empty stri await testUtils.fields.editInput(form.$('input[name=char_field]'), ''); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Char:MarcNone", "should display the correct content of tracked field of type char: from a string to empty string (Char: Marc -> None)" ); @@ -246,7 +246,7 @@ QUnit.test('rendering of tracked field of type char: from empty string to a stri await testUtils.fields.editInput(form.$('input[name=char_field]'), 'Marc'); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Char:NoneMarc", "should display the correct content of tracked field of type char: from empty string to a string (Char: None -> Marc)" ); @@ -262,7 +262,7 @@ QUnit.test('rendering of tracked field of type date: from no date to a set date' await testUtils.fields.editAndTrigger(form.$('.o_datepicker[name=date_field] .o_datepicker_input'), '12/14/2018', ['change']); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Date:None12/14/2018", "should display the correct content of tracked field of type date: from no date to a set date (Date: None -> 12/14/2018)" ); @@ -278,7 +278,7 @@ QUnit.test('rendering of tracked field of type date: from a set date to no date' await testUtils.fields.editAndTrigger(form.$('.o_datepicker[name=date_field] .o_datepicker_input'), '', ['change']); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Date:12/14/2018None", "should display the correct content of tracked field of type date: from a set date to no date (Date: 12/14/2018 -> None)" ); @@ -294,7 +294,7 @@ QUnit.test('rendering of tracked field of type datetime: from no date and time t await testUtils.fields.editAndTrigger(form.$('.o_datepicker[name=datetime_field] .o_datepicker_input'), '12/14/2018 13:42:28', ['change']); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Datetime:None12/14/2018 13:42:28", "should display the correct content of tracked field of type datetime: from no date and time to a set date and time (Datetime: None -> 12/14/2018 13:42:28)" ); @@ -310,7 +310,7 @@ QUnit.test('rendering of tracked field of type datetime: from a set date and tim await testUtils.fields.editAndTrigger(form.$('.o_datepicker[name=datetime_field] .o_datepicker_input'), '', ['change']); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Datetime:12/14/2018 13:42:28None", "should display the correct content of tracked field of type datetime: from a set date and time to no date and time (Datetime: 12/14/2018 13:42:28 -> None)" ); @@ -326,7 +326,7 @@ QUnit.test('rendering of tracked field of type text: from some text to empty', a await testUtils.fields.editInput(form.$('textarea[name=text_field]'), ''); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Text:MarcNone", "should display the correct content of tracked field of type text: from some text to empty (Text: Marc -> None)" ); @@ -342,7 +342,7 @@ QUnit.test('rendering of tracked field of type text: from empty to some text', a await testUtils.fields.editInput(form.$('textarea[name=text_field]'), 'Marc'); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Text:NoneMarc", "should display the correct content of tracked field of type text: from empty to some text (Text: None -> Marc)" ); @@ -358,7 +358,7 @@ QUnit.test('rendering of tracked field of type selection: from a selection to no await testUtils.fields.editSelect(form.$('select[name=selection_field]'), ''); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Selection:firstNone", "should display the correct content of tracked field of type selection: from a selection to no selection (Selection: first -> None)" ); @@ -374,7 +374,7 @@ QUnit.test('rendering of tracked field of type selection: from no selection to a await testUtils.fields.editSelect(form.$('select[name=selection_field]'), '"first"'); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Selection:Nonefirst", "should display the correct content of tracked field of type selection: from no selection to a selection (Selection: None -> first)" ); @@ -391,7 +391,7 @@ QUnit.test('rendering of tracked field of type many2one: from having a related r await testUtils.fields.editAndTrigger(form.$('.o_field_many2one_selection input'), '', ['keyup']); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Many2one:MarcNone", "should display the correct content of tracked field of type many2one: from having a related record to no related record (Many2one: Marc -> None)" ); @@ -409,7 +409,7 @@ QUnit.test('rendering of tracked field of type many2one: from no related record await testUtils.fields.many2one.clickItem('many2one_field_id', 'Marc'); await click('.o_form_button_save'); assert.strictEqual( - document.querySelector('.o_Message_trackingValue').textContent, + document.querySelector('.o_TrackingValue').textContent, "Many2one:NoneMarc", "should display the correct content of tracked field of type many2one: from no related record to having a related record (Many2one: None -> Marc)" );