From 1fa6175fb892d81a49b2327356821461d318be7a Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 29 Aug 2026 17:48:42 +0000 Subject: [PATCH] refactor(rundown): keep runtime views on the loaded rundown Only the editor and the cuesheet can be pointed at a background rundown. Everything else always works against the rundown being played, so it has no business taking part in a rundown scope. Split the readers by that assumption: - useRundownById holds the query and the shared derivation - useRundown reads from the enclosing scope, for the editor and cuesheet - useLoadedRundown resolves the loaded rundown directly, for the viewers, the operator, app settings and the overview This drops the app wide scope provider, so views which read no rundown (studio, project info) no longer subscribe to the rundown list, and a scope becomes what it claims to be: a panel concern which throws when used outside a panel. It also fixes the overview, which reads runtime ids (the playing group, the next flag). Those only exist in the loaded rundown, so resolving them against a scope returned nothing while a background rundown was open in the cuesheet. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011a5cbVjNC5XXF88b2PkUCa --- apps/client/src/App.tsx | 6 +- .../common/hooks-query/useLoadedRundown.ts | 73 +++++++++++++++ .../src/common/hooks-query/useRundown.ts | 91 +------------------ .../src/common/hooks-query/useRundownById.ts | 66 ++++++++++++++ .../panel/feature-panel/ReportSettings.tsx | 4 +- .../sources-panel/SourcesPanel.tsx | 4 +- .../src/features/operator/useOperatorData.ts | 4 +- .../overview/composite/TimeElements.tsx | 6 +- .../overview/composite/TitleOverview.tsx | 4 +- .../src/views/backstage/useBackstageData.ts | 4 +- .../views/common/schedule/ScheduleContext.tsx | 4 +- .../src/views/countdown/useCountdownData.ts | 4 +- .../src/views/timeline/useTimelineData.ts | 4 +- apps/client/src/views/timer/useTimerData.ts | 4 +- 14 files changed, 166 insertions(+), 112 deletions(-) create mode 100644 apps/client/src/common/hooks-query/useLoadedRundown.ts create mode 100644 apps/client/src/common/hooks-query/useRundownById.ts diff --git a/apps/client/src/App.tsx b/apps/client/src/App.tsx index 28b5498dd..b723476bf 100644 --- a/apps/client/src/App.tsx +++ b/apps/client/src/App.tsx @@ -9,7 +9,6 @@ import AppRouter from './AppRouter'; import ErrorBoundary from './common/components/error-boundary/ErrorBoundary'; import IdentifyOverlay from './common/components/identify-overlay/IdentifyOverlay'; import { AppContextProvider } from './common/context/AppContext'; -import { RundownScopeProvider } from './common/context/RundownScopeContext'; import { ontimeQueryClient } from './common/queryClient'; import { connectSocket } from './common/utils/socket'; import { baseURI } from './externals'; @@ -29,10 +28,7 @@ function App() { - {/* the app follows the loaded rundown, panels nest a scope to point elsewhere */} - - - + diff --git a/apps/client/src/common/hooks-query/useLoadedRundown.ts b/apps/client/src/common/hooks-query/useLoadedRundown.ts new file mode 100644 index 000000000..f1da2e6df --- /dev/null +++ b/apps/client/src/common/hooks-query/useLoadedRundown.ts @@ -0,0 +1,73 @@ +import { EntryId, OntimeEntry } from 'ontime-types'; +import { useMemo } from 'react'; + +import { useSelectedEventId } from '../hooks/useSocket'; +import { ExtendedEntry, getFlatRundownMetadata, getRundownMetadata } from '../utils/rundownMetadata'; +import { useProjectRundowns } from './useProjectRundowns'; +import { flattenRundown, useRundownById } from './useRundownById'; + +/** + * Rundown data for surfaces which only ever work against the rundown being played: + * the viewers, the operator, app settings and the runtime overview. + * + * These take no part in a rundown scope, they resolve the loaded rundown directly. + * Anything which can be pointed at a background rundown reads from its scope instead. + */ +export function useLoadedRundown() { + const { + data: { loaded }, + } = useProjectRundowns(); + return useRundownById(loaded); +} + +export function useLoadedRundownWithMetadata() { + const { data, status } = useLoadedRundown(); + const selectedEventId = useSelectedEventId(); + const rundownMetadata = useMemo(() => getRundownMetadata(data, selectedEventId), [data, selectedEventId]); + return { data, status, rundownMetadata }; +} + +export function useLoadedFlatRundown() { + const { data, status } = useLoadedRundown(); + const flatRundown = useMemo(() => flattenRundown(data), [data]); + return { data: flatRundown, rundownId: data.id, status }; +} + +export function useLoadedFlatRundownWithMetadata() { + const { data, status } = useLoadedRundown(); + const selectedEventId = useSelectedEventId(); + const rundownWithMetadata = useMemo(() => getFlatRundownMetadata(data, selectedEventId), [data, selectedEventId]); + return { data: rundownWithMetadata, status }; +} + +/** + * Provides access to a partial rundown based on a filter callback + * + * Callers MUST memoize the callback with useCallback to prevent + * re-filtering on every render. + */ +export function useLoadedPartialRundown(cb: (event: ExtendedEntry) => boolean) { + const { data, status } = useLoadedFlatRundownWithMetadata(); + const filteredData = useMemo(() => data.filter(cb), [data, cb]); + return { data: filteredData, status }; +} + +/** + * Hook to get a specific entry by ID from the loaded rundown. + * Runtime ids (the playing event, its group, the next flag) only exist here. + */ +export function useLoadedEntry(entryId: EntryId | null): OntimeEntry | null { + const { data: rundown } = useLoadedRundown(); + + if (entryId === null) return null; + return rundown.entries[entryId] ?? null; +} + +export function useLoadedRundownAuxData() { + const { data, status } = useLoadedRundown(); + const filteredData = useMemo(() => { + const { title, id } = data; + return { title, id }; + }, [data]); + return { data: filteredData, status }; +} diff --git a/apps/client/src/common/hooks-query/useRundown.ts b/apps/client/src/common/hooks-query/useRundown.ts index c0d1f7551..51b84bcbe 100644 --- a/apps/client/src/common/hooks-query/useRundown.ts +++ b/apps/client/src/common/hooks-query/useRundown.ts @@ -1,60 +1,10 @@ -import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { EntryId, OntimeEntry, Rundown } from 'ontime-types'; -import { useEffect, useMemo, useRef } from 'react'; +import { EntryId, OntimeEntry } from 'ontime-types'; +import { useMemo } from 'react'; -import { queryRefetchIntervalSlow } from '../../ontimeConfig'; -import { CURRENT_RUNDOWN_QUERY_KEY, getRundownCacheKey, getRundownQueryKey } from '../api/constants'; -import { fetchCurrentRundown, fetchRundown } from '../api/rundown'; import { useRundownScope } from '../context/RundownScopeContext'; import { useSelectedEventId } from '../hooks/useSocket'; -import { ExtendedEntry, getFlatRundownMetadata, getRundownMetadata } from '../utils/rundownMetadata'; - -// revision is -1 so that the remote revision is higher -const cachedRundownPlaceholder: Rundown = { - id: 'default', - title: '', - order: [], - flatOrder: [], - entries: {}, - revision: -1, -}; - -/** - * Provides access to a specific rundown by ID. - * - * Without an ID we do not yet know which rundown is loaded, so we bootstrap via - * the `/current` alias to keep the first paint to a single round-trip, then seed - * the id-keyed cache that every other reader shares. - */ -export function useRundownById(rundownId: string | null | undefined) { - const queryClient = useQueryClient(); - const id = rundownId ?? ''; - const isBootstrap = id === ''; - - const { data, status, isError, refetch, isFetching } = useQuery({ - queryKey: getRundownCacheKey(id), - queryFn: ({ signal }) => (isBootstrap ? fetchCurrentRundown({ signal }) : fetchRundown(id, { signal })), - placeholderData: (previousData, _previousQuery) => previousData, - refetchInterval: queryRefetchIntervalSlow, - }); - - // Seed the id-keyed cache when fetching via the bootstrap alias - useEffect(() => { - if (!data || !isBootstrap) return; - queryClient.setQueryData(getRundownQueryKey(data.id), data); - }, [data, isBootstrap, queryClient]); - - // Once we have the ID, drop the temporary current cache. - // Only the reader which bootstrapped may do so, others are still relying on it. - const didBootstrap = useRef(isBootstrap); - useEffect(() => { - if (isBootstrap || !didBootstrap.current) return; - didBootstrap.current = false; - queryClient.removeQueries({ queryKey: CURRENT_RUNDOWN_QUERY_KEY, exact: true }); - }, [isBootstrap, queryClient]); - - return { data: data ?? cachedRundownPlaceholder, status, isError, refetch, isFetching }; -} +import { getFlatRundownMetadata, getRundownMetadata } from '../utils/rundownMetadata'; +import { flattenRundown, useRundownById } from './useRundownById'; /** * Normalised rundown data for the rundown of the enclosing scope @@ -87,13 +37,7 @@ export function useRundownWithMetadata() { */ export function useFlatRundown() { const { data, status } = useRundown(); - - const flatRundown = useMemo(() => { - if (data.revision === -1) { - return []; - } - return data.flatOrder.map((id) => data.entries[id]).filter((entry): entry is OntimeEntry => entry !== undefined); - }, [data]); + const flatRundown = useMemo(() => flattenRundown(data), [data]); return { data: flatRundown, rundownId: data.id, status }; } @@ -106,22 +50,6 @@ export function useFlatRundownWithMetadata() { return { data: rundownWithMetadata, status }; } -/** - * Provides access to a partial rundown based on a filter callback - * - * Callers MUST memoize the callback with useCallback to prevent - * re-filtering on every render. - * - */ -export function usePartialRundown(cb: (event: ExtendedEntry) => boolean) { - const { data, status } = useFlatRundownWithMetadata(); - const filteredData = useMemo(() => { - return data.filter(cb); - }, [data, cb]); - - return { data: filteredData, status }; -} - /** * Hook to get a specific entry by ID from the rundown */ @@ -131,12 +59,3 @@ export function useEntry(entryId: EntryId | null): OntimeEntry | null { if (entryId === null) return null; return rundown.entries[entryId] ?? null; } - -export function useRundownAuxData() { - const { data, status } = useRundown(); - const filteredData = useMemo(() => { - const { title, id } = data; - return { title, id }; - }, [data]); - return { data: filteredData, status }; -} diff --git a/apps/client/src/common/hooks-query/useRundownById.ts b/apps/client/src/common/hooks-query/useRundownById.ts new file mode 100644 index 000000000..f4631beb7 --- /dev/null +++ b/apps/client/src/common/hooks-query/useRundownById.ts @@ -0,0 +1,66 @@ +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { OntimeEntry, Rundown } from 'ontime-types'; +import { useEffect, useRef } from 'react'; + +import { queryRefetchIntervalSlow } from '../../ontimeConfig'; +import { CURRENT_RUNDOWN_QUERY_KEY, getRundownCacheKey, getRundownQueryKey } from '../api/constants'; +import { fetchCurrentRundown, fetchRundown } from '../api/rundown'; + +// revision is -1 so that the remote revision is higher +const cachedRundownPlaceholder: Rundown = { + id: 'default', + title: '', + order: [], + flatOrder: [], + entries: {}, + revision: -1, +}; + +/** + * Provides access to a specific rundown by ID. + * + * Without an ID we do not yet know which rundown is loaded, so we bootstrap via + * the `/current` alias to keep the first paint to a single round-trip, then seed + * the id-keyed cache that every other reader shares. + */ +export function useRundownById(rundownId: string | null | undefined) { + const queryClient = useQueryClient(); + const id = rundownId ?? ''; + const isBootstrap = id === ''; + + const { data, status, isError, refetch, isFetching } = useQuery({ + queryKey: getRundownCacheKey(id), + queryFn: ({ signal }) => (isBootstrap ? fetchCurrentRundown({ signal }) : fetchRundown(id, { signal })), + placeholderData: (previousData, _previousQuery) => previousData, + refetchInterval: queryRefetchIntervalSlow, + }); + + // Seed the id-keyed cache when fetching via the bootstrap alias + useEffect(() => { + if (!data || !isBootstrap) return; + queryClient.setQueryData(getRundownQueryKey(data.id), data); + }, [data, isBootstrap, queryClient]); + + // Once we have the ID, drop the temporary current cache. + // Only the reader which bootstrapped may do so, others are still relying on it. + const didBootstrap = useRef(isBootstrap); + useEffect(() => { + if (isBootstrap || !didBootstrap.current) return; + didBootstrap.current = false; + queryClient.removeQueries({ queryKey: CURRENT_RUNDOWN_QUERY_KEY, exact: true }); + }, [isBootstrap, queryClient]); + + return { data: data ?? cachedRundownPlaceholder, status, isError, refetch, isFetching }; +} + +/** + * Builds a flat rundown from the order and entries fields + */ +export function flattenRundown(rundown: Rundown): OntimeEntry[] { + if (rundown.revision === -1) { + return []; + } + return rundown.flatOrder + .map((id) => rundown.entries[id]) + .filter((entry): entry is OntimeEntry => entry !== undefined); +} diff --git a/apps/client/src/features/app-settings/panel/feature-panel/ReportSettings.tsx b/apps/client/src/features/app-settings/panel/feature-panel/ReportSettings.tsx index 924bda3d4..e0a4483c5 100644 --- a/apps/client/src/features/app-settings/panel/feature-panel/ReportSettings.tsx +++ b/apps/client/src/features/app-settings/panel/feature-panel/ReportSettings.tsx @@ -4,8 +4,8 @@ import { IoTrashBin } from 'react-icons/io5'; import { deleteAllReport } from '../../../../common/api/report'; import { createBlob, downloadBlob } from '../../../../common/api/utils'; import Button from '../../../../common/components/buttons/Button'; +import { useLoadedRundown } from '../../../../common/hooks-query/useLoadedRundown'; import useReport from '../../../../common/hooks-query/useReport'; -import useRundown from '../../../../common/hooks-query/useRundown'; import { cx } from '../../../../common/utils/styleUtils'; import { formatTime } from '../../../../common/utils/time'; import * as Panel from '../../panel-utils/PanelUtils'; @@ -15,7 +15,7 @@ import style from './ReportSettings.module.scss'; export default function ReportSettings() { const { data: reportData } = useReport(); - const { data } = useRundown(); + const { data } = useLoadedRundown(); const clearReport = async () => await deleteAllReport(); const downloadCSV = (combinedReport: CombinedReport[]) => { diff --git a/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/SourcesPanel.tsx b/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/SourcesPanel.tsx index 87180a840..7ef599955 100644 --- a/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/SourcesPanel.tsx +++ b/apps/client/src/features/app-settings/panel/manage-panel/sources-panel/SourcesPanel.tsx @@ -24,7 +24,7 @@ import Button from '../../../../../common/components/buttons/Button'; import Info from '../../../../../common/components/info/Info'; import ExternalLink from '../../../../../common/components/link/external-link/ExternalLink'; import Modal from '../../../../../common/components/modal/Modal'; -import useRundown from '../../../../../common/hooks-query/useRundown'; +import { useLoadedRundown } from '../../../../../common/hooks-query/useLoadedRundown'; import { removeFileExtension, validateExcelImport } from '../../../../../common/utils/uploadUtils'; import * as Panel from '../../../panel-utils/PanelUtils'; import GSheetSetup from './GSheetSetup'; @@ -59,7 +59,7 @@ export default function SourcesPanel() { const [activeSource, setActiveSource] = useState(null); const [completedRundownTitle, setCompletedRundownTitle] = useState(''); - const { data: currentRundown } = useRundown(); + const { data: currentRundown } = useLoadedRundown(); const { applyImport } = useSpreadsheetImport(); const navigate = useNavigate(); diff --git a/apps/client/src/features/operator/useOperatorData.ts b/apps/client/src/features/operator/useOperatorData.ts index 8eeeae6b2..12dbda6eb 100644 --- a/apps/client/src/features/operator/useOperatorData.ts +++ b/apps/client/src/features/operator/useOperatorData.ts @@ -1,7 +1,7 @@ import { CustomFields, Rundown, Settings } from 'ontime-types'; import useCustomFields from '../../common/hooks-query/useCustomFields'; -import { useRundownWithMetadata } from '../../common/hooks-query/useRundown'; +import { useLoadedRundownWithMetadata } from '../../common/hooks-query/useLoadedRundown'; import useSettings from '../../common/hooks-query/useSettings'; import { RundownMetadataObject } from '../../common/utils/rundownMetadata'; import { ViewData, aggregateQueryStatus } from '../../views/utils/viewLoader.utils'; @@ -14,7 +14,7 @@ export interface OperatorData { } export function useOperatorData(): ViewData { - const { data: rundown, rundownMetadata, status: rundownStatus } = useRundownWithMetadata(); + const { data: rundown, rundownMetadata, status: rundownStatus } = useLoadedRundownWithMetadata(); const { data: customFields, status: customFieldStatus } = useCustomFields(); const { data: settings, status: settingsStatus } = useSettings(); diff --git a/apps/client/src/features/overview/composite/TimeElements.tsx b/apps/client/src/features/overview/composite/TimeElements.tsx index 27e8c8f50..c844c2f9b 100644 --- a/apps/client/src/features/overview/composite/TimeElements.tsx +++ b/apps/client/src/features/overview/composite/TimeElements.tsx @@ -12,7 +12,7 @@ import { } from 'react-icons/tb'; import Tooltip from '../../../common/components/tooltip/Tooltip'; -import { useEntry } from '../../../common/hooks-query/useRundown'; +import { useLoadedEntry } from '../../../common/hooks-query/useLoadedRundown'; import { useAutoTickingClock } from '../../../common/hooks/useAutoTickingClock'; import { useCurrentGroupId, @@ -210,7 +210,7 @@ export function MetadataTimes() { function GroupTimes() { const { clock, mode, groupExpectedEnd, actualGroupStart, currentDay, playback, phase } = useGroupTimerOverView(); const currentGroupId = useCurrentGroupId(); - const group = useEntry(currentGroupId) as OntimeGroup | null; + const group = useLoadedEntry(currentGroupId) as OntimeGroup | null; const hasRunningTimer = phase !== TimerPhase.Pending && isPlaybackActive(playback); @@ -266,7 +266,7 @@ function GroupTimes() { function FlagTimes() { const { clock, mode, actualStart, plannedStart, playback, currentDay, phase } = useFlagTimerOverView(); const { id, expectedStart } = useNextFlag(); - const entry = useEntry(id) as OntimeEvent | null; + const entry = useLoadedEntry(id) as OntimeEvent | null; const hasRunningTimer = phase !== TimerPhase.Pending && isPlaybackActive(playback); diff --git a/apps/client/src/features/overview/composite/TitleOverview.tsx b/apps/client/src/features/overview/composite/TitleOverview.tsx index 5f29c0bf3..7d8f3f586 100644 --- a/apps/client/src/features/overview/composite/TitleOverview.tsx +++ b/apps/client/src/features/overview/composite/TitleOverview.tsx @@ -1,12 +1,12 @@ +import { useLoadedRundownAuxData } from '../../../common/hooks-query/useLoadedRundown'; import useProjectData from '../../../common/hooks-query/useProjectData'; -import { useRundownAuxData } from '../../../common/hooks-query/useRundown'; import style from './TitleOverview.module.scss'; export default function TitleOverview() { 'use memo'; const { data: projectData } = useProjectData(); - const { data: rundownData } = useRundownAuxData(); + const { data: rundownData } = useLoadedRundownAuxData(); const projectTitle = projectData.title.trim(); const rundownTitle = rundownData.title.trim(); diff --git a/apps/client/src/views/backstage/useBackstageData.ts b/apps/client/src/views/backstage/useBackstageData.ts index 1a804edac..ad5381240 100644 --- a/apps/client/src/views/backstage/useBackstageData.ts +++ b/apps/client/src/views/backstage/useBackstageData.ts @@ -1,8 +1,8 @@ import { CustomFields, OntimeEntry, ProjectData, Settings } from 'ontime-types'; import useCustomFields from '../../common/hooks-query/useCustomFields'; +import { useLoadedFlatRundown } from '../../common/hooks-query/useLoadedRundown'; import useProjectData from '../../common/hooks-query/useProjectData'; -import { useFlatRundown } from '../../common/hooks-query/useRundown'; import useSettings from '../../common/hooks-query/useSettings'; import { useViewOptionsStore } from '../../common/stores/viewOptions'; import { ViewData, aggregateQueryStatus } from '../utils/viewLoader.utils'; @@ -20,7 +20,7 @@ export function useBackstageData(): ViewData { const isMirrored = useViewOptionsStore((state) => state.mirror); // HTTP API data - const { data: rundownData, status: rundownStatus } = useFlatRundown(); + const { data: rundownData, status: rundownStatus } = useLoadedFlatRundown(); const { data: projectData, status: projectDataStatus } = useProjectData(); const { data: settings, status: settingsStatus } = useSettings(); const { data: customFields, status: customFieldsStatus } = useCustomFields(); diff --git a/apps/client/src/views/common/schedule/ScheduleContext.tsx b/apps/client/src/views/common/schedule/ScheduleContext.tsx index c260c1958..090011fe8 100644 --- a/apps/client/src/views/common/schedule/ScheduleContext.tsx +++ b/apps/client/src/views/common/schedule/ScheduleContext.tsx @@ -12,7 +12,7 @@ import { useState, } from 'react'; -import { usePartialRundown } from '../../../common/hooks-query/useRundown'; +import { useLoadedPartialRundown } from '../../../common/hooks-query/useLoadedRundown'; import { ExtendedEntry } from '../../../common/utils/rundownMetadata'; import { useScheduleOptions } from './schedule.options'; @@ -45,7 +45,7 @@ export const ScheduleProvider = ({ children, selectedEventId }: PropsWithChildre [filter], ); - const { data: events } = usePartialRundown(filterCallback); + const { data: events } = useLoadedPartialRundown(filterCallback); const [firstIndex, setFirstIndex] = useState(-1); const [numPages, setNumPages] = useState(0); diff --git a/apps/client/src/views/countdown/useCountdownData.ts b/apps/client/src/views/countdown/useCountdownData.ts index 9faaf6c82..0c45b24e1 100644 --- a/apps/client/src/views/countdown/useCountdownData.ts +++ b/apps/client/src/views/countdown/useCountdownData.ts @@ -1,8 +1,8 @@ import { CustomFields, OntimeEntry, ProjectData, Settings } from 'ontime-types'; import useCustomFields from '../../common/hooks-query/useCustomFields'; +import { useLoadedFlatRundownWithMetadata } from '../../common/hooks-query/useLoadedRundown'; import useProjectData from '../../common/hooks-query/useProjectData'; -import { useFlatRundownWithMetadata } from '../../common/hooks-query/useRundown'; import useSettings from '../../common/hooks-query/useSettings'; import { useViewOptionsStore } from '../../common/stores/viewOptions'; import { ExtendedEntry } from '../../common/utils/rundownMetadata'; @@ -21,7 +21,7 @@ export function useCountdownData(): ViewData { const isMirrored = useViewOptionsStore((state) => state.mirror); // HTTP API data - const { data: rundownData, status: rundownStatus } = useFlatRundownWithMetadata(); + const { data: rundownData, status: rundownStatus } = useLoadedFlatRundownWithMetadata(); const { data: projectData, status: projectDataStatus } = useProjectData(); const { data: settings, status: settingsStatus } = useSettings(); const { data: customFields, status: customFieldsStatus } = useCustomFields(); diff --git a/apps/client/src/views/timeline/useTimelineData.ts b/apps/client/src/views/timeline/useTimelineData.ts index bd2f996f6..9abc78d94 100644 --- a/apps/client/src/views/timeline/useTimelineData.ts +++ b/apps/client/src/views/timeline/useTimelineData.ts @@ -1,8 +1,8 @@ import { CustomFields, OntimeEntry, ProjectData, Settings } from 'ontime-types'; import useCustomFields from '../../common/hooks-query/useCustomFields'; +import { useLoadedFlatRundownWithMetadata } from '../../common/hooks-query/useLoadedRundown'; import useProjectData from '../../common/hooks-query/useProjectData'; -import { useFlatRundownWithMetadata } from '../../common/hooks-query/useRundown'; import useSettings from '../../common/hooks-query/useSettings'; import { ExtendedEntry } from '../../common/utils/rundownMetadata'; import { ViewData, aggregateQueryStatus } from '../utils/viewLoader.utils'; @@ -16,7 +16,7 @@ export interface TimelineData { export function useTimelineData(): ViewData { // HTTP API data - const { data: rundownData, status: rundownStatus } = useFlatRundownWithMetadata(); + const { data: rundownData, status: rundownStatus } = useLoadedFlatRundownWithMetadata(); const { data: projectData, status: projectDataStatus } = useProjectData(); const { data: settings, status: settingsStatus } = useSettings(); const { data: customFields, status: customFieldsStatus } = useCustomFields(); diff --git a/apps/client/src/views/timer/useTimerData.ts b/apps/client/src/views/timer/useTimerData.ts index 406912e0b..6212b4945 100644 --- a/apps/client/src/views/timer/useTimerData.ts +++ b/apps/client/src/views/timer/useTimerData.ts @@ -1,8 +1,8 @@ import { CustomFields, ProjectData, RundownEntries, Settings, ViewSettings } from 'ontime-types'; import useCustomFields from '../../common/hooks-query/useCustomFields'; +import { useLoadedRundown } from '../../common/hooks-query/useLoadedRundown'; 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'; @@ -26,7 +26,7 @@ export function useTimerData(): ViewData { 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 { data: rundown, status: rundownStatus } = useLoadedRundown(); const { entries } = rundown; return {