[REF] mail: introduce id & get() on all discuss models
1. Introduce `static id` to all models, to uniquely identify
a record in a model. This allows normalizing discuss store
for all models, which helps as preparation for managing
record deletion. Can also be combined
```js
class Message {
static id = "id";
id;
}
class Thread {
static id = AND("model", "id");
}
```
2. Introduce `Model.get()` to easily get a record of model
from data that can identify the record. This prevent leaking
the way the record are stored in `records`, as now all records
are indexed by localId, and localId is technical detail.
```js
Message.get(messageId);
Thread.get({ model: "discuss.channel", id: 1 });
```
Part-of: odoo/odoo#134008
This commit is contained in:
@@ -2,13 +2,13 @@
|
||||
|
||||
import { DEFAULT_AVATAR } from "@mail/core/common/persona_service";
|
||||
import { Thread } from "@mail/core/common/thread_model";
|
||||
import { assignDefined, createLocalId } from "@mail/utils/common/misc";
|
||||
import { assignDefined } from "@mail/utils/common/misc";
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(Thread, {
|
||||
insert(data) {
|
||||
const isUnknown = !(createLocalId(data.model, data.id) in this.records);
|
||||
const isUnknown = !this.get(data);
|
||||
const thread = super.insert(data);
|
||||
if (thread.type === "livechat") {
|
||||
if (data?.channel) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Thread } from "@mail/core/common/thread_model";
|
||||
import { createLocalId, onChange } from "@mail/utils/common/misc";
|
||||
import { onChange } from "@mail/utils/common/misc";
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { session } from "@web/session";
|
||||
@@ -9,7 +9,7 @@ import { SESSION_STATE } from "./livechat_service";
|
||||
|
||||
patch(Thread, {
|
||||
insert(data) {
|
||||
const isUnknown = !(createLocalId(data.model, data.id) in this.records);
|
||||
const isUnknown = !this.get(data);
|
||||
const thread = super.insert(...arguments);
|
||||
const livechatService = this.env.services["im_livechat.livechat"];
|
||||
const chatbotService = this.env.services["im_livechat.chatbot"];
|
||||
|
||||
@@ -7,6 +7,7 @@ import { deserializeDateTime } from "@web/core/l10n/dates";
|
||||
import { url } from "@web/core/utils/urls";
|
||||
|
||||
export class Attachment extends Record {
|
||||
static id = "id";
|
||||
/** @type {Object.<number, Attachment>} */
|
||||
static records = {};
|
||||
|
||||
@@ -18,10 +19,11 @@ export class Attachment extends Record {
|
||||
if (!("id" in data)) {
|
||||
throw new Error("Cannot insert attachment: id is missing in data");
|
||||
}
|
||||
let attachment = this.records[data.id];
|
||||
let attachment = this.get(data);
|
||||
if (!attachment) {
|
||||
this.records[data.id] = new Attachment();
|
||||
attachment = this.records[data.id];
|
||||
attachment = this.new(data);
|
||||
this.records[attachment.localId] = attachment;
|
||||
attachment = this.records[attachment.localId];
|
||||
Object.assign(attachment, { _store: this.store, id: data.id });
|
||||
}
|
||||
this.env.services["mail.attachment"].update(attachment, data);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { removeFromArrayWithPredicate } from "@mail/utils/common/arrays";
|
||||
import { assignDefined, createLocalId } from "@mail/utils/common/misc";
|
||||
import { assignDefined } from "@mail/utils/common/misc";
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
@@ -46,7 +46,7 @@ export class AttachmentService {
|
||||
model: threadData.model,
|
||||
id: threadData.id,
|
||||
});
|
||||
attachment.originThreadLocalId = createLocalId(threadData.model, threadData.id);
|
||||
attachment.originThreadLocalId = this.store.Thread.localId(threadData);
|
||||
const thread = attachment.originThread;
|
||||
if (attachment.notIn(thread.attachments)) {
|
||||
thread.attachments.push(attachment);
|
||||
@@ -64,7 +64,7 @@ export class AttachmentService {
|
||||
if (attachment.tmpUrl) {
|
||||
URL.revokeObjectURL(attachment.tmpUrl);
|
||||
}
|
||||
delete this.store.Attachment.records[attachment.id];
|
||||
delete this.store.Attachment.records[attachment.localId];
|
||||
if (attachment.originThread) {
|
||||
removeFromArrayWithPredicate(attachment.originThread.attachments, (att) =>
|
||||
att.eq(attachment)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { Deferred } from "@web/core/utils/concurrency";
|
||||
@@ -83,8 +82,7 @@ export class AttachmentUploadService {
|
||||
}
|
||||
const threadId = parseInt(upload.data.get("thread_id"));
|
||||
const threadModel = upload.data.get("thread_model");
|
||||
const originThread =
|
||||
this.store.Thread.records[createLocalId(threadModel, threadId)];
|
||||
const originThread = this.store.Thread.get({ model: threadModel, id: threadId });
|
||||
const attachment = this.store.Attachment.insert({
|
||||
...response,
|
||||
extension: upload.title.split(".").pop(),
|
||||
@@ -99,7 +97,7 @@ export class AttachmentUploadService {
|
||||
}
|
||||
}
|
||||
const def = this.deferredByAttachmentId.get(tmpId);
|
||||
this.unlink(this.store.Attachment.records[tmpId]);
|
||||
this.unlink(this.store.Attachment.get(tmpId));
|
||||
if (def) {
|
||||
def.resolve(attachment);
|
||||
this.deferredByAttachmentId.delete(tmpId);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { Record } from "@mail/core/common/record";
|
||||
|
||||
export class CannedResponse extends Record {
|
||||
static id = "id";
|
||||
/** @type {Object.<number, CannedResponse>} */
|
||||
static records = {};
|
||||
/**
|
||||
@@ -10,10 +11,11 @@ export class CannedResponse extends Record {
|
||||
* @returns {CannedResponse}
|
||||
*/
|
||||
static insert(data) {
|
||||
let cannedResponse = this.records[data.id];
|
||||
let cannedResponse = this.get(data);
|
||||
if (!cannedResponse) {
|
||||
this.records[data.id] = new CannedResponse();
|
||||
cannedResponse = this.records[data.id];
|
||||
cannedResponse = this.new(data);
|
||||
this.records[cannedResponse.localId] = cannedResponse;
|
||||
cannedResponse = this.records[cannedResponse.localId];
|
||||
}
|
||||
Object.assign(cannedResponse, {
|
||||
id: data.id,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Record } from "@mail/core/common/record";
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
|
||||
/**
|
||||
* @class ChannelMember
|
||||
@@ -11,6 +10,7 @@ import { createLocalId } from "@mail/utils/common/misc";
|
||||
* @property {number} threadId
|
||||
*/
|
||||
export class ChannelMember extends Record {
|
||||
static id = "id";
|
||||
/** @type {Object.<number, ChannelMember>} */
|
||||
static records = {};
|
||||
/**
|
||||
@@ -19,10 +19,11 @@ export class ChannelMember extends Record {
|
||||
*/
|
||||
static insert(data) {
|
||||
const memberData = Array.isArray(data) ? data[1] : data;
|
||||
let member = this.records[memberData.id];
|
||||
let member = this.get(memberData);
|
||||
if (!member) {
|
||||
this.records[memberData.id] = new ChannelMember();
|
||||
member = this.records[memberData.id];
|
||||
member = this.new(memberData);
|
||||
this.records[member.localId] = member;
|
||||
member = this.records[member.localId];
|
||||
member._store = this.store;
|
||||
}
|
||||
this.env.services["discuss.channel.member"].update(member, data);
|
||||
@@ -46,11 +47,11 @@ export class ChannelMember extends Record {
|
||||
}
|
||||
|
||||
get rtcSession() {
|
||||
return this._store.RtcSession.records[this.rtcSessionId];
|
||||
return this._store.RtcSession.get(this.rtcSessionId);
|
||||
}
|
||||
|
||||
get thread() {
|
||||
return this._store.Thread.records[createLocalId("discuss.channel", this.threadId)];
|
||||
return this._store.Thread.get({ model: "discuss.channel", id: this.threadId });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ import { _t } from "@web/core/l10n/translation";
|
||||
/** @typedef {{ thread?: import("@mail/core/common/thread_model").Thread, folded?: boolean, replaceNewMessageChatWindow?: boolean }} ChatWindowData */
|
||||
|
||||
export class ChatWindow extends Record {
|
||||
static id = "threadLocalId";
|
||||
/** @type {ChatWindow[]} */
|
||||
static records = [];
|
||||
/**
|
||||
@@ -17,7 +18,7 @@ export class ChatWindow extends Record {
|
||||
static insert(data = {}) {
|
||||
const chatWindow = this.records.find((c) => c.threadLocalId === data.thread?.localId);
|
||||
if (!chatWindow) {
|
||||
const chatWindow = new ChatWindow();
|
||||
const chatWindow = this.new(data);
|
||||
Object.assign(chatWindow, {
|
||||
thread: data.thread,
|
||||
_store: this.store,
|
||||
|
||||
@@ -554,8 +554,9 @@ export class Composer extends Component {
|
||||
* @param {postData} postData Message meta data info
|
||||
*/
|
||||
async _sendMessage(value, postData) {
|
||||
const thread = this.props.composer.thread;
|
||||
await this.threadService.post(this.thread, value, postData);
|
||||
if (this.props.composer.thread.type === "mailbox") {
|
||||
if (thread.type === "mailbox") {
|
||||
this.notifySendFromMailbox();
|
||||
}
|
||||
this.suggestion?.clearRawMentions();
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Record } from "@mail/core/common/record";
|
||||
import { OR, Record } from "@mail/core/common/record";
|
||||
|
||||
/**
|
||||
* @typedef {{partnerIds: Set<number>, threadIds: Set<number>}} RawMentions
|
||||
*/
|
||||
|
||||
export class Composer extends Record {
|
||||
static id = OR("threadLocalId", "messageLocalId");
|
||||
/**
|
||||
* @param {Object} data
|
||||
* @returns {Composer}
|
||||
@@ -18,7 +19,7 @@ export class Composer extends Record {
|
||||
}
|
||||
let composer = (thread ?? message)?.composer;
|
||||
if (!composer) {
|
||||
composer = new Composer();
|
||||
composer = this.new(data);
|
||||
const { message, thread } = data;
|
||||
if (thread) {
|
||||
composer.thread = thread;
|
||||
@@ -51,8 +52,8 @@ export class Composer extends Record {
|
||||
|
||||
/** @type {import("@mail/core/common/attachment_model").Attachment[]} */
|
||||
attachments = [];
|
||||
/** @type {import("@mail/core/common/message_model").Message} */
|
||||
message;
|
||||
/** @type {import("@mail/core/common/message_model").Message.localId} */
|
||||
messageLocalId;
|
||||
/** @type {RawMentions} */
|
||||
rawMentions = {
|
||||
partnerIds: new Set(),
|
||||
@@ -62,8 +63,8 @@ export class Composer extends Record {
|
||||
cannedResponseIds = new Set();
|
||||
/** @type {string} */
|
||||
textInputContent;
|
||||
/** @type {import("@mail/core/common/thread_model").Thread */
|
||||
thread;
|
||||
/** @type {import("@mail/core/common/thread_model").Thread.localId} */
|
||||
threadLocalId;
|
||||
/** @type {{ start: number, end: number, direction: "forward" | "backward" | "none"}}*/
|
||||
selection = {
|
||||
start: 0,
|
||||
@@ -75,6 +76,26 @@ export class Composer extends Record {
|
||||
/** @type {import("@mail/core/common/store_service").Store} */
|
||||
_store;
|
||||
isFocused = false;
|
||||
|
||||
/** @type {import("@mail/core/common/message_model").Message} */
|
||||
get message() {
|
||||
return this._store.Message.records[this.messageLocalId];
|
||||
}
|
||||
|
||||
/** @param {import("@mail/core/common/message_model").Message} */
|
||||
set message(newMessage) {
|
||||
this.messageLocalId = newMessage?.localId;
|
||||
}
|
||||
|
||||
/** @type {import("@mail/core/common/thread_model").Thread} */
|
||||
get thread() {
|
||||
return this._store.Thread.records[this.threadLocalId];
|
||||
}
|
||||
|
||||
/** @param {import("@mail/core/common/thread_model").Thread} */
|
||||
set thread(newThread) {
|
||||
this.threadLocalId = newThread?.localId;
|
||||
}
|
||||
}
|
||||
|
||||
Composer.register();
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Record } from "@mail/core/common/record";
|
||||
*/
|
||||
|
||||
export class Follower extends Record {
|
||||
static id = "id";
|
||||
/** @type {Object.<number, Follower>} */
|
||||
static records = {};
|
||||
/**
|
||||
@@ -18,10 +19,11 @@ export class Follower extends Record {
|
||||
* @returns {Follower}
|
||||
*/
|
||||
static insert(data) {
|
||||
let follower = this.records[data.id];
|
||||
let follower = this.get(data);
|
||||
if (!follower) {
|
||||
this.records[data.id] = new Follower();
|
||||
follower = this.records[data.id];
|
||||
follower = this.new(data);
|
||||
this.records[follower.localId] = follower;
|
||||
follower = this.records[follower.localId];
|
||||
}
|
||||
Object.assign(follower, {
|
||||
followedThread: data.followedThread,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { Record } from "@mail/core/common/record";
|
||||
|
||||
export class LinkPreview extends Record {
|
||||
static id = "id";
|
||||
/**
|
||||
* @param {Object} data
|
||||
* @returns {LinkPreview}
|
||||
@@ -12,9 +13,9 @@ export class LinkPreview extends Record {
|
||||
if (linkPreview) {
|
||||
return Object.assign(linkPreview, data);
|
||||
}
|
||||
linkPreview = new LinkPreview();
|
||||
linkPreview = this.new(data);
|
||||
Object.assign(linkPreview, data);
|
||||
this.store.Message.records[data.message.id]?.linkPreviews.push(linkPreview);
|
||||
this.store.Message.get(data.message.id)?.linkPreviews.push(linkPreview);
|
||||
return linkPreview;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,14 +28,14 @@ export class MailCoreCommon {
|
||||
if (messageData) {
|
||||
this.store.Message.insert({ ...messageData });
|
||||
}
|
||||
const attachment = this.store.Attachment.records[attachmentId];
|
||||
const attachment = this.store.Attachment.get(attachmentId);
|
||||
if (attachment) {
|
||||
this.attachmentService.remove(attachment);
|
||||
}
|
||||
});
|
||||
this.busService.subscribe("mail.link.preview/delete", (payload) => {
|
||||
const { id, message_id } = payload;
|
||||
const message = this.store.Message.records[message_id];
|
||||
const message = this.store.Message.get(message_id);
|
||||
if (message) {
|
||||
removeFromArrayWithPredicate(
|
||||
message.linkPreviews,
|
||||
@@ -45,11 +45,11 @@ export class MailCoreCommon {
|
||||
});
|
||||
this.busService.subscribe("mail.message/delete", (payload) => {
|
||||
for (const messageId of payload.message_ids) {
|
||||
const message = this.store.Message.records[messageId];
|
||||
const message = this.store.Message.get(messageId);
|
||||
if (!message) {
|
||||
continue;
|
||||
}
|
||||
delete this.store.Message.records[messageId];
|
||||
delete this.store.Message.records[this.store.Message.localId(messageId)];
|
||||
if (message.originThread) {
|
||||
removeFromArrayWithPredicate(message.originThread.messages, (msg) =>
|
||||
msg.eq(message)
|
||||
@@ -100,14 +100,14 @@ export class MailCoreCommon {
|
||||
const { LinkPreview: linkPreviews } = payload;
|
||||
if (linkPreviews) {
|
||||
for (const linkPreview of linkPreviews) {
|
||||
this.store.Message.records[linkPreview.message.id]?.linkPreviews.push(
|
||||
this.store.Message.get(linkPreview.message.id)?.linkPreviews.push(
|
||||
this.store.LinkPreview.insert(linkPreview)
|
||||
);
|
||||
}
|
||||
}
|
||||
const { Message: messageData } = payload;
|
||||
if (messageData) {
|
||||
const isStarred = this.store.Message.records[messageData.id]?.isStarred;
|
||||
const isStarred = this.store.Message.get(messageData.id)?.isStarred;
|
||||
const message = this.store.Message.insert({
|
||||
...messageData,
|
||||
body: messageData.body ? markup(messageData.body) : messageData.body,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { Record } from "@mail/core/common/record";
|
||||
import { htmlToTextContentInline } from "@mail/utils/common/format";
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
|
||||
import { toRaw } from "@odoo/owl";
|
||||
|
||||
@@ -14,6 +13,7 @@ import { url } from "@web/core/utils/urls";
|
||||
const { DateTime } = luxon;
|
||||
|
||||
export class Message extends Record {
|
||||
static id = "id";
|
||||
/** @type {Object.<number, Message>} */
|
||||
static records = {};
|
||||
/**
|
||||
@@ -28,13 +28,12 @@ export class Message extends Record {
|
||||
id: data.res_id,
|
||||
});
|
||||
}
|
||||
if (data.id in this.records) {
|
||||
message = this.records[data.id];
|
||||
} else {
|
||||
message = new Message();
|
||||
message = this.get(data);
|
||||
if (!message) {
|
||||
message = this.new(data);
|
||||
message._store = this.store;
|
||||
this.records[data.id] = message;
|
||||
message = this.records[data.id];
|
||||
this.records[message.localId] = message;
|
||||
message = this.records[message.localId];
|
||||
}
|
||||
this.env.services["mail.message"].update(message, data);
|
||||
// return reactive version
|
||||
@@ -196,7 +195,7 @@ export class Message extends Record {
|
||||
}
|
||||
|
||||
get originThread() {
|
||||
return this._store.Thread.records[createLocalId(this.resModel, this.resId)];
|
||||
return this._store.Thread.get({ model: this.resModel, id: this.resId });
|
||||
}
|
||||
|
||||
get resUrl() {
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Record } from "@mail/core/common/record";
|
||||
import { AND, Record } from "@mail/core/common/record";
|
||||
|
||||
export class MessageReactions extends Record {
|
||||
static id = AND("messageId", "content");
|
||||
/**
|
||||
* @param {Object} data
|
||||
* @returns {MessageReactions}
|
||||
*/
|
||||
static insert(data) {
|
||||
let reaction = this.store.Message.records[data.message.id]?.reactions.find(
|
||||
let reaction = this.store.Message.get(data.message.id)?.reactions.find(
|
||||
({ content }) => content === data.content
|
||||
);
|
||||
if (!reaction) {
|
||||
reaction = new MessageReactions();
|
||||
reaction = this.new(data);
|
||||
reaction._store = this.store;
|
||||
}
|
||||
const personasToUnlink = new Set();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { removeFromArrayWithPredicate, replaceArrayWithCompare } from "@mail/utils/common/arrays";
|
||||
import { convertBrToLineBreak, prettifyMessageContent } from "@mail/utils/common/format";
|
||||
import { assignDefined, createLocalId } from "@mail/utils/common/misc";
|
||||
import { assignDefined } from "@mail/utils/common/misc";
|
||||
|
||||
import { markup } from "@odoo/owl";
|
||||
|
||||
@@ -96,7 +96,7 @@ export class MessageService {
|
||||
const rawMentionedPartnerIds = rawMentions.partnerIds || [];
|
||||
const rawMentionedThreadIds = rawMentions.threadIds || [];
|
||||
for (const partnerId of rawMentionedPartnerIds) {
|
||||
const partner = this.store.Persona.records[createLocalId("partner", partnerId)];
|
||||
const partner = this.store.Persona.get({ type: "partner", id: partnerId });
|
||||
const index = body.indexOf(`@${partner.name}`);
|
||||
if (index === -1) {
|
||||
continue;
|
||||
@@ -104,7 +104,7 @@ export class MessageService {
|
||||
partners.push(partner);
|
||||
}
|
||||
for (const threadId of rawMentionedThreadIds) {
|
||||
const thread = this.store.Thread.records[createLocalId("discuss.channel", threadId)];
|
||||
const thread = this.store.Thread.get({ model: "discuss.channel", id: threadId });
|
||||
const index = body.indexOf(`#${thread.displayName}`);
|
||||
if (index === -1) {
|
||||
continue;
|
||||
|
||||
@@ -7,6 +7,7 @@ import { _t } from "@web/core/l10n/translation";
|
||||
|
||||
let nextId = 1;
|
||||
export class NotificationGroup extends Record {
|
||||
static id = "id";
|
||||
/** @type {NotificationGroup[]} */
|
||||
static records = [];
|
||||
/**
|
||||
@@ -22,10 +23,10 @@ export class NotificationGroup extends Record {
|
||||
);
|
||||
});
|
||||
if (!group) {
|
||||
group = new NotificationGroup();
|
||||
group._store = this.store;
|
||||
const id = nextId++;
|
||||
group = this.new({ id });
|
||||
Object.assign(group, { id, _store: this.store });
|
||||
this.store.NotificationGroup.records.push(group);
|
||||
group.id = nextId++;
|
||||
// return reactive
|
||||
group = this.store.NotificationGroup.records.find((g) => g.eq(group));
|
||||
}
|
||||
@@ -60,7 +61,7 @@ export class NotificationGroup extends Record {
|
||||
}
|
||||
|
||||
get lastMessage() {
|
||||
return this._store.Message.records[this.lastMessageId];
|
||||
return this._store.Message.get(this.lastMessageId);
|
||||
}
|
||||
|
||||
get datetime() {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Record } from "@mail/core/common/record";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
|
||||
export class Notification extends Record {
|
||||
static id = "id";
|
||||
/** @type {Object.<number, Notification>} */
|
||||
static records = {};
|
||||
/**
|
||||
@@ -12,15 +13,15 @@ export class Notification extends Record {
|
||||
* @returns {Notification}
|
||||
*/
|
||||
static insert(data) {
|
||||
let notification = this.records[data.id];
|
||||
let notification = this.get(data);
|
||||
if (!notification) {
|
||||
notification = new Notification();
|
||||
this.records[data.id] = notification;
|
||||
notification = this.new(data);
|
||||
this.records[notification.localId] = notification;
|
||||
Object.assign(notification, {
|
||||
id: data.id,
|
||||
_store: this.store,
|
||||
});
|
||||
notification = this.records[data.id];
|
||||
notification = this.records[notification.localId];
|
||||
}
|
||||
this.env.services["mail.message"].updateNotification(notification, data);
|
||||
return notification;
|
||||
@@ -42,7 +43,7 @@ export class Notification extends Record {
|
||||
_store;
|
||||
|
||||
get message() {
|
||||
return this._store.Message.records[this.messageId];
|
||||
return this._store.Message.get(this.messageId);
|
||||
}
|
||||
|
||||
get isFailure() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Record } from "@mail/core/common/record";
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
import { AND, Record } from "@mail/core/common/record";
|
||||
|
||||
/**
|
||||
* @typedef {'offline' | 'bot' | 'online' | 'away' | 'im_partner' | undefined} ImStatus
|
||||
@@ -14,6 +13,7 @@ import { createLocalId } from "@mail/utils/common/misc";
|
||||
*/
|
||||
|
||||
export class Persona extends Record {
|
||||
static id = AND("type", "id");
|
||||
/** @type {Object.<number, Persona>} */
|
||||
static records = {};
|
||||
/**
|
||||
@@ -21,17 +21,16 @@ export class Persona extends Record {
|
||||
* @returns {Persona}
|
||||
*/
|
||||
static insert(data) {
|
||||
const localId = createLocalId(data.type, data.id);
|
||||
let persona = this.records[localId];
|
||||
let persona = this.get(data);
|
||||
if (!persona) {
|
||||
persona = new Persona();
|
||||
persona = this.new(data);
|
||||
persona._store = this.store;
|
||||
persona.localId = localId;
|
||||
this.records[localId] = persona;
|
||||
this.records[persona.localId] = persona;
|
||||
persona = this.records[persona.localId];
|
||||
}
|
||||
this.env.services["mail.persona"].update(persona, data);
|
||||
// return reactive version
|
||||
return this.records[localId];
|
||||
return persona;
|
||||
}
|
||||
|
||||
/** @type {string} */
|
||||
|
||||
@@ -5,11 +5,71 @@ import { registry } from "@web/core/registry";
|
||||
|
||||
export const modelRegistry = registry.category("discuss.model");
|
||||
|
||||
const OR_SYM = Symbol("or");
|
||||
const AND_SYM = Symbol("and");
|
||||
|
||||
export function AND(...args) {
|
||||
return [AND_SYM, ...args];
|
||||
}
|
||||
export function OR(...args) {
|
||||
return [OR_SYM, ...args];
|
||||
}
|
||||
|
||||
export class Record {
|
||||
static id;
|
||||
static records = {};
|
||||
static get(data) {
|
||||
return this.records[this.localId(data)];
|
||||
}
|
||||
static modelFromLocalId(localId) {
|
||||
return localId.split(",")[0];
|
||||
}
|
||||
static register() {
|
||||
modelRegistry.add(this.name, this);
|
||||
}
|
||||
static localId(data) {
|
||||
let idStr;
|
||||
if (typeof data === "object") {
|
||||
idStr = this._localId(this.id, data);
|
||||
} else {
|
||||
idStr = data; // non-object data => single id
|
||||
}
|
||||
return `${this.name},${idStr}`;
|
||||
}
|
||||
static _localId(expr, data, { brackets = false } = {}) {
|
||||
if (!Array.isArray(expr)) {
|
||||
return data[expr];
|
||||
}
|
||||
const vals = [];
|
||||
for (let i = 1; i < expr.length; i++) {
|
||||
vals.push(this._localId(expr[i], data, { brackets: true }));
|
||||
}
|
||||
let res = vals.join(expr[0] === OR_SYM ? " OR " : " AND ");
|
||||
if (brackets) {
|
||||
res = `(${res})`;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* Technical attribute, DO NOT USE in business code.
|
||||
* This class is almost equivalent to current class of model,
|
||||
* except this is a function, so we can new() it, whereas
|
||||
* `this` is not, because it's an object.
|
||||
* (in order to comply with OWL reactivity)
|
||||
*
|
||||
* @type {typeof Record}
|
||||
*/
|
||||
static Class;
|
||||
/**
|
||||
* This method is almost equivalent to new Class, except that it properly
|
||||
* setup relational fields of model with get/set, @see Class
|
||||
*
|
||||
* @returns {Record}
|
||||
*/
|
||||
static new(data) {
|
||||
const obj = new this.Class();
|
||||
return Object.assign(obj, { localId: this.localId(data) });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} data
|
||||
@@ -29,6 +89,9 @@ export class Record {
|
||||
|
||||
/** @param {Record[]} list */
|
||||
in(list) {
|
||||
if (!list) {
|
||||
return false;
|
||||
}
|
||||
return list.some((record) => record.eq(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -187,6 +187,7 @@ export const storeService = {
|
||||
// work-around: make an object whose prototype is the class, so that static props become
|
||||
// instance props.
|
||||
const entry = Object.assign(Object.create(Model), { env, store: res });
|
||||
entry.Class = Model;
|
||||
entry.records = JSON.parse(JSON.stringify(Model.records));
|
||||
res[name] = entry;
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ export class Thread extends Component {
|
||||
const { oeType, oeId } = ev.target.dataset;
|
||||
if (oeType === "highlight") {
|
||||
await this.env.messageHighlight?.highlightMessage(
|
||||
this.store.Message.records[Number(oeId)],
|
||||
this.store.Message.get(Number(oeId)),
|
||||
this.props.thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
|
||||
import { Component, useState } from "@odoo/owl";
|
||||
@@ -26,8 +24,6 @@ export class ThreadIcon extends Component {
|
||||
}
|
||||
|
||||
get chatPartner() {
|
||||
return this.store.Persona.records[
|
||||
createLocalId("partner", this.props.thread.chatPartnerId)
|
||||
];
|
||||
return this.store.Persona.get({ type: "partner", id: this.props.thread.chatPartnerId });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Record } from "@mail/core/common/record";
|
||||
import { AND, Record } from "@mail/core/common/record";
|
||||
import { ScrollPosition } from "@mail/core/common/scroll_position";
|
||||
import { createLocalId, onChange } from "@mail/utils/common/misc";
|
||||
import { onChange } from "@mail/utils/common/misc";
|
||||
|
||||
import { deserializeDateTime } from "@web/core/l10n/dates";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
@@ -22,8 +22,20 @@ import { Deferred } from "@web/core/utils/concurrency";
|
||||
*/
|
||||
|
||||
export class Thread extends Record {
|
||||
static id = AND("model", "id");
|
||||
/** @type {Object.<string, Thread>} */
|
||||
static records = {};
|
||||
/**
|
||||
* @param {Thread.localId} localId
|
||||
* @returns {string}
|
||||
*/
|
||||
static localIdToActiveId(localId) {
|
||||
if (!localId) {
|
||||
return undefined;
|
||||
}
|
||||
// Transform "Thread,<model> AND <id>" to "<model>_<id>""
|
||||
return localId.split(",").slice(1).join("_").replace(" AND ", "_");
|
||||
}
|
||||
/**
|
||||
* @param {Object} data
|
||||
* @returns {Thread}
|
||||
@@ -35,13 +47,12 @@ export class Thread extends Record {
|
||||
if (!("model" in data)) {
|
||||
throw new Error("Cannot insert thread: model is missing in data");
|
||||
}
|
||||
const localId = createLocalId(data.model, data.id);
|
||||
if (localId in this.records) {
|
||||
const thread = this.records[localId];
|
||||
let thread = this.get(data);
|
||||
if (thread) {
|
||||
this.env.services["mail.thread"].update(thread, data);
|
||||
return thread;
|
||||
}
|
||||
let thread = new Thread();
|
||||
thread = this.new(data);
|
||||
Object.assign(thread, {
|
||||
id: data.id,
|
||||
model: data.model,
|
||||
@@ -192,7 +203,7 @@ export class Thread extends Record {
|
||||
}
|
||||
|
||||
get activeRtcSession() {
|
||||
return this._store.RtcSession.records[this.activeRtcSessionId];
|
||||
return this._store.RtcSession.get(this.activeRtcSessionId);
|
||||
}
|
||||
|
||||
set activeRtcSession(session) {
|
||||
@@ -263,7 +274,7 @@ export class Thread extends Record {
|
||||
if (this.type === "chat" && this.chatPartnerId) {
|
||||
return (
|
||||
this.customName ||
|
||||
this._store.Persona.records[createLocalId("partner", this.chatPartnerId)]
|
||||
this._store.Persona.get({ type: "partner", id: this.chatPartnerId })
|
||||
.nameOrDisplayName
|
||||
);
|
||||
}
|
||||
@@ -329,10 +340,6 @@ export class Thread extends Record {
|
||||
return null;
|
||||
}
|
||||
|
||||
get localId() {
|
||||
return createLocalId(this.model, this.id);
|
||||
}
|
||||
|
||||
get needactionCounter() {
|
||||
return this.isChatChannel ? this.message_unread_counter : this.message_needaction_counter;
|
||||
}
|
||||
@@ -460,7 +467,7 @@ export class Thread extends Record {
|
||||
}
|
||||
|
||||
get rtcInvitingSession() {
|
||||
return this._store.RtcSession.records[this.invitingRtcSessionId];
|
||||
return this._store.RtcSession.get(this.invitingRtcSessionId);
|
||||
}
|
||||
|
||||
get hasNeedactionMessages() {
|
||||
@@ -493,7 +500,7 @@ export class Thread extends Record {
|
||||
if (previousMessages.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return this._store.Message.records[Math.max(...previousMessages.map((m) => m.id))];
|
||||
return this._store.Message.get(Math.max(...previousMessages.map((m) => m.id)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
replaceArrayWithCompare,
|
||||
} from "@mail/utils/common/arrays";
|
||||
import { prettifyMessageContent } from "@mail/utils/common/format";
|
||||
import { assignDefined, createLocalId, nullifyClearCommands } from "@mail/utils/common/misc";
|
||||
import { assignDefined, nullifyClearCommands } from "@mail/utils/common/misc";
|
||||
|
||||
import { markup } from "@odoo/owl";
|
||||
|
||||
@@ -340,8 +340,7 @@ export class ThreadService {
|
||||
if (ids.length) {
|
||||
const previews = await this.orm.call("discuss.channel", "channel_fetch_preview", [ids]);
|
||||
for (const preview of previews) {
|
||||
const thread =
|
||||
this.store.Thread.records[createLocalId("discuss.channel", preview.id)];
|
||||
const thread = this.store.Thread.get({ model: "discuss.channel", id: preview.id });
|
||||
const data = Object.assign(preview.last_message, {
|
||||
body: markup(preview.last_message.body),
|
||||
});
|
||||
@@ -836,7 +835,7 @@ export class ThreadService {
|
||||
tmpData.guestAuthor = this.store.self;
|
||||
}
|
||||
if (parentId) {
|
||||
tmpData.parentMessage = this.store.Message.records[parentId];
|
||||
tmpData.parentMessage = this.store.Message.get(parentId);
|
||||
}
|
||||
const prettyContent = await prettifyMessageContent(body, params.validMentions);
|
||||
const { emojis } = await loadEmoji();
|
||||
@@ -865,7 +864,7 @@ export class ThreadService {
|
||||
const data = await this.rpc(this.getMessagePostRoute(thread), params);
|
||||
if (thread.type !== "chatter") {
|
||||
removeFromArrayWithPredicate(thread.messages, (msg) => msg.eq(tmpMsg));
|
||||
delete this.store.Message.records[tmpMsg.id];
|
||||
delete this.store.Message.records[this.store.Message.localId(tmpMsg.id)];
|
||||
}
|
||||
if (!data) {
|
||||
return;
|
||||
|
||||
@@ -34,6 +34,7 @@ import { assignDefined } from "@mail/utils/common/misc";
|
||||
*/
|
||||
|
||||
export class Activity extends Record {
|
||||
static id = "id";
|
||||
/** @type {Object.<number, Activity>} */
|
||||
static records = {};
|
||||
|
||||
@@ -44,16 +45,16 @@ export class Activity extends Record {
|
||||
* @returns {Activity}
|
||||
*/
|
||||
static insert(data, { broadcast = true } = {}) {
|
||||
let activity = this.records[data.id];
|
||||
let activity = this.get(data);
|
||||
if (!activity) {
|
||||
activity = new Activity();
|
||||
activity = this.new(data);
|
||||
Object.assign(activity, {
|
||||
id: data.id,
|
||||
_store: this.store,
|
||||
});
|
||||
this.store.Activity.records[data.id] = activity;
|
||||
this.records[activity.localId] = activity;
|
||||
// return reactive
|
||||
activity = this.store.Activity.records[data.id];
|
||||
activity = this.records[activity.localId];
|
||||
}
|
||||
if (data.request_partner_id) {
|
||||
data.request_partner_id = data.request_partner_id[0];
|
||||
|
||||
@@ -78,7 +78,7 @@ export class ActivityService {
|
||||
}
|
||||
|
||||
delete(activity, { broadcast = true } = {}) {
|
||||
delete this.store.Activity.records[activity.id];
|
||||
delete this.store.Activity.records[this.store.Activity.localId(activity.id)];
|
||||
if (broadcast) {
|
||||
this.broadcastChannel?.postMessage({ type: "delete", payload: { id: activity.id } });
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import { Component, onWillStart, onWillUpdateProps, useState } from "@odoo/owl";
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
|
||||
/**
|
||||
* @typedef {Object} Props
|
||||
@@ -45,7 +44,7 @@ export class DiscussClientAction extends Component {
|
||||
const rawActiveId =
|
||||
props.action.context.active_id ??
|
||||
props.action.params?.active_id ??
|
||||
this.store.discuss.threadLocalId?.replace(",", "_") ??
|
||||
this.store.Thread.localIdToActiveId(this.store.discuss.threadLocalId) ??
|
||||
"mail.box_inbox";
|
||||
const activeId =
|
||||
typeof rawActiveId === "number" ? `discuss.channel_${rawActiveId}` : rawActiveId;
|
||||
@@ -54,10 +53,10 @@ export class DiscussClientAction extends Component {
|
||||
// legacy format (sent in old emails, shared links, ...)
|
||||
model = "discuss.channel";
|
||||
}
|
||||
const activeThreadLocalId = createLocalId(model, id);
|
||||
const activeThreadLocalId = this.store.Thread.localId({ model, id });
|
||||
if (activeThreadLocalId !== this.store.discuss.threadLocalId) {
|
||||
const thread =
|
||||
this.store.Thread.records[createLocalId(model, id)] ??
|
||||
this.store.Thread.get({ model, id }) ??
|
||||
(await this.threadService.fetchChannel(parseInt(id)));
|
||||
if (!thread.is_pinned) {
|
||||
await this.threadService.pin(thread);
|
||||
|
||||
@@ -92,7 +92,7 @@ export class MailCoreWeb {
|
||||
// Furthermore, server should not send back all messageIds marked as read
|
||||
// but something like last read messageId or something like that.
|
||||
// (just imagine you mark 1000 messages as read ... )
|
||||
const message = this.store.Message.records[messageId];
|
||||
const message = this.store.Message.get(messageId);
|
||||
if (!message) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { ImStatus } from "@mail/core/common/im_status";
|
||||
import { NotificationItem } from "@mail/core/web/notification_item";
|
||||
import { onExternalClick } from "@mail/utils/common/hooks";
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
|
||||
import { Component, useState } from "@odoo/owl";
|
||||
|
||||
@@ -64,10 +63,6 @@ export class MessagingMenu extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
createLocalId(...args) {
|
||||
return createLocalId(...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {'chat' | 'group'} tab
|
||||
* @returns Thread types matching the given tab.
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { ThreadService, threadService } from "@mail/core/common/thread_service";
|
||||
import { parseEmail } from "@mail/js/utils";
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
|
||||
import { markup } from "@odoo/owl";
|
||||
|
||||
@@ -102,15 +101,15 @@ patch(ThreadService.prototype, {
|
||||
return result;
|
||||
},
|
||||
getThread(resModel, resId) {
|
||||
const localId = createLocalId(resModel, resId);
|
||||
if (localId in this.store.Thread.records) {
|
||||
let thread = this.store.Thread.get({ model: resModel, id: resId });
|
||||
if (thread) {
|
||||
if (resId === false) {
|
||||
return this.store.Thread.records[localId];
|
||||
return thread;
|
||||
}
|
||||
// to force a reload
|
||||
this.store.Thread.records[localId].status = "new";
|
||||
thread.status = "new";
|
||||
}
|
||||
const thread = this.store.Thread.insert({
|
||||
thread = this.store.Thread.insert({
|
||||
id: resId,
|
||||
model: resModel,
|
||||
type: "chatter",
|
||||
@@ -215,7 +214,7 @@ patch(ThreadService.prototype, {
|
||||
} else {
|
||||
thread.followers.delete(follower);
|
||||
}
|
||||
delete this.store.Follower.records[follower.id];
|
||||
delete this.store.Follower.records[this.store.Follower.localId(follower.id)];
|
||||
},
|
||||
unpin(thread) {
|
||||
const chatWindow = this.store.ChatWindow.records.find(
|
||||
|
||||
@@ -88,7 +88,7 @@ export class Call extends Component {
|
||||
for (const memberId of this.props.thread.invitedMemberIds) {
|
||||
invitationCards.push({
|
||||
key: "member_" + memberId,
|
||||
member: this.store.ChannelMember.records[memberId],
|
||||
member: this.store.ChannelMember.get(memberId),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { BlurManager } from "@mail/discuss/call/common/blur_manager";
|
||||
import { monitorAudio } from "@mail/discuss/call/common/media_monitoring";
|
||||
import { removeFromArray } from "@mail/utils/common/arrays";
|
||||
import { closeStream, createLocalId, onChange } from "@mail/utils/common/misc";
|
||||
import { closeStream, onChange } from "@mail/utils/common/misc";
|
||||
|
||||
import { reactive } from "@odoo/owl";
|
||||
|
||||
@@ -771,7 +771,7 @@ export class Rtc {
|
||||
this.state.logs.clear();
|
||||
this.state.channel = channel;
|
||||
this.onThreadUpdate(this.state.channel, { rtcSessions, invitedMembers });
|
||||
this.state.selfSession = this.store.RtcSession.records[sessionId];
|
||||
this.state.selfSession = this.store.RtcSession.get(sessionId);
|
||||
this.state.iceServers = iceServers || DEFAULT_ICE_SERVERS;
|
||||
this.state.logs.set("channelId", this.state.channel?.id);
|
||||
this.state.logs.set("selfSessionId", this.state.selfSession?.id);
|
||||
@@ -1393,16 +1393,16 @@ export class Rtc {
|
||||
* @param {import("@mail/discuss/call/common/rtc_session_model").id} id
|
||||
*/
|
||||
deleteSession(id) {
|
||||
const session = this.store.RtcSession.records[id];
|
||||
const session = this.store.RtcSession.get(id);
|
||||
if (session) {
|
||||
if (this.state.selfSession && session.eq(this.state.selfSession)) {
|
||||
this.endCall();
|
||||
}
|
||||
delete this.store.Thread.records[createLocalId("discuss.channel", session.channelId)]
|
||||
delete this.store.Thread.get({ model: "discuss.channel", id: session.channelId })
|
||||
?.rtcSessions[id];
|
||||
this.disconnect(session);
|
||||
}
|
||||
delete this.store.RtcSession.records[id];
|
||||
delete this.store.RtcSession.records[this.store.RtcSession.localId(id)];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1464,7 +1464,7 @@ export class Rtc {
|
||||
}
|
||||
|
||||
updateRtcSessions(channelId, sessionsData, command) {
|
||||
const channel = this.store.Thread.records[createLocalId("discuss.channel", channelId)];
|
||||
const channel = this.store.Thread.get({ model: "discuss.channel", id: channelId });
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Record } from "@mail/core/common/record";
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
|
||||
export class RtcSession extends Record {
|
||||
static id = "id";
|
||||
/** @type {Object.<number, RtcSession>} */
|
||||
static records = {};
|
||||
/**
|
||||
@@ -11,11 +11,9 @@ export class RtcSession extends Record {
|
||||
* @returns {number, RtcSession}
|
||||
*/
|
||||
static insert(data) {
|
||||
let session;
|
||||
if (this.records[data.id]) {
|
||||
session = this.records[data.id];
|
||||
} else {
|
||||
session = new RtcSession();
|
||||
let session = this.get(data);
|
||||
if (!session) {
|
||||
session = this.new(data);
|
||||
session._store = this.store;
|
||||
}
|
||||
const { channelMember, ...remainingData } = data;
|
||||
@@ -33,9 +31,9 @@ export class RtcSession extends Record {
|
||||
channelMemberRecord.thread.rtcSessions[session.id] = session;
|
||||
}
|
||||
}
|
||||
this.records[session.id] = session;
|
||||
this.records[session.localId] = session;
|
||||
// return reactive version
|
||||
return this.records[session.id];
|
||||
return this.records[session.localId];
|
||||
}
|
||||
|
||||
// Server data
|
||||
@@ -79,11 +77,11 @@ export class RtcSession extends Record {
|
||||
logStep;
|
||||
|
||||
get channelMember() {
|
||||
return this._store.ChannelMember.records[this.channelMemberId];
|
||||
return this._store.ChannelMember.get(this.channelMemberId);
|
||||
}
|
||||
|
||||
get channel() {
|
||||
return this._store.Thread.records[createLocalId("discuss.channel", this.channelId)];
|
||||
return this._store.Thread.get({ model: "discuss.channel", id: this.channelId });
|
||||
}
|
||||
|
||||
get isMute() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { removeFromArrayWithPredicate } from "@mail/utils/common/arrays";
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
|
||||
import { markup, reactive } from "@odoo/owl";
|
||||
|
||||
@@ -50,7 +49,7 @@ export class DiscussCoreCommon {
|
||||
});
|
||||
this.busService.subscribe("discuss.channel/last_interest_dt_changed", (payload) => {
|
||||
const { id, last_interest_dt } = payload;
|
||||
const channel = this.store.Thread.records[createLocalId("discuss.channel", id)];
|
||||
const channel = this.store.Thread.get({ model: "discuss.channel", id });
|
||||
if (channel) {
|
||||
this.threadService.update(channel, { last_interest_dt });
|
||||
if (channel.type !== "channel") {
|
||||
@@ -96,8 +95,10 @@ export class DiscussCoreCommon {
|
||||
}
|
||||
});
|
||||
this.busService.subscribe("discuss.channel/transient_message", (payload) => {
|
||||
const channel =
|
||||
this.store.Thread.records[createLocalId("discuss.channel", payload.res_id)];
|
||||
const channel = this.store.Thread.get({
|
||||
model: "discuss.channel",
|
||||
id: payload.res_id,
|
||||
});
|
||||
const message = this.messageService.createTransient(
|
||||
Object.assign(payload, { body: markup(payload.body) })
|
||||
);
|
||||
@@ -105,8 +106,7 @@ export class DiscussCoreCommon {
|
||||
channel.transientMessages.push(message);
|
||||
});
|
||||
this.busService.subscribe("discuss.channel/unpin", (payload) => {
|
||||
const thread =
|
||||
this.store.Thread.records[createLocalId("discuss.channel", payload.id)];
|
||||
const thread = this.store.Thread.get({ model: "discuss.channel", id: payload.id });
|
||||
if (thread) {
|
||||
thread.is_pinned = false;
|
||||
this.notificationService.add(
|
||||
@@ -117,8 +117,7 @@ export class DiscussCoreCommon {
|
||||
});
|
||||
this.busService.subscribe("discuss.channel.member/fetched", (payload) => {
|
||||
const { channel_id, last_message_id, partner_id } = payload;
|
||||
const channel =
|
||||
this.store.Thread.records[createLocalId("discuss.channel", channel_id)];
|
||||
const channel = this.store.Thread.get({ model: "discuss.channel", id: channel_id });
|
||||
if (channel) {
|
||||
const seenInfo = channel.seenInfos.find(
|
||||
(seenInfo) => seenInfo.partner.id === partner_id
|
||||
@@ -130,8 +129,7 @@ export class DiscussCoreCommon {
|
||||
});
|
||||
this.busService.subscribe("discuss.channel.member/seen", (payload) => {
|
||||
const { channel_id, last_message_id, partner_id } = payload;
|
||||
const channel =
|
||||
this.store.Thread.records[createLocalId("discuss.channel", channel_id)];
|
||||
const channel = this.store.Thread.get({ model: "discuss.channel", id: channel_id });
|
||||
if (!channel) {
|
||||
// for example seen from another browser, the current one has no
|
||||
// knowledge of the channel
|
||||
@@ -216,7 +214,7 @@ export class DiscussCoreCommon {
|
||||
|
||||
async _handleNotificationNewMessage(notif) {
|
||||
const { id, message: messageData } = notif.payload;
|
||||
let channel = this.store.Thread.records[createLocalId("discuss.channel", id)];
|
||||
let channel = this.store.Thread.get({ model: "discuss.channel", id });
|
||||
if (!channel || !channel.type) {
|
||||
const [channelData] = await this.rpc("/discuss/channel/info", { channel_id: id });
|
||||
channel = this.store.Thread.insert({
|
||||
@@ -229,7 +227,7 @@ export class DiscussCoreCommon {
|
||||
this.threadService.pin(channel);
|
||||
}
|
||||
removeFromArrayWithPredicate(channel.messages, ({ id }) => id === messageData.temporary_id);
|
||||
delete this.store.Message.records[messageData.temporary_id];
|
||||
delete this.store.Message.records[this.store.Message.localId(messageData.temporary_id)];
|
||||
messageData.temporary_id = null;
|
||||
if ("parentMessage" in messageData && messageData.parentMessage.body) {
|
||||
messageData.parentMessage.body = markup(messageData.parentMessage.body);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { NavigableList } from "@mail/core/common/navigable_list";
|
||||
import { cleanTerm } from "@mail/utils/common/format";
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
|
||||
import { Component, onMounted, useEffect, useRef, useState } from "@odoo/owl";
|
||||
|
||||
@@ -231,7 +230,7 @@ export class ChannelSelector extends Component {
|
||||
get tagsList() {
|
||||
const res = [];
|
||||
for (const partnerId of this.state.selectedPartners) {
|
||||
const partner = this.store.Persona.records[createLocalId("partner", partnerId)];
|
||||
const partner = this.store.Persona.get({ type: "partner", id: partnerId });
|
||||
res.push({
|
||||
id: partner.id,
|
||||
text: partner.name,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
import { reactive } from "@odoo/owl";
|
||||
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
@@ -87,7 +86,7 @@ export class DiscussCoreWeb {
|
||||
this.busService.subscribe("mail.record/insert", async (payload) => {
|
||||
if (payload.Thread) {
|
||||
const data = payload.Thread;
|
||||
const thread = this.store.Thread.records[createLocalId(data.model, data.id)];
|
||||
const thread = this.store.Thread.get(data);
|
||||
if (data.serverFoldState && thread && data.serverFoldState !== thread.state) {
|
||||
thread.state = data.serverFoldState;
|
||||
if (thread.state === "closed") {
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
import { reactive } from "@odoo/owl";
|
||||
|
||||
export function createLocalId(...args) {
|
||||
return args.join(",");
|
||||
}
|
||||
|
||||
export function nullifyClearCommands(data) {
|
||||
for (const key in data) {
|
||||
if (!Array.isArray(data[key])) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
import { Command } from "@mail/../tests/helpers/command";
|
||||
import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils";
|
||||
|
||||
@@ -174,8 +173,10 @@ QUnit.test("Channel member count update after user left", async (assert) => {
|
||||
});
|
||||
const { env, openDiscuss } = await start();
|
||||
openDiscuss(channelId);
|
||||
const thread =
|
||||
env.services["mail.store"].Thread.records[createLocalId("discuss.channel", channelId)];
|
||||
const thread = env.services["mail.store"].Thread.get({
|
||||
model: "discuss.channel",
|
||||
id: channelId,
|
||||
});
|
||||
assert.strictEqual(thread.memberCount, 2);
|
||||
await pyEnv.withUser(userId, () =>
|
||||
env.services.orm.call("discuss.channel", "action_unfollow", [channelId])
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { UPDATE_BUS_PRESENCE_DELAY } from "@bus/im_status_service";
|
||||
|
||||
import { createLocalId } from "@mail/utils/common/misc";
|
||||
import { Command } from "@mail/../tests/helpers/command";
|
||||
import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils";
|
||||
|
||||
@@ -93,7 +92,7 @@ QUnit.test("Can handle im_status of unknown partner", async (assert) => {
|
||||
Partner: { im_status: "online", id: partnerId },
|
||||
});
|
||||
await nextTick();
|
||||
const persona = env.services["mail.store"].Persona.records[createLocalId("partner", partnerId)];
|
||||
const persona = env.services["mail.store"].Persona.get({ type: "partner", id: partnerId });
|
||||
assert.ok(persona);
|
||||
assert.ok(persona.im_status === "online");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user