[IMP] im_livechat,mail: remove MobileMessagingNavbar/tabs deep props

In preparation for using OWL v2 in discuss code.
(shouldUpdateBasedOnProps will be removed)

Solution consists of introducing MobileMessagingNavbarView model.

Task-2695743

closes odoo/odoo#80617

Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Alexandre Kühn
2021-12-23 19:15:38 +00:00
parent c71d9ba51e
commit cc28195b7d
13 changed files with 246 additions and 156 deletions
@@ -1,26 +0,0 @@
/** @odoo-module **/
import { Discuss } from '@mail/components/discuss/discuss';
import { patch } from 'web.utils';
const components = { Discuss };
patch(components.Discuss.prototype, 'im_livechat/static/src/components/discuss/discuss.js', {
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* @override
*/
mobileNavbarTabs(...args) {
return [...this._super(...args), {
icon: 'fa fa-comments',
id: 'livechat',
label: this.env._t("Livechat"),
}];
}
});
@@ -0,0 +1,16 @@
/** @odoo-module **/
import { addFields } from '@mail/model/model_core';
import { one2many } from '@mail/model/model_field';
// ensure that the model definition is loaded before the patch
import '@mail/models/messaging/messaging';
addFields('Messaging', {
/**
* All pinned livechats that are known.
*/
pinnedLivechats: one2many('Thread', {
inverse: 'messagingAsPinnedLivechat',
readonly: true,
}),
});
@@ -0,0 +1,22 @@
/** @odoo-module **/
import { patchRecordMethods } from '@mail/model/model_core';
// ensure that the model definition is loaded before the patch
import '@mail/models/mobile_messaging_navbar_view/mobile_messaging_navbar_view';
patchRecordMethods('MobileMessagingNavbarView', {
/**
* @override
*/
_computeTabs() {
const res = this._super();
if (this.messaging.pinnedLivechats.length > 0) {
return [...res, {
icon: 'fa fa-comments',
id: 'livechat',
label: this.env._t("Livechat"),
}];
}
return res;
},
});
@@ -1,10 +1,34 @@
/** @odoo-module **/
import { patchModelMethods, patchRecordMethods } from '@mail/model/model_core';
import { insert, link, unlink } from '@mail/model/model_field_command';
import { addFields, addRecordMethods, patchModelMethods, patchRecordMethods } from '@mail/model/model_core';
import { many2one } from '@mail/model/model_field';
import { clear, insert, link, replace, unlink } from '@mail/model/model_field_command';
// ensure that the model definition is loaded before the patch
import '@mail/models/thread/thread';
addFields('Thread', {
/**
* If set, current thread is a livechat.
*/
messagingAsPinnedLivechat: many2one('Messaging', {
compute: '_computeMessagingAsPinnedLivechat',
inverse: 'pinnedLivechats',
}),
});
addRecordMethods('Thread', {
/**
* @private
* @returns {FieldCommand}
*/
_computeMessagingAsPinnedLivechat() {
if (!this.messaging || this.channel_type !== 'livechat' || !this.isPinned) {
return clear();
}
return replace(this.messaging);
},
});
patchModelMethods('Thread', {
/**
* @override
@@ -21,7 +21,6 @@ export class Discuss extends Component {
useUpdate({ func: () => this._update() });
onWillUnmount(() => this._willUnmount());
this._onHideMobileAddItemHeader = this._onHideMobileAddItemHeader.bind(this);
this._onSelectMobileNavbarTab = this._onSelectMobileNavbarTab.bind(this);
}
_update() {
@@ -78,25 +77,6 @@ export class Discuss extends Component {
return this.messaging && this.messaging.discuss;
}
/**
* @returns {Object[]}
*/
mobileNavbarTabs() {
return [{
icon: 'fa fa-inbox',
id: 'mailbox',
label: this.env._t("Mailboxes"),
}, {
icon: 'fa fa-user',
id: 'chat',
label: this.env._t("Chat"),
}, {
icon: 'fa fa-users',
id: 'channel',
label: this.env._t("Channel"),
}];
}
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
@@ -169,33 +149,6 @@ export class Discuss extends Component {
}
}
/**
* @private
* @param {Object} detail
* @param {string} detail.tabId
*/
_onSelectMobileNavbarTab(detail) {
if (this.discuss.activeMobileNavbarTabId === detail.tabId) {
return;
}
this.discuss.update({ activeMobileNavbarTabId: detail.tabId });
if (
this.discuss.activeMobileNavbarTabId === 'mailbox' &&
(!this.discuss.thread || this.discuss.thread.model !== 'mailbox')
) {
this.discuss.update({ thread: link(this.messaging.inbox) });
}
if (this.discuss.activeMobileNavbarTabId !== 'mailbox') {
this.discuss.update({ thread: unlink() });
}
if (this.discuss.activeMobileNavbarTabId !== 'chat') {
this.discuss.update({ isAddingChat: false });
}
if (this.discuss.activeMobileNavbarTabId !== 'channel') {
this.discuss.update({ isAddingChannel: false });
}
}
}
Object.assign(Discuss, {
@@ -76,12 +76,10 @@
filter="discuss.activeMobileNavbarTabId"
/>
</t>
<t t-if="messaging.device.isMobile and !(discuss.threadView and discuss.threadView.replyingToMessageView)">
<t t-if="discuss.mobileMessagingNavbarView">
<MobileMessagingNavbar
className="'o_Discuss_mobileNavbar'"
activeTabId="discuss.activeMobileNavbarTabId"
tabs="mobileNavbarTabs()"
onSelectMobileMessagingNavbarTab="_onSelectMobileNavbarTab"
mobileMessagingNavbarViewLocalId="discuss.mobileMessagingNavbarView.localId"
/>
</t>
</t>
@@ -23,7 +23,6 @@ export class MessagingMenu extends Component {
this._onMobileNewMessageInputSource = this._onMobileNewMessageInputSource.bind(this);
this._onClickCaptureGlobal = this._onClickCaptureGlobal.bind(this);
this._onHideMobileNewMessage = this._onHideMobileNewMessage.bind(this);
this._onSelectMobileNavbarTab = this._onSelectMobileNavbarTab.bind(this);
onMounted(() => this._mounted());
onWillUnmount(() => this._willUnmount());
}
@@ -54,25 +53,6 @@ export class MessagingMenu extends Component {
return this.env._t("Search user...");
}
/**
* @returns {Object[]}
*/
get tabs() {
return [{
icon: 'fa fa-envelope',
id: 'all',
label: this.env._t("All"),
}, {
icon: 'fa fa-user',
id: 'chat',
label: this.env._t("Chat"),
}, {
icon: 'fa fa-users',
id: 'channel',
label: this.env._t("Channel"),
}];
}
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
@@ -171,15 +151,6 @@ export class MessagingMenu extends Component {
});
}
/**
* @private
* @param {Object} detail
* @param {string} detail.tabId
*/
_onSelectMobileNavbarTab(detail) {
this.messagingMenu.update({ activeTabId: detail.tabId });
}
}
Object.assign(MessagingMenu, {
@@ -54,12 +54,10 @@
classNameObj="{ 'o-mobile': messaging.device.isMobile }"
filter="messagingMenu.activeTabId"
/>
<t t-if="messaging.device.isMobile">
<t t-if="messagingMenu.mobileMessagingNavbarView">
<MobileMessagingNavbar
className="'o_MessagingMenu_mobileNavbar'"
activeTabId="messagingMenu.activeTabId"
tabs="tabs"
onSelectMobileMessagingNavbarTab="_onSelectMobileNavbarTab"
mobileMessagingNavbarViewLocalId="messagingMenu.mobileMessagingNavbarView.localId"
/>
</t>
</t>
@@ -6,50 +6,20 @@ const { Component } = owl;
export class MobileMessagingNavbar extends Component {
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @param {MouseEvent} ev
* @returns {MobileMessagingNavbarView}
*/
_onClick(ev) {
if (this.props.onSelectMobileMessagingNavbarTab) {
this.props.onSelectMobileMessagingNavbarTab({
tabId: ev.currentTarget.dataset.tabId,
});
}
get mobileMessagingNavbarView() {
return this.messaging && this.messaging.models['MobileMessagingNavbarView'].get(this.props.mobileMessagingNavbarViewLocalId);
}
}
Object.assign(MobileMessagingNavbar, {
defaultProps: {
tabs: [],
},
props: {
activeTabId: String,
onSelectMobileMessagingNavbarTab: {
type: Function,
optional: true,
},
tabs: {
type: Array,
element: {
type: Object,
shape: {
icon: {
type: String,
optional: true,
},
id: String,
label: String,
},
},
},
mobileMessagingNavbarViewLocalId: String,
},
template: 'mail.MobileMessagingNavbar',
});
registerMessagingComponent(MobileMessagingNavbar, { propsCompareDepth: { tabs: 2 } });
registerMessagingComponent(MobileMessagingNavbar);
@@ -3,13 +3,15 @@
<t t-name="mail.MobileMessagingNavbar" owl="1">
<div class="o_MobileMessagingNavbar" t-attf-class="{{ className }}" t-ref="root">
<t t-foreach="props.tabs" t-as="tab" t-key="tab.id">
<div class="o_MobileMessagingNavbar_tab" t-att-class="{ 'o-active': props.activeTabId === tab.id }" t-on-click="_onClick" t-att-data-tab-id="tab.id">
<t t-if="tab.icon">
<span class="o_MobileMessagingNavbar_tabIcon" t-att-class="tab.icon"/>
</t>
<span class="o_MobileMessagingNavbar_tabLabel"><t t-esc="tab.label"/></span>
</div>
<t t-if="mobileMessagingNavbarView">
<t t-foreach="mobileMessagingNavbarView.tabs" t-as="tab" t-key="tab.id">
<div class="o_MobileMessagingNavbar_tab" t-att-class="{ 'o-active': mobileMessagingNavbarView.activeTabId === tab.id }" t-on-click="mobileMessagingNavbarView.onClick.bind(mobileMessagingNavbarView, tab.id)" t-att-data-tab-id="tab.id">
<t t-if="tab.icon">
<span class="o_MobileMessagingNavbar_tabIcon" t-att-class="tab.icon"/>
</t>
<span class="o_MobileMessagingNavbar_tabLabel"><t t-esc="tab.label"/></span>
</div>
</t>
</t>
</div>
</t>
@@ -285,6 +285,20 @@ registerModel({
}
return this.isAddingChat;
},
/**
* @private
* @returns {FieldCommand}
*/
_computeMobileMessagingNavbarView() {
if (
this.messaging.device &&
this.messaging.device.isMobile &&
!(this.threadView && this.threadView.replyingToMessageView)
) {
return insertAndReplace();
}
return clear();
},
/**
* Only pinned threads are allowed in discuss.
*
@@ -387,6 +401,15 @@ registerModel({
menu_id: attr({
default: null,
}),
/**
* The navbar view on the discuss app when in mobile and when not
* replying to a message from inbox.
*/
mobileMessagingNavbarView: one2one('MobileMessagingNavbarView', {
compute: '_computeMobileMessagingNavbarView',
inverse: 'discuss',
isCausal: true,
}),
/**
* Quick search input value in the discuss sidebar (desktop). Useful
* to filter channels and chats based on this input content.
@@ -1,7 +1,8 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr, one2many } from '@mail/model/model_field';
import { attr, one2many, one2one } from '@mail/model/model_field';
import { clear, insertAndReplace } from '@mail/model/model_field_command';
registerModel({
name: 'MessagingMenu',
@@ -48,6 +49,16 @@ registerModel({
const notificationPemissionCounter = this.messaging.isNotificationPermissionDefault ? 1 : 0;
return inboxCounter + unreadChannelsCounter + notificationGroupsCounter + notificationPemissionCounter;
},
/**
* @private
* @returns {MobileMessagingNavbarView|FieldCommand}
*/
_computeMobileMessagingNavbarView() {
if (this.messaging.device && this.messaging.device.isMobile) {
return insertAndReplace();
}
return clear();
},
},
fields: {
/**
@@ -77,10 +88,18 @@ registerModel({
isOpen: attr({
default: false,
}),
/**
* The navbar view on the messaging menu when in mobile.
*/
mobileMessagingNavbarView: one2one('MobileMessagingNavbarView', {
compute: '_computeMobileMessagingNavbarView',
inverse: 'messagingMenu',
isCausal: true,
}),
/**
* States all the pinned channels that have unread messages.
*/
pinnedAndUnreadChannels: one2many('Thread', {
pinnedAndUnreadChannels: one2many('Thread', {
inverse: 'messagingMenuAsPinnedAndUnreadChannel',
readonly: true,
}),
@@ -0,0 +1,120 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr, one2one } from '@mail/model/model_field';
import { clear, replace } from '@mail/model/model_field_command';
registerModel({
name: 'MobileMessagingNavbarView',
identifyingFields: [['discuss', 'messagingMenu']],
recordMethods: {
/**
* @param {string} tabId
*/
onClick(tabId) {
if (this.discuss) {
if (this.discuss.activeMobileNavbarTabId === tabId) {
return;
}
this.discuss.update({ activeMobileNavbarTabId: tabId });
if (
this.discuss.activeMobileNavbarTabId === 'mailbox' &&
(!this.discuss.thread || this.discuss.thread.model !== 'mailbox')
) {
this.discuss.update({ thread: replace(this.messaging.inbox) });
}
if (this.discuss.activeMobileNavbarTabId !== 'mailbox') {
this.discuss.update({ thread: clear() });
}
if (this.discuss.activeMobileNavbarTabId !== 'chat') {
this.discuss.update({ isAddingChat: false });
}
if (this.discuss.activeMobileNavbarTabId !== 'channel') {
this.discuss.update({ isAddingChannel: false });
}
}
if (this.messagingMenu) {
this.messagingMenu.update({ activeTabId: tabId });
}
},
/**
* @private
* @returns {string|FieldCommand}
*/
_computeActiveTabId() {
if (this.discuss) {
return this.discuss.activeMobileNavbarTabId;
}
if (this.messagingMenu) {
return this.messagingMenu.activeTabId;
}
return clear();
},
/**
* @private
* @returns {Object[]}
*/
_computeTabs() {
if (this.discuss) {
return [{
icon: 'fa fa-inbox',
id: 'mailbox',
label: this.env._t("Mailboxes"),
}, {
icon: 'fa fa-user',
id: 'chat',
label: this.env._t("Chat"),
}, {
icon: 'fa fa-users',
id: 'channel',
label: this.env._t("Channel"),
}];
}
if (this.messagingMenu) {
return [{
icon: 'fa fa-envelope',
id: 'all',
label: this.env._t("All"),
}, {
icon: 'fa fa-user',
id: 'chat',
label: this.env._t("Chat"),
}, {
icon: 'fa fa-users',
id: 'channel',
label: this.env._t("Channel"),
}];
}
return [];
},
},
fields: {
/**
* Tab selected in this navbar.
* Either 'all', 'mailbox', 'chat' or 'channel'.
*/
activeTabId: attr({
compute: '_computeActiveTabId',
}),
discuss: one2one('Discuss', {
inverse: 'mobileMessagingNavbarView',
readonly: true,
}),
messagingMenu: one2one('MessagingMenu', {
inverse: 'mobileMessagingNavbarView',
readonly: true,
}),
/**
* Ordered list of tabs that this navbar has.
* Format of tab:
* {
* icon: <the classname for this tab>
* id: <the id for this tab>
* label: <the label/name of this tab>
* }
*/
tabs: attr({
compute: '_computeTabs',
}),
},
});