mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-20 22:49:18 +00:00
feat: add group metadata to overview
This commit is contained in:
committed by
Carlos Valente
parent
17a7d035bf
commit
a7ae8598db
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { OntimeEntry, Rundown } from 'ontime-types';
|
import { EntryId, OntimeEntry, Rundown } from 'ontime-types';
|
||||||
|
|
||||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||||
import { RUNDOWN } from '../api/constants';
|
import { RUNDOWN } from '../api/constants';
|
||||||
@@ -78,3 +78,18 @@ export function usePartialRundown(cb: (event: OntimeEntry) => boolean) {
|
|||||||
|
|
||||||
return { data: filteredData, status };
|
return { data: filteredData, status };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to get a specific entry by ID from the rundown
|
||||||
|
*/
|
||||||
|
export function useEntry(entryId: EntryId | null): OntimeEntry | null {
|
||||||
|
const { data: rundown } = useRundown();
|
||||||
|
|
||||||
|
// track the specific entry we care about
|
||||||
|
const entry = useMemo(() => {
|
||||||
|
if (entryId === null) return null;
|
||||||
|
return rundown.entries[entryId];
|
||||||
|
}, [entryId, rundown.entries]);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,13 @@ import { memo, PropsWithChildren, useMemo } from 'react';
|
|||||||
import { useIsMobileScreen } from '../../common/hooks/useIsMobileScreen';
|
import { useIsMobileScreen } from '../../common/hooks/useIsMobileScreen';
|
||||||
import { useRuntimeOverview } from '../../common/hooks/useSocket';
|
import { useRuntimeOverview } from '../../common/hooks/useSocket';
|
||||||
|
|
||||||
import { CurrentBlockOverview, OverviewWrapper, RuntimeOverview, TimerOverview } from './composite/OverviewWrapper';
|
import {
|
||||||
|
ClockOverview,
|
||||||
|
CurrentBlockOverview,
|
||||||
|
OverviewWrapper,
|
||||||
|
RuntimeOverview,
|
||||||
|
TimerOverview,
|
||||||
|
} from './composite/OverviewWrapper';
|
||||||
import { TimeRow } from './composite/TimeLayout';
|
import { TimeRow } from './composite/TimeLayout';
|
||||||
import { calculateEndAndDaySpan, formatedTime } from './overviewUtils';
|
import { calculateEndAndDaySpan, formatedTime } from './overviewUtils';
|
||||||
|
|
||||||
@@ -51,8 +57,9 @@ function CuesheetDesktop({ children }: PropsWithChildren) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<TimerOverview />
|
<TimerOverview />
|
||||||
<CurrentBlockOverview />
|
|
||||||
<RuntimeOverview />
|
<RuntimeOverview />
|
||||||
|
<CurrentBlockOverview />
|
||||||
|
<ClockOverview />
|
||||||
<div>
|
<div>
|
||||||
<TimeRow
|
<TimeRow
|
||||||
label='Planned end'
|
label='Planned end'
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { memo, PropsWithChildren, useMemo } from 'react';
|
|||||||
import { useRuntimeOverview } from '../../common/hooks/useSocket';
|
import { useRuntimeOverview } from '../../common/hooks/useSocket';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ClockOverview,
|
||||||
CurrentBlockOverview,
|
CurrentBlockOverview,
|
||||||
OverviewWrapper,
|
OverviewWrapper,
|
||||||
ProgressOverview,
|
ProgressOverview,
|
||||||
@@ -42,8 +43,9 @@ function EditorOverview({ children }: PropsWithChildren) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ProgressOverview />
|
<ProgressOverview />
|
||||||
<CurrentBlockOverview />
|
|
||||||
<RuntimeOverview />
|
<RuntimeOverview />
|
||||||
|
<CurrentBlockOverview />
|
||||||
|
<ClockOverview />
|
||||||
<div>
|
<div>
|
||||||
<TimeRow
|
<TimeRow
|
||||||
label='Planned end'
|
label='Planned end'
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
import { PropsWithChildren, ReactNode } from 'react';
|
import { PropsWithChildren, ReactNode } from 'react';
|
||||||
import { ErrorBoundary } from '@sentry/react';
|
import { ErrorBoundary } from '@sentry/react';
|
||||||
|
import { isOntimeBlock } from 'ontime-types';
|
||||||
import { isPlaybackActive, millisToString } from 'ontime-utils';
|
import { isPlaybackActive, millisToString } from 'ontime-utils';
|
||||||
|
|
||||||
import { useIsOnline, useRuntimePlaybackOverview, useTimer } from '../../../common/hooks/useSocket';
|
import {
|
||||||
|
useClock,
|
||||||
|
useCurrentBlockId,
|
||||||
|
useIsOnline,
|
||||||
|
useRuntimePlaybackOverview,
|
||||||
|
useTimer,
|
||||||
|
} from '../../../common/hooks/useSocket';
|
||||||
import useProjectData from '../../../common/hooks-query/useProjectData';
|
import useProjectData from '../../../common/hooks-query/useProjectData';
|
||||||
import { cx, enDash, timerPlaceholder } from '../../../common/utils/styleUtils';
|
import { useEntry } from '../../../common/hooks-query/useRundown';
|
||||||
|
import { cx, enDash, timerPlaceholder, timerPlaceholderMin } from '../../../common/utils/styleUtils';
|
||||||
import { formatedTime, getOffsetText } from '../overviewUtils';
|
import { formatedTime, getOffsetText } from '../overviewUtils';
|
||||||
|
|
||||||
import { TimeColumn } from './TimeLayout';
|
import { TimeColumn, TimeRow } from './TimeLayout';
|
||||||
|
|
||||||
import style from '../Overview.module.scss';
|
import style from '../Overview.module.scss';
|
||||||
|
|
||||||
@@ -44,10 +52,48 @@ export function TitlesOverview() {
|
|||||||
|
|
||||||
export function CurrentBlockOverview() {
|
export function CurrentBlockOverview() {
|
||||||
const { blockStartedAt: blockStartAt, clock } = useRuntimePlaybackOverview();
|
const { blockStartedAt: blockStartAt, clock } = useRuntimePlaybackOverview();
|
||||||
|
const { currentBlockId } = useCurrentBlockId();
|
||||||
|
const entry = useEntry(currentBlockId);
|
||||||
|
|
||||||
const timeInBlock = formatedTime(blockStartAt ? clock - blockStartAt : null);
|
const timeInBlock = formatedTime(blockStartAt ? clock - blockStartAt : null, 2);
|
||||||
|
|
||||||
return <TimeColumn label='Time in block' value={timeInBlock} className={style.clock} muted={blockStartAt === null} />;
|
/**
|
||||||
|
* The time to the end of the block
|
||||||
|
* as scheduled
|
||||||
|
* TODO(v4): this needs to be calculated according to offset mode
|
||||||
|
*/
|
||||||
|
const blockEnd = (() => {
|
||||||
|
if (!entry) return timerPlaceholderMin;
|
||||||
|
if (!isOntimeBlock(entry)) return timerPlaceholderMin;
|
||||||
|
if (entry.timeEnd === null) return timerPlaceholderMin;
|
||||||
|
return formatedTime(entry.timeEnd - clock, 2);
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time to the end of the block
|
||||||
|
* as projected accounting for delays and offset
|
||||||
|
* TODO(v4): this needs to be calculated according to offset mode
|
||||||
|
*/
|
||||||
|
const projectedBlockEnd = (() => {
|
||||||
|
if (blockStartAt === null || !entry) return timerPlaceholderMin;
|
||||||
|
if (!isOntimeBlock(entry)) return timerPlaceholderMin;
|
||||||
|
return formatedTime(blockStartAt + entry.duration - clock, 2);
|
||||||
|
})();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TimeColumn label='Elapsed in block' value={timeInBlock} className={style.clock} muted={blockStartAt === null} />
|
||||||
|
<div>
|
||||||
|
<TimeRow label='Block end' value={blockEnd} className={style.end} muted={blockStartAt === null} />
|
||||||
|
<TimeRow
|
||||||
|
label='Projected block end'
|
||||||
|
value={projectedBlockEnd}
|
||||||
|
className={style.end}
|
||||||
|
muted={blockStartAt === null}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TimerOverview() {
|
export function TimerOverview() {
|
||||||
@@ -62,23 +108,23 @@ export function ProgressOverview() {
|
|||||||
const { numEvents, selectedEventIndex } = useRuntimePlaybackOverview();
|
const { numEvents, selectedEventIndex } = useRuntimePlaybackOverview();
|
||||||
|
|
||||||
const current = selectedEventIndex !== null ? selectedEventIndex + 1 : enDash;
|
const current = selectedEventIndex !== null ? selectedEventIndex + 1 : enDash;
|
||||||
const ofTotal = numEvents || enDash;
|
const progressText = numEvents ? `${current} of ${numEvents || enDash}` : enDash;
|
||||||
const progressText = numEvents ? `${current} of ${ofTotal}` : '-';
|
|
||||||
|
|
||||||
return <TimeColumn label='Progress' value={progressText} />;
|
return <TimeColumn label='Progress' value={progressText} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RuntimeOverview() {
|
export function RuntimeOverview() {
|
||||||
const { clock, offset, playback } = useRuntimePlaybackOverview();
|
const { offset, playback } = useRuntimePlaybackOverview();
|
||||||
|
|
||||||
const isPlaying = isPlaybackActive(playback);
|
const isPlaying = isPlaybackActive(playback);
|
||||||
const offsetText = getOffsetText(isPlaying ? offset : null);
|
const offsetText = getOffsetText(isPlaying ? offset : null);
|
||||||
const offsetClasses = cx([style.offset, isPlaying && (offset < 0 ? style.behind : style.ahead)]);
|
const offsetClasses = cx([style.offset, isPlaying && (offset < 0 ? style.behind : style.ahead)]);
|
||||||
|
|
||||||
return (
|
return <TimeColumn label='Offset' value={offsetText} className={offsetClasses} testId='offset' />;
|
||||||
<>
|
}
|
||||||
<TimeColumn label='Offset' value={offsetText} className={offsetClasses} testId='offset' />
|
|
||||||
<TimeColumn label='Time now' value={formatedTime(clock)} />
|
export function ClockOverview() {
|
||||||
</>
|
const { clock } = useClock();
|
||||||
);
|
|
||||||
|
return <TimeColumn label='Time now' value={formatedTime(clock)} />;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user