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()