Feat: unify view search params (#1947)

* feat: main src in backstage view

* feat: main src in timeline view

* feat: main src in countdown view

* feat: main src in studio view

* feat: hide past events in countdown view

* notes can not be set as main src

* feat: show group title as secondary src

* chore: spelling

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>

---------

Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
This commit is contained in:
Alex Christoffer Rasmussen
2026-01-27 20:42:07 +01:00
committed by GitHub
parent ec1890c275
commit 026e24bf84
28 changed files with 224 additions and 64 deletions
+2 -1
View File
@@ -49,7 +49,7 @@ export default function TimerLoader() {
return <Timer {...data} />;
}
function Timer({ customFields, projectData, isMirrored, settings, viewSettings }: TimerData) {
function Timer({ customFields, projectData, isMirrored, settings, viewSettings, entries }: TimerData) {
const { eventNext, eventNow, message, time, clock, timerTypeNow, countToEndNow, auxTimer } = useTimerSocket();
const {
hideClock,
@@ -97,6 +97,7 @@ function Timer({ customFields, projectData, isMirrored, settings, viewSettings }
secondarySource,
time.playback,
time.phase,
entries,
);
// gather timer data
+3 -3
View File
@@ -27,12 +27,12 @@ export const getTimerOptions = (timeFormat: string, customFields: CustomFields):
const mainOptions = makeOptionsFromCustomFields(customFields, [
{ value: 'none', label: 'None' },
{ value: 'title', label: 'Title' },
{ value: 'note', label: 'Note' },
]);
const secondaryOptions = makeOptionsFromCustomFields(customFields, [
{ value: 'none', label: 'None' },
{ value: 'title', label: 'Title' },
{ value: 'note', label: 'Note' },
{ value: 'parent', label: 'Group Title' },
]);
return [
@@ -185,8 +185,8 @@ type TimerOptions = {
hideLogo: boolean;
hideTimerSeconds: boolean;
removeLeadingZeros: boolean;
mainSource: keyof OntimeEvent | null;
secondarySource: keyof OntimeEvent | null;
mainSource: keyof OntimeEvent | null | 'none';
secondarySource: keyof OntimeEvent | null | 'none';
timerType?: TimerType;
freezeOvertime: boolean;
freezeMessage: string;
+18 -8
View File
@@ -1,4 +1,13 @@
import { MaybeNumber, MessageState, OntimeEvent, Playback, TimerMessage, TimerPhase, TimerType } from 'ontime-types';
import {
MaybeNumber,
MessageState,
OntimeEvent,
Playback,
RundownEntries,
TimerMessage,
TimerPhase,
TimerType,
} from 'ontime-types';
import { isPlaybackActive } from 'ontime-utils';
import { getFormattedTimer, getPropertyValue } from '../common/viewUtils';
@@ -141,10 +150,11 @@ export function getSecondaryDisplay(
export function getCardData(
eventNow: OntimeEvent | null,
eventNext: OntimeEvent | null,
mainSource: keyof OntimeEvent | null,
secondarySource: keyof OntimeEvent | null,
mainSource: keyof OntimeEvent | null | 'none',
secondarySource: keyof OntimeEvent | null | 'none',
playback: Playback,
phase: TimerPhase,
entries: RundownEntries,
) {
if (playback === Playback.Stop) {
return {
@@ -162,19 +172,19 @@ export function getCardData(
// if we are loaded, we show the upcoming event as next
const nowMain = hasActiveTimer ? getPropertyValue(eventNow, mainSource ?? 'title') : undefined;
const nowSecondary = hasActiveTimer ? getPropertyValue(eventNow, secondarySource) : undefined;
const nowSecondary = hasActiveTimer ? getPropertyValue(eventNow, secondarySource, entries) : undefined;
const nextMain = hasActiveTimer
? getPropertyValue(eventNext, mainSource ?? 'title')
: getPropertyValue(eventNow, mainSource ?? 'title');
const nextSecondary = hasActiveTimer
? getPropertyValue(eventNext, secondarySource)
: getPropertyValue(eventNow, secondarySource);
? getPropertyValue(eventNext, secondarySource, entries)
: getPropertyValue(eventNow, secondarySource, entries);
return {
showNow: Boolean(nowMain) || Boolean(nowSecondary),
showNow: mainSource !== 'none' || Boolean(nowSecondary),
nowMain,
nowSecondary,
showNext: Boolean(nextMain) || Boolean(nextSecondary),
showNext: mainSource !== 'none' || Boolean(nextSecondary),
nextMain,
nextSecondary,
};
+13 -2
View File
@@ -1,7 +1,8 @@
import { CustomFields, ProjectData, Settings, ViewSettings } from 'ontime-types';
import { CustomFields, ProjectData, RundownEntries, Settings, ViewSettings } from 'ontime-types';
import useCustomFields from '../../common/hooks-query/useCustomFields';
import useProjectData from '../../common/hooks-query/useProjectData';
import useRundown from '../../common/hooks-query/useRundown';
import useSettings from '../../common/hooks-query/useSettings';
import useViewSettings from '../../common/hooks-query/useViewSettings';
import { useViewOptionsStore } from '../../common/stores/viewOptions';
@@ -13,6 +14,7 @@ export interface TimerData {
isMirrored: boolean;
settings: Settings;
viewSettings: ViewSettings;
entries: RundownEntries;
}
export function useTimerData(): ViewData<TimerData> {
@@ -24,6 +26,8 @@ export function useTimerData(): ViewData<TimerData> {
const { data: viewSettings, status: viewSettingsStatus } = useViewSettings();
const { data: settings, status: settingsStatus } = useSettings();
const { data: customFields, status: customFieldsStatus } = useCustomFields();
const { data: rundown, status: rundownStatus } = useRundown();
const { entries } = rundown;
return {
data: {
@@ -32,7 +36,14 @@ export function useTimerData(): ViewData<TimerData> {
isMirrored,
settings,
viewSettings,
entries,
},
status: aggregateQueryStatus([projectDataStatus, viewSettingsStatus, settingsStatus, customFieldsStatus]),
status: aggregateQueryStatus([
projectDataStatus,
viewSettingsStatus,
settingsStatus,
customFieldsStatus,
rundownStatus,
]),
};
}