mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-15 12:23:51 +00:00
feat: operator view (#440)
* feat: operator view * chore: smoke test operator * refactor: small improvements from deepsource --------- Co-authored-by: arihanv <arihanvaranasi@gmail.com> Co-authored-by: arihanv <63890951+arihanv@users.noreply.github.com>
This commit is contained in:
@@ -113,14 +113,6 @@ $table-header-font-size: calc(1rem - 3px);
|
||||
}
|
||||
}
|
||||
|
||||
.delaySymbol {
|
||||
svg {
|
||||
font-size: 1.5rem;
|
||||
color: $ontime-delay;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.delayedTime {
|
||||
color: $ontime-delay-text;
|
||||
font-size: calc(1rem - 2px);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MutableRefObject, useEffect, useRef } from 'react';
|
||||
import { useRef } from 'react';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import {
|
||||
closestCenter,
|
||||
@@ -14,6 +14,7 @@ import { horizontalListSortingStrategy, SortableContext, sortableKeyboardCoordin
|
||||
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
||||
import { isOntimeBlock, isOntimeDelay, isOntimeEvent, OntimeRundown, OntimeRundownEntry } from 'ontime-types';
|
||||
|
||||
import useFollowComponent from '../../common/hooks/useFollowComponent';
|
||||
import { useLocalStorage } from '../../common/hooks/useLocalStorage';
|
||||
import { millisToDelayString } from '../../common/utils/dateConfig';
|
||||
import { getAccessibleColour } from '../../common/utils/styleUtils';
|
||||
@@ -46,6 +47,8 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
||||
const [columnSizing, setColumnSizing] = useLocalStorage('table-sizes', {});
|
||||
|
||||
const selectedRef = useRef<HTMLTableRowElement | null>(null);
|
||||
const tableContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
useFollowComponent({ followRef: selectedRef, scrollRef: tableContainerRef, doFollow: followSelected });
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
@@ -63,7 +66,6 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
||||
onColumnSizingChange: setColumnSizing,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
});
|
||||
const tableContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, {
|
||||
@@ -83,34 +85,6 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
||||
}),
|
||||
);
|
||||
|
||||
// when selection moves, view should follow
|
||||
useEffect(() => {
|
||||
function scrollToComponent(
|
||||
componentRef: MutableRefObject<HTMLTableRowElement>,
|
||||
scrollRef: MutableRefObject<HTMLDivElement>,
|
||||
) {
|
||||
const componentRect = componentRef.current.getBoundingClientRect();
|
||||
const scrollRect = scrollRef.current.getBoundingClientRect();
|
||||
const top = componentRect.top - scrollRect.top + scrollRef.current.scrollTop - 100;
|
||||
scrollRef.current.scrollTo({ top, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
if (!followSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedRef.current && tableContainerRef.current) {
|
||||
// Use requestAnimationFrame to ensure the component is fully loaded
|
||||
window.requestAnimationFrame(() => {
|
||||
scrollToComponent(
|
||||
selectedRef as MutableRefObject<HTMLTableRowElement>,
|
||||
tableContainerRef as MutableRefObject<HTMLDivElement>,
|
||||
);
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line -- the prompt seems incorrect, we need the refs
|
||||
}, [selectedRef.current, tableContainerRef.current, followSelected]);
|
||||
|
||||
const handleOnDragEnd = (event: DragEndEvent) => {
|
||||
const { delta, active, over } = event;
|
||||
|
||||
@@ -243,7 +217,7 @@ export default function Cuesheet({ data, columns, handleUpdate, selectedId }: Cu
|
||||
|
||||
let rowBgColour: string | undefined;
|
||||
if (row.original.id === selectedId) {
|
||||
rowBgColour = '#D20300'; // $red-700
|
||||
rowBgColour = 'var(--cuesheet-running-bg-override, #D20300)'; // $red-700
|
||||
}
|
||||
return (
|
||||
<tr
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('parseField()', () => {
|
||||
});
|
||||
|
||||
it('returns an empty string on undefined fields', () => {
|
||||
expect(parseField('presenter', undefined)).toBe('');
|
||||
expect(parseField('presenter')).toBe('');
|
||||
});
|
||||
|
||||
describe('simply returns any other value in any other field', () => {
|
||||
|
||||
+4
-4
@@ -101,13 +101,13 @@ $active-colour: $gray-500;
|
||||
.actionIcon {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: $active-colour;
|
||||
}
|
||||
|
||||
&.enabled {
|
||||
color: $active-indicator;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $active-colour;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline'
|
||||
import { EventData, Playback } from 'ontime-types';
|
||||
import { formatDisplay } from 'ontime-utils';
|
||||
|
||||
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 { formatTime } from '../../../common/utils/time';
|
||||
import { tooltipDelayFast } from '../../../ontimeConfig';
|
||||
import { useCuesheetSettings } from '../store/CuesheetSettings';
|
||||
import PlaybackIcon from '../tableElements/PlaybackIcon';
|
||||
|
||||
import style from './CuesheetTableHeader.module.scss';
|
||||
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { useCallback } from 'react';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { IoCheckmark } from '@react-icons/all-files/io5/IoCheckmark';
|
||||
import { IoChevronDown } from '@react-icons/all-files/io5/IoChevronDown';
|
||||
import { IoChevronUp } from '@react-icons/all-files/io5/IoChevronUp';
|
||||
import { CellContext, ColumnDef } from '@tanstack/react-table';
|
||||
import { OntimeEvent, OntimeRundownEntry, UserFields } from 'ontime-types';
|
||||
import { millisToString } from 'ontime-utils';
|
||||
|
||||
import { millisToDelayString } from '../../common/utils/dateConfig';
|
||||
import { tooltipDelayFast } from '../../ontimeConfig';
|
||||
import DelayIndicator from '../../common/components/delay-indicator/DelayIndicator';
|
||||
|
||||
import { useCuesheetSettings } from './store/CuesheetSettings';
|
||||
import EditableCell from './tableElements/EditableCell';
|
||||
@@ -20,30 +16,6 @@ function makePublic(row: CellContext<OntimeRundownEntry, unknown>) {
|
||||
return cellValue ? <IoCheckmark className={style.check} /> : '';
|
||||
}
|
||||
|
||||
function DelayIndicator(props: { delayValue: number }) {
|
||||
const { delayValue } = props;
|
||||
if (delayValue < 0) {
|
||||
return (
|
||||
<Tooltip openDelay={tooltipDelayFast} label={millisToDelayString(delayValue)}>
|
||||
<span className={style.delaySymbol}>
|
||||
<IoChevronDown />
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
if (delayValue > 0) {
|
||||
return (
|
||||
<Tooltip openDelay={tooltipDelayFast} label={millisToDelayString(delayValue)}>
|
||||
<span className={style.delaySymbol}>
|
||||
<IoChevronUp />
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function MakeTimer({ getValue, row: { original } }: CellContext<OntimeRundownEntry, unknown>) {
|
||||
const showDelayedTimes = useCuesheetSettings((state) => state.showDelayedTimes);
|
||||
const cellValue = (getValue() as number | null) ?? 0;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { IoPause } from '@react-icons/all-files/io5/IoPause';
|
||||
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
||||
import { IoStop } from '@react-icons/all-files/io5/IoStop';
|
||||
import { Playback } from 'ontime-types';
|
||||
|
||||
import { tooltipDelayFast } from '../../../ontimeConfig';
|
||||
|
||||
interface PlaybackIconProps {
|
||||
state: Playback;
|
||||
}
|
||||
|
||||
export default function PlaybackIcon(props: PlaybackIconProps) {
|
||||
const { state } = props;
|
||||
|
||||
// if timer is Pause or Armed
|
||||
let label = 'Timer Paused';
|
||||
let Icon = IoPause;
|
||||
|
||||
if (state === Playback.Roll) {
|
||||
label = 'Timer Rolling';
|
||||
Icon = IoPlay;
|
||||
} else if (state === Playback.Play) {
|
||||
label = 'Timer Playing';
|
||||
Icon = IoPlay;
|
||||
} else if (state === Playback.Stop) {
|
||||
label = 'Timer Stopped';
|
||||
Icon = IoStop;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip openDelay={tooltipDelayFast} label={label} shouldWrapChildren>
|
||||
<Icon />
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user