diff --git a/addons/mail/static/src/components/chatter/chatter.xml b/addons/mail/static/src/components/chatter/chatter.xml index a35a2f257c4..0055eb2964b 100644 --- a/addons/mail/static/src/components/chatter/chatter.xml +++ b/addons/mail/static/src/components/chatter/chatter.xml @@ -12,6 +12,7 @@
diff --git a/addons/mail/static/src/components/chatter_container/chatter_container.js b/addons/mail/static/src/components/chatter_container/chatter_container.js index 176dd043c51..08746c89086 100644 --- a/addons/mail/static/src/components/chatter_container/chatter_container.js +++ b/addons/mail/static/src/components/chatter_container/chatter_container.js @@ -8,7 +8,7 @@ import { getMessagingComponent } from "@mail/utils/messaging_component"; const { Component, onWillDestroy, onWillUpdateProps } = owl; -const getChatterNextTemporaryId = (function () { +export const getChatterNextTemporaryId = (function () { let tmpId = 0; return () => { tmpId += 1; @@ -32,23 +32,21 @@ export class ChatterContainer extends Component { setup() { useModels(); super.setup(); - this.chatter = undefined; - this.chatterId = getChatterNextTemporaryId(); + this.localChatter = undefined; this._insertFromProps(this.props); - onWillUpdateProps(nextProps => this._willUpdateProps(nextProps)); - onWillDestroy(() => this._onWillDestroy()); + onWillUpdateProps(nextProps => { + this._insertFromProps(nextProps); + }); + onWillDestroy(() => this.deleteLocalChatter()); } - _willUpdateProps(nextProps) { - this._insertFromProps(nextProps); + get chatter() { + return this.props.chatter || this.localChatter; } - /** - * @override - */ - _onWillDestroy() { - if (this.chatter && this.chatter.exists()) { - this.chatter.delete(); + deleteLocalChatter() { + if (this.localChatter && this.localChatter.exists()) { + this.localChatter.delete(); } } @@ -64,15 +62,23 @@ export class ChatterContainer extends Component { if (owl.status(this) === "destroyed") { return; } - const values = { id: this.chatterId, ...props }; + const values = { ...props }; + delete values.chatter; delete values.className; if (values.threadId === undefined) { values.threadId = clear(); } - this.chatter = messaging.models['Chatter'].insert(values); + const hasToCreateChatter = !props.chatter && !this.localChatter; + if (hasToCreateChatter) { + this.localChatter = messaging.models['Chatter'].insert({ id: getChatterNextTemporaryId(), ...values }); + } + const chatter = props.chatter || this.localChatter; + if (!hasToCreateChatter) { + chatter.update(values); + } if (owl.status(this) === "destroyed") { // insert might trigger a re-render which might destroy the current component - this.chatter.delete(); + this.deleteLocalChatter(); return; } /** @@ -90,7 +96,9 @@ export class ChatterContainer extends Component { * calling the props change method but it is in general not a good * assumption to make. */ - this.chatter.refresh(); + if (chatter.thread) { + chatter.refresh(); + } this.render(); } @@ -99,6 +107,10 @@ export class ChatterContainer extends Component { Object.assign(ChatterContainer, { components: { Chatter: getMessagingComponent('Chatter') }, props: { + chatter: { + type: Object, + optional: true, + }, className: { type: String, optional: true, diff --git a/addons/mail/static/src/components/chatter_container/chatter_container.xml b/addons/mail/static/src/components/chatter_container/chatter_container.xml index 5ab821d3e87..45240c9a2b5 100644 --- a/addons/mail/static/src/components/chatter_container/chatter_container.xml +++ b/addons/mail/static/src/components/chatter_container/chatter_container.xml @@ -3,7 +3,7 @@
- + diff --git a/addons/mail/static/src/models/chatter.js b/addons/mail/static/src/models/chatter.js index d3d2ab706ce..227311bf853 100644 --- a/addons/mail/static/src/models/chatter.js +++ b/addons/mail/static/src/models/chatter.js @@ -172,6 +172,9 @@ registerModel({ * @private */ _onThreadIdOrThreadModelChanged() { + if (!this.threadModel) { + return; + } if (this.threadId) { if (this.thread && this.thread.isTemporary) { this.thread.delete(); @@ -261,6 +264,9 @@ registerModel({ }), dropZoneView: one('DropZoneView', { compute() { + if (!this.thread) { + return clear(); + } if (this.useDragVisibleDropZone.isVisible) { return {}; } @@ -403,6 +409,9 @@ registerModel({ */ threadViewer: one('ThreadViewer', { compute() { + if (!this.thread) { + return clear(); + } return { hasThreadView: this.hasThreadView, order: 'desc', @@ -410,10 +419,11 @@ registerModel({ }; }, inverse: 'chatter', - required: true, }), topbar: one('ChatterTopbar', { - default: {}, + compute() { + return this.thread ? {} : clear(); + }, inverse: 'chatter', }), useDragVisibleDropZone: one('UseDragVisibleDropZone', { diff --git a/addons/mail/static/src/models/follower_list_menu_view.js b/addons/mail/static/src/models/follower_list_menu_view.js index 78fe25ed49d..48da5184cc7 100644 --- a/addons/mail/static/src/models/follower_list_menu_view.js +++ b/addons/mail/static/src/models/follower_list_menu_view.js @@ -54,7 +54,7 @@ registerModel({ return; } // since dropdown is conditionally shown based on state, dropdownRef can be null - if (this.dropdownRef.el && !this.dropdownRef.el.contains(ev.target)) { + if (this.dropdownRef && this.dropdownRef.el && !this.dropdownRef.el.contains(ev.target)) { this.hide(); } }, diff --git a/addons/mail/static/src/views/form/form_compiler.js b/addons/mail/static/src/views/form/form_compiler.js index 7e750ab1a1f..aa5bbcfe179 100644 --- a/addons/mail/static/src/views/form/form_compiler.js +++ b/addons/mail/static/src/views/form/form_compiler.js @@ -37,6 +37,7 @@ function compileChatter(node, params) { } const chatterContainerXml = createElement("ChatterContainer"); setAttributes(chatterContainerXml, { + "chatter": params.chatter, "hasActivities": hasActivities, "hasFollowers": hasFollowers, "hasMessageList": hasMessageList, @@ -116,6 +117,7 @@ export class MailFormCompiler extends ViewCompiler { compileChatter(node) { return compileChatter(node, { + chatter: "chatter", threadId: "model.root.resId or undefined", threadModel: "model.root.resModel", webRecord: "model.root", @@ -134,6 +136,7 @@ registry.category("form_compilers").add("chatter_compiler", { selector: "div.oe_chatter", fn: (node) => compileChatter(node, { + chatter: "props.chatter", threadId: "props.record.resId or undefined", threadModel: "props.record.resModel", webRecord: "props.record", diff --git a/addons/mail/static/src/views/form/form_controller.js b/addons/mail/static/src/views/form/form_controller.js index 69525a5d54c..cf074655e88 100644 --- a/addons/mail/static/src/views/form/form_controller.js +++ b/addons/mail/static/src/views/form/form_controller.js @@ -1,7 +1,7 @@ /** @odoo-module */ import { useModels } from "@mail/component_hooks/use_models"; -import { ChatterContainer } from "@mail/components/chatter_container/chatter_container"; +import { ChatterContainer, getChatterNextTemporaryId } from "@mail/components/chatter_container/chatter_container"; import { WebClientViewAttachmentViewContainer } from "@mail/components/web_client_view_attachment_view_container/web_client_view_attachment_view_container"; import { browser } from "@web/core/browser/browser"; @@ -15,16 +15,27 @@ import { evalDomain } from "@web/views/utils"; import { MailFormCompiler } from "./form_compiler"; -const { onMounted, onWillUnmount } = owl; +const { onMounted, onWillDestroy, onWillUnmount } = owl; patch(FormController.prototype, "mail", { setup() { this._super(); this.uiService = useService("ui"); this.hasAttachmentViewerInArch = false; + this.chatter = undefined; if (this.env.services.messaging) { useModels(); + this.env.services.messaging.modelManager.messagingCreatedPromise.then(() => { + if (owl.status(this) === "destroyed") { + return; + } + const messaging = this.env.services.messaging.modelManager.messaging; + this.chatter = messaging.models['Chatter'].insert({ id: getChatterNextTemporaryId() }); + if (owl.status(this) === "destroyed") { + this.chatter.delete(); + } + }); } const { archInfo } = this.props; @@ -49,6 +60,11 @@ patch(FormController.prototype, "mail", { this.onResize = useDebounced(this.render, 200); onMounted(() => browser.addEventListener("resize", this.onResize)); onWillUnmount(() => browser.removeEventListener("resize", this.onResize)); + onWillDestroy(() => { + if (this.chatter && this.chatter.exists()) { + this.chatter.delete(); + } + }); }, /** * @returns {Messaging|undefined} diff --git a/addons/mail/static/src/views/form/form_controller.xml b/addons/mail/static/src/views/form/form_controller.xml index 2e30944ce92..c56f5653f92 100644 --- a/addons/mail/static/src/views/form/form_controller.xml +++ b/addons/mail/static/src/views/form/form_controller.xml @@ -8,6 +8,7 @@ + chatter hasAttachmentViewerInArch hasAttachmentViewer()