refactor: react state for cuesheet v editor layout

This commit is contained in:
alex-arc
2026-06-16 19:31:48 +02:00
parent b2f9b812bd
commit 58dce0a18c
11 changed files with 37 additions and 64 deletions
@@ -59,7 +59,6 @@ export function useRundownWithMetadata(rundownId: Maybe<string>) {
/**
* Provides access to a flat rundown
* built from the order and rundown fields
* @deprecated
*/
export function useFlatRundown(rundownId: Maybe<string>) {
const { data, status } = useRundown(rundownId);
@@ -90,7 +89,6 @@ export function useFlatRundownWithMetadata(rundownId: Maybe<string>) {
* Callers MUST memoize the callback with useCallback to prevent
* re-filtering on every render.
*
* @deprecated
*/
export function usePartialRundown(rundownId: Maybe<string>, cb: (event: ExtendedEntry<OntimeEntry>) => boolean) {
const { data, status } = useFlatRundownWithMetadata(rundownId);
@@ -112,10 +110,6 @@ export function useEntry(rundownId: Maybe<string>, entryId: EntryId | null): Ont
return rundown.entries[entryId] ?? null;
}
/**
*
* @deprecated
*/
export function useRundownAuxData(rundownId: Maybe<string>) {
const { data, status } = useRundown(rundownId);
const filteredData = useMemo(() => {
@@ -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);
@@ -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;
@@ -20,7 +20,7 @@ export function useBackstageData(): ViewData<BackstageData> {
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();
@@ -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);
@@ -21,7 +21,7 @@ export function useCountdownData(): ViewData<CountdownData> {
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();
@@ -34,7 +34,6 @@ function CuesheetTableWrapper() {
cuesheetMode={cuesheetMode}
tableRoot='cuesheet'
setCuesheetMode={setCuesheetMode}
isCurrentRundown={isLoadedRundown}
/>
)}
</CuesheetDnd>
@@ -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}
/>
<TableVirtuoso
ref={virtuosoRef}
@@ -10,6 +10,7 @@ import Button from '../../../../common/components/buttons/Button';
import Checkbox from '../../../../common/components/checkbox/Checkbox';
import * as Editor from '../../../../common/components/editor-utils/EditorUtils';
import PopoverContents from '../../../../common/components/popover/Popover';
import { useRundownSelectionContext } from '../../../../common/context/RundownSelectionContext';
import type { ExtendedEntry } from '../../../../common/utils/rundownMetadata';
import { AppMode } from '../../../../ontimeConfig';
import { useCuesheetPermissions } from '../../useTablePermissions';
@@ -31,20 +32,15 @@ type TableHeaderOptionValues = Pick<
'hideTableSeconds' | 'hideIndexColumn' | 'showDelayedTimes' | 'hideDelays'
>;
type TableModeControls = {
cuesheetMode: AppMode;
setCuesheetMode: (mode: AppMode) => void;
isCurrentRundown?: boolean;
};
interface CuesheetTableHeaderToolbarProps {
columns: Column<ExtendedEntry, unknown>[];
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 (
<Toolbar.Root className={style.tableSettings} data-background-rundown={isBackground}>
<Toolbar.Root className={style.tableSettings} data-background-rundown={!isLoadedRundown}>
<ViewSettings optionsStore={optionsStore} />
<ColumnSettings
columns={columns}
@@ -76,15 +72,14 @@ export default function CuesheetTableHeaderToolbar({
handleResetReordering={handleResetReordering}
handleClearToggles={handleClearToggles}
/>
{modeControls && canChangeMode && (
<div className={style.apart}>
{/* {insertElement} */}
<RundownSelect cuesheetMode={modeControls.cuesheetMode} />
<div className={style.apart}>
<RundownSelect appMode={appMode} />
{canChangeMode && (
<ToggleGroup
value={[modeControls.cuesheetMode]}
value={[appMode]}
onValueChange={toggleCuesheetMode}
className={style.group}
disabled={!modeControls.isCurrentRundown}
disabled={!isLoadedRundown}
>
<Toolbar.Button render={<Toggle />} value={AppMode.Run} className={style.radioButton}>
Run
@@ -93,10 +88,10 @@ export default function CuesheetTableHeaderToolbar({
Edit
</Toolbar.Button>
</ToggleGroup>
</div>
)}
)}
</div>
{showShare && canShare && (
{canShare && (
<>
<Editor.Separator orientation='vertical' />
<CuesheetShareModal />
@@ -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
/>
</div>
@@ -16,7 +16,7 @@ export interface TimelineData {
export function useTimelineData(): ViewData<TimelineData> {
// 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();