fix(rundown): preserve revision and runtime semantics

Advance swapped-entry revisions correctly and rename loaded rundowns without restarting playback, while documenting the shared revision invariant.
This commit is contained in:
Carlos Valente
2026-09-13 20:20:27 +02:00
parent 48c76947c5
commit 982cb8e495
4 changed files with 24 additions and 22 deletions
@@ -1718,16 +1718,18 @@ describe('rundownMutation.swap()', () => {
expect((testRundown.entries['1'] as OntimeEvent).id).toBe('1');
expect((testRundown.entries['1'] as OntimeEvent).cue).toBe('data2');
expect((testRundown.entries['1'] as OntimeEvent).timeStart).toBe(1);
expect((testRundown.entries['1'] as OntimeEvent).revision).toBe(1);
// the swapped entries changed, their revision has to say so
expect((testRundown.entries['1'] as OntimeEvent).revision).toBe(2);
expect((testRundown.entries['2'] as OntimeEvent).id).toBe('2');
expect((testRundown.entries['2'] as OntimeEvent).cue).toBe('data1');
expect((testRundown.entries['2'] as OntimeEvent).timeStart).toBe(2);
expect((testRundown.entries['2'] as OntimeEvent).revision).toBe(1);
expect((testRundown.entries['2'] as OntimeEvent).revision).toBe(2);
expect((testRundown.entries['3'] as OntimeEvent).id).toBe('3');
expect((testRundown.entries['3'] as OntimeEvent).cue).toBe('data3');
expect((testRundown.entries['3'] as OntimeEvent).timeStart).toBe(3);
// untouched, so it keeps its revision
expect((testRundown.entries['3'] as OntimeEvent).revision).toBe(1);
});
});
@@ -422,7 +422,7 @@ function swap(rundown: Rundown, eventFrom: OntimeEvent, eventTo: OntimeEvent) {
gap: eventFrom.gap,
dayOffset: eventFrom.dayOffset,
// keep revision number but increment it
revision: eventFrom.revision++,
revision: eventFrom.revision + 1,
};
rundown.entries[eventTo.id] = {
@@ -440,7 +440,7 @@ function swap(rundown: Rundown, eventFrom: OntimeEvent, eventTo: OntimeEvent) {
gap: eventTo.gap,
dayOffset: eventTo.dayOffset,
// keep revision number but increment it
revision: eventTo.revision++,
revision: eventTo.revision + 1,
};
}
@@ -816,27 +816,23 @@ export async function createNewRundown(title: string) {
* @throws if the provided id does not exist
*/
export async function renameRundown(id: string, title: string) {
const dataProvider = getDataProvider();
const rundown = dataProvider.getRundown(id);
const { rundown, commit } = createTransaction({ rundownId: id, mutableRundown: true });
await dataProvider.setRundown(id, { ...rundown, title, revision: rundown.revision + 1 });
/**
* If we are modifying the loaded rundown we re-init it
* This is likely over-kill but the simplest way to ensure state consistency
*/
if (isCurrentRundown(id)) {
const rundown = dataProvider.getRundown(id);
const customField = dataProvider.getCustomFields();
// init rundown does its own refetch
await initRundown(rundown, customField);
} else {
setImmediate(() => {
sendRefetch(RefetchKey.ProjectRundowns);
});
if (rundown.title === title) {
return getDataProvider().getProjectRundowns();
}
return dataProvider.getProjectRundowns();
rundown.title = title;
// a title has no bearing on the schedule, there is nothing to process and no runtime to notify
const { rundownMetadata, revision } = await commit(false);
setImmediate(() => {
notifyChanges(id, rundownMetadata, revision, { external: true });
sendRefetch(RefetchKey.ProjectRundowns);
});
return getDataProvider().getProjectRundowns();
}
/**