refactor: always reload on changes

This commit is contained in:
Carlos Valente
2025-07-13 17:32:10 +02:00
parent 445cc9e845
commit dd47d2b7e7
3 changed files with 11 additions and 80 deletions
@@ -538,26 +538,11 @@ type NotifyChangesOptions = {
/** /**
* Notify services of changes in the rundown * Notify services of changes in the rundown
*
* @private - exported for testing
*/ */
export function notifyChanges(rundownMetadata: RundownMetadata, revision: number, options: NotifyChangesOptions) { function notifyChanges(rundownMetadata: RundownMetadata, revision: number, options: NotifyChangesOptions) {
// notify timer service of changed events // notify timer service of changed events
if (options.timer) { if (options.timer) {
// all events were deleted runtimeService.notifyOfChangedEvents(rundownMetadata);
if (rundownMetadata.playableEventOrder.length === 0) {
runtimeService.stop();
} else {
/**
* Timer can be
* - true: all events changed
* - an array of changed IDs
* - undefined: filtered above, no notification intended
*/
// timer can be true or an array of changed IDs
const affected = Array.isArray(options.timer) ? options.timer : undefined;
runtimeService.notifyOfChangedEvents(affected);
}
} }
// notify external services of changes // notify external services of changes
@@ -1,6 +1,5 @@
import { import {
EndAction, EndAction,
EntryId,
isOntimeEvent, isOntimeEvent,
isPlayableEvent, isPlayableEvent,
LogOrigin, LogOrigin,
@@ -38,6 +37,7 @@ import {
getShouldClockUpdate, getShouldClockUpdate,
getShouldTimerUpdate, getShouldTimerUpdate,
} from './rundownService.utils.js'; } from './rundownService.utils.js';
import { RundownMetadata } from '../../api-data/rundown/rundown.types.js';
type RuntimeStateEventKeys = keyof Pick<RuntimeState, 'eventNext' | 'eventNow'>; type RuntimeStateEventKeys = keyof Pick<RuntimeState, 'eventNext' | 'eventNow'>;
@@ -178,80 +178,25 @@ class RuntimeService {
} }
} }
/**
* Checks if a list of IDs is in the current selection
*/
private affectsLoaded(affectedIds: string[]): boolean {
const state = runtimeState.getState();
const now = state.eventNow?.id;
const next = state.eventNext?.id;
return (now !== undefined && affectedIds.includes(now)) || (next !== undefined && affectedIds.includes(next));
}
private isNewNext() {
const { timedEventOrder } = getRundownMetadata();
const state = runtimeState.getState();
const now = state.eventNow?.id;
const next = state.eventNext?.id;
// check whether the index of now and next are consecutive
const indexNow = timedEventOrder.findIndex((id) => id === now);
const indexNext = timedEventOrder.findIndex((id) => id === next);
return indexNext - indexNow !== 1;
}
/** /**
* Called when the underlying data has changed, * Called when the underlying data has changed,
* we check if the change affects the runtime * we check if the change affects the runtime
*/ */
public notifyOfChangedEvents(affectedIds?: EntryId[]) { public notifyOfChangedEvents(rundownMetadata: RundownMetadata) {
const state = runtimeState.getState(); const state = runtimeState.getState();
const hasLoadedElements = state.eventNow !== null || state.eventNext !== null; const hasLoadedElements = state.eventNow !== null || state.eventNext !== null;
if (!hasLoadedElements) { if (!hasLoadedElements) {
return; return;
} }
// we need to reload in a few scenarios: // all events were deleted
// 1. we are not confident that changes do not affect running event (eg. all events where changed) if (rundownMetadata.playableEventOrder.length === 0) {
const safeOption = affectedIds === undefined; runtimeState.stop();
// 2. the edited event is in memory (now or next) running
// behind conditional to avoid doing unnecessary work
const eventInMemory = safeOption ? false : this.affectsLoaded(affectedIds);
// 3. the edited event replaces next event
let isNext = false;
// if we are not sure, or the event is in memory, we reload
if (safeOption || eventInMemory) {
if (state.eventNow !== null) {
// load stuff again, but keep running if our events still exist
const eventNow = getEntryWithId(state.eventNow.id);
if (!isOntimeEvent(eventNow) || !isPlayableEvent(eventNow)) {
// maybe the event was deleted or the skip state was changed
runtimeState.stop();
return;
}
const onlyChangedNow = affectedIds?.length === 1 && affectedIds.at(0) === eventNow.id;
if (onlyChangedNow) {
runtimeState.updateLoaded(eventNow);
} else {
const rundown = getCurrentRundown();
const metadata = getRundownMetadata();
runtimeState.updateAll(rundown, metadata);
}
return;
}
} }
// Maybe the event will become the next const rundown = getCurrentRundown();
isNext = this.isNewNext(); const metadata = getRundownMetadata();
if (isNext) { runtimeState.updateAll(rundown, metadata);
const rundown = getCurrentRundown();
const metadata = getRundownMetadata();
runtimeState.loadNext(rundown, metadata);
}
} }
/** /**
+1
View File
@@ -342,6 +342,7 @@ export function updateAll(rundown: Rundown, metadata: RundownMetadata) {
loadNext(rundown, metadata, eventNowIndex >= 0 ? eventNowIndex : undefined); loadNext(rundown, metadata, eventNowIndex >= 0 ? eventNowIndex : undefined);
updateLoaded(runtimeState.eventNow ?? undefined); updateLoaded(runtimeState.eventNow ?? undefined);
loadBlock(rundown); loadBlock(rundown);
loadNextFlag(eventNowIndex, rundown, metadata);
} }
export function start(state: RuntimeState = runtimeState): boolean { export function start(state: RuntimeState = runtimeState): boolean {