summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/components/message/message.xml
diff options
context:
space:
mode:
authorSébastien Theys <seb@odoo.com>2020-06-15 18:12:21 +0000
committerSébastien Theys <seb@odoo.com>2020-06-15 18:12:21 +0000
commit3fea5b2136627c1d7e83b2a5e111952fe3eb10a1 (patch)
tree5eefad07972a87ce4689b83260f981bc87aadad4 /addons/mail/static/src/components/message/message.xml
parent0a82848606151ef60eb6523e9c4c161171f214e7 (diff)
[REF] mail, *: refactor messaging with OWL
This commit is a significant rewriting of client-side discuss, chatter, chat window, and messaging menu using OWL. The behavior should be broadly the same, with some slight functional changes here and there. From a technical standpoint, the code of messaging is mainly organized in 2 main groups of modules: - models, which are logical entities that depict the client-side state of messaging as a whole. - components, which are in charge of displaying information from models. This refactoring also introduces new JS guidelines regarding folder structure (/static) and naming rules for JS modules. Community PR: https://github.com/odoo/odoo/pull/39023 Enterprise PR: https://github.com/odoo/enterprise/pull/6249 Task-1914207 This PR is a collaborative work by Alexandre, Julien, Sébastien and Xavier, with the precious help of Lucas to speed it up towards the end. closes odoo/odoo#39023 Related: odoo/enterprise#6249 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com> Co-authored-by: Alexandre Kühn <aku@odoo.com> Co-authored-by: Julien Giannone <jgi@odoo.com> Co-authored-by: Lucas Perais <lpe@odoo.com> Co-authored-by: Sébastien Theys <seb@odoo.com> Co-authored-by: Xavier Dubuc <xdu@odoo.com>
Diffstat (limited to 'addons/mail/static/src/components/message/message.xml')
-rw-r--r--addons/mail/static/src/components/message/message.xml220
1 files changed, 220 insertions, 0 deletions
diff --git a/addons/mail/static/src/components/message/message.xml b/addons/mail/static/src/components/message/message.xml
new file mode 100644
index 00000000000..b55e7a5ccf6
--- /dev/null
+++ b/addons/mail/static/src/components/message/message.xml
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates xml:space="preserve">
+
+ <t t-name="mail.Message" owl="1">
+ <div class="o_Message"
+ t-att-class="{
+ 'o-clicked': state.isClicked,
+ 'o-discussion': message and (message.is_discussion or message.is_notification),
+ 'o-mobile': env.messaging.device.isMobile,
+ 'o-not-discussion': message and !(message.is_discussion or message.is_notification),
+ 'o-notification': message and message.message_type === 'notification',
+ 'o-selected': props.isSelected,
+ 'o-squashed': props.isSquashed,
+ 'o-starred': message and isStarred,
+ }" t-on-click="_onClick" t-att-data-message-local-id="message and message.localId"
+ >
+ <t t-if="message" name="rootCondition">
+ <div class="o_Message_sidebar" t-att-class="{ 'o-message-squashed': props.isSquashed }">
+ <t t-if="!props.isSquashed">
+ <div class="o_Message_authorAvatarContainer o_Message_sidebarItem">
+ <img class="o_Message_authorAvatar rounded-circle" t-att-class="{ o_Message_authorRedirect: hasAuthorRedirect, o_redirect: hasAuthorRedirect }" t-att-src="avatar" t-on-click="_onClickAuthor" t-att-title="hasAuthorRedirect ? 'Open chat' : ''" alt=""/>
+ <t t-if="message.author and message.author.im_status">
+ <PartnerImStatusIcon
+ class="o_Message_partnerImStatusIcon"
+ t-att-class="{
+ 'o-message-not-discussion': !(message.is_discussion or message.is_notification),
+ 'o-message-selected': props.isSelected,
+ 'o_Message_partnerImStatusIcon-mobile': env.messaging.device.isMobile,
+ }"
+ partnerLocalId="message.author.localId"
+ />
+ </t>
+ </div>
+ </t>
+ <t t-else="">
+ <div class="o_Message_date o_Message_sidebarItem o-message-squashed" t-att-class="{ 'o-message-selected': props.isSelected }">
+ <t t-esc="shortTime"/>
+ </div>
+ <div class="o_Message_commands o_Message_sidebarCommands o_Message_sidebarItem o-message-squashed" t-att-class="{ 'o-message-selected': props.isSelected, 'o-mobile': env.messaging.device.isMobile }">
+ <t t-if="message.message_type !== 'notification'">
+ <div class="o_Message_command o_Message_commandStar fa"
+ t-att-class="{
+ 'fa-star': isStarred,
+ 'fa-star-o': !isStarred,
+ 'o-message-selected': props.isSelected,
+ 'o-message-starred': isStarred,
+ 'o-mobile': env.messaging.device.isMobile,
+ }" t-on-click="_onClickStar"
+ />
+ </t>
+ </div>
+ <t t-if="message.isCurrentPartnerAuthor and threadViewer and threadViewer.thread">
+ <MessageSeenIndicator class="o_Message_seenIndicator o-message-squashed" messageLocalId="message.localId" threadLocalId="threadViewer.thread.localId"/>
+ </t>
+ </t>
+ </div>
+ <div class="o_Message_core">
+ <t t-if="!props.isSquashed">
+ <div class="o_Message_header">
+ <t t-if="message.author">
+ <div class="o_Message_authorName" t-att-class="hasAuthorRedirect ? 'o_Message_authorRedirect o_redirect' : ''" t-on-click="_onClickAuthor" t-att-title="hasAuthorRedirect ? 'Open chat' : ''">
+ <t t-esc="message.author.nameOrDisplayName"/>
+ </div>
+ </t>
+ <t t-elif="message.email_from">
+ <a class="o_Message_authorName" t-attf-href="mailto:{{ message.email_from }}?subject=Re: {{ message.subject ? message.subject : '' }}">
+ <t t-esc="message.email_from"/>
+ </a>
+ </t>
+ <t t-else="">
+ <div class="o_Message_authorName">
+ Anonymous
+ </div>
+ </t>
+ <div class="o_Message_date o_Message_headerDate" t-att-class="{ 'o-message-selected': props.isSelected }" t-att-title="datetime">
+ - <t t-esc="state.timeElapsed"/>
+ </div>
+ <t t-if="message.isCurrentPartnerAuthor and threadViewer and threadViewer.thread">
+ <MessageSeenIndicator class="o_Message_seenIndicator" messageLocalId="message.localId" threadLocalId="threadViewer.thread.localId"/>
+ </t>
+ <t t-if="hasDifferentOriginThread">
+ <div class="o_Message_originThread" t-att-class="{ 'o-message-selected': props.isSelected }">
+ <t t-if="message.originThread.model === 'mail.channel'">
+ (from <a class="o_Message_originThreadLink" href="#" t-on-click="_onClickOriginThread">#<t t-esc="message.originThread.name"/></a>)
+ </t>
+ <t t-else="">
+ on <a class="o_Message_originThreadLink" href="#" t-on-click="_onClickOriginThread"><t t-esc="message.originThread.name"/></a>
+ </t>
+ </div>
+ </t>
+ <t t-if="message.moderation_status === 'pending_moderation' and !message.isModeratedByCurrentPartner">
+ <span class="o_Message_moderationPending o-author" title="Your message is pending moderation.">Pending moderation</span>
+ </t>
+ <t t-if="message.notifications.length > 0">
+ <t t-if="message.failureNotifications.length > 0">
+ <span class="o_Message_notificationIconContainer o-error" t-on-click="_onClickFailure">
+ <i name="failureIcon" class="o_Message_notificationIcon fa fa-envelope"/>
+ </span>
+ </t>
+ <t t-else="">
+ <Popover>
+ <span class="o_Message_notificationIconContainer">
+ <i name="notificationIcon" class="o_Message_notificationIcon fa fa-envelope-o"/>
+ </span>
+ <t t-set="opened">
+ <NotificationPopover
+ notificationLocalIds="message.notifications.map(notification => notification.localId)"
+ />
+ </t>
+ </Popover>
+ </t>
+ </t>
+ <div class="o_Message_commands o_Message_headerCommands" t-att-class="{ 'o-mobile': env.messaging.device.isMobile }">
+ <t t-if="!message.isTemporary and ((message.message_type !== 'notification' and message.originThread and message.originThread.model === 'mail.channel') or !message.isTransient) and message.moderation_status !== 'pending_moderation'">
+ <span class="o_Message_command o_Message_commandStar o_Message_headerCommand fa"
+ t-att-class="{
+ 'fa-star': isStarred,
+ 'fa-star-o': !isStarred,
+ 'o-message-selected': props.isSelected,
+ 'o-message-starred': isStarred,
+ 'o-mobile': env.messaging.device.isMobile,
+ }" t-on-click="_onClickStar" title="Mark as Todo"
+ />
+ </t>
+ <t t-if="props.hasReplyIcon">
+ <span class="o_Message_command o_Message_commandReply o_Message_headerCommand fa fa-reply"
+ t-att-class="{
+ 'o-message-selected': props.isSelected,
+ 'o-mobile': env.messaging.device.isMobile,
+ }" t-on-click="_onClickReply" title="Reply"
+ />
+ </t>
+ <t t-if="props.hasMarkAsReadIcon">
+ <span class="o_Message_command o_Message_commandMarkAsRead o_Message_headerCommand fa fa-check"
+ t-att-class="{
+ 'o-message-selected': props.isSelected,
+ 'o-mobile': env.messaging.device.isMobile,
+ }" t-on-click="_onClickMarkAsRead" title="Mark as Read"
+ />
+ </t>
+ </div>
+ </div>
+ <t t-if="message.isModeratedByCurrentPartner">
+ <div class="o_Message_moderationSubHeader">
+ <t t-if="threadViewer and props.hasCheckbox and message.hasCheckbox">
+ <input class="o_Message_checkbox" type="checkbox" t-att-checked="message.isChecked(threadViewer.thread, threadViewer.stringifiedDomain) ? 'checked': ''" t-on-change="_onChangeCheckbox" t-ref="checkbox"/>
+ </t>
+ <span class="o_Message_moderationPending">Pending moderation:</span>
+ <a class="o_Message_moderationAction o-accept" href="#" title="Accept" t-on-click="_onClickModerationAccept">Accept</a>
+ <a class="o_Message_moderationAction o-reject" href="#" title="Remove message with explanation" t-on-click="_onClickModerationReject">Reject</a>
+ <a class="o_Message_moderationAction o-discard" href="#" title="Remove message without explanation" t-on-click="_onClickModerationDiscard">Discard</a>
+ <a class="o_Message_moderationAction o-allow" href="#" title="Add this email address to white list of people" t-on-click="_onClickModerationAllow">Always Allow</a>
+ <a class="o_Message_moderationAction o-ban" href="#" title="Ban this email address" t-on-click="_onClickModerationBan">Ban</a>
+ </div>
+ </t>
+ </t>
+ <div class="o_Message_content" t-ref="content">
+ <t t-raw="message.prettyBody"/>
+ <t t-if="message.subtype_description">
+ <p t-esc="message.subtype_description"/>
+ </t>
+ <t t-if="trackingValues.length > 0">
+ <ul class="o_Message_trackingValues">
+ <t t-foreach="trackingValues" t-as="value" t-key="value.id">
+ <li>
+ <div class="o_Message_trackingValue">
+ <div class="o_Message_trackingValueItem" t-esc="value.changed_field"/>
+ <t t-if="value.old_value">
+ <div class="o_Message_trackingValueItem" t-esc="value.old_value || ((value.field_type !== 'boolean') and '')"/>
+ <t t-if="value.old_value !== value.new_value">
+ <div class="o_Message_trackingValueItem fa fa-long-arrow-right" title="Changed" role="img"/>
+ </t>
+ </t>
+ <t t-if="value.old_value !== value.new_value">
+ <div class="o_Message_trackingValueItem" t-esc="value.new_value || ((value.field_type !== 'boolean') and '')"/>
+ </t>
+ </div>
+ </li>
+ </t>
+ </ul>
+ </t>
+ </div>
+ <t t-if="message.attachments and message.attachments.length > 0">
+ <div class="o_Message_footer">
+ <!-- TODO XDU This does not allow to preview all attachments at once, find somethind else -->
+ <t t-if="imageAttachments and imageAttachments.length > 0">
+ <AttachmentList
+ class="o_Message_attachmentList"
+ areAttachmentsDownloadable="true"
+ areAttachmentsEditable="true"
+ attachmentLocalIds="imageAttachments.map(attachment => attachment.localId)"
+ attachmentsDetailsMode="props.attachmentsDetailsMode"
+ />
+ </t>
+ <t t-if="nonImageAttachments and nonImageAttachments.length > 0">
+ <AttachmentList
+ class="o_Message_attachmentList"
+ areAttachmentsDownloadable="true"
+ areAttachmentsEditable="true"
+ attachmentLocalIds="nonImageAttachments.map(attachment => attachment.localId)"
+ attachmentsDetailsMode="props.attachmentsDetailsMode"
+ />
+ </t>
+ </div>
+ </t>
+ </div>
+ <t t-if="state.hasModerationBanDialog">
+ <ModerationBanDialog messageLocalIds="[message.localId]" t-on-dialog-closed="_onDialogClosedModerationBan"/>
+ </t>
+ <t t-if="state.hasModerationDiscardDialog">
+ <ModerationDiscardDialog messageLocalIds="[message.localId]" t-on-dialog-closed="_onDialogClosedModerationDiscard"/>
+ </t>
+ <t t-if="state.hasModerationRejectDialog">
+ <ModerationRejectDialog messageLocalIds="[message.localId]" t-on-dialog-closed="_onDialogClosedModerationReject"/>
+ </t>
+ </t>
+ </div>
+ </t>
+
+</templates>