mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-11 09:09:34 +00:00
Alpha 5 (#1741)
* refactor: align header columns * refactor: improve scrollbar visibility * refactor: center align table elements * refactor: make param elements stateful * fix: issue with collapsed elements not loosing value * fix: prevent search params containing multiple alias references * fix: the issue where a file disappears if it is both migrated and recovered in the same load operation (#1744) * refactor: disable group action for elements in groups * refactor: move context menu items into the event element (#1747) * feat: sheet import new features for v4 (#1730) * import milestone * fixup! import milestone * test: milestone import * add entries to group stop on new group or on group-end type * fixup! add entries to group * cleanup * add event target duration * link start if undefined * add skip import type * extract some to the excel paresing functions * tweaks to presentation * move file --------- Co-authored-by: Carlos Valente <carlosvalente@pm.me> * fix: notify runtimeStore of events bieng groupd * fix: improve authentication and stage detection in demo * chore: ship logo with project * fix: client is referenced by name * fix: prevent reflow in event editor * fix: stale render on selected event due to ref mismatch * Create/Load/Delete multiple rundowns (#1696) * refactor: restore last loaded rundown * refactor: initialise rundown in ProjectService * feat: allow switching rundowns ensure on coordination between the db object and the working object server provide list of rundowns implement switch in the UI implement delete implement new rundown button * fix: render order for floating button * refactor: appropriate names to service * refactor: rundown endpoints * refactor: save last loaded rundown ID * refactor: rundown management UI * refactor: emit refetch all on project load --------- Co-authored-by: Carlos Valente <carlosvalente@pm.me> * feat: recover single event subscription * fixup! feat: sheet import new features for v4 (#1730) * fix: prevent dropping a group inside another * fixup! refactor: move context menu items into the event element (#1747) * fix: prevent stale references to custom fields * fix: propagate updates to all rundowns * refactor: client rundown metadata (#1728) * generate metadata in the hook * move test * ensure there is always a last element * use for-loop * update metadata in useEfect * fully extract metadata generation * use direct assignment * cleanup --------- Co-authored-by: Carlos Valente <carlosvalente@pm.me> * refactor: small imporvement and tests for coerce functions (#1752) * refactor: small imporvement and tests for coerce functions add test `coerceString` add test `coerceBoolean` add test `coerceColour` * remove old todo * fix: consistent quick add behaviour * refactor: create flat rundown with metadata * fix: show add buttons on top * feat: allow editing milestones * refactor: style tweaks to rundown elements refactor: milestones are full width refactor: cuesheet header alignment fix: editor styling in cuesheet * refactor: virtualise table * refactor: improve overscan (#1758) * bump version to 4.0.0-alpha.5 --------- Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
import { millisToSeconds } from 'ontime-utils';
|
||||
import {
|
||||
EntryId,
|
||||
isOntimeEvent,
|
||||
isPlayableEvent,
|
||||
MaybeNumber,
|
||||
OntimeEvent,
|
||||
Rundown,
|
||||
Offset,
|
||||
TimerState,
|
||||
TimerType,
|
||||
} from 'ontime-types';
|
||||
|
||||
import { deepEqual } from 'fast-equals';
|
||||
|
||||
export function isNewSecond(
|
||||
previousValue: MaybeNumber | undefined,
|
||||
currentValue: MaybeNumber | undefined,
|
||||
direction: TimerType.CountDown | TimerType.CountUp = TimerType.CountDown,
|
||||
) {
|
||||
return millisToSeconds(currentValue ?? null, direction) !== millisToSeconds(previousValue ?? null, direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we should update the clock value
|
||||
* - we have rolled into a new seconds unit
|
||||
* this is different from the timer update as it looks at the clock as counting up
|
||||
*/
|
||||
export function getShouldClockUpdate(previousUpdate: number, now: number): boolean {
|
||||
const newSeconds = millisToSeconds(now, TimerType.CountUp) !== millisToSeconds(previousUpdate, TimerType.CountUp);
|
||||
return newSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we should update the timer value
|
||||
* - we have rolled into a new seconds unit
|
||||
*/
|
||||
export function getShouldTimerUpdate(previousValue: TimerState | undefined, currentValue: TimerState): boolean {
|
||||
if (previousValue === undefined) return true;
|
||||
return (
|
||||
// current timer value
|
||||
isNewSecond(previousValue.current, currentValue.current) ||
|
||||
//secondary timer value, when in pre-roll
|
||||
isNewSecond(previousValue.secondaryTimer, currentValue.secondaryTimer) ||
|
||||
// other timer values that could have changed
|
||||
previousValue.addedTime !== currentValue.addedTime ||
|
||||
previousValue.duration !== currentValue.duration ||
|
||||
previousValue.phase !== currentValue.phase ||
|
||||
previousValue.playback !== currentValue.playback ||
|
||||
previousValue.startedAt !== currentValue.startedAt
|
||||
// elapsed - this would be the direct invert of current value so no need to check
|
||||
// expectedFinish - this will be moved out by the current value going into over time, no need to check
|
||||
);
|
||||
}
|
||||
|
||||
export function getShouldOffsetUpdate(
|
||||
previousValue: Offset | undefined,
|
||||
currentValue: Offset,
|
||||
didDependencyUpdate: boolean,
|
||||
): boolean {
|
||||
if (previousValue === undefined) return true;
|
||||
if (previousValue.mode !== currentValue.mode) return true;
|
||||
// absolute, relative, expected*End are ticked with `didDependencyUpdate`
|
||||
return didDependencyUpdate && !deepEqual(previousValue, currentValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* finds the previous playable event, if it exists
|
||||
*/
|
||||
export function findPreviousPlayableId(playableEventsOrder: EntryId[], currentEventId?: string): EntryId | undefined {
|
||||
if (!playableEventsOrder.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if there is no event running, go to first
|
||||
if (!currentEventId) {
|
||||
return getFirstPlayableId(playableEventsOrder);
|
||||
}
|
||||
|
||||
const currentIndex = playableEventsOrder.findIndex((eventId) => eventId === currentEventId);
|
||||
|
||||
if (currentIndex < 1) {
|
||||
return getFirstPlayableId(playableEventsOrder);
|
||||
}
|
||||
|
||||
return playableEventsOrder.at(currentIndex - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* finds the next event playable event, if it exists
|
||||
*/
|
||||
export function findNextPlayableId(playableEventsOrder: EntryId[], currentEventId?: string): EntryId | undefined {
|
||||
if (!playableEventsOrder.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if there is no event running, go to first
|
||||
if (!currentEventId) {
|
||||
return getFirstPlayableId(playableEventsOrder);
|
||||
}
|
||||
|
||||
const currentIndex = playableEventsOrder.findIndex((eventId) => eventId === currentEventId);
|
||||
if (currentIndex === -1 || currentIndex >= playableEventsOrder.length - 1) {
|
||||
return getFirstPlayableId(playableEventsOrder);
|
||||
}
|
||||
|
||||
return playableEventsOrder.at(currentIndex + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns next event that matches a given cue
|
||||
* then loops from the start
|
||||
*/
|
||||
export function findNextPlayableWithCue(
|
||||
rundown: Rundown,
|
||||
playableEventsOrder: EntryId[],
|
||||
targetCue: string,
|
||||
currentEventIndex = 0,
|
||||
): OntimeEvent | undefined {
|
||||
const lowerCaseCue = targetCue.toLowerCase();
|
||||
|
||||
for (let i = currentEventIndex; i < playableEventsOrder.length; i++) {
|
||||
const eventId = playableEventsOrder[i];
|
||||
const event = rundown.entries[eventId];
|
||||
if (isOntimeEvent(event) && isPlayableEvent(event) && event.cue.toLowerCase() === lowerCaseCue) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < currentEventIndex; i++) {
|
||||
const eventId = playableEventsOrder[i];
|
||||
const event = rundown.entries[eventId];
|
||||
if (isOntimeEvent(event) && isPlayableEvent(event) && event.cue.toLowerCase() === lowerCaseCue) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility returns the first playable event in rundown, if it exists
|
||||
*/
|
||||
export function getFirstPlayableId(playableOrder: EntryId[]): EntryId | undefined {
|
||||
return playableOrder.at(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a utility function to return an event at a given index
|
||||
* It uses the timedEventOrder so that the index is the same as the one in the UI
|
||||
*/
|
||||
export function getEventAtIndex(
|
||||
rundown: Rundown,
|
||||
timedEventOrder: EntryId[],
|
||||
eventIndex: number,
|
||||
): OntimeEvent | undefined {
|
||||
const eventId = timedEventOrder[eventIndex];
|
||||
if (!eventId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return rundown.entries[eventId] as OntimeEvent | undefined;
|
||||
}
|
||||
Reference in New Issue
Block a user