From 24e325726cb2e543bbd7ae1ff2bb62ebbed8077b Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sat, 14 Mar 2026 07:34:02 +0100 Subject: [PATCH] refactor: improve object handling performance --- apps/client/src/common/hooks/useSocket.ts | 4 +-- apps/server/src/adapters/WebsocketAdapter.ts | 7 ++++- .../src/api-data/rundown/rundown.dao.ts | 10 +++++-- .../src/api-data/rundown/rundown.service.ts | 28 +++++++++++++++---- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/apps/client/src/common/hooks/useSocket.ts b/apps/client/src/common/hooks/useSocket.ts index a2413eaf5..d01ab126d 100644 --- a/apps/client/src/common/hooks/useSocket.ts +++ b/apps/client/src/common/hooks/useSocket.ts @@ -139,9 +139,7 @@ export const setEventPlayback = { pause: () => sendSocket('pause', undefined), }; -export const useTimer = createSelector((state: RuntimeStore) => ({ - ...state.timer, -})); +export const useTimer = createSelector((state: RuntimeStore) => state.timer); export const useClock = createSelector((state: RuntimeStore) => state.clock); diff --git a/apps/server/src/adapters/WebsocketAdapter.ts b/apps/server/src/adapters/WebsocketAdapter.ts index 531429c17..7557069fc 100644 --- a/apps/server/src/adapters/WebsocketAdapter.ts +++ b/apps/server/src/adapters/WebsocketAdapter.ts @@ -223,9 +223,14 @@ class SocketServer implements IAdapter { // message is any serializable value public sendAsJson(tag: T, payload: Pick['payload']) { + const wss = this.wss; + if (!wss || wss.clients.size === 0) { + return; + } + try { const stringifiedMessage = JSON.stringify({ tag, payload }); - this.wss?.clients.forEach((client) => { + wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send(stringifiedMessage); } diff --git a/apps/server/src/api-data/rundown/rundown.dao.ts b/apps/server/src/api-data/rundown/rundown.dao.ts index 456ed0a51..01a99bfc6 100644 --- a/apps/server/src/api-data/rundown/rundown.dao.ts +++ b/apps/server/src/api-data/rundown/rundown.dao.ts @@ -186,7 +186,8 @@ function remove(rundown: Rundown, entry: OntimeEntry) { // for ontime groups, we need to iterate through the children and delete them for (let i = 0; i < entry.entries.length; i++) { const nestedEntryId = entry.entries[i]; - deleteEntry(nestedEntryId); + // nested entries are not part of the top-level order + deleteEntry(nestedEntryId, false); } } else if (entry.parent) { // at this point, we are handling entries inside a group, so we need to remove the reference @@ -205,10 +206,13 @@ function remove(rundown: Rundown, entry: OntimeEntry) { edit(rundown, { id: parentGroup.id, entries: filteredEvents }); } } + deleteEntry(entry.id); - function deleteEntry(idToDelete: EntryId) { - rundown.order = deleteById(rundown.order, idToDelete); + function deleteEntry(idToDelete: EntryId, shouldDeleteFromOrder: boolean = true) { + if (shouldDeleteFromOrder) { + rundown.order = deleteById(rundown.order, idToDelete); + } delete rundown.entries[idToDelete]; } } diff --git a/apps/server/src/api-data/rundown/rundown.service.ts b/apps/server/src/api-data/rundown/rundown.service.ts index 48a8873e5..a4b30efdd 100644 --- a/apps/server/src/api-data/rundown/rundown.service.ts +++ b/apps/server/src/api-data/rundown/rundown.service.ts @@ -140,7 +140,6 @@ export async function batchEditEntries(ids: EntryId[], patch: Partial { + const currentRundown = getCurrentRundown(); + const shouldDelete = entryIds.some((entryId) => Object.hasOwn(currentRundown.entries, entryId)); + if (!shouldDelete) { + return currentRundown as Rundown; + } + const { rundown, commit } = createTransaction({ mutableRundown: true, mutableCustomFields: false }); + const deletedIds: EntryId[] = []; for (let i = 0; i < entryIds.length; i++) { const entry = rundown.entries[entryIds[i]]; @@ -200,6 +211,11 @@ export async function deleteEntries(entryIds: EntryId[]): Promise { continue; } rundownMutation.remove(rundown, entry); + deletedIds.push(entry.id); + } + + if (deletedIds.length === 0) { + return currentRundown as Rundown; } const { rundown: rundownResult, rundownMetadata, revision } = commit(); @@ -210,7 +226,7 @@ export async function deleteEntries(entryIds: EntryId[]): Promise { updateRuntimeOnChange(rundownMetadata); // notify timer and external services of change - notifyChanges(rundownMetadata, revision, { timer: entryIds, external: true }); + notifyChanges(rundownMetadata, revision, { timer: deletedIds, external: true }); }); return rundownResult; @@ -571,8 +587,10 @@ type NotifyChangesOptions = { * Notify services of changes in the rundown */ function notifyChanges(rundownMetadata: RundownMetadata, revision: number, options: NotifyChangesOptions) { + const shouldNotifyTimer = options.timer === true || (Array.isArray(options.timer) && options.timer.length > 0); + // notify timer service of changed events - if (options.timer) { + if (shouldNotifyTimer) { runtimeService.notifyOfChangedEvents(rundownMetadata); }