[IMP] mail, *: make discuss component templates more compact

*: hr_holidays, im_livechat, snailmail, website_livechat

Clean template of discuss component templates, so that they
are more appropriately compact, which makes it easier to
read the layout at a glance.

Task-3055780

Part-of: odoo/odoo#105099
This commit is contained in:
Alexandre Kühn
2022-11-06 00:28:15 +01:00
parent 9851c62635
commit 98323245bc
101 changed files with 1948 additions and 2684 deletions
@@ -2,15 +2,9 @@
<templates xml:space="preserve">
<t t-inherit="mail.PersonaImStatusIconView" t-inherit-mode="extension">
<xpath expr="//*[@name='root']" position="inside">
<t t-if="persona.im_status === 'leave_online'">
<i class="o_PersonaImStatusIconView_icon o-online fa fa-plane fa-stack-1x" title="Online" role="img" aria-label="User is online"/>
</t>
<t t-if="persona.im_status === 'leave_away'">
<i class="o_PersonaImStatusIconView_icon o-away fa fa-plane fa-stack-1x text-warning" title="Away" role="img" aria-label="User is away"/>
</t>
<t t-if="persona.im_status === 'leave_offline'">
<i class="o_PersonaImStatusIconView_icon o-offline fa fa-plane fa-stack-1x text-700" title="Out of office" role="img" aria-label="User is out of office"/>
</t>
<i t-if="persona.im_status === 'leave_online'" class="o_PersonaImStatusIconView_icon o-online fa fa-plane fa-stack-1x" title="Online" role="img" aria-label="User is online"/>
<i t-if="persona.im_status === 'leave_away'" class="o_PersonaImStatusIconView_icon o-away fa fa-plane fa-stack-1x text-warning" title="Away" role="img" aria-label="User is away"/>
<i t-if="persona.im_status === 'leave_offline'" class="o_PersonaImStatusIconView_icon o-offline fa fa-plane fa-stack-1x text-700" title="Out of office" role="img" aria-label="User is out of office"/>
</xpath>
</t>
</templates>
@@ -2,15 +2,9 @@
<templates xml:space="preserve">
<t t-inherit="mail.ThreadIconView" t-inherit-mode="extension">
<xpath expr="//*[@name='noImStatusCondition']" position="before">
<t t-elif="thread.channel.correspondent.im_status === 'leave_online'">
<div class="o_ThreadIconView_online fa fa-fw fa-plane" title="Online"/>
</t>
<t t-elif="thread.channel.correspondent.im_status === 'leave_away'">
<div class="o_ThreadIconView_away fa fa-fw fa-plane text-warning" title="Away"/>
</t>
<t t-elif="thread.channel.correspondent.im_status === 'leave_offline'">
<div class="o_ThreadIconView_offline fa fa-fw fa-plane" title="Out of office"/>
</t>
<div t-elif="thread.channel.correspondent.im_status === 'leave_online'" class="o_ThreadIconView_online fa fa-fw fa-plane" title="Online"/>
<div t-elif="thread.channel.correspondent.im_status === 'leave_away'" class="o_ThreadIconView_away fa fa-fw fa-plane text-warning" title="Away"/>
<div t-elif="thread.channel.correspondent.im_status === 'leave_offline'" class="o_ThreadIconView_offline fa fa-fw fa-plane" title="Out of office"/>
</xpath>
</t>
</templates>
@@ -2,9 +2,7 @@
<templates xml:space="preserve">
<t t-inherit="mail.ThreadView" t-inherit-mode="extension">
<xpath expr="//*[@name='loadingCondition']" position="before">
<t t-if="thread.channel and thread.channel.correspondent and thread.channel.correspondent.outOfOfficeText">
<div class="o_ThreadView_outOfOffice alert alert-primary" t-esc="thread.channel.correspondent.outOfOfficeText" role="alert"/>
</t>
<div t-if="thread.channel and thread.channel.correspondent and thread.channel.correspondent.outOfOfficeText" class="o_ThreadView_outOfOffice alert alert-primary" t-esc="thread.channel.correspondent.outOfOfficeText" role="alert"/>
</xpath>
</t>
</templates>
@@ -3,12 +3,10 @@
<t t-inherit="mail.DiscussSidebarView" t-inherit-mode="extension">
<xpath expr="//*[@name='beforeCategoryChat']" position="before">
<t t-set="categoryLivechat" t-value="owner.discuss.categoryLivechat"/>
<t t-if="categoryLivechat and categoryLivechat.categoryItems.length">
<DiscussSidebarCategory
className="'o_DiscussSidebarView_category o_DiscussSidebarView_categoryLivechat'"
record="categoryLivechat"
/>
</t>
<DiscussSidebarCategory t-if="categoryLivechat and categoryLivechat.categoryItems.length"
className="'o_DiscussSidebarView_category o_DiscussSidebarView_categoryLivechat'"
record="categoryLivechat"
/>
</xpath>
</t>
</templates>
@@ -3,15 +3,11 @@
<t t-inherit="mail.ThreadIconView" t-inherit-mode="extension">
<xpath expr="//*[@name='root']" position="inside">
<t t-elif="thread.channel and thread.channel.channel_type === 'livechat'">
<t t-if="threadTypingIconView">
<ThreadTypingIconView
className="'o_ThreadIconView_typing'"
record="threadTypingIconView"
/>
</t>
<t t-else="">
<div class="fa fa-fw fa-comments" title="Livechat"/>
</t>
<ThreadTypingIconView t-if="threadTypingIconView"
className="'o_ThreadIconView_typing'"
record="threadTypingIconView"
/>
<div t-else="" class="fa fa-fw fa-comments" title="Livechat"/>
</t>
</xpath>
</t>
@@ -6,6 +6,6 @@
class="o_ActivityException float-end mt-1"
t-att-class="textClass"
title="This record has an exception activity."
></div>
/>
</t>
</templates>
@@ -3,18 +3,14 @@
<t t-name="mail.ActivityListView" owl="1">
<div class="o_ActivityListView d-flex flex-column" t-ref="root">
<div class="o_ActivityListView_activityList d-flex flex-column flex-grow-1">
<t t-if="activityListViewItems.length === 0">
<span class="p-3 text-center fst-italic text-500 border-bottom">Schedule activities to help you get things done.</span>
</t>
<span t-if="activityListViewItems.length === 0" class="p-3 text-center fst-italic text-500 border-bottom">Schedule activities to help you get things done.</span>
<t t-if="overdueActivityListViewItems.length > 0">
<div class="d-flex bg-100 py-2 border-bottom">
<span class="o_ActivityListView_overdueTitle text-danger fw-bold mx-3">Overdue</span>
<span class="flex-grow-1"/>
<span class="badge rounded-pill text-bg-danger mx-3 align-self-center" t-esc="overdueActivityListViewItems.length"/>
</div>
<t t-foreach="overdueActivityListViewItems" t-as="activityListViewItem" t-key="activityListViewItem">
<ActivityListViewItem record="activityListViewItem"/>
</t>
<ActivityListViewItem t-foreach="overdueActivityListViewItems" t-as="activityListViewItem" t-key="activityListViewItem" record="activityListViewItem"/>
</t>
<t t-if="todayActivityListViewItems.length > 0">
<div class="d-flex bg-100 py-2 border-bottom">
@@ -22,9 +18,7 @@
<span class="flex-grow-1"/>
<span class="badge rounded-pill text-bg-warning mx-3 align-self-center" t-esc="todayActivityListViewItems.length"/>
</div>
<t t-foreach="todayActivityListViewItems" t-as="activityListViewItem" t-key="activityListViewItem">
<ActivityListViewItem record="activityListViewItem"/>
</t>
<ActivityListViewItem t-foreach="todayActivityListViewItems" t-as="activityListViewItem" t-key="activityListViewItem" record="activityListViewItem"/>
</t>
<t t-if="plannedActivityListViewItems.length > 0">
<div class="d-flex bg-100 py-2 border-bottom">
@@ -32,9 +26,7 @@
<span class="flex-grow-1"/>
<span class="badge rounded-pill text-bg-success mx-3 align-self-center" t-esc="plannedActivityListViewItems.length"/>
</div>
<t t-foreach="plannedActivityListViewItems" t-as="activityListViewItem" t-key="activityListViewItem">
<ActivityListViewItem record="activityListViewItem"/>
</t>
<ActivityListViewItem t-foreach="plannedActivityListViewItems" t-as="activityListViewItem" t-key="activityListViewItem" record="activityListViewItem"/>
</t>
</div>
<button class="o_ActivityListView_addActivityButton btn btn-secondary p-3 text-center" t-on-click="onClickAddActivityButton">
@@ -4,12 +4,8 @@
<div class="o_ActivityListViewItem d-flex flex-column border-bottom py-2">
<div class="o_ActivityListViewItem_container d-flex align-items-baseline ms-3 me-1">
<i t-if="activity.icon" class="fa small me-2" t-attf-class="{{ activity.icon }}" role="img"/>
<t t-if="activity.summary">
<b class="text-900 me-2 text-truncate flex-grow-1 flex-basis-0" t-esc="activity.summary"/>
</t>
<t t-if="!activity.summary and activity.type">
<b class="text-900 me-2 text-truncate flex-grow-1" t-esc="activity.type.displayName"/>
</t>
<b t-if="activity.summary" class="text-900 me-2 text-truncate flex-grow-1 flex-basis-0" t-esc="activity.summary"/>
<b t-if="!activity.summary and activity.type" class="text-900 me-2 text-truncate flex-grow-1" t-esc="activity.type.displayName"/>
<button t-if="hasEditButton" class="o_ActivityListViewItem_editButton btn btn-sm btn-link" t-on-click="onClickEditActivityButton">
<i class="fa fa-pencil"/>
</button>
@@ -2,142 +2,107 @@
<templates xml:space="preserve">
<t t-name="mail.ActivityView" owl="1">
<div class="o_ActivityView d-flex py-2 px-3" t-attf-class="{{ className }}" t-on-click="onClickActivity" t-ref="root">
<div class="o_ActivityView_sidebar me-3">
<div class="o_ActivityView_user position-relative h-100 w-100">
<t t-if="activity.assignee">
<img class="o_ActivityView_userAvatar rounded-circle h-100 w-100 o_object_fit_cover" t-attf-src="/web/image/res.users/{{ activity.assignee.id }}/avatar_128" t-att-alt="activity.assignee.nameOrDisplayName"/>
</t>
<div class="o_ActivityView_iconContainer d-flex align-items-center justify-content-center rounded-circle w-50 h-50"
t-att-class="{
'text-bg-success': activity.state === 'planned',
'text-bg-warning': activity.state === 'today',
'text-bg-danger': activity.state === 'overdue',
}"
>
<i class="o_ActivityView_icon fa small" t-attf-class="{{ activity.icon }}"/>
</div>
<div class="o_ActivityView d-flex py-2 px-3" t-attf-class="{{ className }}" t-on-click="onClickActivity" t-ref="root">
<div class="o_ActivityView_sidebar me-3">
<div class="o_ActivityView_user position-relative h-100 w-100">
<img t-if="activity.assignee" class="o_ActivityView_userAvatar rounded-circle h-100 w-100 o_object_fit_cover" t-attf-src="/web/image/res.users/{{ activity.assignee.id }}/avatar_128" t-att-alt="activity.assignee.nameOrDisplayName"/>
<div class="o_ActivityView_iconContainer d-flex align-items-center justify-content-center rounded-circle w-50 h-50"
t-att-class="{
'text-bg-success': activity.state === 'planned',
'text-bg-warning': activity.state === 'today',
'text-bg-danger': activity.state === 'overdue',
}"
>
<i class="o_ActivityView_icon fa small" t-attf-class="{{ activity.icon }}"/>
</div>
</div>
<div class="o_ActivityView_core">
<div class="o_ActivityView_info d-flex align-items-baseline">
<div class="o_ActivityView_dueDateText me-2"
t-att-class="{
'text-danger': activity.state === 'overdue',
'text-success': activity.state === 'planned',
'text-warning': activity.state === 'today',
}"
>
<b t-esc="delayLabel"/>
</div>
<t t-if="activity.summary">
<b class="o_ActivityView_summary text-900 me-2">
<t t-esc="summary"/>
</b>
</t>
<t t-elif="activity.type">
<b class="o_ActivityView_summary o_ActivityView_type text-900 me-2">
<t t-esc="activity.type.displayName"/>
</b>
</t>
<t t-if="activity.assignee">
<div class="o_ActivityView_userName">
<t t-esc="assignedUserText"/>
</div>
</t>
<a
href="#"
class="o_ActivityView_detailsButton btn py-0"
t-att-class="areDetailsVisible ? 'text-primary' : 'btn-link btn-primary'"
t-att-aria-expanded="areDetailsVisible ? 'true' : 'false'"
t-on-click="onClickDetailsButton"
role="button"
>
<i class="fa fa-info-circle" role="img" title="Info" aria-label="Info"/>
</a>
</div>
<t t-if="areDetailsVisible">
<div class="o_ActivityView_details">
<div class="d-md-table table table-sm mt-2 mb-3">
<div t-if="activity.type" class="d-md-table-row mb-3">
<div class="d-md-table-cell fw-bold text-md-end m-0 py-md-1 px-md-4">Activity type</div>
<div class="o_ActivityView_type d-md-table-cell py-md-1 pe-4">
<t t-esc="activity.type.displayName"/>
</div>
</div>
<div t-if="activity.creator" class="d-md-table-row mb-3">
<div class="d-md-table-cell fw-bold text-md-end m-0 py-md-1 px-md-4">Created</div>
<div class="o_ActivityView_detailsCreation d-md-table-cell py-md-1 pe-4">
<t t-esc="formattedCreateDatetime"/>, <br t-if="messaging.device.isSmall"/>by
<img class="o_ActivityView_detailsUserAvatar o_ActivityView_detailsCreatorAvatar ms-1 me-1 rounded-circle align-text-bottom p-0" t-attf-src="/web/image/res.users/{{ activity.creator.id }}/avatar_128" t-att-title="activity.creator.nameOrDisplayName" t-att-alt="activity.creator.nameOrDisplayName"/>
<b class="o_ActivityView_detailsCreator">
<t t-esc="activity.creator.nameOrDisplayName"/>
</b>
</div>
</div>
<div t-if="activity.assignee" class="d-md-table-row mb-3">
<div class="d-md-table-cell fw-bold text-md-end m-0 py-md-1 px-md-4">Assigned to</div>
<div class="o_ActivityView_detailsAssignation d-md-table-cell py-md-1 pe-4">
<img class="o_ActivityView_detailsUserAvatar o_ActivityView_detailsAssignationUserAvatar me-1 rounded-circle align-text-bottom p-0" t-attf-src="/web/image/res.users/{{ activity.assignee.id }}/avatar_128" t-att-title="activity.assignee.nameOrDisplayName" t-att-alt="activity.assignee.nameOrDisplayName"/>
<b t-esc="activity.assignee.nameOrDisplayName"/>
</div>
</div>
<div class="d-md-table-row">
<div class="d-md-table-cell fw-bold text-md-end m-0 py-md-1 px-md-4">Due on</div>
<div class="o_ActivityView_detailsDueDate d-md-table-cell py-md-1 pe-4">
<span class="o_ActivityView_deadlineDateText"
t-att-class="{
'text-danger': activity.state === 'overdue',
'text-success': activity.state === 'planned',
'text-warning': activity.state === 'today',
}"
>
<t t-esc="formattedDeadlineDate"/>
</span>
</div>
</div>
</div>
</div>
</t>
<t t-if="activity.note">
<div class="o_ActivityView_note">
<t t-out="activity.noteAsMarkup"/>
</div>
</t>
<t t-if="mailTemplateViews.length > 0">
<div class="o_ActivityView_mailTemplates">
<t t-foreach="mailTemplateViews" t-as="mailTemplateView" t-key="mailTemplateView.localId">
<MailTemplateView
className="'o_ActivityView_mailTemplate'"
record="mailTemplateView"
/>
</t>
</div>
</t>
<t t-if="activity.canWrite">
<div name="tools" class="o_ActivityView_tools d-flex">
<button class="o_ActivityView_toolButton o_ActivityView_markDoneButton btn btn-link btn-primary pt-0 ps-0" t-att-title="markDoneText" t-ref="markDoneButton" t-on-click="onClickMarkDoneButton">
<i class="fa fa-check"/> Mark Done
</button>
<t t-if="fileUploader">
<button class="o_ActivityView_toolButton o_ActivityView_uploadButton btn btn-link btn-primary pt-0 ps-0" t-on-click="onClickUploadDocument">
<i class="fa fa-upload"/> Upload Document
</button>
</t>
<button class="o_ActivityView_toolButton o_ActivityView_editButton btn btn-link btn-primary pt-0" t-on-click="onClickEdit">
<i class="fa fa-pencil"/> Edit
</button>
<button class="o_ActivityView_toolButton o_ActivityView_cancelButton btn btn-link btn-primary pt-0" t-on-click="onClickCancel" >
<i class="fa fa-times"/> Cancel
</button>
</div>
</t>
</div>
</div>
<div class="o_ActivityView_core">
<div class="o_ActivityView_info d-flex align-items-baseline">
<div class="o_ActivityView_dueDateText me-2"
t-att-class="{
'text-danger': activity.state === 'overdue',
'text-success': activity.state === 'planned',
'text-warning': activity.state === 'today',
}"
>
<b t-esc="delayLabel"/>
</div>
<b t-if="activity.summary" class="o_ActivityView_summary text-900 me-2" t-esc="summary"/>
<b t-elif="activity.type" class="o_ActivityView_summary o_ActivityView_type text-900 me-2" t-esc="activity.type.displayName"/>
<div t-if="activity.assignee" class="o_ActivityView_userName" t-esc="assignedUserText"/>
<a
href="#"
class="o_ActivityView_detailsButton btn py-0"
t-att-class="areDetailsVisible ? 'text-primary' : 'btn-link btn-primary'"
t-att-aria-expanded="areDetailsVisible ? 'true' : 'false'"
t-on-click="onClickDetailsButton"
role="button"
>
<i class="fa fa-info-circle" role="img" title="Info" aria-label="Info"/>
</a>
</div>
<div t-if="areDetailsVisible" class="o_ActivityView_details">
<div class="d-md-table table table-sm mt-2 mb-3">
<div t-if="activity.type" class="d-md-table-row mb-3">
<div class="d-md-table-cell fw-bold text-md-end m-0 py-md-1 px-md-4">Activity type</div>
<div class="o_ActivityView_type d-md-table-cell py-md-1 pe-4" t-esc="activity.type.displayName"/>
</div>
<div t-if="activity.creator" class="d-md-table-row mb-3">
<div class="d-md-table-cell fw-bold text-md-end m-0 py-md-1 px-md-4">Created</div>
<div class="o_ActivityView_detailsCreation d-md-table-cell py-md-1 pe-4">
<t t-esc="formattedCreateDatetime"/>, <br t-if="messaging.device.isSmall"/>by
<img class="o_ActivityView_detailsUserAvatar o_ActivityView_detailsCreatorAvatar ms-1 me-1 rounded-circle align-text-bottom p-0" t-attf-src="/web/image/res.users/{{ activity.creator.id }}/avatar_128" t-att-title="activity.creator.nameOrDisplayName" t-att-alt="activity.creator.nameOrDisplayName"/>
<b class="o_ActivityView_detailsCreator" t-esc="activity.creator.nameOrDisplayName"/>
</div>
</div>
<div t-if="activity.assignee" class="d-md-table-row mb-3">
<div class="d-md-table-cell fw-bold text-md-end m-0 py-md-1 px-md-4">Assigned to</div>
<div class="o_ActivityView_detailsAssignation d-md-table-cell py-md-1 pe-4">
<img class="o_ActivityView_detailsUserAvatar o_ActivityView_detailsAssignationUserAvatar me-1 rounded-circle align-text-bottom p-0" t-attf-src="/web/image/res.users/{{ activity.assignee.id }}/avatar_128" t-att-title="activity.assignee.nameOrDisplayName" t-att-alt="activity.assignee.nameOrDisplayName"/>
<b t-esc="activity.assignee.nameOrDisplayName"/>
</div>
</div>
<div class="d-md-table-row">
<div class="d-md-table-cell fw-bold text-md-end m-0 py-md-1 px-md-4">Due on</div>
<div class="o_ActivityView_detailsDueDate d-md-table-cell py-md-1 pe-4">
<span class="o_ActivityView_deadlineDateText"
t-att-class="{
'text-danger': activity.state === 'overdue',
'text-success': activity.state === 'planned',
'text-warning': activity.state === 'today',
}"
t-esc="formattedDeadlineDate"
/>
</div>
</div>
</div>
</div>
<div t-if="activity.note" class="o_ActivityView_note" t-out="activity.noteAsMarkup"/>
<div t-if="mailTemplateViews.length > 0" class="o_ActivityView_mailTemplates">
<t t-foreach="mailTemplateViews" t-as="mailTemplateView" t-key="mailTemplateView.localId">
<MailTemplateView
className="'o_ActivityView_mailTemplate'"
record="mailTemplateView"
/>
</t>
</div>
<div t-if="activity.canWrite" name="tools" class="o_ActivityView_tools d-flex">
<button class="o_ActivityView_toolButton o_ActivityView_markDoneButton btn btn-link btn-primary pt-0 ps-0" t-att-title="markDoneText" t-ref="markDoneButton" t-on-click="onClickMarkDoneButton">
<i class="fa fa-check"/> Mark Done
</button>
<button t-if="fileUploader" class="o_ActivityView_toolButton o_ActivityView_uploadButton btn btn-link btn-primary pt-0 ps-0" t-on-click="onClickUploadDocument">
<i class="fa fa-upload"/> Upload Document
</button>
<button class="o_ActivityView_toolButton o_ActivityView_editButton btn btn-link btn-primary pt-0" t-on-click="onClickEdit">
<i class="fa fa-pencil"/> Edit
</button>
<button class="o_ActivityView_toolButton o_ActivityView_cancelButton btn btn-link btn-primary pt-0" t-on-click="onClickCancel" >
<i class="fa fa-times"/> Cancel
</button>
</div>
</div>
</div>
</t>
</templates>
@@ -2,42 +2,24 @@
<templates xml:space="preserve">
<t t-name="mail.ActivityBoxView" owl="1">
<div class="o_ActivityBoxView" t-attf-class="{{ className }}" t-ref="root">
<a href="#" role="button" class="o_ActivityBoxView_title btn d-flex align-items-center mt-4 p-0 w-100 fw-bold" t-att-aria-expanded="isActivityListVisible ? 'true' : 'false'" t-on-click="onClickActivityBoxTitle">
<hr class="o_ActivityBoxView_titleLine w-auto flex-grow-1 me-3" />
<span class="o_ActivityBoxView_titleText">
<i class="fa fa-fw" t-att-class="isActivityListVisible ? 'fa-caret-down' : 'fa-caret-right'"/>
Planned activities
</span>
<t t-if="!isActivityListVisible">
<span class="o_ActivityBoxView_titleBadges ms-2">
<t t-if="chatter.thread.overdueActivities.length > 0">
<span class="o_ActivityBoxView_titleBadge me-1 badge text-bg-danger">
<t t-esc="chatter.thread.overdueActivities.length"/>
</span>
</t>
<t t-if="chatter.thread.todayActivities.length > 0">
<span class="o_ActivityBoxView_titleBadge me-1 badge text-bg-warning">
<t t-esc="chatter.thread.todayActivities.length"/>
</span>
</t>
<t t-if="chatter.thread.futureActivities.length > 0">
<span class="o_ActivityBoxView_titleBadge me-1 badge text-bg-success">
<t t-esc="chatter.thread.futureActivities.length"/>
</span>
</t>
</span>
</t>
<hr class="o_ActivityBoxView_titleLine w-auto flex-grow-1 ms-3"/>
</a>
<t t-if="isActivityListVisible">
<div class="o_ActivityBoxView_activityList">
<t t-foreach="activityViews" t-as="activityView" t-key="activityView.localId">
<ActivityView className="'o_ActivityBoxView_activity'" record="activityView"/>
</t>
</div>
</t>
<div class="o_ActivityBoxView" t-attf-class="{{ className }}" t-ref="root">
<a href="#" role="button" class="o_ActivityBoxView_title btn d-flex align-items-center mt-4 p-0 w-100 fw-bold" t-att-aria-expanded="isActivityListVisible ? 'true' : 'false'" t-on-click="onClickActivityBoxTitle">
<hr class="o_ActivityBoxView_titleLine w-auto flex-grow-1 me-3" />
<span class="o_ActivityBoxView_titleText">
<i class="fa fa-fw" t-att-class="isActivityListVisible ? 'fa-caret-down' : 'fa-caret-right'"/>
Planned activities
</span>
<span t-if="!isActivityListVisible" class="o_ActivityBoxView_titleBadges ms-2">
<span t-if="chatter.thread.overdueActivities.length > 0" class="o_ActivityBoxView_titleBadge me-1 badge text-bg-danger" t-esc="chatter.thread.overdueActivities.length"/>
<span t-if="chatter.thread.todayActivities.length > 0" class="o_ActivityBoxView_titleBadge me-1 badge text-bg-warning" t-esc="chatter.thread.todayActivities.length"/>
<span t-if="chatter.thread.futureActivities.length > 0" class="o_ActivityBoxView_titleBadge me-1 badge text-bg-success" t-esc="chatter.thread.futureActivities.length"/>
</span>
<hr class="o_ActivityBoxView_titleLine w-auto flex-grow-1 ms-3"/>
</a>
<div t-if="isActivityListVisible" class="o_ActivityBoxView_activityList">
<ActivityView t-foreach="activityViews" t-as="activityView" t-key="activityView.localId" className="'o_ActivityBoxView_activity'" record="activityView"/>
</div>
</div>
</t>
</templates>
@@ -2,25 +2,23 @@
<templates xml:space="preserve">
<t t-name="mail.ActivityMarkDonePopoverContentView" owl="1">
<div class="o_ActivityMarkDonePopoverContentView" t-attf-class="{{ className }}" t-on-keydown="onKeydown" t-ref="root">
<h6 t-if="hasHeader" class="o_ActivityMarkDonePopoverContentView_header p-2 fw-bolder bg-200 border-bottom" t-esc="headerText"/>
<div class="o_ActivityMarkDonePopoverContentView_content py-2 px-3">
<textarea class="form-control o_ActivityMarkDonePopoverContentView_feedback" rows="3" placeholder="Write Feedback" t-on-blur="onBlur" t-ref="feedbackTextarea"/>
<div class="o_ActivityMarkDonePopoverContentView_buttons mt-2">
<button type="button" class="o_ActivityMarkDonePopoverContentView_doneScheduleNextButton btn btn-sm btn-primary" t-on-click="onClickDoneAndScheduleNext">
Done &amp; Schedule Next
</button>
<t t-if="activity.chaining_type === 'suggest'">
<button type="button" class="o_ActivityMarkDonePopoverContentView_doneButton btn btn-sm btn-primary mx-2" t-on-click="onClickDone">
Done
</button>
</t>
<button type="button" class="o_ActivityMarkDonePopoverContentView_discardButton btn btn-sm btn-link" t-on-click="onClickDiscard">
Discard
</button>
</div>
<div class="o_ActivityMarkDonePopoverContentView" t-attf-class="{{ className }}" t-on-keydown="onKeydown" t-ref="root">
<h6 t-if="hasHeader" class="o_ActivityMarkDonePopoverContentView_header p-2 fw-bolder bg-200 border-bottom" t-esc="headerText"/>
<div class="o_ActivityMarkDonePopoverContentView_content py-2 px-3">
<textarea class="form-control o_ActivityMarkDonePopoverContentView_feedback" rows="3" placeholder="Write Feedback" t-on-blur="onBlur" t-ref="feedbackTextarea"/>
<div class="o_ActivityMarkDonePopoverContentView_buttons mt-2">
<button type="button" class="o_ActivityMarkDonePopoverContentView_doneScheduleNextButton btn btn-sm btn-primary" t-on-click="onClickDoneAndScheduleNext">
Done &amp; Schedule Next
</button>
<button t-if="activity.chaining_type === 'suggest'" type="button" class="o_ActivityMarkDonePopoverContentView_doneButton btn btn-sm btn-primary mx-2" t-on-click="onClickDone">
Done
</button>
<button type="button" class="o_ActivityMarkDonePopoverContentView_discardButton btn btn-sm btn-link" t-on-click="onClickDiscard">
Discard
</button>
</div>
</div>
</div>
</t>
</templates>
@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.ActivityMenuContainer" owl="1">
<t t-if="activityMenuView">
<ActivityMenuView record="activityMenuView"/>
</t>
<ActivityMenuView t-if="activityMenuView" record="activityMenuView"/>
</t>
</templates>
@@ -8,11 +8,9 @@
</a>
<div t-if="activityMenuView.isOpen" class="o_ActivityMenuView_dropdownMenu o-dropdown-menu dropdown-menu-end show bg-view" role="menu">
<div class="o_ActivityMenuView_activityGroups">
<t t-if="activityMenuView.activityGroupViews.length === 0">
<div class="o_ActivityMenuView_noActivity dropdown-item-text text-center d-flex justify-content-center">
<span>Congratulations, you're done with your activities.</span>
</div>
</t>
<div t-if="activityMenuView.activityGroupViews.length === 0" class="o_ActivityMenuView_noActivity dropdown-item-text text-center d-flex justify-content-center">
<span>Congratulations, you're done with your activities.</span>
</div>
<t t-foreach="activityMenuView.activityGroupViews" t-as="activityGroupView" t-key="activityGroupView.localId" name="activityGroupLoop">
<div class="o_ActivityMenuView_activityGroup" t-att-data-res_model="activityGroupView.activityGroup.irModel.model" t-att-data-model_name="activityGroupView.activityGroup.irModel.name" t-att-data-domain="activityGroupView.activityGroup.domain" data-filter='my' t-att-data-activity-group-view-local-id="activityGroupView.localId" t-on-click="activityGroupView.onClickFilterButton">
<div t-if="activityGroupView.activityGroup.irModel.iconUrl" class="o_ActivityMenuView_activityGroupIconContainer">
@@ -20,22 +18,18 @@
</div>
<div class="o_ActivityMenuView_activityGroupInfo">
<div class="o_ActivityMenuView_activityGroupTitle">
<span class="o_ActivityMenuView_activityGroupName">
<t t-esc="activityGroupView.activityGroup.irModel.name"/>
</span>
<span class="o_ActivityMenuView_activityGroupName" t-esc="activityGroupView.activityGroup.irModel.name"/>
<div t-if="activityGroupView.activityGroup.actions" class="o_ActivityMenuView_activityGroupActionButtons">
<t t-foreach="activityGroupView.activityGroup.actions" t-as="action" t-key="action.name">
<button type="button"
t-att-title="action.name"
t-att-class="'o_ActivityMenuView_activityGroupActionButton btn btn-link fa ' + action.icon"
t-att-data-action_xmlid="action.action_xmlid"
t-att-data-res_model="activityGroupView.activityGroup.irModel.model"
t-att-data-model_name="activityGroupView.activityGroup.irModel.name"
t-att-data-domain="activityGroupView.activityGroup.domain"
t-on-click="activityGroupView.onClick"
>
</button>
</t>
<button type="button"
t-foreach="activityGroupView.activityGroup.actions" t-as="action" t-key="action.name"
t-att-title="action.name"
t-att-class="'o_ActivityMenuView_activityGroupActionButton btn btn-link fa ' + action.icon"
t-att-data-action_xmlid="action.action_xmlid"
t-att-data-res_model="activityGroupView.activityGroup.irModel.model"
t-att-data-model_name="activityGroupView.activityGroup.irModel.name"
t-att-data-domain="activityGroupView.activityGroup.domain"
t-on-click="activityGroupView.onClick"
/>
</div>
</div>
<div t-if="activityGroupView.activityGroup.type == 'activity'">
@@ -2,27 +2,25 @@
<templates xml:space="preserve">
<t t-name="mail.AttachmentBoxView" owl="1">
<div class="o_AttachmentBoxView position-relative" t-attf-class="{{ className }}" t-ref="root">
<div class="o_AttachmentBoxView_title d-flex align-items-center">
<hr class="o_AttachmentBoxView_dashedLine flex-grow-1"/>
<span class="o_AttachmentBoxView_titleText p-3 fw-bold">
Files
</span>
<hr class="o_AttachmentBoxView_dashedLine flex-grow-1"/>
</div>
<div class="o_AttachmentBoxView_content d-flex flex-column">
<t t-if="attachmentList">
<AttachmentList
className="'o_attachmentBox_attachmentList'"
record="attachmentList"
/>
</t>
<button class="o_AttachmentBoxView_buttonAdd btn btn-link" type="button" t-on-click="onClickAddAttachment" t-att-disabled="!chatter.hasWriteAccess">
<i class="fa fa-plus-square"/>
Attach files
</button>
</div>
<div class="o_AttachmentBoxView position-relative" t-attf-class="{{ className }}" t-ref="root">
<div class="o_AttachmentBoxView_title d-flex align-items-center">
<hr class="o_AttachmentBoxView_dashedLine flex-grow-1"/>
<span class="o_AttachmentBoxView_titleText p-3 fw-bold">
Files
</span>
<hr class="o_AttachmentBoxView_dashedLine flex-grow-1"/>
</div>
<div class="o_AttachmentBoxView_content d-flex flex-column">
<AttachmentList t-if="attachmentList"
className="'o_attachmentBox_attachmentList'"
record="attachmentList"
/>
<button class="o_AttachmentBoxView_buttonAdd btn btn-link" type="button" t-on-click="onClickAddAttachment" t-att-disabled="!chatter.hasWriteAccess">
<i class="fa fa-plus-square"/>
Attach files
</button>
</div>
</div>
</t>
</templates>
@@ -1,58 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.AttachmentCard" owl="1">
<div t-attf-class="{{ className }}" t-ref="root">
<div class="o_AttachmentCard o-has-card-details d-flex rounded bg-300"
t-att-class="{
'o-isUploading': attachment.isUploading,
'o-viewable': attachment.isViewable,
}" t-att-title="attachment.displayName ? attachment.displayName : undefined" role="menu" t-att-aria-label="attachment.displayName" t-att-data-id="attachment.localId"
>
<!-- Image style-->
<!-- o_image from mimetype.scss -->
<div class="o_AttachmentCard_image o_image flex-shrink-0 m-1" t-on-click="onClickImage" t-att-class="{'o-attachment-viewable opacity-75-hover': attachment.isViewable,}" role="menuitem" aria-label="Preview" t-att-tabindex="attachment.isViewable ? 0 : -1" t-att-aria-disabled="!attachment.isViewable" t-att-data-mimetype="attachment.mimetype">
<div t-attf-class="{{ className }}" t-ref="root">
<div class="o_AttachmentCard o-has-card-details d-flex rounded bg-300"
t-att-class="{
'o-isUploading': attachment.isUploading,
'o-viewable': attachment.isViewable,
}" t-att-title="attachment.displayName ? attachment.displayName : undefined" role="menu" t-att-aria-label="attachment.displayName" t-att-data-id="attachment.localId"
>
<!-- Image style-->
<!-- o_image from mimetype.scss -->
<div class="o_AttachmentCard_image o_image flex-shrink-0 m-1" t-on-click="onClickImage" t-att-class="{'o-attachment-viewable opacity-75-hover': attachment.isViewable,}" role="menuitem" aria-label="Preview" t-att-tabindex="attachment.isViewable ? 0 : -1" t-att-aria-disabled="!attachment.isViewable" t-att-data-mimetype="attachment.mimetype"/>
<!-- Attachment details -->
<div class="o_AttachmentCard_details d-flex justify-content-center flex-column px-1">
<div t-if="attachment.displayName" class="o_AttachmentCard_filename text-truncate" t-esc="attachment.displayName"/>
<small t-if="attachment.extension" class="o_AttachmentCard_extension text-uppercase" t-esc="attachment.extension"/>
</div>
<!-- Attachment aside -->
<div class="o_AttachmentCard_aside position-relative rounded-end overflow-hidden" t-att-class="{ 'o-hasMultipleActions d-flex flex-column': hasMultipleActions }">
<!-- Uploading icon -->
<div t-if="attachment.isUploading and attachmentList.composerViewOwner" class="o_AttachmentCard_asideItem o_AttachmentCard_asideItemUploading d-flex justify-content-center align-items-center w-100 h-100" title="Uploading">
<i class="fa fa-spin fa-spinner"/>
</div>
<!-- Attachment details -->
<div class="o_AttachmentCard_details d-flex justify-content-center flex-column px-1">
<t t-if="attachment.displayName">
<div class="o_AttachmentCard_filename text-truncate">
<t t-esc="attachment.displayName"/>
</div>
</t>
<t t-if="attachment.extension">
<small class="o_AttachmentCard_extension text-uppercase">
<t t-esc="attachment.extension"/>
</small>
</t>
</div>
<!-- Attachment aside -->
<div class="o_AttachmentCard_aside position-relative rounded-end overflow-hidden" t-att-class="{ 'o-hasMultipleActions d-flex flex-column': hasMultipleActions }">
<!-- Uploading icon -->
<t t-if="attachment.isUploading and attachmentList.composerViewOwner">
<div class="o_AttachmentCard_asideItem o_AttachmentCard_asideItemUploading d-flex justify-content-center align-items-center w-100 h-100" title="Uploading">
<i class="fa fa-spin fa-spinner"/>
</div>
</t>
<!-- Uploaded icon -->
<t t-if="!attachment.isUploading and attachmentList.composerViewOwner">
<div class="o_AttachmentCard_asideItem o_AttachmentCard_asideItemUploaded d-flex justify-content-center align-items-center w-100 h-100 text-primary" title="Uploaded">
<i class="fa fa-check"/>
</div>
</t>
<!-- Remove button -->
<t t-if="attachment.isDeletable">
<button class="o_AttachmentCard_asideItem o_AttachmentCard_asideItemUnlink btn top-0 justify-content-center align-items-center d-flex w-100 h-100 rounded-0" t-attf-class="{{ attachmentList.composerViewOwner ? 'o-pretty position-absolute btn-primary transition-base' : 'bg-300' }}" t-on-click="onClickUnlink" title="Remove">
<i class="fa fa-trash" role="img" aria-label="Remove"/>
</button>
</t>
<!-- Download button -->
<t t-if="!attachmentList.composerViewOwner and !attachment.isUploading">
<button class="o_AttachmentCard_asideItem o_AttachmentCard_asideItemDownload btn d-flex justify-content-center align-items-center w-100 h-100 rounded-0 bg-300" t-on-click="attachment.onClickDownload" title="Download">
<i class="fa fa-download" role="img" aria-label="Download"/>
</button>
</t>
<!-- Uploaded icon -->
<div t-if="!attachment.isUploading and attachmentList.composerViewOwner" class="o_AttachmentCard_asideItem o_AttachmentCard_asideItemUploaded d-flex justify-content-center align-items-center w-100 h-100 text-primary" title="Uploaded">
<i class="fa fa-check"/>
</div>
<!-- Remove button -->
<button t-if="attachment.isDeletable" class="o_AttachmentCard_asideItem o_AttachmentCard_asideItemUnlink btn top-0 justify-content-center align-items-center d-flex w-100 h-100 rounded-0" t-attf-class="{{ attachmentList.composerViewOwner ? 'o-pretty position-absolute btn-primary transition-base' : 'bg-300' }}" t-on-click="onClickUnlink" title="Remove">
<i class="fa fa-trash" role="img" aria-label="Remove"/>
</button>
<!-- Download button -->
<button t-if="!attachmentList.composerViewOwner and !attachment.isUploading" class="o_AttachmentCard_asideItem o_AttachmentCard_asideItemDownload btn d-flex justify-content-center align-items-center w-100 h-100 rounded-0 bg-300" t-on-click="attachment.onClickDownload" title="Download">
<i class="fa fa-download" role="img" aria-label="Download"/>
</button>
</div>
</div>
</div>
</t>
</templates>
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.AttachmentDeleteConfirmView" owl="1">
<div class="o_AttachmentDeleteConfirmView card bg-view" t-attf-class="{{ className }}" t-ref="root">
<h4 class="m-3">Confirmation</h4>
<hr class="mt-0 mb-3"/>
<p class="o_AttachmentDeleteConfirmView_mainText mx-3 mb-3" t-esc="body"/>
<hr class="mt-0 mb-3"/>
<div class="o_AttachmentDeleteConfirmView_buttons mx-3 mb-3">
<button class="o_AttachmentDeleteConfirmView_confirmButton btn btn-primary me-2" t-on-click="onClickOk">Ok</button>
<button class="o_AttachmentDeleteConfirmView_cancelButton btn btn-secondary me-2" t-on-click="onClickCancel">Cancel</button>
</div>
<div class="o_AttachmentDeleteConfirmView card bg-view" t-attf-class="{{ className }}" t-ref="root">
<h4 class="m-3">Confirmation</h4>
<hr class="mt-0 mb-3"/>
<p class="o_AttachmentDeleteConfirmView_mainText mx-3 mb-3" t-esc="body"/>
<hr class="mt-0 mb-3"/>
<div class="o_AttachmentDeleteConfirmView_buttons mx-3 mb-3">
<button class="o_AttachmentDeleteConfirmView_confirmButton btn btn-primary me-2" t-on-click="onClickOk">Ok</button>
<button class="o_AttachmentDeleteConfirmView_cancelButton btn btn-secondary me-2" t-on-click="onClickCancel">Cancel</button>
</div>
</div>
</t>
</templates>
@@ -1,36 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.AttachmentImage" owl="1">
<div t-attf-class="{{ className }}" role="menu" t-att-aria-label="attachment.displayName" t-ref="root">
<div class="o_AttachmentImage d-flex position-relative flex-shrink-0"
t-att-class="{
'o-isUploading': attachment.isUploading,
}"
t-att-title="attachment.displayName ? attachment.displayName : undefined"
t-att-data-id="attachment.localId"
tabindex="0"
aria-label="View image"
role="menuitem"
t-on-click="onClickImage"
t-att-data-mimetype="attachment.mimetype"
>
<t t-if="!attachment.isUploading">
<img class="img img-fluid my-0 mx-auto" t-att-src="imageUrl" t-att-alt="attachment.name" t-attf-style="max-width: min(100%, {{ width }}px); max-height: {{ height }}px;"/>
</t>
<t t-if="attachment.isUploading">
<div class="o_AttachmentImageUploading position-absolute top-0 bottom-0 start-0 end-0 d-flex align-items-center justify-content-center" title="Uploading">
<i class="fa fa-spin fa-spinner"/>
</div>
</t>
<div class="o_AttachmentImage_imageOverlay position-absolute top-0 bottom-0 start-0 end-0 p-2 text-white opacity-0 opacity-100-hover d-flex align-items-end flax-wrap flex-column">
<div t-if="attachment.isDeletable" class="o_AttachmentImage_action o_AttachmentImage_actionUnlink btn btn-sm btn-dark rounded opacity-75 opacity-100-hover" t-att-class="{'o-pretty': attachmentList.composerViewOwner}" tabindex="0" aria-label="Remove" role="menuitem" t-on-click="onClickUnlink" title="Remove">
<i class="fa fa-trash"/>
</div>
<div t-if="hasDownloadButton" class="o_AttachmentImage_action o_AttachmentImage_actionDownload btn btn-sm btn-dark rounded opacity-75 opacity-100-hover mt-auto" t-on-click="onClickDownload" title="Download">
<i class="fa fa-download"/>
</div>
<div t-attf-class="{{ className }}" role="menu" t-att-aria-label="attachment.displayName" t-ref="root">
<div class="o_AttachmentImage d-flex position-relative flex-shrink-0"
t-att-class="{
'o-isUploading': attachment.isUploading,
}"
t-att-title="attachment.displayName ? attachment.displayName : undefined"
t-att-data-id="attachment.localId"
tabindex="0"
aria-label="View image"
role="menuitem"
t-on-click="onClickImage"
t-att-data-mimetype="attachment.mimetype"
>
<img t-if="!attachment.isUploading" class="img img-fluid my-0 mx-auto" t-att-src="imageUrl" t-att-alt="attachment.name" t-attf-style="max-width: min(100%, {{ width }}px); max-height: {{ height }}px;"/>
<div t-if="attachment.isUploading" class="o_AttachmentImageUploading position-absolute top-0 bottom-0 start-0 end-0 d-flex align-items-center justify-content-center" title="Uploading">
<i class="fa fa-spin fa-spinner"/>
</div>
<div class="o_AttachmentImage_imageOverlay position-absolute top-0 bottom-0 start-0 end-0 p-2 text-white opacity-0 opacity-100-hover d-flex align-items-end flax-wrap flex-column">
<div t-if="attachment.isDeletable" class="o_AttachmentImage_action o_AttachmentImage_actionUnlink btn btn-sm btn-dark rounded opacity-75 opacity-100-hover" t-att-class="{'o-pretty': attachmentList.composerViewOwner}" tabindex="0" aria-label="Remove" role="menuitem" t-on-click="onClickUnlink" title="Remove">
<i class="fa fa-trash"/>
</div>
<div t-if="hasDownloadButton" class="o_AttachmentImage_action o_AttachmentImage_actionDownload btn btn-sm btn-dark rounded opacity-75 opacity-100-hover mt-auto" t-on-click="onClickDownload" title="Download">
<i class="fa fa-download"/>
</div>
</div>
</div>
</div>
</t>
</templates>
@@ -2,18 +2,14 @@
<templates xml:space="preserve">
<t t-name="mail.AttachmentList" owl="1">
<div class="o_AttachmentList d-flex flex-column mt-1" t-att-class="{ 'me-2 pe-4': isInChatWindowAndIsAlignedLeft and !composerViewOwner, 'ms-2 ps-4': isInChatWindowAndIsAlignedRight and !composerViewOwner }" t-attf-class="{{ className }}" t-ref="root">
<div t-if="attachmentImages.length > 0" class="o_AttachmentList_partialList o_AttachmentList_partialListImages d-flex flex-grow-1 flex-wrap" t-att-class="{ 'justify-content-end': isInChatWindowAndIsAlignedRight and !composerViewOwner }">
<t t-foreach="attachmentImages" t-as="attachmentImage" t-key="attachmentImage.localId">
<AttachmentImage className="'o_AttachmentList_attachment mw-100 mb-1'" classNameObj="{ 'ms-1': isInChatWindowAndIsAlignedRight, 'me-1': !isInChatWindowAndIsAlignedRight }" record="attachmentImage"/>
</t>
</div>
<div t-if="attachmentCards.length > 0" class="o_AttachmentList_partialList o_AttachmentList_partialListNonImages d-flex flex-grow-1 flex-wrap mt-1" t-att-class="{ 'justify-content-end': isInChatWindowAndIsAlignedRight and !composerViewOwner }">
<t t-foreach="attachmentCards" t-as="attachmentCard" t-key="attachmentCard.localId">
<AttachmentCard className="'o_AttachmentList_attachment mw-100 mb-1'" classNameObj="{ 'ms-1': isInChatWindowAndIsAlignedRight, 'me-1': !isInChatWindowAndIsAlignedRight }" record="attachmentCard"/>
</t>
</div>
<div class="o_AttachmentList d-flex flex-column mt-1" t-att-class="{ 'me-2 pe-4': isInChatWindowAndIsAlignedLeft and !composerViewOwner, 'ms-2 ps-4': isInChatWindowAndIsAlignedRight and !composerViewOwner }" t-attf-class="{{ className }}" t-ref="root">
<div t-if="attachmentImages.length > 0" class="o_AttachmentList_partialList o_AttachmentList_partialListImages d-flex flex-grow-1 flex-wrap" t-att-class="{ 'justify-content-end': isInChatWindowAndIsAlignedRight and !composerViewOwner }">
<AttachmentImage t-foreach="attachmentImages" t-as="attachmentImage" t-key="attachmentImage.localId" className="'o_AttachmentList_attachment mw-100 mb-1'" classNameObj="{ 'ms-1': isInChatWindowAndIsAlignedRight, 'me-1': !isInChatWindowAndIsAlignedRight }" record="attachmentImage"/>
</div>
<div t-if="attachmentCards.length > 0" class="o_AttachmentList_partialList o_AttachmentList_partialListNonImages d-flex flex-grow-1 flex-wrap mt-1" t-att-class="{ 'justify-content-end': isInChatWindowAndIsAlignedRight and !composerViewOwner }">
<AttachmentCard t-foreach="attachmentCards" t-as="attachmentCard" t-key="attachmentCard.localId" className="'o_AttachmentList_attachment mw-100 mb-1'" classNameObj="{ 'ms-1': isInChatWindowAndIsAlignedRight, 'me-1': !isInChatWindowAndIsAlignedRight }" record="attachmentCard"/>
</div>
</div>
</t>
</templates>
@@ -2,97 +2,69 @@
<templates xml:space="preserve">
<t t-name="mail.AttachmentViewer" owl="1">
<t t-if="attachmentViewer">
<div class="o_AttachmentViewer flex-column align-items-center d-flex w-100 h-100" t-attf-class="{{ className }}" t-on-click="attachmentViewer.onClick" t-on-keydown="attachmentViewer.onKeydown" tabindex="0" t-ref="root">
<div class="o_AttachmentViewer_header d-flex w-100 bg-black-75 text-400" t-on-click="attachmentViewer.onClickHeader">
<t t-if="attachmentViewer.attachmentViewerViewable.isViewable">
<div class="o_AttachmentViewer_headerItem o_AttachmentViewer_icon d-flex align-items-center ms-4 me-2">
<t t-if="attachmentViewer.attachmentViewerViewable.isImage">
<i class="fa fa-picture-o" role="img" title="Image"/>
</t>
<t t-if="attachmentViewer.attachmentViewerViewable.isPdf">
<i class="fa fa-file-text" role="img" title="PDF file"/>
</t>
<t t-if="attachmentViewer.attachmentViewerViewable.isText">
<i class="fa fa-file-text" role="img" title="Text file"/>
</t>
<t t-if="attachmentViewer.attachmentViewerViewable.isVideo">
<i class="fa fa-video-camera" role="img" title="Video"/>
</t>
</div>
</t>
<div class="o_AttachmentViewer_headerItem o_AttachmentViewer_name d-flex align-items-center mx-2">
<span class="o_AttachmentViewer_nameText text-truncate" t-esc="attachmentViewer.attachmentViewerViewable.displayName"/>
</div>
<div class="flex-grow-1"/>
<div class="o_AttachmentViewer_buttonDownload o_AttachmentViewer_headerItem o_AttachmentViewer_headerItemButton d-flex align-items-center px-3 cursor-pointer" t-on-click="attachmentViewer.onClickDownload" role="button" title="Download">
<i class="o_AttachmentViewer_headerItemButtonIcon fa fa-download fa-fw" t-att-class="{ 'o-hasLabel me-2': messaging.device.sizeClass > messaging.device.sizeClasses.MD }" role="img"/>
<t t-if="messaging.device.sizeClass > messaging.device.sizeClasses.MD">
<span>Download</span>
</t>
</div>
<div class="o_AttachmentViewer_headerItem o_AttachmentViewer_headerItemButton o_AttachmentViewer_headerItemButtonClose d-flex align-items-center mb-0 px-3 h4 text-reset cursor-pointer" t-on-click="attachmentViewer.onClickClose" role="button" title="Close (Esc)" aria-label="Close">
<i class="fa fa-fw fa-times" role="img"/>
</div>
<div class="o_AttachmentViewer flex-column align-items-center d-flex w-100 h-100" t-attf-class="{{ className }}" t-on-click="attachmentViewer.onClick" t-on-keydown="attachmentViewer.onKeydown" tabindex="0" t-ref="root">
<div class="o_AttachmentViewer_header d-flex w-100 bg-black-75 text-400" t-on-click="attachmentViewer.onClickHeader">
<div t-if="attachmentViewer.attachmentViewerViewable.isViewable" class="o_AttachmentViewer_headerItem o_AttachmentViewer_icon d-flex align-items-center ms-4 me-2">
<i t-if="attachmentViewer.attachmentViewerViewable.isImage" class="fa fa-picture-o" role="img" title="Image"/>
<i t-if="attachmentViewer.attachmentViewerViewable.isPdf" class="fa fa-file-text" role="img" title="PDF file"/>
<i t-if="attachmentViewer.attachmentViewerViewable.isText" class="fa fa-file-text" role="img" title="Text file"/>
<i t-if="attachmentViewer.attachmentViewerViewable.isVideo" class="fa fa-video-camera" role="img" title="Video"/>
</div>
<div class="o_AttachmentViewer_main position-absolute top-0 bottom-0 start-0 end-0 align-items-center justify-content-center d-flex" t-att-class="{ 'o_with_img overflow-hidden': attachmentViewer.attachmentViewerViewable.isImage }" t-on-mousemove="attachmentViewer.onMousemoveView">
<t t-if="attachmentViewer.attachmentViewerViewable.isImage">
<div class="o_AttachmentViewer_zoomer position-absolute align-items-center justify-content-center d-flex w-100 h-100" t-ref="zoomer">
<t t-if="attachmentViewer.isImageLoading">
<div class="o_AttachmentViewer_loading position-absolute">
<i class="fa fa-3x fa-circle-o-notch fa-fw fa-spin text-white" role="img" title="Loading"/>
</div>
</t>
<img class="o_AttachmentViewer_view o_AttachmentViewer_viewImage mw-100 mh-100 transition-base" t-on-click="attachmentViewer.onClickImage" t-on-mousedown="attachmentViewer.onMousedownImage" t-on-wheel="attachmentViewer.onWheelImage" t-on-load="attachmentViewer.onLoadImage" t-att-src="attachmentViewer.attachmentViewerViewable.imageUrl" t-att-style="attachmentViewer.imageStyle" draggable="false" alt="Viewer" t-ref="image"/>
</div>
</t>
<t t-if="attachmentViewer.attachmentViewerViewable.isPdf">
<iframe class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_AttachmentViewer_viewPdf w-75 h-100 border-0" t-ref="iframeViewerPdf" t-att-class="{ 'w-100': messaging.device.isSmall }" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource"/>
</t>
<t t-if="attachmentViewer.attachmentViewerViewable.isText">
<iframe class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_AttachmentViewer_isText o_text w-75 h-100 border-0" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource"/>
</t>
<t t-if="attachmentViewer.attachmentViewerViewable.isUrlYoutube">
<iframe allow="autoplay; encrypted-media" class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_AttachmentViewer_youtube w-75 h-100 border-0" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource" height="315" width="560"/>
</t>
<t t-if="attachmentViewer.attachmentViewerViewable.isVideo">
<video class="o_AttachmentViewer_view o_AttachmentViewer_viewVideo w-75 h-75" t-att-class="{ 'w-100 h-100': messaging.device.isSmall }" t-on-click="attachmentViewer.onClickVideo" controls="controls">
<source t-att-data-type="attachmentViewer.attachmentViewerViewable.mimetype" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource"/>
</video>
</t>
<div class="o_AttachmentViewer_headerItem o_AttachmentViewer_name d-flex align-items-center mx-2">
<span class="o_AttachmentViewer_nameText text-truncate" t-esc="attachmentViewer.attachmentViewerViewable.displayName"/>
</div>
<div class="flex-grow-1"/>
<div class="o_AttachmentViewer_buttonDownload o_AttachmentViewer_headerItem o_AttachmentViewer_headerItemButton d-flex align-items-center px-3 cursor-pointer" t-on-click="attachmentViewer.onClickDownload" role="button" title="Download">
<i class="o_AttachmentViewer_headerItemButtonIcon fa fa-download fa-fw" t-att-class="{ 'o-hasLabel me-2': messaging.device.sizeClass > messaging.device.sizeClasses.MD }" role="img"/>
<span t-if="messaging.device.sizeClass > messaging.device.sizeClasses.MD">Download</span>
</div>
<div class="o_AttachmentViewer_headerItem o_AttachmentViewer_headerItemButton o_AttachmentViewer_headerItemButtonClose d-flex align-items-center mb-0 px-3 h4 text-reset cursor-pointer" t-on-click="attachmentViewer.onClickClose" role="button" title="Close (Esc)" aria-label="Close">
<i class="fa fa-fw fa-times" role="img"/>
</div>
<t t-if="attachmentViewer.attachmentViewerViewable.isImage">
<div class="o_AttachmentViewer_toolbar position-absolute bottom-0 d-flex" role="toolbar">
<div class="o_AttachmentViewer_toolbarButton p-3 rounded-0" t-on-click="attachmentViewer.onClickZoomIn" title="Zoom In (+)" role="button">
<i class="fa fa-fw fa-plus" role="img"/>
</div>
<div class="o_AttachmentViewer_toolbarButton p-3 rounded-0" t-att-class="{ 'o_disabled opacity-50': attachmentViewer.scale === 1 }" t-on-click="attachmentViewer.onClickZoomReset" role="button" title="Reset Zoom (0)">
<i class="fa fa-fw fa-search" role="img"/>
</div>
<div class="o_AttachmentViewer_toolbarButton p-3 rounded-0" t-att-class="{ 'o_disabled opacity-50': attachmentViewer.scale === attachmentViewer.minScale }" t-on-click="attachmentViewer.onClickZoomOut" title="Zoom Out (-)" role="button">
<i class="fa fa-fw fa-minus" role="img"/>
</div>
<div class="o_AttachmentViewer_toolbarButton p-3 rounded-0" t-on-click="attachmentViewer.onClickRotate" title="Rotate (r)" role="button">
<i class="fa fa-fw fa-repeat" role="img"/>
</div>
<div class="o_AttachmentViewer_toolbarButton p-3 rounded-0" t-on-click="attachmentViewer.onClickPrint" title="Print" role="button">
<i class="fa fa-fw fa-print" role="img"/>
</div>
<div class="o_AttachmentViewer_buttonDownload o_AttachmentViewer_toolbarButton p-3 rounded-0 cursor-pointer" t-on-click="attachmentViewer.onClickDownload" title="Download" role="button">
<i class="fa fa-download fa-fw" role="img"/>
</div>
</div>
</t>
<t t-if="attachmentViewer.attachmentViewerViewables.length > 1">
<div class="o_AttachmentViewer_buttonNavigation o_AttachmentViewer_buttonNavigationPrevious o_AttachmentViewer_buttonNavigationPreviousIcon position-absolute top-0 bottom-0 start-0 align-items-center justify-content-center d-flex my-auto ms-3 rounded-circle" t-on-click="attachmentViewer.onClickPrevious" title="Previous (Left-Arrow)" role="button">
<span class="fa fa-chevron-left" role="img"/>
</div>
<div class="o_AttachmentViewer_buttonNavigation o_AttachmentViewer_buttonNavigationNext o_AttachmentViewer_buttonNavigationNextIcon position-absolute top-0 bottom-0 end-0 align-items-center justify-content-center d-flex my-auto me-3 rounded-circle" t-on-click="attachmentViewer.onClickNext" title="Next (Right-Arrow)" role="button">
<span class="fa fa-chevron-right" role="img"/>
</div>
</t>
</div>
</t>
<div class="o_AttachmentViewer_main position-absolute top-0 bottom-0 start-0 end-0 align-items-center justify-content-center d-flex" t-att-class="{ 'o_with_img overflow-hidden': attachmentViewer.attachmentViewerViewable.isImage }" t-on-mousemove="attachmentViewer.onMousemoveView">
<div t-if="attachmentViewer.attachmentViewerViewable.isImage" class="o_AttachmentViewer_zoomer position-absolute align-items-center justify-content-center d-flex w-100 h-100" t-ref="zoomer">
<div t-if="attachmentViewer.isImageLoading" class="o_AttachmentViewer_loading position-absolute">
<i class="fa fa-3x fa-circle-o-notch fa-fw fa-spin text-white" role="img" title="Loading"/>
</div>
<img class="o_AttachmentViewer_view o_AttachmentViewer_viewImage mw-100 mh-100 transition-base" t-on-click="attachmentViewer.onClickImage" t-on-mousedown="attachmentViewer.onMousedownImage" t-on-wheel="attachmentViewer.onWheelImage" t-on-load="attachmentViewer.onLoadImage" t-att-src="attachmentViewer.attachmentViewerViewable.imageUrl" t-att-style="attachmentViewer.imageStyle" draggable="false" alt="Viewer" t-ref="image"/>
</div>
<iframe t-if="attachmentViewer.attachmentViewerViewable.isPdf" class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_AttachmentViewer_viewPdf w-75 h-100 border-0" t-ref="iframeViewerPdf" t-att-class="{ 'w-100': messaging.device.isSmall }" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource"/>
<iframe t-if="attachmentViewer.attachmentViewerViewable.isText" class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_AttachmentViewer_isText o_text w-75 h-100 border-0" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource"/>
<iframe t-if="attachmentViewer.attachmentViewerViewable.isUrlYoutube" allow="autoplay; encrypted-media" class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_AttachmentViewer_youtube w-75 h-100 border-0" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource" height="315" width="560"/>
<video t-if="attachmentViewer.attachmentViewerViewable.isVideo" class="o_AttachmentViewer_view o_AttachmentViewer_viewVideo w-75 h-75" t-att-class="{ 'w-100 h-100': messaging.device.isSmall }" t-on-click="attachmentViewer.onClickVideo" controls="controls">
<source t-att-data-type="attachmentViewer.attachmentViewerViewable.mimetype" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource"/>
</video>
</div>
<div t-if="attachmentViewer.attachmentViewerViewable.isImage" class="o_AttachmentViewer_toolbar position-absolute bottom-0 d-flex" role="toolbar">
<div class="o_AttachmentViewer_toolbarButton p-3 rounded-0" t-on-click="attachmentViewer.onClickZoomIn" title="Zoom In (+)" role="button">
<i class="fa fa-fw fa-plus" role="img"/>
</div>
<div class="o_AttachmentViewer_toolbarButton p-3 rounded-0" t-att-class="{ 'o_disabled opacity-50': attachmentViewer.scale === 1 }" t-on-click="attachmentViewer.onClickZoomReset" role="button" title="Reset Zoom (0)">
<i class="fa fa-fw fa-search" role="img"/>
</div>
<div class="o_AttachmentViewer_toolbarButton p-3 rounded-0" t-att-class="{ 'o_disabled opacity-50': attachmentViewer.scale === attachmentViewer.minScale }" t-on-click="attachmentViewer.onClickZoomOut" title="Zoom Out (-)" role="button">
<i class="fa fa-fw fa-minus" role="img"/>
</div>
<div class="o_AttachmentViewer_toolbarButton p-3 rounded-0" t-on-click="attachmentViewer.onClickRotate" title="Rotate (r)" role="button">
<i class="fa fa-fw fa-repeat" role="img"/>
</div>
<div class="o_AttachmentViewer_toolbarButton p-3 rounded-0" t-on-click="attachmentViewer.onClickPrint" title="Print" role="button">
<i class="fa fa-fw fa-print" role="img"/>
</div>
<div class="o_AttachmentViewer_buttonDownload o_AttachmentViewer_toolbarButton p-3 rounded-0 cursor-pointer" t-on-click="attachmentViewer.onClickDownload" title="Download" role="button">
<i class="fa fa-download fa-fw" role="img"/>
</div>
</div>
<t t-if="attachmentViewer.attachmentViewerViewables.length > 1">
<div class="o_AttachmentViewer_buttonNavigation o_AttachmentViewer_buttonNavigationPrevious o_AttachmentViewer_buttonNavigationPreviousIcon position-absolute top-0 bottom-0 start-0 align-items-center justify-content-center d-flex my-auto ms-3 rounded-circle" t-on-click="attachmentViewer.onClickPrevious" title="Previous (Left-Arrow)" role="button">
<span class="fa fa-chevron-left" role="img"/>
</div>
<div class="o_AttachmentViewer_buttonNavigation o_AttachmentViewer_buttonNavigationNext o_AttachmentViewer_buttonNavigationNextIcon position-absolute top-0 bottom-0 end-0 align-items-center justify-content-center d-flex my-auto me-3 rounded-circle" t-on-click="attachmentViewer.onClickNext" title="Next (Right-Arrow)" role="button">
<span class="fa fa-chevron-right" role="img"/>
</div>
</t>
</div>
</t>
</templates>
@@ -2,141 +2,129 @@
<templates xml:space="preserve">
<t t-name="mail.CallActionListView" owl="1">
<div class="o_CallActionListView d-flex justify-content-between" t-attf-class="{{ className }}" t-ref="root">
<div class="o_CallActionListView_buttons d-flex align-items-center flex-wrap">
<t t-if="thread.rtc and messaging.rtc.currentRtcSession">
<button class="o_CallActionListView_button btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
t-att-class="{ 'o-isActive': !messaging.rtc.currentRtcSession.isMute, 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
t-att-aria-label="microphoneButtonTitle"
t-att-title="microphoneButtonTitle"
t-on-click="onClickMicrophone">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-stack-1x" t-att-class="{
'fa-lg': !isSmall,
'fa-microphone': !messaging.rtc.currentRtcSession.isMute,
'fa-microphone-slash': messaging.rtc.currentRtcSession.isMute,
'text-danger': messaging.rtc.currentRtcSession.isMute,
}"/>
</div>
</button>
<button class="o_CallActionListView_button btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
t-att-class="{ 'o-isActive': !messaging.rtc.currentRtcSession.isDeaf, 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
t-att-aria-label="headphoneButtonTitle"
t-att-title="headphoneButtonTitle"
t-on-click="onClickDeafen">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-stack-1x" t-att-class="{
'fa-lg': !isSmall,
'fa-headphones': !messaging.rtc.currentRtcSession.isDeaf,
'fa-deaf': messaging.rtc.currentRtcSession.isDeaf,
'text-danger': messaging.rtc.currentRtcSession.isDeaf,
}"/>
</div>
</button>
<button class="o_CallActionListView_button o_CallActionListView_videoButton btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
t-att-class="{
'o-isActive': messaging.rtc.sendUserVideo,
'o-isSmall p-2': isSmall,
'p-3': !isSmall,
}"
t-att-aria-label="cameraButtonTitle"
t-att-title="cameraButtonTitle"
t-on-click="onClickCamera">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-video-camera fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall, 'text-success': messaging.rtc.sendUserVideo }"/>
</div>
</button>
<t t-if="!messaging.device.isMobileDevice">
<button class="o_CallActionListView_button o_CallActionListView_videoButton btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
t-att-class="{
'o-isActive': messaging.rtc.sendDisplay,
'o-isSmall p-2': isSmall,
'p-3': !isSmall,
}"
t-att-aria-label="screenSharingButtonTitle"
t-att-title="screenSharingButtonTitle"
t-on-click="onClickScreen">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-desktop fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall, 'text-success': messaging.rtc.sendDisplay }"/>
</div>
</button>
</t>
<t t-if="!callView.isFullScreen">
<button class="o_CallActionListView_button btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
aria-label="Activate Full Screen"
title="Activate Full Screen"
t-att-class="{ 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
t-on-click="callView.activateFullScreen"
>
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-arrows-alt fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
</t>
<t t-if="callView.isFullScreen">
<button class="o_CallActionListView_button btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
aria-label="Deactivate Full Screen"
title="Deactivate Full Screen"
t-att-class="{ 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
t-on-click="callView.deactivateFullScreen"
>
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-compress fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
</t>
<t t-if="messaging.modelManager.isDebug">
<button class="o_CallActionListView_button btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
aria-label="More"
title="More"
t-att-class="{ 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
t-on-click="onClickMore"
t-ref="moreButton"
>
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-ellipsis-h fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
</t>
</t>
<t t-if="!thread">
<button class="o_CallActionListView_button o_CallActionListView_callToggle btn btn-success d-flex m-1 border-0 rounded-circle shadow-none"
<div class="o_CallActionListView d-flex justify-content-between" t-attf-class="{{ className }}" t-ref="root">
<div class="o_CallActionListView_buttons d-flex align-items-center flex-wrap">
<t t-if="thread.rtc and messaging.rtc.currentRtcSession">
<button class="o_CallActionListView_button btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
t-att-class="{ 'o-isActive': !messaging.rtc.currentRtcSession.isMute, 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
t-att-aria-label="microphoneButtonTitle"
t-att-title="microphoneButtonTitle"
t-on-click="onClickMicrophone">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-stack-1x" t-att-class="{
'fa-lg': !isSmall,
'fa-microphone': !messaging.rtc.currentRtcSession.isMute,
'fa-microphone-slash': messaging.rtc.currentRtcSession.isMute,
'text-danger': messaging.rtc.currentRtcSession.isMute,
}"/>
</div>
</button>
<button class="o_CallActionListView_button btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
t-att-class="{ 'o-isActive': !messaging.rtc.currentRtcSession.isDeaf, 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
t-att-aria-label="headphoneButtonTitle"
t-att-title="headphoneButtonTitle"
t-on-click="onClickDeafen">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-stack-1x" t-att-class="{
'fa-lg': !isSmall,
'fa-headphones': !messaging.rtc.currentRtcSession.isDeaf,
'fa-deaf': messaging.rtc.currentRtcSession.isDeaf,
'text-danger': messaging.rtc.currentRtcSession.isDeaf,
}"/>
</div>
</button>
<button class="o_CallActionListView_button o_CallActionListView_videoButton btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
t-att-class="{
'o-isActive': messaging.rtc.sendUserVideo,
'o-isSmall p-2': isSmall,
'p-3': !isSmall,
}"
t-att-aria-label="cameraButtonTitle"
t-att-title="cameraButtonTitle"
t-on-click="onClickCamera">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-video-camera fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall, 'text-success': messaging.rtc.sendUserVideo }"/>
</div>
</button>
<button t-if="!messaging.device.isMobileDevice" class="o_CallActionListView_button o_CallActionListView_videoButton btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
t-att-class="{
'o-isActive': messaging.rtc.sendDisplay,
'o-isSmall p-2': isSmall,
'p-3': !isSmall,
}"
t-att-aria-label="screenSharingButtonTitle"
t-att-title="screenSharingButtonTitle"
t-on-click="onClickScreen">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-desktop fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall, 'text-success': messaging.rtc.sendDisplay }"/>
</div>
</button>
<button t-if="!callView.isFullScreen" class="o_CallActionListView_button btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
aria-label="Activate Full Screen"
title="Activate Full Screen"
t-att-class="{ 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
t-on-click="callView.activateFullScreen"
>
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-arrows-alt fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
<button t-if="callView.isFullScreen" class="o_CallActionListView_button btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
aria-label="Deactivate Full Screen"
title="Deactivate Full Screen"
t-att-class="{ 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
t-on-click="callView.deactivateFullScreen"
>
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-compress fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
<button t-if="messaging.modelManager.isDebug" class="o_CallActionListView_button btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
aria-label="More"
title="More"
t-att-class="{ 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
aria-label="Join Video Call"
title="Join Video Call"
t-att-disabled="thread.hasPendingRtcRequest"
t-on-click="onClickToggleVideoCall">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-video-camera fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
</t>
<t t-if="thread">
<t t-if="thread.rtcInvitingSession and !thread.rtc">
<button class="o_CallActionListView_button o_CallActionListView_callToggle o-isActive btn btn-danger d-flex m-1 border-0 rounded-circle shadow-none"
t-att-class="{ 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
aria-label="Reject"
title="Reject"
t-att-disabled="thread.hasPendingRtcRequest"
t-on-click="onClickRejectCall">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-phone fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
</t>
<button class="o_CallActionListView_button o_CallActionListView_callToggle btn d-flex m-1 border-0 rounded-circle shadow-none"
t-att-aria-label="callButtonTitle"
t-att-class="{ 'o-isActive btn-danger': !!thread.rtc, 'o-isSmall p-2': isSmall, 'p-3': !isSmall, 'btn-success': !thread.rtc }"
t-att-disabled="thread.hasPendingRtcRequest"
t-att-title="callButtonTitle"
t-on-click="onClickToggleAudioCall">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-phone fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
</t>
</div>
t-on-click="onClickMore"
t-ref="moreButton"
>
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-ellipsis-h fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
</t>
<button t-if="!thread" class="o_CallActionListView_button o_CallActionListView_callToggle btn btn-success d-flex m-1 border-0 rounded-circle shadow-none"
t-att-class="{ 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
aria-label="Join Video Call"
title="Join Video Call"
t-att-disabled="thread.hasPendingRtcRequest"
t-on-click="onClickToggleVideoCall">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-video-camera fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
<t t-if="thread">
<button t-if="thread.rtcInvitingSession and !thread.rtc" class="o_CallActionListView_button o_CallActionListView_callToggle o-isActive btn btn-danger d-flex m-1 border-0 rounded-circle shadow-none"
t-att-class="{ 'o-isSmall p-2': isSmall, 'p-3': !isSmall }"
aria-label="Reject"
title="Reject"
t-att-disabled="thread.hasPendingRtcRequest"
t-on-click="onClickRejectCall">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-phone fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
<button class="o_CallActionListView_button o_CallActionListView_callToggle btn d-flex m-1 border-0 rounded-circle shadow-none"
t-att-aria-label="callButtonTitle"
t-att-class="{ 'o-isActive btn-danger': !!thread.rtc, 'o-isSmall p-2': isSmall, 'p-3': !isSmall, 'btn-success': !thread.rtc }"
t-att-disabled="thread.hasPendingRtcRequest"
t-att-title="callButtonTitle"
t-on-click="onClickToggleAudioCall">
<div class="o_CallActionListView_buttonIconWrapper fa-stack" t-att-class="{ 'o-isSmall': isSmall }">
<i class="fa fa-phone fa-stack-1x" t-att-class="{ 'fa-lg': !isSmall }"/>
</div>
</button>
</t>
</div>
</div>
</t>
</templates>
@@ -2,22 +2,22 @@
<templates xml:space="preserve">
<t t-name="mail.CallDemoView" owl="1">
<div class="o_CallDemoView position-relative d-flex justify-content-center" t-attf-class="{{ className }}" t-ref="root">
<video class="o_CallDemoView_videoDisplay shadow rounded bg-dark" height="480" width="640" autoplay="" t-ref="video"/>
<p t-if="doesBrowserSupportMediaDevices and !isVideoEnabled" class="o_CallDemoView_mediaDevicesStatus position-absolute text-light">
Camera is off
</p>
<p t-if="!doesBrowserSupportMediaDevices" class="o_CallDemoView_mediaDevicesStatus text-light">
Your browser does not support videoconference
</p>
<div class="o_CallDemoView_buttonsContainer">
<button t-if="!isMicrophoneEnabled" class="o_CallDemoView_enableMicrophoneButton o_CallDemoView_button btn btn-danger btn-lg rounded-circle p-0 m-3 fa fa-microphone-slash" t-on-click="onClickEnableMicrophoneButton"/>
<button t-if="isMicrophoneEnabled" class="o_CallDemoView_disableMicrophoneButton o_CallDemoView_button btn btn-dark btn-lg p-0 m-3 rounded-circle border-light fa fa-microphone" t-on-click="onClickDisableMicrophoneButton"/>
<button t-if="!isVideoEnabled" class="o_CallDemoView_enableVideoButton o_CallDemoView_button btn btn-danger btn-lg p-0 m-3 rounded-circle fa fa-eye-slash" t-on-click="onClickEnableVideoButton"/>
<button t-if="isVideoEnabled" class="o_CallDemoView_disableVideoButton o_CallDemoView_button btn btn-dark btn-lg p-0 m-3 rounded-circle border-light fa fa-video-camera" t-on-click="onClickDisableVideoButton"/>
</div>
<audio class="o_CallDemoView_audioPlayer" autoplay="" t-ref="audio"/>
<div class="o_CallDemoView position-relative d-flex justify-content-center" t-attf-class="{{ className }}" t-ref="root">
<video class="o_CallDemoView_videoDisplay shadow rounded bg-dark" height="480" width="640" autoplay="" t-ref="video"/>
<p t-if="doesBrowserSupportMediaDevices and !isVideoEnabled" class="o_CallDemoView_mediaDevicesStatus position-absolute text-light">
Camera is off
</p>
<p t-if="!doesBrowserSupportMediaDevices" class="o_CallDemoView_mediaDevicesStatus text-light">
Your browser does not support videoconference
</p>
<div class="o_CallDemoView_buttonsContainer">
<button t-if="!isMicrophoneEnabled" class="o_CallDemoView_enableMicrophoneButton o_CallDemoView_button btn btn-danger btn-lg rounded-circle p-0 m-3 fa fa-microphone-slash" t-on-click="onClickEnableMicrophoneButton"/>
<button t-if="isMicrophoneEnabled" class="o_CallDemoView_disableMicrophoneButton o_CallDemoView_button btn btn-dark btn-lg p-0 m-3 rounded-circle border-light fa fa-microphone" t-on-click="onClickDisableMicrophoneButton"/>
<button t-if="!isVideoEnabled" class="o_CallDemoView_enableVideoButton o_CallDemoView_button btn btn-danger btn-lg p-0 m-3 rounded-circle fa fa-eye-slash" t-on-click="onClickEnableVideoButton"/>
<button t-if="isVideoEnabled" class="o_CallDemoView_disableVideoButton o_CallDemoView_button btn btn-dark btn-lg p-0 m-3 rounded-circle border-light fa fa-video-camera" t-on-click="onClickDisableVideoButton"/>
</div>
<audio class="o_CallDemoView_audioPlayer" autoplay="" t-ref="audio"/>
</div>
</t>
</templates>
@@ -2,32 +2,30 @@
<templates xml:space="preserve">
<t t-name="mail.CallInviteRequestPopup" owl="1">
<div class="o_CallInviteRequestPopup d-flex flex-column m-2 p-5 border border-dark rounded-1 bg-900" t-attf-class="{{ className }}" t-ref="root">
<t t-if="thread.rtcInvitingSession">
<div class="o_CallInviteRequestPopup_partnerInfo d-flex flex-column justify-content-around align-items-center text-nowrap">
<img class="o_CallInviteRequestPopup_partnerInfoImage mb-2 rounded-circle cursor-pointer"
t-att-src="thread.rtcInvitingSession.channelMember.avatarUrl"
t-on-click="onClickAvatar"
alt="Avatar"/>
<span class="o_CallInviteRequestPopup_partnerInfoName w-100 fw-bolder text-truncate text-center overflow-hidden" t-esc="thread.rtcInvitingSession.channelMember.persona.name"/>
<span class="o_CallInviteRequestPopup_partnerInfoText fst-italic opacity-75">Incoming Call...</span>
</div>
</t>
<div class="o_CallInviteRequestPopup_buttonList d-flex justify-content-around align-items-center w-100 mt-4">
<button class="o_CallInviteRequestPopup_buttonListButton o_CallInviteRequestPopup_buttonListRefuse p-2 rounded-circle border-0 bg-danger"
aria-label="Refuse"
title="Refuse"
t-on-click="onClickRefuse">
<i class="o_CallInviteRequestPopup_buttonListButtonIcon fa fa-lg fa-times m-3"/>
</button>
<button class="o_CallInviteRequestPopup_buttonListButton o_CallInviteRequestPopup_buttonListAccept p-2 rounded-circle border-0 bg-success"
aria-label="Accept"
title="Accept"
t-on-click="onClickAccept">
<i class="o_CallInviteRequestPopup_buttonListButtonIcon fa fa-lg fa-phone m-3"/>
</button>
</div>
<div class="o_CallInviteRequestPopup d-flex flex-column m-2 p-5 border border-dark rounded-1 bg-900" t-attf-class="{{ className }}" t-ref="root">
<div t-if="thread.rtcInvitingSession" class="o_CallInviteRequestPopup_partnerInfo d-flex flex-column justify-content-around align-items-center text-nowrap">
<img class="o_CallInviteRequestPopup_partnerInfoImage mb-2 rounded-circle cursor-pointer"
t-att-src="thread.rtcInvitingSession.channelMember.avatarUrl"
t-on-click="onClickAvatar"
alt="Avatar"/>
<span class="o_CallInviteRequestPopup_partnerInfoName w-100 fw-bolder text-truncate text-center overflow-hidden" t-esc="thread.rtcInvitingSession.channelMember.persona.name"/>
<span class="o_CallInviteRequestPopup_partnerInfoText fst-italic opacity-75">Incoming Call...</span>
</div>
<div class="o_CallInviteRequestPopup_buttonList d-flex justify-content-around align-items-center w-100 mt-4">
<button class="o_CallInviteRequestPopup_buttonListButton o_CallInviteRequestPopup_buttonListRefuse p-2 rounded-circle border-0 bg-danger"
aria-label="Refuse"
title="Refuse"
t-on-click="onClickRefuse">
<i class="o_CallInviteRequestPopup_buttonListButtonIcon fa fa-lg fa-times m-3"/>
</button>
<button class="o_CallInviteRequestPopup_buttonListButton o_CallInviteRequestPopup_buttonListAccept p-2 rounded-circle border-0 bg-success"
aria-label="Accept"
title="Accept"
t-on-click="onClickAccept">
<i class="o_CallInviteRequestPopup_buttonListButtonIcon fa fa-lg fa-phone m-3"/>
</button>
</div>
</div>
</t>
</templates>
@@ -4,9 +4,7 @@
<t t-name="mail.CallInviteRequestPopupList" owl="1">
<div class="o_CallInviteRequestPopupList position-absolute top-0 end-0 d-flex flex-column p-2" t-attf-class="{{ className }}" t-ref="root">
<t t-if="messaging.ringingThreads">
<t t-foreach="messaging.callInviteRequestPopups" t-as="callInviteRequestPopup" t-key="callInviteRequestPopup.localId">
<CallInviteRequestPopup record="callInviteRequestPopup"/>
</t>
<CallInviteRequestPopup t-foreach="messaging.callInviteRequestPopups" t-as="callInviteRequestPopup" t-key="callInviteRequestPopup.localId" record="callInviteRequestPopup"/>
</t>
</div>
</t>
@@ -2,35 +2,33 @@
<templates xml:space="preserve">
<t t-name="mail.CallMainView" owl="1">
<div class="o_CallMainView d-flex flex-grow-1 flex-column align-items-center justify-content-center position-relative bg-black-50" t-ref="root" t-on-mouseleave="onMouseleave">
<div
class="o_CallMainView_grid d-flex align-items-center overflow-hidden h-100 w-100 flex-wrap justify-content-center"
t-attf-style="--height:{{tileHeight}}px; --width:{{tileWidth}}px;"
t-on-click="onClick"
t-on-mousemove="onMouseMove"
t-ref="tileContainer"
>
<t t-foreach="mainTiles" t-as="tile" t-key="'grid_tile_'+tile.localId">
<CallParticipantCard
className="'o_CallMainView_gridParticipantCard'"
record="tile.participantCard"
/>
</t>
</div>
<!-- Buttons -->
<t t-if="hasSidebarButton">
<i t-if="callView.isSidebarOpen" class="o_CallMainView_sidebarButton cursor-pointer position-absolute fa fa-arrow-right" title="Hide sidebar" t-on-click="onClickHideSidebar"/>
<i t-else="" class="o_CallMainView_sidebarButton cursor-pointer position-absolute fa fa-arrow-left" title="Show sidebar" t-on-click="onClickShowSidebar"/>
</t>
<t t-if="showOverlay or !isControllerFloating">
<div class="o_CallMainView_controls d-flex justify-content-center w-100 pb-1" t-att-class="{ 'o-isFloating position-absolute bottom-0 pb-3': isControllerFloating }">
<div class="o_CallMainView_controlsOverlayContainer" t-on-mousemove="onMouseMoveOverlay">
<CallActionListView record="callActionListView"/>
</div>
</div>
<div class="o_CallMainView d-flex flex-grow-1 flex-column align-items-center justify-content-center position-relative bg-black-50" t-ref="root" t-on-mouseleave="onMouseleave">
<div
class="o_CallMainView_grid d-flex align-items-center overflow-hidden h-100 w-100 flex-wrap justify-content-center"
t-attf-style="--height:{{tileHeight}}px; --width:{{tileWidth}}px;"
t-on-click="onClick"
t-on-mousemove="onMouseMove"
t-ref="tileContainer"
>
<t t-foreach="mainTiles" t-as="tile" t-key="'grid_tile_'+tile.localId">
<CallParticipantCard
className="'o_CallMainView_gridParticipantCard'"
record="tile.participantCard"
/>
</t>
</div>
<!-- Buttons -->
<t t-if="hasSidebarButton">
<i t-if="callView.isSidebarOpen" class="o_CallMainView_sidebarButton cursor-pointer position-absolute fa fa-arrow-right" title="Hide sidebar" t-on-click="onClickHideSidebar"/>
<i t-else="" class="o_CallMainView_sidebarButton cursor-pointer position-absolute fa fa-arrow-left" title="Show sidebar" t-on-click="onClickShowSidebar"/>
</t>
<div t-if="showOverlay or !isControllerFloating" class="o_CallMainView_controls d-flex justify-content-center w-100 pb-1" t-att-class="{ 'o-isFloating position-absolute bottom-0 pb-3': isControllerFloating }">
<div class="o_CallMainView_controlsOverlayContainer" t-on-mousemove="onMouseMoveOverlay">
<CallActionListView record="callActionListView"/>
</div>
</div>
</div>
</t>
</templates>
@@ -2,12 +2,12 @@
<templates xml:space="preserve">
<t t-name="mail.CallOptionMenu" owl="1">
<div class="o_CallOptionMenu d-flex flex-column p-3" t-attf-class="{{ className }}" t-ref="root">
<button class="o_CallOptionMenu_button btn d-flex align-items-center border-0 rounded text-800 fw-normal" t-on-click="onClickDownloadLogs">
<i class="o_CallOptionMenu_buttonIcon fa fa-lg fa-file-text-o m-1 p-1"/>
<span class="o_CallOptionMenu_buttonText text-truncate">Download logs</span>
</button>
</div>
<div class="o_CallOptionMenu d-flex flex-column p-3" t-attf-class="{{ className }}" t-ref="root">
<button class="o_CallOptionMenu_button btn d-flex align-items-center border-0 rounded text-800 fw-normal" t-on-click="onClickDownloadLogs">
<i class="o_CallOptionMenu_buttonIcon fa fa-lg fa-file-text-o m-1 p-1"/>
<span class="o_CallOptionMenu_buttonText text-truncate">Download logs</span>
</button>
</div>
</t>
</templates>
@@ -2,82 +2,61 @@
<templates xml:space="preserve">
<t t-name="mail.CallParticipantCard" owl="1">
<div class="o_CallParticipantCard position-relative cursor-pointer d-flex flex-column align-items-center justify-content-center mh-100 mw-100 p-1 rounded-1"
t-att-class="{
'o-isTalking': !isMinimized and isTalking,
'o-isInvitation opacity-50': !rtcSession,
}"
t-att-title="channelMember.persona.name"
t-att-aria-label="channelMember.persona.name"
t-attf-class="{{ className }}"
t-on-click="onClick"
t-on-contextmenu="onContextMenu"
t-ref="root"
>
<!-- card -->
<t t-if="callParticipantVideoView">
<CallParticipantVideoView record="callParticipantVideoView"/>
</t>
<t t-else="">
<div class="o_CallParticipantCard_avatarFrame d-flex align-items-center justify-content-center h-100 w-100 rounded-1" t-att-class="{ 'o-isMinimized': isMinimized }" draggable="false">
<img alt="Avatar"
t-att-class="{
'o-isTalking': isTalking,
'o-isInvitation': !rtcSession,
}"
class="o_CallParticipantCard_avatarImage h-100 rounded-circle border-5 o_object_fit_cover"
t-att-src="channelMember.avatarUrl"
draggable="false"
/>
</div>
</t>
<t t-if="rtcSession">
<!-- overlay -->
<span class="o_CallParticipantCard_overlay o_CallParticipantCard_overlayBottom position-absolute bottom-0 start-0 d-flex overflow-hidden">
<t t-if="!isMinimized">
<span class="o_CallParticipantCard_name p-1 rounded-1 bg-black-75 text-truncate" t-esc="channelMember.persona.name"/>
</t>
<t t-if="rtcSession.isScreenSharingOn and isMinimized and !rtcSession.channel.rtc">
<small class="o_CallParticipantCard_liveIndicator o-isMinimized rounded-pill text-bg-danger d-flex align-items-center fw-bolder" title="live" aria-label="live">
LIVE
</small>
</t>
</span>
<div class="o_CallParticipantCard_overlay o_CallParticipantCard_overlayTop position-absolute top-0 end-0 d-flex flex-row-reverse">
<t t-if="rtcSession.isSelfMuted and !rtcSession.isDeaf">
<span class="o_CallParticipantCard_overlayTopElement d-flex flex-column justify-content-center me-1 rounded-circle bg-900" t-att-class="{'o-isMinimized p-1': isMinimized, 'p-2': !isMinimized }" title="muted" aria-label="muted">
<i class="fa fa-microphone-slash"/>
</span>
</t>
<t t-if="rtcSession.isDeaf">
<span class="o_CallParticipantCard_overlayTopElement d-flex flex-column justify-content-center me-1 rounded-circle bg-900" t-att-class="{'o-isMinimized p-1': isMinimized, 'p-2': !isMinimized }" title="deaf" aria-label="deaf">
<i class="fa fa-deaf"/>
</span>
</t>
<t t-if="rtcSession.channel.rtc and rtcSession.isAudioInError">
<span class="o_CallParticipantCard_overlayTopElement d-flex flex-column justify-content-center me-1 p-2 rounded-circle bg-900 text-danger" title="Issue with audio">
<i class="fa fa-exclamation-triangle"/>
</span>
</t>
<t t-if="rtcSession.channel.rtc and !rtcSession.rtcAsCurrentSession and !['connected', 'completed'].includes(rtcSession.connectionState)">
<span class="o_CallParticipantCard_overlayTopElement d-flex flex-column justify-content-center me-1 p-2 rounded-circle bg-900" t-att-title="rtcSession.connectionState">
<i class="fa fa-exclamation-triangle o_CallParticipantCard_connectionState text-warning"/>
</span>
</t>
<t t-if="rtcSession.isScreenSharingOn and !isMinimized and !rtcSession.channel.rtc">
<span class="o_CallParticipantCard_liveIndicator rounded-pill text-bg-danger d-flex align-items-center me-1 fw-bolder" title="live" aria-label="live">
LIVE
</span>
</t>
</div>
<!-- volume popover -->
<t t-if="!rtcSession.isOwnSession">
<i class="o_CallParticipantCard_volumeMenuAnchor position-absolute bottom-0 start-50" t-on-click="onClickVolumeAnchor" t-ref="volumeMenuAnchor"/>
</t>
</t>
<div class="o_CallParticipantCard position-relative cursor-pointer d-flex flex-column align-items-center justify-content-center mh-100 mw-100 p-1 rounded-1"
t-att-class="{
'o-isTalking': !isMinimized and isTalking,
'o-isInvitation opacity-50': !rtcSession,
}"
t-att-title="channelMember.persona.name"
t-att-aria-label="channelMember.persona.name"
t-attf-class="{{ className }}"
t-on-click="onClick"
t-on-contextmenu="onContextMenu"
t-ref="root"
>
<!-- card -->
<CallParticipantVideoView t-if="callParticipantVideoView" record="callParticipantVideoView"/>
<div t-else="" class="o_CallParticipantCard_avatarFrame d-flex align-items-center justify-content-center h-100 w-100 rounded-1" t-att-class="{ 'o-isMinimized': isMinimized }" draggable="false">
<img alt="Avatar"
t-att-class="{
'o-isTalking': isTalking,
'o-isInvitation': !rtcSession,
}"
class="o_CallParticipantCard_avatarImage h-100 rounded-circle border-5 o_object_fit_cover"
t-att-src="channelMember.avatarUrl"
draggable="false"
/>
</div>
<t t-if="rtcSession">
<!-- overlay -->
<span class="o_CallParticipantCard_overlay o_CallParticipantCard_overlayBottom position-absolute bottom-0 start-0 d-flex overflow-hidden">
<span t-if="!isMinimized" class="o_CallParticipantCard_name p-1 rounded-1 bg-black-75 text-truncate" t-esc="channelMember.persona.name"/>
<small t-if="rtcSession.isScreenSharingOn and isMinimized and !rtcSession.channel.rtc" class="o_CallParticipantCard_liveIndicator o-isMinimized rounded-pill text-bg-danger d-flex align-items-center fw-bolder" title="live" aria-label="live">
LIVE
</small>
</span>
<div class="o_CallParticipantCard_overlay o_CallParticipantCard_overlayTop position-absolute top-0 end-0 d-flex flex-row-reverse">
<span t-if="rtcSession.isSelfMuted and !rtcSession.isDeaf" class="o_CallParticipantCard_overlayTopElement d-flex flex-column justify-content-center me-1 rounded-circle bg-900" t-att-class="{'o-isMinimized p-1': isMinimized, 'p-2': !isMinimized }" title="muted" aria-label="muted">
<i class="fa fa-microphone-slash"/>
</span>
<span t-if="rtcSession.isDeaf" class="o_CallParticipantCard_overlayTopElement d-flex flex-column justify-content-center me-1 rounded-circle bg-900" t-att-class="{'o-isMinimized p-1': isMinimized, 'p-2': !isMinimized }" title="deaf" aria-label="deaf">
<i class="fa fa-deaf"/>
</span>
<span t-if="rtcSession.channel.rtc and rtcSession.isAudioInError" class="o_CallParticipantCard_overlayTopElement d-flex flex-column justify-content-center me-1 p-2 rounded-circle bg-900 text-danger" title="Issue with audio">
<i class="fa fa-exclamation-triangle"/>
</span>
<span t-if="rtcSession.channel.rtc and !rtcSession.rtcAsCurrentSession and !['connected', 'completed'].includes(rtcSession.connectionState)" class="o_CallParticipantCard_overlayTopElement d-flex flex-column justify-content-center me-1 p-2 rounded-circle bg-900" t-att-title="rtcSession.connectionState">
<i class="fa fa-exclamation-triangle o_CallParticipantCard_connectionState text-warning"/>
</span>
<span t-if="rtcSession.isScreenSharingOn and !isMinimized and !rtcSession.channel.rtc" class="o_CallParticipantCard_liveIndicator rounded-pill text-bg-danger d-flex align-items-center me-1 fw-bolder" title="live" aria-label="live">
LIVE
</span>
</div>
<!-- volume popover -->
<i t-if="!rtcSession.isOwnSession" class="o_CallParticipantCard_volumeMenuAnchor position-absolute bottom-0 start-50" t-on-click="onClickVolumeAnchor" t-ref="volumeMenuAnchor"/>
</t>
</div>
</t>
</templates>
@@ -11,9 +11,7 @@
<div>
<select name="inputDevice" class="o_CallSettingsMenu_optionDeviceSelect form-select" t-att-value="messaging.userSetting.audioInputDeviceId" t-on-change="onChangeSelectAudioInput">
<option value="">Browser default</option>
<t t-foreach="userDevices" t-as="device" t-key="device_index">
<CallSettingsMenuDevice device="device"/>
</t>
<CallSettingsMenuDevice t-foreach="userDevices" t-as="device" t-key="device_index" device="device"/>
</select>
</div>
</label>
@@ -29,20 +27,13 @@
<label class="o_CallSettingsMenu_optionLabel o_CallSettingsMenu_pushToTalkKeyOption d-flex align-items-center flex-wrap mw-100 cursor-pointer" title="Push-to-talk key" aria-label="Push-to-talk key">
<span class="o_CallSettingsMenu_optionName me-2 text-truncate">Push-to-talk key</span>
<span class="o_CallSettingsMenu_optionPushToTalkGroup d-flex">
<t t-if="messaging.userSetting.pushToTalkKey">
<span class="o_CallSettingsMenu_optionPushToTalkGroupKey ms-1 px-3 border border-2 rounded fs-3" t-attf-class="{{ userSetting.isRegisteringKey ? 'o-isRegistering border-danger' : 'border-primary' }}" t-esc="messaging.userSetting.pushToTalkKeyToString()"/>
</t>
<span t-if="messaging.userSetting.pushToTalkKey" class="o_CallSettingsMenu_optionPushToTalkGroupKey ms-1 px-3 border border-2 rounded fs-3" t-attf-class="{{ userSetting.isRegisteringKey ? 'o-isRegistering border-danger' : 'border-primary' }}" t-esc="messaging.userSetting.pushToTalkKeyToString()"/>
<button class="o_CallSettingsMenu_button btn btn-link px-2 py-0 text-black" t-on-click="onClickRegisterKeyButton">
<t t-if="userSetting.isRegisteringKey">
<i title="Cancel" aria-label="Cancel" class="fa fa-2x fa-times-circle"/>
</t>
<t t-else="">
<i title="Register new key" aria-label="Register new key" class="fa fa-2x fa-keyboard-o"/>
</t>
<i t-if="userSetting.isRegisteringKey" title="Cancel" aria-label="Cancel" class="fa fa-2x fa-times-circle"/>
<i t-else="" title="Register new key" aria-label="Register new key" class="fa fa-2x fa-keyboard-o"/>
</button>
</span>
</label>
</div>
<div t-if="userSetting.isRegisteringKey">Press a key to register it as the push-to-talk shortcut</div>
<div class="o_CallSettingsMenu_option mb-3 d-flex align-items-center flex-wrap">
@@ -54,16 +45,14 @@
</label>
</div>
</t>
<t t-else="">
<div class="o_CallSettingsMenu_option mb-3 d-flex align-items-center flex-wrap">
<label class="o_CallSettingsMenu_optionLabel o_CallSettingsMenu_voiceThresholdOption d-flex align-items-center flex-wrap mw-100 cursor-pointer" title="Voice detection threshold" aria-label="Voice detection threshold">
<span class="o_CallSettingsMenu_optionName me-2 text-truncate">Voice detection threshold</span>
<div class="o_CallSettingsMenu_optionInputGroup d-flex w-100">
<input class="o_CallSettingsMenu_optionInputGroupInput form-range" type="range" min="0.001" max="1" step="0.001" t-att-value="messaging.userSetting.voiceActivationThreshold" t-on-change="onChangeThreshold"/>
</div>
</label>
</div>
</t>
<div t-else="" class="o_CallSettingsMenu_option mb-3 d-flex align-items-center flex-wrap">
<label class="o_CallSettingsMenu_optionLabel o_CallSettingsMenu_voiceThresholdOption d-flex align-items-center flex-wrap mw-100 cursor-pointer" title="Voice detection threshold" aria-label="Voice detection threshold">
<span class="o_CallSettingsMenu_optionName me-2 text-truncate">Voice detection threshold</span>
<div class="o_CallSettingsMenu_optionInputGroup d-flex w-100">
<input class="o_CallSettingsMenu_optionInputGroupInput form-range" type="range" min="0.001" max="1" step="0.001" t-att-value="messaging.userSetting.voiceActivationThreshold" t-on-change="onChangeThreshold"/>
</div>
</label>
</div>
</div>
<div class="o_CallSettingsMenu_category d-flex flex-column px-3 overflow-auto">
<div class="o_CallSettingsMenu_categoryTitle py-2 fw-bolder text-700 text-truncate text-uppercase">Video Settings</div>
@@ -73,14 +62,12 @@
<span class="o_CallSettingsMenu_optionName ms-2 text-truncate">Show video participants only</span>
</label>
</div>
<t t-if="messaging.device.hasCanvasFilterSupport">
<div class="o_CallSettingsMenu_option mb-3 d-flex align-items-center flex-wrap">
<label class="o_CallSettingsMenu_optionLabel o_CallSettingsMenu_blurOption d-flex align-items-center flex-wrap mw-100 cursor-pointer" title="Blur video background" aria-label="Blur video background">
<input type="checkbox" aria-label="Blur video background" title="Blur video background" t-on-change="onChangeBlur" t-att-checked="messaging.userSetting.useBlur ? 'checked' : ''" class="form-check-input"/>
<span class="o_CallSettingsMenu_optionName ms-2 text-truncate">Blur video background</span>
</label>
</div>
</t>
<div t-if="messaging.device.hasCanvasFilterSupport" class="o_CallSettingsMenu_option mb-3 d-flex align-items-center flex-wrap">
<label class="o_CallSettingsMenu_optionLabel o_CallSettingsMenu_blurOption d-flex align-items-center flex-wrap mw-100 cursor-pointer" title="Blur video background" aria-label="Blur video background">
<input type="checkbox" aria-label="Blur video background" title="Blur video background" t-on-change="onChangeBlur" t-att-checked="messaging.userSetting.useBlur ? 'checked' : ''" class="form-check-input"/>
<span class="o_CallSettingsMenu_optionName ms-2 text-truncate">Blur video background</span>
</label>
</div>
<t t-if="messaging.userSetting.useBlur">
<div class="o_CallSettingsMenu_option mb-3 d-flex align-items-center flex-wrap">
<label class="o_CallSettingsMenu_optionLabel o_CallSettingsMenu_backgroundBlurIntensityOption d-flex align-items-center flex-wrap mw-100 cursor-pointer" title="Background blur intensity" aria-label="Background blur intensity">
@@ -2,9 +2,7 @@
<templates xml:space="preserve">
<t t-name="mail.CallSettingsMenuDevice" owl="1">
<t t-if="props.device.kind === 'audioinput'">
<option t-att-value="props.device.deviceId" t-attf-class="{{ className }}" t-ref="root"><t t-esc="props.device.label"/></option>
</t>
<option t-if="props.device.kind === 'audioinput'" t-att-value="props.device.deviceId" t-attf-class="{{ className }}" t-ref="root"><t t-esc="props.device.label"/></option>
</t>
</templates>
@@ -2,14 +2,12 @@
<templates xml:space="preserve">
<t t-name="mail.CallSidebarView" owl="1">
<div class="o_CallSidebarView d-flex align-items-center h-100 flex-column">
<t t-foreach="sidebarTiles" t-as="tile" t-key="tile.localId">
<CallParticipantCard
className="'o_CallSidebarView_participantCard w-100'"
record="tile.participantCard"
/>
</t>
</div>
<div class="o_CallSidebarView d-flex align-items-center h-100 flex-column">
<CallParticipantCard t-foreach="sidebarTiles" t-as="tile" t-key="tile.localId"
className="'o_CallSidebarView_participantCard w-100'"
record="tile.participantCard"
/>
</div>
</t>
</templates>
@@ -5,23 +5,21 @@
<div class="o_CallSystrayMenu dropdown" t-attf-class="{{ className }}" t-ref="root">
<t t-if="messaging">
<CallInviteRequestPopupList/>
<t t-if="messaging.rtc.channel">
<button class="o_CallSystrayMenu_button px-3 user-select-none dropdown-toggle o-no-caret o-dropdown--narrow" t-att-title="callSystrayMenu.buttonTitle" role="button" t-on-click="messaging.rtc.onClickActivityNoticeButton">
<div class="o_CallSystrayMenu_buttonContent d-flex align-items-center">
<span class="position-relative me-2">
<i class="o_CallSystrayMenu_outputIndicator fa me-2" t-att-class="{
'fa-microphone': !messaging.rtc.sendDisplay and !messaging.rtc.sendUserVideo,
'fa-video-camera': messaging.rtc.sendUserVideo,
'fa-desktop': messaging.rtc.sendDisplay,
}"/>
<small class="position-absolute top-0 end-0 bottom-0 mt-n3 pt-1">
<i class="o_CallSystrayMenu_dot fa fa-circle text-warning small"/>
</small>
</span>
<em class="o_CallSystrayMenu_buttonTitle text-truncate" t-esc="messaging.rtc.channel.displayName"/>
</div>
</button>
</t>
<button t-if="messaging.rtc.channel" class="o_CallSystrayMenu_button px-3 user-select-none dropdown-toggle o-no-caret o-dropdown--narrow" t-att-title="callSystrayMenu.buttonTitle" role="button" t-on-click="messaging.rtc.onClickActivityNoticeButton">
<div class="o_CallSystrayMenu_buttonContent d-flex align-items-center">
<span class="position-relative me-2">
<i class="o_CallSystrayMenu_outputIndicator fa me-2" t-att-class="{
'fa-microphone': !messaging.rtc.sendDisplay and !messaging.rtc.sendUserVideo,
'fa-video-camera': messaging.rtc.sendUserVideo,
'fa-desktop': messaging.rtc.sendDisplay,
}"/>
<small class="position-absolute top-0 end-0 bottom-0 mt-n3 pt-1">
<i class="o_CallSystrayMenu_dot fa fa-circle text-warning small"/>
</small>
</span>
<em class="o_CallSystrayMenu_buttonTitle text-truncate" t-esc="messaging.rtc.channel.displayName"/>
</div>
</button>
</t>
</div>
</t>
@@ -3,9 +3,7 @@
<t t-name="mail.CallSystrayMenuContainer" owl="1">
<div class="CallSystrayMenuContainer">
<t t-if="messaging">
<CallSystrayMenu record="messaging.rtc.callSystrayMenu"/>
</t>
<CallSystrayMenu t-if="messaging" record="messaging.rtc.callSystrayMenu"/>
</div>
</t>
</templates>
@@ -4,10 +4,8 @@
<t t-name="mail.CallView" owl="1">
<div class="o_CallView d-flex" t-att-class="{'o-fullScreen fixed-top vw-100 vh-100': isFullScreen, 'o-isMinimized': isMinimized, 'position-relative': !isFullScreen }" t-attf-class="{{ className }}" t-ref="root">
<!-- Used to make the component depend on the window size and trigger an update when the window size changes. -->
<CallMainView record="callMainView"/>
<CallSidebarView t-if="callSidebarView" record="callSidebarView"/>
</div>
</t>
@@ -2,56 +2,42 @@
<templates xml:space="preserve">
<t t-name="mail.ChannelInvitationForm" owl="1">
<div class="o_ChannelInvitationForm d-flex flex-column" t-attf-class="{{ className }}" t-ref="root">
<h3 class="mx-3 mt-3 mb-2">Invite people</h3>
<t t-if="!messaging.isCurrentUserGuest">
<div class="mx-3 my-2">
<input class="o_ChannelInvitationForm_searchInput form-control" type="text" t-att-value="searchTerm" placeholder="Type the name of a person" t-on-input="onInputSearch" t-ref="searchInput"/>
<div class="o_ChannelInvitationForm d-flex flex-column" t-attf-class="{{ className }}" t-ref="root">
<h3 class="mx-3 mt-3 mb-2">Invite people</h3>
<t t-if="!messaging.isCurrentUserGuest">
<div class="mx-3 my-2">
<input class="o_ChannelInvitationForm_searchInput form-control" type="text" t-att-value="searchTerm" placeholder="Type the name of a person" t-on-input="onInputSearch" t-ref="searchInput"/>
</div>
<div class="d-flex flex-column flex-grow-1 mx-0 py-2 overflow-auto">
<ChannelInvitationFormSelectablePartnerView t-foreach="selectablePartnerViews" t-as="selectablePartnerView" t-key="selectablePartnerView.localId" record="selectablePartnerView"/>
<div t-if="selectablePartners.length === 0" class="mx-3">No user found that is not already a member of this channel.</div>
<div t-if="searchResultCount > selectablePartners.length" class="mx-3">
Showing <t t-esc="selectablePartners.length"/> results out of <t t-esc="searchResultCount"/>. Narrow your search to see more choices.
</div>
<div class="d-flex flex-column flex-grow-1 mx-0 py-2 overflow-auto">
<t t-foreach="selectablePartnerViews" t-as="selectablePartnerView" t-key="selectablePartnerView.localId">
<ChannelInvitationFormSelectablePartnerView record="selectablePartnerView"/>
</t>
<t t-if="selectablePartners.length === 0">
<div class="mx-3">No user found that is not already a member of this channel.</div>
</t>
<t t-if="searchResultCount > selectablePartners.length">
<div class="mx-3">
Showing <t t-esc="selectablePartners.length"/> results out of <t t-esc="searchResultCount"/>. Narrow your search to see more choices.
</div>
</t>
</div>
<div t-if="selectedPartners.length > 0" class="mx-3 mt-3">
<h4>Selected users:</h4>
<div class="o_ChannelInvitationForm_selectedPartners overflow-auto">
<ChannelInvitationFormSelectedPartnerView t-foreach="selectedPartnerViews" t-as="selectedPartnerView" t-key="selectedPartnerView.localId" record="selectedPartnerView"/>
</div>
<t t-if="selectedPartners.length > 0">
<div class="mx-3 mt-3">
<h4>Selected users:</h4>
<div class="o_ChannelInvitationForm_selectedPartners overflow-auto">
<t t-foreach="selectedPartnerViews" t-as="selectedPartnerView" t-key="selectedPartnerView.localId">
<ChannelInvitationFormSelectedPartnerView record="selectedPartnerView"/>
</t>
</div>
</div>
</t>
<div class="mx-3 mt-2 mb-3">
<button class="o_ChannelInvitationForm_inviteButton btn btn-primary w-100" t-att-disabled="selectedPartners.length === 0" t-on-click="onClickInvite">
<t t-esc="inviteButtonText"/>
</div>
<div class="mx-3 mt-2 mb-3">
<button class="o_ChannelInvitationForm_inviteButton btn btn-primary w-100" t-att-disabled="selectedPartners.length === 0" t-esc="inviteButtonText" t-on-click="onClickInvite"/>
</div>
</t>
<t t-if="thread and thread.invitationLink">
<h4 class="mx-3 mt-3 mb-2">Invitation Link</h4>
<div class="mx-3 mt-2 mb-3">
<div class="input-group">
<input class="form-control" type="text" t-att-value="thread.invitationLink" readonly="" t-on-focus="onFocusInvitationLinkInput" />
<button class="btn btn-primary" t-on-click="onClickCopy">
<i class="fa fa-copy"/>
</button>
</div>
</t>
<t t-if="thread and thread.invitationLink">
<h4 class="mx-3 mt-3 mb-2">Invitation Link</h4>
<div class="mx-3 mt-2 mb-3">
<div class="input-group">
<input class="form-control" type="text" t-att-value="thread.invitationLink" readonly="" t-on-focus="onFocusInvitationLinkInput" />
<button class="btn btn-primary" t-on-click="onClickCopy">
<i class="fa fa-copy"/>
</button>
</div>
<t t-if="accessRestrictedToGroupText">
<div class="o_ChannelInvitationForm_accessRestrictedToGroup mt-2" t-esc="accessRestrictedToGroupText"/>
</t>
</div>
</t>
</div>
<div t-if="accessRestrictedToGroupText" class="o_ChannelInvitationForm_accessRestrictedToGroup mt-2" t-esc="accessRestrictedToGroupText"/>
</div>
</t>
</div>
</t>
</templates>
@@ -5,20 +5,16 @@
<div class="o_ChannelInvitationFormSelectablePartnerView d-flex align-items-center px-3 py-1 btn-light" t-on-click="() => channelInvitationFormOwner.onClickSelectablePartner(partner)" t-att-data-partner-id="partner.id" t-attf-class="{{ className }}" t-ref="root">
<div class="o_ChannelInvitationFormSelectablePartnerView_avatarContainer position-relative flex-shrink-0">
<img class="o_ChannelInvitationFormSelectablePartnerView_avatar w-100 h-100 rounded-circle" t-att-src="partner.avatarUrl" alt="Avatar"/>
<t t-if="personaImStatusIconView">
<PersonaImStatusIconView
className="'o_ChannelInvitationFormSelectablePartnerView_imStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center text-white'"
classNameObj="{
'o_ChannelInvitationFormSelectablePartnerView_imStatusIcon-mobile': messaging.device.isSmall,
'small' : !messaging.device.isSmall,
}"
record="personaImStatusIconView"
/>
</t>
<PersonaImStatusIconView t-if="personaImStatusIconView"
className="'o_ChannelInvitationFormSelectablePartnerView_imStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center text-white'"
classNameObj="{
'o_ChannelInvitationFormSelectablePartnerView_imStatusIcon-mobile': messaging.device.isSmall,
'small' : !messaging.device.isSmall,
}"
record="personaImStatusIconView"
/>
</div>
<span class="o_ChannelInvitationFormSelectablePartnerView_name flex-grow-1 mx-2 text-truncate">
<t t-esc="partner.nameOrDisplayName"/>
</span>
<span class="o_ChannelInvitationFormSelectablePartnerView_name flex-grow-1 mx-2 text-truncate" t-esc="partner.nameOrDisplayName"/>
<input class="o_ChannelInvitationFormSelectablePartnerView_checkbox form-check-input flex-shrink-0" type="checkbox" t-att-checked="channelInvitationFormOwner.selectedPartners.includes(partner) ? 'checked' : undefined" t-on-input="ev => channelInvitationFormOwner.onInputPartnerCheckbox(partner, ev)" t-ref="selection-status"/>
</div>
</t>
@@ -5,21 +5,16 @@
<div class="o_ChannelMemberView d-flex align-items-center mx-2 p-2" t-att-class="{'cursor-pointer': hasOpenChat}" t-attf-class="{{ className }}" t-att-data-partner-id="channelMember.persona.partner and channelMember.persona.partner.id" t-att-title="memberTitleText" t-on-click="onClickMember" t-ref="root">
<div class="o_ChannelMemberView_avatarContainer position-relative flex-shrink-0">
<img class="o_ChannelMemberView_avatar rounded-circle w-100 h-100" t-att-src="channelMember.avatarUrl" alt="Avatar"/>
<t t-if="personaImStatusIconView">
<PersonaImStatusIconView
className="'o_ChannelMemberView_personaImStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center text-light'"
classNameObj="{
'o-isDeviceSmall': messaging.device.isSmall,
'small': !messaging.device.isSmall,
}"
record="personaImStatusIconView"
/>
</t>
<PersonaImStatusIconView t-if="personaImStatusIconView"
className="'o_ChannelMemberView_personaImStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center text-light'"
classNameObj="{
'o-isDeviceSmall': messaging.device.isSmall,
'small': !messaging.device.isSmall,
}"
record="personaImStatusIconView"
/>
</div>
<span class="o_ChannelMemberView_name ms-2 flex-column-1 text-truncate">
<t t-esc="channelMember.channel.thread.getMemberName(channelMember.persona)"/>
</span>
<span class="o_ChannelMemberView_name ms-2 flex-column-1 text-truncate" t-esc="channelMember.channel.thread.getMemberName(channelMember.persona)"/>
</div>
</t>
@@ -2,25 +2,15 @@
<templates xml:space="preserve">
<t t-name="mail.ChannelMemberListView" owl="1">
<div class="o_ChannelMemberListView d-flex flex-column overflow-auto bg-light" t-attf-class="{{ className }}" t-ref="root">
<t t-if="onlineCategoryView">
<ChannelMemberListCategoryView record="onlineCategoryView"/>
</t>
<t t-if="offlineCategoryView">
<ChannelMemberListCategoryView record="offlineCategoryView"/>
</t>
<t t-if="channel.unknownMemberCount === 1">
<span class="mx-2 mt-2">And 1 other member.</span>
</t>
<t t-if="channel.unknownMemberCount > 1">
<span class="mx-2 mt-2">And <t t-esc="channel.unknownMemberCount"/> other members.</span>
</t>
<t t-if="!channel.areAllMembersLoaded">
<div class="mx-2 my-1">
<button class="o_ChannelMemberListView_loadMoreButton btn btn-secondary" t-on-click="onClickLoadMoreMembers">Load more</button>
</div>
</t>
<div class="o_ChannelMemberListView d-flex flex-column overflow-auto bg-light" t-attf-class="{{ className }}" t-ref="root">
<ChannelMemberListCategoryView t-if="onlineCategoryView" record="onlineCategoryView"/>
<ChannelMemberListCategoryView t-if="offlineCategoryView" record="offlineCategoryView"/>
<span t-if="channel.unknownMemberCount === 1" class="mx-2 mt-2">And 1 other member.</span>
<span t-if="channel.unknownMemberCount > 1" class="mx-2 mt-2">And <t t-esc="channel.unknownMemberCount"/> other members.</span>
<div t-if="!channel.areAllMembersLoaded" class="mx-2 my-1">
<button class="o_ChannelMemberListView_loadMoreButton btn btn-secondary" t-on-click="onClickLoadMoreMembers">Load more</button>
</div>
</div>
</t>
</templates>
@@ -3,9 +3,7 @@
<t t-name="mail.ChannelMemberListCategoryView" owl="1">
<h6 class="m-2" t-esc="title"/>
<t t-foreach="channelMemberViews" t-as="channelMemberView" t-key="channelMemberView.localId">
<ChannelMemberView record="channelMemberView"/>
</t>
<ChannelMemberView t-foreach="channelMemberViews" t-as="channelMemberView" t-key="channelMemberView.localId" record="channelMemberView"/>
</t>
</templates>
@@ -2,72 +2,56 @@
<templates xml:space="preserve">
<t t-name="mail.ChannelPreviewView" owl="1">
<!--
The preview template is used by the discuss in mobile, and by the systray
menu in order to show preview of threads.
-->
<div class="o_NotificationListItem o_ChannelPreviewView d-flex flex-shrink-0 align-items-center p-1 cursor-pointer"
t-att-class="{ 'o-muted': channel.localMessageUnreadCounter === 0 }"
t-attf-class="{{ className }}"
t-on-click="onClick"
t-att-data-channel-id="channel.id"
t-ref="root"
>
<div class="o_NotificationListItem_sidebar o_ChannelPreviewView_sidebar m-1">
<div class="o_NotificationListItem_imageContainer o_ChannelPreviewView_imageContainer o_ChannelPreviewView_sidebarItem position-relative">
<img class="o_NotificationListItem_image o_ChannelPreviewView_image w-100 h-100 rounded-circle" t-att-src="imageUrl" alt="Thread Image"/>
<t t-if="personaImStatusIconView">
<PersonaImStatusIconView
className="'o_NotificationListItem_personaImStatusIcon o_ChannelPreviewView_personaImStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center'"
classNameObj="{
'o-isDeviceSmall': messaging.device.isSmall,
'small': !messaging.device.isSmall,
'o-muted': channel.localMessageUnreadCounter === 0,
}"
record="personaImStatusIconView"
/>
</t>
</div>
</div>
<div class="o_NotificationListItem_content o_ChannelPreviewView_content d-flex flex-column flex-grow-1 align-self-start m-2">
<div class="o_NotificationListItem_header o_ChannelPreviewView_header d-flex align-items-baseline">
<span class="o_NotificationListItem_name o_ChannelPreviewView_name text-truncate fw-bold" t-att-class="{ 'o-isDeviceSmall fs-5': messaging.device.isSmall, 'o-muted text-600': channel.localMessageUnreadCounter === 0 }">
<t t-esc="channel.displayName"/>
</span>
<t t-if="channel.localMessageUnreadCounter > 1">
<span class="o_NotificationListItem_counter o_ChannelPreviewView_counter mx-1 fw-bold">
(<t t-esc="channel.localMessageUnreadCounter"/>)
</span>
</t>
<t t-if="thread.rtcSessions.length > 0">
<span class="o_ChannelPreviewView_callIndicator fa fa-volume-up mx-2" t-att-class="{ 'o-isCalling text-danger': thread.rtc }"/>
</t>
<span class="flex-grow-1"/>
<t t-if="thread.lastMessage and thread.lastMessage.date">
<small class="o_NotificationListItem_date o_ChannelPreviewView_date flex-shrink-0 text-500" t-att-class="{ 'o-muted': channel.localMessageUnreadCounter === 0 }">
<t t-esc="thread.lastMessage.momentDate.fromNow()"/>
</small>
</t>
</div>
<div class="o_ChannelPreviewView_core d-flex align-items-baseline">
<span class="o_NotificationListItem_coreItem o_NotificationListItem_inlineText o_ChannelPreviewView_coreItem o_ChannelPreviewView_inlineText me-2 text-truncate" t-att-class="{ 'o-empty': isEmpty }">
<t t-if="lastTrackingValue">
<TrackingValue value="lastTrackingValue"/>
</t>
<t t-else="">
<t t-if="messageAuthorPrefixView">
<MessageAuthorPrefixView record="messageAuthorPrefixView"/>
</t>
<span class="o_ChannelPreviewView_messageBody" t-esc="inlineLastMessageBody"/>
</t>
</span>
<span class="flex-grow-1"/>
<t t-if="channel.localMessageUnreadCounter > 0">
<span class="o_NotificationListItem_coreItem o_NotificationListItem_markAsRead o_ChannelPreviewView_coreItem o_ChannelPreviewView_markAsRead fa fa-check d-flex flex-shrink-0 ms-2 text-600 opacity-50 opacity-100-hover" title="Mark as Read" t-on-click="onClickMarkAsRead" t-ref="markAsRead"/>
</t>
</div>
<!--
The preview template is used by the discuss in mobile, and by the systray
menu in order to show preview of threads.
-->
<div class="o_NotificationListItem o_ChannelPreviewView d-flex flex-shrink-0 align-items-center p-1 cursor-pointer"
t-att-class="{ 'o-muted': channel.localMessageUnreadCounter === 0 }"
t-attf-class="{{ className }}"
t-on-click="onClick"
t-att-data-channel-id="channel.id"
t-ref="root"
>
<div class="o_NotificationListItem_sidebar o_ChannelPreviewView_sidebar m-1">
<div class="o_NotificationListItem_imageContainer o_ChannelPreviewView_imageContainer o_ChannelPreviewView_sidebarItem position-relative">
<img class="o_NotificationListItem_image o_ChannelPreviewView_image w-100 h-100 rounded-circle" t-att-src="imageUrl" alt="Thread Image"/>
<PersonaImStatusIconView t-if="personaImStatusIconView"
className="'o_NotificationListItem_personaImStatusIcon o_ChannelPreviewView_personaImStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center'"
classNameObj="{
'o-isDeviceSmall': messaging.device.isSmall,
'small': !messaging.device.isSmall,
'o-muted': channel.localMessageUnreadCounter === 0,
}"
record="personaImStatusIconView"
/>
</div>
</div>
<div class="o_NotificationListItem_content o_ChannelPreviewView_content d-flex flex-column flex-grow-1 align-self-start m-2">
<div class="o_NotificationListItem_header o_ChannelPreviewView_header d-flex align-items-baseline">
<span class="o_NotificationListItem_name o_ChannelPreviewView_name text-truncate fw-bold" t-att-class="{ 'o-isDeviceSmall fs-5': messaging.device.isSmall, 'o-muted text-600': channel.localMessageUnreadCounter === 0 }" t-esc="channel.displayName"/>
<span t-if="channel.localMessageUnreadCounter > 1" class="o_NotificationListItem_counter o_ChannelPreviewView_counter mx-1 fw-bold">
(<t t-esc="channel.localMessageUnreadCounter"/>)
</span>
<span t-if="thread.rtcSessions.length > 0" class="o_ChannelPreviewView_callIndicator fa fa-volume-up mx-2" t-att-class="{ 'o-isCalling text-danger': thread.rtc }"/>
<span class="flex-grow-1"/>
<small t-if="thread.lastMessage and thread.lastMessage.date" class="o_NotificationListItem_date o_ChannelPreviewView_date flex-shrink-0 text-500" t-att-class="{ 'o-muted': channel.localMessageUnreadCounter === 0 }">
<t t-esc="thread.lastMessage.momentDate.fromNow()"/>
</small>
</div>
<div class="o_ChannelPreviewView_core d-flex align-items-baseline">
<span class="o_NotificationListItem_coreItem o_NotificationListItem_inlineText o_ChannelPreviewView_coreItem o_ChannelPreviewView_inlineText me-2 text-truncate" t-att-class="{ 'o-empty': isEmpty }">
<TrackingValue t-if="lastTrackingValue" value="lastTrackingValue"/>
<t t-else="">
<MessageAuthorPrefixView t-if="messageAuthorPrefixView" record="messageAuthorPrefixView"/>
<span class="o_ChannelPreviewView_messageBody" t-esc="inlineLastMessageBody"/>
</t>
</span>
<span class="flex-grow-1"/>
<span t-if="channel.localMessageUnreadCounter > 0" class="o_NotificationListItem_coreItem o_NotificationListItem_markAsRead o_ChannelPreviewView_coreItem o_ChannelPreviewView_markAsRead fa fa-check d-flex flex-shrink-0 ms-2 text-600 opacity-50 opacity-100-hover" title="Mark as Read" t-on-click="onClickMarkAsRead" t-ref="markAsRead"/>
</div>
</div>
</div>
</t>
</templates>
@@ -2,50 +2,38 @@
<templates xml:space="preserve">
<t t-name="mail.ChatWindow" owl="1">
<t t-if="chatWindow">
<div class="o_ChatWindow position-absolute bottom-0 d-flex flex-column rounded-top-3 bg-view" t-attf-class="{{ className }}" tabindex="0" t-att-data-visible-index="chatWindow.visibleIndex"
t-att-class="{
'o-focused': chatWindow.isFocused,
'o-folded': chatWindow.isFolded,
'o-fullscreen w-100 h-100': chatWindow.isFullscreen,
'o-isDeviceSmall position-fixed': messaging.device.isSmall,
'mw-100 mh-100': !messaging.device.isSmall,
'o-new-message': !chatWindow.thread,
}" t-att-style="chatWindow.componentStyle" t-on-keydown="chatWindow.onKeydown" t-on-focusout="chatWindow.onFocusout" t-att-data-chat-window-local-id="chatWindow.localId" t-att-data-thread-id="chatWindow.thread ? chatWindow.thread.id : ''" t-ref="root"
t-att-data-thread-model="chatWindow.thread ? chatWindow.thread.model : ''"
>
<ChatWindowHeaderView
className="'o_ChatWindow_header flex-grow-0 flex-shrink-0'"
record="chatWindow.chatWindowHeaderView"
<div class="o_ChatWindow position-absolute bottom-0 d-flex flex-column rounded-top-3 bg-view" t-attf-class="{{ className }}" tabindex="0" t-att-data-visible-index="chatWindow.visibleIndex"
t-att-class="{
'o-focused': chatWindow.isFocused,
'o-folded': chatWindow.isFolded,
'o-fullscreen w-100 h-100': chatWindow.isFullscreen,
'o-isDeviceSmall position-fixed': messaging.device.isSmall,
'mw-100 mh-100': !messaging.device.isSmall,
'o-new-message': !chatWindow.thread,
}" t-att-style="chatWindow.componentStyle" t-on-keydown="chatWindow.onKeydown" t-on-focusout="chatWindow.onFocusout" t-att-data-chat-window-local-id="chatWindow.localId" t-att-data-thread-id="chatWindow.thread ? chatWindow.thread.id : ''" t-ref="root"
t-att-data-thread-model="chatWindow.thread ? chatWindow.thread.model : ''"
>
<ChatWindowHeaderView
className="'o_ChatWindow_header flex-grow-0 flex-shrink-0'"
record="chatWindow.chatWindowHeaderView"
/>
<ChannelMemberListView t-if="chatWindow.channelMemberListView" record="chatWindow.channelMemberListView" className="'bg-view'"/>
<CallSettingsMenu t-if="chatWindow.callSettingsMenu" record="chatWindow.callSettingsMenu" className="'bg-view'"/>
<ChannelInvitationForm t-if="chatWindow.channelInvitationForm" className="'o_ChatWindow_channelInvitationForm'" record="chatWindow.channelInvitationForm"/>
<ThreadView t-if="chatWindow.threadView"
className="'o_ChatWindow_thread flex-grow-1 flex-shrink-1'"
record="chatWindow.threadView"
/>
<div t-if="chatWindow.newMessageAutocompleteInputView" class="o_ChatWindow_newMessageForm d-flex align-items-center m-3">
<span class="o_ChatWindow_newMessageFormLabel flex-grow-0 flex-shrink-0 me-2">
To:
</span>
<AutocompleteInputView
className="'o_ChatWindow_newMessageFormInput flex-grow-1 flex-shrink-1 border'"
record="chatWindow.newMessageAutocompleteInputView"
/>
<t t-if="chatWindow.channelMemberListView">
<ChannelMemberListView record="chatWindow.channelMemberListView" className="'bg-view'"/>
</t>
<t t-if="chatWindow.callSettingsMenu">
<CallSettingsMenu record="chatWindow.callSettingsMenu" className="'bg-view'"/>
</t>
<t t-if="chatWindow.channelInvitationForm">
<ChannelInvitationForm className="'o_ChatWindow_channelInvitationForm'" record="chatWindow.channelInvitationForm"/>
</t>
<t t-if="chatWindow.threadView">
<ThreadView
className="'o_ChatWindow_thread flex-grow-1 flex-shrink-1'"
record="chatWindow.threadView"
/>
</t>
<t t-if="chatWindow.newMessageAutocompleteInputView">
<div class="o_ChatWindow_newMessageForm d-flex align-items-center m-3">
<span class="o_ChatWindow_newMessageFormLabel flex-grow-0 flex-shrink-0 me-2">
To:
</span>
<AutocompleteInputView
className="'o_ChatWindow_newMessageFormInput flex-grow-1 flex-shrink-1 border'"
record="chatWindow.newMessageAutocompleteInputView"
/>
</div>
</t>
</div>
</t>
</div>
</t>
</templates>
@@ -3,25 +3,17 @@
<t t-name="mail.ChatWindowHeaderView" owl="1">
<div class="o_ChatWindowHeaderView d-flex align-items-center" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'cursor-pointer': !messaging.device.isSmall }" t-attf-class="{{ className }}" t-on-click="onClick" t-ref="root">
<t t-if="chatWindowOwner.hasCloseAsBackButton">
<div class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandBack o_ChatWindowHeaderView_commandClose cursor-pointer d-flex align-items-center h-100 px-3 py-0 me-2" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall }" t-on-click="chatWindowOwner.onClickClose" title="Close conversation">
<i class="fa fa-arrow-left"/>
</div>
</t>
<t t-if="threadIconView">
<ThreadIconView
className="'o_ChatWindowHeaderView_icon o_ChatWindowHeaderView_item ms-3 me-1 my-0'"
record="threadIconView"
/>
</t>
<div class="o_ChatWindowHeaderView_item o_ChatWindowHeaderView_name mh-100 mx-1 my-0 text-truncate" t-att-class="{'ms-3':!chatWindowOwner.thread or !chatWindowOwner.thread.channel}" t-att-title="chatWindowOwner.name">
<t t-esc="chatWindowOwner.name"/>
<div t-if="chatWindowOwner.hasCloseAsBackButton" class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandBack o_ChatWindowHeaderView_commandClose cursor-pointer d-flex align-items-center h-100 px-3 py-0 me-2" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall }" t-on-click="chatWindowOwner.onClickClose" title="Close conversation">
<i class="fa fa-arrow-left"/>
</div>
<ThreadIconView t-if="threadIconView"
className="'o_ChatWindowHeaderView_icon o_ChatWindowHeaderView_item ms-3 me-1 my-0'"
record="threadIconView"
/>
<div class="o_ChatWindowHeaderView_item o_ChatWindowHeaderView_name mh-100 mx-1 my-0 text-truncate" t-att-class="{'ms-3':!chatWindowOwner.thread or !chatWindowOwner.thread.channel}" t-esc="chatWindowOwner.name" t-att-title="chatWindowOwner.name"/>
<div t-if="chatWindowOwner.thread and chatWindowOwner.thread.channel and chatWindowOwner.thread.channel.localMessageUnreadCounter > 0" class="o_ChatWindowHeaderView_counter o_ChatWindowHeaderView_item mx-1 my-0">
(<t t-esc="chatWindowOwner.thread.channel.localMessageUnreadCounter"/>)
</div>
<t t-if="chatWindowOwner.thread and chatWindowOwner.thread.channel and chatWindowOwner.thread.channel.localMessageUnreadCounter > 0">
<div class="o_ChatWindowHeaderView_counter o_ChatWindowHeaderView_item mx-1 my-0">
(<t t-esc="chatWindowOwner.thread.channel.localMessageUnreadCounter"/>)
</div>
</t>
<div class="flex-grow-1"/>
<div class="o_ChatWindowHeaderView_item o_ChatWindowHeaderView_rightArea d-flex align-items-center h-100 ms-1 me-0 my-0" t-att-class="{'opacity-75 opacity-100-hover': !messaging.device.isSmall }">
<t t-if="chatWindowOwner.hasCallButtons">
@@ -33,47 +25,31 @@
</div>
</t>
<t t-if="chatWindowOwner.hasInviteFeature">
<t t-if="!chatWindowOwner.channelInvitationForm">
<div class="o_ChatWindowHeaderView_command cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" title="Add users" t-on-click="chatWindowOwner.onClickShowInviteForm">
<i class="fa fa-lg fa-user-plus"/>
</div>
</t>
<t t-if="chatWindowOwner.channelInvitationForm">
<div class="o_ChatWindowHeaderView_command cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" title="Stop adding users" t-on-click="chatWindowOwner.onClickHideInviteForm">
<i class="fa fa-lg fa-user-plus"/>
</div>
</t>
</t>
<t t-if="chatWindowOwner.thread and chatWindowOwner.thread.hasMemberListFeature and !chatWindowOwner.isMemberListOpened">
<div class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandShowMemberList cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall}" title="Show Member List" t-on-click="chatWindowOwner.onClickShowMemberList">
<i class="fa fa-users"/>
</div>
</t>
<t t-if="chatWindowOwner.thread and chatWindowOwner.thread.hasMemberListFeature and chatWindowOwner.isMemberListOpened">
<div class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandHideMemberList cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" title="Hide Member List" t-on-click="chatWindowOwner.onClickHideMemberList">
<i class="fa fa-users"/>
</div>
</t>
<t t-if="chatWindowOwner.thread and chatWindowOwner.thread.hasCallFeature and !chatWindowOwner.isCallSettingsMenuOpen">
<div class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandShowCallSettingsMenu cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall}" title="Show Member List" t-on-click="chatWindowOwner.onClickShowCallSettingsMenu">
<i class="fa fa-gear"/>
</div>
</t>
<t t-if="chatWindowOwner.thread and chatWindowOwner.thread.hasCallFeature and chatWindowOwner.isCallSettingsMenuOpen">
<div class="o_ChatWindowHeaderView_command cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" title="Hide Member List" t-on-click="chatWindowOwner.onClickHideCallSettingsMenu">
<i class="fa fa-gear"/>
</div>
</t>
<t t-if="chatWindowOwner.isExpandable">
<div class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandExpand cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" t-on-click="chatWindowOwner.onClickExpand" title="Open in Discuss">
<i class="fa fa-expand"/>
</div>
</t>
<t t-if="!chatWindowOwner.hasCloseAsBackButton">
<div class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandClose cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" t-on-click="chatWindowOwner.onClickClose" title="Close chat window">
<i class="fa fa-close"/>
<div t-if="!chatWindowOwner.channelInvitationForm" class="o_ChatWindowHeaderView_command cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" title="Add users" t-on-click="chatWindowOwner.onClickShowInviteForm">
<i class="fa fa-lg fa-user-plus"/>
</div>
<div t-if="chatWindowOwner.channelInvitationForm" class="o_ChatWindowHeaderView_command cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" title="Stop adding users" t-on-click="chatWindowOwner.onClickHideInviteForm">
<i class="fa fa-lg fa-user-plus"/>
</div>
</t>
<div t-if="chatWindowOwner.thread and chatWindowOwner.thread.hasMemberListFeature and !chatWindowOwner.isMemberListOpened" class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandShowMemberList cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall}" title="Show Member List" t-on-click="chatWindowOwner.onClickShowMemberList">
<i class="fa fa-users"/>
</div>
<div t-if="chatWindowOwner.thread and chatWindowOwner.thread.hasMemberListFeature and chatWindowOwner.isMemberListOpened" class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandHideMemberList cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" title="Hide Member List" t-on-click="chatWindowOwner.onClickHideMemberList">
<i class="fa fa-users"/>
</div>
<div t-if="chatWindowOwner.thread and chatWindowOwner.thread.hasCallFeature and !chatWindowOwner.isCallSettingsMenuOpen" class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandShowCallSettingsMenu cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall}" title="Show Member List" t-on-click="chatWindowOwner.onClickShowCallSettingsMenu">
<i class="fa fa-gear"/>
</div>
<div t-if="chatWindowOwner.thread and chatWindowOwner.thread.hasCallFeature and chatWindowOwner.isCallSettingsMenuOpen" class="o_ChatWindowHeaderView_command cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" title="Hide Member List" t-on-click="chatWindowOwner.onClickHideCallSettingsMenu">
<i class="fa fa-gear"/>
</div>
<div t-if="chatWindowOwner.isExpandable" class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandExpand cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" t-on-click="chatWindowOwner.onClickExpand" title="Open in Discuss">
<i class="fa fa-expand"/>
</div>
<div t-if="!chatWindowOwner.hasCloseAsBackButton" class="o_ChatWindowHeaderView_command o_ChatWindowHeaderView_commandClose cursor-pointer d-flex align-items-center h-100 px-3 py-0 m-0" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'opacity-50 opacity-100-hover': !messaging.device.isSmall }" t-on-click="chatWindowOwner.onClickClose" title="Close chat window">
<i class="fa fa-close"/>
</div>
</div>
</div>
</t>
@@ -5,20 +5,12 @@
<div class="o_ChatWindowHiddenMenuView dropup position-fixed bottom-0 align-items-stretch d-flex px-2 py-1 rounded-top-3 bg-900 cursor-pointer" t-attf-class="{{ className }}" t-ref="root">
<div class="o_ChatWindowHiddenMenuView_dropdownToggle dropdown-toggle justify-content-center align-items-center flex-grow-1 d-flex mw-100" t-att-class="{ 'show opacity-50': isOpen }" data-bs-toggle="dropdown" t-on-click="messaging.chatWindowManager.onClickHiddenMenuToggler">
<div class="o_ChatWindowHiddenMenuView_dropdownToggleIcon o_ChatWindowHiddenMenuView_dropdownToggleItem me-1 fa fa-comments-o"/>
<div class="o_ChatWindowHiddenMenuView_dropdownToggleItem o_ChatWindowHiddenMenuView_windowCounter mx-1 text-truncate">
<t t-esc="messaging.chatWindowManager.allOrderedHidden.length"/>
</div>
<div class="o_ChatWindowHiddenMenuView_dropdownToggleItem o_ChatWindowHiddenMenuView_windowCounter mx-1 text-truncate" t-esc="messaging.chatWindowManager.allOrderedHidden.length"/>
</div>
<ul class="o_ChatWindowHiddenMenuView_list dropdown-menu dropdown-menu-end m-0 p-0 overflow-auto" t-att-class="{ show: isOpen }" role="menu" t-ref="list">
<t t-foreach="items" t-as="item" t-key="item.localId">
<ChatWindowHiddenMenuItemView record="item"/>
</t>
<ChatWindowHiddenMenuItemView record="item" t-foreach="items" t-as="item" t-key="item.localId"/>
</ul>
<t t-if="messaging.chatWindowManager.unreadHiddenConversationAmount > 0">
<div class="o_ChatWindowHiddenMenuView_unreadCounter position-absolute end-0 top-0 badge rounded-pill text-bg-primary">
<t t-esc="messaging.chatWindowManager.unreadHiddenConversationAmount"/>
</div>
</t>
<div t-if="messaging.chatWindowManager.unreadHiddenConversationAmount > 0" class="o_ChatWindowHiddenMenuView_unreadCounter position-absolute end-0 top-0 badge rounded-pill text-bg-primary" t-esc="messaging.chatWindowManager.unreadHiddenConversationAmount"/>
</div>
</t>
@@ -5,9 +5,7 @@
<div class="o_ChatWindowManager flex-row-reverse d-flex" t-attf-class="{{ className }}" t-ref="root">
<!-- Note: DOM elements are ordered from left to right -->
<ChatWindowHiddenMenuView t-if="messaging.chatWindowManager.hiddenMenuView" className="'o_ChatWindowManager_hiddenMenu'" record="messaging.chatWindowManager.hiddenMenuView"/>
<t t-foreach="messaging.chatWindowManager.allOrderedVisible" t-as="chatWindow" t-key="chatWindow.localId">
<ChatWindow record="chatWindow"/>
</t>
<ChatWindow t-foreach="messaging.chatWindowManager.allOrderedVisible" t-as="chatWindow" t-key="chatWindow.localId" record="chatWindow"/>
</div>
</t>
@@ -2,50 +2,38 @@
<templates xml:space="preserve">
<t t-name="mail.Chatter" owl="1">
<t t-if="chatter">
<div class="o_Chatter position-relative flex-grow-1 flex-column d-flex w-100 bg-view" t-attf-class="{{ className }}" t-ref="root">
<t t-if="chatter.dropZoneView">
<DropZoneView
className="'o_Chatter_dropZone'"
record="chatter.dropZoneView"
/>
</t>
<div class="o_Chatter_fixedPanel">
<ChatterTopbar
t-if="chatter.topbar"
className="'o_Chatter_topbar'"
record="chatter.topbar"
/>
<t t-if="chatter.composerView">
<ComposerView
className="'o_Chatter_composer border-bottom'"
classNameObj="{ 'o-bordered': chatter.hasExternalBorder }"
record="chatter.composerView"
/>
</t>
</div>
<div class="o_Chatter_scrollPanel overflow-auto" t-on-scroll="chatter.onScrollScrollPanel" t-ref="scrollPanel">
<t t-if="chatter.attachmentBoxView">
<AttachmentBoxView
className="'o_Chatter_attachmentBox'"
record="chatter.attachmentBoxView"
/>
</t>
<t t-if="chatter.activityBoxView">
<ActivityBoxView
className="'o_Chatter_activityBox'"
record="chatter.activityBoxView"
/>
</t>
<t t-if="chatter.threadView">
<ThreadView
className="'o_Chatter_thread'"
record="chatter.threadView"
/>
</t>
</div>
<div class="o_Chatter position-relative flex-grow-1 flex-column d-flex w-100 bg-view" t-attf-class="{{ className }}" t-ref="root">
<DropZoneView t-if="chatter.dropZoneView"
className="'o_Chatter_dropZone'"
record="chatter.dropZoneView"
/>
<div class="o_Chatter_fixedPanel">
<ChatterTopbar
t-if="chatter.topbar"
className="'o_Chatter_topbar'"
record="chatter.topbar"
/>
<ComposerView t-if="chatter.composerView"
className="'o_Chatter_composer border-bottom'"
classNameObj="{ 'o-bordered': chatter.hasExternalBorder }"
record="chatter.composerView"
/>
</div>
</t>
<div class="o_Chatter_scrollPanel overflow-auto" t-on-scroll="chatter.onScrollScrollPanel" t-ref="scrollPanel">
<AttachmentBoxView t-if="chatter.attachmentBoxView"
className="'o_Chatter_attachmentBox'"
record="chatter.attachmentBoxView"
/>
<ActivityBoxView t-if="chatter.activityBoxView"
className="'o_Chatter_activityBox'"
record="chatter.activityBoxView"
/>
<ThreadView t-if="chatter.threadView"
className="'o_Chatter_thread'"
record="chatter.threadView"
/>
</div>
</div>
</t>
</templates>
@@ -3,12 +3,8 @@
<t t-name="mail.ChatterContainer" owl="1">
<div class="o_ChatterContainer flex-grow-1 d-flex" t-att-class="{ 'o-isInFormSheetBg mx-auto': props.isInFormSheetBg }" t-attf-class="{{ props.className }}" data-command-category="mail" t-ref="root">
<t t-if="chatter and chatter.thread">
<Chatter record="chatter"/>
</t>
<t t-else="">
<div class="o_ChatterContainer_noChatter flex-grow-1 align-items-center justify-content-center d-flex"><i class="o_ChatterContainer_noChatterIcon fa fa-circle-o-notch fa-spin me-2"/>Please wait...</div>
</t>
<Chatter t-if="chatter and chatter.thread" record="chatter"/>
<div t-else="" class="o_ChatterContainer_noChatter flex-grow-1 align-items-center justify-content-center d-flex"><i class="o_ChatterContainer_noChatterIcon fa fa-circle-o-notch fa-spin me-2"/>Please wait...</div>
</div>
</t>
@@ -2,88 +2,76 @@
<templates xml:space="preserve">
<t t-name="mail.ChatterTopbar" owl="1">
<div class="o_ChatterTopbar justify-content-between d-flex" t-attf-class="{{ className }}" t-ref="root">
<div class="o_ChatterTopbar_actions flex-fill d-flex border-transparent">
<div class="o_ChatterTopbar_controllers d-flex pe-2" t-if="chatter.threadView">
<button class="o_ChatterTopbar_button o_ChatterTopbar_buttonSendMessage btn text-nowrap me-2"
type="button"
t-att-class="{
'o-active btn-odoo': chatter.composerView and !chatter.composerView.composer.isLog,
'btn-odoo': !chatter.composerView,
'btn-light': chatter.composerView and chatter.composerView.composer.isLog,
}"
t-att-disabled="!chatter.hasWriteAccess"
data-hotkey="m"
t-on-click="chatter.onClickSendMessage"
>
Send message
</button>
<button class="o_ChatterTopbar_button o_ChatterTopbar_buttonLogNote btn text-nowrap"
type="button"
t-att-class="{
'o-active btn-odoo': chatter.composerView and chatter.composerView.composer.isLog,
'btn-light': chatter.composerView and !chatter.composerView.composer.isLog or !chatter.composerView,
}"
t-att-disabled="!chatter.hasWriteAccess"
t-on-click="chatter.onClickLogNote"
data-hotkey="shift+m"
>
Log note
</button>
</div>
<div class="o_ChatterTopbar_tools position-relative d-flex flex-grow-1 border-bottom"
<div class="o_ChatterTopbar justify-content-between d-flex" t-attf-class="{{ className }}" t-ref="root">
<div class="o_ChatterTopbar_actions flex-fill d-flex border-transparent">
<div class="o_ChatterTopbar_controllers d-flex pe-2" t-if="chatter.threadView">
<button class="o_ChatterTopbar_button o_ChatterTopbar_buttonSendMessage btn text-nowrap me-2"
type="button"
t-att-class="{
'border-start ps-2': chatter.hasActivities,
'o-active btn-odoo': chatter.composerView and !chatter.composerView.composer.isLog,
'btn-odoo': !chatter.composerView,
'btn-light': chatter.composerView and chatter.composerView.composer.isLog,
}"
t-att-disabled="!chatter.hasWriteAccess"
data-hotkey="m"
t-on-click="chatter.onClickSendMessage"
>
<t t-if="chatter.hasActivities">
<button class="o_ChatterTopbar_button o_ChatterTopbar_buttonScheduleActivity btn btn-light text-nowrap" type="button" t-att-disabled="!chatter.hasWriteAccess" t-on-click="chatter.onClickScheduleActivity" data-hotkey="shift+a">
<i class="fa fa-clock-o me-1"/>
<span>Activities</span>
</button>
Send message
</button>
<button class="o_ChatterTopbar_button o_ChatterTopbar_buttonLogNote btn text-nowrap"
type="button"
t-att-class="{
'o-active btn-odoo': chatter.composerView and chatter.composerView.composer.isLog,
'btn-light': chatter.composerView and !chatter.composerView.composer.isLog or !chatter.composerView,
}"
t-att-disabled="!chatter.hasWriteAccess"
t-on-click="chatter.onClickLogNote"
data-hotkey="shift+m"
>
Log note
</button>
</div>
<div class="o_ChatterTopbar_tools position-relative d-flex flex-grow-1 border-bottom"
t-att-class="{
'border-start ps-2': chatter.hasActivities,
}"
>
<button t-if="chatter.hasActivities" class="o_ChatterTopbar_button o_ChatterTopbar_buttonScheduleActivity btn btn-light text-nowrap" type="button" t-att-disabled="!chatter.hasWriteAccess" t-on-click="chatter.onClickScheduleActivity" data-hotkey="shift+a">
<i class="fa fa-clock-o me-1"/>
<span>Activities</span>
</button>
<div class="flex-grow-1 border-start pe-2"
t-att-class="{
'ms-2': chatter.hasActivities,
}"
/>
<div class="o_ChatterTopbar_rightSection flex-grow-1 flex-shrink-0 justify-content-end d-flex">
<button t-if="chatter.thread.allAttachments.length === 0" class="o_ChatterTopbar_button o_ChatterTopbar_buttonAddAttachments btn btn-light btn-primary" type="button" t-att-disabled="!chatter.hasWriteAccess" t-on-click="chatter.onClickButtonAddAttachments" >
<i class="fa fa-paperclip fa-lg me-1" role="img" aria-label="Attachments"/>
<i t-if="chatter.isShowingAttachmentsLoading" class="o_ChatterTopbar_buttonAttachmentsCountLoader fa fa-circle-o-notch fa-spin" aria-label="Attachment counter loading..."/>
</button>
<button t-if="chatter.thread.allAttachments.length > 0" class="o_ChatterTopbar_button o_ChatterTopbar_buttonToggleAttachments btn btn-light btn-primary" type="button" t-att-disabled="!chatter.hasReadAccess" t-att-aria-expanded="chatter.attachmentBoxView ? 'true' : 'false'" t-on-click="chatter.onClickButtonToggleAttachments">
<i class="fa fa-paperclip fa-lg me-1" role="img" aria-label="Attachments"/>
<span t-if="!chatter.isShowingAttachmentsLoading" class="o_ChatterTopbar_buttonCount o_ChatterTopbar_buttonAttachmentsCount" t-esc="attachmentButtonText"/>
<i t-if="chatter.isShowingAttachmentsLoading" class="o_ChatterTopbar_buttonAttachmentsCountLoader fa fa-circle-o-notch fa-spin" aria-label="Attachment counter loading..."/>
</button>
<t t-if="chatter.hasFollowers and chatter.thread">
<FollowerListMenuView
className="'o_ChatterTopbar_followerListMenu'"
record="chatter.followerListMenuView"
/>
<FollowButtonView t-if="chatter.followButtonView"
className="'o_ChatterTopbar_followButton'"
record="chatter.followButtonView"
/>
</t>
<div class="flex-grow-1 border-start pe-2"
t-att-class="{
'ms-2': chatter.hasActivities,
}"
/>
<div class="o_ChatterTopbar_rightSection flex-grow-1 flex-shrink-0 justify-content-end d-flex">
<button t-if="chatter.thread.allAttachments.length === 0" class="o_ChatterTopbar_button o_ChatterTopbar_buttonAddAttachments btn btn-light btn-primary" type="button" t-att-disabled="!chatter.hasWriteAccess" t-on-click="chatter.onClickButtonAddAttachments" >
<i class="fa fa-paperclip fa-lg me-1" role="img" aria-label="Attachments"/>
<t t-if="chatter.isShowingAttachmentsLoading">
<i class="o_ChatterTopbar_buttonAttachmentsCountLoader fa fa-circle-o-notch fa-spin" aria-label="Attachment counter loading..."/>
</t>
</button>
<button t-if="chatter.thread.allAttachments.length > 0" class="o_ChatterTopbar_button o_ChatterTopbar_buttonToggleAttachments btn btn-light btn-primary" type="button" t-att-disabled="!chatter.hasReadAccess" t-att-aria-expanded="chatter.attachmentBoxView ? 'true' : 'false'" t-on-click="chatter.onClickButtonToggleAttachments">
<i class="fa fa-paperclip fa-lg me-1" role="img" aria-label="Attachments"/>
<t t-if="!chatter.isShowingAttachmentsLoading">
<span class="o_ChatterTopbar_buttonCount o_ChatterTopbar_buttonAttachmentsCount" t-esc="attachmentButtonText"/>
</t>
<t t-if="chatter.isShowingAttachmentsLoading">
<i class="o_ChatterTopbar_buttonAttachmentsCountLoader fa fa-circle-o-notch fa-spin" aria-label="Attachment counter loading..."/>
</t>
</button>
<t t-if="chatter.hasFollowers and chatter.thread">
<FollowerListMenuView
className="'o_ChatterTopbar_followerListMenu'"
record="chatter.followerListMenuView"
/>
<t t-if="chatter.followButtonView">
<FollowButtonView
className="'o_ChatterTopbar_followButton'"
record="chatter.followButtonView"
/>
</t>
</t>
</div>
</div>
</div>
<t t-if="chatter.hasTopbarCloseButton">
<button class="o_ChatterTopbar_buttonClose btn btn-dark flex-shrink-0 rounded-bottom-3" aria-label="Close" t-on-click="chatter.onClickChatterTopbarClose">
<i class="oi oi-large oi-close"/>
</button>
</t>
</div>
<button t-if="chatter.hasTopbarCloseButton" class="o_ChatterTopbar_buttonClose btn btn-dark flex-shrink-0 rounded-bottom-3" aria-label="Close" t-on-click="chatter.onClickChatterTopbarClose">
<i class="oi oi-large oi-close"/>
</button>
</div>
</t>
</templates>
@@ -2,168 +2,140 @@
<templates xml:space="preserve">
<t t-name="mail.ComposerView" owl="1">
<div class="o_ComposerView"
t-att-class="{
'o-focused': isFocused,
'o-has-current-partner-avatar pe-3 ps-1': hasCurrentPartnerAvatar,
'o-has-footer': hasFooter,
'o-has-header': hasHeader,
'o-is-in-thread-view bg-view': threadView,
'o-is-compact': isCompact,
'o-messaging-in-editing': messageViewInEditing,
'pt-3 pb-4': hasCurrentPartnerAvatar and hasHeader,
'py-4': hasCurrentPartnerAvatar and !hasHeader and !threadView,
'py-1': hasCurrentPartnerAvatar and !hasHeader and threadView,
}"
t-attf-class="{{ className }}"
t-on-keydown="onKeydown"
t-ref="root"
>
<t t-if="dropZoneView">
<DropZoneView
className="'o_ComposerView_dropZone'"
record="dropZoneView"
/>
<div class="o_ComposerView"
t-att-class="{
'o-focused': isFocused,
'o-has-current-partner-avatar pe-3 ps-1': hasCurrentPartnerAvatar,
'o-has-footer': hasFooter,
'o-has-header': hasHeader,
'o-is-in-thread-view bg-view': threadView,
'o-is-compact': isCompact,
'o-messaging-in-editing': messageViewInEditing,
'pt-3 pb-4': hasCurrentPartnerAvatar and hasHeader,
'py-4': hasCurrentPartnerAvatar and !hasHeader and !threadView,
'py-1': hasCurrentPartnerAvatar and !hasHeader and threadView,
}"
t-attf-class="{{ className }}"
t-on-keydown="onKeydown"
t-ref="root"
>
<DropZoneView t-if="dropZoneView"
className="'o_ComposerView_dropZone'"
record="dropZoneView"
/>
<div t-if="hasHeader" class="o_ComposerView_coreHeader text-truncate" t-att-class="{ 'small p-2': isInChatWindow or isInDiscuss }">
<t t-if="threadView and threadView.replyingToMessageView">
<span class="cursor-pointer" t-on-click="onClickReplyingToMessage">
Replying to <b t-esc="threadView.replyingToMessageView.message.authorName"/>
</span>
<i t-if="threadView.thread !== messaging.inbox.thread" class="o_ComposerView_cancelReply fa fa-lg fa-times-circle rounded-circle p-0 ms-1 cursor-pointer" title="Stop replying" t-on-click="onClickStopReplying"/>
</t>
<t t-if="hasHeader">
<div class="o_ComposerView_coreHeader text-truncate" t-att-class="{ 'small p-2': isInChatWindow or isInDiscuss }">
<t t-if="threadView and threadView.replyingToMessageView">
<span class="cursor-pointer" t-on-click="onClickReplyingToMessage">
Replying to <b t-esc="threadView.replyingToMessageView.message.authorName"/>
</span>
<i t-if="threadView.thread !== messaging.inbox.thread" class="o_ComposerView_cancelReply fa fa-lg fa-times-circle rounded-circle p-0 ms-1 cursor-pointer" title="Stop replying" t-on-click="onClickStopReplying"/>
</t>
<t t-if="hasThreadName">
<span class="o_ComposerView_threadName">
on: <b><t t-esc="composer.activeThread.displayName"/></b>
</span>
</t>
<t t-if="hasFollowers and !composer.isLog">
<!-- Text for followers -->
<small class="o_ComposerView_followers flex-shrink-0">
<b class="text-muted">To: </b>
<em class="text-muted">Followers of </em>
<b>
<t t-if="composer.activeThread.displayName">
&#32;&quot;<t t-esc="composer.activeThread.displayName"/>&quot;
</t>
<t t-else="">
this document
</t>
</b>
</small>
<ComposerSuggestedRecipientListView record="composerSuggestedRecipientListView"/>
</t>
</div>
</t>
<t t-if="hasCurrentPartnerAvatar">
<div class="o_ComposerView_sidebarMain">
<t t-if="!messaging.currentGuest or composer.activeThread.model !== 'mail.channel'">
<img class="o_ComposerView_currentPartnerAvatar mt-1 rounded-circle o_object_fit_cover" t-att-src="currentPartnerAvatar" alt="Avatar of user"/>
</t>
<t t-if="messaging.currentGuest and composer.activeThread.model === 'mail.channel'">
<img class="o_ComposerView_currentPartnerAvatar mt-1 rounded-circle o_object_fit_cover" t-attf-src="/mail/channel/{{ composer.activeThread.id }}/guest/{{ messaging.currentGuest.id }}/avatar_128?unique={{ messaging.currentGuest.name }}" alt="Avatar of guest"/>
</t>
</div>
</t>
<div
class="o_ComposerView_coreMain d-flex flex-nowrap align-items-start flex-grow-1"
t-att-class="{
'o-composer-is-compact': isCompact,
'flex-column border rounded-3 bg-view': !isCompact,
}"
>
<ComposerTextInputView
className="'o_ComposerView_textInput flex-grow-1 align-self-stretch'"
classNameObj="{
'o-composer-is-compact': isCompact,
'rounded-3': !isCompact,
'o_ComposerView_textInput-mobile': messaging.device.isSmall,
'o-has-current-partner-avatar': hasCurrentPartnerAvatar,
'rounded-start-3': isCompact and hasCurrentPartnerAvatar,
}"
record="textInput"
t-key="localId"
/>
<div class="o_ComposerView_buttons d-flex align-items-stretch align-self-stretch flex-shrink-0" t-att-class="{ 'o-composer-is-compact': isCompact, 'h-auto w-100 px-3': !isCompact, 'o-isDeviceSmall': messaging.device.isSmall, 'o-messaging-in-editing': messageViewInEditing, 'border-end': messageViewInEditing and !hasCurrentPartnerAvatar }">
<div class="o_ComposerView_toolButtons d-flex py-1 border-top bg-view"
t-att-class="{
'o-composer-has-current-partner-avatar': hasCurrentPartnerAvatar,
'o-composer-is-compact border-bottom': isCompact,
'flex-row flex-grow-1 justify-content-between': !isCompact,
}">
<div class="o_ComposerView_primaryToolButtons d-flex align-items-center" t-att-class="{ 'o-composer-is-compact px-2': isCompact, 'flex-column': messageViewInEditing and messageViewInEditing.isInChatWindow }">
<button class="o_ComposerView_button o_ComposerView_buttonEmojis o_ComposerView_toolButton btn btn-light border-0 rounded-pill bg-view"
t-att-class="{
'o-open bg-200': emojisPopoverView,
'o-isDeviceSmall': messaging.device.isSmall,
}"
t-attf-class="{{ messageViewInEditing ? 'my-1' : 'mx-1' }}"
t-att-aria-expanded="emojisPopoverView ? 'true' : 'false'"
t-on-keydown="onKeydownButtonEmojis"
t-on-click="onClickButtonEmojis"
t-ref="buttonEmojis"
>
<i class="fa fa-smile-o" role="img" aria-label="Emojis"/>
</button>
<button class="o_ComposerView_button o_ComposerView_buttonAttachment o_ComposerView_toolButton btn btn-light fa fa-paperclip border-0 rounded-pill bg-view" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall }" t-attf-class="{{ messageViewInEditing ? 'my-1' : 'mx-1' }}" title="Add attachment" aria-label="Add attachment" type="button" t-on-click="onClickAddAttachment"/>
</div>
<t t-if="isExpandable">
<div class="o_ComposerView_secondaryToolButtons">
<button class="o_ComposerView_button o_ComposerView_buttonFullComposer o_ComposerView_toolButton btn btn-light fa fa-expand mx-1 border-0 rounded-pill bg-view" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall }" title="Full composer" aria-label="Full composer" type="button" t-on-click="onClickFullComposer"/>
</div>
<span t-if="hasThreadName" class="o_ComposerView_threadName">
on: <b><t t-esc="composer.activeThread.displayName"/></b>
</span>
<t t-if="hasFollowers and !composer.isLog">
<!-- Text for followers -->
<small class="o_ComposerView_followers flex-shrink-0">
<b class="text-muted">To: </b>
<em class="text-muted">Followers of </em>
<b>
<t t-if="composer.activeThread.displayName">
&#32;&quot;<t t-esc="composer.activeThread.displayName"/>&quot;
</t>
</div>
<t t-if="isCompact">
<t t-call="mail.ComposerView.actionButtons"/>
</t>
</div>
</div>
<t t-if="hasFooter">
<div class="o_ComposerView_coreFooter overflow-auto" t-att-class="{ 'o-composer-is-compact': isCompact, 'ms-0': !isCompact }">
<t t-if="threadTextualTypingStatusView">
<ThreadTextualTypingStatusView className="'o_ComposerView_threadTextualTypingStatus small'" record="threadTextualTypingStatusView"/>
</t>
<AttachmentList
t-if="attachmentList"
className="'o_ComposerView_attachmentList flex-grow-1'"
classNameObj="{ 'o-composer-is-compact': isCompact, 'overflow-auto': !isCompact }"
record="attachmentList"
/>
<t t-if="!isCompact">
<t t-call="mail.ComposerView.actionButtons"/>
</t>
<t t-if="messageViewInEditing">
<span class="text-muted">escape to <a href="#" t-on-click="onClickCancelLink">cancel</a>, enter to <a href="#" t-on-click="onClickSaveLink">save</a></span>
</t>
</div>
<t t-else="">
this document
</t>
</b>
</small>
<ComposerSuggestedRecipientListView record="composerSuggestedRecipientListView"/>
</t>
</div>
<div t-if="hasCurrentPartnerAvatar" class="o_ComposerView_sidebarMain">
<img t-if="!messaging.currentGuest or composer.activeThread.model !== 'mail.channel'" class="o_ComposerView_currentPartnerAvatar mt-1 rounded-circle o_object_fit_cover" t-att-src="currentPartnerAvatar" alt="Avatar of user"/>
<img t-if="messaging.currentGuest and composer.activeThread.model === 'mail.channel'" class="o_ComposerView_currentPartnerAvatar mt-1 rounded-circle o_object_fit_cover" t-attf-src="/mail/channel/{{ composer.activeThread.id }}/guest/{{ messaging.currentGuest.id }}/avatar_128?unique={{ messaging.currentGuest.name }}" alt="Avatar of guest"/>
</div>
<div
class="o_ComposerView_coreMain d-flex flex-nowrap align-items-start flex-grow-1"
t-att-class="{
'o-composer-is-compact': isCompact,
'flex-column border rounded-3 bg-view': !isCompact,
}"
>
<ComposerTextInputView
className="'o_ComposerView_textInput flex-grow-1 align-self-stretch'"
classNameObj="{
'o-composer-is-compact': isCompact,
'rounded-3': !isCompact,
'o_ComposerView_textInput-mobile': messaging.device.isSmall,
'o-has-current-partner-avatar': hasCurrentPartnerAvatar,
'rounded-start-3': isCompact and hasCurrentPartnerAvatar,
}"
record="textInput"
t-key="localId"
/>
<div class="o_ComposerView_buttons d-flex align-items-stretch align-self-stretch flex-shrink-0" t-att-class="{ 'o-composer-is-compact': isCompact, 'h-auto w-100 px-3': !isCompact, 'o-isDeviceSmall': messaging.device.isSmall, 'o-messaging-in-editing': messageViewInEditing, 'border-end': messageViewInEditing and !hasCurrentPartnerAvatar }">
<div class="o_ComposerView_toolButtons d-flex py-1 border-top bg-view"
t-att-class="{
'o-composer-has-current-partner-avatar': hasCurrentPartnerAvatar,
'o-composer-is-compact border-bottom': isCompact,
'flex-row flex-grow-1 justify-content-between': !isCompact,
}">
<div class="o_ComposerView_primaryToolButtons d-flex align-items-center" t-att-class="{ 'o-composer-is-compact px-2': isCompact, 'flex-column': messageViewInEditing and messageViewInEditing.isInChatWindow }">
<button class="o_ComposerView_button o_ComposerView_buttonEmojis o_ComposerView_toolButton btn btn-light border-0 rounded-pill bg-view"
t-att-class="{
'o-open bg-200': emojisPopoverView,
'o-isDeviceSmall': messaging.device.isSmall,
}"
t-attf-class="{{ messageViewInEditing ? 'my-1' : 'mx-1' }}"
t-att-aria-expanded="emojisPopoverView ? 'true' : 'false'"
t-on-keydown="onKeydownButtonEmojis"
t-on-click="onClickButtonEmojis"
t-ref="buttonEmojis"
>
<i class="fa fa-smile-o" role="img" aria-label="Emojis"/>
</button>
<button class="o_ComposerView_button o_ComposerView_buttonAttachment o_ComposerView_toolButton btn btn-light fa fa-paperclip border-0 rounded-pill bg-view" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall }" t-attf-class="{{ messageViewInEditing ? 'my-1' : 'mx-1' }}" title="Add attachment" aria-label="Add attachment" type="button" t-on-click="onClickAddAttachment"/>
</div>
<div t-if="isExpandable" class="o_ComposerView_secondaryToolButtons">
<button class="o_ComposerView_button o_ComposerView_buttonFullComposer o_ComposerView_toolButton btn btn-light fa fa-expand mx-1 border-0 rounded-pill bg-view" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall }" title="Full composer" aria-label="Full composer" type="button" t-on-click="onClickFullComposer"/>
</div>
</div>
<t t-if="isCompact" t-call="mail.ComposerView.actionButtons"/>
</div>
</div>
<div t-if="hasFooter" class="o_ComposerView_coreFooter overflow-auto" t-att-class="{ 'o-composer-is-compact': isCompact, 'ms-0': !isCompact }">
<ThreadTextualTypingStatusView t-if="threadTextualTypingStatusView" className="'o_ComposerView_threadTextualTypingStatus small'" record="threadTextualTypingStatusView"/>
<AttachmentList
t-if="attachmentList"
className="'o_ComposerView_attachmentList flex-grow-1'"
classNameObj="{ 'o-composer-is-compact': isCompact, 'overflow-auto': !isCompact }"
record="attachmentList"
/>
<t t-if="!isCompact" t-call="mail.ComposerView.actionButtons"/>
<span t-if="messageViewInEditing" class="text-muted">escape to <a href="#" t-on-click="onClickCancelLink">cancel</a>, enter to <a href="#" t-on-click="onClickSaveLink">save</a></span>
</div>
</div>
</t>
<t t-name="mail.ComposerView.actionButtons" owl="1">
<div class="o_ComposerView_actionButtons" t-att-class="{ 'o-composer-is-compact d-flex': isCompact, 'mt-2': !isCompact }">
<t t-if="hasSendButton">
<button class="o_ComposerView_actionButton o_ComposerView_button o_ComposerView_buttonSend btn btn-primary"
t-att-class="{
'o-last': !hasDiscardButton,
'o-composer-is-compact border-start-0': isCompact,
'o-has-current-partner-avatar': hasCurrentPartnerAvatar,
'rounded-0 rounded-end-3': !hasDiscardButton and hasCurrentPartnerAvatar and isCompact,
}"
t-att-disabled="!composer.canPostMessage ? 'disabled' : ''"
type="button"
t-on-click="onClickSend"
>
<t t-if="!messaging.device.isSmall"><t t-esc="sendButtonText"/></t>
<t t-else=""><i class="fa fa-paper-plane-o"/></t>
</button>
</t>
<t t-if="hasDiscardButton">
<button class="o_ComposerView_actionButton o-last o_ComposerView_button o_ComposerView_buttonDiscard btn btn-secondary" t-att-class="{ 'o-composer-is-compact border-start-0': isCompact, 'o-has-current-partner-avatar': hasCurrentPartnerAvatar, 'rounded-0 rounded-end-3': hasCurrentPartnerAvatar and isCompact }" type="button" t-on-click="onClickDiscard">
Discard
</button>
</t>
<button t-if="hasSendButton" class="o_ComposerView_actionButton o_ComposerView_button o_ComposerView_buttonSend btn btn-primary"
t-att-class="{
'o-last': !hasDiscardButton,
'o-composer-is-compact border-start-0': isCompact,
'o-has-current-partner-avatar': hasCurrentPartnerAvatar,
'rounded-0 rounded-end-3': !hasDiscardButton and hasCurrentPartnerAvatar and isCompact,
}"
t-att-disabled="!composer.canPostMessage ? 'disabled' : ''"
type="button"
t-on-click="onClickSend"
>
<t t-if="!messaging.device.isSmall" t-esc="sendButtonText"/>
<i t-else="" class="fa fa-paper-plane-o"/>
</button>
<button t-if="hasDiscardButton" class="o_ComposerView_actionButton o-last o_ComposerView_button o_ComposerView_buttonDiscard btn btn-secondary" t-att-class="{ 'o-composer-is-compact border-start-0': isCompact, 'o-has-current-partner-avatar': hasCurrentPartnerAvatar, 'rounded-0 rounded-end-3': hasCurrentPartnerAvatar and isCompact }" type="button" t-on-click="onClickDiscard">
Discard
</button>
</div>
</t>
@@ -1,20 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.ComposerSuggestedRecipientView" owl="1">
<t t-if="composerSuggestedRecipientView">
<div class="o_ComposerSuggestedRecipientView" t-attf-class="{{ className }}" t-att-data-partner-id="composerSuggestedRecipientView.suggestedRecipientInfo.partner and composerSuggestedRecipientView.suggestedRecipientInfo.partner.id ? composerSuggestedRecipientView.suggestedRecipientInfo.partner.id : false" t-att-title="composerSuggestedRecipientView.suggestedRecipientInfo.titleText" t-ref="root">
<div class="form-check">
<input t-attf-id="{{ id }}_checkbox" class="form-check-input" type="checkbox" t-att-checked="composerSuggestedRecipientView.suggestedRecipientInfo.isSelected ? 'checked' : undefined" t-on-change="_onChangeCheckbox" t-ref="checkbox" />
<label class="form-check-label" t-attf-for="{{ id }}_checkbox">
<t t-if="composerSuggestedRecipientView.suggestedRecipientInfo.name">
<t t-esc="composerSuggestedRecipientView.suggestedRecipientInfo.name"/>
</t>
<t t-if="composerSuggestedRecipientView.suggestedRecipientInfo.email">
(<t t-esc="composerSuggestedRecipientView.suggestedRecipientInfo.email"/>)
</t>
</label>
</div>
<div class="o_ComposerSuggestedRecipientView" t-attf-class="{{ className }}" t-att-data-partner-id="composerSuggestedRecipientView.suggestedRecipientInfo.partner and composerSuggestedRecipientView.suggestedRecipientInfo.partner.id ? composerSuggestedRecipientView.suggestedRecipientInfo.partner.id : false" t-att-title="composerSuggestedRecipientView.suggestedRecipientInfo.titleText" t-ref="root">
<div class="form-check">
<input t-attf-id="{{ id }}_checkbox" class="form-check-input" type="checkbox" t-att-checked="composerSuggestedRecipientView.suggestedRecipientInfo.isSelected ? 'checked' : undefined" t-on-change="_onChangeCheckbox" t-ref="checkbox" />
<label class="form-check-label" t-attf-for="{{ id }}_checkbox">
<t t-if="composerSuggestedRecipientView.suggestedRecipientInfo.name" t-esc="composerSuggestedRecipientView.suggestedRecipientInfo.name"/>
<t t-if="composerSuggestedRecipientView.suggestedRecipientInfo.email">
(<t t-esc="composerSuggestedRecipientView.suggestedRecipientInfo.email"/>)
</t>
</label>
</div>
</t>
</div>
</t>
</templates>
@@ -1,22 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.ComposerSuggestedRecipientListView" owl="1">
<div class="o_ComposerSuggestedRecipientListView mb-2" t-attf-class="{{ className }}" t-ref="root">
<t t-foreach="composerSuggestedRecipientViews" t-as="composerSuggestedRecipientView" t-key="composerSuggestedRecipientView.localId">
<ComposerSuggestedRecipientView record="composerSuggestedRecipientView"/>
</t>
<t t-if="thread.suggestedRecipientInfoList.length > 3">
<t t-if="!hasShowMoreButton" >
<button class="o_ComposerSuggestedRecipientListView_showMore btn btn-sm btn-link" t-on-click="onClickShowMore">
Show more
</button>
</t>
<t t-else="">
<button class="o_ComposerSuggestedRecipientListView_showLess btn btn-sm btn-link" t-on-click="onClickShowLess">
Show less
</button>
</t>
</t>
</div>
<div class="o_ComposerSuggestedRecipientListView mb-2" t-attf-class="{{ className }}" t-ref="root">
<ComposerSuggestedRecipientView t-foreach="composerSuggestedRecipientViews" t-as="composerSuggestedRecipientView" t-key="composerSuggestedRecipientView.localId" record="composerSuggestedRecipientView"/>
<t t-if="thread.suggestedRecipientInfoList.length > 3">
<button t-if="!hasShowMoreButton" class="o_ComposerSuggestedRecipientListView_showMore btn btn-sm btn-link" t-on-click="onClickShowMore">
Show more
</button>
<button t-else="" class="o_ComposerSuggestedRecipientListView_showLess btn btn-sm btn-link" t-on-click="onClickShowLess">
Show less
</button>
</t>
</div>
</t>
</templates>
@@ -2,21 +2,15 @@
<templates xml:space="preserve">
<t t-name="mail.ComposerSuggestionListView" owl="1">
<div class="o_ComposerSuggestionListView position-absolute w-100" t-att-class="{ 'o-lowPosition bottom-0': composerViewOwner.hasMentionSuggestionsBelowPosition }" t-attf-class="{{ className }}" t-ref="root">
<div class="o_ComposerSuggestionListView_drop w-100" t-att-class="{ 'dropdown': composerViewOwner.hasMentionSuggestionsBelowPosition, 'dropup': !composerViewOwner.hasMentionSuggestionsBelowPosition }">
<div class="o_ComposerSuggestionListView_list dropdown-menu show w-100 overflow-auto" t-att-class="{ 'bottom-100': !composerViewOwner.hasMentionSuggestionsBelowPosition }">
<t t-foreach="composerSuggestionListViewMainComposerSuggestionViewItems" t-as="composerSuggestionListViewMainComposerSuggestionViewItem" t-key="composerSuggestionListViewMainComposerSuggestionViewItem.localId">
<ComposerSuggestionView record="composerSuggestionListViewMainComposerSuggestionViewItem.composerSuggestionView"/>
</t>
<t t-if="composerSuggestionListViewMainComposerSuggestionViewItems.length > 0 and composerSuggestionListViewExtraComposerSuggestionViewItems.length > 0">
<div role="separator" class="dropdown-divider"/>
</t>
<t t-foreach="composerSuggestionListViewExtraComposerSuggestionViewItems" t-as="composerSuggestionListViewExtraComposerSuggestionViewItem" t-key="composerSuggestionListViewExtraComposerSuggestionViewItem.localId">
<ComposerSuggestionView record="composerSuggestionListViewExtraComposerSuggestionViewItem.composerSuggestionView"/>
</t>
</div>
<div class="o_ComposerSuggestionListView position-absolute w-100" t-att-class="{ 'o-lowPosition bottom-0': composerViewOwner.hasMentionSuggestionsBelowPosition }" t-attf-class="{{ className }}" t-ref="root">
<div class="o_ComposerSuggestionListView_drop w-100" t-att-class="{ 'dropdown': composerViewOwner.hasMentionSuggestionsBelowPosition, 'dropup': !composerViewOwner.hasMentionSuggestionsBelowPosition }">
<div class="o_ComposerSuggestionListView_list dropdown-menu show w-100 overflow-auto" t-att-class="{ 'bottom-100': !composerViewOwner.hasMentionSuggestionsBelowPosition }">
<ComposerSuggestionView t-foreach="composerSuggestionListViewMainComposerSuggestionViewItems" t-as="composerSuggestionListViewMainComposerSuggestionViewItem" t-key="composerSuggestionListViewMainComposerSuggestionViewItem.localId" record="composerSuggestionListViewMainComposerSuggestionViewItem.composerSuggestionView"/>
<div t-if="composerSuggestionListViewMainComposerSuggestionViewItems.length > 0 and composerSuggestionListViewExtraComposerSuggestionViewItems.length > 0" role="separator" class="dropdown-divider"/>
<ComposerSuggestionView t-foreach="composerSuggestionListViewExtraComposerSuggestionViewItems" t-as="composerSuggestionListViewExtraComposerSuggestionViewItem" t-key="composerSuggestionListViewExtraComposerSuggestionViewItem.localId" record="composerSuggestionListViewExtraComposerSuggestionViewItem.composerSuggestionView"/>
</div>
</div>
</div>
</t>
</templates>
@@ -2,31 +2,25 @@
<templates xml:space="preserve">
<t t-name="mail.ComposerSuggestionView" owl="1">
<a class="o_ComposerSuggestionView dropdown-item d-flex w-100 py-2 px-4" t-att-class="{ 'active bg-300': composerSuggestionListViewOwnerAsActiveSuggestionView }" t-attf-class="{{ className }}" href="#" t-att-title="title" role="menuitem" t-on-click="onClick" t-ref="root">
<t t-if="suggestable.cannedResponse">
<strong class="o_ComposerSuggestionView_part1 flex-shrink-0 mw-100 pe-2 text-truncate"><t t-esc="suggestable.cannedResponse.source"/></strong>
<em class="o_ComposerSuggestionView_part2 text-600 text-truncate"><t t-esc="suggestable.cannedResponse.substitution"/></em>
</t>
<t t-if="suggestable.thread">
<strong class="o_ComposerSuggestionView_part1 flex-shrink-0 mw-100 pe-2 text-truncate"><t t-esc="suggestable.thread.name"/></strong>
</t>
<t t-if="suggestable.channelCommand">
<strong class="o_ComposerSuggestionView_part1 flex-shrink-0 mw-100 pe-2 text-truncate"><t t-esc="suggestable.channelCommand.name"/></strong>
<em class="o_ComposerSuggestionView_part2 text-600 text-truncate"><t t-esc="suggestable.channelCommand.help"/></em>
</t>
<t t-if="suggestable.partner">
<t t-if="personaImStatusIconView">
<PersonaImStatusIconView
className="'o_ComposerSuggestionView_personaImStatusIcon flex-shrink-0 me-1'"
record="personaImStatusIconView"
/>
</t>
<strong class="o_ComposerSuggestionView_part1 flex-shrink-0 mw-100 pe-2 text-truncate"><t t-esc="suggestable.partner.nameOrDisplayName"/></strong>
<t t-if="suggestable.partner.email">
<em class="o_ComposerSuggestionView_part2 text-600 text-truncate">(<t t-esc="suggestable.partner.email"/>)</em>
</t>
</t>
</a>
<a class="o_ComposerSuggestionView dropdown-item d-flex w-100 py-2 px-4" t-att-class="{ 'active bg-300': composerSuggestionListViewOwnerAsActiveSuggestionView }" t-attf-class="{{ className }}" href="#" t-att-title="title" role="menuitem" t-on-click="onClick" t-ref="root">
<t t-if="suggestable.cannedResponse">
<strong class="o_ComposerSuggestionView_part1 flex-shrink-0 mw-100 pe-2 text-truncate" t-esc="suggestable.cannedResponse.source"/>
<em class="o_ComposerSuggestionView_part2 text-600 text-truncate" t-esc="suggestable.cannedResponse.substitution"/>
</t>
<strong t-if="suggestable.thread" class="o_ComposerSuggestionView_part1 flex-shrink-0 mw-100 pe-2 text-truncate"><t t-esc="suggestable.thread.name"/></strong>
<t t-if="suggestable.channelCommand">
<strong class="o_ComposerSuggestionView_part1 flex-shrink-0 mw-100 pe-2 text-truncate" t-esc="suggestable.channelCommand.name"/>
<em class="o_ComposerSuggestionView_part2 text-600 text-truncate" t-esc="suggestable.channelCommand.help"/>
</t>
<t t-if="suggestable.partner">
<PersonaImStatusIconView t-if="personaImStatusIconView"
className="'o_ComposerSuggestionView_personaImStatusIcon flex-shrink-0 me-1'"
record="personaImStatusIconView"
/>
<strong class="o_ComposerSuggestionView_part1 flex-shrink-0 mw-100 pe-2 text-truncate" t-esc="suggestable.partner.nameOrDisplayName"/>
<em t-if="suggestable.partner.email" class="o_ComposerSuggestionView_part2 text-600 text-truncate">(<t t-esc="suggestable.partner.email"/>)</em>
</t>
</a>
</t>
</templates>
@@ -2,18 +2,16 @@
<templates xml:space="preserve">
<t t-name="mail.ComposerTextInputView" owl="1">
<div class="o_ComposerTextInputView position-relative bg-view" t-attf-class="{{ className }} {{ owner.isCompact ? 'border border-end-0' : 'border-0' }}" t-att-class="{ 'border-start-0': owner.isInChatWindow }" t-on-paste="owner.onPasteTextInput" t-ref="root">
<t t-if="owner.composerSuggestionListView">
<ComposerSuggestionListView record="owner.composerSuggestionListView"/>
</t>
<textarea class="o_ComposerTextInputView_textarea o_ComposerTextInputView_textareaStyle form-control px-3 border-0 shadow-none overflow-auto" t-att-class="{ 'o-composer-is-compact rounded-0 rounded-start-3': owner.isCompact, 'rounded-3': !owner.isCompact }" t-esc="owner.composer.textInputContent" t-att-placeholder="owner.composer.placeholder" t-on-click="owner.onClickTextarea" t-on-focusin="owner.onFocusinTextarea" t-on-focusout="owner.onFocusoutTextarea" t-on-keydown="owner.onKeydownTextarea" t-on-keyup="owner.onKeyupTextarea" t-on-input="owner.onInputTextarea" t-ref="textarea"/>
<!--
This is an invisible textarea used to compute the composer
height based on the text content. We need it to downsize
the textarea properly without flicker.
-->
<textarea class="o_ComposerTextInputView_mirroredTextarea o_ComposerTextInputView_textareaStyle position-absolute px-3 border-0 overflow-hidden opacity-0" t-att-class="{ 'o-composer-is-compact rounded-0 rounded-start-3': owner.isCompact, 'rounded-3': !owner.isCompact }" t-esc="owner.composer.textInputContent" t-ref="mirroredTextarea" disabled="1"/>
</div>
<div class="o_ComposerTextInputView position-relative bg-view" t-attf-class="{{ className }} {{ owner.isCompact ? 'border border-end-0' : 'border-0' }}" t-att-class="{ 'border-start-0': owner.isInChatWindow }" t-on-paste="owner.onPasteTextInput" t-ref="root">
<ComposerSuggestionListView t-if="owner.composerSuggestionListView" record="owner.composerSuggestionListView"/>
<textarea class="o_ComposerTextInputView_textarea o_ComposerTextInputView_textareaStyle form-control px-3 border-0 shadow-none overflow-auto" t-att-class="{ 'o-composer-is-compact rounded-0 rounded-start-3': owner.isCompact, 'rounded-3': !owner.isCompact }" t-esc="owner.composer.textInputContent" t-att-placeholder="owner.composer.placeholder" t-on-click="owner.onClickTextarea" t-on-focusin="owner.onFocusinTextarea" t-on-focusout="owner.onFocusoutTextarea" t-on-keydown="owner.onKeydownTextarea" t-on-keyup="owner.onKeyupTextarea" t-on-input="owner.onInputTextarea" t-ref="textarea"/>
<!--
This is an invisible textarea used to compute the composer
height based on the text content. We need it to downsize
the textarea properly without flicker.
-->
<textarea class="o_ComposerTextInputView_mirroredTextarea o_ComposerTextInputView_textareaStyle position-absolute px-3 border-0 overflow-hidden opacity-0" t-att-class="{ 'o-composer-is-compact rounded-0 rounded-start-3': owner.isCompact, 'rounded-3': !owner.isCompact }" t-esc="owner.composer.textInputContent" t-ref="mirroredTextarea" disabled="1"/>
</div>
</t>
</templates>
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.DeleteMessageConfirmView" owl="1">
<div class="o_DeleteMessageConfirmView card bg-view" t-attf-class="{{ className }}" t-ref="root">
<h4 class="m-3">Confirmation</h4>
<hr class="mt-0 mb-3"/>
<p class="mx-3 mb-3">Are you sure you want to delete this message?</p>
<blockquote class="o_DeleteMessageConfirmView_blockquote mx-3 mb-3 fst-normal">
<MessageView record="messageView"/>
</blockquote>
<small t-if="!message.originThread or message.originThread.model !== 'mail.channel'" class="mx-3 mb-3">Pay attention: The followers of this document who were notified by email will still be able to read the content of this message and reply to it.</small>
<hr class="mt-0 mb-3"/>
<div class="o_DeleteMessageConfirmView_buttons mx-3 mb-3">
<button class="btn btn-primary me-2" t-on-click="onClickDelete">Delete</button>
<button class="btn btn-secondary me-2" t-on-click="onClickCancel">Cancel</button>
</div>
<div class="o_DeleteMessageConfirmView card bg-view" t-attf-class="{{ className }}" t-ref="root">
<h4 class="m-3">Confirmation</h4>
<hr class="mt-0 mb-3"/>
<p class="mx-3 mb-3">Are you sure you want to delete this message?</p>
<blockquote class="o_DeleteMessageConfirmView_blockquote mx-3 mb-3 fst-normal">
<MessageView record="messageView"/>
</blockquote>
<small t-if="!message.originThread or message.originThread.model !== 'mail.channel'" class="mx-3 mb-3">Pay attention: The followers of this document who were notified by email will still be able to read the content of this message and reply to it.</small>
<hr class="mt-0 mb-3"/>
<div class="o_DeleteMessageConfirmView_buttons mx-3 mb-3">
<button class="btn btn-primary me-2" t-on-click="onClickDelete">Delete</button>
<button class="btn btn-secondary me-2" t-on-click="onClickCancel">Cancel</button>
</div>
</div>
</t>
</templates>
@@ -2,17 +2,15 @@
<templates xml:space="preserve">
<t t-name="mail.Dialog" owl="1">
<t t-if="dialog">
<div class="o_Dialog modal fixed-top bottom-0 d-flex justify-content-center" t-attf-class="{{ className }}" t-att-style="dialog.style" t-ref="root">
<t
t-component="constructor.components[dialog.componentName]"
t-props="{
className: `o_Dialog_component ${dialog.componentClassName}`,
record: dialog.record,
}"
/>
</div>
</t>
<div class="o_Dialog modal fixed-top bottom-0 d-flex justify-content-center" t-attf-class="{{ className }}" t-att-style="dialog.style" t-ref="root">
<t
t-component="constructor.components[dialog.componentName]"
t-props="{
className: `o_Dialog_component ${dialog.componentClassName}`,
record: dialog.record,
}"
/>
</div>
</t>
</templates>
@@ -3,12 +3,10 @@
<t t-name="mail.DialogManager" owl="1">
<div class="o_DialogManager" t-attf-class="{{ className }}" t-ref="root">
<t t-foreach="dialogManager.dialogs" t-as="dialog" t-key="dialog.localId">
<Dialog
className="'o_DialogManager_dialog'"
record="dialog"
/>
</t>
<Dialog t-foreach="dialogManager.dialogs" t-as="dialog" t-key="dialog.localId"
className="'o_DialogManager_dialog'"
record="dialog"
/>
</div>
</t>
@@ -2,36 +2,26 @@
<templates xml:space="preserve">
<t t-name="mail.DiscussView" owl="1">
<t t-if="discussView">
<div class="o_DiscussView d-flex h-100" t-attf-class="{{ className }}"
t-att-class="{ 'o-isDeviceSmall flex-column align-items-center bg-view': messaging.device.isSmall }"
t-ref="root"
>
<t t-if="discussView.sidebar">
<DiscussSidebarView className="'o_DiscussView_sidebar flex-shrink-0 h-100 pt-3 border-end bg-light'" record="discussView.sidebar"/>
</t>
<t t-if="messaging.device.isSmall" t-call="mail.DiscussView.content"/>
<t t-else="">
<div class="o_DiscussView_content d-flex flex-column flex-grow-1 h-100 overflow-auto">
<t t-call="mail.DiscussView.content"/>
</div>
</t>
<div class="o_DiscussView d-flex h-100" t-attf-class="{{ className }}"
t-att-class="{ 'o-isDeviceSmall flex-column align-items-center bg-view': messaging.device.isSmall }"
t-ref="root"
>
<DiscussSidebarView t-if="discussView.sidebar" className="'o_DiscussView_sidebar flex-shrink-0 h-100 pt-3 border-end bg-light'" record="discussView.sidebar"/>
<t t-if="messaging.device.isSmall" t-call="mail.DiscussView.content"/>
<div t-else="" class="o_DiscussView_content d-flex flex-column flex-grow-1 h-100 overflow-auto">
<t t-call="mail.DiscussView.content"/>
</div>
</t>
</div>
</t>
<t t-name="mail.DiscussView.content" owl="1">
<t t-if="discussView.mobileMailboxSelectionView">
<DiscussMobileMailboxSelectionView className="'o_DiscussView_mobileMailboxSelection w-100 border-bottom'" record="discussView.mobileMailboxSelectionView"/>
</t>
<t t-if="discussView.mobileAddItemHeaderAutocompleteInputView">
<div class="o_DiscussView_mobileAddItemHeader d-flex justify-content-center w-100 p-3 border-bottom bg-light">
<AutocompleteInputView
className="'o_DiscussView_mobileAddItemHeaderInput flex-grow-1 mb-3 p-2 rounded border'"
record="discussView.mobileAddItemHeaderAutocompleteInputView"
/>
</div>
</t>
<DiscussMobileMailboxSelectionView t-if="discussView.mobileMailboxSelectionView" className="'o_DiscussView_mobileMailboxSelection w-100 border-bottom'" record="discussView.mobileMailboxSelectionView"/>
<div t-if="discussView.mobileAddItemHeaderAutocompleteInputView" class="o_DiscussView_mobileAddItemHeader d-flex justify-content-center w-100 p-3 border-bottom bg-light">
<AutocompleteInputView
className="'o_DiscussView_mobileAddItemHeaderInput flex-grow-1 mb-3 p-2 rounded border'"
record="discussView.mobileAddItemHeaderAutocompleteInputView"
/>
</div>
<t t-if="discussView.discuss.threadView">
<t name="beforeThread"/>
<ThreadView
@@ -40,32 +30,22 @@
record="discussView.discuss.threadView"
/>
</t>
<t t-if="!discussView.discuss.activeThread and (!messaging.device.isSmall or discussView.discuss.activeMobileNavbarTabId === 'mailbox')">
<div class="o_DiscussView_noThread d-flex flex-grow-1 align-items-center justify-content-center w-100 bg-view">
<h4 class="text-muted"><b><i>No conversation selected.</i></b></h4>
</div>
</t>
<div t-if="!discussView.discuss.activeThread and (!messaging.device.isSmall or discussView.discuss.activeMobileNavbarTabId === 'mailbox')" class="o_DiscussView_noThread d-flex flex-grow-1 align-items-center justify-content-center w-100 bg-view">
<h4 class="text-muted"><b><i>No conversation selected.</i></b></h4>
</div>
<t t-if="messaging.device.isSmall and discussView.discuss.activeMobileNavbarTabId !== 'mailbox'">
<t t-if="discussView.discuss.activeMobileNavbarTabId === 'chat'">
<button class="o_DiscussView_mobileNewChatButton w-100 p-2 btn btn-secondary border-bottom bg-light" t-on-click="discussView.onClickMobileNewChatButton">
Start a conversation
</button>
</t>
<t t-if="discussView.discuss.activeMobileNavbarTabId === 'channel'">
<button class="o_DiscussView_mobileNewChannelButton w-100 p-2 btn btn-secondary border-bottom bg-light" t-on-click="discussView.onClickMobileNewChannelButton">
New Channel
</button>
</t>
</t>
<t t-if="discussView.discuss.notificationListView">
<NotificationListView className="'o_DiscussView_notificationList flex-grow-1 w-100'" record="discussView.discuss.notificationListView"/>
</t>
<t t-if="discussView.discuss.mobileMessagingNavbarView">
<MobileMessagingNavbarView
className="'o_DiscussView_mobileNavbar w-100'"
record="discussView.discuss.mobileMessagingNavbarView"
/>
<button t-if="discussView.discuss.activeMobileNavbarTabId === 'chat'" class="o_DiscussView_mobileNewChatButton w-100 p-2 btn btn-secondary border-bottom bg-light" t-on-click="discussView.onClickMobileNewChatButton">
Start a conversation
</button>
<button t-if="discussView.discuss.activeMobileNavbarTabId === 'channel'" class="o_DiscussView_mobileNewChannelButton w-100 p-2 btn btn-secondary border-bottom bg-light" t-on-click="discussView.onClickMobileNewChannelButton">
New Channel
</button>
</t>
<NotificationListView t-if="discussView.discuss.notificationListView" className="'o_DiscussView_notificationList flex-grow-1 w-100'" record="discussView.discuss.notificationListView"/>
<MobileMessagingNavbarView t-if="discussView.discuss.mobileMessagingNavbarView"
className="'o_DiscussView_mobileNavbar w-100'"
record="discussView.discuss.mobileMessagingNavbarView"
/>
</t>
</templates>
@@ -3,9 +3,7 @@
<t t-name="mail.DiscussMobileMailboxSelectionView" owl="1">
<div class="o_DiscussMobileMailboxSelectionView d-flex" t-attf-class="{{ className }}" t-ref="root">
<t t-foreach="items" t-as="item" t-key="item.localId">
<DiscussMobileMailboxSelectionItemView record="item"/>
</t>
<DiscussMobileMailboxSelectionItemView t-foreach="items" t-as="item" t-key="item.localId" record="item"/>
</div>
</t>
@@ -5,10 +5,8 @@
<button class="o_DiscussMobileMailboxSelectionItemView btn btn-secondary flex-grow-1 p-2"
t-att-class="{
'active o-active shadow-none': owner.owner.discuss.activeThread === mailbox.thread,
}" t-attf-class="{{ className }}" t-on-click="onClick" t-att-data-mailbox-local-id="mailbox.localId" type="button" t-ref="root"
>
<t t-esc="mailbox.name"/>
</button>
}" t-attf-class="{{ className }}" t-on-click="onClick" t-att-data-mailbox-local-id="mailbox.localId" type="button" t-esc="mailbox.name" t-ref="root"
/>
</t>
</templates>
@@ -1,15 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.DiscussPublicView" owl="1">
<t t-if="discussPublicView">
<div class="o_DiscussPublicView d-flex flex-column h-100 w-100 position-absolute" t-attf-class="{{ className }}" t-ref="root">
<ThreadView t-if="discussPublicView.threadView"
record="discussPublicView.threadView"
/>
<WelcomeView t-if="discussPublicView.welcomeView"
record="discussPublicView.welcomeView"
/>
</div>
</t>
<div class="o_DiscussPublicView d-flex flex-column h-100 w-100 position-absolute" t-attf-class="{{ className }}" t-ref="root">
<ThreadView t-if="discussPublicView.threadView"
record="discussPublicView.threadView"
/>
<WelcomeView t-if="discussPublicView.welcomeView"
record="discussPublicView.welcomeView"
/>
</div>
</t>
</templates>
@@ -2,34 +2,32 @@
<templates xml:space="preserve">
<t t-name="mail.DiscussSidebarView" owl="1">
<div name="root" class="o_DiscussSidebarView d-flex flex-column overflow-auto" t-attf-class="{{ className }}" t-ref="root">
<div class="d-flex justify-content-center">
<button class="o_DiscussSidebarView_startAMeetingButton btn btn-primary rounded" title="Start a meeting" t-on-click="owner.onClickStartAMeetingButton">
Start a meeting
</button>
</div>
<hr class="o_DiscussSidebarView_separator w-100 border-top"/>
<div class="o_DiscussSidebarView_category o_DiscussSidebarView_categoryMailbox d-flex flex-column flex-grow-0">
<DiscussSidebarMailboxView record="owner.inboxView"/>
<DiscussSidebarMailboxView record="owner.starredView"/>
<DiscussSidebarMailboxView record="owner.historyView"/>
</div>
<hr class="o_DiscussSidebarView_separator w-100 border-top"/>
<t t-if="messaging.models['Thread'].all(thread => thread.isPinned and thread.model === 'mail.channel').length > 19">
<input class="o_DiscussSidebarView_quickSearch form-control mx-4 mb-2 rounded-3 w-auto" t-on-input="owner.onInputQuickSearch" placeholder="Quick search..." t-ref="quickSearchInput" t-esc="owner.discuss.sidebarQuickSearchValue"/>
</t>
<DiscussSidebarCategory
t-if="owner.discuss.categoryChannel"
className="'o_DiscussSidebarView_category o_DiscussSidebarView_categoryChannel'"
record="owner.discuss.categoryChannel"
/>
<t name="beforeCategoryChat"/>
<DiscussSidebarCategory
t-if="owner.discuss.categoryChat"
className="'o_DiscussSidebarView_category o_DiscussSidebarView_categoryChat'"
record="owner.discuss.categoryChat"
/>
<div name="root" class="o_DiscussSidebarView d-flex flex-column overflow-auto" t-attf-class="{{ className }}" t-ref="root">
<div class="d-flex justify-content-center">
<button class="o_DiscussSidebarView_startAMeetingButton btn btn-primary rounded" title="Start a meeting" t-on-click="owner.onClickStartAMeetingButton">
Start a meeting
</button>
</div>
<hr class="o_DiscussSidebarView_separator w-100 border-top"/>
<div class="o_DiscussSidebarView_category o_DiscussSidebarView_categoryMailbox d-flex flex-column flex-grow-0">
<DiscussSidebarMailboxView record="owner.inboxView"/>
<DiscussSidebarMailboxView record="owner.starredView"/>
<DiscussSidebarMailboxView record="owner.historyView"/>
</div>
<hr class="o_DiscussSidebarView_separator w-100 border-top"/>
<input t-if="messaging.models['Thread'].all(thread => thread.isPinned and thread.model === 'mail.channel').length > 19" class="o_DiscussSidebarView_quickSearch form-control mx-4 mb-2 rounded-3 w-auto" t-on-input="owner.onInputQuickSearch" placeholder="Quick search..." t-ref="quickSearchInput" t-esc="owner.discuss.sidebarQuickSearchValue"/>
<DiscussSidebarCategory
t-if="owner.discuss.categoryChannel"
className="'o_DiscussSidebarView_category o_DiscussSidebarView_categoryChannel'"
record="owner.discuss.categoryChannel"
/>
<t name="beforeCategoryChat"/>
<DiscussSidebarCategory
t-if="owner.discuss.categoryChat"
className="'o_DiscussSidebarView_category o_DiscussSidebarView_categoryChat'"
record="owner.discuss.categoryChat"
/>
</div>
</t>
</templates>
@@ -2,52 +2,38 @@
<templates xml:space="preserve">
<t t-name="mail.DiscussSidebarCategory" owl="1">
<t t-set="o_DiscussSidebarCategory_hoverItem" t-value="'btn p-0 text-start text-700 opacity-100-hover opacity-75'"/>
<div class="o_DiscussSidebarCategory" t-attf-class="{{ className }}" t-att-data-category-local-id="localId" t-ref="root">
<div class="o_DiscussSidebarCategory_header d-flex align-items-center my-1">
<div t-attf-class="o_DiscussSidebarCategory_title o_DiscussSidebarCategory_headerItem d-flex align-items-baseline mx-1 {{ o_DiscussSidebarCategory_hoverItem }}" t-on-click="onClick">
<i class="o_DiscussSidebarCategory_titleIcon small" t-att-class="isOpen ? 'fa fa-chevron-down' : 'fa fa-chevron-right'"/>
<span class="o_DiscussSidebarCategory_titleText btn-sm p-0 text-uppercase fw-bolder"><t t-esc="name"/></span>
</div>
<div class="o_DiscussSidebarCategory_headerItem flex-grow-1"/>
<div class="o_DiscussSidebarCategory_commands o_DiscussSidebarCategory_headerItem d-flex me-3">
<t t-if="hasViewCommand">
<i t-attf-class="o_DiscussSidebarCategory_command o_DiscussSidebarCategory_commandView fa fa-cog {{ o_DiscussSidebarCategory_hoverItem }}" title="View or join channels" t-on-click="onClickCommandView" role="img"/>
</t>
<t t-if="hasAddCommand and isOpen">
<i t-attf-class="o_DiscussSidebarCategory_command o_DiscussSidebarCategory_commandAdd fa fa-plus {{ o_DiscussSidebarCategory_hoverItem }} ms-1" t-on-click="onClickCommandAdd" t-att-title="commandAddTitleText" role="img"/>
</t>
</div>
<t t-if="!isOpen and counter > 0">
<div class="o_DiscussSidebarCategory_counter o_DiscussSidebarCategory_headerItem badge rounded-pill text-bg-primary me-3">
<t t-esc="counter"/>
</div>
</t>
<t t-set="o_DiscussSidebarCategory_hoverItem" t-value="'btn p-0 text-start text-700 opacity-100-hover opacity-75'"/>
<div class="o_DiscussSidebarCategory" t-attf-class="{{ className }}" t-att-data-category-local-id="localId" t-ref="root">
<div class="o_DiscussSidebarCategory_header d-flex align-items-center my-1">
<div t-attf-class="o_DiscussSidebarCategory_title o_DiscussSidebarCategory_headerItem d-flex align-items-baseline mx-1 {{ o_DiscussSidebarCategory_hoverItem }}" t-on-click="onClick">
<i class="o_DiscussSidebarCategory_titleIcon small" t-att-class="isOpen ? 'fa fa-chevron-down' : 'fa fa-chevron-right'"/>
<span class="o_DiscussSidebarCategory_titleText btn-sm p-0 text-uppercase fw-bolder" t-esc="name"/>
</div>
<div class="o_DiscussSidebarCategory_content">
<t t-if="isOpen">
<t t-if="addingItemAutocompleteInputView">
<div class="o_DiscussSidebarCategory_addingItem d-flex mb-2">
<AutocompleteInputView
className="'o_DiscussSidebarCategory_addingItemInput form-control mx-4 rounded'"
record="addingItemAutocompleteInputView"
/>
</div>
</t>
<t t-foreach="filteredCategoryItems" t-as="item" t-key="item.localId">
<DiscussSidebarCategoryItem
className="'o_DiscussSidebarCategory_item'"
record="item"
/>
</t>
</t>
<t t-if="!isOpen and activeItem">
<DiscussSidebarCategoryItem
className="'o_DiscussSidebarCategory_item'"
record="activeItem"
/>
</t>
<div class="o_DiscussSidebarCategory_headerItem flex-grow-1"/>
<div class="o_DiscussSidebarCategory_commands o_DiscussSidebarCategory_headerItem d-flex me-3">
<i t-if="hasViewCommand" t-attf-class="o_DiscussSidebarCategory_command o_DiscussSidebarCategory_commandView fa fa-cog {{ o_DiscussSidebarCategory_hoverItem }}" title="View or join channels" t-on-click="onClickCommandView" role="img"/>
<i t-if="hasAddCommand and isOpen" t-attf-class="o_DiscussSidebarCategory_command o_DiscussSidebarCategory_commandAdd fa fa-plus {{ o_DiscussSidebarCategory_hoverItem }} ms-1" t-on-click="onClickCommandAdd" t-att-title="commandAddTitleText" role="img"/>
</div>
<div t-if="!isOpen and counter > 0" class="o_DiscussSidebarCategory_counter o_DiscussSidebarCategory_headerItem badge rounded-pill text-bg-primary me-3" t-esc="counter"/>
</div>
<div class="o_DiscussSidebarCategory_content">
<t t-if="isOpen">
<div t-if="addingItemAutocompleteInputView" class="o_DiscussSidebarCategory_addingItem d-flex mb-2">
<AutocompleteInputView
className="'o_DiscussSidebarCategory_addingItemInput form-control mx-4 rounded'"
record="addingItemAutocompleteInputView"
/>
</div>
<DiscussSidebarCategoryItem t-foreach="filteredCategoryItems" t-as="item" t-key="item.localId"
className="'o_DiscussSidebarCategory_item'"
record="item"
/>
</t>
<DiscussSidebarCategoryItem t-if="!isOpen and activeItem"
className="'o_DiscussSidebarCategory_item'"
record="activeItem"
/>
</div>
</div>
</t>
</templates>
@@ -1,46 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.DiscussSidebarCategoryItem" owl="1">
<t t-set="o_DiscussSidebarCategoryItem_hoverItem" t-value="'btn p-0 text-start text-700 opacity-100-hover opacity-75'"/>
<button class="o_DiscussSidebarCategoryItem btn d-flex align-items-center w-100 px-0 py-2 border-0 rounded-0 fw-normal text-reset"
t-att-class="{
'bg-100': !isActive,
'o-active bg-200': isActive,
'o-unread': isUnread,
}" t-attf-class="{{ className }}" t-on-click="onClick" t-att-data-channel-id="channel.id" t-att-data-channel-name="channel.displayName"
t-ref="root"
>
<div class="o_DiscussSidebarCategoryItem_item o_DiscussSidebarCategoryItem_avatar ms-4">
<div class="o_DiscussSidebarCategoryItem_imageContainer position-relative d-flex">
<img class="o_DiscussSidebarCategoryItem_image w-100 h-100 rounded-circle" t-att-src="avatarUrl" alt="Thread Image"/>
<t t-if="threadIconView">
<ThreadIconView className="'o_DiscussSidebarCategoryItem_threadIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center rounded-circle bg-100'" record="threadIconView"/>
</t>
</div>
<t t-set="o_DiscussSidebarCategoryItem_hoverItem" t-value="'btn p-0 text-start text-700 opacity-100-hover opacity-75'"/>
<button class="o_DiscussSidebarCategoryItem btn d-flex align-items-center w-100 px-0 py-2 border-0 rounded-0 fw-normal text-reset"
t-att-class="{
'bg-100': !isActive,
'o-active bg-200': isActive,
'o-unread': isUnread,
}" t-attf-class="{{ className }}" t-on-click="onClick" t-att-data-channel-id="channel.id" t-att-data-channel-name="channel.displayName"
t-ref="root"
>
<div class="o_DiscussSidebarCategoryItem_item o_DiscussSidebarCategoryItem_avatar ms-4">
<div class="o_DiscussSidebarCategoryItem_imageContainer position-relative d-flex">
<img class="o_DiscussSidebarCategoryItem_image w-100 h-100 rounded-circle" t-att-src="avatarUrl" alt="Thread Image"/>
<ThreadIconView t-if="threadIconView" className="'o_DiscussSidebarCategoryItem_threadIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center rounded-circle bg-100'" record="threadIconView"/>
</div>
<span class="o_DiscussSidebarCategoryItem_item o_DiscussSidebarCategoryItem_name ms-3 me-2 text-truncate" t-att-class="{ 'o-item-unread fw-bolder': isUnread }">
<t t-esc="thread.displayName"/>
</span>
<div class="o_DiscussSidebarCategoryItem_item flex-grow-1"/>
<div t-attf-class="o_DiscussSidebarCategoryItem_item o_DiscussSidebarCategoryItem_commands ms-1 {{ thread and thread.rtcSessions.length ? 'me-1' : 'me-3' }}">
<t t-if="hasSettingsCommand">
<div t-attf-class="o_DiscussSidebarCategoryItem_command o_DiscussSidebarCategoryItem_commandSettings fa fa-cog {{ o_DiscussSidebarCategoryItem_hoverItem }}" t-on-click="onClickCommandSettings" title="Channel settings" role="img"/>
</t>
<t t-if="hasLeaveCommand">
<div t-attf-class="o_DiscussSidebarCategoryItem_command o_DiscussSidebarCategoryItem_commandLeave fa fa-times {{ o_DiscussSidebarCategoryItem_hoverItem }} ms-1" t-on-click="onClickCommandLeave" title="Leave this channel" role="img"/>
</t>
<t t-if="hasUnpinCommand">
<div t-attf-class="o_DiscussSidebarCategoryItem_command o_DiscussSidebarCategoryItem_commandUnpin fa fa-times {{ o_DiscussSidebarCategoryItem_hoverItem }} ms-1" t-on-click="onClickCommandUnpin" title="Unpin Conversation" role="img"/>
</t>
</div>
<t t-if="thread and thread.rtcSessions.length">
<div class="o_DiscussSidebarCategoryItem_item o_DiscussSidebarCategoryItem_callIndicator fa fa-volume-up ms-1 me-3" t-att-class="{ 'o-isCalling text-danger': thread.rtc }"/>
</t>
<t t-if="counter > 0">
<div class="o_DiscussSidebarCategoryItem_counter o_DiscussSidebarCategoryItem_item badge rounded-pill text-bg-primary ms-1 me-3">
<t t-esc="counter"/>
</div>
</t>
</button>
</div>
<span class="o_DiscussSidebarCategoryItem_item o_DiscussSidebarCategoryItem_name ms-3 me-2 text-truncate" t-att-class="{ 'o-item-unread fw-bolder': isUnread }" t-esc="thread.displayName"/>
<div class="o_DiscussSidebarCategoryItem_item flex-grow-1"/>
<div t-attf-class="o_DiscussSidebarCategoryItem_item o_DiscussSidebarCategoryItem_commands ms-1 {{ thread and thread.rtcSessions.length ? 'me-1' : 'me-3' }}">
<div t-if="hasSettingsCommand" t-attf-class="o_DiscussSidebarCategoryItem_command o_DiscussSidebarCategoryItem_commandSettings fa fa-cog {{ o_DiscussSidebarCategoryItem_hoverItem }}" t-on-click="onClickCommandSettings" title="Channel settings" role="img"/>
<div t-if="hasLeaveCommand" t-attf-class="o_DiscussSidebarCategoryItem_command o_DiscussSidebarCategoryItem_commandLeave fa fa-times {{ o_DiscussSidebarCategoryItem_hoverItem }} ms-1" t-on-click="onClickCommandLeave" title="Leave this channel" role="img"/>
<div t-if="hasUnpinCommand" t-attf-class="o_DiscussSidebarCategoryItem_command o_DiscussSidebarCategoryItem_commandUnpin fa fa-times {{ o_DiscussSidebarCategoryItem_hoverItem }} ms-1" t-on-click="onClickCommandUnpin" title="Unpin Conversation" role="img"/>
</div>
<div t-if="thread and thread.rtcSessions.length" class="o_DiscussSidebarCategoryItem_item o_DiscussSidebarCategoryItem_callIndicator fa fa-volume-up ms-1 me-3" t-att-class="{ 'o-isCalling text-danger': thread.rtc }"/>
<div t-if="counter > 0" class="o_DiscussSidebarCategoryItem_counter o_DiscussSidebarCategoryItem_item badge rounded-pill text-bg-primary ms-1 me-3" t-esc="counter"/>
</button>
</t>
</templates>
@@ -10,15 +10,9 @@
t-ref="root"
>
<ThreadIconView className="'o_DiscussSidebarMailboxView_item ms-4 me-2'" record="threadIconView"/>
<div class="o_DiscussSidebarMailboxView_item o_DiscussSidebarMailboxView_name me-2 text-truncate">
<t t-esc="mailbox.name"/>
</div>
<div class="o_DiscussSidebarMailboxView_item o_DiscussSidebarMailboxView_name me-2 text-truncate" t-esc="mailbox.name"/>
<div t-attf-class="o_DiscussSidebarMailboxView_item flex-grow-1 {{ mailbox.counter === 0 ? 'me-3': '' }}"/>
<t t-if="mailbox.counter > 0">
<div t-attf-class="o_DiscussSidebarMailboxView_counter o_DiscussSidebarMailboxView_item badge rounded-pill {{ mailbox === messaging.starred ? 'bg-400 text-light' : 'text-bg-primary' }} ms-1 me-3">
<t t-esc="mailbox.counter"/>
</div>
</t>
<div t-if="mailbox.counter > 0" t-attf-class="o_DiscussSidebarMailboxView_counter o_DiscussSidebarMailboxView_item badge rounded-pill {{ mailbox === messaging.starred ? 'bg-400 text-light' : 'text-bg-primary' }} ms-1 me-3" t-esc="mailbox.counter"/>
</button>
</t>
</templates>
@@ -3,9 +3,7 @@
<t t-name="mail.EmojiCategoryBarView" owl="1">
<div class="o_EmojiCategoryBarView d-flex flex-shrink-0 overflow-auto border-end" t-attf-class="{{ className }}" t-ref="root">
<t t-foreach="emojiCategoryViews" t-as="emojiCategoryView" t-key="emojiCategoryView.localId">
<EmojiCategoryView record="emojiCategoryView"/>
</t>
<EmojiCategoryView t-foreach="emojiCategoryViews" t-as="emojiCategoryView" t-key="emojiCategoryView.localId" record="emojiCategoryView"/>
</div>
</t>
@@ -2,9 +2,7 @@
<templates xml:space="preserve">
<t t-name="mail.EmojiCategoryView" owl="1">
<span class="o_EmojiCategoryView flex-grow-1 px-2 py-1 fs-5 cursor-pointer" t-att-class="(isHovered or isActive) ? 'active bg-view' : 'border-bottom'" t-att-title="category.name" t-on-click="onClick" t-on-mouseenter="onMouseenter" t-on-mouseleave="onMouseleave" t-attf-class="{{ className }}" t-ref="root">
<t t-esc="category.title"/>
</span>
<span class="o_EmojiCategoryView flex-grow-1 px-2 py-1 fs-5 cursor-pointer" t-att-class="(isHovered or isActive) ? 'active bg-view' : 'border-bottom'" t-att-title="category.name" t-esc="category.title" t-on-click="onClick" t-on-mouseenter="onMouseenter" t-on-mouseleave="onMouseleave" t-attf-class="{{ className }}" t-ref="root"/>
</t>
</templates>
@@ -5,9 +5,7 @@
<div class="o_EmojiGridRowView">
<EmojiGridSectionView t-if="sectionView" record="sectionView"/>
<t t-else="">
<t t-foreach="items" t-as="item" t-key="item">
<EmojiGridItemView className="'o_EmojiGridRowView_item'" record="item"/>
</t>
<EmojiGridItemView t-foreach="items" t-as="item" t-key="item" className="'o_EmojiGridRowView_item'" record="item"/>
</t>
</div>
</t>
@@ -2,15 +2,15 @@
<templates xml:space="preserve">
<t t-name="mail.EmojiGridView" owl="1">
<div class="o_EmojiGridView o_EmojiGridView_container" t-attf-style="--rowHeight: {{rowHeight}}px; --itemWidth: {{itemWidth}}px; height: {{height}}px; width: {{width}}px;" t-on-scroll="onScroll" t-ref="containerRef">
<EmojiGridLoadingScreen t-if="!this.messaging.emojiRegistry.isLoaded" record="loadingScreenView"/>
<EmojiGridSearchNoContentView t-if="searchNoContentView" record="searchNoContentView"/>
<div t-if="!searchNoContentView" class="o_EmojiGridView_list" t-attf-style="height: {{listHeight}}px; min-height: {{listHeight}}px;" t-ref="listRef">
<div t-if="lastRenderedRowIndex >= firstRenderedRowIndex" class="o_EmojiGridView_viewBlock" t-attf-style="top: {{ distanceFromTop - distanceInRowOffset }}px; width: {{ width }}px;" t-ref="viewBlockRef">
<EmojiGridRowView t-foreach="renderedRows" t-as="row" t-key="row" record="row"/>
<div class="o_EmojiGridView o_EmojiGridView_container" t-attf-style="--rowHeight: {{rowHeight}}px; --itemWidth: {{itemWidth}}px; height: {{height}}px; width: {{width}}px;" t-on-scroll="onScroll" t-ref="containerRef">
<EmojiGridLoadingScreen t-if="!this.messaging.emojiRegistry.isLoaded" record="loadingScreenView"/>
<EmojiGridSearchNoContentView t-if="searchNoContentView" record="searchNoContentView"/>
<div t-if="!searchNoContentView" class="o_EmojiGridView_list" t-attf-style="height: {{listHeight}}px; min-height: {{listHeight}}px;" t-ref="listRef">
<div t-if="lastRenderedRowIndex >= firstRenderedRowIndex" class="o_EmojiGridView_viewBlock" t-attf-style="top: {{ distanceFromTop - distanceInRowOffset }}px; width: {{ width }}px;" t-ref="viewBlockRef">
<EmojiGridRowView t-foreach="renderedRows" t-as="row" t-key="row" record="row"/>
</div>
</div>
</div>
</div>
</t>
</templates>
@@ -2,9 +2,7 @@
<templates xml:space="preserve">
<t t-name="mail.EmojiView" owl="1">
<span class="o_EmojiView p-1 fs-3 cursor-pointer" t-att-class="emojiGridViewAsHovered ? 'bg-200' : ''" t-on-click="onClick" t-on-mouseenter="onMouseenter" t-on-mouseleave="onMouseleave" t-att-title="emoji.name" t-att-data-source="emoji.sources[0]" t-att-data-codepoints="emoji.codepoints" t-attf-class="{{ className }}" t-ref="root">
<t t-esc="emoji.codepoints"/>
</span>
<span class="o_EmojiView p-1 fs-3 cursor-pointer" t-att-class="emojiGridViewAsHovered ? 'bg-200' : ''" t-esc="emoji.codepoints" t-on-click="onClick" t-on-mouseenter="onMouseenter" t-on-mouseleave="onMouseleave" t-att-title="emoji.name" t-att-data-source="emoji.sources[0]" t-att-data-codepoints="emoji.codepoints" t-attf-class="{{ className }}" t-ref="root"/>
</t>
</templates>
@@ -2,29 +2,25 @@
<templates xml:space="preserve">
<t t-name="mail.FollowButtonView" owl="1">
<div class="o_FollowButtonView d-flex" t-attf-class="{{ className }}" t-ref="root">
<t t-if="chatterOwner.thread and chatterOwner.thread.isCurrentPartnerFollowing">
<button class="o_FollowButtonView_unfollow btn px-0" t-att-class="{ 'o_ChatterTopbar_button': chatterOwner, 'o-following text-success': !isUnfollowButtonHighlighted, 'o-unfollow text-warning': isUnfollowButtonHighlighted }" t-att-disabled="isDisabled" t-on-click="onClickUnfollow" t-on-mouseenter="onMouseEnterUnfollow" t-on-mouseleave="onMouseleaveUnfollow">
<div class="position-relative">
<!-- Hidden element used to set the button maximum size -->
<span class="invisible">
<i class="fa fa-fw fa fa-eye-slash"/> <t t-out="followingText.length > unfollowingText.length ? followingText : unfollowingText"></t>
</span>
<span t-if="isUnfollowButtonHighlighted" class="o_FollowButtonView_text position-absolute end-0 top-0 bottom-0 text-warning">
<i class="fa fa-fw fa-times"/> <span t-out="unfollowingText"/>
</span>
<span t-else="" class="o_FollowButtonView_text d-block position-absolute end-0 top-0 bottom-0">
<i class="fa fa-fw fa-check"/> <span t-out="followingText"/>
</span>
</div>
</button>
</t>
<t t-else="">
<button class="o_FollowButtonView_follow btn btn-link text-600 pe-0" t-att-disabled="isDisabled" t-on-click="onClickFollow" t-att-class="{ 'o_ChatterTopbar_button': chatterOwner }">
Follow
</button>
</t>
</div>
<div class="o_FollowButtonView d-flex" t-attf-class="{{ className }}" t-ref="root">
<button t-if="chatterOwner.thread and chatterOwner.thread.isCurrentPartnerFollowing" class="o_FollowButtonView_unfollow btn px-0" t-att-class="{ 'o_ChatterTopbar_button': chatterOwner, 'o-following text-success': !isUnfollowButtonHighlighted, 'o-unfollow text-warning': isUnfollowButtonHighlighted }" t-att-disabled="isDisabled" t-on-click="onClickUnfollow" t-on-mouseenter="onMouseEnterUnfollow" t-on-mouseleave="onMouseleaveUnfollow">
<div class="position-relative">
<!-- Hidden element used to set the button maximum size -->
<span class="invisible">
<i class="fa fa-fw fa fa-eye-slash"/> <t t-out="followingText.length > unfollowingText.length ? followingText : unfollowingText"></t>
</span>
<span t-if="isUnfollowButtonHighlighted" class="o_FollowButtonView_text position-absolute end-0 top-0 bottom-0 text-warning">
<i class="fa fa-fw fa-times"/> <span t-out="unfollowingText"/>
</span>
<span t-else="" class="o_FollowButtonView_text d-block position-absolute end-0 top-0 bottom-0">
<i class="fa fa-fw fa-check"/> <span t-out="followingText"/>
</span>
</div>
</button>
<button t-else="" class="o_FollowButtonView_follow btn btn-link text-600 pe-0" t-att-disabled="isDisabled" t-on-click="onClickFollow" t-att-class="{ 'o_ChatterTopbar_button': chatterOwner }">
Follow
</button>
</div>
</t>
</templates>
@@ -2,20 +2,20 @@
<templates xml:space="preserve">
<t t-name="mail.FollowerView" owl="1">
<div class="o_FollowerView d-flex justify-content-between p-0" t-attf-class="{{ className }}" t-ref="root">
<a class="o_FollowerView_details d-flex align-items-center flex-grow-1 px-3 text-700" t-att-class="{ 'o-inactive fst-italic opacity-25': !follower.isActive }" href="#" role="menuitem" t-on-click="onClickDetails">
<img class="o_FollowerView_avatar me-2 rounded-circle" t-att-src="follower.partner.avatarUrl" alt=""/>
<span class="o_FollowerView_name flex-shrink text-truncate" t-esc="follower.partner.nameOrDisplayName"/>
</a>
<t t-if="follower.isEditable">
<button class="o_FollowerView_button o_FollowerView_editButton btn btn-icon rounded-0" title="Edit subscription" aria-label="Edit subscription" t-on-click="onClickEdit">
<i class="fa fa-pencil"/>
</button>
<button class="o_FollowerView_button o_FollowerView_removeButton btn btn-icon rounded-0" title="Remove this follower" aria-label="Remove this follower" t-on-click="onClickRemove">
<i class="fa fa-remove"/>
</button>
</t>
</div>
<div class="o_FollowerView d-flex justify-content-between p-0" t-attf-class="{{ className }}" t-ref="root">
<a class="o_FollowerView_details d-flex align-items-center flex-grow-1 px-3 text-700" t-att-class="{ 'o-inactive fst-italic opacity-25': !follower.isActive }" href="#" role="menuitem" t-on-click="onClickDetails">
<img class="o_FollowerView_avatar me-2 rounded-circle" t-att-src="follower.partner.avatarUrl" alt=""/>
<span class="o_FollowerView_name flex-shrink text-truncate" t-esc="follower.partner.nameOrDisplayName"/>
</a>
<t t-if="follower.isEditable">
<button class="o_FollowerView_button o_FollowerView_editButton btn btn-icon rounded-0" title="Edit subscription" aria-label="Edit subscription" t-on-click="onClickEdit">
<i class="fa fa-pencil"/>
</button>
<button class="o_FollowerView_button o_FollowerView_removeButton btn btn-icon rounded-0" title="Remove this follower" aria-label="Remove this follower" t-on-click="onClickRemove">
<i class="fa fa-remove"/>
</button>
</t>
</div>
</t>
</templates>
@@ -2,39 +2,32 @@
<templates xml:space="preserve">
<t t-name="mail.FollowerListMenuView" owl="1">
<div class="o_FollowerListMenuView position-relative d-flex" t-attf-class="{{ className }}" t-on-keydown="onKeydown" t-ref="root">
<div class="o_FollowerListMenuView_followers d-flex" t-ref="dropdown">
<button class="o_FollowerListMenuView_buttonFollowers o_ChatterTopbar_button btn btn-light" t-att-disabled="isDisabled" t-att-aria-expanded="isDropdownOpen ? 'true' : 'false'" t-on-click="onClickFollowersButton" aria-label="Show Followers">
<i class="fa fa-user-o" role="img"/>
<span class="o_FollowerListMenuView_buttonFollowersCount ps-1" t-esc="followerViews.length"/>
</button>
<t t-if="isDropdownOpen">
<div class="o_FollowerListMenuView_dropdown o-dropdown-menu dropdown-menu-end flex-column d-flex" role="menu">
<t t-if="chatterOwner.thread.model !== 'channel' and chatterOwner.thread.hasWriteAccess">
<a class="o_FollowerListMenuView_addFollowersButton dropdown-item" href="#" role="menuitem" t-on-click="onClickAddFollowers">
Add Followers
</a>
<t t-if="followerViews.length > 0">
<div role="separator" class="dropdown-divider"/>
</t>
</t>
<t t-if="followerViews.length > 0">
<FollowerView
t-foreach="followerViews" t-as="followerView" t-key="followerView.localId"
className="'o_FollowerMenu_follower dropdown-item'"
record="followerView"
/>
</t>
<t t-elif="!chatterOwner.thread.hasWriteAccess">
<div class="o_FollowerListMenuView_noFollowers dropdown-item disabled">
No Followers
</div>
</t>
</div>
<div class="o_FollowerListMenuView position-relative d-flex" t-attf-class="{{ className }}" t-on-keydown="onKeydown" t-ref="root">
<div class="o_FollowerListMenuView_followers d-flex" t-ref="dropdown">
<button class="o_FollowerListMenuView_buttonFollowers o_ChatterTopbar_button btn btn-light" t-att-disabled="isDisabled" t-att-aria-expanded="isDropdownOpen ? 'true' : 'false'" t-on-click="onClickFollowersButton" aria-label="Show Followers">
<i class="fa fa-user-o" role="img"/>
<span class="o_FollowerListMenuView_buttonFollowersCount ps-1" t-esc="followerViews.length"/>
</button>
<div t-if="isDropdownOpen" class="o_FollowerListMenuView_dropdown o-dropdown-menu dropdown-menu-end flex-column d-flex" role="menu">
<t t-if="chatterOwner.thread.model !== 'channel' and chatterOwner.thread.hasWriteAccess">
<a class="o_FollowerListMenuView_addFollowersButton dropdown-item" href="#" role="menuitem" t-on-click="onClickAddFollowers">
Add Followers
</a>
<div t-if="followerViews.length > 0" role="separator" class="dropdown-divider"/>
</t>
<t t-if="followerViews.length > 0">
<FollowerView
t-foreach="followerViews" t-as="followerView" t-key="followerView.localId"
className="'o_FollowerMenu_follower dropdown-item'"
record="followerView"
/>
</t>
<div t-elif="!chatterOwner.thread.hasWriteAccess" class="o_FollowerListMenuView_noFollowers dropdown-item disabled">
No Followers
</div>
</div>
</div>
</div>
</t>
</templates>
@@ -2,12 +2,12 @@
<templates xml:space="preserve">
<t t-name="mail.FollowerSubtypeView" owl="1">
<div class="o_FollowerSubtypeView" t-attf-class="{{ className }}" t-att-data-follower-subtype-id="subtype.id" t-ref="root">
<label class="o_FollowerSubtypeView_label flex-grow-1 align-items-center d-flex mb-0 p-2 cursor-pointer">
<input class="o_FollowerSubtypeView_checkbox form-check-input me-2" type="checkbox" t-att-checked="follower.selectedSubtypes.includes(subtype) ? 'checked': ''" t-on-change="onChangeCheckbox"/>
<t t-esc="subtype.name"/>
</label>
</div>
<div class="o_FollowerSubtypeView" t-attf-class="{{ className }}" t-att-data-follower-subtype-id="subtype.id" t-ref="root">
<label class="o_FollowerSubtypeView_label flex-grow-1 align-items-center d-flex mb-0 p-2 cursor-pointer">
<input class="o_FollowerSubtypeView_checkbox form-check-input me-2" type="checkbox" t-att-checked="follower.selectedSubtypes.includes(subtype) ? 'checked': ''" t-on-change="onChangeCheckbox"/>
<t t-esc="subtype.name"/>
</label>
</div>
</t>
</templates>
@@ -2,34 +2,32 @@
<templates xml:space="preserve">
<t t-name="mail.FollowerSubtypeList" owl="1">
<div class="o_FollowerSubtypeList modal-dialog" t-attf-class="{{ className }}" t-ref="root">
<div class="modal-content">
<header class="modal-header">
<h4 class="modal-title">
Edit Subscription of <t t-esc="follower.partner.nameOrDisplayName"/>
</h4>
<i class="o_FollowerSubtypeList_closeButton close fa fa-times" aria-label="Close" t-on-click="onClickCancel"/>
</header>
<main class="modal-body">
<div class="o_FollowerSubtypeList_subtypes flex-column d-flex">
<t t-foreach="followerSubtypeViews" t-as="followerSubtypeView" t-key="followerSubtypeView.localId">
<FollowerSubtypeView
className="'o_FollowerSubtypeList_subtype'"
record="followerSubtypeView"
/>
</t>
</div>
</main>
<div class="modal-footer">
<button class="o-apply btn btn-primary" t-on-click="onClickApply">
Apply
</button>
<button class="o-cancel btn btn-secondary" t-on-click="onClickCancel">
Cancel
</button>
<div class="o_FollowerSubtypeList modal-dialog" t-attf-class="{{ className }}" t-ref="root">
<div class="modal-content">
<header class="modal-header">
<h4 class="modal-title">
Edit Subscription of <t t-esc="follower.partner.nameOrDisplayName"/>
</h4>
<i class="o_FollowerSubtypeList_closeButton close fa fa-times" aria-label="Close" t-on-click="onClickCancel"/>
</header>
<main class="modal-body">
<div class="o_FollowerSubtypeList_subtypes flex-column d-flex">
<FollowerSubtypeView t-foreach="followerSubtypeViews" t-as="followerSubtypeView" t-key="followerSubtypeView.localId"
className="'o_FollowerSubtypeList_subtype'"
record="followerSubtypeView"
/>
</div>
</main>
<div class="modal-footer">
<button class="o-apply btn btn-primary" t-on-click="onClickApply">
Apply
</button>
<button class="o-cancel btn btn-secondary" t-on-click="onClickCancel">
Cancel
</button>
</div>
</div>
</div>
</t>
</templates>
@@ -2,30 +2,30 @@
<templates xml:space="preserve">
<t t-name="mail.MailTemplateView" owl="1">
<div class="o_MailTemplateView d-flex align-items-baseline flex-wrap" t-attf-class="{{ className }}" t-ref="root">
<div class="text-truncate">
<i class="fa fa-envelope-o" title="Mail" role="img"/>
<span class="o_MailTemplateView_name ms-2" t-esc="mailTemplate.name"/>
<span>:</span>
</div>
<div class="d-flex align-items-baseline">
<button
class="o_MailTemplateView_button o_MailTemplateView_preview btn btn-link py-0"
t-att-data-mail-template-id="mailTemplate.id"
t-on-click="onClickPreview"
>
Preview
</button>
<em class="o_MailTemplateView_text text-500">or</em>
<button
class="o_MailTemplateView_button o_MailTemplateView_send btn btn-link py-0"
t-att-data-mail-template-id="mailTemplate.id"
t-on-click="onClickSend"
>
Send Now
</button>
</div>
<div class="o_MailTemplateView d-flex align-items-baseline flex-wrap" t-attf-class="{{ className }}" t-ref="root">
<div class="text-truncate">
<i class="fa fa-envelope-o" title="Mail" role="img"/>
<span class="o_MailTemplateView_name ms-2" t-esc="mailTemplate.name"/>
<span>:</span>
</div>
<div class="d-flex align-items-baseline">
<button
class="o_MailTemplateView_button o_MailTemplateView_preview btn btn-link py-0"
t-att-data-mail-template-id="mailTemplate.id"
t-on-click="onClickPreview"
>
Preview
</button>
<em class="o_MailTemplateView_text text-500">or</em>
<button
class="o_MailTemplateView_button o_MailTemplateView_send btn btn-link py-0"
t-att-data-mail-template-id="mailTemplate.id"
t-on-click="onClickSend"
>
Send Now
</button>
</div>
</div>
</t>
</templates>
@@ -2,218 +2,166 @@
<templates xml:space="preserve">
<t t-name="mail.MessageView" owl="1">
<div class="o_MessageView position-relative py-1"
t-att-class="{
'o_MessageView_active': isActive,
'o-clicked': messagingAsClickedMessageView,
'o-discussion': message.isDiscussionOrNotification,
'o-has-message-selection': messageListViewItemOwner and messageListViewItemOwner.messageListViewOwner.threadViewOwner.replyingToMessageView,
'o-highlighted': message.isHighlighted or isHighlighted,
'o-isReplyHighlighted bg-view shadow-lg': isHighlighted,
'o-isDeviceSmall': messaging.device.isSmall,
'o-not-discussion': !message.isDiscussionOrNotification,
'o-notification': message.message_type === 'notification',
'o-selected': isSelected,
'o-squashed pt-1': isSquashed,
'o-starred': message.isStarred,
'o-currentAuthor': message.isCurrentUserOrGuestAuthor,
'mt-1': !isSquashed and messageListViewItemOwner,
'px-3': !isInChatWindow,
'px-1': isInChatWindow,
'opacity-50': (messageListViewItemOwner and messageListViewItemOwner.messageListViewOwner.threadViewOwner.replyingToMessageView) and !isSelected,
}" t-attf-class="{{ extraClass }} {{ className }}" role="group" t-att-aria-label="message.messageTypeText" t-on-click="onClick" t-on-mouseenter="onMouseenter" t-on-mouseleave="onMouseleave" t-att-data-id="message.id" t-att-data-message-id="message.id"
t-ref="root"
>
<div class="o_MessageView_inReplyToWrap" t-att-class="{ 'me-5': isInDiscuss or isInChatWindowAndIsAlignedLeft, 'd-flex justify-content-end ms-5': isInChatWindowAndIsAlignedRight }">
<MessageInReplyToView t-if="messageInReplyToView" record="messageInReplyToView" className="'mb-1'" classNameObj="{ 'me-5': isInChatWindowAndIsAlignedLeft, 'ms-5': isInChatWindowAndIsAlignedRight }"/>
</div>
<div class="position-relative d-flex flex-shrink-0" t-att-class="{ 'flex-row-reverse': isInChatWindowAndIsAlignedRight }">
<div class="o_MessageView_sidebar d-flex flex-shrink-0" t-att-class="{ 'o-message-squashed align-items-start': isSquashed, 'justify-content-center': isInChatWindow }">
<t t-if="!isSquashed">
<div class="o_MessageView_authorAvatarContainer o_MessageView_sidebarItem position-relative">
<img class="o_MessageView_authorAvatar w-100 h-100 rounded-circle o_object_fit_cover" t-att-class="{ 'cursor-pointer': hasAuthorOpenChat, o_redirect: hasAuthorOpenChat }" t-att-src="message.avatarUrl" t-att-role="hasAuthorOpenChat ? 'button' : ''" t-att-tabindex="hasAuthorOpenChat ? '0' : ''" t-on-click="onClickAuthorAvatar" t-att-title="authorTitleText" t-att-alt="authorTitleText"/>
<t t-if="personaImStatusIconView">
<PersonaImStatusIconView
className="'o_MessageView_personaImStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center text-white'"
classNameObj="{
'o-message-selected': isSelected,
'o_MessageView_personaImStatusIcon-mobile': messaging.device.isSmall,
'small': !messaging.device.isSmall,
'text-100': message.is_note and !isSelected,
}"
record="personaImStatusIconView"
/>
</t>
</div>
</t>
<t t-else="">
<t t-if="isActive and message.date">
<small class="o_MessageView_date o_MessageView_sidebarItem mt-3 mx-1 text-muted opacity-50">
<t t-esc="message.shortTime"/>
</small>
</t>
<t t-if="!isActive and messageSeenIndicatorView">
<div t-att-class="{ 'position-absolute bottom-0 mb-1': !isInChatter }">
<MessageSeenIndicatorView className="'o_MessageView_seenIndicator me-1'" record="messageSeenIndicatorView"/>
</div>
</t>
</t>
<div class="o_MessageView position-relative py-1"
t-att-class="{
'o_MessageView_active': isActive,
'o-clicked': messagingAsClickedMessageView,
'o-discussion': message.isDiscussionOrNotification,
'o-has-message-selection': messageListViewItemOwner and messageListViewItemOwner.messageListViewOwner.threadViewOwner.replyingToMessageView,
'o-highlighted': message.isHighlighted or isHighlighted,
'o-isReplyHighlighted bg-view shadow-lg': isHighlighted,
'o-isDeviceSmall': messaging.device.isSmall,
'o-not-discussion': !message.isDiscussionOrNotification,
'o-notification': message.message_type === 'notification',
'o-selected': isSelected,
'o-squashed pt-1': isSquashed,
'o-starred': message.isStarred,
'o-currentAuthor': message.isCurrentUserOrGuestAuthor,
'mt-1': !isSquashed and messageListViewItemOwner,
'px-3': !isInChatWindow,
'px-1': isInChatWindow,
'opacity-50': (messageListViewItemOwner and messageListViewItemOwner.messageListViewOwner.threadViewOwner.replyingToMessageView) and !isSelected,
}" t-attf-class="{{ extraClass }} {{ className }}" role="group" t-att-aria-label="message.messageTypeText" t-on-click="onClick" t-on-mouseenter="onMouseenter" t-on-mouseleave="onMouseleave" t-att-data-id="message.id" t-att-data-message-id="message.id"
t-ref="root"
>
<div class="o_MessageView_inReplyToWrap" t-att-class="{ 'me-5': isInDiscuss or isInChatWindowAndIsAlignedLeft, 'd-flex justify-content-end ms-5': isInChatWindowAndIsAlignedRight }">
<MessageInReplyToView t-if="messageInReplyToView" record="messageInReplyToView" className="'mb-1'" classNameObj="{ 'me-5': isInChatWindowAndIsAlignedLeft, 'ms-5': isInChatWindowAndIsAlignedRight }"/>
</div>
<div class="position-relative d-flex flex-shrink-0" t-att-class="{ 'flex-row-reverse': isInChatWindowAndIsAlignedRight }">
<div class="o_MessageView_sidebar d-flex flex-shrink-0" t-att-class="{ 'o-message-squashed align-items-start': isSquashed, 'justify-content-center': isInChatWindow }">
<div t-if="!isSquashed" class="o_MessageView_authorAvatarContainer o_MessageView_sidebarItem position-relative">
<img class="o_MessageView_authorAvatar w-100 h-100 rounded-circle o_object_fit_cover" t-att-class="{ 'cursor-pointer': hasAuthorOpenChat, o_redirect: hasAuthorOpenChat }" t-att-src="message.avatarUrl" t-att-role="hasAuthorOpenChat ? 'button' : ''" t-att-tabindex="hasAuthorOpenChat ? '0' : ''" t-on-click="onClickAuthorAvatar" t-att-title="authorTitleText" t-att-alt="authorTitleText"/>
<PersonaImStatusIconView t-if="personaImStatusIconView"
className="'o_MessageView_personaImStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center text-white'"
classNameObj="{
'o-message-selected': isSelected,
'o_MessageView_personaImStatusIcon-mobile': messaging.device.isSmall,
'small': !messaging.device.isSmall,
'text-100': message.is_note and !isSelected,
}"
record="personaImStatusIconView"
/>
</div>
<div class="o_MessageView_core flex-grow-1">
<t t-if="!isSquashed">
<div class="o_MessageView_header d-flex flex-wrap align-items-baseline" t-att-class="{ 'justify-content-end': isInChatWindowAndIsAlignedRight }">
<t t-if="message.author">
<strong t-if="isShowingAuthorName" class="o_MessageView_authorName o_redirect me-1 text-truncate" t-att-class="{ 'cursor-pointer': hasAuthorOpenChat }" t-att-role="hasAuthorOpenChat ? 'button' : ''" t-att-tabindex="hasAuthorOpenChat ? '0' : ''" t-on-click="onClickAuthorName" t-att-title="authorTitleText">
<t t-if="message.originThread">
<t t-esc="message.originThread.getMemberName(message.author.persona)"/>
</t>
<t t-else="">
<t t-esc="message.author.nameOrDisplayName"/>
</t>
</strong>
</t>
<t t-elif="message.guestAuthor">
<strong class="o_MessageView_authorName me-2 text-truncate text-muted">
<t t-esc="message.guestAuthor.name"/>
</strong>
</t>
<t t-elif="message.email_from">
<a class="o_MessageView_authorName me-2 text-truncate text-muted" t-attf-href="mailto:{{ message.email_from }}?subject=Re: {{ message.subject ? message.subject : '' }}">
<strong>
<t t-esc="message.email_from"/>
</strong>
</a>
</t>
<t t-else="">
<strong class="o_MessageView_authorName me-2 text-truncate text-muted">
Anonymous
</strong>
</t>
<t t-if="message.date">
<small class="o_MessageView_date o_MessageView_headerDate text-muted opacity-50" t-att-class="{ 'o-message-selected': isSelected, 'me-2': !(isInChatWindowAndIsAlignedRight) }" t-att-title="message.datetime">
<span t-if="isShowingAuthorName">-</span> <t t-esc="dateFromNow"/>
</small>
</t>
<t t-if="messageSeenIndicatorView">
<MessageSeenIndicatorView className="'o_MessageView_seenIndicator ms-1'" record="messageSeenIndicatorView"/>
</t>
<t t-if="messageListViewItemOwner and message.originThread and message.originThread !== messageListViewItemOwner.messageListViewOwner.threadViewOwner.thread">
<small class="o_MessageView_originThread me-2" t-att-class="{ 'o-message-selected text-600': isSelected, 'text-500': !isSelected }">
<t t-if="message.originThread.model === 'mail.channel'">
(from <a class="o_MessageView_originThreadLink fs-6" t-att-href="message.originThread.url" t-on-click="onClickOriginThread"><t t-if="message.originThread.displayName">#<t t-esc="message.originThread.displayName"/></t><t t-else="">channel</t></a>)
</t>
<t t-else="">
on <a class="o_MessageView_originThreadLink fs-6" t-att-href="message.originThread.url" t-on-click="onClickOriginThread"><t t-if="message.originThread.displayName"><t t-esc="message.originThread.displayName"/></t><t t-else="">document</t></a>
</t>
</small>
</t>
<t t-if="messageListViewItemOwner and message.originThread and message.originThread === messageListViewItemOwner.messageListViewOwner.threadViewOwner.thread and message.notifications.length > 0">
<div t-att-class="{ 'ms-2': isInChatWindowAndIsAlignedRight }">
<t t-if="message.failureNotifications.length > 0">
<span class="o_MessageView_notificationIconClickable o-error cursor-pointer text-danger" role="button" tabindex="0" t-on-click="onClickFailure">
<i class="o_MessageView_notificationIcon" t-att-class="failureNotificationIconClassName" role="img" aria-label="Delivery failure"/> <span t-if="failureNotificationIconLabel" t-out="failureNotificationIconLabel"/>
</span>
</t>
<t t-else="">
<span class="o_MessageView_notificationIconClickable text-600 cursor-pointer" t-on-click="onClickNotificationIcon" t-ref="notificationIcon">
<i class="o_MessageView_notificationIcon" t-att-class="notificationIconClassName"/> <span t-if="notificationIconLabel" t-out="notificationIconLabel"/>
</span>
</t>
</div>
</t>
</div>
<t t-else="">
<small t-if="isActive and message.date" class="o_MessageView_date o_MessageView_sidebarItem mt-3 mx-1 text-muted opacity-50" t-esc="message.shortTime"/>
<div t-if="!isActive and messageSeenIndicatorView" t-att-class="{ 'position-absolute bottom-0 mb-1': !isInChatter }">
<MessageSeenIndicatorView className="'o_MessageView_seenIndicator me-1'" record="messageSeenIndicatorView"/>
</div>
</t>
</div>
<div class="o_MessageView_core flex-grow-1">
<div t-if="!isSquashed" class="o_MessageView_header d-flex flex-wrap align-items-baseline" t-att-class="{ 'justify-content-end': isInChatWindowAndIsAlignedRight }">
<t t-if="message.author">
<strong t-if="isShowingAuthorName" class="o_MessageView_authorName o_redirect me-1 text-truncate" t-att-class="{ 'cursor-pointer': hasAuthorOpenChat }" t-att-role="hasAuthorOpenChat ? 'button' : ''" t-att-tabindex="hasAuthorOpenChat ? '0' : ''" t-on-click="onClickAuthorName" t-att-title="authorTitleText">
<t t-if="message.originThread" t-esc="message.originThread.getMemberName(message.author.persona)"/>
<t t-else="" t-esc="message.author.nameOrDisplayName"/>
</strong>
</t>
<strong t-elif="message.guestAuthor" class="o_MessageView_authorName me-2 text-truncate text-muted" t-esc="message.guestAuthor.name"/>
<a t-elif="message.email_from" class="o_MessageView_authorName me-2 text-truncate text-muted" t-attf-href="mailto:{{ message.email_from }}?subject=Re: {{ message.subject ? message.subject : '' }}">
<strong t-esc="message.email_from"/>
</a>
<strong t-else="" class="o_MessageView_authorName me-2 text-truncate text-muted">
Anonymous
</strong>
<small t-if="message.date" class="o_MessageView_date o_MessageView_headerDate text-muted opacity-50" t-att-class="{ 'o-message-selected': isSelected, 'me-2': !(isInChatWindowAndIsAlignedRight) }" t-att-title="message.datetime">
<span t-if="isShowingAuthorName">-</span> <t t-esc="dateFromNow"/>
</small>
<MessageSeenIndicatorView t-if="messageSeenIndicatorView" className="'o_MessageView_seenIndicator ms-1'" record="messageSeenIndicatorView"/>
<small t-if="messageListViewItemOwner and message.originThread and message.originThread !== messageListViewItemOwner.messageListViewOwner.threadViewOwner.thread" class="o_MessageView_originThread me-2" t-att-class="{ 'o-message-selected text-600': isSelected, 'text-500': !isSelected }">
<t t-if="message.originThread.model === 'mail.channel'">
(from <a class="o_MessageView_originThreadLink fs-6" t-att-href="message.originThread.url" t-on-click="onClickOriginThread"><t t-if="message.originThread.displayName">#<t t-esc="message.originThread.displayName"/></t><t t-else="">channel</t></a>)
</t>
<t t-else="">
on <a class="o_MessageView_originThreadLink fs-6" t-att-href="message.originThread.url" t-on-click="onClickOriginThread"><t t-if="message.originThread.displayName"><t t-esc="message.originThread.displayName"/></t><t t-else="">document</t></a>
</t>
</small>
<div t-if="messageListViewItemOwner and message.originThread and message.originThread === messageListViewItemOwner.messageListViewOwner.threadViewOwner.thread and message.notifications.length > 0" t-att-class="{ 'ms-2': isInChatWindowAndIsAlignedRight }">
<span t-if="message.failureNotifications.length > 0" class="o_MessageView_notificationIconClickable o-error cursor-pointer text-danger" role="button" tabindex="0" t-on-click="onClickFailure">
<i class="o_MessageView_notificationIcon" t-att-class="failureNotificationIconClassName" role="img" aria-label="Delivery failure"/> <span t-if="failureNotificationIconLabel" t-out="failureNotificationIconLabel"/>
</span>
<span t-else="" class="o_MessageView_notificationIconClickable text-600 cursor-pointer" t-on-click="onClickNotificationIcon" t-ref="notificationIcon">
<i class="o_MessageView_notificationIcon" t-att-class="notificationIconClassName"/> <span t-if="notificationIconLabel" t-out="notificationIconLabel"/>
</span>
</div>
</div>
<div
class="o_MessageView_bubbleWrap position-relative d-flex align-items-start"
t-att-class="{
'd-flex justify-content-end': isInChatWindowAndIsAlignedRight,
'pe-4': isInChatWindowAndIsAlignedLeft and !composerViewInEditing,
'ps-4': isInChatWindowAndIsAlignedRight and !composerViewInEditing,
'pe-2': isInChatWindowAndIsAlignedLeft and composerViewInEditing,
'ps-2': isInChatWindowAndIsAlignedRight and composerViewInEditing,
}"
>
<div
class="o_MessageView_bubbleWrap position-relative d-flex align-items-start"
class="o_MessageView_bubble position-relative"
t-att-class="{
'd-flex justify-content-end': isInChatWindowAndIsAlignedRight,
'pe-4': isInChatWindowAndIsAlignedLeft and !composerViewInEditing,
'ps-4': isInChatWindowAndIsAlignedRight and !composerViewInEditing,
'pe-2': isInChatWindowAndIsAlignedLeft and composerViewInEditing,
'ps-2': isInChatWindowAndIsAlignedRight and composerViewInEditing,
'flex-grow-1': composerViewInEditing,
'w-100': !(message.isDiscussionOrNotification or message.message_type === 'sms') and !isInChatWindow,
'me-2': isInChatWindowAndIsAlignedLeft and !composerViewInEditing,
'ms-2': isInChatWindowAndIsAlignedRight and !composerViewInEditing,
'p-3': message.prettyBody !== '' and !composerViewInEditing and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'p-2': composerViewInEditing,
'text-muted': message.is_note and message.message_type !== 'sms',
}"
>
<div
class="o_MessageView_bubble position-relative"
t-if="message.prettyBody !== '' || composerViewInEditing"
class="o_MessageView_background position-absolute start-0 top-0 w-100 h-100"
t-att-class="{
'flex-grow-1': composerViewInEditing,
'w-100': !(message.isDiscussionOrNotification or message.message_type === 'sms') and !isInChatWindow,
'me-2': isInChatWindowAndIsAlignedLeft and !composerViewInEditing,
'ms-2': isInChatWindowAndIsAlignedRight and !composerViewInEditing,
'p-3': message.prettyBody !== '' and !composerViewInEditing and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'p-2': composerViewInEditing,
'text-muted': message.is_note and message.message_type !== 'sms',
'rounded-end-3': !isInChatWindowAndIsAlignedRight and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'rounded-start-3': isInChatWindowAndIsAlignedRight and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'rounded-bottom-3 border': message.isDiscussionOrNotification or message.message_type === 'sms',
'o-isAuthorNotCurrentUserOrGuest border-info bg-info-light': !message.isCurrentUserOrGuestAuthor and !message.isHighlighted and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'border-success bg-success-light opacity-25': message.isCurrentUserOrGuestAuthor and !message.isHighlighted and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'border-warning bg-warning-light opacity-50': message.isHighlighted and (message.isDiscussionOrNotification or message.message_type === 'sms'),
}"
>
<div
t-if="message.prettyBody !== '' || composerViewInEditing"
class="o_MessageView_background position-absolute start-0 top-0 w-100 h-100"
t-att-class="{
'rounded-end-3': !isInChatWindowAndIsAlignedRight and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'rounded-start-3': isInChatWindowAndIsAlignedRight and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'rounded-bottom-3 border': message.isDiscussionOrNotification or message.message_type === 'sms',
'o-isAuthorNotCurrentUserOrGuest border-info bg-info-light': !message.isCurrentUserOrGuestAuthor and !message.isHighlighted and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'border-success bg-success-light opacity-25': message.isCurrentUserOrGuestAuthor and !message.isHighlighted and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'border-warning bg-warning-light opacity-50': message.isHighlighted and (message.isDiscussionOrNotification or message.message_type === 'sms'),
}"
/>
<em t-if="message.subject and !message.isSubjectSimilarToOriginThreadName" class="o_MessageView_subject position-relative mb-1 me-2">Subject: <t t-esc="message.subject"/></em>
<div class="o_MessageView_content position-relative text-break" t-ref="content">
<div t-if="!composerViewInEditing" class="o_MessageView_prettyBody" t-ref="prettyBody"/><!-- message.prettyBody is inserted here from _update() -->
<ComposerView t-if="composerViewInEditing"
className="'o_MessageView_composer'"
record="composerViewInEditing"
/>
<t t-if="message.subject and !message.isSubjectSimilarToOriginThreadName">
<em class="o_MessageView_subject position-relative mb-1 me-2">Subject: <t t-esc="message.subject"/></em>
</t>
<div class="o_MessageView_content position-relative text-break" t-ref="content">
<t t-if="!composerViewInEditing">
<div class="o_MessageView_prettyBody" t-ref="prettyBody"/><!-- message.prettyBody is inserted here from _update() -->
</t>
<t t-if="composerViewInEditing">
<ComposerView
className="'o_MessageView_composer'"
record="composerViewInEditing"
/>
</t>
<t t-if="message.subtype_description and !message.isBodyEqualSubtypeDescription">
<p t-esc="message.subtype_description" class="mb-0"/>
</t>
<t t-if="message.trackingValues.length > 0">
<ul class="o_MessageView_trackingValues mb-0 ps-4">
<t t-foreach="message.trackingValues" t-as="trackingValue" t-key="trackingValue.id">
<li>
<TrackingValue value="trackingValue"/>
</li>
</t>
</ul>
</t>
</div>
</div>
<div
t-if="messageActionList and !composerViewInEditing"
class="o_MessageView_actionListContainer"
t-att-class="{
'o-squashed': isSquashed,
'position-absolute top-0': !isInDiscuss,
'start-0 ms-3': isInChatWindowAndIsAlignedRight,
'end-0 me-3': isInChatWindowAndIsAlignedLeft || isInChatter,
'mt-n4': isInChatter and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'mt-n5': isInChatter and !(message.isDiscussionOrNotification or message.message_type === 'sms'),
'mt-2': isInDiscuss and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'mt-n3': isInChatWindow,
'ms-2': isInDiscuss,
}"
t-attf-class="{{ isActive ? 'visible' : 'invisible' }}"
>
<MessageActionList record="messageActionList" classNameObj="{ 'mt-3': isInChatter and !(message.isDiscussionOrNotification or message.message_type === 'sms') }"/>
<p t-if="message.subtype_description and !message.isBodyEqualSubtypeDescription" t-esc="message.subtype_description" class="mb-0"/>
<ul t-if="message.trackingValues.length > 0" class="o_MessageView_trackingValues mb-0 ps-4">
<li t-foreach="message.trackingValues" t-as="trackingValue" t-key="trackingValue.id">
<TrackingValue value="trackingValue"/>
</li>
</ul>
</div>
</div>
<AttachmentList t-if="attachmentList" record="attachmentList" className="'position-relative'"/>
<LinkPreviewListView t-if="linkPreviewListView" record="linkPreviewListView"/>
<div t-if="message.messageReactionGroups.length > 0" class="position-relative d-flex flex-wrap"
t-att-class="{ 'flex-row-reverse me-3': isInChatWindowAndIsAlignedRight, 'ms-3': !isInChatWindowAndIsAlignedRight and (message.isDiscussionOrNotification or message.message_type === 'sms')}" t-attf-class="{{ message.isDiscussionOrNotification or message.message_type === 'sms' ? 'mt-n2' : 'mt-1' }}">
<t t-foreach="message.messageReactionGroups" t-as="messageReactionGroup" t-key="messageReactionGroup.localId">
<MessageReactionGroup className="'mb-1'" classNameObj="{ 'ms-1': isInChatWindowAndIsAlignedRight, 'me-1': !(isInChatWindowAndIsAlignedRight) }" record="messageReactionGroup"/>
</t>
<div
t-if="messageActionList and !composerViewInEditing"
class="o_MessageView_actionListContainer"
t-att-class="{
'o-squashed': isSquashed,
'position-absolute top-0': !isInDiscuss,
'start-0 ms-3': isInChatWindowAndIsAlignedRight,
'end-0 me-3': isInChatWindowAndIsAlignedLeft || isInChatter,
'mt-n4': isInChatter and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'mt-n5': isInChatter and !(message.isDiscussionOrNotification or message.message_type === 'sms'),
'mt-2': isInDiscuss and (message.isDiscussionOrNotification or message.message_type === 'sms'),
'mt-n3': isInChatWindow,
'ms-2': isInDiscuss,
}"
t-attf-class="{{ isActive ? 'visible' : 'invisible' }}"
>
<MessageActionList record="messageActionList" classNameObj="{ 'mt-3': isInChatter and !(message.isDiscussionOrNotification or message.message_type === 'sms') }"/>
</div>
</div>
<AttachmentList t-if="attachmentList" record="attachmentList" className="'position-relative'"/>
<LinkPreviewListView t-if="linkPreviewListView" record="linkPreviewListView"/>
<div t-if="message.messageReactionGroups.length > 0" class="position-relative d-flex flex-wrap"
t-att-class="{ 'flex-row-reverse me-3': isInChatWindowAndIsAlignedRight, 'ms-3': !isInChatWindowAndIsAlignedRight and (message.isDiscussionOrNotification or message.message_type === 'sms')}" t-attf-class="{{ message.isDiscussionOrNotification or message.message_type === 'sms' ? 'mt-n2' : 'mt-1' }}">
<MessageReactionGroup t-foreach="message.messageReactionGroups" t-as="messageReactionGroup" t-key="messageReactionGroup.localId" className="'mb-1'" classNameObj="{ 'ms-1': isInChatWindowAndIsAlignedRight, 'me-1': !(isInChatWindowAndIsAlignedRight) }" record="messageReactionGroup"/>
</div>
</div>
</div>
</div>
</t>
</templates>
@@ -1,10 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<templates>
<t t-name="mail.MessageActionList" owl="1">
<div class="o_MessageActionList d-flex rounded-1 shadow-sm overflow-hidden" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'flex-row-reverse': messageView.isInChatWindowAndIsAlignedRight }" t-attf-class="{{ className }}" t-ref="root">
<t t-foreach="messageActionViews" t-as="messageActionView" t-key="messageActionView.localId">
<MessageActionView record="messageActionView"/>
</t>
</div>
<div class="o_MessageActionList d-flex rounded-1 shadow-sm overflow-hidden" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'flex-row-reverse': messageView.isInChatWindowAndIsAlignedRight }" t-attf-class="{{ className }}" t-ref="root">
<MessageActionView t-foreach="messageActionViews" t-as="messageActionView" t-key="messageActionView.localId" record="messageActionView"/>
</div>
</t>
</templates>
@@ -2,16 +2,16 @@
<templates xml:space="preserve">
<t t-name="mail.MessageAuthorPrefixView" owl="1">
<span class="o_MessageAuthorPrefixView" t-attf-class="{{ className }}" t-ref="root">
<t t-if="message">
<t t-if="message.author and message.author === messaging.currentPartner">
<i class="o_MessageAuthorPrefixView_icon fa fa-mail-reply me-1"/>You:
</t>
<t t-elif="thread and (!thread.channel or message.author !== thread.channel.correspondent)">
<t t-esc="message.author.nameOrDisplayName"/>:
</t>
<span class="o_MessageAuthorPrefixView" t-attf-class="{{ className }}" t-ref="root">
<t t-if="message">
<t t-if="message.author and message.author === messaging.currentPartner">
<i class="o_MessageAuthorPrefixView_icon fa fa-mail-reply me-1"/>You:
</t>
</span>
<t t-elif="thread and (!thread.channel or message.author !== thread.channel.correspondent)">
<t t-esc="message.author.nameOrDisplayName"/>:
</t>
</t>
</span>
</t>
</templates>
@@ -1,28 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.MessageInReplyToView" owl="1">
<small class="o_MessageInReplyToView position-relative d-block text-small" t-attf-class="{{ className }} {{ messageView.isInChatWindowAndIsAlignedRight ? 'justify-content-end pe-5': 'ps-5' }}" t-ref="root">
<span class="o_MessageInReplyToView_corner position-absolute bottom-0 top-50 pe-4 border-top text-300" t-attf-class="{{ messageView.isInChatWindowAndIsAlignedRight ? 'o-isRightAlign border-end' : 'o-isLeftAlign border-start' }}" t-att-class="{ 'ms-n2': messageView.isInDiscuss }"/>
<t t-if="!messageView.message.parentMessage.isEmpty">
<span class="o_MessageInReplyToView_wrapOuter d-flex align-items-center text-muted opacity-75 opacity-100-hover cursor-pointer" t-attf-class="{{ messageView.isInChatWindowAndIsAlignedRight ? 'pe-3': 'ps-3' }}" t-on-click="onClickReply">
<img class="o_MessageInReplyToView_avatar me-2 rounded-circle" t-att-src="messageView.message.parentMessage.avatarUrl" t-att-title="messageView.message.parentMessage.authorName" alt="Avatar"/>
<span class="o_MessageInReplyToView_wrapInner overflow-hidden">
<b class="o_MessageInReplyToView_author">@<t t-out="messageView.message.parentMessage.authorName"/></b>:
<span class="o_MessageInReplyToView_body ms-1 text-break">
<t t-if="hasBodyBackLink">
<t t-out="messageView.message.parentMessage.prettyBodyAsMarkup"/>
</t>
<t t-if="hasAttachmentBackLink">
<span class="me-2 fst-italic">Click to see the attachments</span>
<i class="fa fa-image"/>
</t>
</span>
</span>
<small class="o_MessageInReplyToView position-relative d-block text-small" t-attf-class="{{ className }} {{ messageView.isInChatWindowAndIsAlignedRight ? 'justify-content-end pe-5': 'ps-5' }}" t-ref="root">
<span class="o_MessageInReplyToView_corner position-absolute bottom-0 top-50 pe-4 border-top text-300" t-attf-class="{{ messageView.isInChatWindowAndIsAlignedRight ? 'o-isRightAlign border-end' : 'o-isLeftAlign border-start' }}" t-att-class="{ 'ms-n2': messageView.isInDiscuss }"/>
<span t-if="!messageView.message.parentMessage.isEmpty" class="o_MessageInReplyToView_wrapOuter d-flex align-items-center text-muted opacity-75 opacity-100-hover cursor-pointer" t-attf-class="{{ messageView.isInChatWindowAndIsAlignedRight ? 'pe-3': 'ps-3' }}" t-on-click="onClickReply">
<img class="o_MessageInReplyToView_avatar me-2 rounded-circle" t-att-src="messageView.message.parentMessage.avatarUrl" t-att-title="messageView.message.parentMessage.authorName" alt="Avatar"/>
<span class="o_MessageInReplyToView_wrapInner overflow-hidden">
<b class="o_MessageInReplyToView_author">@<t t-out="messageView.message.parentMessage.authorName"/></b>:
<span class="o_MessageInReplyToView_body ms-1 text-break">
<t t-if="hasBodyBackLink" t-out="messageView.message.parentMessage.prettyBodyAsMarkup"/>
<t t-if="hasAttachmentBackLink">
<span class="me-2 fst-italic">Click to see the attachments</span>
<i class="fa fa-image"/>
</t>
</span>
</t>
<t t-if="messageView.message.parentMessage.isEmpty">
<i class="o_MessageInReplyToView_deletedMessage text-muted ms-2">Original message was deleted</i>
</t>
</small>
</span>
</span>
<i t-if="messageView.message.parentMessage.isEmpty" class="o_MessageInReplyToView_deletedMessage text-muted ms-2">Original message was deleted</i>
</small>
</t>
</templates>
@@ -2,90 +2,74 @@
<templates xml:space="preserve">
<t t-name="mail.MessageListView" owl="1">
<t t-if="messageListView">
<div class="o_MessageListView bg-view d-flex flex-column overflow-auto" t-att-class="{ 'o-empty align-items-center justify-content-center': messageListView.threadViewOwner.messages.length === 0, 'pb-4': messageListView.threadViewOwner.messages.length !== 0 }" t-attf-class="{{ className }}" t-on-scroll="messageListView.onScroll" t-ref="root">
<!-- No result messages -->
<t t-if="messageListView.threadViewOwner.threadCache.orderedNonEmptyMessages.length === 0">
<div class="o_MessageListView_empty o_MessageListView_item d-flex flex-grow-1 flex-column align-items-center justify-content-center align-self-center w-100 h-100 p-4 text-center text-muted fst-italic">
<t t-if="messageListView.threadViewOwner.thread === messaging.inbox.thread">
<h4 class="o_MessageListView_emptyTitle mb-3 fw-bolder">
Congratulations, your inbox is empty
</h4>
New messages appear here.
</t>
<t t-elif="messageListView.threadViewOwner.thread === messaging.starred.thread">
<h4 class="o_MessageListView_emptyTitle mb-3 fw-bolder">
No starred messages
</h4>
You can mark any message as 'starred', and it shows up in this mailbox.
</t>
<t t-elif="messageListView.threadViewOwner.thread === messaging.history.thread">
<img src="/web/static/img/neutral_face.svg" alt="History"/>
<h4 class="o_MessageListView_emptyTitle mb-3 fw-bolder">
No history messages
</h4>
Messages marked as read will appear in the history.
</t>
<t t-else="">
There are no messages in this conversation.
</t>
</div>
<div class="o_MessageListView bg-view d-flex flex-column overflow-auto" t-att-class="{ 'o-empty align-items-center justify-content-center': messageListView.threadViewOwner.messages.length === 0, 'pb-4': messageListView.threadViewOwner.messages.length !== 0 }" t-attf-class="{{ className }}" t-on-scroll="messageListView.onScroll" t-ref="root">
<!-- No result messages -->
<div t-if="messageListView.threadViewOwner.threadCache.orderedNonEmptyMessages.length === 0" class="o_MessageListView_empty o_MessageListView_item d-flex flex-grow-1 flex-column align-items-center justify-content-center align-self-center w-100 h-100 p-4 text-center text-muted fst-italic">
<t t-if="messageListView.threadViewOwner.thread === messaging.inbox.thread">
<h4 class="o_MessageListView_emptyTitle mb-3 fw-bolder">
Congratulations, your inbox is empty
</h4>
New messages appear here.
</t>
<!-- LOADING (if order asc)-->
<t t-if="messageListView.threadViewOwner.threadCache.hasLoadingFailed">
<div class="o_MessageListView_alertLoadingFailed d-flex align-items-center alert alert-info">
<div>
An error occurred while fetching messages.
</div>
<button class="o_MessageListView_alertLoadingFailedRetryButton btn btn-link" t-on-click="messageListView.onClickRetryLoadMoreMessages">
Click here to retry
</button>
</div>
<t t-elif="messageListView.threadViewOwner.thread === messaging.starred.thread">
<h4 class="o_MessageListView_emptyTitle mb-3 fw-bolder">
No starred messages
</h4>
You can mark any message as 'starred', and it shows up in this mailbox.
</t>
<t t-if="!messageListView.threadViewOwner.threadCache.hasLoadingFailed and messageListView.threadViewOwner.order === 'asc'">
<t t-call="mail.MessageListView.loadMore"/>
<t t-elif="messageListView.threadViewOwner.thread === messaging.history.thread">
<img src="/web/static/img/neutral_face.svg" alt="History"/>
<h4 class="o_MessageListView_emptyTitle mb-3 fw-bolder">
No history messages
</h4>
Messages marked as read will appear in the history.
</t>
<div t-if="messageListView.threadViewOwner.order === 'asc' and messageListView.threadViewOwner.threadCache.orderedNonEmptyMessages.length !== 0 and !(messageListView.threadViewOwner.thread and messageListView.threadViewOwner.thread.mailbox)" class="flex-grow-1"/>
<!-- MESSAGES -->
<t t-set="current_day" t-value="0"/>
<t t-foreach="messageListView.messageListViewItems" t-as="messageListViewItem" t-key="messageListViewItem.localId">
<Transition visible="messageListViewItem.message === messageListView.threadViewOwner.thread.messageAfterNewMessageSeparator" name="'o-fade'" t-slot-scope="transition">
<div class="o_MessageListView_separator o_MessageListView_separatorNewMessages o_MessageListView_item d-flex flex-shrink-0 align-items-center me-4 p-0 fw-bolder" t-att-class="{ 'o-disable-animation': messaging.disableAnimation, 'opacity-0': transition.className.includes('o-fade-leave') }" t-attf-class="{{transition.className}}">
<hr class="o_MessageListView_separatorLine o_MessageListView_separatorLineNewMessages flex-grow-1 w-auto"/><span class="o_MessageListView_separatorLabel o_MessageListView_separatorLabelNewMessages px-3">New messages</span>
</div>
</Transition>
<t t-if="!messageListViewItem.message.isEmpty">
<t t-set="message_day" t-value="messageListViewItem.message.dateDay"/>
<t t-if="current_day !== message_day">
<div class="o_MessageListView_separator o_MessageListView_separatorDate o_MessageListView_item d-flex flex-shrink-0 align-items-center pt-4 pb-0 px-0 fw-bolder">
<hr class="o_MessageListView_separatorLine flex-grow-1 w-auto border-top"/><span class="o_MessageListView_separatorLabel o_MessageListView_separatorLabelDate px-3"><t t-esc="message_day"/></span><hr class="o_MessageListView_separatorLine flex-grow-1 w-auto border-top"/>
<t t-set="current_day" t-value="message_day"/>
</div>
</t>
<NotificationMessageView t-if="messageListViewItem.notificationMessageView" record="messageListViewItem.notificationMessageView"/>
<MessageView t-if="messageListViewItem.messageView" record="messageListViewItem.messageView"/>
</t>
</t>
<!-- LOADING (if order desc)-->
<t t-if="!messageListView.threadViewOwner.threadCache.hasLoadingFailed and messageListView.threadViewOwner.order === 'desc'">
<t t-call="mail.MessageListView.loadMore"/>
<t t-else="">
There are no messages in this conversation.
</t>
</div>
</t>
<!-- LOADING (if order asc)-->
<div t-if="messageListView.threadViewOwner.threadCache.hasLoadingFailed" class="o_MessageListView_alertLoadingFailed d-flex align-items-center alert alert-info">
<div>
An error occurred while fetching messages.
</div>
<button class="o_MessageListView_alertLoadingFailedRetryButton btn btn-link" t-on-click="messageListView.onClickRetryLoadMoreMessages">
Click here to retry
</button>
</div>
<t t-if="!messageListView.threadViewOwner.threadCache.hasLoadingFailed and messageListView.threadViewOwner.order === 'asc'" t-call="mail.MessageListView.loadMore"/>
<div t-if="messageListView.threadViewOwner.order === 'asc' and messageListView.threadViewOwner.threadCache.orderedNonEmptyMessages.length !== 0 and !(messageListView.threadViewOwner.thread and messageListView.threadViewOwner.thread.mailbox)" class="flex-grow-1"/>
<!-- MESSAGES -->
<t t-set="current_day" t-value="0"/>
<t t-foreach="messageListView.messageListViewItems" t-as="messageListViewItem" t-key="messageListViewItem.localId">
<Transition visible="messageListViewItem.message === messageListView.threadViewOwner.thread.messageAfterNewMessageSeparator" name="'o-fade'" t-slot-scope="transition">
<div class="o_MessageListView_separator o_MessageListView_separatorNewMessages o_MessageListView_item d-flex flex-shrink-0 align-items-center me-4 p-0 fw-bolder" t-att-class="{ 'o-disable-animation': messaging.disableAnimation, 'opacity-0': transition.className.includes('o-fade-leave') }" t-attf-class="{{transition.className}}">
<hr class="o_MessageListView_separatorLine o_MessageListView_separatorLineNewMessages flex-grow-1 w-auto"/><span class="o_MessageListView_separatorLabel o_MessageListView_separatorLabelNewMessages px-3">New messages</span>
</div>
</Transition>
<t t-if="!messageListViewItem.message.isEmpty">
<t t-set="message_day" t-value="messageListViewItem.message.dateDay"/>
<div t-if="current_day !== message_day" class="o_MessageListView_separator o_MessageListView_separatorDate o_MessageListView_item d-flex flex-shrink-0 align-items-center pt-4 pb-0 px-0 fw-bolder">
<hr class="o_MessageListView_separatorLine flex-grow-1 w-auto border-top"/><span class="o_MessageListView_separatorLabel o_MessageListView_separatorLabelDate px-3" t-esc="message_day"/><hr class="o_MessageListView_separatorLine flex-grow-1 w-auto border-top"/>
<t t-set="current_day" t-value="message_day"/>
</div>
<NotificationMessageView t-if="messageListViewItem.notificationMessageView" record="messageListViewItem.notificationMessageView"/>
<MessageView t-if="messageListViewItem.messageView" record="messageListViewItem.messageView"/>
</t>
</t>
<!-- LOADING (if order desc)-->
<t t-if="!messageListView.threadViewOwner.threadCache.hasLoadingFailed and messageListView.threadViewOwner.order === 'desc'" t-call="mail.MessageListView.loadMore"/>
</div>
</t>
<t t-name="mail.MessageListView.loadMore" owl="1">
<t t-if="messageListView.threadViewOwner.threadCache.isLoadingMore">
<div class="o_MessageListView_item o_MessageListView_isLoadingMore align-self-center">
<i class="o_MessageListView_isLoadingMoreIcon fa fa-spin fa-circle-o-notch me-1"/>
Loading...
</div>
</t>
<t t-elif="!messageListView.threadViewOwner.threadCache.isAllHistoryLoaded and !messageListView.threadViewOwner.thread.isTemporary">
<a class="o_MessageListView_item o_MessageListView_loadMore align-self-center" href="#" t-on-click="messageListView.onClickLoadMore" t-ref="loadMore">
Load more
</a>
</t>
<div t-if="messageListView.threadViewOwner.threadCache.isLoadingMore" class="o_MessageListView_item o_MessageListView_isLoadingMore align-self-center">
<i class="o_MessageListView_isLoadingMoreIcon fa fa-spin fa-circle-o-notch me-1"/>
Loading...
</div>
<a t-elif="!messageListView.threadViewOwner.threadCache.isAllHistoryLoaded and !messageListView.threadViewOwner.thread.isTemporary" class="o_MessageListView_item o_MessageListView_loadMore align-self-center" href="#" t-on-click="messageListView.onClickLoadMore" t-ref="loadMore">
Load more
</a>
</t>
</templates>
@@ -3,14 +3,10 @@
<t t-name="mail.MessageNotificationPopoverContentView" owl="1">
<div class="o_MessageNotificationPopoverContentView m-2" t-attf-class="{{ className }}" t-ref="root">
<t t-foreach="messageView.message.notifications" t-as="notification" t-key="notification.localId">
<div class="o_MessageNotificationPopoverContentView_notification">
<i class="o_MessageNotificationPopoverContentView_notificationIcon me-2" t-att-class="notification.iconClass" t-att-title="notification.iconTitle" role="img"/>
<t t-if="notification.partner">
<span class="o_MessageNotificationPopoverContentView_notificationPartnerName" t-esc="notification.partner.nameOrDisplayName"/>
</t>
</div>
</t>
<div t-foreach="messageView.message.notifications" t-as="notification" t-key="notification.localId" class="o_MessageNotificationPopoverContentView_notification">
<i class="o_MessageNotificationPopoverContentView_notificationIcon me-2" t-att-class="notification.iconClass" t-att-title="notification.iconTitle" role="img"/>
<span t-if="notification.partner" class="o_MessageNotificationPopoverContentView_notificationPartnerName" t-esc="notification.partner.nameOrDisplayName"/>
</div>
</div>
</t>
@@ -2,14 +2,10 @@
<templates xml:space="preserve">
<t t-name="mail.MessageReactionGroup" owl="1">
<button class="o_MessageReactionGroup btn d-flex p-0 border rounded-1" t-att-class="{'o-hasUserReacted border-primary': hasUserReacted, 'bg-view': !hasUserReacted}" t-attf-class="{{ className }}" t-att-title="summary" t-on-click="onClick" t-ref="root">
<span class="o_MessageReactionGroup_content mx-1">
<t t-esc="content"/>
</span>
<span class="o_MessageReactionGroup_count mx-1" t-att-class="{'o-hasUserReacted text-primary fw-bolder': hasUserReacted}">
<t t-esc="count"/>
</span>
</button>
<button class="o_MessageReactionGroup btn d-flex p-0 border rounded-1" t-att-class="{'o-hasUserReacted border-primary': hasUserReacted, 'bg-view': !hasUserReacted}" t-attf-class="{{ className }}" t-att-title="summary" t-on-click="onClick" t-ref="root">
<span class="o_MessageReactionGroup_content mx-1" t-esc="content"/>
<span class="o_MessageReactionGroup_count mx-1" t-att-class="{'o-hasUserReacted text-primary fw-bolder': hasUserReacted}" t-esc="count"/>
</button>
</t>
</templates>
@@ -2,17 +2,11 @@
<templates xml:space="preserve">
<t t-name="mail.MessageSeenIndicatorView" owl="1">
<t t-if="messageSeenIndicator">
<span class="o_MessageSeenIndicatorView position-relative d-flex opacity-75-hover opacity-50" t-att-class="{ 'o-all-seen text-odoo': messageSeenIndicator.hasEveryoneSeen }" t-attf-class="{{ className }}" t-att-title="messageSeenIndicator.text" t-ref="root">
<t t-if="!messageSeenIndicator.isMessagePreviousToLastCurrentPartnerMessageSeenByEveryone">
<t t-if="messageSeenIndicator.hasSomeoneFetched or messageSeenIndicator.hasSomeoneSeen">
<i class="o_MessageSeenIndicatorView_icon o-first fa fa-check ps-1"/>
</t>
<t t-if="messageSeenIndicator.hasSomeoneSeen">
<i class="o_MessageSeenIndicatorView_icon o-second fa fa-check position-absolute"/>
</t>
</t>
</span>
</t>
<span class="o_MessageSeenIndicatorView position-relative d-flex opacity-75-hover opacity-50" t-att-class="{ 'o-all-seen text-odoo': messageSeenIndicator.hasEveryoneSeen }" t-attf-class="{{ className }}" t-att-title="messageSeenIndicator.text" t-ref="root">
<t t-if="!messageSeenIndicator.isMessagePreviousToLastCurrentPartnerMessageSeenByEveryone">
<i t-if="messageSeenIndicator.hasSomeoneFetched or messageSeenIndicator.hasSomeoneSeen" class="o_MessageSeenIndicatorView_icon o-first fa fa-check ps-1"/>
<i t-if="messageSeenIndicator.hasSomeoneSeen" class="o_MessageSeenIndicatorView_icon o-second fa fa-check position-absolute"/>
</t>
</span>
</t>
</templates>
@@ -2,57 +2,35 @@
<templates xml:space="preserve">
<t t-name="mail.MessagingMenu" owl="1">
<t t-if="messagingMenu">
<div class="o_MessagingMenu dropdown" t-att-class="{ 'show bg-black-15': messagingMenu.isOpen, 'o-isDeviceSmall': messaging.device.isSmall }" t-attf-class="{{ className }}" t-ref="root">
<a class="o_MessagingMenu_toggler dropdown-toggle o-no-caret o-dropdown--narrow" t-att-class="{ 'o-no-notification': !messagingMenu.counter }" href="#" title="Conversations" role="button" t-att-aria-expanded="messagingMenu.isOpen ? 'true' : 'false'" aria-haspopup="true" t-on-click="messagingMenu.onClickToggler">
<i class="o_MessagingMenu_icon fa fa-lg fa-comments" role="img" aria-label="Messages"/>
<t t-if="!messaging.isInitialized">
<i class="o_MessagingMenu_loading fa fa-circle-o-notch fa-spin position-absolute bottom-50 end-0 small"/>
</t>
<t t-elif="messagingMenu.counter > 0">
<span class="o_MessagingMenu_counter badge">
<t t-esc="messagingMenu.counter"/>
</span>
</t>
</a>
<t t-if="messagingMenu.isOpen">
<div class="o_MessagingMenu_dropdownMenu o-dropdown-menu dropdown-menu-end d-flex flex-column mt-0 py-0 bg-view overflow-auto" t-att-class="{ 'o-isDeviceSmall position-fixed bottom-0 start-0 end-0 flex-grow-1 w-100 m-0 border-0': messaging.device.isSmall, 'border': !messaging.device.isSmall, 'o-messaging-not-initialized align-items-center justify-content-center': !messaging.isInitialized }" role="menu">
<t t-if="!messaging.isInitialized">
<span><i class="o_MessagingMenu_dropdownLoadingIcon fa fa-circle-o-notch fa-spin me-1"/>Please wait...</span>
</t>
<t t-else="">
<div class="o_MessagingMenu_dropdownMenuHeader border-bottom" t-attf-class="{{ messaging.device.isSmall ? 'o-isDeviceSmall p-2' : 'd-flex flex-shrink-0' }}">
<MessagingMenuTabView t-if="messagingMenu.allTab" record="messagingMenu.allTab"/>
<MessagingMenuTabView t-if="messagingMenu.chatTab" record="messagingMenu.chatTab"/>
<MessagingMenuTabView t-if="messagingMenu.channelTab" record="messagingMenu.channelTab"/>
<t t-if="messaging.device.isSmall">
<t t-call="mail.MessagingMenu.newMessageButton"/>
</t>
<div class="flex-grow-1"/>
<t t-if="!messaging.device.isSmall and !messaging.discuss.discussView">
<t t-call="mail.MessagingMenu.newMessageButton"/>
</t>
<t t-if="messagingMenu.mobileNewMessageAutocompleteInputView">
<AutocompleteInputView
className="'o_MessagingMenu_mobileNewMessageInput mt-2 p-2 rounded-3'"
record="messagingMenu.mobileNewMessageAutocompleteInputView"
/>
</t>
</div>
<t t-if="messagingMenu.notificationListView">
<NotificationListView className="'o_MessagingMenu_notificationList'" classNameObj="{ 'o-isDeviceSmall flex-grow-1 overflow-auto': messaging.device.isSmall }" record="messagingMenu.notificationListView"/>
</t>
<t t-if="messagingMenu.mobileMessagingNavbarView">
<MobileMessagingNavbarView
className="'o_MessagingMenu_mobileNavbar'"
record="messagingMenu.mobileMessagingNavbarView"
/>
</t>
</t>
<div class="o_MessagingMenu dropdown" t-att-class="{ 'show bg-black-15': messagingMenu.isOpen, 'o-isDeviceSmall': messaging.device.isSmall }" t-attf-class="{{ className }}" t-ref="root">
<a class="o_MessagingMenu_toggler dropdown-toggle o-no-caret o-dropdown--narrow" t-att-class="{ 'o-no-notification': !messagingMenu.counter }" href="#" title="Conversations" role="button" t-att-aria-expanded="messagingMenu.isOpen ? 'true' : 'false'" aria-haspopup="true" t-on-click="messagingMenu.onClickToggler">
<i class="o_MessagingMenu_icon fa fa-lg fa-comments" role="img" aria-label="Messages"/>
<i t-if="!messaging.isInitialized" class="o_MessagingMenu_loading fa fa-circle-o-notch fa-spin position-absolute bottom-50 end-0 small"/>
<span t-elif="messagingMenu.counter > 0" class="o_MessagingMenu_counter badge" t-esc="messagingMenu.counter"/>
</a>
<div t-if="messagingMenu.isOpen" class="o_MessagingMenu_dropdownMenu o-dropdown-menu dropdown-menu-end d-flex flex-column mt-0 py-0 bg-view overflow-auto" t-att-class="{ 'o-isDeviceSmall position-fixed bottom-0 start-0 end-0 flex-grow-1 w-100 m-0 border-0': messaging.device.isSmall, 'border': !messaging.device.isSmall, 'o-messaging-not-initialized align-items-center justify-content-center': !messaging.isInitialized }" role="menu">
<span t-if="!messaging.isInitialized"><i class="o_MessagingMenu_dropdownLoadingIcon fa fa-circle-o-notch fa-spin me-1"/>Please wait...</span>
<t t-else="">
<div class="o_MessagingMenu_dropdownMenuHeader border-bottom" t-attf-class="{{ messaging.device.isSmall ? 'o-isDeviceSmall p-2' : 'd-flex flex-shrink-0' }}">
<MessagingMenuTabView t-if="messagingMenu.allTab" record="messagingMenu.allTab"/>
<MessagingMenuTabView t-if="messagingMenu.chatTab" record="messagingMenu.chatTab"/>
<MessagingMenuTabView t-if="messagingMenu.channelTab" record="messagingMenu.channelTab"/>
<t t-if="messaging.device.isSmall" t-call="mail.MessagingMenu.newMessageButton"/>
<div class="flex-grow-1"/>
<t t-if="!messaging.device.isSmall and !messaging.discuss.discussView" t-call="mail.MessagingMenu.newMessageButton"/>
<AutocompleteInputView t-if="messagingMenu.mobileNewMessageAutocompleteInputView"
className="'o_MessagingMenu_mobileNewMessageInput mt-2 p-2 rounded-3'"
record="messagingMenu.mobileNewMessageAutocompleteInputView"
/>
</div>
<NotificationListView t-if="messagingMenu.notificationListView" className="'o_MessagingMenu_notificationList'" classNameObj="{ 'o-isDeviceSmall flex-grow-1 overflow-auto': messaging.device.isSmall }" record="messagingMenu.notificationListView"/>
<MobileMessagingNavbarView t-if="messagingMenu.mobileMessagingNavbarView"
className="'o_MessagingMenu_mobileNavbar'"
record="messagingMenu.mobileMessagingNavbarView"
/>
</t>
</div>
</t>
</div>
</t>
<t t-name="mail.MessagingMenu.newMessageButton" owl="1">
@@ -3,12 +3,8 @@
<t t-name="mail.MessagingMenuContainer" owl="1">
<div class="MessagingMenuContainer">
<t t-if="messaging and messaging.messagingMenu">
<MessagingMenu record="messaging.messagingMenu"/>
</t>
<t t-else="">
<i class="o_MessagingMenuContainer_spinner fa fa-circle-o-notch fa-spin mx-2" title="Please wait..."/>
</t>
<MessagingMenu t-if="messaging and messaging.messagingMenu" record="messaging.messagingMenu"/>
<i t-else="" class="o_MessagingMenuContainer_spinner fa fa-circle-o-notch fa-spin mx-2" title="Please wait..."/>
</div>
</t>
</templates>
@@ -2,9 +2,7 @@
<templates xml:space="preserve">
<t t-name="mail.MessagingMenuTabView" owl="1">
<button class="o_MessagingMenuTabView o-desktop btn btn-link" t-att-class="{ 'o-active fw-bolder': isActive, 'text-dark': !isActive }" t-on-click="onClick" type="button" role="tab" t-att-data-tab-id="id" t-attf-class="{{ className }}" t-ref="root">
<t t-out="name"/>
</button>
<button class="o_MessagingMenuTabView o-desktop btn btn-link" t-att-class="{ 'o-active fw-bolder': isActive, 'text-dark': !isActive }" t-on-click="onClick" type="button" role="tab" t-out="name" t-att-data-tab-id="id" t-attf-class="{{ className }}" t-ref="root"/>
</t>
</templates>
@@ -2,16 +2,12 @@
<templates xml:space="preserve">
<t t-name="mail.MobileMessagingNavbarView" owl="1">
<div class="o_MobileMessagingNavbarView d-flex flex-shrink-0 border-top bg-view shadow-lg" t-attf-class="{{ className }}" t-ref="root">
<t t-foreach="tabs" t-as="tab" t-key="tab.id">
<div class="o_MobileMessagingNavbarView_tab d-flex flex-column align-items-center flex-grow-1 p-2" t-att-class="{ 'o-active text-primary': activeTabId === tab.id, 'border-start': tab_index !== 0 }" t-on-click="ev => onClick(tab.id, ev)" t-att-data-tab-id="tab.id">
<t t-if="tab.icon">
<span class="o_MobileMessagingNavbarView_tabIcon fs-4" t-att-class="tab.icon"/>
</t>
<span class="o_MobileMessagingNavbarView_tabLabel small"><t t-esc="tab.label"/></span>
</div>
</t>
<div class="o_MobileMessagingNavbarView d-flex flex-shrink-0 border-top bg-view shadow-lg" t-attf-class="{{ className }}" t-ref="root">
<div t-foreach="tabs" t-as="tab" t-key="tab.id" class="o_MobileMessagingNavbarView_tab d-flex flex-column align-items-center flex-grow-1 p-2" t-att-class="{ 'o-active text-primary': activeTabId === tab.id, 'border-start': tab_index !== 0 }" t-on-click="ev => onClick(tab.id, ev)" t-att-data-tab-id="tab.id">
<span t-if="tab.icon" class="o_MobileMessagingNavbarView_tabIcon fs-4" t-att-class="tab.icon"/>
<span class="o_MobileMessagingNavbarView_tabLabel small" t-esc="tab.label"/>
</div>
</div>
</t>
</templates>
@@ -2,40 +2,32 @@
<templates xml:space="preserve">
<t t-name="mail.NotificationGroupView" owl="1">
<div class="o_NotificationListItem o_NotificationGroupView d-flex flex-shrink-0 align-items-center p-1 cursor-pointer" t-attf-class="{{ className }}" t-on-click="onClick" t-ref="root">
<div class="o_NotificationListItem_sidebar o_NotificationGroupView_sidebar m-1">
<div class="o_NotificationListItem_imageContainer o_NotificationGroupView_imageContainer o_NotificationGroupView_sidebarItem position-relative">
<img class="o_NotificationListItem_image o_NotificationGroupView_image w-100 h-100 rounded-circle" t-att-src="imageSrc" alt="Message delivery failure image"/>
</div>
</div>
<div class="o_NotificationListItem_content o_NotificationGroupView_content d-flex flex-column flex-grow-1 align-self-start m-2">
<div class="o_NotificationGroupView_header o_NotificationListItem_header d-flex">
<span class="o_NotificationListItem_name o_NotificationGroupView_name text-truncate fw-bold" t-att-class="{ 'o-mobile fs-5': messaging.device.isSmall }">
<t t-esc="notificationGroup.res_model_name"/>
</span>
<t t-if="notificationGroup.notifications.length > 1">
<span class="o_NotificationListItem_counter o_NotificationGroupView_counter mx-1 fw-bold">
(<t t-esc="notificationGroup.notifications.length"/>)
</span>
</t>
<span class="flex-grow-1"/>
<t t-if="notificationGroup.date">
<small class="o_NotificationListItem_date o_NotificationGroupView_date flex-shrink-0 text-500">
<t t-esc="notificationGroup.date.fromNow()"/>
</small>
</t>
</div>
<div class="o_NotificationGroupView_core d-flex align-items-baseline">
<span class="o_NotificationListItem_coreItem o_NotificationListItem_inlineText o_NotificationGroupView_coreItem o_NotificationGroupView_inlineText me-2 text-truncate">
<t t-if="notificationGroup.notification_type === 'email'">
An error occurred when sending an email.
</t>
</span>
<span class="flex-grow-1"/>
<span class="o_NotificationListItem_coreItem o_NotificationListItem_markAsRead o_NotificationGroupView_coreItem o_NotificationGroupView_markAsRead fa fa-check d-flex flex-shrink-0 ms-2 text-600 opacity-50 opacity-100-hover" title="Discard message delivery failures" t-on-click="onClickMarkAsRead" t-ref="markAsRead"/>
</div>
<div class="o_NotificationListItem o_NotificationGroupView d-flex flex-shrink-0 align-items-center p-1 cursor-pointer" t-attf-class="{{ className }}" t-on-click="onClick" t-ref="root">
<div class="o_NotificationListItem_sidebar o_NotificationGroupView_sidebar m-1">
<div class="o_NotificationListItem_imageContainer o_NotificationGroupView_imageContainer o_NotificationGroupView_sidebarItem position-relative">
<img class="o_NotificationListItem_image o_NotificationGroupView_image w-100 h-100 rounded-circle" t-att-src="imageSrc" alt="Message delivery failure image"/>
</div>
</div>
<div class="o_NotificationListItem_content o_NotificationGroupView_content d-flex flex-column flex-grow-1 align-self-start m-2">
<div class="o_NotificationGroupView_header o_NotificationListItem_header d-flex">
<span class="o_NotificationListItem_name o_NotificationGroupView_name text-truncate fw-bold" t-att-class="{ 'o-mobile fs-5': messaging.device.isSmall }" t-esc="notificationGroup.res_model_name"/>
<span t-if="notificationGroup.notifications.length > 1" class="o_NotificationListItem_counter o_NotificationGroupView_counter mx-1 fw-bold">
(<t t-esc="notificationGroup.notifications.length"/>)
</span>
<span class="flex-grow-1"/>
<small t-if="notificationGroup.date" class="o_NotificationListItem_date o_NotificationGroupView_date flex-shrink-0 text-500" t-esc="notificationGroup.date.fromNow()"/>
</div>
<div class="o_NotificationGroupView_core d-flex align-items-baseline">
<span class="o_NotificationListItem_coreItem o_NotificationListItem_inlineText o_NotificationGroupView_coreItem o_NotificationGroupView_inlineText me-2 text-truncate">
<t t-if="notificationGroup.notification_type === 'email'">
An error occurred when sending an email.
</t>
</span>
<span class="flex-grow-1"/>
<span class="o_NotificationListItem_coreItem o_NotificationListItem_markAsRead o_NotificationGroupView_coreItem o_NotificationGroupView_markAsRead fa fa-check d-flex flex-shrink-0 ms-2 text-600 opacity-50 opacity-100-hover" title="Discard message delivery failures" t-on-click="onClickMarkAsRead" t-ref="markAsRead"/>
</div>
</div>
</div>
</t>
</templates>
@@ -2,48 +2,42 @@
<templates xml:space="preserve">
<t t-name="mail.NotificationListView" owl="1">
<div class="o_NotificationListView d-flex flex-column overflow-auto" t-att-class="{ 'o-empty justify-content-center': notificationViews.length === 0 }" t-attf-class="{{ className }}" t-ref="root">
<t t-if="notificationViews.length === 0">
<div class="o_NotificationListView_noConversation d-flex align-items-center justify-content-center py-4 px-2 text-muted">
No conversation yet...
</div>
</t>
<t t-else="">
<t t-foreach="notificationViews" t-as="notificationView" t-key="notificationView.localId">
<t t-if="notificationView.constructor.name === 'ChannelPreviewView'">
<ChannelPreviewView
className="'o_NotificationListView_preview'"
classNameObj="{ 'o-isDeviceSmall p-2': messaging.device.isSmall }"
record="notificationView"
/>
</t>
<t t-if="notificationView.constructor.name === 'ThreadNeedactionPreviewView'">
<ThreadNeedactionPreviewView
className="'o_NotificationListView_preview'"
classNameObj="{ 'o-isDeviceSmall p-2': messaging.device.isSmall }"
record="notificationView"
/>
</t>
<t t-if="notificationView.constructor.name === 'NotificationGroupView'">
<NotificationGroupView
className="'o_NotificationListView_group'"
classNameObj="{ 'o-isDeviceSmall p-2': messaging.device.isSmall }"
record="notificationView"
/>
</t>
<t t-if="notificationView.constructor.name === 'NotificationRequestView'">
<NotificationRequestView
className="'o_NotificationListView_notificationRequest'"
classNameObj="{ 'o-isDeviceSmall p-2': messaging.device.isSmall }"
record="notificationView"
/>
</t>
<t t-if="!notificationView_last">
<div class="o_NotificationListView_separator flex-shrink-0 w-100 border-bottom"/>
</t>
</t>
</t>
<div class="o_NotificationListView d-flex flex-column overflow-auto" t-att-class="{ 'o-empty justify-content-center': notificationViews.length === 0 }" t-attf-class="{{ className }}" t-ref="root">
<div t-if="notificationViews.length === 0" class="o_NotificationListView_noConversation d-flex align-items-center justify-content-center py-4 px-2 text-muted">
No conversation yet...
</div>
<t t-else="">
<t t-foreach="notificationViews" t-as="notificationView" t-key="notificationView.localId">
<t t-if="notificationView.constructor.name === 'ChannelPreviewView'">
<ChannelPreviewView
className="'o_NotificationListView_preview'"
classNameObj="{ 'o-isDeviceSmall p-2': messaging.device.isSmall }"
record="notificationView"
/>
</t>
<t t-if="notificationView.constructor.name === 'ThreadNeedactionPreviewView'">
<ThreadNeedactionPreviewView
className="'o_NotificationListView_preview'"
classNameObj="{ 'o-isDeviceSmall p-2': messaging.device.isSmall }"
record="notificationView"
/>
</t>
<t t-if="notificationView.constructor.name === 'NotificationGroupView'">
<NotificationGroupView
className="'o_NotificationListView_group'"
classNameObj="{ 'o-isDeviceSmall p-2': messaging.device.isSmall }"
record="notificationView"
/>
</t>
<NotificationRequestView t-if="notificationView.constructor.name === 'NotificationRequestView'"
className="'o_NotificationListView_notificationRequest'"
classNameObj="{ 'o-isDeviceSmall p-2': messaging.device.isSmall }"
record="notificationView"
/>
<div t-if="!notificationView_last" class="o_NotificationListView_separator flex-shrink-0 w-100 border-bottom"/>
</t>
</t>
</div>
</t>
</templates>
@@ -2,31 +2,29 @@
<templates xml:space="preserve">
<t t-name="mail.NotificationRequestView" owl="1">
<div class="o_NotificationListItem o_NotificationRequestView d-flex flex-shrink-0 align-items-center p-1 cursor-pointer" t-attf-class="{{ className }}" t-on-click="onClick" t-ref="root">
<div class="o_NotificationListItem_sidebar o_NotificationRequestView_sidebar m-1">
<div class="o_NotificationListItem_imageContainer o_NotificationRequestView_imageContainer o_NotificationRequestView_sidebarItem position-relative">
<img class="o_NotificationListItem_image o_NotificationRequestView_image w-100 h-100 rounded-circle" t-att-src="messaging.partnerRoot.avatarUrl" alt="Avatar of OdooBot"/>
<PersonaImStatusIconView
t-if="personaImStatusIconView"
className="'o_NotificationListItem_personaImStatusIcon o_NotificationRequestView_personaImStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center'"
classNameObj="{ 'o-isDeviceSmall': messaging.device.isSmall, 'small': !messaging.device.isSmall }"
record="personaImStatusIconView"
/>
</div>
</div>
<div class="o_NotificationListItem_content o_NotificationRequestView_content d-flex flex-column flex-grow-1 align-self-start m-2">
<div class="o_NotificationListItem_header o_NotificationRequestView_header d-flex">
<span class="o_NotificationListItem_name o_NotificationRequestView_name text-truncate fw-bold" t-att-class="{ 'o-isDeviceSmall fs-5': messaging.device.isSmall }">
<t t-esc="headerText"/>
</span>
</div>
<div class="o_NotificationRequestView_core">
<span class="o_NotificationListItem_coreItem o_NotificationListItem_inlineText o_NotificationRequestView_coreItem o_NotificationRequestView_inlineText text-truncate">
Enable desktop notifications to chat.
</span>
</div>
<div class="o_NotificationListItem o_NotificationRequestView d-flex flex-shrink-0 align-items-center p-1 cursor-pointer" t-attf-class="{{ className }}" t-on-click="onClick" t-ref="root">
<div class="o_NotificationListItem_sidebar o_NotificationRequestView_sidebar m-1">
<div class="o_NotificationListItem_imageContainer o_NotificationRequestView_imageContainer o_NotificationRequestView_sidebarItem position-relative">
<img class="o_NotificationListItem_image o_NotificationRequestView_image w-100 h-100 rounded-circle" t-att-src="messaging.partnerRoot.avatarUrl" alt="Avatar of OdooBot"/>
<PersonaImStatusIconView
t-if="personaImStatusIconView"
className="'o_NotificationListItem_personaImStatusIcon o_NotificationRequestView_personaImStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center'"
classNameObj="{ 'o-isDeviceSmall': messaging.device.isSmall, 'small': !messaging.device.isSmall }"
record="personaImStatusIconView"
/>
</div>
</div>
<div class="o_NotificationListItem_content o_NotificationRequestView_content d-flex flex-column flex-grow-1 align-self-start m-2">
<div class="o_NotificationListItem_header o_NotificationRequestView_header d-flex">
<span class="o_NotificationListItem_name o_NotificationRequestView_name text-truncate fw-bold" t-att-class="{ 'o-isDeviceSmall fs-5': messaging.device.isSmall }" t-esc="headerText"/>
</div>
<div class="o_NotificationRequestView_core">
<span class="o_NotificationListItem_coreItem o_NotificationListItem_inlineText o_NotificationRequestView_coreItem o_NotificationRequestView_inlineText text-truncate">
Enable desktop notifications to chat.
</span>
</div>
</div>
</div>
</t>
</templates>
@@ -2,36 +2,28 @@
<templates xml:space="preserve">
<t t-name="mail.PersonaImStatusIconView" owl="1">
<span class="o_PersonaImStatusIconView d-flex flex-column fa-stack"
t-att-class="{
'o-away': persona.im_status === 'away',
'o-bot': messaging.partnerRoot.persona === persona,
'o-has-open-chat cursor-pointer': hasOpenChat,
'o-offline': persona.im_status === 'offline',
'o-online': persona.im_status === 'online',
}"
t-attf-class="{{ className }}"
t-on-click="onClick"
t-ref="root"
name="root"
>
<t t-if="hasBackground">
<i class="o_PersonaImStatusIconView_outerBackground fa fa-circle fa-stack-1x"/>
<i class="o_PersonaImStatusIconView_innerBackground fa fa-circle fa-stack-1x"/>
</t>
<t t-if="persona.im_status === 'online'">
<i class="o_PersonaImStatusIconView_icon o-online fa fa-circle fa-stack-1x text-primary" title="Online" role="img" aria-label="User is online"/>
</t>
<t t-if="persona.im_status === 'away'">
<i class="o_PersonaImStatusIconView_icon o-away fa fa-circle fa-stack-1x text-warning" title="Idle" role="img" aria-label="User is idle"/>
</t>
<t t-if="persona.im_status === 'offline'">
<i class="o_PersonaImStatusIconView_icon o-offline fa fa-circle-o fa-stack-1x text-700" title="Offline" role="img" aria-label="User is offline"/>
</t>
<t t-if="persona === messaging.partnerRoot.persona">
<i class="o_PersonaImStatusIconView_icon o-bot fa fa-heart fa-stack-1x text-primary" title="Bot" role="img" aria-label="User is a bot"/>
</t>
</span>
<span class="o_PersonaImStatusIconView d-flex flex-column fa-stack"
t-att-class="{
'o-away': persona.im_status === 'away',
'o-bot': messaging.partnerRoot.persona === persona,
'o-has-open-chat cursor-pointer': hasOpenChat,
'o-offline': persona.im_status === 'offline',
'o-online': persona.im_status === 'online',
}"
t-attf-class="{{ className }}"
t-on-click="onClick"
t-ref="root"
name="root"
>
<t t-if="hasBackground">
<i class="o_PersonaImStatusIconView_outerBackground fa fa-circle fa-stack-1x"/>
<i class="o_PersonaImStatusIconView_innerBackground fa fa-circle fa-stack-1x"/>
</t>
<i t-if="persona.im_status === 'online'" class="o_PersonaImStatusIconView_icon o-online fa fa-circle fa-stack-1x text-primary" title="Online" role="img" aria-label="User is online"/>
<i t-if="persona.im_status === 'away'" class="o_PersonaImStatusIconView_icon o-away fa fa-circle fa-stack-1x text-warning" title="Idle" role="img" aria-label="User is idle"/>
<i t-if="persona.im_status === 'offline'" class="o_PersonaImStatusIconView_icon o-offline fa fa-circle-o fa-stack-1x text-700" title="Offline" role="img" aria-label="User is offline"/>
<i t-if="persona === messaging.partnerRoot.persona" class="o_PersonaImStatusIconView_icon o-bot fa fa-heart fa-stack-1x text-primary" title="Bot" role="img" aria-label="User is a bot"/>
</span>
</t>
</templates>
@@ -3,12 +3,10 @@
<t t-name="mail.PopoverManager" owl="1">
<div class="o_PopoverManager" t-attf-class="{{ className }}" t-ref="root">
<t t-foreach="popoverManager.popoverViews" t-as="popoverView" t-key="popoverView.localId">
<PopoverView
className="'o_PopoverManager_popover'"
record="popoverView"
/>
</t>
<PopoverView t-foreach="popoverManager.popoverViews" t-as="popoverView" t-key="popoverView.localId"
className="'o_PopoverManager_popover'"
record="popoverView"
/>
</div>
</t>
@@ -2,13 +2,13 @@
<templates xml:space="preserve">
<t t-name="mail.PopoverView" owl="1">
<div class="o_PopoverView border bg-view shadow-sm" t-attf-class="{{ className }}" t-ref="root">
<t
t-component="constructor.components[contentComponentName]"
className="contentClassName"
t-props="{ record: content }"
/>
</div>
<div class="o_PopoverView border bg-view shadow-sm" t-attf-class="{{ className }}" t-ref="root">
<t
t-component="constructor.components[contentComponentName]"
className="contentClassName"
t-props="{ record: content }"
/>
</div>
</t>
</templates>
@@ -2,53 +2,31 @@
<templates xml:space="preserve">
<t t-name="mail.ThreadIconView" owl="1">
<div class="o_ThreadIconView d-flex justify-content-center flex-shrink-0" t-attf-class="{{ className }}" t-ref="root" name="root">
<t t-if="thread.channel and thread.channel.channel_type === 'channel'">
<t t-if="thread.authorizedGroupFullName">
<div class="o_ThreadIconView_groupRestrictedChannel fa fa-fw fa-hashtag" t-att-title="thread.accessRestrictedToGroupText"/>
</t>
<t t-if="!thread.authorizedGroupFullName">
<div class="o_ThreadIconView_publicChannel fa fa-fw fa-globe" title="Public Channel"/>
</t>
<div class="o_ThreadIconView d-flex justify-content-center flex-shrink-0" t-attf-class="{{ className }}" t-ref="root" name="root">
<t t-if="thread.channel and thread.channel.channel_type === 'channel'">
<div t-if="thread.authorizedGroupFullName" class="o_ThreadIconView_groupRestrictedChannel fa fa-fw fa-hashtag" t-att-title="thread.accessRestrictedToGroupText"/>
<div t-if="!thread.authorizedGroupFullName" class="o_ThreadIconView_publicChannel fa fa-fw fa-globe" title="Public Channel"/>
</t>
<t t-elif="thread.channel and thread.channel.channel_type === 'chat' and thread.channel.correspondent">
<ThreadTypingIconView t-if="threadTypingIconView"
className="'o_ThreadIconView_typing flex-grow-1'"
record="threadTypingIconView"
/>
<div t-elif="thread.channel.correspondent.im_status === 'online'" class="o_ThreadIconView_online fa fa-fw fa-circle" title="Online"/>
<div t-elif="thread.channel.correspondent.im_status === 'offline'" class="o_ThreadIconView_offline fa fa-fw fa-circle-o" title="Offline"/>
<div t-elif="thread.channel.correspondent.im_status === 'away'" class="o_ThreadIconView_away fa fa-fw fa-circle text-warning" title="Away"/>
<div t-elif="thread.channel.correspondent === messaging.partnerRoot" class="o_ThreadIconView_online fa fa-fw fa-heart" title="Bot"/>
<t t-else="" name="noImStatusCondition">
<div class="o_ThreadIconView_noImStatus fa fa-fw fa-question-circle" title="No IM status available"/>
</t>
<t t-elif="thread.channel and thread.channel.channel_type === 'chat' and thread.channel.correspondent">
<t t-if="threadTypingIconView">
<ThreadTypingIconView
className="'o_ThreadIconView_typing flex-grow-1'"
record="threadTypingIconView"
/>
</t>
<t t-elif="thread.channel.correspondent.im_status === 'online'">
<div class="o_ThreadIconView_online fa fa-fw fa-circle" title="Online"/>
</t>
<t t-elif="thread.channel.correspondent.im_status === 'offline'">
<div class="o_ThreadIconView_offline fa fa-fw fa-circle-o" title="Offline"/>
</t>
<t t-elif="thread.channel.correspondent.im_status === 'away'">
<div class="o_ThreadIconView_away fa fa-fw fa-circle text-warning" title="Away"/>
</t>
<t t-elif="thread.channel.correspondent === messaging.partnerRoot">
<div class="o_ThreadIconView_online fa fa-fw fa-heart" title="Bot"/>
</t>
<t t-else="" name="noImStatusCondition">
<div class="o_ThreadIconView_noImStatus fa fa-fw fa-question-circle" title="No IM status available"/>
</t>
</t>
<t t-elif="thread.channel and thread.channel.channel_type === 'group'">
<div class="o_ThreadIconView fa fa-fw fa-users" title="Grouped Chat"/>
</t>
<t t-elif="thread.mailbox">
<t t-if="thread.mailbox === messaging.inbox">
<div class="o_ThreadIconView_mailboxInbox fa fa-fw fa-inbox"/>
</t>
<t t-elif="thread.mailbox === messaging.starred">
<div class="o_ThreadIconView_mailboxStarred fa fa-fw fa-star-o"/>
</t>
<t t-elif="thread.mailbox === messaging.history">
<div class="o_ThreadIconView_mailboxHistory fa fa-fw fa-history"/>
</t>
</t>
</div>
</t>
<div t-elif="thread.channel and thread.channel.channel_type === 'group'" class="o_ThreadIconView fa fa-fw fa-users" title="Grouped Chat"/>
<t t-elif="thread.mailbox">
<div t-if="thread.mailbox === messaging.inbox" class="o_ThreadIconView_mailboxInbox fa fa-fw fa-inbox"/>
<div t-elif="thread.mailbox === messaging.starred" class="o_ThreadIconView_mailboxStarred fa fa-fw fa-star-o"/>
<div t-elif="thread.mailbox === messaging.history" class="o_ThreadIconView_mailboxHistory fa fa-fw fa-history"/>
</t>
</div>
</t>
</templates>
@@ -2,68 +2,54 @@
<templates xml:space="preserve">
<t t-name="mail.ThreadNeedactionPreviewView" owl="1">
<t t-if="threadNeedactionPreviewView">
<!--
The preview template is used by the discuss in mobile, and by the systray
menu in order to show preview of threads.
-->
<div class="o_NotificationListItem o_ThreadNeedactionPreviewView d-flex flex-shrink-0 align-items-center p-1 cursor-pointer"
t-attf-class="{{ className }}"
t-on-click="threadNeedactionPreviewView.onClick"
t-att-data-thread-id="threadNeedactionPreviewView.thread.id"
t-att-data-thread-model="threadNeedactionPreviewView.thread.model"
t-ref="root"
>
<div class="o_NotificationListItem_sidebar o_ThreadNeedactionPreviewView_sidebar m-1">
<div class="o_NotificationListItem_imageContainer o_ThreadNeedactionPreviewView_imageContainer o_ThreadNeedactionPreviewView_sidebarItem position-relative">
<img class="o_NotificationListItem_image o_ThreadNeedactionPreviewView_image w-100 h-100" t-att-src="image()" alt="Thread Image"/>
<t t-if="threadNeedactionPreviewView.personaImStatusIconView">
<PersonaImStatusIconView
className="'o_NotificationListItem_personaImStatusIcon o_ThreadNeedactionPreviewView_personaImStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center'"
classNameObj="{
'o-isDeviceSmall': messaging.device.isSmall,
'small': !messaging.device.isSmall,
}"
record="threadNeedactionPreviewView.personaImStatusIconView"
/>
</t>
</div>
</div>
<div class="o_NotificationListItem_content o_ThreadNeedactionPreviewView_content d-flex flex-column flex-grow-1 align-self-start m-2">
<div class="o_NotificationListItem_header o_ThreadNeedactionPreviewView_header d-flex">
<span class="o_NotificationListItem_name o_ThreadNeedactionPreviewView_name text-truncate fw-bold" t-att-class="{ 'o-isDeviceSmall fs-5': messaging.device.isSmall }">
<t t-esc="threadNeedactionPreviewView.thread.displayName"/>
</span>
<t t-if="threadNeedactionPreviewView.thread.needactionMessagesAsOriginThread.length > 1">
<span class="o_NotificationListItem_counter o_ThreadNeedactionPreviewView_counter mx-1 fw-bold">
(<t t-esc="threadNeedactionPreviewView.thread.needactionMessagesAsOriginThread.length"/>)
</span>
</t>
<span class="flex-grow-1"/>
<t t-if="threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread and threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread.date">
<small class="o_NotificationListItem_date o_ThreadNeedactionPreviewView_date flex-shrink-0 text-500">
<t t-esc="threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread.momentDate.fromNow()"/>
</small>
</t>
</div>
<div class="o_ThreadNeedactionPreviewView_core d-flex align-items-baseline">
<span class="o_NotificationListItem_coreItem o_NotificationListItem_inlineText o_ThreadNeedactionPreviewView_coreItem o_ThreadNeedactionPreviewView_inlineText me-2 text-truncate" t-att-class="{ 'o-empty': threadNeedactionPreviewView.isEmpty }">
<t t-if="threadNeedactionPreviewView.lastTrackingValue">
<TrackingValue value="threadNeedactionPreviewView.lastTrackingValue"/>
</t>
<t t-else="">
<t t-if="threadNeedactionPreviewView.messageAuthorPrefixView">
<MessageAuthorPrefixView record="threadNeedactionPreviewView.messageAuthorPrefixView"/>
</t>
<span class="o_ThreadNeedactionPreviewView_messageBody" t-esc="threadNeedactionPreviewView.inlineLastNeedactionMessageAsOriginThreadBody"/>
</t>
</span>
<span class="flex-grow-1"/>
<span class="o_NotificationListItem_coreItem o_NotificationListItem_markAsRead o_ThreadNeedactionPreviewView_coreItem o_ThreadNeedactionPreviewView_markAsRead fa fa-check d-flex flex-shrink-0 ms-2 text-600 opacity-50 opacity-100-hover" title="Mark as Read" t-on-click="threadNeedactionPreviewView.onClickMarkAsRead" t-ref="markAsRead"/>
</div>
<!--
The preview template is used by the discuss in mobile, and by the systray
menu in order to show preview of threads.
-->
<div class="o_NotificationListItem o_ThreadNeedactionPreviewView d-flex flex-shrink-0 align-items-center p-1 cursor-pointer"
t-attf-class="{{ className }}"
t-on-click="threadNeedactionPreviewView.onClick"
t-att-data-thread-id="threadNeedactionPreviewView.thread.id"
t-att-data-thread-model="threadNeedactionPreviewView.thread.model"
t-ref="root"
>
<div class="o_NotificationListItem_sidebar o_ThreadNeedactionPreviewView_sidebar m-1">
<div class="o_NotificationListItem_imageContainer o_ThreadNeedactionPreviewView_imageContainer o_ThreadNeedactionPreviewView_sidebarItem position-relative">
<img class="o_NotificationListItem_image o_ThreadNeedactionPreviewView_image w-100 h-100" t-att-src="image()" alt="Thread Image"/>
<PersonaImStatusIconView t-if="threadNeedactionPreviewView.personaImStatusIconView"
className="'o_NotificationListItem_personaImStatusIcon o_ThreadNeedactionPreviewView_personaImStatusIcon position-absolute bottom-0 end-0 d-flex align-items-center justify-content-center'"
classNameObj="{
'o-isDeviceSmall': messaging.device.isSmall,
'small': !messaging.device.isSmall,
}"
record="threadNeedactionPreviewView.personaImStatusIconView"
/>
</div>
</div>
</t>
<div class="o_NotificationListItem_content o_ThreadNeedactionPreviewView_content d-flex flex-column flex-grow-1 align-self-start m-2">
<div class="o_NotificationListItem_header o_ThreadNeedactionPreviewView_header d-flex">
<span class="o_NotificationListItem_name o_ThreadNeedactionPreviewView_name text-truncate fw-bold" t-att-class="{ 'o-isDeviceSmall fs-5': messaging.device.isSmall }" t-esc="threadNeedactionPreviewView.thread.displayName"/>
<span t-if="threadNeedactionPreviewView.thread.needactionMessagesAsOriginThread.length > 1" class="o_NotificationListItem_counter o_ThreadNeedactionPreviewView_counter mx-1 fw-bold">
(<t t-esc="threadNeedactionPreviewView.thread.needactionMessagesAsOriginThread.length"/>)
</span>
<span class="flex-grow-1"/>
<small t-if="threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread and threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread.date" class="o_NotificationListItem_date o_ThreadNeedactionPreviewView_date flex-shrink-0 text-500">
<t t-esc="threadNeedactionPreviewView.thread.lastNeedactionMessageAsOriginThread.momentDate.fromNow()"/>
</small>
</div>
<div class="o_ThreadNeedactionPreviewView_core d-flex align-items-baseline">
<span class="o_NotificationListItem_coreItem o_NotificationListItem_inlineText o_ThreadNeedactionPreviewView_coreItem o_ThreadNeedactionPreviewView_inlineText me-2 text-truncate" t-att-class="{ 'o-empty': threadNeedactionPreviewView.isEmpty }">
<TrackingValue t-if="threadNeedactionPreviewView.lastTrackingValue" value="threadNeedactionPreviewView.lastTrackingValue"/>
<t t-else="">
<MessageAuthorPrefixView t-if="threadNeedactionPreviewView.messageAuthorPrefixView" record="threadNeedactionPreviewView.messageAuthorPrefixView"/>
<span class="o_ThreadNeedactionPreviewView_messageBody" t-esc="threadNeedactionPreviewView.inlineLastNeedactionMessageAsOriginThreadBody"/>
</t>
</span>
<span class="flex-grow-1"/>
<span class="o_NotificationListItem_coreItem o_NotificationListItem_markAsRead o_ThreadNeedactionPreviewView_coreItem o_ThreadNeedactionPreviewView_markAsRead fa fa-check d-flex flex-shrink-0 ms-2 text-600 opacity-50 opacity-100-hover" title="Mark as Read" t-on-click="threadNeedactionPreviewView.onClickMarkAsRead" t-ref="markAsRead"/>
</div>
</div>
</div>
</t>
</templates>
@@ -2,13 +2,13 @@
<templates xml:space="preserve">
<t t-name="mail.ThreadTextualTypingStatusView" owl="1">
<div class="o_ThreadTextualTypingStatusView d-flex" t-attf-class="{{ className }}" t-ref="root">
<t t-if="threadTypingIconView">
<ThreadTypingIconView record="threadTypingIconView"/>
<span class="o_ThreadTextualTypingStatusView_separator ms-1"/>
<span class="text-truncate" t-esc="thread.typingStatusText"/>
</t>
</div>
<div class="o_ThreadTextualTypingStatusView d-flex" t-attf-class="{{ className }}" t-ref="root">
<t t-if="threadTypingIconView">
<ThreadTypingIconView record="threadTypingIconView"/>
<span class="o_ThreadTextualTypingStatusView_separator ms-1"/>
<span class="text-truncate" t-esc="thread.typingStatusText"/>
</t>
</div>
</t>
</templates>
@@ -2,62 +2,46 @@
<templates xml:space="preserve">
<t t-name="mail.ThreadView" owl="1">
<div class="o_ThreadView position-relative d-flex flex-column bg-100"
t-att-class="extraClass"
t-attf-class="{{ className }}"
t-att-data-correspondent-id="thread.channel and thread.channel.correspondent and thread.channel.correspondent.id"
t-att-data-thread-id="thread and thread.id"
t-att-data-thread-model="thread and thread.model"
t-on-focusin="onFocusin"
t-ref="root"
>
<t t-if="topbar">
<ThreadViewTopbar className="'border-bottom'" record="topbar"/>
</t>
<div class="o_ThreadView_bottomPart d-flex flex-grow-1" t-att-class="{ 'border-start border-end': threadViewer.chatWindow }">
<div class="o_ThreadView_core d-flex flex-column flex-grow-1">
<t t-if="callView">
<CallView record="callView"/>
</t>
<t t-if="isLoading and !threadCache.isLoaded" name="loadingCondition">
<div class="o_ThreadView_loading d-flex align-self-center flex-grow-1 align-items-center">
<span><i class="o_ThreadView_loadingIcon fa fa-circle-o-notch fa-spin me-1" title="Loading..." role="img"/>Loading...</span>
</div>
</t>
<t t-elif="messageListView">
<MessageListView
className="'o_ThreadView_messageList flex-grow-1'"
record="messageListView"
/>
</t>
<t t-elif="threadCache.hasLoadingFailed">
<div class="o_ThreadView_loadingFailed d-flex flex-grow-1 align-items-center justify-content-center flex-column">
<div class="o_ThreadView_loadingFailedText">
An error occurred while fetching messages.
</div>
<button class="o_ThreadView_loadingFailedRetryButton btn btn-link" t-on-click="onClickRetryLoadMessages">
Click here to retry
</button>
</div>
</t>
<t t-elif="composerView">
<div class="flex-grow-1"/>
</t>
<t t-if="composerView">
<ComposerView
className="'o_ThreadView_composer flex-shrink-0'"
record="composerView"
/>
</t>
<div class="o_ThreadView position-relative d-flex flex-column bg-100"
t-att-class="extraClass"
t-attf-class="{{ className }}"
t-att-data-correspondent-id="thread.channel and thread.channel.correspondent and thread.channel.correspondent.id"
t-att-data-thread-id="thread and thread.id"
t-att-data-thread-model="thread and thread.model"
t-on-focusin="onFocusin"
t-ref="root"
>
<ThreadViewTopbar t-if="topbar" className="'border-bottom'" record="topbar"/>
<div class="o_ThreadView_bottomPart d-flex flex-grow-1" t-att-class="{ 'border-start border-end': threadViewer.chatWindow }">
<div class="o_ThreadView_core d-flex flex-column flex-grow-1">
<CallView t-if="callView" record="callView"/>
<t t-if="isLoading and !threadCache.isLoaded" name="loadingCondition">
<div class="o_ThreadView_loading d-flex align-self-center flex-grow-1 align-items-center">
<span><i class="o_ThreadView_loadingIcon fa fa-circle-o-notch fa-spin me-1" title="Loading..." role="img"/>Loading...</span>
</div>
</t>
<MessageListView t-elif="messageListView"
className="'o_ThreadView_messageList flex-grow-1'"
record="messageListView"
/>
<div t-elif="threadCache.hasLoadingFailed" class="o_ThreadView_loadingFailed d-flex flex-grow-1 align-items-center justify-content-center flex-column">
<div class="o_ThreadView_loadingFailedText">
An error occurred while fetching messages.
</div>
<button class="o_ThreadView_loadingFailedRetryButton btn btn-link" t-on-click="onClickRetryLoadMessages">
Click here to retry
</button>
</div>
<t t-if="channelMemberListView">
<ChannelMemberListView className="'o_ThreadView_channelMemberList flex-shrink-0 border-start'" record="channelMemberListView"/>
</t>
<t t-if="isCallSettingsMenuOpen">
<CallSettingsMenu className="'o_ThreadView_callSettingsMenu flex-shrink-0 border-start'" record="callSettingsMenu"/>
</t>
<div t-elif="composerView" class="flex-grow-1"/>
<ComposerView t-if="composerView"
className="'o_ThreadView_composer flex-shrink-0'"
record="composerView"
/>
</div>
<ChannelMemberListView t-if="channelMemberListView" className="'o_ThreadView_channelMemberList flex-shrink-0 border-start'" record="channelMemberListView"/>
<CallSettingsMenu t-if="isCallSettingsMenuOpen" className="'o_ThreadView_callSettingsMenu flex-shrink-0 border-start'" record="callSettingsMenu"/>
</div>
</div>
</t>
</templates>
@@ -2,101 +2,61 @@
<templates xml:space="preserve">
<t t-name="mail.ThreadViewTopbar" owl="1">
<div class="o_ThreadViewTopbar d-flex flex-shrink-0 w-100 px-3 bg-100" t-attf-class="{{ className }}" t-ref="root">
<t t-if="threadIconView">
<ThreadIconView className="'o_ThreadViewTopbar_threadIcon me-2 align-self-center'" record="threadIconView"/>
<div class="o_ThreadViewTopbar d-flex flex-shrink-0 w-100 px-3 bg-100" t-attf-class="{{ className }}" t-ref="root">
<ThreadIconView t-if="threadIconView" className="'o_ThreadViewTopbar_threadIcon me-2 align-self-center'" record="threadIconView"/>
<div class="o_ThreadViewTopbar_title d-flex flex-grow-1 align-self-center align-items-center">
<t t-if="thread">
<div t-if="!isEditingThreadName" class="o_ThreadViewTopbar_threadName o_ThreadViewTopbar_editableItem lead flex-shrink-0 px-1 border text-truncate fw-bold" t-att-title="thread.displayName" t-on-click="onClickTopbarThreadName" t-on-mouseenter="onMouseEnterTopbarThreadName" t-on-mouseleave="onMouseLeaveTopbarThreadName" t-attf-class="{{ isMouseOverThreadName and !messaging.isCurrentUserGuest ? 'o-threadNameEditable bg-view' : 'border-light' }}" t-esc="thread.displayName"/>
<input t-if="isEditingThreadName" class="o_ThreadViewTopbar_threadNameInput form-control lead fw-bold" type="text" t-att-value="pendingThreadName" t-on-input="onInputThreadNameInput" t-on-keydown="onKeyDownThreadNameInput" t-ref="threadNameInput"/>
</t>
<div class="o_ThreadViewTopbar_title d-flex flex-grow-1 align-self-center align-items-center">
<t t-if="thread">
<t t-if="!isEditingThreadName">
<div class="o_ThreadViewTopbar_threadName o_ThreadViewTopbar_editableItem lead flex-shrink-0 px-1 border text-truncate fw-bold" t-att-title="thread.displayName" t-on-click="onClickTopbarThreadName" t-on-mouseenter="onMouseEnterTopbarThreadName" t-on-mouseleave="onMouseLeaveTopbarThreadName" t-attf-class="{{ isMouseOverThreadName and !messaging.isCurrentUserGuest ? 'o-threadNameEditable bg-view' : 'border-light' }}">
<t t-esc="thread.displayName"/>
</div>
</t>
<t t-if="isEditingThreadName">
<input class="o_ThreadViewTopbar_threadNameInput form-control lead fw-bold" type="text" t-att-value="pendingThreadName" t-on-input="onInputThreadNameInput" t-on-keydown="onKeyDownThreadNameInput" t-ref="threadNameInput"/>
</t>
</t>
<t t-if="!thread">
<div class="o_ThreadViewTopbar_threadName lead flex-shrink-0 px-1 text-truncate fw-bold">
Discuss
<div t-if="!thread" class="o_ThreadViewTopbar_threadName lead flex-shrink-0 px-1 text-truncate fw-bold">
Discuss
</div>
<t t-if="hasDescriptionArea">
<div class="o_ThreadViewTopbar_threadDescriptionSeparator flex-shrink-0 mx-2 py-2 border-start"/>
<t t-if="!isEditingThreadDescription">
<div t-if="thread.description" class="o_ThreadViewTopbar_threadDescription o_ThreadViewTopbar_editableItem px-1 border text-truncate" t-att-title="thread.description" t-on-click="onClickTopbarThreadDescription" t-on-mouseenter="onMouseEnterTopbarThreadDescription" t-on-mouseleave="onMouseLeaveTopbarThreadDescription" t-attf-class="{{ isDescriptionHighlighted ? 'o-threadDescriptionEditable bg-view' : 'border-light' }}" t-esc="thread.description"/>
<div t-if="!thread.description" class="o_ThreadViewTopbar_threadAddDescriptionEmptyLabel text-truncate text-900 opacity-50 opacity-100-hover cursor-pointer" t-on-click="onClickTopbarThreadDescription">
Add a description
</div>
</t>
<t t-if="hasDescriptionArea">
<div class="o_ThreadViewTopbar_threadDescriptionSeparator flex-shrink-0 mx-2 py-2 border-start"/>
<t t-if="!isEditingThreadDescription">
<t t-if="thread.description">
<div class="o_ThreadViewTopbar_threadDescription o_ThreadViewTopbar_editableItem px-1 border text-truncate" t-att-title="thread.description" t-on-click="onClickTopbarThreadDescription" t-on-mouseenter="onMouseEnterTopbarThreadDescription" t-on-mouseleave="onMouseLeaveTopbarThreadDescription" t-attf-class="{{ isDescriptionHighlighted ? 'o-threadDescriptionEditable bg-view' : 'border-light' }}">
<t t-esc="thread.description"/>
</div>
</t>
<t t-if="!thread.description">
<div class="o_ThreadViewTopbar_threadAddDescriptionEmptyLabel text-truncate text-900 opacity-50 opacity-100-hover cursor-pointer" t-on-click="onClickTopbarThreadDescription">
Add a description
</div>
</t>
</t>
<t t-if="isEditingThreadDescription">
<input class="o_ThreadViewTopbar_threadDescriptionInput form-control" type="text" t-att-value="pendingThreadDescription" t-on-input="onInputThreadDescriptionInput" t-on-keydown="onKeyDownThreadDescriptionInput" t-ref="threadDescriptionInput"/>
</t>
</t>
</div>
<div class="o_ThreadViewTopbar_actions d-flex align-items-center ms-1">
<t t-if="thread and thread === messaging.inbox.thread">
<button class="o_ThreadViewTopbar_markAllReadButton btn btn-secondary" t-att-disabled="threadView.messages.length === 0" t-on-click="onClickInboxMarkAllAsRead">Mark all read</button>
</t>
<t t-if="thread and thread === messaging.starred.thread">
<button class="o_ThreadViewTopbar_unstarAllButton btn btn-secondary" t-att-disabled="threadView.messages.length === 0" t-on-click="onClickUnstarAll">Unstar all</button>
</t>
<t t-if="thread and thread.hasCallFeature and thread.rtcSessions.length === 0">
<button class="o_ThreadViewTopbar_callButton o_ThreadViewTopbar_button btn px-2 border-none rounded shadow-none" t-att-disabled="thread.hasPendingRtcRequest" title="Start a Call" t-on-click="onClickPhone">
<i class="fa fa-lg fa-phone text-700"/>
</button>
<button class="o_ThreadViewTopbar_callButton o_ThreadViewTopbar_button btn px-2 border-none rounded shadow-none" t-att-disabled="thread.hasPendingRtcRequest" title="Start a Video Call" t-on-click="onClickCamera">
<i class="fa fa-lg fa-video-camera text-700"/>
</button>
</t>
<t t-if="thread and thread.hasInviteFeature">
<button class="o_ThreadViewTopbar_inviteButton o_ThreadViewTopbar_button btn px-2 border-none rounded shadow-none" t-attf-class="{{ invitePopoverView ? 'o-isActive' : '' }}" title="Add users" t-on-click="onClickInviteButton" t-ref="inviteButton">
<i class="fa fa-lg fa-user-plus text-700"/>
</button>
</t>
<!-- FIXME: guests should be able to see members but there currently is no route for it, so hide it for now -->
<t t-if="!messaging.isCurrentUserGuest and thread and thread.hasMemberListFeature and threadView.hasMemberList and !threadView.isMemberListOpened">
<button class="o_ThreadViewTopbar_showMemberListButton o_ThreadViewTopbar_button btn px-2 border-none rounded shadow-none" title="Show Member List" t-on-click="onClickShowMemberList">
<i class="fa fa-lg fa-users text-700"/>
</button>
</t>
<t t-if="thread and thread.hasMemberListFeature and threadView.hasMemberList and threadView.isMemberListOpened">
<button class="o_ThreadViewTopbar_hideMemberListButton o_ThreadViewTopbar_button o-isActive btn px-2 border-none rounded shadow-none" title="Hide Member List" t-on-click="onClickHideMemberList">
<i class="fa fa-lg fa-users text-700"/>
</button>
</t>
<t t-if="thread and thread.hasCallFeature and !threadView.isCallSettingsMenuOpen">
<button class="o_ThreadViewTopbar_openCallSettingsButton o_ThreadViewTopbar_button btn px-2 border-none rounded shadow-none" title="Show Call Settings" t-on-click="onClickShowCallSettingsMenu">
<i class="fa fa-lg fa-gear text-700"/>
</button>
</t>
<t t-if="thread and thread.hasCallFeature and threadView.isCallSettingsMenuOpen">
<button class="o_ThreadViewTopbar_button o-isActive btn px-2 border-none rounded shadow-none" title="Hide Call Settings" t-on-click="onClickHideCallSettingsMenu">
<i class="fa fa-lg fa-gear text-700"/>
</button>
</t>
</div>
<!-- FIXME: handle display on mobile -->
<t t-if="threadView.threadViewer.discussPublicView and !messaging.device.isSmall">
<div class="o_ThreadViewTopbar_userInfo d-flex align-items-center">
<img class="o_ThreadViewTopbar_avatar mx-1 rounded-circle o_object_fit_cover" t-att-src="avatarUrl" alt="Avatar"/>
<t t-if="!isEditingGuestName">
<span class="o_ThreadViewTopbar_userName o_ThreadViewTopbar_editableItem px-1 border fw-bold text-truncate" t-attf-class="{{ isMouseOverUserName and messaging.isCurrentUserGuest ? 'o-userNameEditable bg-view' : 'border-light' }}" t-on-click="onClickUserName" t-on-mouseenter="onMouseEnterUserName" t-on-mouseleave="onMouseLeaveUserName">
<t t-esc="messaging.isCurrentUserGuest ? messaging.currentGuest.name : messaging.currentUser.nameOrDisplayName"/>
</span>
</t>
<t t-if="isEditingGuestName">
<input class="o_ThreadViewTopbar_guestNameInput form-control" type="text" t-att-value="messaging.currentGuest.name" t-on-input="onInputGuestNameInput" t-on-keydown="onKeyDownGuestNameInput" t-ref="guestNameInput"/>
</t>
</div>
<input t-if="isEditingThreadDescription" class="o_ThreadViewTopbar_threadDescriptionInput form-control" type="text" t-att-value="pendingThreadDescription" t-on-input="onInputThreadDescriptionInput" t-on-keydown="onKeyDownThreadDescriptionInput" t-ref="threadDescriptionInput"/>
</t>
</div>
<div class="o_ThreadViewTopbar_actions d-flex align-items-center ms-1">
<button t-if="thread and thread === messaging.inbox.thread" class="o_ThreadViewTopbar_markAllReadButton btn btn-secondary" t-att-disabled="threadView.messages.length === 0" t-on-click="onClickInboxMarkAllAsRead">Mark all read</button>
<button t-if="thread and thread === messaging.starred.thread" class="o_ThreadViewTopbar_unstarAllButton btn btn-secondary" t-att-disabled="threadView.messages.length === 0" t-on-click="onClickUnstarAll">Unstar all</button>
<t t-if="thread and thread.hasCallFeature and thread.rtcSessions.length === 0">
<button class="o_ThreadViewTopbar_callButton o_ThreadViewTopbar_button btn px-2 border-none rounded shadow-none" t-att-disabled="thread.hasPendingRtcRequest" title="Start a Call" t-on-click="onClickPhone">
<i class="fa fa-lg fa-phone text-700"/>
</button>
<button class="o_ThreadViewTopbar_callButton o_ThreadViewTopbar_button btn px-2 border-none rounded shadow-none" t-att-disabled="thread.hasPendingRtcRequest" title="Start a Video Call" t-on-click="onClickCamera">
<i class="fa fa-lg fa-video-camera text-700"/>
</button>
</t>
<button t-if="thread and thread.hasInviteFeature" class="o_ThreadViewTopbar_inviteButton o_ThreadViewTopbar_button btn px-2 border-none rounded shadow-none" t-attf-class="{{ invitePopoverView ? 'o-isActive' : '' }}" title="Add users" t-on-click="onClickInviteButton" t-ref="inviteButton">
<i class="fa fa-lg fa-user-plus text-700"/>
</button>
<!-- FIXME: guests should be able to see members but there currently is no route for it, so hide it for now -->
<button t-if="!messaging.isCurrentUserGuest and thread and thread.hasMemberListFeature and threadView.hasMemberList and !threadView.isMemberListOpened" class="o_ThreadViewTopbar_showMemberListButton o_ThreadViewTopbar_button btn px-2 border-none rounded shadow-none" title="Show Member List" t-on-click="onClickShowMemberList">
<i class="fa fa-lg fa-users text-700"/>
</button>
<button t-if="thread and thread.hasMemberListFeature and threadView.hasMemberList and threadView.isMemberListOpened" class="o_ThreadViewTopbar_hideMemberListButton o_ThreadViewTopbar_button o-isActive btn px-2 border-none rounded shadow-none" title="Hide Member List" t-on-click="onClickHideMemberList">
<i class="fa fa-lg fa-users text-700"/>
</button>
<button t-if="thread and thread.hasCallFeature and !threadView.isCallSettingsMenuOpen" class="o_ThreadViewTopbar_openCallSettingsButton o_ThreadViewTopbar_button btn px-2 border-none rounded shadow-none" title="Show Call Settings" t-on-click="onClickShowCallSettingsMenu">
<i class="fa fa-lg fa-gear text-700"/>
</button>
<button t-if="thread and thread.hasCallFeature and threadView.isCallSettingsMenuOpen" class="o_ThreadViewTopbar_button o-isActive btn px-2 border-none rounded shadow-none" title="Hide Call Settings" t-on-click="onClickHideCallSettingsMenu">
<i class="fa fa-lg fa-gear text-700"/>
</button>
</div>
<!-- FIXME: handle display on mobile -->
<div t-if="threadView.threadViewer.discussPublicView and !messaging.device.isSmall" class="o_ThreadViewTopbar_userInfo d-flex align-items-center">
<img class="o_ThreadViewTopbar_avatar mx-1 rounded-circle o_object_fit_cover" t-att-src="avatarUrl" alt="Avatar"/>
<span t-if="!isEditingGuestName" class="o_ThreadViewTopbar_userName o_ThreadViewTopbar_editableItem px-1 border fw-bold text-truncate" t-attf-class="{{ isMouseOverUserName and messaging.isCurrentUserGuest ? 'o-userNameEditable bg-view' : 'border-light' }}" t-esc="messaging.isCurrentUserGuest ? messaging.currentGuest.name : messaging.currentUser.nameOrDisplayName" t-on-click="onClickUserName" t-on-mouseenter="onMouseEnterUserName" t-on-mouseleave="onMouseLeaveUserName"/>
<input t-if="isEditingGuestName" class="o_ThreadViewTopbar_guestNameInput form-control" type="text" t-att-value="messaging.currentGuest.name" t-on-input="onInputGuestNameInput" t-on-keydown="onKeyDownGuestNameInput" t-ref="guestNameInput"/>
</div>
</div>
</t>
</templates>
@@ -3,9 +3,7 @@
<t t-name="mail.WebClientViewAttachmentView" owl="1">
<t t-if="webClientViewAttachmentView.thread.mainAttachment">
<t t-if="!webClientViewAttachmentView.thread.mainAttachment.isPdf">
<h3 class="mt0 mb8 ps-2 text-muted float-end"><t t-esc="webClientViewAttachmentView.thread.mainAttachment.filename"/></h3>
</t>
<h3 t-if="!webClientViewAttachmentView.thread.mainAttachment.isPdf" class="mt0 mb8 ps-2 text-muted float-end"><t t-esc="webClientViewAttachmentView.thread.mainAttachment.filename"/></h3>
<div t-if="webClientViewAttachmentView.thread.mainAttachment.isImage" class="o_attachment_preview_img">
<img id="attachment_img" class="img img-fluid d-block" t-attf-src="/web/image/#{webClientViewAttachmentView.thread.mainAttachment.id}?unique=1"/>
</div>
@@ -2,11 +2,9 @@
<templates xml:space="preserve">
<t t-name="mail.WebClientViewAttachmentViewContainer" owl="1">
<t t-if="webClientViewAttachmentView and webClientViewAttachmentView.thread.attachmentsInWebClientView.length > 0">
<div class="o_attachment_preview_container">
<WebClientViewAttachmentView record="webClientViewAttachmentView"/>
</div>
</t>
<div t-if="webClientViewAttachmentView and webClientViewAttachmentView.thread.attachmentsInWebClientView.length > 0" class="o_attachment_preview_container">
<WebClientViewAttachmentView record="webClientViewAttachmentView"/>
</div>
</t>
</templates>
@@ -2,28 +2,26 @@
<templates xml:space="preserve">
<t t-name="mail.WelcomeView" owl="1">
<div class="o_WelcomeView h-100 d-flex flex-column justify-content-center align-items-center bg-light" t-attf-class="{{ className }}" t-ref="root">
<h1 class="fw-light">
<span t-if="callDemoView">You've been invited to a meeting!</span>
<span t-if="!callDemoView">You've been invited to a chat!</span>
</h1>
<h2 class="m-5" t-esc="messaging.companyName"/>
<div class="d-flex justify-content-center">
<CallDemoView t-if="callDemoView" className="'me-5'" record="callDemoView"/>
<div class="d-flex flex-column justify-content-center">
<t t-if="messaging.currentGuest">
<label class="o_WelcomeView_guestNameInputLabel text-center fs-4" t-att-for="guestNameInputUniqueId">What's your name?</label>
<input class="form-control mb-3" type="text" placeholder="Your name" t-att-name="guestNameInputUniqueId" t-att-id="guestNameInputUniqueId" t-att-value="pendingGuestName" t-ref="guestNameInput" t-on-input="onInputGuestNameInput" t-on-keydown="onKeydownGuestNameInput"/>
</t>
<t t-if="messaging.currentUser">
<p class="o_WelcomeView_loggedAsStatus fs-4">Logged as <span t-esc="messaging.currentUser.nameOrDisplayName"/></p>
</t>
<button class="o_WelcomeView_joinButton btn btn-success fa-stack align-self-end p-0 rounded-circle fs-1 shadow" title="Join Channel" t-att-disabled="isJoinButtonDisabled" t-on-click="onClickJoinButton">
<i class="fa fa-phone fa-stack"/>
</button>
</div>
<div class="o_WelcomeView h-100 d-flex flex-column justify-content-center align-items-center bg-light" t-attf-class="{{ className }}" t-ref="root">
<h1 class="fw-light">
<span t-if="callDemoView">You've been invited to a meeting!</span>
<span t-if="!callDemoView">You've been invited to a chat!</span>
</h1>
<h2 class="m-5" t-esc="messaging.companyName"/>
<div class="d-flex justify-content-center">
<CallDemoView t-if="callDemoView" className="'me-5'" record="callDemoView"/>
<div class="d-flex flex-column justify-content-center">
<t t-if="messaging.currentGuest">
<label class="o_WelcomeView_guestNameInputLabel text-center fs-4" t-att-for="guestNameInputUniqueId">What's your name?</label>
<input class="form-control mb-3" type="text" placeholder="Your name" t-att-name="guestNameInputUniqueId" t-att-id="guestNameInputUniqueId" t-att-value="pendingGuestName" t-ref="guestNameInput" t-on-input="onInputGuestNameInput" t-on-keydown="onKeydownGuestNameInput"/>
</t>
<p t-if="messaging.currentUser" class="o_WelcomeView_loggedAsStatus fs-4">Logged as <span t-esc="messaging.currentUser.nameOrDisplayName"/></p>
<button class="o_WelcomeView_joinButton btn btn-success fa-stack align-self-end p-0 rounded-circle fs-1 shadow" title="Join Channel" t-att-disabled="isJoinButtonDisabled" t-on-click="onClickJoinButton">
<i class="fa fa-phone fa-stack"/>
</button>
</div>
</div>
</div>
</t>
</templates>
@@ -2,60 +2,50 @@
<templates xml:space="preserve">
<t t-name="snailmail.SnailmailErrorView" owl="1">
<div class="o_SnailmailErrorView card bg-white" t-attf-class="{{ className }}" t-ref="root">
<h4 class="m-3">Failed letter</h4>
<hr class="mt-0 mb-3"/>
<t t-if="notification.failure_type === 'sn_credit'">
<p class="o_SnailmailErrorView_contentCredit mx-3 mb-3">
The letter could not be sent due to insufficient credits on your IAP account.
</p>
<t t-if="messaging.snailmail_credits_url">
<div class="text-end mx-3 mb-3">
<a class="btn btn-link" t-att-href="messaging.snailmail_credits_url" target="_blank">
<i class="fa fa-arrow-right"/> Buy credits
</a>
</div>
</t>
</t>
<t t-elif="notification.failure_type === 'sn_trial'">
<p class="o_SnailmailErrorView_contentTrial mx-3 mb-3">
You need credits on your IAP account to send a letter.
</p>
<t t-if="messaging.snailmail_credits_url_trial">
<div class="text-end mx-3 mb-3">
<a class="btn btn-link" t-att-href="messaging.snailmail_credits_url_trial">
<i class="fa fa-arrow-right"/> Buy credits
</a>
</div>
</t>
</t>
<t t-elif="notification.failure_type === 'sn_price'">
<p class="o_SnailmailErrorView_contentPrice mx-3 mb-3">
The country to which you want to send the letter is not supported by our service.
</p>
</t>
<t t-elif="notification.failure_type === 'sn_error'">
<p class="o_SnailmailErrorView_contentError mx-3 mb-3">
An unknown error occurred. Please contact our <a href="https://www.odoo.com/help" target="new">support</a> for further assistance.
</p>
</t>
<hr class="mt-0 mb-3"/>
<div class="o_SnailmailErrorView_buttons mx-3 mb-3">
<t t-if="hasCreditsError">
<button class="o_SnailmailErrorView_resendLetterButton btn btn-primary me-2" t-on-click="onClickResendLetter">Re-send letter</button>
</t>
<button class="o_SnailmailErrorView_cancelLetterButton btn me-2"
t-att-class="{
'btn-primary': !hasCreditsError,
'btn-secondary': hasCreditsError,
}"
t-on-click="onClickCancelLetter"
>
Cancel letter
</button>
<button class="o_SnailmailErrorView_closeButton btn btn-secondary me-2" t-on-click="onClickClose">Close</button>
<div class="o_SnailmailErrorView card bg-white" t-attf-class="{{ className }}" t-ref="root">
<h4 class="m-3">Failed letter</h4>
<hr class="mt-0 mb-3"/>
<t t-if="notification.failure_type === 'sn_credit'">
<p class="o_SnailmailErrorView_contentCredit mx-3 mb-3">
The letter could not be sent due to insufficient credits on your IAP account.
</p>
<div t-if="messaging.snailmail_credits_url" class="text-end mx-3 mb-3">
<a class="btn btn-link" t-att-href="messaging.snailmail_credits_url" target="_blank">
<i class="fa fa-arrow-right"/> Buy credits
</a>
</div>
</t>
<t t-elif="notification.failure_type === 'sn_trial'">
<p class="o_SnailmailErrorView_contentTrial mx-3 mb-3">
You need credits on your IAP account to send a letter.
</p>
<div t-if="messaging.snailmail_credits_url_trial" class="text-end mx-3 mb-3">
<a class="btn btn-link" t-att-href="messaging.snailmail_credits_url_trial">
<i class="fa fa-arrow-right"/> Buy credits
</a>
</div>
</t>
<p t-elif="notification.failure_type === 'sn_price'" class="o_SnailmailErrorView_contentPrice mx-3 mb-3">
The country to which you want to send the letter is not supported by our service.
</p>
<p t-elif="notification.failure_type === 'sn_error'" class="o_SnailmailErrorView_contentError mx-3 mb-3">
An unknown error occurred. Please contact our <a href="https://www.odoo.com/help" target="new">support</a> for further assistance.
</p>
<hr class="mt-0 mb-3"/>
<div class="o_SnailmailErrorView_buttons mx-3 mb-3">
<button t-if="hasCreditsError" class="o_SnailmailErrorView_resendLetterButton btn btn-primary me-2" t-on-click="onClickResendLetter">Re-send letter</button>
<button class="o_SnailmailErrorView_cancelLetterButton btn me-2"
t-att-class="{
'btn-primary': !hasCreditsError,
'btn-secondary': hasCreditsError,
}"
t-on-click="onClickCancelLetter"
>
Cancel letter
</button>
<button class="o_SnailmailErrorView_closeButton btn btn-secondary me-2" t-on-click="onClickClose">Close</button>
</div>
</div>
</t>
</templates>

Some files were not shown because too many files have changed in this diff Show More