From 58dce0a18c846e53039b343337c25f1d2efd16c8 Mon Sep 17 00:00:00 2001 From: alex-arc Date: Tue, 16 Jun 2026 19:31:48 +0200 Subject: [PATCH] refactor: react state for cuesheet v editor layout --- .../src/common/hooks-query/useRundown.ts | 6 --- .../overview/composite/TimeElements.tsx | 4 +- .../overview/composite/TitleOverview.tsx | 2 +- .../src/views/backstage/useBackstageData.ts | 2 +- .../views/common/schedule/ScheduleContext.tsx | 2 +- .../src/views/countdown/useCountdownData.ts | 2 +- .../views/cuesheet/CuesheetTableWrapper.tsx | 1 - .../cuesheet/cuesheet-table/CuesheetTable.tsx | 27 +++-------- .../CuesheetTableHeaderToolbar.tsx | 47 +++++++++---------- .../cuesheet-table-settings/RundownSelect.tsx | 6 +-- .../src/views/timeline/useTimelineData.ts | 2 +- 11 files changed, 37 insertions(+), 64 deletions(-) diff --git a/apps/client/src/common/hooks-query/useRundown.ts b/apps/client/src/common/hooks-query/useRundown.ts index d1a6d7024..9f0eef415 100644 --- a/apps/client/src/common/hooks-query/useRundown.ts +++ b/apps/client/src/common/hooks-query/useRundown.ts @@ -59,7 +59,6 @@ export function useRundownWithMetadata(rundownId: Maybe) { /** * Provides access to a flat rundown * built from the order and rundown fields - * @deprecated */ export function useFlatRundown(rundownId: Maybe) { const { data, status } = useRundown(rundownId); @@ -90,7 +89,6 @@ export function useFlatRundownWithMetadata(rundownId: Maybe) { * Callers MUST memoize the callback with useCallback to prevent * re-filtering on every render. * - * @deprecated */ export function usePartialRundown(rundownId: Maybe, cb: (event: ExtendedEntry) => boolean) { const { data, status } = useFlatRundownWithMetadata(rundownId); @@ -112,10 +110,6 @@ export function useEntry(rundownId: Maybe, entryId: EntryId | null): Ont return rundown.entries[entryId] ?? null; } -/** - * - * @deprecated - */ export function useRundownAuxData(rundownId: Maybe) { const { data, status } = useRundown(rundownId); const filteredData = useMemo(() => { diff --git a/apps/client/src/features/overview/composite/TimeElements.tsx b/apps/client/src/features/overview/composite/TimeElements.tsx index 27e8c8f50..a39214145 100644 --- a/apps/client/src/features/overview/composite/TimeElements.tsx +++ b/apps/client/src/features/overview/composite/TimeElements.tsx @@ -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 = useEntry(null, 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 = useEntry(null, 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 147ca2e5d..b690f8e46 100644 --- a/apps/client/src/features/overview/composite/TitleOverview.tsx +++ b/apps/client/src/features/overview/composite/TitleOverview.tsx @@ -6,7 +6,7 @@ import style from './TitleOverview.module.scss'; export default function TitleOverview() { 'use memo'; const { data: projectData } = useProjectData(); - const { data: rundownData } = useRundownAuxData(); + const { data: rundownData } = useRundownAuxData(null); if (!projectData.title && !rundownData.title) { return null; diff --git a/apps/client/src/views/backstage/useBackstageData.ts b/apps/client/src/views/backstage/useBackstageData.ts index 1a804edac..fb248c591 100644 --- a/apps/client/src/views/backstage/useBackstageData.ts +++ b/apps/client/src/views/backstage/useBackstageData.ts @@ -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 } = useFlatRundown(null); 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..2fcb0d00a 100644 --- a/apps/client/src/views/common/schedule/ScheduleContext.tsx +++ b/apps/client/src/views/common/schedule/ScheduleContext.tsx @@ -45,7 +45,7 @@ export const ScheduleProvider = ({ children, selectedEventId }: PropsWithChildre [filter], ); - const { data: events } = usePartialRundown(filterCallback); + const { data: events } = usePartialRundown(null, 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..4feac424c 100644 --- a/apps/client/src/views/countdown/useCountdownData.ts +++ b/apps/client/src/views/countdown/useCountdownData.ts @@ -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 } = useFlatRundownWithMetadata(null); 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/cuesheet/CuesheetTableWrapper.tsx b/apps/client/src/views/cuesheet/CuesheetTableWrapper.tsx index 12a71ce34..62c05d5d0 100644 --- a/apps/client/src/views/cuesheet/CuesheetTableWrapper.tsx +++ b/apps/client/src/views/cuesheet/CuesheetTableWrapper.tsx @@ -34,7 +34,6 @@ function CuesheetTableWrapper() { cuesheetMode={cuesheetMode} tableRoot='cuesheet' setCuesheetMode={setCuesheetMode} - isCurrentRundown={isLoadedRundown} /> )} diff --git a/apps/client/src/views/cuesheet/cuesheet-table/CuesheetTable.tsx b/apps/client/src/views/cuesheet/cuesheet-table/CuesheetTable.tsx index 81d8bc557..441b1f562 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/CuesheetTable.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table/CuesheetTable.tsx @@ -1,7 +1,7 @@ import { useTableNav } from '@table-nav/react'; import { ColumnDef, Table, getCoreRowModel, useReactTable } from '@tanstack/react-table'; import { OntimeEntry, SupportedEntry, TimeField, isOntimeDelay, isOntimeGroup, isOntimeMilestone } from 'ontime-types'; -import { ComponentProps, ReactNode, memo, useCallback, useEffect, useMemo, useRef } from 'react'; +import { ComponentProps, memo, useCallback, useEffect, useMemo, useRef } from 'react'; import { ContextProp, ItemProps, @@ -40,25 +40,17 @@ type CuesheetTableBaseProps = { type EditorCuesheetTableProps = CuesheetTableBaseProps & { tableRoot: 'editor'; setCuesheetMode?: undefined; - isCurrentRundown?: undefined; }; type ViewCuesheetTableProps = CuesheetTableBaseProps & { tableRoot: 'cuesheet'; setCuesheetMode: (mode: AppMode) => void; - isCurrentRundown?: boolean; }; type CuesheetTableProps = EditorCuesheetTableProps | ViewCuesheetTableProps; -export default function CuesheetTable({ - columns, - cuesheetMode, - tableRoot, - setCuesheetMode, - isCurrentRundown, -}: CuesheetTableProps) { - const { flatRundown, status, selectedEventId } = source; +export default function CuesheetTable({ columns, cuesheetMode, tableRoot, setCuesheetMode }: CuesheetTableProps) { + const { flatRundown, status, loadedEventId } = useContextRundownTable(); const { updateEntry, updateTimer, addEntry } = useEntryActionsContext(); const canCreateEntries = useCuesheetPermissions((state) => state.canCreateEntries) && cuesheetMode === AppMode.Edit; @@ -238,16 +230,9 @@ export default function CuesheetTable({ handleResetResizing={resetColumnResizing} handleResetReordering={resetColumnOrder} handleClearToggles={setAllVisible} - modeControls={ - tableRoot === 'cuesheet' - ? { - cuesheetMode, - setCuesheetMode, - isCurrentRundown, - } - : undefined - } - showShare={tableRoot === 'cuesheet'} + appMode={cuesheetMode} + tableRoot={tableRoot} + setCuesheetMode={setCuesheetMode} /> ; -type TableModeControls = { - cuesheetMode: AppMode; - setCuesheetMode: (mode: AppMode) => void; - isCurrentRundown?: boolean; -}; - interface CuesheetTableHeaderToolbarProps { columns: Column[]; optionsStore: TableHeaderOptionsStore; handleResetResizing: () => void; handleResetReordering: () => void; handleClearToggles: () => void; - modeControls?: TableModeControls; - showShare?: boolean; + setCuesheetMode?: (mode: AppMode) => void; + appMode: AppMode; + tableRoot: 'editor' | 'cuesheet'; } export default function CuesheetTableHeaderToolbar({ @@ -53,22 +49,22 @@ export default function CuesheetTableHeaderToolbar({ handleResetResizing, handleResetReordering, handleClearToggles, - modeControls, - showShare = false, + setCuesheetMode, + tableRoot, + appMode, }: CuesheetTableHeaderToolbarProps) { - const canChangeMode = useCuesheetPermissions((state) => state.canChangeMode); - const canShare = useCuesheetPermissions((state) => state.canShare); + const canChangeMode = useCuesheetPermissions((state) => state.canChangeMode) && tableRoot === 'cuesheet'; + const canShare = useCuesheetPermissions((state) => state.canShare) && tableRoot === 'cuesheet'; + const { isLoadedRundown } = useRundownSelectionContext(); const toggleCuesheetMode = (mode: AppMode[]) => { const newValue = mode.at(0); - if (!newValue || !modeControls) return; - modeControls.setCuesheetMode(newValue); + if (!newValue || !setCuesheetMode) return; + setCuesheetMode(newValue); }; - const isBackground = !(modeControls?.isCurrentRundown ?? true); - return ( - + - {modeControls && canChangeMode && ( -
- {/* {insertElement} */} - +
+ + {canChangeMode && ( } value={AppMode.Run} className={style.radioButton}> Run @@ -93,10 +88,10 @@ export default function CuesheetTableHeaderToolbar({ Edit -
- )} + )} +
- {showShare && canShare && ( + {canShare && ( <> diff --git a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-settings/RundownSelect.tsx b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-settings/RundownSelect.tsx index acf542e37..21d13d3c9 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-settings/RundownSelect.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-settings/RundownSelect.tsx @@ -7,10 +7,10 @@ import styles from './RundownSelect.module.scss'; const FOLLOW = '___null___'; interface RundownSelectProps { - cuesheetMode: AppMode; + appMode: AppMode; } -export function RundownSelect({ cuesheetMode }: RundownSelectProps) { +export function RundownSelect({ appMode }: RundownSelectProps) { 'use memo'; const { selectRundownId, rundowns, loadedRundownId, selectedRundownId } = useRundownSelectionContext(); @@ -34,7 +34,7 @@ export function RundownSelect({ cuesheetMode }: RundownSelectProps) { if (value === FOLLOW) selectRundownId(null); else selectRundownId(value); }} - disabled={cuesheetMode === AppMode.Run} + disabled={appMode === AppMode.Run} fluid /> diff --git a/apps/client/src/views/timeline/useTimelineData.ts b/apps/client/src/views/timeline/useTimelineData.ts index bd2f996f6..368ba00d7 100644 --- a/apps/client/src/views/timeline/useTimelineData.ts +++ b/apps/client/src/views/timeline/useTimelineData.ts @@ -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 } = useFlatRundownWithMetadata(null); const { data: projectData, status: projectDataStatus } = useProjectData(); const { data: settings, status: settingsStatus } = useSettings(); const { data: customFields, status: customFieldsStatus } = useCustomFields();