[REF] mail: support multi-data insertion in discuss model
Before this commit, when having an array of data to insert in a model, we had to iterate and insert data item on by one: ```js messageDataList.forEach(data => this.store.Message.insert(data)); ``` With this commit, we can simply insert the array of data to insert: ```js this.store.Message.insert(messageDataList); ``` This helps simplifying the business code further, less LOCs is usually better! Part-of: odoo/odoo#139501
This commit is contained in:
@@ -14,11 +14,8 @@ export class Attachment extends FileModelMixin(Record) {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").Attachment} */
|
||||
/** @returns {import("models").Attachment|import("models").Attachment[]} */
|
||||
static insert(data) {
|
||||
if (!("id" in data)) {
|
||||
throw new Error("Cannot insert attachment: id is missing in data");
|
||||
}
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
static new(data) {
|
||||
|
||||
@@ -10,7 +10,7 @@ export class CannedResponse extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").CannedResponse} */
|
||||
/** @returns {import("models").CannedResponse|import("models").CannedResponse[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export class ChannelMember extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").ChannelMember} */
|
||||
/** @returns {import("models").ChannelMember|import("models").ChannelMember[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export class ChatWindow extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").ChatWindow} */
|
||||
/** @returns {import("models").ChatWindow|import("models").ChatWindow[]} */
|
||||
static insert() {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -8,12 +8,8 @@ export class Composer extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").Composer} */
|
||||
/** @returns {import("models").Composer|import("models").Composer[]} */
|
||||
static insert(data) {
|
||||
const { message, thread } = data;
|
||||
if (Boolean(message) === Boolean(thread)) {
|
||||
throw new Error("Composer shall have a thread xor a message.");
|
||||
}
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ export class DiscussAppCategory extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").DiscussAppCategory} */
|
||||
/** @returns {import("models").DiscussAppCategory|import("models").DiscussAppCategory[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ export class DiscussApp extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").DiscussApp} */
|
||||
/** @returns {import("models").DiscussApp|import("models").DiscussApp[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export class Failure extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").Failure} */
|
||||
/** @returns {import("models").Failure|import("models").Failure[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export class Follower extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").Follower} */
|
||||
/** @returns {import("models").Follower|import("models").Follower[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export class LinkPreview extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").LinkPreview} */
|
||||
/** @returns {import("models").LinkPreview|import("models").LinkPreview[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export class MailCoreCommon {
|
||||
this.busService.subscribe("ir.attachment/delete", (payload) => {
|
||||
const { id: attachmentId, message: messageData } = payload;
|
||||
if (messageData) {
|
||||
this.store.Message.insert({ ...messageData });
|
||||
this.store.Message.insert(messageData);
|
||||
}
|
||||
const attachment = this.store.Attachment.get(attachmentId);
|
||||
if (attachment) {
|
||||
@@ -54,18 +54,13 @@ export class MailCoreCommon {
|
||||
}
|
||||
});
|
||||
this.busService.subscribe("mail.message/notification_update", (payload) => {
|
||||
payload.elements.map((message) => {
|
||||
this.store.Message.insert(
|
||||
{
|
||||
...message,
|
||||
// implicit: failures are sent by the server at
|
||||
// initialization only if the current partner is
|
||||
// author of the message
|
||||
author: this.store.self,
|
||||
},
|
||||
{ html: true }
|
||||
);
|
||||
});
|
||||
// implicit: failures are sent by the server at
|
||||
// initialization only if the current partner is
|
||||
// author of the message
|
||||
this.store.Message.insert(
|
||||
payload.elements.map((data) => ({ ...data, author: this.store.self })),
|
||||
{ html: true }
|
||||
);
|
||||
});
|
||||
this.busService.subscribe("mail.message/toggle_star", (payload) => {
|
||||
const { message_ids: messageIds, starred } = payload;
|
||||
@@ -88,26 +83,8 @@ export class MailCoreCommon {
|
||||
}
|
||||
});
|
||||
this.busService.subscribe("mail.record/insert", (payload) => {
|
||||
if (payload.Thread) {
|
||||
this.store.Thread.insert(payload.Thread);
|
||||
}
|
||||
if (payload.Persona) {
|
||||
const personas = Array.isArray(payload.Persona)
|
||||
? payload.Persona
|
||||
: [payload.Persona];
|
||||
for (const persona of personas) {
|
||||
this.store.Persona.insert(persona);
|
||||
}
|
||||
}
|
||||
const { LinkPreview: linkPreviews } = payload;
|
||||
if (linkPreviews) {
|
||||
for (const linkPreview of linkPreviews) {
|
||||
this.store.LinkPreview.insert(linkPreview);
|
||||
}
|
||||
}
|
||||
const { Message: messageData } = payload;
|
||||
if (messageData) {
|
||||
this.store.Message.insert(messageData, { html: true });
|
||||
for (const Model in payload) {
|
||||
this.store[Model].insert(payload[Model], { html: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,7 +33,7 @@ export class Message extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").Message} */
|
||||
/** @returns {import("models").Message|import("models").Message[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export class MessageReactions extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").MessageReactions} */
|
||||
/** @returns {import("models").MessageReactions|import("models").MessageReactions[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -84,9 +84,7 @@ export class Messaging {
|
||||
this.store.discuss.isActive =
|
||||
data.menu_id === this.router.current.hash?.menu_id ||
|
||||
this.router.hash?.action === "mail.action_discuss";
|
||||
(data.shortcodes ?? []).forEach((code) => {
|
||||
this.store.CannedResponse.insert(code);
|
||||
});
|
||||
this.store.CannedResponse.insert(data.shortcodes ?? []);
|
||||
this.store.hasLinkPreviewFeature = data.hasLinkPreviewFeature;
|
||||
this.store.initBusId = data.initBusId;
|
||||
this.store.odoobotOnboarding = data.odoobotOnboarding;
|
||||
@@ -114,7 +112,7 @@ export class Messaging {
|
||||
* @return {import("models").Persona[]}
|
||||
*/
|
||||
async searchPartners(searchStr = "", limit = 10) {
|
||||
let partners = [];
|
||||
const partners = [];
|
||||
const searchTerm = cleanTerm(searchStr);
|
||||
for (const localId in this.store.Persona.records) {
|
||||
const persona = this.store.Persona.records[localId];
|
||||
@@ -136,9 +134,7 @@ export class Messaging {
|
||||
searchTerm,
|
||||
limit,
|
||||
]);
|
||||
partners = partnersData.map((data) =>
|
||||
this.store.Persona.insert({ ...data, type: "partner" })
|
||||
);
|
||||
this.store.Persona.insert(partnersData);
|
||||
}
|
||||
return partners;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export class Notification extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").Notification} */
|
||||
/** @returns {import("models").Notification|import("models").Notification[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export class Persona extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {import("models").Persona} */
|
||||
/** @returns {import("models").Persona|import("models").Persona[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -680,12 +680,19 @@ export class Record {
|
||||
static attr(def, { html } = {}) {
|
||||
return [ATTR_SYM, { default: def, html }];
|
||||
}
|
||||
/** @returns {Record} */
|
||||
static insert(data, { html } = {}) {
|
||||
/** @returns {Record|Record[]} */
|
||||
static insert(data, options = {}) {
|
||||
const isMulti = Array.isArray(data);
|
||||
if (!isMulti) {
|
||||
data = [data];
|
||||
}
|
||||
const oldTrusted = Record.trusted;
|
||||
Record.trusted = html ?? Record.trusted;
|
||||
const res = this._insert(...arguments);
|
||||
Record.trusted = options.html ?? Record.trusted;
|
||||
const res = data.map((d) => this._insert(d, options));
|
||||
Record.trusted = oldTrusted;
|
||||
if (!isMulti) {
|
||||
return res[0];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/** @returns {Record} */
|
||||
|
||||
@@ -29,7 +29,7 @@ export class BaseStore extends Record {
|
||||
}
|
||||
|
||||
export class Store extends BaseStore {
|
||||
/** @returns {import("models").Store} */
|
||||
/** @returns {import("models").Store|import("models").Store[]} */
|
||||
static insert() {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ export function useSuggestion() {
|
||||
const comp = useComponent();
|
||||
const sequential = useSequential();
|
||||
const suggestionService = useService("mail.suggestion");
|
||||
const store = useState(useService("mail.store"));
|
||||
const self = {
|
||||
clearRawMentions() {
|
||||
comp.props.composer.mentionedChannels.length = 0;
|
||||
@@ -110,9 +109,7 @@ export function useSuggestion() {
|
||||
});
|
||||
}
|
||||
if (option.cannedResponse) {
|
||||
comp.props.composer.cannedResponses.push(
|
||||
store.CannedResponse.insert(option.cannedResponse)
|
||||
);
|
||||
comp.props.composer.cannedResponses.push(option.cannedResponse);
|
||||
}
|
||||
self.clearSearch();
|
||||
comp.props.composer.textInputContent = textLeft + recordReplacement + " " + textRight;
|
||||
|
||||
@@ -14,7 +14,7 @@ export class SuggestionService {
|
||||
this.env = env;
|
||||
this.orm = services.orm;
|
||||
this.store = services["mail.store"];
|
||||
this.personaService = services['mail.persona'];
|
||||
this.personaService = services["mail.persona"];
|
||||
}
|
||||
|
||||
getSupportedDelimiters(thread) {
|
||||
@@ -51,7 +51,7 @@ export class SuggestionService {
|
||||
[],
|
||||
kwargs
|
||||
);
|
||||
suggestedPartners.forEach((data) => this.store.Persona.insert(data));
|
||||
this.store.Persona.insert(suggestedPartners);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ export class SuggestionService {
|
||||
[],
|
||||
{ search: term }
|
||||
);
|
||||
suggestedThreads.forEach((data) => this.store.Thread.insert(data));
|
||||
this.store.Thread.insert(suggestedThreads);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,14 +53,8 @@ export class Thread extends Record {
|
||||
// Transform "Thread,<model> AND <id>" to "<model>_<id>""
|
||||
return localId.split(",").slice(1).join("_").replace(" AND ", "_");
|
||||
}
|
||||
/** @returns {import("models").Thread} */
|
||||
/** @returns {import("models").Thread|import("models").Thread[]} */
|
||||
static insert(data) {
|
||||
if (!("id" in data)) {
|
||||
throw new Error("Cannot insert thread: id is missing in data");
|
||||
}
|
||||
if (!("model" in data)) {
|
||||
throw new Error("Cannot insert thread: model is missing in data");
|
||||
}
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
|
||||
@@ -191,9 +191,7 @@ export class ThreadService {
|
||||
after,
|
||||
before,
|
||||
});
|
||||
const messages = rawMessages
|
||||
.reverse()
|
||||
.map((data) => this.store.Message.insert(data, { html: true }));
|
||||
const messages = this.store.Message.insert(rawMessages.reverse(), { html: true });
|
||||
thread.isLoaded = true;
|
||||
return messages;
|
||||
} catch (e) {
|
||||
@@ -292,9 +290,7 @@ export class ThreadService {
|
||||
...this.getFetchParams(thread),
|
||||
around: messageId,
|
||||
});
|
||||
thread.messages = messages
|
||||
.reverse()
|
||||
.map((message) => this.store.Message.insert(message, { html: true }));
|
||||
thread.messages = this.store.Message.insert(messages.reverse(), { html: true });
|
||||
thread.loadNewer = messageId ? true : false;
|
||||
thread.loadOlder = true;
|
||||
if (messages.length < FETCH_LIMIT) {
|
||||
@@ -968,7 +964,7 @@ export class ThreadService {
|
||||
return {
|
||||
count,
|
||||
loadMore: messages.length === FETCH_LIMIT,
|
||||
messages: messages.map((message) => this.store.Message.insert(message, { html: true })),
|
||||
messages: this.store.Message.insert(messages, { html: true }),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,8 +87,6 @@ export class ActivityListPopover extends Component {
|
||||
context: this.user.user_context,
|
||||
}
|
||||
);
|
||||
for (const activityData of activitiesData) {
|
||||
this.store.Activity.insert(activityData);
|
||||
}
|
||||
this.store.Activity.insert(activitiesData, { html: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export class Activity extends Record {
|
||||
* @param {Data} data
|
||||
* @param {Object} [param1]
|
||||
* @param {boolean} param1.broadcast
|
||||
* @returns {import("models").Activity}
|
||||
* @returns {import("models").Activity|import("models").Activity[]}
|
||||
*/
|
||||
static insert(data, { broadcast = true } = {}) {
|
||||
return super.insert(...arguments);
|
||||
|
||||
@@ -52,7 +52,7 @@ export class ActivityService {
|
||||
return action;
|
||||
}
|
||||
|
||||
async edit(activityId){
|
||||
async edit(activityId) {
|
||||
return new Promise((resolve) =>
|
||||
this.env.services.action.doAction(
|
||||
{
|
||||
@@ -74,16 +74,20 @@ export class ActivityService {
|
||||
active_model: resModel,
|
||||
active_ids: resIds,
|
||||
active_id: resIds[0],
|
||||
...((defaultActivityTypeId !== undefined) ? {
|
||||
default_activity_type_id: defaultActivityTypeId,
|
||||
} : {}),
|
||||
...(defaultActivityTypeId !== undefined
|
||||
? {
|
||||
default_activity_type_id: defaultActivityTypeId,
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
return new Promise((resolve) =>
|
||||
this.env.services.action.doAction(
|
||||
{
|
||||
type: "ir.actions.act_window",
|
||||
name: (resIds && resIds.length > 1) ? _t("Schedule Activity On Selected Records") :
|
||||
_t("Schedule Activity"),
|
||||
name:
|
||||
resIds && resIds.length > 1
|
||||
? _t("Schedule Activity On Selected Records")
|
||||
: _t("Schedule Activity"),
|
||||
res_model: "mail.activity.schedule",
|
||||
view_mode: "form",
|
||||
views: [[false, "form"]],
|
||||
@@ -105,7 +109,7 @@ export class ActivityService {
|
||||
_onBroadcastChannelMessage({ data }) {
|
||||
switch (data.type) {
|
||||
case "INSERT":
|
||||
this.store.Activity.insert(data.payload, { broadcast: false });
|
||||
this.store.Activity.insert(data.payload, { broadcast: false, html: true });
|
||||
break;
|
||||
case "DELETE": {
|
||||
const activity = this.store.Activity.insert(data.payload, { broadcast: false });
|
||||
|
||||
@@ -23,17 +23,12 @@ export class MailCoreWeb {
|
||||
setup() {
|
||||
this.messagingService.isReady.then(() => {
|
||||
this.rpc("/mail/load_message_failures", {}, { silent: true }).then((messages) => {
|
||||
messages.map((messageData) =>
|
||||
this.store.Message.insert(
|
||||
{
|
||||
...messageData,
|
||||
// implicit: failures are sent by the server at
|
||||
// initialization only if the current partner is
|
||||
// author of the message
|
||||
author: this.store.user,
|
||||
},
|
||||
{ html: true }
|
||||
)
|
||||
// implicit: failures are sent by the server at
|
||||
// initialization only if the current partner is
|
||||
// author of the message
|
||||
this.store.Message.insert(
|
||||
messages.map((m) => ({ ...m, author: this.store.user })),
|
||||
{ html: true }
|
||||
);
|
||||
this.store.failures.sort((f1, f2) => f2.lastMessage?.id - f1.lastMessage?.id);
|
||||
});
|
||||
|
||||
@@ -1581,11 +1581,6 @@ export const rtcService = {
|
||||
services["mail.user_settings"].setVolumes(payload);
|
||||
}
|
||||
});
|
||||
services["bus_service"].subscribe("mail.record/insert", (payload) => {
|
||||
if (payload.RtcSession) {
|
||||
rtc.store.RtcSession.insert(payload.RtcSession);
|
||||
}
|
||||
});
|
||||
return rtc;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ export class RtcSession extends Record {
|
||||
static get(data) {
|
||||
return super.get(data);
|
||||
}
|
||||
/** @returns {number, import("models").RtcSession} */
|
||||
/** @returns {import("models").RtcSession|import("models").RtcSession[]} */
|
||||
static insert(data) {
|
||||
return super.insert(...arguments);
|
||||
}
|
||||
|
||||
@@ -53,15 +53,7 @@ export class ChannelInvitation extends Component {
|
||||
if (!results) {
|
||||
return;
|
||||
}
|
||||
const Partners = results["partners"];
|
||||
const selectablePartners = [];
|
||||
for (const selectablePartner of Partners) {
|
||||
const newPartner = this.store.Persona.insert({
|
||||
type: "partner",
|
||||
...selectablePartner,
|
||||
});
|
||||
selectablePartners.push(newPartner);
|
||||
}
|
||||
const selectablePartners = this.store.Persona.insert(results.partners);
|
||||
this.state.selectablePartners = this.suggestionService.sortPartnerSuggestions(
|
||||
selectablePartners,
|
||||
this.searchStr,
|
||||
|
||||
@@ -39,7 +39,7 @@ patch(ThreadService.prototype, {
|
||||
channel_id: thread.id,
|
||||
limit,
|
||||
});
|
||||
const attachments = rawAttachments.map((a) => this.store.Attachment.insert(a));
|
||||
const attachments = this.store.Attachment.insert(rawAttachments);
|
||||
if (attachments.length < limit) {
|
||||
thread.areAttachmentsLoaded = true;
|
||||
}
|
||||
|
||||
@@ -80,9 +80,7 @@ export class MessagePin {
|
||||
const messagesData = await this.rpcService("/discuss/channel/pinned_messages", {
|
||||
channel_id: channel.id,
|
||||
});
|
||||
messagesData.forEach((messageData) =>
|
||||
this.store.Message.insert(messageData, { html: true })
|
||||
);
|
||||
this.store.Message.insert(messagesData, { html: true });
|
||||
channel.pinnedMessagesState = "loaded";
|
||||
} catch (e) {
|
||||
channel.pinnedMessagesState = "error";
|
||||
|
||||
@@ -74,10 +74,8 @@ QUnit.test("Assign & Delete on fields with inverses", async (assert) => {
|
||||
}).register();
|
||||
const store = await start();
|
||||
const thread = store.Thread.insert("General");
|
||||
const john = store.Member.insert("John");
|
||||
const marc = store.Member.insert("Marc");
|
||||
const hello = store.Message.insert("hello");
|
||||
const world = store.Message.insert("world");
|
||||
const [john, marc] = store.Member.insert(["John", "Marc"]);
|
||||
const [hello, world] = store.Message.insert(["hello", "world"]);
|
||||
// Assign on fields should adapt inverses
|
||||
Object.assign(thread, { composer: {}, members: [["ADD", john]], messages: [hello, world] });
|
||||
assert.ok(thread.composer);
|
||||
@@ -132,8 +130,7 @@ QUnit.test("Computed relational field", async (assert) => {
|
||||
}).register();
|
||||
const store = await start();
|
||||
const thread = store.Thread.insert("General");
|
||||
const john = store.Persona.insert("John");
|
||||
const marc = store.Persona.insert("Marc");
|
||||
const [john, marc] = store.Persona.insert(["John", "Marc"]);
|
||||
Object.assign(thread, { members: [john, marc] });
|
||||
assert.ok(thread.admin.eq(john));
|
||||
thread.members.delete(john);
|
||||
|
||||
Reference in New Issue
Block a user