mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-18 21:54:09 +00:00
refactor: delays account for gaps (#784)
This commit is contained in:
@@ -31,15 +31,53 @@ describe('init() function', () => {
|
|||||||
it('calculates delays versions of a given rundown', () => {
|
it('calculates delays versions of a given rundown', () => {
|
||||||
const testRundown: OntimeRundown = [
|
const testRundown: OntimeRundown = [
|
||||||
{ type: SupportedEvent.Delay, id: '1', duration: 100 } as OntimeDelay,
|
{ type: SupportedEvent.Delay, id: '1', duration: 100 } as OntimeDelay,
|
||||||
{ type: SupportedEvent.Event, id: '2', timeStart: 1 } as OntimeEvent,
|
{ type: SupportedEvent.Event, id: '2', timeStart: 1, timeEnd: 100 } as OntimeEvent,
|
||||||
{ type: SupportedEvent.Block, id: '3' } as OntimeBlock,
|
|
||||||
{ type: SupportedEvent.Event, id: '4', timeStart: 2 } as OntimeEvent,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const initResult = generate(testRundown);
|
const initResult = generate(testRundown);
|
||||||
expect(initResult.order.length).toBe(4);
|
expect(initResult.order.length).toBe(2);
|
||||||
expect((initResult.rundown['2'] as OntimeEvent).delay).toBe(100);
|
expect((initResult.rundown['2'] as OntimeEvent).delay).toBe(100);
|
||||||
|
expect(initResult.totalDelay).toBe(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accounts for gaps in rundown when calculating delays', () => {
|
||||||
|
const testRundown: OntimeRundown = [
|
||||||
|
{ type: SupportedEvent.Event, id: '1', timeStart: 100, timeEnd: 200 } as OntimeEvent,
|
||||||
|
{ type: SupportedEvent.Delay, id: 'delay', duration: 200 } as OntimeDelay,
|
||||||
|
{ type: SupportedEvent.Event, id: '2', timeStart: 200, timeEnd: 300 } as OntimeEvent,
|
||||||
|
{ type: SupportedEvent.Block, id: 'block', title: 'break' } as OntimeBlock,
|
||||||
|
{ type: SupportedEvent.Event, id: '3', timeStart: 400, timeEnd: 500 } as OntimeEvent,
|
||||||
|
{ type: SupportedEvent.Block, id: 'another-block', title: 'another-break' } as OntimeBlock,
|
||||||
|
{ type: SupportedEvent.Event, id: '4', timeStart: 600, timeEnd: 700 } as OntimeEvent,
|
||||||
|
];
|
||||||
|
|
||||||
|
const initResult = generate(testRundown);
|
||||||
|
expect(initResult.order.length).toBe(7);
|
||||||
|
expect((initResult.rundown['1'] as OntimeEvent).delay).toBe(0);
|
||||||
|
expect((initResult.rundown['2'] as OntimeEvent).delay).toBe(200);
|
||||||
|
expect((initResult.rundown['3'] as OntimeEvent).delay).toBe(100);
|
||||||
expect((initResult.rundown['4'] as OntimeEvent).delay).toBe(0);
|
expect((initResult.rundown['4'] as OntimeEvent).delay).toBe(0);
|
||||||
|
expect(initResult.totalDelay).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles negative delays', () => {
|
||||||
|
const testRundown: OntimeRundown = [
|
||||||
|
{ type: SupportedEvent.Event, id: '1', timeStart: 100, timeEnd: 200 } as OntimeEvent,
|
||||||
|
{ type: SupportedEvent.Delay, id: 'delay', duration: -200 } as OntimeDelay,
|
||||||
|
{ type: SupportedEvent.Event, id: '2', timeStart: 200, timeEnd: 300 } as OntimeEvent,
|
||||||
|
{ type: SupportedEvent.Block, id: 'block', title: 'break' } as OntimeBlock,
|
||||||
|
{ type: SupportedEvent.Event, id: '3', timeStart: 400, timeEnd: 500 } as OntimeEvent,
|
||||||
|
{ type: SupportedEvent.Block, id: 'another-block', title: 'another-break' } as OntimeBlock,
|
||||||
|
{ type: SupportedEvent.Event, id: '4', timeStart: 600, timeEnd: 700 } as OntimeEvent,
|
||||||
|
];
|
||||||
|
|
||||||
|
const initResult = generate(testRundown);
|
||||||
|
expect(initResult.order.length).toBe(7);
|
||||||
|
expect((initResult.rundown['1'] as OntimeEvent).delay).toBe(0);
|
||||||
|
expect((initResult.rundown['2'] as OntimeEvent).delay).toBe(-200);
|
||||||
|
expect((initResult.rundown['3'] as OntimeEvent).delay).toBe(-200);
|
||||||
|
expect((initResult.rundown['4'] as OntimeEvent).delay).toBe(-200);
|
||||||
|
expect(initResult.totalDelay).toBe(-200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('links times across events', () => {
|
it('links times across events', () => {
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
import {
|
import { isOntimeDelay, isOntimeEvent, OntimeEvent, OntimeRundown, OntimeRundownEntry } from 'ontime-types';
|
||||||
isOntimeBlock,
|
|
||||||
isOntimeDelay,
|
|
||||||
isOntimeEvent,
|
|
||||||
OntimeEvent,
|
|
||||||
OntimeRundown,
|
|
||||||
OntimeRundownEntry,
|
|
||||||
} from 'ontime-types';
|
|
||||||
import {
|
import {
|
||||||
generateId,
|
generateId,
|
||||||
deleteAtIndex,
|
deleteAtIndex,
|
||||||
@@ -31,6 +24,7 @@ let rundown: NormalisedRundown = {};
|
|||||||
let order: EventID[] = [];
|
let order: EventID[] = [];
|
||||||
let revision = 0;
|
let revision = 0;
|
||||||
let isStale = true;
|
let isStale = true;
|
||||||
|
let totalDelay = 0;
|
||||||
|
|
||||||
let links: Record<EventID, EventID> = {};
|
let links: Record<EventID, EventID> = {};
|
||||||
|
|
||||||
@@ -64,6 +58,8 @@ export function generate(initialRundown: OntimeRundown = persistedRundown) {
|
|||||||
links = {};
|
links = {};
|
||||||
|
|
||||||
let accumulatedDelay = 0;
|
let accumulatedDelay = 0;
|
||||||
|
let previousEnd: number;
|
||||||
|
|
||||||
for (let i = 0; i < initialRundown.length; i++) {
|
for (let i = 0; i < initialRundown.length; i++) {
|
||||||
const currentEvent = initialRundown[i];
|
const currentEvent = initialRundown[i];
|
||||||
let updatedEvent = { ...currentEvent };
|
let updatedEvent = { ...currentEvent };
|
||||||
@@ -89,10 +85,16 @@ export function generate(initialRundown: OntimeRundown = persistedRundown) {
|
|||||||
// calculate delays
|
// calculate delays
|
||||||
if (isOntimeDelay(updatedEvent)) {
|
if (isOntimeDelay(updatedEvent)) {
|
||||||
accumulatedDelay += updatedEvent.duration;
|
accumulatedDelay += updatedEvent.duration;
|
||||||
} else if (isOntimeBlock(updatedEvent)) {
|
|
||||||
accumulatedDelay = 0;
|
|
||||||
} else if (isOntimeEvent(updatedEvent)) {
|
} else if (isOntimeEvent(updatedEvent)) {
|
||||||
|
const eventStart = updatedEvent.timeStart;
|
||||||
|
|
||||||
|
// we only affect positive delays (time forwards)
|
||||||
|
if (accumulatedDelay > 0 && previousEnd) {
|
||||||
|
const gap = Math.max(eventStart - previousEnd, 0);
|
||||||
|
accumulatedDelay = Math.max(accumulatedDelay - gap, 0);
|
||||||
|
}
|
||||||
updatedEvent.delay = accumulatedDelay;
|
updatedEvent.delay = accumulatedDelay;
|
||||||
|
previousEnd = updatedEvent.timeEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
order.push(updatedEvent.id);
|
order.push(updatedEvent.id);
|
||||||
@@ -100,7 +102,8 @@ export function generate(initialRundown: OntimeRundown = persistedRundown) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isStale = false;
|
isStale = false;
|
||||||
return { rundown, order, links };
|
totalDelay = accumulatedDelay;
|
||||||
|
return { rundown, order, links, totalDelay };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns an ID guaranteed to be unique */
|
/** Returns an ID guaranteed to be unique */
|
||||||
@@ -153,6 +156,7 @@ type MutatingReturn = {
|
|||||||
newEvent?: OntimeRundownEntry;
|
newEvent?: OntimeRundownEntry;
|
||||||
};
|
};
|
||||||
type MutatingFn<T extends object> = (params: MutationParams<T>) => MutatingReturn;
|
type MutatingFn<T extends object> = (params: MutationParams<T>) => MutatingReturn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decorators injects data into mutation
|
* Decorators injects data into mutation
|
||||||
* @param mutation
|
* @param mutation
|
||||||
@@ -182,10 +186,12 @@ export function mutateCache<T extends object>(mutation: MutatingFn<T>) {
|
|||||||
// TODO: could we return a patch object?
|
// TODO: could we return a patch object?
|
||||||
return { newEvent };
|
return { newEvent };
|
||||||
}
|
}
|
||||||
|
|
||||||
return scopedMutation;
|
return scopedMutation;
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddArgs = MutationParams<{ atIndex: number; event: OntimeRundownEntry }>;
|
type AddArgs = MutationParams<{ atIndex: number; event: OntimeRundownEntry }>;
|
||||||
|
|
||||||
export function add({ persistedRundown, atIndex, event }: AddArgs): Required<MutatingReturn> {
|
export function add({ persistedRundown, atIndex, event }: AddArgs): Required<MutatingReturn> {
|
||||||
const newEvent: OntimeRundownEntry = { ...event };
|
const newEvent: OntimeRundownEntry = { ...event };
|
||||||
const newRundown = insertAtIndex(atIndex, newEvent, persistedRundown);
|
const newRundown = insertAtIndex(atIndex, newEvent, persistedRundown);
|
||||||
@@ -194,6 +200,7 @@ export function add({ persistedRundown, atIndex, event }: AddArgs): Required<Mut
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoveArgs = MutationParams<{ eventId: string }>;
|
type RemoveArgs = MutationParams<{ eventId: string }>;
|
||||||
|
|
||||||
export function remove({ persistedRundown, eventId }: RemoveArgs): MutatingReturn {
|
export function remove({ persistedRundown, eventId }: RemoveArgs): MutatingReturn {
|
||||||
const atIndex = persistedRundown.findIndex((event) => event.id === eventId);
|
const atIndex = persistedRundown.findIndex((event) => event.id === eventId);
|
||||||
const newRundown = deleteAtIndex(atIndex, persistedRundown);
|
const newRundown = deleteAtIndex(atIndex, persistedRundown);
|
||||||
@@ -222,6 +229,7 @@ function makeEvent(eventFromRundown: OntimeRundownEntry, patch: Partial<OntimeRu
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EditArgs = MutationParams<{ eventId: string; patch: Partial<OntimeRundownEntry> }>;
|
type EditArgs = MutationParams<{ eventId: string; patch: Partial<OntimeRundownEntry> }>;
|
||||||
|
|
||||||
export function edit({ persistedRundown, eventId, patch }: EditArgs): Required<MutatingReturn> {
|
export function edit({ persistedRundown, eventId, patch }: EditArgs): Required<MutatingReturn> {
|
||||||
const indexAt = persistedRundown.findIndex((event) => event.id === eventId);
|
const indexAt = persistedRundown.findIndex((event) => event.id === eventId);
|
||||||
|
|
||||||
@@ -246,6 +254,7 @@ export function edit({ persistedRundown, eventId, patch }: EditArgs): Required<M
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BatchEditArgs = MutationParams<{ eventIds: string[]; patch: Partial<OntimeRundownEntry> }>;
|
type BatchEditArgs = MutationParams<{ eventIds: string[]; patch: Partial<OntimeRundownEntry> }>;
|
||||||
|
|
||||||
export function batchEdit({ persistedRundown, eventIds, patch }: BatchEditArgs): MutatingReturn {
|
export function batchEdit({ persistedRundown, eventIds, patch }: BatchEditArgs): MutatingReturn {
|
||||||
const ids = new Set(eventIds);
|
const ids = new Set(eventIds);
|
||||||
|
|
||||||
@@ -265,6 +274,7 @@ export function batchEdit({ persistedRundown, eventIds, patch }: BatchEditArgs):
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ReorderArgs = MutationParams<{ eventId: string; from: number; to: number }>;
|
type ReorderArgs = MutationParams<{ eventId: string; from: number; to: number }>;
|
||||||
|
|
||||||
export function reorder({ persistedRundown, eventId, from, to }: ReorderArgs): Required<MutatingReturn> {
|
export function reorder({ persistedRundown, eventId, from, to }: ReorderArgs): Required<MutatingReturn> {
|
||||||
const event = persistedRundown[from];
|
const event = persistedRundown[from];
|
||||||
if (!event || eventId !== event.id) {
|
if (!event || eventId !== event.id) {
|
||||||
@@ -282,12 +292,14 @@ export function reorder({ persistedRundown, eventId, from, to }: ReorderArgs): R
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ApplyDelayArgs = MutationParams<{ eventId: string }>;
|
type ApplyDelayArgs = MutationParams<{ eventId: string }>;
|
||||||
|
|
||||||
export function applyDelay({ persistedRundown, eventId }: ApplyDelayArgs): MutatingReturn {
|
export function applyDelay({ persistedRundown, eventId }: ApplyDelayArgs): MutatingReturn {
|
||||||
const newRundown = apply(eventId, persistedRundown);
|
const newRundown = apply(eventId, persistedRundown);
|
||||||
return { newRundown };
|
return { newRundown };
|
||||||
}
|
}
|
||||||
|
|
||||||
type SwapArgs = MutationParams<{ fromId: string; toId: string }>;
|
type SwapArgs = MutationParams<{ fromId: string; toId: string }>;
|
||||||
|
|
||||||
export function swap({ persistedRundown, fromId, toId }: SwapArgs): MutatingReturn {
|
export function swap({ persistedRundown, fromId, toId }: SwapArgs): MutatingReturn {
|
||||||
const indexA = persistedRundown.findIndex((event) => event.id === fromId);
|
const indexA = persistedRundown.findIndex((event) => event.id === fromId);
|
||||||
const eventA = persistedRundown.at(indexA);
|
const eventA = persistedRundown.at(indexA);
|
||||||
|
|||||||
Reference in New Issue
Block a user