summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/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/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/xml')
-rw-r--r--addons/mail/static/src/xml/abstract_thread_window.xml85
-rw-r--r--addons/mail/static/src/xml/chatter.xml152
-rw-r--r--addons/mail/static/src/xml/composer.xml91
-rw-r--r--addons/mail/static/src/xml/discuss.xml352
-rw-r--r--addons/mail/static/src/xml/followers.xml95
-rw-r--r--addons/mail/static/src/xml/out_of_office.xml9
-rw-r--r--addons/mail/static/src/xml/systray.xml58
-rw-r--r--addons/mail/static/src/xml/text_emojis.xml2
-rw-r--r--addons/mail/static/src/xml/thread.xml536
-rw-r--r--addons/mail/static/src/xml/thread_window.xml32
10 files changed, 2 insertions, 1410 deletions
diff --git a/addons/mail/static/src/xml/abstract_thread_window.xml b/addons/mail/static/src/xml/abstract_thread_window.xml
deleted file mode 100644
index ae29a21b5ba..00000000000
--- a/addons/mail/static/src/xml/abstract_thread_window.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<templates xml:space="preserve">
-
- <!--
- @param {mail.AbstractThreadWindow} widget
- -->
- <t t-name="mail.AbstractThreadWindow">
- <div class="o_thread_window o_in_home_menu" t-att-data-thread-id="widget.getID()">
- <div class="o_thread_window_header">
- <t t-call="mail.AbstractThreadWindow.HeaderContent">
- <t t-set="status" t-value="widget.getThreadStatus()"/>
- <t t-set="title" t-value="widget.getTitle()"/>
- <t t-set="unreadCounter" t-value="widget.getUnreadCounter()"/>
- <t t-set="thread" t-value="widget.getThread()"/>
- </t>
- </div>
- <div class="o_thread_window_content">
- </div>
- <div t-if="widget.needsComposer()" class="o_thread_composer o_chat_mini_composer">
- <input class="o_composer_text_field" t-att-placeholder="widget.options.placeholder"/>
- </div>
- </div>
- </t>
-
- <!--
- @param {boolean} [open=false] tell whether the hidden thread window
- dropdown menu is open or not.
- @param {mail.ThreadWindow[]} threadWindows list of thread windows
- that are hidden, i.e. put in the hidden window dropdown menu.
- @param {integer} [unreadCounter] the total unread counter of all
- threads which are linked to the thread windows that are put in the
- hidden thread window dropdown menu.
- -->
- <t t-name="mail.HiddenThreadWindowsDropdown">
- <div t-attf-class="o_thread_window o_in_home_menu o_thread_window_dropdown dropup #{open ? 'open' : ''}">
- <span role="alert" class="o_thread_window_dropdown_toggler dropdown-toggle" data-toggle="dropdown" title="Unread messages">
- <i class="fa fa-comments-o" role="img" aria-label="Messages"/> <t t-esc="threadWindows.length"/>
- <span class="o_total_unread_counter">
- <t t-if="unreadCounter"><t t-esc="unreadCounter"/></t>
- </span>
- </span>
- <ul class="dropdown-menu" role="menu">
- <t t-foreach="threadWindows" t-as="threadWindow">
- <li role="menuitem" class="o_thread_window_header" t-att-data-thread-id="threadWindow.getID()">
- <t t-call="mail.AbstractThreadWindow.HeaderContent">
- <t t-set="status" t-value="threadWindow.getThreadStatus()"/>
- <t t-set="title" t-value="threadWindow.getTitle()"/>
- <t t-set="unreadCounter" t-value="threadWindow.getUnreadCounter()"/>
- </t>
- </li>
- </t>
- </ul>
- </div>
- </t>
-
- <!--
- @param {string} [status] e.g. 'online', 'offline'.
- @param {string} title the title of the thread window, e.g. the record
- name of the document.
- @param {integer} [unreadCounter] the number of unread messages on the
- thread.
- @param {mail.model.Thread|undefined} thread
- @param {Object} widget
- @param {function} widget.isMobile function without any param that
- states whether it should render for desktop or mobile screen.
- -->
- <t t-name="mail.AbstractThreadWindow.HeaderContent">
- <span t-if="widget.isMobile()">
- <a href="#" class="o_thread_window_close fa fa-1x fa-arrow-left" aria-label="Close chat window" title="Close chat window"/>
- </span>
- <div t-if="thread and thread.getType() === 'dm_chat'" class="o_thread_window_avatar">
- <img alt="" t-att-src="'/web/image/res.partner/' + thread.getDirectPartnerID() + '/image_128'"/>
- <t t-call="mail.UserStatus"/>
- </div>
- <span class="o_thread_window_title">
- <t t-esc="title"/>
- <span t-if="unreadCounter"> (<t t-esc="unreadCounter"/>)</span>
- <t t-if="thread and thread.hasTypingNotification() and thread.isSomeoneTyping()" t-call="mail.ThreadTypingIcon"/>
- </span>
- <span t-if="!widget.isMobile()" class="o_thread_window_buttons">
- <a href="#" class="o_thread_window_close fa fa-close"/>
- </span>
- </t>
-
-</templates>
diff --git a/addons/mail/static/src/xml/chatter.xml b/addons/mail/static/src/xml/chatter.xml
deleted file mode 100644
index 1f36287cdf8..00000000000
--- a/addons/mail/static/src/xml/chatter.xml
+++ /dev/null
@@ -1,152 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<templates>
-
- <!--
- Chatter attachment tab
- -->
-
- <div t-name="mail.chatter.AttachmentBox" class="o_mail_chatter_attachments">
- <div class="o_chatter_attachment">
- <div class="o_border_dashed">
- <span class="o_attach_title">Attachments</span>
- </div>
- <div t-if="widget.imageList.length > 0" class="o_attachments_previews">
- <t t-foreach="widget.imageList" t-as="attachment">
- <t t-call="mail.AttachmentPreview">
- <t t-set="isDeletable" t-value="true"/>
- </t>
- </t>
- </div>
- <div t-if="widget.otherList.length > 0" class="o_attachments_list">
- <t t-foreach="widget.otherList" t-as="attachment">
- <t t-call="mail.Attachment">
- <t t-set="isDeletable" t-value="true"/>
- </t>
- </t>
- </div>
- <div class="o_chatter_attachment_form">
- <t t-call="HiddenInputFile">
- <t t-set="fileupload_id" t-value="widget.fileuploadId"/>
- <t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
- <t t-set="multi_upload" t-value="true"/>
- <input type="hidden" name="model" t-att-value="widget.currentResModel"/>
- <input type="hidden" name="id" t-att-value="widget.currentResID"/>
- <center><span class="btn btn-link o_upload_attachments_button"><span class="fa fa-plus-square"/> Add Attachments</span></center>
- </t>
- </div>
- </div>
- </div>
-
- <!--
- Chatter Suggested Partners
- -->
- <t t-name="mail.chatter.ComposerSuggestedPartners">
- <!-- List of followers -->
- <div class="o_composer_suggested_partners">
- <t t-foreach='widget.suggestedPartners' t-as='recipient'>
- <div t-attf-title="Add as recipient and follower (reason: {{recipient.reason}})" t-att-class="recipient_index > 2 ? 'o_suggested_toggle o_hidden' : ''">
- <div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- t-attf-id="o_composer_suggested_partners_p{{recipient_index}}"
- t-att-checked="recipient.checked ? 'checked' : undefined"
- t-att-data-fullname="recipient.full_name"/>
- <label t-attf-for="o_composer_suggested_partners_p{{recipient_index}}" class="custom-control-label">
- <t t-esc="recipient.name"/>
- <t t-if="recipient.email_address">(<t t-esc="recipient.email_address"/>)</t>
- </label>
- </div>
- </div>
- </t>
- <t t-if='widget.suggestedPartners.length > 3'>
- <a href="#" class='o_suggested_show_more_less o_suggested_toggle'>
- Show <t t-esc="widget.suggestedPartners.length - 3"/> more
- </a>
- <a href="#" class='o_suggested_show_more_less o_suggested_toggle o_hidden'>
- Show <t t-esc="widget.suggestedPartners.length - 3"/> less
- </a>
- </t>
- </div>
- </t>
-
- <!--
- Chatter composer
-
- @param {mail.composer.Chatter} widget
- -->
-
- <t t-name="mail.chatter.Composer" t-extend="mail.Composer">
- <!-- Insert information before the composer -->
- <t t-jquery=".o_composer_container" t-operation="before">
- <!-- New message composer -->
- <t t-if="!widget.options.isLog">
- <!-- Text for followers -->
- <small class="o_chatter_composer_info">
- <b class="text-muted">To: </b>
- <em class="text-muted">Followers of </em>
- <b>
- <t t-if="widget.options.recordName">
- &#32;&quot;<t t-esc="widget.options.recordName"/>&quot;
- </t>
- <t t-if="!widget.options.recordName">
- this document
- </t>
- </b>
- </small>
- <t t-call="mail.chatter.ComposerSuggestedPartners"/>
- </t>
- </t>
-
- <!-- Add a button to open the full composer dialog -->
- <t t-jquery=".o_composer_button_add_attachment" t-operation="after">
- <button tabindex="6" class="btn btn-secondary fa fa-expand o_composer_button_full_composer" type="button" title="Full composer" aria-label="Full composer"/>
- </t>
- </t>
-
- <!--
- Chatter (mail_thread widget) buttons
-
- @param {boolean} [isMobile]
- @param {boolean} [logNoteButton]
- @param {boolean} [newMessageButton]
- @param {boolean} [scheduleActivityButton]
- -->
- <t t-name="mail.chatter.Buttons">
- <button t-if="newMessageButton" type="button" class="btn btn-link o_chatter_button_new_message" title="Send a message" disabled="disabled">
- Send message
- </button>
- <button t-if="logNoteButton" class="btn btn-link o_chatter_button_log_note" title="Log a note. Followers will not be notified." disabled="disabled">
- Log note
- </button>
- <button t-if="scheduleActivityButton" class="btn btn-link o_chatter_button_schedule_activity" title="Log or schedule an activity" disabled="disabled">
- <i class="fa fa-clock-o" title="Dates"/> <t t-if="isMobile">Activity</t><t t-else="">Schedule activity</t>
- </button>
- </t>
-
- <!--
- Chatter attachment paperclip button.
-
- @param {integer} [count]
- -->
- <t t-name="mail.chatter.Attachment.Button">
- <t t-set="attachment_button_aria_label">Attachments</t>
- <button class="btn btn-link o_chatter_button_attachment" title="View all the attachments of the current record" t-attf-aria-label="#{attachment_button_aria_label} #{count}">
- <span>
- <i class="fa fa-paperclip"/>
- <span class="o_chatter_attachment_button_count" t-esc="count"/>
- </span>
- </button>
- </t>
-
- <!--
- Chatter main div
- -->
- <t t-name="mail.Chatter">
- <aside class="o_chatter">
- <div class="o_chatter_topbar">
- <div class="o_topbar_right_area"/>
- </div>
- </aside>
- </t>
-
-</templates>
diff --git a/addons/mail/static/src/xml/composer.xml b/addons/mail/static/src/xml/composer.xml
index 071a8023e83..49c0a3bf9b4 100644
--- a/addons/mail/static/src/xml/composer.xml
+++ b/addons/mail/static/src/xml/composer.xml
@@ -1,54 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
- <div t-name="mail.Composer" t-attf-class="o_thread_composer #{widget.extended ? 'o_thread_composer_extended' : (widget.notInline ? '' : 'o_chat_inline_composer')} #{widget.isMini ? 'o_chat_mini_composer' : ''}">
- <div t-if="widget.isMini || !widget.notInline" class="o_file_drop_zone_container d-none">
- <h4>Drag Files Here <span class="fa fa-download"/></h4>
- </div>
- <div class="o_composer_container">
- <img t-if="widget.avatarURL" height="36" width="36" class="o_thread_message_sidebar o_chatter_avatar o_object_fit_cover rounded-circle" t-att-src="widget.avatarURL" alt="Avatar"/>
- <div t-if="widget.extended" class="o_composer_subject">
- <input tabindex="1" type="text" placeholder="Subject" class="o_input"/>
- </div>
- <div t-attf-class="o_composer #{widget.extended ? 'o_extended_composer' : ''}">
- <div t-if="widget.notInline" class="o_file_drop_zone_container d-none">
- <h4>Drag Files Here <span class="fa fa-download"/></h4>
- </div>
- <div class="o_composer_input">
- <textarea class="o_input o_composer_text_field" tabindex="2" placeholder="Write something..."/>
- <div class="o_chatter_composer_tools">
- <button tabindex="4" class="btn btn-secondary fa fa-smile-o o_composer_button_emoji" type="button" data-toggle="popover" title="Emojis" aria-label="Emojis"/>
- <button tabindex="5" class="btn btn-secondary fa fa-paperclip o_composer_button_add_attachment" type="button" aria-label="Add attachment" title="Add attachment"/>
- <button t-if="widget.options.isMobile" tabindex="3" t-attf-class="btn #{widget.isMini ? 'btn-primary' : 'btn-secondary'} fa fa-paper-plane-o o_composer_button_send" type="button" title="Send" aria-label="Send"/>
- </div>
- </div>
- </div>
- <div class="o_composer_attachments_list"/>
- <div class="o_composer_thread_typing"/>
- </div>
- <div class="o_composer_send">
- <button tabindex="3" class="btn btn-primary o_composer_button_send d-none d-md-inline-block" type="button"><t t-esc="widget.options.sendText"/></button>
- <button tabindex="3" class="btn btn-secondary o_composer_button_discard d-none" type="button">Discard</button>
- </div>
- <span class="d-none">
- <t t-call="HiddenInputFile">
- <t t-set="fileupload_id" t-value="widget.fileuploadID"/>
- <t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
- <t t-set="multi_upload" t-value="true"/>
- <input type="hidden" name="model" value="mail.compose.message"/>
- <input type="hidden" name="id" value="0"/>
- </t>
- </span>
- </div>
-
- <!--
- @param {mail.model.Thread} thread
- -->
- <t t-name="mail.Composer.ThreadTyping">
- <t t-esc="thread.getTypingMembersToText()"/>
- </t>
-
- <div t-name="mail.Composer.emojis" class="o_mail_emoji_container">
+ <div t-name="mail.legacy.Composer.emojis" class="o_mail_emoji_container">
<t t-foreach="emojis" t-as="emoji">
<span t-att-data-emoji="emoji.sources[0]" class="o_mail_emoji" t-att-title="emoji.description" t-att-aria-label="emoji.description">
<t t-raw="emoji.unicode"/>
@@ -56,48 +9,6 @@
</t>
</div>
- <!--
- @param {Object[]} suggestions
- @param {boolean} [suggestions.divider=false]
- -->
- <t t-name="mail.MentionSuggestions">
- <div class="dropdown-menu" role="menu">
- <t t-foreach="suggestions" t-as="suggestion">
- <div role="separator" t-if="suggestion.divider" class="dropdown-divider"/>
- <a t-else="" href="#" class="dropdown-item o_mention_proposition" t-att-data-id="suggestion.id" role="menuitem"/>
- </t>
- </div>
- </t>
- <t t-name="mail.MentionSuggestions.Partner" t-extend="mail.MentionSuggestions">
- <t t-jquery=".o_mention_proposition" t-operation="append">
- <t t-call="mail.UserStatus">
- <t t-set="status" t-value="suggestion.im_status"/>
- <t t-set="partnerID" t-value="suggestion.id"/>
- </t>
- <span class="o_mention_name"><t t-esc="suggestion.name"/></span>
- <t t-if="suggestion.email">
- <span class="o_mention_info">(<t t-esc="suggestion.email"/>)</span>
- </t>
- </t>
- </t>
- <t t-name="mail.MentionSuggestions.Channel" t-extend="mail.MentionSuggestions">
- <t t-jquery=".o_mention_proposition" t-operation="append">
- <span class="o_mention_name"><t t-esc="suggestion.name"/></span>
- </t>
- </t>
- <t t-name="mail.MentionSuggestions.CannedResponse" t-extend="mail.MentionSuggestions">
- <t t-jquery=".o_mention_proposition" t-operation="append">
- <span class="o_mention_name"><t t-esc="suggestion.source"/></span>
- <span class="o_mention_info"><t t-esc="suggestion.substitution"/></span>
- </t>
- </t>
- <t t-name="mail.MentionSuggestions.Command" t-extend="mail.MentionSuggestions">
- <t t-jquery=".o_mention_proposition" t-operation="append">
- <span class="o_mention_name">/<t t-esc="suggestion.name"/></span>
- <span class="o_mention_info"><t t-esc="suggestion.help"/></span>
- </t>
- </t>
-
<t t-name="FieldMany2ManyTagsEmail" t-extend="FieldMany2ManyTag">
<t t-jquery="[t-attf-class*=badge]" t-operation="replace">
<div t-attf-class="badge badge-pill dropdown o_tag_color_0 #{el.email.indexOf('@') &lt; 0 ? 'o_tag_error' : ''}" t-att-data-color="color" t-att-data-index="el_index" t-att-data-id="el.id" t-attf-title="Tag color: #{colornames[color]}">
diff --git a/addons/mail/static/src/xml/discuss.xml b/addons/mail/static/src/xml/discuss.xml
deleted file mode 100644
index 98788e303ff..00000000000
--- a/addons/mail/static/src/xml/discuss.xml
+++ /dev/null
@@ -1,352 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<templates xml:space="preserve">
-
- <!--
- Discuss Main template
-
- @param {mail.discuss} widget
- -->
- <t t-name="mail.discuss">
- <div class="o_mail_discuss">
- <div class="o_mail_discuss_sidebar">
- <div class="o_mail_discuss_loading">
- <i class="fa fa-spinner fa-spin"/> Please wait...
- </div>
- </div>
- <div class="o_mail_discuss_content">
- <div class="o_mail_discuss_loading">
- <i class="fa fa-spinner fa-spin"/> Please wait...
- </div>
- </div>
- </div>
- </t>
-
- <!--
- @param {string|integer} activeThreadID
- @param {mail.model.Channel[]} channels
- @param {boolean} isMyselfModerator
- @param {mail.model.Mailbox} inbox
- @param {mail.model.Mailbox} starred
- @param {mail.model.Mailbox|undefined} moderation set if current user is moderator
- @param {boolean} displayQuickSearch
- @param {Object} options
- -->
- <t t-name="mail.discuss.Sidebar">
- <div class="o_mail_discuss_sidebar">
- <div class="o_mail_discuss_sidebar_mailboxes">
- <t t-call="mail.discuss.SidebarMailboxes"/>
- </div>
- <hr class="mb8"/>
- <div t-if="displayQuickSearch" class="o_discuss_sidebar_quick_search">
- <t t-set="inputPlaceholder">Quick search...</t>
- <input t-att-placeholder="inputPlaceholder"/>
- </div>
- <div class="o_mail_discuss_sidebar_channels">
- <t t-call="mail.discuss.SidebarChannels"/>
- </div>
- </div>
- </t>
-
- <!--
- @param {string|integer} activeThreadID
- @param {boolean} isMyselfModerator
- @param {mail.model.Mailbox} inbox
- @param {mail.model.Mailbox} starred
- @param {mail.model.Mailbox|undefined} moderation set if current user is moderator
- -->
- <t t-name="mail.discuss.SidebarMailboxes">
- <div t-attf-class="o_mail_discuss_title_main o_mail_discuss_item #{(activeThreadID === 'mailbox_inbox') ? 'o_active': ''}"
- data-thread-id="mailbox_inbox">
- <span class="o_thread_name"><i class="fa fa-inbox mr8"/>Inbox</span>
- <t t-set="counter" t-value="inbox.getMailboxCounter()"/>
- <t t-call="mail.discuss.SidebarCounter"/>
- </div>
- <div t-attf-class="o_mail_discuss_title_main o_mail_mailbox_title_starred o_mail_discuss_item #{(activeThreadID === 'mailbox_starred') ? 'o_active': ''}"
- data-thread-id="mailbox_starred">
- <span class="o_thread_name"><i class="fa fa-star-o mr8"/>Starred</span>
- <t t-set="counter" t-value="starred.getMailboxCounter()"/>
- <t t-call="mail.discuss.SidebarCounter"/>
- </div>
- <div t-attf-class="o_mail_discuss_title_main o_mail_discuss_item #{(activeThreadID === 'mailbox_history') ? 'o_active': ''}"
- data-thread-id="mailbox_history">
- <span class="o_thread_name"><i class="fa fa-history mr8"/>History</span>
- </div>
- <div t-if="isMyselfModerator" t-attf-class="o_mail_discuss_title_main o_mail_discuss_item #{(activeThreadID == 'mailbox_moderation') ? 'o_active': ''}"
- data-thread-id="mailbox_moderation">
- <span class="o_thread_name"> <i class="fa fa-envelope mr8"/>Moderation Queue</span>
- <t t-set="counter" t-value="moderation.getMailboxCounter()"/>
- <t t-call="mail.discuss.SidebarCounter"/>
- </div>
- </t>
-
- <!--
- @param {string|integer} activeThreadID
- @param {mail.model.Channel[]} channels
- -->
- <t t-name="mail.discuss.SidebarChannels">
- <t t-set="type" t-value="'multi_user_channel'"/>
- <t t-call="mail.discuss.SidebarTitle">
- <t t-set="title">Channels</t>
- <t t-set="icon" t-value="fa-users"/>
- </t>
- <t t-call="mail.discuss.SidebarItems">
- <t t-set="displayHash" t-value="true"/>
- <t t-set="inputPlaceholder">Add a channel</t>
- </t>
-
- <t t-set="type" t-value="'dm_chat'"/>
- <t t-call="mail.discuss.SidebarTitle">
- <t t-set="title">Direct Messages</t>
- <t t-set="icon" t-value="fa-user"/>
- </t>
- <t t-call="mail.discuss.SidebarItems">
- <t t-set="displayStatus" t-value="true"/>
- <t t-set="inputPlaceholder">User name</t>
- </t>
- </t>
-
- <!--
- @param {integer} counter
- -->
- <t t-name="mail.discuss.SidebarCounter">
- <span t-attf-class="o_mail_sidebar_needaction badge badge-pill #{(!counter ? 'd-none' : '')}">
- <t t-esc="counter"/>
- </span>
- </t>
-
- <!--
- Don't display the thread type if there is no thread of such type
- and the 'add a thread' option is disabled for this type
-
- @param {mail.model.Channel[]} channels
- @param {boolean} [disableAddThread] whether the 'Add thread' action should disabled or not for the considered discuss item category
- @param {string} [icon] classname to add on title to display icon
- @param {string} title the displayed type of the discuss items (e.g. "Channels")
- @param {string} type the type of the thread
- -->
- <t t-name="mail.discuss.SidebarTitle">
- <t t-if="disableAddThread">
- <t t-set="empty" t-value="true"/>
- <t t-foreach="channels" t-as="channel">
- <t t-if="channel.getType() === type">
- <t t-set="empty" t-value="false"/>
- </t>
- </t>
- </t>
- <t t-if="!disableAddThread || !empty">
- <div class="o_mail_sidebar_title">
- <h4 t-att-class="type == 'multi_user_channel' ? 'o_mail_open_channels' : ''">
- <i t-if="icon" t-attf-class="mr4 fa-fw fa #{icon}" role="img" aria-label="Channel" title="Channel"></i>
- <b><t t-esc="title"/></b>
- </h4>
- <span t-if="!disableAddThread" class="fa fa-plus o_add" title="Add" t-attf-data-type="#{type}" role="img" aria-label="Add"/>
- </div>
- </t>
- </t>
-
- <!--
- @param {string|integer} activeThreadID
- @param {mail.model.Channel[]} channels
- @param {boolean} disableAddThread whether the 'Add thread' action should be disable or not for the considered discuss item category
- @param {boolean} [displayHash] whether the hash ('#') character should be displayed as a prefix for item's name
- @param {boolean} [displayStatus] whether the item should display its status (should be the case only for chats)
- @param {string} inputPlaceholder text placeholder on showing input in a sidebar category
- -->
- <t t-name="mail.discuss.SidebarItems">
- <div t-if="!disableAddThread" class="o_mail_add_thread" t-attf-data-type="#{type}">
- <span t-if="displayHash">#</span>
- <input type="text" class="o_input" t-attf-placeholder="#{inputPlaceholder}"/>
- </div>
- <t t-foreach="channels" t-as="channel">
- <t t-set="counter" t-value="channel.isTwoUserThread() ? channel.getUnreadCounter() : channel.getNeedactionCounter()"/>
- <div t-if="channel.getType() === type" t-att-data-thread-id="channel.getID()" t-att-title="channel.getName()"
- t-attf-class="o_mail_discuss_item #{channel.hasUnreadMessages() ? ' o_unread_message' : ''} #{(activeThreadID == channel.getID()) ? 'o_active': ''}">
- <span class="o_thread_name">
- <span t-if="displayStatus">
- <t t-call="mail.UserStatus">
- <t t-set="status" t-value="channel.getStatus()"/>
- <t t-set="partnerID" t-value="channel.getDirectPartnerID()"/>
- </t>
- </span>
- <span t-if="displayHash" class="o_mail_hash">#</span>
- <i t-if="channel.getType() === 'multi_user_channel' and !channel.isPublic()" class="fa fa-lock" title="Private channel" role="img" aria-label="Private channel"/>
- <t t-esc="_.unescape(channel.getName())"/>
- <i t-if="channel.isMassMailing()" class="fa fa-envelope-o" title="Sends messages by email" role="img" aria-label="Send by mail"/>
- </span>
- <t t-if="channel.hasTypingNotification() and channel.isSomeoneTyping()">
- <t t-set="thread" t-value="channel"/>
- <t t-call="mail.ThreadTypingIcon"/>
- </t>
- <span t-attf-class="fa fa-cog o_mail_channel_settings"
- title="Channel settings" role="img" aria-label="Channel settings" t-att-data-thread-id="channel.getID()"/>
- <t t-call="mail.discuss.SidebarCounter"/>
- <span t-if="!channel.isGroupBasedSubscription()" t-attf-class="fa fa-times o_mail_partner_unpin #{counter ? 'd-none' : ''}"
- title="Leave this channel" role="img" aria-label="Leave this channel" t-att-data-thread-id="channel.getID()"/>
- </div>
- </t>
- </t>
-
- <!--
- @param {string} status
- @param {integer|undefined} [partnerID]
- -->
- <t t-name="mail.UserStatus">
- <span t-att-class="partnerID ? 'o_updatable_im_status' : ''" t-att-data-partner-id="partnerID">
- <i t-if="status == 'online'" class="o_mail_user_status o_user_online fa fa-circle" title="Online" role="img" aria-label="User is online"/>
- <i t-if="status == 'away'" class="o_mail_user_status o_user_idle fa fa-circle" title="Idle" role="img" aria-label="User is idle"/>
- <i t-if="status == 'offline'" class="o_mail_user_status fa fa-circle-o" title="Offline" role="img" aria-label="User is offline"/>
- </span>
- </t>
-
- <!--
- @param {string} documentName
- -->
- <t t-name="mail.discuss.MessageSentSnackbar">
- <div class="alert o_mail_snackbar" data-dismiss="alert" role="alert">
- Message sent in "<t t-esc="documentName"/>".
- </div>
- </t>
-
-
- <!--
- Buttons of the Control Panel
-
- @param {boolean} [disableAddThread] whether the 'Add channel' action should be disabled or not for the considered discuss item category
- -->
- <t t-name="mail.discuss.ControlButtons">
- <div>
- <button type="button" class="btn btn-primary o_mail_discuss_button_invite d-none d-md-inline-block" title="Invite people">Invite</button>
- <button type="button" class="btn btn-secondary o_mail_discuss_button_mark_all_read d-none d-md-inline-block" title="Mark all as read">Mark all read</button>
- <button type="button" class="btn btn-secondary o_mail_discuss_button_unstar_all" title="Unstar all messages">Unstar all</button>
- <button type="button" class="btn btn-secondary o_mail_discuss_button_dm_chat o_hidden d-md-none" title="New Message">New Message</button>
- <button t-if="!disableAddThread" type="button" class="btn btn-secondary o_mail_discuss_button_multi_user_channel d-block d-md-none" title="New Channel">New Channel</button>
- <button type="button" class="btn btn-secondary o_hidden o_mail_discuss_button_select_all" title="Select all messages to moderate">Select All</button>
- <button type="button" class="btn btn-secondary o_hidden o_mail_discuss_button_unselect_all" title="Unselect all messages to moderate">Unselect All</button>
- <button type="button" data-decision="accept" class="btn btn-secondary o_mail_discuss_button_moderate_all" title="Accept selected messages">Accept</button>
- <button type="button" data-decision="reject" class="btn btn-secondary o_mail_discuss_button_moderate_all" title="Reject selected messages">Reject</button>
- <button type="button" data-decision="discard" class="btn btn-secondary o_mail_discuss_button_moderate_all" title="Discard selected messages">Discard</button>
- </div>
- </t>
-
- <!-- Invite dialog's content -->
- <div t-name="mail.PartnerInviteDialog">
- <input type="text" class="o_input o_mail_discuss_partner_invite_input" id="mail_search_partners"/>
- </div>
-
- <!-- Rename channel dialog's content -->
- <div t-name="mail.RenameConversationDialog">
- <input type="text" class="o_input o_mail_discuss_rename_channel_input"/>
- </div>
-
- <div t-name="mail.ModeratorRejectMessageDialog">
- <input class="form-control" type="text" id="message_title" placeholder="Subject" value="Message Rejected"/>
- <textarea class="form-control mt16" id="reject_message" placeholder="Mail Body">Your message was rejected by moderator.</textarea>
- </div>
-
- <!-- Mobile templates -->
- <t t-name="mail.discuss_mobile">
- <div class="o_mail_discuss">
- <div class="o_mail_discuss_mobile_mailboxes_buttons">
- <button type="button" class="btn btn-primary d-inline d-md-none o_mailbox_inbox_item" title="Inbox" data-type="mailbox_inbox">
- Inbox
- </button>
- <button type="button" class="btn btn-secondary d-inline d-md-none o_mailbox_inbox_item" title="Starred" data-type="mailbox_starred">
- Starred
- </button>
- <button type="button" class="btn btn-secondary d-inline d-md-none o_mailbox_inbox_item" title="History" data-type="mailbox_history">
- History
- </button>
- </div>
- <div class="o_mail_discuss_content"/>
- <div class="o_mail_mobile_tabs">
- <div class="o_mail_mobile_tab" data-type="mailbox_inbox">
- <span class="fa fa-inbox"/>
- <span class="o_tab_title">Inbox</span>
- </div>
- <div class="o_mail_mobile_tab" data-type="dm_chat">
- <span class="fa fa-user"/>
- <span class="o_tab_title">Chat</span>
- </div>
- <div class="o_mail_mobile_tab" data-type="multi_user_channel">
- <span class="fa fa-users"/>
- <span class="o_tab_title">Channels</span>
- </div>
- </div>
- </div>
- </t>
-
- <!--
- @param {boolean} [disableAddThread] whether the 'Add thread' action should be disabled or not for the considered discuss item category
- @param {Object[]} previews valid objects for preview rendering (see mail.Preview template)
- -->
- <t t-name="mail.discuss.MobileTabPane">
- <div class="o_mail_discuss_tab_pane" t-att-data-type="type">
- <div t-if="!disableAddThread" class="o_mail_add_thread" t-att-data-type="type">
- <span t-if="type == 'multi_user_channel'">#</span>
- <t t-set="inputPlaceholder" t-if="type == 'multi_user_channel'">Add a channel</t>
- <t t-set="inputPlaceholder" t-if="type == 'dm_chat'">Open chat</t>
- <input type="text" t-attf-placeholder="#{inputPlaceholder}"/>
- </div>
- <t t-foreach="previews" t-as="preview">
- <t t-call="mail.Preview"/>
- </t>
- </div>
- </t>
-
- <!--
- The preview template is used by the discuss in mobile, and by the systray menu
- In order to show preview of threads
-
- FIXME: it is shared with systray, so it should not be in discuss.xml
-
- @param {Object} preview a valid object for preview rendering
- @param {integer} [preview.documentID]
- @param {string} [preview.documentModel]
- @param {string|integer} preview.id
- @param {string} [preview.imageSRC]
- @param {boolean} [preview.isMyselfAuthor]
- @param {moment} [preview.date]
- @param {string} [preview.author]
- @param {string} [preview.body]
- @param {string} [preview.title]
- @param {string} [preview.status]
- @param {integer} [preview.unreadCounter]
- @param {integer[]} [preview.messageIDs]
- -->
- <t t-name="mail.Preview">
- <div t-attf-class="o_mail_preview #{preview.unreadCounter &gt; 0 ? 'o_preview_unread' : ''}"
- t-att-data-preview-id="preview.id" t-att-data-document-id="preview.documentID" t-att-data-document-model="preview.documentModel" t-att-data-unread-counter="preview.unreadCounter" t-att-data-message-ids="preview.messageIDs">
- <div t-attf-class="o_mail_preview_image #{preview.documentModel ? 'o_mail_preview_app' : ''}">
- <img class="o_mail_preview_image" t-att-src="preview.imageSRC" alt="Preview"/>
- <t t-call="mail.UserStatus">
- <t t-set="status" t-value="preview.status"/>
- </t>
- </div>
- <div class="o_preview_info">
- <div class="o_preview_title">
- <span class="o_preview_name">
- <t t-esc="preview.title"/>
- </span>
- <span class="o_preview_counter">
- <t t-if="preview.unreadCounter &gt; 0">&amp;nbsp;(<t t-esc="preview.unreadCounter"/>)</t>
- </span>
- <span t-if="preview.isLinkedToDocumentThread" class="o_discuss_icon o_thread_window_expand fa fa-expand"/>
- <span class="o_last_message_date ml-auto mr-2"> <t t-esc="preview.date ? preview.date.fromNow() : ''"/> </span>
- </div>
- <div class="o_last_message_preview">
- <t t-if="preview.body">
- <t t-if="preview.isMyselfAuthor">
- <span class="fa fa-mail-reply" role="img" aria-label="Reply"/> You:
- </t>
- <t t-elif="preview.author">
- <t t-esc="preview.author"/>:
- </t>
- <t t-esc="preview.body"/>
- </t>
- </div>
- <span title="Mark as Read" class="o_discuss_icon o_mail_preview_mark_as_read fa fa-check" t-if="preview.unreadCounter"/>
- </div>
- </div>
- </t>
-
-</templates>
diff --git a/addons/mail/static/src/xml/followers.xml b/addons/mail/static/src/xml/followers.xml
deleted file mode 100644
index d1f6ebd63a4..00000000000
--- a/addons/mail/static/src/xml/followers.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<templates>
-
- <!--
- Followers, actions and subtypes in a record.
- -->
- <t t-name="mail.Followers">
- <div class="o_followers btn-group">
- <div class="o_followers_title_box btn-group">
- <button class="btn btn-link" title="Dropdown menu - Followers"
- data-toggle="dropdown" aria-expanded="false">
- <i class="fa fa-user" role="img" aria-label="Followers"></i>
- <span class="o_followers_count"/>
- </button>
- <div class="dropdown-menu dropdown-menu-right o_followers_list" role="menu"/>
- </div>
- <div class="o_followers_actions btn-group">
- <button class="btn btn-link o_followers_follow_button o_followers_notfollow">
- <span class="o_follow">Follow</span>
- <i class="fa fa-times o_followers_unfollow"/>
- <span class="o_followers_unfollow"> Unfollow</span>
- <i class="fa fa-check o_followers_following"/>
- <span class="o_followers_following"> Following</span>
- </button>
- </div>
- </div>
- </t>
-
- <!--
- Partner or channel following the record
- -->
- <t t-name="mail.Followers.partner">
- <div role="menuitem" t-attf-class="dropdown-item o_partner {{ !record.is_active ? 'o_inactive': '' }}">
- <a class="o_mail_redirect text-truncate"
- href="#"
- t-att-title="record.title"
- t-att-data-oe-model="record.partner_id ? 'res.partner' : 'mail.channel'"
- t-att-data-oe-id="record.partner_id ? record.partner_id : record.channel_id">
- <img t-att-src="record.avatar_url" alt="Avatar" class="o_image_64_cover"/>
- <t t-esc="record.name"/>
- </a>
- <button t-if="record.is_editable"
- class="btn btn-icon fa fa-pencil o_edit_subtype d-none"
- title="Edit subscription"
- aria-label="Edit subscription"
- role="img"
- t-att-data-follower-id="record.id"
- t-att-data-oe-id="record.partner_id ? record.partner_id : record.channel_id"
- t-att-data-oe-model="record.partner_id ? 'res.partner' : 'mail.channel'"/>
- <button t-if="widget.isEditable"
- class="btn btn-icon fa fa-remove o_remove_follower"
- aria-label="Remove this follower"
- role="img"
- title="Remove this follower"/>
- </div>
- </t>
-
- <!--
- 'Add followers' and 'Add channels' buttons
- -->
- <t t-name="mail.Followers.add_more">
- <t t-if="widget.isEditable">
- <a href="#" role="menuitem" class="dropdown-item o_add_follower">Add Followers</a>
- <a href="#" role="menuitem" class="dropdown-item o_add_follower_channel">Add Channels</a>
- <div role="separator" t-if="widget.followers.length > 0" class="dropdown-divider"/>
- </t>
- </t>
-
- <!--
- Message subtypes of a follower subscription
- -->
- <t t-name="mail.Followers.subtype">
- <div role="menuitem" class="o_subtype dropdown-item">
- <div class="custom-control custom-checkbox">
- <input type="checkbox"
- t-attf-id="input_mail_followers_subtype_#{record.id + (dialog ? '_in_dialog': '')}"
- t-att-name="record.name"
- class="custom-control-input o_subtype_checkbox"
- t-att-checked="record.followed"
- t-att-data-id="record.id"/>
- <label t-attf-for="input_mail_followers_subtype_#{record.id + (dialog ? '_in_dialog': '')}"
- class="custom-control-label">
- <t t-esc="record.name"/>
- </label>
- </div>
- <i t-if="display_warning" class="fa fa-warning text-warning" role="img" aria-label="Warning" title="Warning"/>
- </div>
- </t>
- <t t-name="mail.Followers.subtypes.warning">
- <span class="text-warning">
- <i class="fa fa-warning"/> Be careful with channels following internal notifications
- </span>
- </t>
-
-</templates>
diff --git a/addons/mail/static/src/xml/out_of_office.xml b/addons/mail/static/src/xml/out_of_office.xml
deleted file mode 100644
index 19fb2c341c6..00000000000
--- a/addons/mail/static/src/xml/out_of_office.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<templates xml:space="preserve">
- <!--
- @param {mail.model.AbstractThread} thread
- -->
- <div class="o_out_of_office" t-name="mail.thread.OutOfOffice">
- <div class="o_out_of_office_info" t-if="thread.getOutOfOfficeInfo()" t-esc="thread.getOutOfOfficeInfo()"/>
- </div>
-</templates>
diff --git a/addons/mail/static/src/xml/systray.xml b/addons/mail/static/src/xml/systray.xml
index b10ef51a429..b9612e13a27 100644
--- a/addons/mail/static/src/xml/systray.xml
+++ b/addons/mail/static/src/xml/systray.xml
@@ -2,64 +2,6 @@
<templates>
<!--
- @param {mail.systray.MessagingMenu} widget
- -->
- <t t-name="mail.systray.MessagingMenu">
- <li class="o_mail_systray_item">
- <a class="dropdown-toggle o-no-caret" data-toggle="dropdown" data-display="static" aria-expanded="false" title="Conversations" href="#" role="button">
- <i class="o_mail_messaging_menu_icon fa fa-comments fa-spinner fa-spin" role="img" aria-label="Messages"/> <span class="o_notification_counter badge badge-pill"/>
- </a>
- <div class="o_mail_systray_dropdown dropdown-menu dropdown-menu-right" role="menu">
- <t t-if="widget.isMobile()">
- <div class="o_mail_systray_mobile_header">
- <button type="button" class="btn btn-secondary o_new_message"> New message </button>
- </div>
- </t>
- <div t-if="!widget.isMobile()" class="o_mail_systray_dropdown_top">
- <div>
- <button type="button" class="btn btn-link o_filter_button active" role="tab"> All </button>
- <button type="button" class="btn btn-link o_filter_button" data-filter='chat' role="tab"> Chat </button>
- <button type="button" class="btn btn-link o_filter_button" data-filter='channels' role="tab"> Channels </button>
- </div>
- <button type="button" class="btn btn-link o_new_message"> New message </button>
- </div>
- <div class="o_mail_systray_dropdown_items"/>
- <t t-if="widget.isMobile()">
- <div class="o_mail_mobile_tabs">
- <div class="o_mail_mobile_tab o_filter_button active" role="tab">
- <span class="fa fa-envelope"/>
- <span class="o_tab_title">All</span>
- </div>
- <div class="o_mail_mobile_tab o_filter_button" data-filter='chat' role="tab">
- <span class="fa fa-user"/>
- <span class="o_tab_title">Chat</span>
- </div>
- <div class="o_mail_mobile_tab o_filter_button" data-filter='channels' role="tab">
- <span class="fa fa-users"/>
- <span class="o_tab_title">Channels</span>
- </div>
- </div>
- </t>
- </div>
- </li>
- </t>
-
- <!--
- @param {Object} previews valid list of objects for preview rendering
- (see mail.Preview template)
- -->
- <t t-name="mail.systray.MessagingMenu.Previews">
- <t t-if="_.isEmpty(previews)">
- <li class="text-center o_no_activity mt16">
- <span>No conversation yet...</span>
- </li>
- </t>
- <t t-foreach="previews" t-as="preview">
- <t t-call="mail.Preview"/>
- </t>
- </t>
-
- <!--
@param {mail.systray.ActivityMenu} widget
@param {Object[]} widget.activities
-->
diff --git a/addons/mail/static/src/xml/text_emojis.xml b/addons/mail/static/src/xml/text_emojis.xml
index 56a74a54fd3..4f333ba941f 100644
--- a/addons/mail/static/src/xml/text_emojis.xml
+++ b/addons/mail/static/src/xml/text_emojis.xml
@@ -10,7 +10,7 @@
<i class="fa fa-smile-o"/>
</button>
<div class="dropdown-menu dropdown-menu-right border-0 p-2" style="width: 406px">
- <t t-call="mail.Composer.emojis">
+ <t t-call="mail.legacy.Composer.emojis">
<t t-set="emojis" t-value="widget.emojis"></t>
</t>
</div>
diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml
index 05f9f04f6f7..5a3205ed2cb 100644
--- a/addons/mail/static/src/xml/thread.xml
+++ b/addons/mail/static/src/xml/thread.xml
@@ -10,33 +10,6 @@
</t>
</t>
<!--
- @param {mail.model.AbstractThread} thread
- @param {Object} options
- @param {boolean} [options.displayEmptyThread]
- @param {boolean} [options.displayModerationCommands]
- @param {boolean} [options.displayNoMatchFound]
- @param {Array} [options.domain=[]] the domain to restrict messages on the thread.
- -->
- <t t-name="mail.widget.Thread">
- <t t-if="thread.hasMessages({ 'domain': options.domain || [] })">
- <t t-call="mail.widget.Thread.Content"/>
- </t>
- <t t-elif="options.displayEmptyThread">
- <t t-call="mail.widget.Thread.Empty" />
- </t>
- <div t-elif="options.displayNoMatchFound" class="o_mail_no_content">
- <div class="o_thread_title">No matches found</div>
- <div>No message matches your search. Try to change your search filters.</div>
- </div>
- </t>
-
- <!-- Rendering of thread when messaging not yet ready -->
- <div t-name="mail.widget.ThreadLoading" class="o_mail_thread_loading">
- <i class="o_mail_thread_loading_icon fa fa-spinner fa-spin"/>
- <span>Please wait...</span>
- </div>
-
- <!--
@param {mail.DocumentViewer} widget
-->
<t t-name="DocumentViewer.Content">
@@ -126,513 +99,4 @@
</html>
</t>
- <!--
- When a thread is empty
-
- @param {mail.model.Thread} thread
- -->
- <div t-name="mail.widget.Thread.Empty" class="o_mail_no_content">
- <t t-if="thread.getID() === 'mailbox_inbox'">
- <div class="o_thread_title">Congratulations, your inbox is empty</div>
- <div>New messages appear here.</div>
- </t>
- <t t-if="thread.getID() === 'mailbox_starred'">
- <div class="o_thread_title">No starred messages</div>
- <div>You can mark any message as 'starred', and it shows up in this mailbox.</div>
- </t>
- <t t-if="thread.getID() === 'mailbox_history'">
- <div class="o_thread_title o_neutral_face_icon">No history messages</div>
- <div>Messages marked as read will appear in the history.</div>
- </t>
- <t t-if="thread.getID() === 'mailbox_moderation'">
- <div class="o_thread_title">You have no message to moderate</div>
- <div>Pending moderation messages appear here.</div>
- </t>
- </div>
-
- <!--
- @param {mail.model.AbstractThread} thread
- @param {Object} options
- @param {integer} [options.displayOrder] 1 or -1 ascending (respectively, descending) order for
- the thread messages (from top to bottom)
- @param {Array} [options.domain=[]] the domain to restrict messages on the thread.
- @param {Object} ORDER
- @param {integer} ORDER.ASC=1 messages are ordered by ascending order of IDs, (from top to bottom)
- @param {integer} ORDER.DESC=-1 messages are ordered by descending IDs, (from top to bottom)
-
- _____________ _____________
- | | | |
- | message 1 | | message n |
- | message 2 | | ... |
- | ... | | message 2 |
- | message n | | message 1 |
- |_____________| |_____________|
-
- ORDER: ASC DESC
-
- -->
- <t t-name="mail.widget.Thread.Content">
- <t t-set="messages" t-value="thread.getMessages({ 'domain': options.domain || [] })"/>
- <t t-if="options.displayOrder === ORDER.ASC" t-call="mail.widget.Thread.Content.ASC"/>
- <t t-else="" t-call="mail.widget.Thread.Content.DESC"/>
- </t>
-
- <!--
- @param {mail.model.AbstractThread} thread
- @param {Object} options
- @param {boolean} [options.displayBottomThreadFreeSpace=false]
- @param {boolean} [options.displayLoadMore=false]
-
- _____________
- | |
- | message 1 |
- | message 2 |
- | ... |
- | message n |
- |_____________|
-
- ASC Order
- -->
- <t t-name="mail.widget.Thread.Content.ASC">
- <div class="o_mail_thread_content">
- <t t-if="options.displayLoadMore" t-call="mail.widget.Thread.LoadMore"/>
- <t t-call="mail.widget.Thread.Messages"/>
- <t t-if="options.displayBottomThreadFreeSpace">
- <div class="o_thread_bottom_free_space"/>
- </t>
- </div>
- </t>
-
- <!--
- @param {mail.model.AbstractThread} thread
- @param {Object} options
- @param {boolean} [options.displayLoadMore=false]
- @param {string|integer} [options.messagesSeparatorPosition] 'top' or
- message ID, the separator is placed just after this message.
-
- _____________
- | |
- | message n |
- | ... |
- | message 2 |
- | message 1 |
- |_____________|
-
- DESC Order
-
- -->
- <t t-name="mail.widget.Thread.Content.DESC">
- <div class="o_mail_thread_content">
- <t t-if="options.messagesSeparatorPosition == 'top'" t-call="mail.MessagesSeparator"/>
- <t t-set="messages" t-value="messages.slice().reverse()"/>
- <t t-call="mail.widget.Thread.Messages"/>
- <t t-if="options.displayLoadMore" t-call="mail.widget.Thread.LoadMore"/>
- </div>
- </t>
-
- <!--
- @param {mail.model.AbstractMessage[]} messages messages are ordered based
- on desired display order
- -->
- <t t-name="mail.widget.Thread.Messages">
- <t t-set="current_day" t-value="0"/>
- <t t-foreach="messages" t-as="message">
- <div t-if="current_day !== message.getDateDay()" class="o_thread_date_separator">
- <span class="o_thread_date">
- <t t-esc="message.getDateDay()"/>
- </span>
- <t t-set="current_day" t-value="message.getDateDay()"/>
- </div>
-
- <t t-call="mail.widget.Thread.Message"/>
- </t>
- </t>
-
- <!--
- @param {mail.model.AbstractThread} thread
- @param {string} dateFormat
- @param {Object} options
- @param {mail.model.AbstractMessage} message
- @param {Object} options
- @param {boolean} [options.displayAvatars]
- @param {boolean} [options.displayDocumentLinks]
- @param {boolean} [options.displayNotificationIcons]
- @param {boolean} [options.displayMarkAsRead]
- @param {boolean} [options.displayModerationCommands] when set, display the moderation commands on
- the message. This includes the moderation checkboxes (needs a control panel such as in Discuss app).
- @param {boolean} [options.displayReplyIcons]
- @param {boolean} [options.displayStars]
- @param {boolean} [options.displaySubjectsOnMessages]
- @param {boolean} options.hasMessageAttachmentDeletable
- @param {string|integer} [options.messagesSeparatorPosition] 'top' or
- message ID, the separator is placed just after this message.
- @param {integer} [options.selectedMessageID]
- -->
- <t t-name="mail.widget.Thread.Message">
- <div t-if="!message.isEmpty()" t-att-class="'o_thread_message ' + (message.getID() === options.selectedMessageID ? 'o_thread_selected_message ' : ' ') + (message.isDiscussion() or message.isNotification() ? ' o_mail_discussion ' : ' o_mail_not_discussion ')" t-att-data-message-id="message.getID()">
- <div t-if="options.displayAvatars" class="o_thread_message_sidebar">
- <t t-if="message.hasAuthor()">
- <div t-if="displayAuthorMessages[message.getID()]" class="o_thread_message_sidebar_image">
- <img
- alt=""
- t-att-src="message.getAvatarSource()"
- data-oe-model="res.partner"
- t-att-data-oe-id="message.shouldRedirectToAuthor() ? message.getAuthorID() : ''"
- t-attf-class="o_thread_message_avatar rounded-circle #{message.shouldRedirectToAuthor() ? 'o_mail_redirect' : ''}"/>
- <t t-call="mail.UserStatus">
- <t t-set="status" t-value="message.getAuthorImStatus()"/>
- <t t-set="partnerID" t-value="message.getAuthorID()"/>
- </t>
- </div>
- </t>
- <t t-else="">
- <img t-if="displayAuthorMessages[message.getID()]"
- alt=""
- t-att-src="message.getAvatarSource()"
- class="o_thread_message_avatar rounded-circle"/>
- </t>
- <span t-if="!displayAuthorMessages[message.getID()]" t-att-title="message.getDate().format(dateFormat)" class="o_thread_message_side_date">
- <t t-esc="message.getDate().format('hh:mm')"/>
- </span>
- <i t-if="!displayAuthorMessages[message.getID()] and options.displayStars and message.getType() !== 'notification'"
- t-att-class="'fa o_thread_message_star o_thread_icon ' + (message.isStarred() ? 'fa-star' : 'fa-star-o')"
- t-att-data-message-id="message.getID()" title="Mark as Todo" role="img" aria-label="Mark as todo"/>
- <t t-if="!displayAuthorMessages[message.getID()] and thread.hasSeenFeature()" t-call="mail.widget.Thread.Message.SeenIcon"/>
- </div>
- <div class="o_thread_message_core">
- <p t-if="displayAuthorMessages[message.getID()]" class="o_mail_info text-muted">
- <input t-if="message.needsModeration() and message.needsModerationByUser() and options.displayModerationCommands" type="checkbox" class="moderation_checkbox" t-att-data-message-id="message.getID()"/>
- <t t-if="message.isNote()">
- Note by
- </t>
-
- <strong t-if="message.hasAuthor()"
- data-oe-model="res.partner" t-att-data-oe-id="message.shouldRedirectToAuthor() ? message.getAuthorID() : ''"
- t-attf-class="o_thread_author #{message.shouldRedirectToAuthor() ? 'o_mail_redirect' : ''}">
- <t t-esc="message.getDisplayedAuthor()"/>
- </strong>
- <strong t-elif="message.hasEmailFrom()">
- <a class="text-muted" t-attf-href="mailto:#{message.getEmailFrom()}?subject=Re: #{message.hasSubject() ? message.getSubject() : ''}">
- <t t-esc="message.getEmailFrom()"/>
- </a>
- </strong>
- <strong t-else="" class="o_thread_author">
- <t t-esc="message.getDisplayedAuthor()"/>
- </strong>
-
- - <small class="o_mail_timestamp" t-att-title="message.getDate().format(dateFormat)"><t t-esc="message.getTimeElapsed()"/></small>
- <t t-if="message.isLinkedToDocumentThread() and options.displayDocumentLinks">
- <small>on</small> <a t-att-href="message.getURL()" t-att-data-oe-model="message.getDocumentModel()" t-att-data-oe-id="message.getDocumentID()" class="o_document_link"><t t-esc="message.getDocumentName()"/></a>
- </t>
- <t t-if="message.originatesFromChannel() and (message.getOriginChannelID() !== thread.getID())">
- (<small>from</small> <a t-att-data-oe-id="message.getOriginChannelID()" href="#">#<t t-esc="message.getOriginChannelName()"/></a>)
- </t>
- <span t-if="options.displayNotificationIcons and message.hasNotifications()" class="o_thread_tooltip_container">
- <span name="notification_icon" t-attf-class="d-inline-flex align-items-center o_thread_tooltip o_thread_message_notification {{ message.hasNotificationsError() ? 'o_thread_message_notification_error' : '' }}" t-att-data-message-id="message.getID()" t-att-data-message-type="message.getType()">
- <i t-att-class="message.getNotificationIcon()"/>
- <small t-if="message.getNotificationText()" t-esc="message.getNotificationText()" class="font-weight-bold ml-1"/>
- </span>
- </span>
- <span t-attf-class="o_thread_icons">
- <t t-if="thread.hasSeenFeature()" t-call="mail.widget.Thread.Message.SeenIcon"/>
- <i t-if="options.displayStars and !message.isSystemNotification() and !message.needsModeration()"
- t-att-class="'fa fa-lg o_thread_icon o_thread_message_star ' + (message.isStarred() ? 'fa-star' : 'fa-star-o')"
- t-att-data-message-id="message.getID()" title="Mark as Todo" role="img" aria-label="Mark as Todo"/>
- <i t-if="message.isLinkedToDocumentThread() and options.displayReplyIcons"
- class="fa fa-reply o_thread_icon o_thread_message_reply"
- t-att-data-message-id="message.getID()" title="Reply" role="img" aria-label="Reply"/>
- <i t-if="message.isNeedaction() and options.displayMarkAsRead"
- class="fa fa-check o_thread_icon o_thread_message_needaction"
- t-att-data-message-id="message.getID()" title="Mark as Read" role="img" aria-label="Mark as Read"/>
-
- <t t-if="message.needsModeration() and message.originatesFromChannel()">
- <t t-call="mail.MessageModeration"/>
- </t>
- </span>
- </p>
- <div class="o_thread_message_content">
- <t t-raw="message.getBody()"/>
- <t t-if="message.hasTrackingValues()">
- <t t-if="message.hasSubtypeDescription()">
- <p><t t-esc="message.getSubtypeDescription()"/></p>
- </t>
- <t t-call="mail.widget.Thread.MessageTracking"/>
- </t>
- <p t-if="options.displaySubjectOnMessages and message.shouldDisplaySubject()" class="o_mail_subject">Subject: <t t-esc="message.getSubject()"/></p>
- <t t-if="message.hasAttachments()">
- <div t-if="message.hasImageAttachments()" class="o_attachments_previews">
- <t t-foreach="message.getImageAttachments()" t-as="attachment">
- <t t-call="mail.AttachmentPreview">
- <t t-set="isDeletable" t-value="options.hasMessageAttachmentDeletable"/>
- </t>
- </t>
- </div>
- <div t-if="message.hasNonImageAttachments()" class="o_attachments_list">
- <t t-foreach="message.getNonImageAttachments()" t-as="attachment">
- <t t-call="mail.Attachment">
- <t t-set="isDeletable" t-value="options.hasMessageAttachmentDeletable"/>
- </t>
- </t>
- </div>
- </t>
- </div>
- </div>
- </div>
- <t t-if="options.messagesSeparatorPosition == message.getID()">
- <t t-call="mail.MessagesSeparator"/>
- </t>
- </t>
-
- <!--
- Display the seen icon of a message in the thread.
- It shows the fetch 'check' before the seen 'check'. We change the order in the template
- so that fetch 'check' is on top of 'seen' check (z-index does not work with absolute positioning)
-
- @param {mail.model.Thread} thread
- @param {mail.model.Message} message
- -->
- <t t-name="mail.widget.Thread.Message.SeenIcon">
- <t t-if="message.isMyselfAuthor() and message.getID() >= thread.getLastMessageIDSeenByEveryone()">
- <span t-attf-class="o_mail_thread_message_seen_icon #{thread.hasEveryoneSeen(message) ? 'o_all_seen' : ''}" t-att-data-message-id="message.getID()">
- <t t-if="thread.hasSomeoneFetched(message)">
- <i class="fa fa-check"/>
- </t>
- <t t-if="thread.hasSomeoneSeen(message)">
- <i class="fa fa-check"/>
- </t>
- </span>
- </t>
- </t>
-
- <!--
- Display the popover content when clicking the seen icion of a message in the thread.
-
- List the members that have received the messages, and the members that have seen it.
-
- @param {mail.model.Thread} thread
- @param {mail.model.Message} message
- -->
- <t t-name="mail.widget.Thread.Message.SeenIconPopoverContent">
- <div class="o_mail_thread_message_seen_icon_content">
- <t t-if="thread.hasEveryoneSeen(message)">
- <p>Seen by Everyone</p>
- </t>
- <t t-else="">
- <t t-if="thread.hasSomeoneSeen(message)">
- <t t-set="seen_members" t-value="thread.getSeenMembers(message)"/>
- Seen by:
- <ul>
- <li t-foreach="seen_members" t-as="member">
- <t t-esc="member.name"/> (<t t-esc="member.email"/>)
- </li>
- </ul>
- </t>
- <t t-if="thread.hasSomeoneFetched(message)">
- <t t-if="thread.hasEveryoneFetched(message)">
- <p>Received by Everyone</p>
- </t>
- <t t-else="">
- <t t-set="fetched_members" t-value="thread.getFetchedNotSeenMembers(message)"/>
- <t t-if="!_.isEmpty(fetched_members)">
- Received by:
- <ul>
- <li t-foreach="fetched_members" t-as="member">
- <t t-esc="member.name"/> (<t t-esc="member.email"/>)
- </li>
- </ul>
- </t>
- </t>
- </t>
- </t>
- </div>
- </t>
-
- <!--
- @param {Object[]} notifications: list of notifications
- A notification is an object with at least the following keys:
- {notification_status, partner_name}
- -->
- <t t-name="mail.widget.Thread.Message.MailTooltip">
- <div t-foreach="notifications" t-as="notification">
- <span name="notification_status" class="d-inline-block text-center o_thread_tooltip_icon">
- <i t-if="notification.notification_status === 'sent'" class='fa fa-check' title="Sent" role="img" aria-label="Sent"/>
- <i t-if="notification.notification_status === 'bounce'" class='fa fa-exclamation text-danger' title="Bounced" role="img" aria-label="Bounced"/>
- <i t-if="notification.notification_status === 'exception'" class='fa fa-exclamation text-danger' title="Error" role="img" aria-label="Error"/>
- <i t-if="notification.notification_status === 'ready'" class='fa fa-send-o' title="Ready" role="img" aria-label="Ready"/>
- <i t-if="notification.notification_status === 'canceled'" class='fa fa-trash-o' title="Canceled" role="img" aria-label="Canceled"/>
- </span>
- <span name="partner_name" t-esc="notification.partner_name"/>
- </div>
- </t>
- <!--
- @param {mail.model.Message} message
- @param {Object} options
- @param {boolean} [options.displayModerationCommands]
- -->
- <t t-name="mail.MessageModeration">
- <i t-if="message.isMyselfAuthor()" class="text-danger" title="Your message is pending moderation"><b>Pending moderation</b></i>
- <t t-elif="message.needsModerationByUser()">
- <t t-if="options.displayModerationCommands" t-call="mail.MessageModerationDecision"/>
- <i t-else="" class="text-danger" title="Open Channel in Discuss to moderate"><b>Pending moderation</b></i>
- </t>
- </t>
-
- <!--
- @param {mail.model.Message} message
- -->
- <t t-name="mail.MessageModerationDecision">
- <i class="o_thread_icon ml4 o_thread_message_moderation text-success"
- t-att-data-message-id="message.getID()" data-decision="accept" title="Accept"><b>Accept |</b></i>
- <i class="o_thread_icon ml4 o_thread_message_moderation text-danger"
- t-att-data-message-id="message.getID()" data-decision="reject" title="Remove message with explanation"><b>Reject |</b></i>
- <i class="o_thread_icon ml4 o_thread_message_moderation text-danger"
- t-att-data-message-id="message.getID()" data-decision="discard" title="Remove message without explanation"><b>Discard |</b></i>
- <i class="o_thread_icon ml4 o_thread_message_moderation text-success"
- t-att-data-message-id="message.getID()" data-decision="allow" title="Add this email address to white list of people"><b>Always Allow |</b></i>
- <i class="o_thread_icon ml4 o_thread_message_moderation text-danger"
- t-att-data-message-id="message.getID()" data-decision="ban" title="Ban this email address"><b>Ban</b></i>
- </t>
-
- <t t-name="mail.MessagesSeparator">
- <div class="o_thread_new_messages_separator">
- <span class="o_thread_separator_label">New messages</span>
- </div>
- </t>
-
- <!--
- @param {mail.model.Message} message
- -->
- <t t-name="mail.widget.Thread.MessageTracking">
- <ul class="o_mail_thread_message_tracking">
- <t t-foreach='message.getTrackingValues()' t-as='value'>
- <li>
- <t t-esc="value.changed_field"/>:
- <t t-if="value.old_value">
- <span> <t t-esc="value.old_value || ((value.field_type !== 'boolean') and '')"/> </span>
- <span t-if="value.old_value !== value.new_value" class="fa fa-long-arrow-right" role="img" aria-label="Changed" title="Changed"/>
- </t>
- <span t-if="value.old_value !== value.new_value">
- <t t-esc="value.new_value || ((value.field_type !== 'boolean') and '')"/>
- </span>
- </li>
- </t>
- </ul>
- </t>
-
- <!--
- @param {Array} attachments
- -->
- <t t-name="mail.composer.Attachments">
- <div t-if="attachments.length > 0" class="o_attachments o_attachments_list">
- <t t-foreach="attachments" t-as='attachment'>
- <t t-call="mail.Attachment">
- <t t-set="editable" t-value="true"/>
- </t>
- </t>
- </div>
- </t>
-
- <!--
- @param {Object} attachment
- @param {integer} attachment.id
- @param {string} attachment.name
- @param {string} attachment.url
- @param {boolean} [isDeletable=false]
- -->
- <t t-name="mail.AttachmentPreview">
- <div class="o_attachment" t-att-title="attachment.name">
- <div class="o_attachment_wrap">
- <div class="o_image_box">
- <div class="o_attachment_image" t-attf-style="background-image:url('/web/image/#{attachment.id}/160x160/?crop=true')"/>
- <div t-attf-class="o_image_overlay o_attachment_view" t-att-data-id="attachment.id">
- <span t-if="isDeletable" class="fa fa-times o_attachment_delete_cross" t-att-title="'Delete ' + attachment.name" t-att-data-id="attachment.id" t-att-data-name="attachment.name"/>
- <span class="o_attachment_title text-white"><t t-esc="attachment.name"/></span>
- <a class="o_attachment_download" t-att-href='attachment.url'>
- <i t-attf-class="fa fa-download text-white" t-att-title="'Download ' + attachment.name" role="img" aria-label="Download"></i>
- </a>
- </div>
- </div>
- </div>
- </div>
- </t>
-
- <!--
- @param {Object} attachment
- @param {string} attachment.filename
- @param {integer} attachment.id
- @param {string} [attachment.mimetype]
- @param {string} attachment.name
- @param {boolean} attachment.upload
- @param {string} attachment.url
- @param {boolean} [editable=false] if set, it means the attachment is rendered in the composer.
- Some changes are required in that case, such as "delete" button is not visible (pretty unlink is used instead).
- @param {boolean} [isDeletable=false]
- -->
- <t t-name="mail.Attachment">
- <t t-set="type" t-value="attachment.mimetype and attachment.mimetype.split('/').shift()"/>
- <div t-attf-class="o_attachment #{ editable ? 'o_attachment_editable' : '' } #{attachment.upload ? 'o_attachment_uploading' : ''}" t-att-title="attachment.name">
- <div class="o_attachment_wrap">
- <span t-if="!editable and isDeletable" class="fa fa-times o_attachment_delete_cross" t-att-title="'Delete ' + attachment.name" t-att-data-id="attachment.id" t-att-data-name="attachment.name"/>
- <t t-set="has_preview" t-value="type == 'image' or type == 'video' or attachment.mimetype == 'application/pdf'"/>
- <t t-set="ext" t-value="attachment.filename.split('.').pop()"/>
-
- <div t-attf-class="o_image_box float-left #{has_preview ? 'o_attachment_view' : ''}" t-att-data-id="attachment.id">
- <div t-if="has_preview"
- class="o_image o_hover"
- t-att-style="type == 'image' ? 'background-image:url(/web/image/' + attachment.id + '/38x38/?crop=true' : '' "
- t-att-data-mimetype="attachment.mimetype">
- </div>
- <a t-elif="!editable" t-att-href='attachment.url' t-att-title="'Download ' + attachment.name" aria-label="Download">
- <span class="o_image o_hover" t-att-data-mimetype="attachment.mimetype" t-att-data-ext="ext"/>
- </a>
- <span t-else="" class="o_image" t-att-data-mimetype="attachment.mimetype" t-att-data-ext="ext" role="img" aria-label="Document not downloadable"/>
- </div>
-
- <div class="caption">
- <span t-if="has_preview or editable" t-attf-class="ml4 #{has_preview? 'o_attachment_view' : ''}" t-att-data-id="attachment.id"><t t-esc='attachment.name'/></span>
- <a t-else="" class="ml4" t-att-href="attachment.url" t-att-title="'Download ' + attachment.name"><t t-esc='attachment.name'/></a>
- </div>
- <div t-if="editable" class="caption small">
- <b t-attf-class="ml4 small text-uppercase #{has_preview? 'o_attachment_view' : ''}" t-att-data-id="attachment.id"><t t-esc="ext"/></b>
- <div class="progress o_attachment_progress_bar">
- <div class="progress-bar progress-bar-striped active" style="width: 100%">Uploading</div>
- </div>
- </div>
- <div t-if="!editable" class="caption small">
- <b t-if="has_preview" class="ml4 small text-uppercase o_attachment_view" t-att-data-id="attachment.id"><t t-esc="ext"/></b>
- <a t-else="" class="ml4 small text-uppercase" t-att-href="attachment.url" t-att-title="'Download ' + attachment.name"><b><t t-esc='ext'/></b></a>
- <a class="ml4 o_attachment_download float-right" t-att-title="'Download ' + attachment.name" t-att-href='attachment.url'><i t-attf-class="fa fa-download" role="img" aria-label="Download"/></a>
- </div>
- <div t-if="editable" class="o_attachment_uploaded"><i class="text-success fa fa-check" role="img" aria-label="Uploaded" title="Uploaded"/></div>
- <div t-if="editable" class="o_attachment_delete" t-att-data-id="attachment.id"><span class="text-white" role="img" aria-label="Delete" title="Delete">×</span></div>
- </div>
- </div>
- </t>
-
- <!--
- @param {Object} options
- @param {boolean} [options.loadMoreOnScroll]
- -->
- <t t-name="mail.widget.Thread.LoadMore">
- <div class="o_thread_show_more">
- <t t-if="options.loadMoreOnScroll">
- <span><i class="fa fa-spinner fa-spin" role="img" aria-label="Please wait" title="Please wait"/> Loading older messages... </span>
- </t>
- <t t-else="">
- <button class="btn btn-link">-------- Show older messages --------</button>
- </t>
- </div>
- </t>
-
- <!--
- @param {mail.model.Thread} thread with typing feature
- -->
- <t t-name="mail.ThreadTypingIcon">
- <span class="o_mail_thread_typing_icon" t-att-title="thread.getTypingMembersToText()">
- <span class="o_mail_thread_typing_icon_dot"/>
- <span class="o_mail_thread_typing_icon_dot"/>
- <span class="o_mail_thread_typing_icon_dot"/>
- </span>
- </t>
-
</templates>
diff --git a/addons/mail/static/src/xml/thread_window.xml b/addons/mail/static/src/xml/thread_window.xml
deleted file mode 100644
index 1e8d3e97c2e..00000000000
--- a/addons/mail/static/src/xml/thread_window.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<templates xml:space="preserve">
-
- <!--
- @param {mail.ThreadWindow} widget
- -->
- <t t-name="mail.ThreadWindow" t-extend="mail.AbstractThreadWindow">
- <t t-jquery=".o_thread_window_header" t-operation="after">
- <t t-if="widget.hasThread()">
- <t t-if="widget.getThread().hasOutOfOffice()">
- <t t-call="mail.thread.OutOfOffice">
- <t t-set="thread" t-value="widget.getThread()"/>
- </t>
- </t>
- </t>
- <div t-else="" class="o_thread_search_input">
- <span> To: </span>
- <input type="text" placeholder="User name"/>
- </div>
- </t>
- </t>
-
- <!--
- @param {string} expandTitle text to display on mouse hover (title attribute)
- -->
- <t t-extend="mail.AbstractThreadWindow.HeaderContent">
- <t t-jquery=".o_thread_window_buttons" t-operation="prepend">
- <a href="#" class="o_thread_window_expand fa fa-expand" t-att-title="expandTitle" t-att-aria-label="expandTitle"/>
- </t>
- </t>
-
-</templates>