odoo18/addons_extensions/knowledge/static/src/web/chatter_patch.js

110 lines
5.2 KiB
JavaScript

/** @odoo-module */
import { useService } from "@web/core/utils/hooks";
import { Deferred, KeepLast } from "@web/core/utils/concurrency";
import { patch } from "@web/core/utils/patch";
import { Chatter } from "@mail/chatter/web_portal/chatter";
import { useCallbackRecorder } from "@web/search/action_hook";
import {
onWillUnmount,
useEffect,
} from "@odoo/owl";
/**
* Knowledge articles can interact with some records with the help of the
* @see KnowledgeCommandsService .
* If any record in a form view has a chatter with the ability to send message
* and/or attach files, they are a potential target for Knowledge macros.
*/
const ChatterPatch = {
setup() {
super.setup(...arguments);
if (this.env.__knowledgeUpdateCommandsRecordInfo__) {
this.knowledgeCommandsService = useService("knowledgeCommandsService");
// Only keep the last request to register a recordInfo active.
const keepLastRecordInfoRequest = new KeepLast();
// Keep track of the fact that the chatter thread is ready and has
// loaded its access rights.
let chatterThreadReady = new Deferred();
let previousThreadId = this.props.threadId;
useEffect(
// Access rights of the current thread of the chatter are
// populated asynchronously after the chatter is mounted, this
// method keeps track of those changes in order to determine
// when a recordInfo request can be evaluated.
(threadId, canPostOnReadonly, hasReadAccess, hasWriteAccess) => {
if (previousThreadId !== threadId) {
// If the chatter changes threadId, resolve the current
// promise keeping track of the thread state to false,
// so that an ongoing request to evaluate a recordInfo
// (related to the previous thread) will be discarded.
chatterThreadReady.resolve(false);
chatterThreadReady = new Deferred();
}
if (
canPostOnReadonly !== undefined &&
hasReadAccess !== undefined &&
hasWriteAccess !== undefined
) {
// When the access rights are all loaded, the thread
// is ready and a recordInfo request can be evaluated.
chatterThreadReady.resolve(true);
}
previousThreadId = threadId;
},
() => [
this.props.threadId,
this.state.thread?.canPostOnReadonly,
this.state.thread?.hasReadAccess,
this.state.thread?.hasWriteAccess,
]
);
onWillUnmount(() => {
// If there is an ongoing request to evaluate a recordInfo,
// discard it.
chatterThreadReady.resolve(false);
});
useCallbackRecorder(
this.env.__knowledgeUpdateCommandsRecordInfo__,
// Callback used to record the values related to the ability to
// post messages or attach files on the current record.
async (recordInfo) => {
// At each new recording request, all previous ongoing
// requests are discarded through the keepLast.
const chatterThreadReadyForRecordInfo = keepLastRecordInfoRequest.add(chatterThreadReady);
if (!await chatterThreadReadyForRecordInfo) {
// If the chatterThreadReadyForRecordInfo promise
// resolves to false, the recording request should be
// discarded.
return;
}
if (
!this.env.model.root?.resId ||
recordInfo.resId !== this.env.model.root.resId ||
recordInfo.resModel !== this.env.model.root.resModel
) {
// Ensure that the current record matches the recordInfo
// candidate.
return;
}
// The conditions for the ability to post or attach should
// be the same as the ones in the Chatter template.
Object.assign(recordInfo, {
canPostMessages:
this.props.threadId &&
(this.state.thread?.hasWriteAccess ||
(this.state.thread?.hasReadAccess &&
this.state.thread?.canPostOnReadonly)),
canAttachFiles: this.props.threadId && this.state.thread?.hasWriteAccess,
});
if (this.knowledgeCommandsService.isRecordCompatibleWithMacro(recordInfo)) {
this.knowledgeCommandsService.setCommandsRecordInfo(recordInfo);
}
}
);
}
}
};
patch(Chatter.prototype, ChatterPatch);