diff --git a/addons/im_livechat/static/src/components/discuss_sidebar/discuss_sidebar.xml b/addons/im_livechat/static/src/components/discuss_sidebar/discuss_sidebar.xml index 9dee8b5aca7..7a2e00d50f1 100644 --- a/addons/im_livechat/static/src/components/discuss_sidebar/discuss_sidebar.xml +++ b/addons/im_livechat/static/src/components/discuss_sidebar/discuss_sidebar.xml @@ -2,7 +2,7 @@ - + this.messaging.discuss.update({ isOpen: true })); + await afterNextRender(() => this.messaging.discuss.open()); assert.containsNone(document.body, '.o_ChatWindow', "should not have any chat window after opening discuss"); - await afterNextRender(() => this.messaging.discuss.update({ isOpen: false })); + await afterNextRender(() => this.messaging.discuss.close()); assert.strictEqual( document.querySelector(`.o_ComposerTextInput_textarea`).value, "XDU for the win !", @@ -1039,12 +1039,12 @@ QUnit.test('chat window: scroll conservation on toggle discuss', async function }, }); - await afterNextRender(() => this.messaging.discuss.update({ isOpen: true })); + await afterNextRender(() => this.messaging.discuss.open()); assert.containsNone(document.body, '.o_ChatWindow', "should not have any chat window after opening discuss"); await this.afterEvent({ eventName: 'o-component-message-list-scrolled', - func: () => this.messaging.discuss.update({ isOpen: false }), + func: () => this.messaging.discuss.close(), message: "should wait until channel 20 restored its scroll to 142 after closing discuss", predicate: ({ scrollTop, thread }) => { return ( @@ -1968,10 +1968,10 @@ QUnit.test('chat window with a thread: keep scroll position in message list on t }); // fold chat window await afterNextRender(() => document.querySelector('.o_ChatWindow_header').click()); - await afterNextRender(() => this.messaging.discuss.update({ isOpen: true })); + await afterNextRender(() => this.messaging.discuss.open()); assert.containsNone(document.body, '.o_ChatWindow', "should not have any chat window after opening discuss"); - await afterNextRender(() => this.messaging.discuss.update({ isOpen: false })); + await afterNextRender(() => this.messaging.discuss.close()); // unfold chat window await this.afterEvent({ eventName: 'o-component-message-list-scrolled', @@ -2039,10 +2039,10 @@ QUnit.test('chat window with a thread: keep scroll position in message list on t }); // fold chat window await afterNextRender(() => document.querySelector('.o_ChatWindow_header').click()); - await afterNextRender(() => this.messaging.discuss.update({ isOpen: true })); + await afterNextRender(() => this.messaging.discuss.open()); assert.containsNone(document.body, '.o_ChatWindow', "should not have any chat window after opening discuss"); - await afterNextRender(() => this.messaging.discuss.update({ isOpen: false })); + await afterNextRender(() => this.messaging.discuss.close()); // unfold chat window await this.afterEvent({ eventName: 'o-component-message-list-scrolled', diff --git a/addons/mail/static/src/components/discuss/discuss.js b/addons/mail/static/src/components/discuss/discuss.js index 1b5c70d527a..0c573f0d304 100644 --- a/addons/mail/static/src/components/discuss/discuss.js +++ b/addons/mail/static/src/components/discuss/discuss.js @@ -1,9 +1,9 @@ /** @odoo-module **/ -import { registerMessagingComponent } from '@mail/utils/messaging_component'; import { useUpdate } from '@mail/component_hooks/use_update/use_update'; +import { registerMessagingComponent } from '@mail/utils/messaging_component'; -const { Component, onWillUnmount } = owl; +const { Component } = owl; export class Discuss extends Component { @@ -17,39 +17,31 @@ export class Discuss extends Component { this._onMobileAddItemHeaderInputSelect = this._onMobileAddItemHeaderInputSelect.bind(this); this._onMobileAddItemHeaderInputSource = this._onMobileAddItemHeaderInputSource.bind(this); useUpdate({ func: () => this._update() }); - onWillUnmount(() => this._willUnmount()); this._onHideMobileAddItemHeader = this._onHideMobileAddItemHeader.bind(this); } _update() { - if (!this.discuss) { + if (!this.discussView) { return; } - this.discuss.update({ isOpen: true }); - if (this.discuss.thread) { + if (this.discussView.discuss.thread) { this.trigger('o-push-state-action-manager'); - } else if (!this._activeThreadCache && this.discuss.messaging.isInitialized) { - this.discuss.openInitThread(); + } else if (!this._activeThreadCache) { + this.discussView.discuss.openInitThread(); } if ( - this.discuss.thread && - this.discuss.thread === this.messaging.inbox && - this.discuss.threadView && - this._lastThreadCache === this.discuss.threadView.threadCache.localId && - this._lastThreadCounter > 0 && this.discuss.thread.counter === 0 + this.discussView.discuss.thread && + this.discussView.discuss.thread === this.messaging.inbox && + this.discussView.discuss.threadView && + this._lastThreadCache === this.discussView.discuss.threadView.threadCache.localId && + this._lastThreadCounter > 0 && this.discussView.discuss.thread.counter === 0 ) { this.trigger('o-show-rainbow-man'); } - this._activeThreadCache = this.discuss.threadView && this.discuss.threadView.threadCache; + this._activeThreadCache = this.discussView.discuss.threadView && this.discussView.discuss.threadView.threadCache; this._updateLocalStoreProps(); } - _willUnmount() { - if (this.discuss) { - this.discuss.close(); - } - } - //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- @@ -69,10 +61,10 @@ export class Discuss extends Component { } /** - * @returns {Discuss} + * @returns {DiscussView} */ - get discuss() { - return this.messaging && this.messaging.discuss; + get discussView() { + return this.messaging && this.messaging.models['DiscussView'].get(this.props.localId); } //-------------------------------------------------------------------------- @@ -83,7 +75,7 @@ export class Discuss extends Component { * @private */ _updateLocalStoreProps() { - if (!this.discuss) { + if (!this.discussView) { return; } /** @@ -92,17 +84,17 @@ export class Discuss extends Component { * rainbox man on inbox. */ this._lastThreadCache = ( - this.discuss.threadView && - this.discuss.threadView.threadCache && - this.discuss.threadView.threadCache.localId + this.discussView.discuss.threadView && + this.discussView.discuss.threadView.threadCache && + this.discussView.discuss.threadView.threadCache.localId ); /** * Locally tracked store props `threadCounter`. * Useful to display the rainbow man on inbox. */ this._lastThreadCounter = ( - this.discuss.thread && - this.discuss.thread.counter + this.discussView.discuss.thread && + this.discussView.discuss.thread.counter ); } @@ -114,7 +106,10 @@ export class Discuss extends Component { * @private */ _onHideMobileAddItemHeader() { - this.discuss.clearIsAddingItem(); + if (!this.discussView) { + return; + } + this.discussView.discuss.clearIsAddingItem(); } /** @@ -125,7 +120,10 @@ export class Discuss extends Component { * @param {integer} ui.item.id */ _onMobileAddItemHeaderInputSelect(ev, ui) { - const discuss = this.discuss; + if (!this.discussView) { + return; + } + const discuss = this.discussView.discuss; if (discuss.isAddingChannel) { discuss.handleAddChannelAutocompleteSelect(ev, ui); } else { @@ -140,17 +138,20 @@ export class Discuss extends Component { * @param {function} res */ _onMobileAddItemHeaderInputSource(req, res) { - if (this.discuss.isAddingChannel) { - this.discuss.handleAddChannelAutocompleteSource(req, res); + if (!this.discussView) { + return; + } + if (this.discussView.discuss.isAddingChannel) { + this.discussView.discuss.handleAddChannelAutocompleteSource(req, res); } else { - this.discuss.handleAddChatAutocompleteSource(req, res); + this.discussView.discuss.handleAddChatAutocompleteSource(req, res); } } } Object.assign(Discuss, { - props: {}, + props: { localId: String }, template: 'mail.Discuss', }); diff --git a/addons/mail/static/src/components/discuss/discuss.scss b/addons/mail/static/src/components/discuss/discuss.scss index 198d662080d..a8d1e9bfb40 100644 --- a/addons/mail/static/src/components/discuss/discuss.scss +++ b/addons/mail/static/src/components/discuss/discuss.scss @@ -30,17 +30,6 @@ flex-flow: column; } -.o_Discuss_messagingNotInitialized { - flex: 1 1 auto; - display: flex; - align-items: center; - justify-content: center; -} - -.o_Discuss_messagingNotInitializedIcon { - margin-right: map-get($spacers, 1); -} - .o_Discuss_mobileAddItemHeader { display: flex; justify-content: center; diff --git a/addons/mail/static/src/components/discuss/discuss.xml b/addons/mail/static/src/components/discuss/discuss.xml index 6556e7444d3..8f08d63f083 100644 --- a/addons/mail/static/src/components/discuss/discuss.xml +++ b/addons/mail/static/src/components/discuss/discuss.xml @@ -4,17 +4,14 @@
- -
Please wait...
-
- + - + @@ -27,58 +24,58 @@ - + - +
- + - +
No conversation selected.
- - - - - - - + + - + diff --git a/addons/mail/static/src/components/discuss/tests/discuss_tests.js b/addons/mail/static/src/components/discuss/tests/discuss_tests.js index 242538164a8..8a56339576f 100644 --- a/addons/mail/static/src/components/discuss/tests/discuss_tests.js +++ b/addons/mail/static/src/components/discuss/tests/discuss_tests.js @@ -49,7 +49,7 @@ QUnit.test('messaging not created', async function (assert) { messagingBeforeCreationDeferred, waitUntilMessagingCondition: 'none' }); - assert.containsOnce(document.body, '.o_Discuss_messagingNotInitialized', "should display messaging not initialized"); + assert.containsOnce(document.body, '.o_DiscussContainer_spinner', "should display messaging not initialized"); messagingBeforeCreationDeferred.resolve(); }); @@ -64,7 +64,7 @@ QUnit.test('discuss should be marked as opened if the component is already rende await afterNextRender(() => messagingBeforeCreationDeferred.resolve()); assert.ok( - this.messaging.discuss.isOpen, + this.messaging.discuss.discussView, "discuss should be marked as opened if the component is already rendered and messaging becomes created afterwards" ); }); @@ -76,7 +76,7 @@ QUnit.test('discuss should be marked as closed when the component is unmounted', await afterNextRender(() => widget.destroy()); assert.notOk( - this.messaging.discuss.isOpen, + this.messaging.discuss.discussView, "discuss should be marked as closed when the component is unmounted" ); }); @@ -95,7 +95,7 @@ QUnit.test('messaging not initialized', async function (assert) { waitUntilMessagingCondition: 'created', }); assert.strictEqual( - document.querySelectorAll('.o_Discuss_messagingNotInitialized').length, + document.querySelectorAll('.o_DiscussContainer_spinner').length, 1, "should display messaging not initialized" ); @@ -117,14 +117,14 @@ QUnit.test('messaging becomes initialized', async function (assert) { waitUntilMessagingCondition: 'created', }); assert.strictEqual( - document.querySelectorAll('.o_Discuss_messagingNotInitialized').length, + document.querySelectorAll('.o_DiscussContainer_spinner').length, 1, "should display messaging not initialized" ); await afterNextRender(() => messagingInitializedProm.resolve()); assert.strictEqual( - document.querySelectorAll('.o_Discuss_messagingNotInitialized').length, + document.querySelectorAll('.o_DiscussContainer_spinner').length, 0, "should no longer display messaging not initialized" ); diff --git a/addons/mail/static/src/components/discuss_container/discuss_container.js b/addons/mail/static/src/components/discuss_container/discuss_container.js new file mode 100644 index 00000000000..b7279cc35e3 --- /dev/null +++ b/addons/mail/static/src/components/discuss_container/discuss_container.js @@ -0,0 +1,42 @@ +/** @odoo-module **/ + +import { useModels } from "@mail/component_hooks/use_models/use_models"; +import { useUpdate } from '@mail/component_hooks/use_update/use_update'; +import { getMessagingComponent } from "@mail/utils/messaging_component"; + +const { Component, onWillUnmount } = owl; + +export class DiscussContainer extends Component { + + /** + * @override + */ + setup() { + // for now, the legacy env is needed for internal functions such as + // `useModels` to work + this.env = Component.env; + useModels(); + super.setup(); + useUpdate({ func: () => this._update() }); + onWillUnmount(() => this._willUnmount()); + } + + _update() { + if (!this.messaging || !this.messaging.discuss) { + return; + } + this.messaging.discuss.open(); + } + + _willUnmount() { + if (this.messaging && this.messaging.discuss) { + this.messaging.discuss.close(); + } + } + +} + +Object.assign(DiscussContainer, { + components: { Discuss: getMessagingComponent('Discuss') }, + template: 'mail.DiscussContainer', +}); diff --git a/addons/mail/static/src/components/discuss_container/discuss_container.xml b/addons/mail/static/src/components/discuss_container/discuss_container.xml new file mode 100644 index 00000000000..2466063c624 --- /dev/null +++ b/addons/mail/static/src/components/discuss_container/discuss_container.xml @@ -0,0 +1,12 @@ + + + + +
+ +
+ Please wait... +
+
+
+
diff --git a/addons/mail/static/src/components/discuss_sidebar/discuss_sidebar.js b/addons/mail/static/src/components/discuss_sidebar/discuss_sidebar.js index 64c0b2fb8c3..1adf8dad7d2 100644 --- a/addons/mail/static/src/components/discuss_sidebar/discuss_sidebar.js +++ b/addons/mail/static/src/components/discuss_sidebar/discuss_sidebar.js @@ -25,10 +25,10 @@ export class DiscussSidebar extends Component { //-------------------------------------------------------------------------- /** - * @returns {Discuss} + * @returns {DiscussView} */ - get discuss() { - return this.messaging && this.messaging.models['Discuss'].get(this.props.localId); + get discussView() { + return this.messaging && this.messaging.models['DiscussView'].get(this.props.localId); } //-------------------------------------------------------------------------- @@ -39,11 +39,11 @@ export class DiscussSidebar extends Component { * @private */ _update() { - if (!this.discuss) { + if (!this.discussView) { return; } if (this._quickSearchInputRef.el) { - this._quickSearchInputRef.el.value = this.discuss.sidebarQuickSearchValue; + this._quickSearchInputRef.el.value = this.discussView.discuss.sidebarQuickSearchValue; } } @@ -57,7 +57,7 @@ export class DiscussSidebar extends Component { */ _onInputQuickSearch(ev) { ev.stopPropagation(); - this.discuss.onInputQuickSearch(this._quickSearchInputRef.el.value); + this.discussView.discuss.onInputQuickSearch(this._quickSearchInputRef.el.value); } } diff --git a/addons/mail/static/src/components/discuss_sidebar/discuss_sidebar.xml b/addons/mail/static/src/components/discuss_sidebar/discuss_sidebar.xml index 0df96ad9838..9910295beaf 100644 --- a/addons/mail/static/src/components/discuss_sidebar/discuss_sidebar.xml +++ b/addons/mail/static/src/components/discuss_sidebar/discuss_sidebar.xml @@ -3,30 +3,34 @@
-
- -
-
-
- - - -
-
- - + +
+ +
+
+
+ + + +
+
+ + + + + + - - -
diff --git a/addons/mail/static/src/components/messaging_menu/messaging_menu.xml b/addons/mail/static/src/components/messaging_menu/messaging_menu.xml index 0c5bd5d9ca4..5ce4d6de708 100644 --- a/addons/mail/static/src/components/messaging_menu/messaging_menu.xml +++ b/addons/mail/static/src/components/messaging_menu/messaging_menu.xml @@ -34,7 +34,7 @@
- + diff --git a/addons/mail/static/src/models/chat_window/chat_window.js b/addons/mail/static/src/models/chat_window/chat_window.js index 62b9a21482c..dd32e7fe5b7 100644 --- a/addons/mail/static/src/models/chat_window/chat_window.js +++ b/addons/mail/static/src/models/chat_window/chat_window.js @@ -19,7 +19,7 @@ registerModel({ if (notifyServer === undefined) { notifyServer = !this.messaging.device.isMobile; } - if (this.messaging.device.isMobile && !this.messaging.discuss.isOpen) { + if (this.messaging.device.isMobile && !this.messaging.discuss.discussView) { // If we are in mobile and discuss is not open, it means the // chat window was opened from the messaging menu. In that // case it should be re-opened to simulate it was always diff --git a/addons/mail/static/src/models/chat_window_manager/chat_window_manager.js b/addons/mail/static/src/models/chat_window_manager/chat_window_manager.js index b6c58bf6547..b6c3a75e0e8 100644 --- a/addons/mail/static/src/models/chat_window_manager/chat_window_manager.js +++ b/addons/mail/static/src/models/chat_window_manager/chat_window_manager.js @@ -272,7 +272,7 @@ registerModel({ const HIDDEN_MENU_WIDTH = 200; // max width, including width of dropup list items const START_GAP_WIDTH = device.isMobile ? 0 : 10; const chatWindows = this.allOrdered; - if (!device.isMobile && discuss.isOpen) { + if (!device.isMobile && discuss.discussView) { return visual; } if (!chatWindows.length) { diff --git a/addons/mail/static/src/models/discuss/discuss.js b/addons/mail/static/src/models/discuss/discuss.js index ff780bf31e0..2a20347d890 100644 --- a/addons/mail/static/src/models/discuss/discuss.js +++ b/addons/mail/static/src/models/discuss/discuss.js @@ -21,7 +21,7 @@ registerModel({ * Close the discuss app. Should reset its internal state. */ close() { - this.update({ isOpen: false }); + this.update({ discussView: clear() }); }, focus() { if (this.threadView && this.threadView.composerView) { @@ -158,6 +158,9 @@ registerModel({ } this.threadView.topbar.openInvitePopoverView(); }, + open() { + this.update({ discussView: insertAndReplace() }); + }, /** * Open thread from init active id. `initActiveId` is used to refer to * a thread that we may not have full data yet, such as when messaging @@ -193,7 +196,7 @@ registerModel({ if (focus !== undefined ? focus : !this.messaging.device.isMobileDevice) { this.focus(); } - if (!this.isOpen) { + if (!this.discussView) { this.env.bus.trigger('do-action', { action: 'mail.action_discuss', options: { @@ -237,7 +240,7 @@ registerModel({ * @returns {string} */ _computeAddingChannelValue() { - if (!this.isOpen) { + if (!this.discussView) { return ""; } return this.addingChannelValue; @@ -247,7 +250,7 @@ registerModel({ * @returns {boolean} */ _computeHasThreadView() { - if (!this.thread || !this.isOpen) { + if (!this.thread || !this.discussView) { return false; } if ( @@ -266,7 +269,7 @@ registerModel({ * @returns {boolean} */ _computeIsAddingChannel() { - if (!this.isOpen) { + if (!this.discussView) { return false; } return this.isAddingChannel; @@ -276,7 +279,7 @@ registerModel({ * @returns {boolean} */ _computeIsAddingChat() { - if (!this.isOpen) { + if (!this.discussView) { return false; } return this.isAddingChat; @@ -357,6 +360,10 @@ registerModel({ inverse: 'discussAsChat', isCausal: true, }), + discussView: one('DiscussView', { + inverse: 'discuss', + isCausal: true, + }), /** * Determines whether `this.thread` should be displayed. */ @@ -390,13 +397,6 @@ registerModel({ compute: '_computeIsAddingChat', default: false, }), - /** - * Whether the discuss app is open or not. Useful to determine - * whether the discuss or chat window logic should be applied. - */ - isOpen: attr({ - default: false, - }), /** * The menu_id of discuss app, received on mail/init_messaging and * used to open discuss from elsewhere. diff --git a/addons/mail/static/src/models/discuss_view/discuss_view.js b/addons/mail/static/src/models/discuss_view/discuss_view.js new file mode 100644 index 00000000000..e285708ed37 --- /dev/null +++ b/addons/mail/static/src/models/discuss_view/discuss_view.js @@ -0,0 +1,16 @@ +/** @odoo-module **/ + +import { registerModel } from '@mail/model/model_core'; +import { one } from '@mail/model/model_field'; + +registerModel({ + name: 'DiscussView', + identifyingFields: ['discuss'], + fields: { + discuss: one('Discuss', { + inverse: 'discussView', + readonly: true, + required: true, + }), + }, +}); diff --git a/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js b/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js index 6a7ceee591b..8d4041547b0 100644 --- a/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js +++ b/addons/mail/static/src/models/messaging_initializer/messaging_initializer.js @@ -40,7 +40,7 @@ registerModel({ route: '/mail/init_messaging', }, { shadow: true })); await this.async(() => this._init(data)); - if (discuss.isOpen) { + if (discuss.discussView) { discuss.openInitThread(); } if (this.messaging.autofetchPartnerImStatus) { diff --git a/addons/mail/static/src/models/thread/thread.js b/addons/mail/static/src/models/thread/thread.js index 9f6a9988646..db4319ba8b3 100644 --- a/addons/mail/static/src/models/thread/thread.js +++ b/addons/mail/static/src/models/thread/thread.js @@ -942,7 +942,7 @@ registerModel({ const discuss = this.messaging.discuss; // check if thread must be opened in form view if (!['mail.box', 'mail.channel'].includes(this.model)) { - if (expanded || discuss.isOpen) { + if (expanded || discuss.discussView) { // Close chat window because having the same thread opened // both in chat window and as main document does not look // good. @@ -957,7 +957,7 @@ registerModel({ // check if thread must be opened in discuss const device = this.messaging.device; if ( - (!device.isMobile && (discuss.isOpen || expanded)) || + (!device.isMobile && (discuss.discussView || expanded)) || this.model === 'mail.box' ) { return discuss.openThread(this, { diff --git a/addons/mail/static/src/widgets/discuss/discuss.js b/addons/mail/static/src/widgets/discuss/discuss.js index 51eeaadddfa..f9068bb6673 100644 --- a/addons/mail/static/src/widgets/discuss/discuss.js +++ b/addons/mail/static/src/widgets/discuss/discuss.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { getMessagingComponent } from "@mail/utils/messaging_component"; +import { DiscussContainer } from "@mail/components/discuss_container/discuss_container"; import AbstractAction from 'web.AbstractAction'; @@ -63,8 +63,7 @@ export const DiscussWidget = AbstractAction.extend({ // prevent twice call to on_attach_callback (FIXME) return; } - const DiscussComponent = getMessagingComponent("Discuss"); - this.component = new DiscussComponent(); + this.component = new DiscussContainer(); this._pushStateActionManagerEventListener = ev => { ev.stopPropagation(); if (this._lastPushStateActiveThread === this.discuss.thread) { diff --git a/addons/website_livechat/static/src/components/discuss/discuss.xml b/addons/website_livechat/static/src/components/discuss/discuss.xml index 0d148d87169..7e73220a387 100644 --- a/addons/website_livechat/static/src/components/discuss/discuss.xml +++ b/addons/website_livechat/static/src/components/discuss/discuss.xml @@ -2,9 +2,9 @@ - +