From 486d89ecf49f5388976bc39f8877adf9e825adc1 Mon Sep 17 00:00:00 2001 From: Alex Christoffer Rasmussen Date: Fri, 8 Aug 2025 20:17:57 +0200 Subject: [PATCH] refactor: remove finishedAt from runtime data (#1716) --- .../template-input/templateInput.utils.ts | 1 - .../src/services/__tests__/timerUtils.test.ts | 56 ++++++++----------- apps/server/src/services/timerUtils.ts | 6 +- .../stores/__mocks__/runtimeState.mocks.ts | 2 +- .../src/stores/__tests__/runtimeState.test.ts | 2 +- apps/server/src/stores/runtimeState.ts | 16 +++--- .../src/definitions/runtime/RuntimeStore.ts | 1 - .../definitions/runtime/TimerState.type.ts | 4 +- 8 files changed, 38 insertions(+), 50 deletions(-) diff --git a/apps/client/src/features/app-settings/panel/automations-panel/template-input/templateInput.utils.ts b/apps/client/src/features/app-settings/panel/automations-panel/template-input/templateInput.utils.ts index bbc8e389b..9542b84f3 100644 --- a/apps/client/src/features/app-settings/panel/automations-panel/template-input/templateInput.utils.ts +++ b/apps/client/src/features/app-settings/panel/automations-panel/template-input/templateInput.utils.ts @@ -16,7 +16,6 @@ const staticAutocompleteOptions = [ '{{timer.duration}}', '{{timer.elapsed}}', '{{timer.expectedFinish}}', - '{{timer.finishedAt}}', '{{timer.secondaryTimer}}', '{{timer.startedAt}}', '{{runtime.selectedEventIndex}}', diff --git a/apps/server/src/services/__tests__/timerUtils.test.ts b/apps/server/src/services/__tests__/timerUtils.test.ts index a71ba4591..8a6bed563 100644 --- a/apps/server/src/services/__tests__/timerUtils.test.ts +++ b/apps/server/src/services/__tests__/timerUtils.test.ts @@ -21,17 +21,17 @@ describe('getExpectedFinish()', () => { timer: { addedTime: 0, duration: 10, - finishedAt: null, startedAt: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; const calculatedFinish = getExpectedFinish(state); expect(calculatedFinish).toBe(null); }); - it('is finishedAt if defined', () => { + it('is hasFinished if defined', () => { const state = { eventNow: { timeEnd: 20, @@ -40,11 +40,11 @@ describe('getExpectedFinish()', () => { timer: { addedTime: 0, duration: 10, - finishedAt: 20, // <---- finished at startedAt: 10, }, _timer: { pausedAt: null, + hasFinished: true, }, } as RuntimeState; const calculatedFinish = getExpectedFinish(state); @@ -59,11 +59,11 @@ describe('getExpectedFinish()', () => { timer: { addedTime: 0, duration: 10, - finishedAt: null, startedAt: 1, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; const calculatedFinish = getExpectedFinish(state); @@ -78,11 +78,11 @@ describe('getExpectedFinish()', () => { timer: { addedTime: 20, duration: 10, - finishedAt: null, startedAt: 1, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -98,11 +98,11 @@ describe('getExpectedFinish()', () => { timer: { addedTime: -10, duration: 10, - finishedAt: null, startedAt: 1, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -118,11 +118,11 @@ describe('getExpectedFinish()', () => { timer: { addedTime: -100, duration: 10, - finishedAt: null, startedAt: 1, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -138,11 +138,11 @@ describe('getExpectedFinish()', () => { timer: { addedTime: 0, duration: 0, - finishedAt: null, startedAt: 1, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -158,11 +158,11 @@ describe('getExpectedFinish()', () => { timer: { addedTime: 0, duration: dayInMs, - finishedAt: null, startedAt: 10, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -179,11 +179,11 @@ describe('getExpectedFinish()', () => { timer: { addedTime: 10, duration: dayInMs, - finishedAt: null, startedAt: 10, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -198,11 +198,11 @@ describe('getExpectedFinish()', () => { }, timer: { addedTime: 0, - finishedAt: null, startedAt: 79200000, // 22:00:00 }, _timer: { pausedAt: null, + hasFinished: false, }, runtime: { actualStart: 79200000, @@ -229,10 +229,10 @@ describe('getCurrent()', () => { addedTime: 10, duration: 111, // <-- we take the duration value startedAt: null, - finishedAt: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -250,10 +250,10 @@ describe('getCurrent()', () => { addedTime: 0, duration: 10, startedAt: 0, - finishedAt: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -271,10 +271,10 @@ describe('getCurrent()', () => { addedTime: 10, duration: 10, startedAt: 0, - finishedAt: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -292,10 +292,10 @@ describe('getCurrent()', () => { addedTime: 0, duration: dayInMs + 10, startedAt: 10, - finishedAt: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -313,10 +313,10 @@ describe('getCurrent()', () => { addedTime: 0, duration: dayInMs + 10, startedAt: 10, - finishedAt: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -334,10 +334,10 @@ describe('getCurrent()', () => { addedTime: 20, duration: dayInMs + 10, startedAt: 10, - finishedAt: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -357,13 +357,13 @@ describe('getCurrent()', () => { addedTime: 0, duration: 100, startedAt: null, - finishedAt: null, }, runtime: { plannedEnd: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -382,13 +382,13 @@ describe('getCurrent()', () => { addedTime: 0, duration: 100, startedAt: 10, - finishedAt: null, }, runtime: { plannedEnd: 100, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -407,13 +407,13 @@ describe('getCurrent()', () => { addedTime: 7, duration: 100, startedAt: 10, - finishedAt: null, }, runtime: { plannedEnd: 100, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -433,7 +433,6 @@ describe('getCurrent()', () => { addedTime: 0, duration: Infinity, // not relevant, startedAt: 79200000, // 22:00:00 - finishedAt: null, }, runtime: { actualStart: 79200000, @@ -441,6 +440,7 @@ describe('getCurrent()', () => { }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -461,7 +461,6 @@ describe('getCurrent()', () => { addedTime: 0, duration: Infinity, // not relevant, startedAt: 79200000, // 22:00:00 - finishedAt: null, }, runtime: { actualStart: 82000000, // 22:46:40 <--- started now @@ -469,6 +468,7 @@ describe('getCurrent()', () => { }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -491,10 +491,10 @@ describe('getExpectedFinish() and getCurrentTime() combined', () => { addedTime: 0, duration, startedAt: 0, - finishedAt: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -519,10 +519,10 @@ describe('getExpectedFinish() and getCurrentTime() combined', () => { addedTime: 3, duration, startedAt: 0, - finishedAt: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; @@ -846,7 +846,6 @@ describe('getRuntimeOffset()', () => { duration: 3600000, elapsed: null, expectedFinish: null, - finishedAt: null, playback: 'armed', secondaryTimer: null, startedAt: null, @@ -887,7 +886,6 @@ describe('getRuntimeOffset()', () => { duration: 3600000, elapsed: null, expectedFinish: null, - finishedAt: null, playback: 'armed', secondaryTimer: null, startedAt: null, @@ -939,7 +937,6 @@ describe('getRuntimeOffset()', () => { duration: 3600000, elapsed: 2000000, expectedFinish: 81600000, - finishedAt: null, playback: Playback.Play, secondaryTimer: null, startedAt: 78000000, @@ -991,7 +988,6 @@ describe('getRuntimeOffset()', () => { duration: 3600000, elapsed: 4000000, expectedFinish: 81600000, - finishedAt: null, playback: Playback.Play, secondaryTimer: null, startedAt: 78000000, @@ -1032,7 +1028,6 @@ describe('getRuntimeOffset()', () => { duration: 3600000, elapsed: 0, expectedFinish: 82000000 + 3600000, // <--- now + duration - finishedAt: null, playback: Playback.Play, secondaryTimer: null, startedAt: 82000000, // <--- started now @@ -1132,7 +1127,6 @@ describe('getTimerPhase()', () => { duration: null, elapsed: null, expectedFinish: null, - finishedAt: null, playback: Playback.Stop, phase: TimerPhase.None, secondaryTimer: null, @@ -1236,7 +1230,6 @@ describe('getTimerPhase()', () => { duration: null, elapsed: 0, expectedFinish: null, - finishedAt: null, phase: 'none', playback: 'roll', secondaryTimer: 168950, @@ -1275,7 +1268,6 @@ describe('getTimerPhase()', () => { duration: null, elapsed: 0, expectedFinish: null, - finishedAt: null, phase: 'none', playback: 'roll', secondaryTimer: 168950, diff --git a/apps/server/src/services/timerUtils.ts b/apps/server/src/services/timerUtils.ts index 9f119abe3..6d3a41723 100644 --- a/apps/server/src/services/timerUtils.ts +++ b/apps/server/src/services/timerUtils.ts @@ -13,7 +13,7 @@ export const normaliseEndTime = (start: number, end: number) => (end < start ? e * @returns {number | null} new current time or null if nothing is running */ export function getExpectedFinish(state: RuntimeState): MaybeNumber { - const { startedAt, finishedAt, duration, addedTime } = state.timer; + const { startedAt, duration, addedTime } = state.timer; if (state.eventNow === null) { return null; @@ -27,10 +27,6 @@ export function getExpectedFinish(state: RuntimeState): MaybeNumber { return null; } - if (finishedAt !== null) { - return finishedAt; - } - const pausedTime = pausedAt != null ? clock - pausedAt : 0; if (countToEnd) { diff --git a/apps/server/src/stores/__mocks__/runtimeState.mocks.ts b/apps/server/src/stores/__mocks__/runtimeState.mocks.ts index 53a34c6df..338ba6c9e 100644 --- a/apps/server/src/stores/__mocks__/runtimeState.mocks.ts +++ b/apps/server/src/stores/__mocks__/runtimeState.mocks.ts @@ -26,7 +26,6 @@ const baseState: RuntimeState = { duration: null, elapsed: null, expectedFinish: null, - finishedAt: null, phase: TimerPhase.None, playback: Playback.Stop, secondaryTimer: null, @@ -36,6 +35,7 @@ const baseState: RuntimeState = { forceFinish: null, pausedAt: null, secondaryTarget: null, + hasFinished: false, }, _rundown: { totalDelay: 0, diff --git a/apps/server/src/stores/__tests__/runtimeState.test.ts b/apps/server/src/stores/__tests__/runtimeState.test.ts index 182b4fa77..d1cdb36ec 100644 --- a/apps/server/src/stores/__tests__/runtimeState.test.ts +++ b/apps/server/src/stores/__tests__/runtimeState.test.ts @@ -43,13 +43,13 @@ const mockState = { duration: null, elapsed: null, expectedFinish: null, - finishedAt: null, playback: Playback.Stop, secondaryTimer: null, startedAt: null, }, _timer: { pausedAt: null, + hasFinished: false, }, } as RuntimeState; diff --git a/apps/server/src/stores/runtimeState.ts b/apps/server/src/stores/runtimeState.ts index c3fa806cf..f8771b73b 100644 --- a/apps/server/src/stores/runtimeState.ts +++ b/apps/server/src/stores/runtimeState.ts @@ -48,6 +48,7 @@ export type RuntimeState = { forceFinish: MaybeNumber; // whether we should declare an event as finished, will contain the finish time pausedAt: MaybeNumber; secondaryTarget: MaybeNumber; + hasFinished: boolean; }; _rundown: { totalDelay: number; // this value comes from rundown service @@ -70,6 +71,7 @@ const runtimeState: RuntimeState = { forceFinish: null, pausedAt: null, secondaryTarget: null, + hasFinished: false, }, _rundown: { totalDelay: 0, @@ -115,6 +117,7 @@ export function clearEventData() { runtimeState._timer.forceFinish = null; runtimeState._timer.pausedAt = null; runtimeState._timer.secondaryTarget = null; + runtimeState._timer.hasFinished = false; } // clear all necessary data when doing a full stop and the event is unloaded @@ -144,6 +147,7 @@ export function clearState() { runtimeState._timer.forceFinish = null; runtimeState._timer.pausedAt = null; runtimeState._timer.secondaryTarget = null; + runtimeState._timer.hasFinished = false; } /** @@ -332,7 +336,7 @@ export function updateLoaded(event?: PlayableEvent): string | undefined { runtimeState.timer.current = runtimeState.timer.duration; runtimeState.timer.startedAt = null; - runtimeState.timer.finishedAt = null; + runtimeState._timer.hasFinished = false; runtimeState.timer.addedTime = 0; runtimeState._timer.pausedAt = null; @@ -450,15 +454,14 @@ export function addTime(amount: number) { // handle edge cases // !!! we need to handle side effects before updating the state const willGoNegative = amount < 0 && Math.abs(amount) > runtimeState.timer.current; - const hasFinished = runtimeState.timer.finishedAt !== null; - if (willGoNegative && !hasFinished) { + if (willGoNegative && !runtimeState._timer.hasFinished) { // set finished time so side effects are triggered runtimeState._timer.forceFinish = timeNow(); } else { const willGoPositive = runtimeState.timer.current < 0 && runtimeState.timer.current + amount > 0; if (willGoPositive) { - runtimeState.timer.finishedAt = null; + runtimeState._timer.hasFinished = false; } } @@ -522,11 +525,10 @@ export function update(): UpdateResult { const finishedNow = Boolean(runtimeState._timer.forceFinish) || - (runtimeState.timer.current <= timerConfig.triggerAhead && runtimeState.timer.finishedAt === null); + (runtimeState.timer.current <= timerConfig.triggerAhead && !runtimeState._timer.hasFinished); if (finishedNow) { - // reset state - runtimeState.timer.finishedAt = runtimeState._timer.forceFinish ?? runtimeState.clock; + runtimeState._timer.hasFinished = true; } else { runtimeState.timer.expectedFinish = getExpectedFinish(runtimeState); } diff --git a/packages/types/src/definitions/runtime/RuntimeStore.ts b/packages/types/src/definitions/runtime/RuntimeStore.ts index 90627b50e..6cc197a44 100644 --- a/packages/types/src/definitions/runtime/RuntimeStore.ts +++ b/packages/types/src/definitions/runtime/RuntimeStore.ts @@ -12,7 +12,6 @@ export const runtimeStorePlaceholder: Readonly = { duration: null, // only changes if event changes elapsed: null, // changes on every update expectedFinish: null, // change can only be initiated by user, can roll over midnight - finishedAt: null, // can change on update or user action phase: TimerPhase.None, // can change on update or user action playback: Playback.Stop, // change initiated by user secondaryTimer: null, // change on every update diff --git a/packages/types/src/definitions/runtime/TimerState.type.ts b/packages/types/src/definitions/runtime/TimerState.type.ts index 302f4e62e..8be3c2f64 100644 --- a/packages/types/src/definitions/runtime/TimerState.type.ts +++ b/packages/types/src/definitions/runtime/TimerState.type.ts @@ -22,9 +22,9 @@ export type TimerState = { elapsed: MaybeNumber; /** time we expect timer to finish */ expectedFinish: MaybeNumber; - /** only if timer has already finished */ - finishedAt: MaybeNumber; + /** phase of of the running event */ phase: TimerPhase; + /** playback state of the event */ playback: Playback; /** used for roll mode */ secondaryTimer: MaybeNumber;