mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-26 17:39:58 +00:00
refactor: recompose and memoise (#522)
This commit is contained in:
@@ -1,34 +1,20 @@
|
|||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { Tooltip } from '@chakra-ui/react';
|
|
||||||
import {
|
|
||||||
closestCenter,
|
|
||||||
DndContext,
|
|
||||||
DragEndEvent,
|
|
||||||
KeyboardSensor,
|
|
||||||
PointerSensor,
|
|
||||||
TouchSensor,
|
|
||||||
useSensor,
|
|
||||||
useSensors,
|
|
||||||
} from '@dnd-kit/core';
|
|
||||||
import { horizontalListSortingStrategy, SortableContext, sortableKeyboardCoordinates } from '@dnd-kit/sortable';
|
|
||||||
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
||||||
import { isOntimeBlock, isOntimeDelay, isOntimeEvent, OntimeRundown, OntimeRundownEntry } from 'ontime-types';
|
import { isOntimeBlock, isOntimeDelay, isOntimeEvent, OntimeRundown, OntimeRundownEntry } from 'ontime-types';
|
||||||
|
|
||||||
import useFollowComponent from '../../common/hooks/useFollowComponent';
|
import useFollowComponent from '../../common/hooks/useFollowComponent';
|
||||||
import { useLocalStorage } from '../../common/hooks/useLocalStorage';
|
import { useLocalStorage } from '../../common/hooks/useLocalStorage';
|
||||||
import { millisToDelayString } from '../../common/utils/dateConfig';
|
|
||||||
import { getAccessibleColour } from '../../common/utils/styleUtils';
|
|
||||||
import { tooltipDelayFast } from '../../ontimeConfig';
|
|
||||||
|
|
||||||
|
import BlockRow from './cuesheet-table-elements/BlockRow';
|
||||||
|
import CuesheetHeader from './cuesheet-table-elements/CuesheetHeader';
|
||||||
|
import DelayRow from './cuesheet-table-elements/DelayRow';
|
||||||
|
import EventRow from './cuesheet-table-elements/EventRow';
|
||||||
import CuesheetTableSettings from './cuesheet-table-settings/CuesheetTableSettings';
|
import CuesheetTableSettings from './cuesheet-table-settings/CuesheetTableSettings';
|
||||||
import { useCuesheetSettings } from './store/CuesheetSettings';
|
import { useCuesheetSettings } from './store/CuesheetSettings';
|
||||||
import { SortableCell } from './tableElements/SortableCell';
|
|
||||||
import { initialColumnOrder } from './cuesheetCols';
|
import { initialColumnOrder } from './cuesheetCols';
|
||||||
|
|
||||||
import style from './Cuesheet.module.scss';
|
import style from './Cuesheet.module.scss';
|
||||||
|
|
||||||
const pastOpacity = '0.2';
|
|
||||||
|
|
||||||
interface CuesheetProps {
|
interface CuesheetProps {
|
||||||
data: OntimeRundown;
|
data: OntimeRundown;
|
||||||
columns: ColumnDef<OntimeRundownEntry>[];
|
columns: ColumnDef<OntimeRundownEntry>[];
|
||||||
@@ -67,49 +53,6 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
|||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const sensors = useSensors(
|
|
||||||
useSensor(PointerSensor, {
|
|
||||||
activationConstraint: {
|
|
||||||
delay: 100,
|
|
||||||
tolerance: 50,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
useSensor(TouchSensor, {
|
|
||||||
activationConstraint: {
|
|
||||||
delay: 100,
|
|
||||||
tolerance: 50,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
useSensor(KeyboardSensor, {
|
|
||||||
coordinateGetter: sortableKeyboardCoordinates,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleOnDragEnd = (event: DragEndEvent) => {
|
|
||||||
const { delta, active, over } = event;
|
|
||||||
|
|
||||||
// cancel if delta y is greater than 200
|
|
||||||
if (delta.y > 200) return;
|
|
||||||
// cancel if we do not have an over id
|
|
||||||
if (over?.id == null) return;
|
|
||||||
|
|
||||||
// get index of from
|
|
||||||
const fromIndex = columnOrder.indexOf(active.id as string);
|
|
||||||
|
|
||||||
// get index of to
|
|
||||||
const toIndex = columnOrder.indexOf(over.id as string);
|
|
||||||
|
|
||||||
if (toIndex === -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const reorderedCols = [...columnOrder];
|
|
||||||
const reorderedItem = reorderedCols.splice(fromIndex, 1);
|
|
||||||
reorderedCols.splice(toIndex, 0, reorderedItem[0]);
|
|
||||||
|
|
||||||
saveColumnOrder(reorderedCols);
|
|
||||||
};
|
|
||||||
|
|
||||||
const resetColumnOrder = () => {
|
const resetColumnOrder = () => {
|
||||||
saveColumnOrder(initialColumnOrder);
|
saveColumnOrder(initialColumnOrder);
|
||||||
};
|
};
|
||||||
@@ -122,6 +65,8 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
|||||||
setColumnSizing({});
|
setColumnSizing({});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const headerGroups = table.getHeaderGroups;
|
||||||
|
|
||||||
let eventIndex = 0;
|
let eventIndex = 0;
|
||||||
let isPast = Boolean(selectedId);
|
let isPast = Boolean(selectedId);
|
||||||
|
|
||||||
@@ -137,37 +82,7 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
|||||||
)}
|
)}
|
||||||
<div ref={tableContainerRef} className={style.cuesheetContainer}>
|
<div ref={tableContainerRef} className={style.cuesheetContainer}>
|
||||||
<table className={style.cuesheet}>
|
<table className={style.cuesheet}>
|
||||||
<thead className={style.tableHeader}>
|
<CuesheetHeader headerGroups={headerGroups} />
|
||||||
{table.getHeaderGroups().map((headerGroup) => {
|
|
||||||
const key = headerGroup.id;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DndContext key={key} sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleOnDragEnd}>
|
|
||||||
<tr key={headerGroup.id}>
|
|
||||||
<th className={style.indexColumn}>
|
|
||||||
<Tooltip label='Event Order' openDelay={tooltipDelayFast}>
|
|
||||||
#
|
|
||||||
</Tooltip>
|
|
||||||
</th>
|
|
||||||
<SortableContext key={key} items={headerGroup.headers} strategy={horizontalListSortingStrategy}>
|
|
||||||
{headerGroup.headers.map((header) => {
|
|
||||||
const width = header.getSize();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SortableCell key={header.column.columnDef.id} header={header} style={{ width }}>
|
|
||||||
{header.isPlaceholder
|
|
||||||
? null
|
|
||||||
: flexRender(header.column.columnDef.header, header.getContext())}
|
|
||||||
</SortableCell>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</SortableContext>
|
|
||||||
</tr>
|
|
||||||
</DndContext>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{table.getRowModel().rows.map((row) => {
|
{table.getRowModel().rows.map((row) => {
|
||||||
const key = row.original.id;
|
const key = row.original.id;
|
||||||
@@ -177,13 +92,7 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isOntimeBlock(row.original)) {
|
if (isOntimeBlock(row.original)) {
|
||||||
const title = row.original.title;
|
return <BlockRow key={key} title={row.original.title} />;
|
||||||
|
|
||||||
return (
|
|
||||||
<tr key={key} className={style.blockRow}>
|
|
||||||
<td>{title}</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (isOntimeDelay(row.original)) {
|
if (isOntimeDelay(row.original)) {
|
||||||
const delayVal = row.original.duration;
|
const delayVal = row.original.duration;
|
||||||
@@ -192,12 +101,7 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const delayTime = millisToDelayString(delayVal);
|
return <DelayRow key={key} duration={delayVal} />;
|
||||||
return (
|
|
||||||
<tr key={key} className={style.delayRow}>
|
|
||||||
<td>{delayTime}</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (isOntimeEvent(row.original)) {
|
if (isOntimeEvent(row.original)) {
|
||||||
eventIndex++;
|
eventIndex++;
|
||||||
@@ -210,25 +114,20 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bgFallback = 'transparent';
|
|
||||||
const bgColour = row.original.colour || bgFallback;
|
|
||||||
const textColour = bgColour === bgFallback ? undefined : getAccessibleColour(bgColour);
|
|
||||||
const isSkipped = row.original.skip;
|
|
||||||
|
|
||||||
let rowBgColour: string | undefined;
|
let rowBgColour: string | undefined;
|
||||||
if (row.original.id === selectedId) {
|
if (isSelected) {
|
||||||
rowBgColour = 'var(--cuesheet-running-bg-override, #D20300)'; // $red-700
|
rowBgColour = 'var(--cuesheet-running-bg-override, #D20300)'; // $red-700
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr
|
<EventRow
|
||||||
key={key}
|
key={key}
|
||||||
className={`${style.eventRow} ${isSkipped ? style.skip : ''}`}
|
eventIndex={eventIndex}
|
||||||
style={{ opacity: `${isPast ? pastOpacity : '1'}` }}
|
isPast={isPast}
|
||||||
ref={isSelected ? selectedRef : undefined}
|
selectedRef={isSelected ? selectedRef : undefined}
|
||||||
|
skip={row.original.skip}
|
||||||
|
colour={row.original.colour}
|
||||||
>
|
>
|
||||||
<td className={style.indexColumn} style={{ backgroundColor: bgColour, color: textColour?.color }}>
|
|
||||||
{eventIndex}
|
|
||||||
</td>
|
|
||||||
{row.getVisibleCells().map((cell) => {
|
{row.getVisibleCells().map((cell) => {
|
||||||
return (
|
return (
|
||||||
<td key={cell.id} style={{ width: cell.column.getSize(), backgroundColor: rowBgColour }}>
|
<td key={cell.id} style={{ width: cell.column.getSize(), backgroundColor: rowBgColour }}>
|
||||||
@@ -236,7 +135,7 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
|||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</tr>
|
</EventRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
|
|
||||||
|
import style from '../Cuesheet.module.scss';
|
||||||
|
|
||||||
|
interface BlockRowProps {
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function BlockRow(props: BlockRowProps) {
|
||||||
|
const { title } = props;
|
||||||
|
return (
|
||||||
|
<tr className={style.blockRow}>
|
||||||
|
<td>{title}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(BlockRow);
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
|
import { Tooltip } from '@chakra-ui/react';
|
||||||
|
import {
|
||||||
|
closestCenter,
|
||||||
|
DndContext,
|
||||||
|
DragEndEvent,
|
||||||
|
KeyboardSensor,
|
||||||
|
PointerSensor,
|
||||||
|
TouchSensor,
|
||||||
|
useSensor,
|
||||||
|
useSensors,
|
||||||
|
} from '@dnd-kit/core';
|
||||||
|
import { horizontalListSortingStrategy, SortableContext, sortableKeyboardCoordinates } from '@dnd-kit/sortable';
|
||||||
|
import { flexRender, HeaderGroup } from '@tanstack/react-table';
|
||||||
|
import { OntimeRundownEntry } from 'ontime-types';
|
||||||
|
|
||||||
|
import { useLocalStorage } from '../../../common/hooks/useLocalStorage';
|
||||||
|
import { tooltipDelayFast } from '../../../ontimeConfig';
|
||||||
|
import { initialColumnOrder } from '../cuesheetCols';
|
||||||
|
|
||||||
|
import { SortableCell } from './SortableCell';
|
||||||
|
|
||||||
|
import style from '../Cuesheet.module.scss';
|
||||||
|
|
||||||
|
interface CuesheetHeaderProps {
|
||||||
|
headerGroups: () => HeaderGroup<OntimeRundownEntry>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function CuesheetHeader(props: CuesheetHeaderProps) {
|
||||||
|
const { headerGroups } = props;
|
||||||
|
const [columnOrder, saveColumnOrder] = useLocalStorage<string[]>('table-order', initialColumnOrder);
|
||||||
|
|
||||||
|
const handleOnDragEnd = (event: DragEndEvent) => {
|
||||||
|
const { delta, active, over } = event;
|
||||||
|
|
||||||
|
// cancel if delta y is greater than 200
|
||||||
|
if (delta.y > 200) return;
|
||||||
|
// cancel if we do not have an over id
|
||||||
|
if (over?.id == null) return;
|
||||||
|
|
||||||
|
// get index of from
|
||||||
|
const fromIndex = columnOrder.indexOf(active.id as string);
|
||||||
|
|
||||||
|
// get index of to
|
||||||
|
const toIndex = columnOrder.indexOf(over.id as string);
|
||||||
|
|
||||||
|
if (toIndex === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reorderedCols = [...columnOrder];
|
||||||
|
const reorderedItem = reorderedCols.splice(fromIndex, 1);
|
||||||
|
reorderedCols.splice(toIndex, 0, reorderedItem[0]);
|
||||||
|
|
||||||
|
saveColumnOrder(reorderedCols);
|
||||||
|
};
|
||||||
|
|
||||||
|
const sensors = useSensors(
|
||||||
|
useSensor(PointerSensor, {
|
||||||
|
activationConstraint: {
|
||||||
|
delay: 100,
|
||||||
|
tolerance: 50,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
useSensor(TouchSensor, {
|
||||||
|
activationConstraint: {
|
||||||
|
delay: 100,
|
||||||
|
tolerance: 50,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
useSensor(KeyboardSensor, {
|
||||||
|
coordinateGetter: sortableKeyboardCoordinates,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<thead className={style.tableHeader}>
|
||||||
|
{headerGroups().map((headerGroup) => {
|
||||||
|
const key = headerGroup.id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DndContext key={key} sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleOnDragEnd}>
|
||||||
|
<tr key={headerGroup.id}>
|
||||||
|
<th className={style.indexColumn}>
|
||||||
|
<Tooltip label='Event Order' openDelay={tooltipDelayFast}>
|
||||||
|
#
|
||||||
|
</Tooltip>
|
||||||
|
</th>
|
||||||
|
<SortableContext key={key} items={headerGroup.headers} strategy={horizontalListSortingStrategy}>
|
||||||
|
{headerGroup.headers.map((header) => {
|
||||||
|
const width = header.getSize();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SortableCell key={header.column.columnDef.id} header={header} style={{ width }}>
|
||||||
|
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
|
</SortableCell>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</SortableContext>
|
||||||
|
</tr>
|
||||||
|
</DndContext>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</thead>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(CuesheetHeader);
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
interface CuesheetRowProps {
|
||||||
|
row: OntimeRundownEntry;
|
||||||
|
isSelected: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CuesheetRow() {}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
|
|
||||||
|
import { millisToDelayString } from '../../../common/utils/dateConfig';
|
||||||
|
|
||||||
|
import style from '../Cuesheet.module.scss';
|
||||||
|
|
||||||
|
interface DelayRowProps {
|
||||||
|
duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function DelayRow(props: DelayRowProps) {
|
||||||
|
const { duration } = props;
|
||||||
|
const delayTime = millisToDelayString(duration);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr className={style.delayRow}>
|
||||||
|
<td>{delayTime}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(DelayRow);
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { memo, MutableRefObject, PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
import { getAccessibleColour } from '../../../common/utils/styleUtils';
|
||||||
|
|
||||||
|
import style from '../Cuesheet.module.scss';
|
||||||
|
|
||||||
|
const pastOpacity = '0.2';
|
||||||
|
|
||||||
|
interface EventRowProps {
|
||||||
|
eventIndex: number;
|
||||||
|
isPast?: boolean;
|
||||||
|
selectedRef?: MutableRefObject<HTMLTableRowElement | null>;
|
||||||
|
skip?: boolean;
|
||||||
|
colour?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function EventRow(props: PropsWithChildren<EventRowProps>) {
|
||||||
|
const { children, eventIndex, isPast, selectedRef, skip, colour } = props;
|
||||||
|
|
||||||
|
const bgFallback = 'transparent';
|
||||||
|
const bgColour = colour || bgFallback;
|
||||||
|
const textColour = bgColour === bgFallback ? undefined : getAccessibleColour(bgColour);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr
|
||||||
|
className={`${style.eventRow} ${skip ? style.skip : ''}`}
|
||||||
|
style={{ opacity: `${isPast ? pastOpacity : '1'}` }}
|
||||||
|
ref={selectedRef}
|
||||||
|
>
|
||||||
|
<td className={style.indexColumn} style={{ backgroundColor: bgColour, color: textColour?.color }}>
|
||||||
|
{eventIndex}
|
||||||
|
</td>
|
||||||
|
{children}
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(EventRow);
|
||||||
@@ -4,16 +4,14 @@ import { IoExpand } from '@react-icons/all-files/io5/IoExpand';
|
|||||||
import { IoLocate } from '@react-icons/all-files/io5/IoLocate';
|
import { IoLocate } from '@react-icons/all-files/io5/IoLocate';
|
||||||
import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline';
|
import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline';
|
||||||
import { EventData, Playback } from 'ontime-types';
|
import { EventData, Playback } from 'ontime-types';
|
||||||
import { formatDisplay } from 'ontime-utils';
|
|
||||||
|
|
||||||
import PlaybackIcon from '../../../common/components/playback-icon/PlaybackIcon';
|
import PlaybackIcon from '../../../common/components/playback-icon/PlaybackIcon';
|
||||||
import useFullscreen from '../../../common/hooks/useFullscreen';
|
|
||||||
import { useTimer } from '../../../common/hooks/useSocket';
|
|
||||||
import useEventData from '../../../common/hooks-query/useEventData';
|
import useEventData from '../../../common/hooks-query/useEventData';
|
||||||
import { formatTime } from '../../../common/utils/time';
|
|
||||||
import { tooltipDelayFast } from '../../../ontimeConfig';
|
import { tooltipDelayFast } from '../../../ontimeConfig';
|
||||||
import { useCuesheetSettings } from '../store/CuesheetSettings';
|
import { useCuesheetSettings } from '../store/CuesheetSettings';
|
||||||
|
|
||||||
|
import CuesheetTableHeaderTimers from './CuesheetTableHeaderTimers';
|
||||||
|
|
||||||
import style from './CuesheetTableHeader.module.scss';
|
import style from './CuesheetTableHeader.module.scss';
|
||||||
|
|
||||||
interface CuesheetTableHeaderProps {
|
interface CuesheetTableHeaderProps {
|
||||||
@@ -31,8 +29,9 @@ export default function CuesheetTableHeader({ handleCSVExport, featureData }: Cu
|
|||||||
const showSettings = useCuesheetSettings((state) => state.showSettings);
|
const showSettings = useCuesheetSettings((state) => state.showSettings);
|
||||||
const toggleSettings = useCuesheetSettings((state) => state.toggleSettings);
|
const toggleSettings = useCuesheetSettings((state) => state.toggleSettings);
|
||||||
const toggleFollow = useCuesheetSettings((state) => state.toggleFollow);
|
const toggleFollow = useCuesheetSettings((state) => state.toggleFollow);
|
||||||
const timer = useTimer();
|
// const { isFullScreen, toggleFullScreen } = useFullscreen();
|
||||||
const { isFullScreen, toggleFullScreen } = useFullscreen();
|
const isFullScreen = false;
|
||||||
|
const toggleFullScreen = () => undefined;
|
||||||
const { data: event } = useEventData();
|
const { data: event } = useEventData();
|
||||||
|
|
||||||
const exportCsv = () => {
|
const exportCsv = () => {
|
||||||
@@ -47,14 +46,6 @@ export default function CuesheetTableHeader({ handleCSVExport, featureData }: Cu
|
|||||||
featureData.numEvents ? featureData.numEvents : '-'
|
featureData.numEvents ? featureData.numEvents : '-'
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
// prepare presentation variables
|
|
||||||
const isOvertime = (timer.current ?? 0) < 0;
|
|
||||||
const timerNow = timer.current == null ? '-' : `${isOvertime ? '-' : ''}${formatDisplay(timer.current)}`;
|
|
||||||
const timeNow = formatTime(timer.clock, {
|
|
||||||
showSeconds: true,
|
|
||||||
format: 'hh:mm:ss a',
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.header}>
|
<div className={style.header}>
|
||||||
<div className={style.event}>
|
<div className={style.event}>
|
||||||
@@ -65,14 +56,7 @@ export default function CuesheetTableHeader({ handleCSVExport, featureData }: Cu
|
|||||||
<div className={style.playbackLabel}>{selected}</div>
|
<div className={style.playbackLabel}>{selected}</div>
|
||||||
<PlaybackIcon state={featureData.playback} />
|
<PlaybackIcon state={featureData.playback} />
|
||||||
</div>
|
</div>
|
||||||
<div className={style.timer}>
|
<CuesheetTableHeaderTimers />
|
||||||
<div className={style.timerLabel}>Running Timer</div>
|
|
||||||
<div className={style.value}>{timerNow}</div>
|
|
||||||
</div>
|
|
||||||
<div className={style.clock}>
|
|
||||||
<div className={style.clockLabel}>Time Now</div>
|
|
||||||
<div className={style.value}>{timeNow}</div>
|
|
||||||
</div>
|
|
||||||
<div className={style.headerActions}>
|
<div className={style.headerActions}>
|
||||||
<Tooltip openDelay={tooltipDelayFast} label='Toggle follow'>
|
<Tooltip openDelay={tooltipDelayFast} label='Toggle follow'>
|
||||||
<span onClick={() => toggleFollow()} className={`${style.actionIcon} ${followSelected ? style.enabled : ''}`}>
|
<span onClick={() => toggleFollow()} className={`${style.actionIcon} ${followSelected ? style.enabled : ''}`}>
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { formatDisplay } from 'ontime-utils';
|
||||||
|
|
||||||
|
import { useTimer } from '../../../common/hooks/useSocket';
|
||||||
|
import { formatTime } from '../../../common/utils/time';
|
||||||
|
|
||||||
|
import style from './CuesheetTableHeader.module.scss';
|
||||||
|
|
||||||
|
export default function CuesheetTableHeaderTimers() {
|
||||||
|
const timer = useTimer();
|
||||||
|
|
||||||
|
// prepare presentation variables
|
||||||
|
const isOvertime = (timer.current ?? 0) < 0;
|
||||||
|
const timerNow = timer.current == null ? '-' : `${isOvertime ? '-' : ''}${formatDisplay(timer.current)}`;
|
||||||
|
const timeNow = formatTime(timer.clock, {
|
||||||
|
showSeconds: true,
|
||||||
|
format: 'hh:mm:ss a',
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={style.timer}>
|
||||||
|
<div className={style.timerLabel}>Running Timer</div>
|
||||||
|
<div className={style.value}>{timerNow}</div>
|
||||||
|
</div>
|
||||||
|
<div className={style.clock}>
|
||||||
|
<div className={style.clockLabel}>Time Now</div>
|
||||||
|
<div className={style.value}>{timeNow}</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
import { Button, Checkbox, Switch } from '@chakra-ui/react';
|
import { Button, Checkbox, Switch } from '@chakra-ui/react';
|
||||||
import { Column } from '@tanstack/react-table';
|
import { Column } from '@tanstack/react-table';
|
||||||
import { OntimeRundownEntry } from 'ontime-types';
|
import { OntimeRundownEntry } from 'ontime-types';
|
||||||
@@ -19,7 +20,7 @@ interface CuesheetTableSettingsProps {
|
|||||||
handleClearToggles: () => void;
|
handleClearToggles: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CuesheetTableSettings(props: CuesheetTableSettingsProps) {
|
function CuesheetTableSettings(props: CuesheetTableSettingsProps) {
|
||||||
const { columns, handleResetResizing, handleResetReordering, handleClearToggles } = props;
|
const { columns, handleResetResizing, handleResetReordering, handleClearToggles } = props;
|
||||||
const showPrevious = useCuesheetSettings((state) => state.showPrevious);
|
const showPrevious = useCuesheetSettings((state) => state.showPrevious);
|
||||||
const togglePreviousVisibility = useCuesheetSettings((state) => state.togglePreviousVisibility);
|
const togglePreviousVisibility = useCuesheetSettings((state) => state.togglePreviousVisibility);
|
||||||
@@ -81,3 +82,5 @@ export default function CuesheetTableSettings(props: CuesheetTableSettingsProps)
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default memo(CuesheetTableSettings);
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { millisToString } from 'ontime-utils';
|
|||||||
|
|
||||||
import DelayIndicator from '../../common/components/delay-indicator/DelayIndicator';
|
import DelayIndicator from '../../common/components/delay-indicator/DelayIndicator';
|
||||||
|
|
||||||
|
import EditableCell from './cuesheet-table-elements/EditableCell';
|
||||||
import { useCuesheetSettings } from './store/CuesheetSettings';
|
import { useCuesheetSettings } from './store/CuesheetSettings';
|
||||||
import EditableCell from './tableElements/EditableCell';
|
|
||||||
|
|
||||||
import style from './Cuesheet.module.scss';
|
import style from './Cuesheet.module.scss';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user