mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-11 09:09:34 +00:00
refactor: improve performance on EventBlock
This commit is contained in:
@@ -10,13 +10,7 @@ export default function TooltipActionBtn(props: TooltipActionBtnProps) {
|
|||||||
const { clickHandler, icon, size = 'xs', tooltip, openDelay = 0, className, ...rest } = props;
|
const { clickHandler, icon, size = 'xs', tooltip, openDelay = 0, className, ...rest } = props;
|
||||||
return (
|
return (
|
||||||
<Tooltip label={tooltip} openDelay={openDelay}>
|
<Tooltip label={tooltip} openDelay={openDelay}>
|
||||||
<IconButton
|
<IconButton {...rest} size={size} icon={icon} onClick={clickHandler} className={className} />
|
||||||
{...rest}
|
|
||||||
size={size}
|
|
||||||
icon={icon}
|
|
||||||
onClick={clickHandler}
|
|
||||||
className={className}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,26 +4,21 @@ import { IoCaretDownCircle } from '@react-icons/all-files/io5/IoCaretDownCircle'
|
|||||||
import { IoCaretUpCircle } from '@react-icons/all-files/io5/IoCaretUpCircle';
|
import { IoCaretUpCircle } from '@react-icons/all-files/io5/IoCaretUpCircle';
|
||||||
import { IoOptions } from '@react-icons/all-files/io5/IoOptions';
|
import { IoOptions } from '@react-icons/all-files/io5/IoOptions';
|
||||||
import { IoPeople } from '@react-icons/all-files/io5/IoPeople';
|
import { IoPeople } from '@react-icons/all-files/io5/IoPeople';
|
||||||
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
|
||||||
import { IoPlayCircle } from '@react-icons/all-files/io5/IoPlayCircle';
|
import { IoPlayCircle } from '@react-icons/all-files/io5/IoPlayCircle';
|
||||||
import { IoPlayForwardCircle } from '@react-icons/all-files/io5/IoPlayForwardCircle';
|
import { IoPlayForwardCircle } from '@react-icons/all-files/io5/IoPlayForwardCircle';
|
||||||
import { IoPlayOutline } from '@react-icons/all-files/io5/IoPlayOutline';
|
|
||||||
import { IoPlaySkipForwardCircle } from '@react-icons/all-files/io5/IoPlaySkipForwardCircle';
|
import { IoPlaySkipForwardCircle } from '@react-icons/all-files/io5/IoPlaySkipForwardCircle';
|
||||||
import { IoReload } from '@react-icons/all-files/io5/IoReload';
|
|
||||||
import { IoRemoveCircle } from '@react-icons/all-files/io5/IoRemoveCircle';
|
|
||||||
import { IoRemoveCircleOutline } from '@react-icons/all-files/io5/IoRemoveCircleOutline';
|
|
||||||
import { IoStopCircle } from '@react-icons/all-files/io5/IoStopCircle';
|
import { IoStopCircle } from '@react-icons/all-files/io5/IoStopCircle';
|
||||||
import { IoTime } from '@react-icons/all-files/io5/IoTime';
|
import { IoTime } from '@react-icons/all-files/io5/IoTime';
|
||||||
import { EndAction, Playback, TimerType } from 'ontime-types';
|
import { EndAction, Playback, TimerType } from 'ontime-types';
|
||||||
|
|
||||||
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
|
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
|
||||||
import { setEventPlayback } from '../../../common/hooks/useSocket';
|
|
||||||
import { useEventEditorStore } from '../../../common/stores/eventEditor';
|
import { useEventEditorStore } from '../../../common/stores/eventEditor';
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
import EditableBlockTitle from '../common/EditableBlockTitle';
|
import EditableBlockTitle from '../common/EditableBlockTitle';
|
||||||
import { EventItemActions } from '../RundownEntry';
|
import { EventItemActions } from '../RundownEntry';
|
||||||
|
|
||||||
import BlockActionMenu from './composite/BlockActionMenu';
|
import BlockActionMenu from './composite/BlockActionMenu';
|
||||||
|
import EventBlockPlayback from './composite/EventBlockPlayback';
|
||||||
import EventBlockProgressBar from './composite/EventBlockProgressBar';
|
import EventBlockProgressBar from './composite/EventBlockProgressBar';
|
||||||
import EventBlockTimers from './composite/EventBlockTimers';
|
import EventBlockTimers from './composite/EventBlockTimers';
|
||||||
|
|
||||||
@@ -104,49 +99,13 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
|
|||||||
|
|
||||||
return !renderInner ? null : (
|
return !renderInner ? null : (
|
||||||
<>
|
<>
|
||||||
<div className={style.playbackActions}>
|
<EventBlockPlayback eventId={eventId} skip={skip} isPlaying={eventIsPlaying} selected={selected} />
|
||||||
<TooltipActionBtn
|
|
||||||
variant='ontime-subtle-white'
|
|
||||||
aria-label='Skip event'
|
|
||||||
tooltip='Skip event'
|
|
||||||
icon={skip ? <IoRemoveCircle /> : <IoRemoveCircleOutline />}
|
|
||||||
{...tooltipProps}
|
|
||||||
{...blockBtnStyle}
|
|
||||||
clickHandler={() => actionHandler('update', { field: 'skip', value: !skip })}
|
|
||||||
tabIndex={-1}
|
|
||||||
disabled={selected}
|
|
||||||
/>
|
|
||||||
<TooltipActionBtn
|
|
||||||
variant='ontime-subtle-white'
|
|
||||||
aria-label='Load event'
|
|
||||||
tooltip='Load event'
|
|
||||||
icon={<IoReload className={style.flip} />}
|
|
||||||
disabled={skip}
|
|
||||||
{...tooltipProps}
|
|
||||||
{...blockBtnStyle}
|
|
||||||
clickHandler={() => setEventPlayback.loadEvent(eventId)}
|
|
||||||
tabIndex={-1}
|
|
||||||
/>
|
|
||||||
<TooltipActionBtn
|
|
||||||
variant='ontime-subtle-white'
|
|
||||||
aria-label='Start event'
|
|
||||||
tooltip='Start event'
|
|
||||||
icon={eventIsPlaying ? <IoPlay /> : <IoPlayOutline />}
|
|
||||||
disabled={skip}
|
|
||||||
{...tooltipProps}
|
|
||||||
{...blockBtnStyle}
|
|
||||||
clickHandler={() => setEventPlayback.startEvent(eventId)}
|
|
||||||
backgroundColor={eventIsPlaying ? '#58A151' : undefined}
|
|
||||||
_hover={{ backgroundColor: eventIsPlaying ? '#58A151' : undefined }}
|
|
||||||
tabIndex={-1}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<EventBlockTimers
|
<EventBlockTimers
|
||||||
|
eventId={eventId}
|
||||||
timeStart={timeStart}
|
timeStart={timeStart}
|
||||||
timeEnd={timeEnd}
|
timeEnd={timeEnd}
|
||||||
duration={duration}
|
duration={duration}
|
||||||
delay={delay}
|
delay={delay}
|
||||||
actionHandler={actionHandler}
|
|
||||||
previousEnd={previousEnd}
|
previousEnd={previousEnd}
|
||||||
/>
|
/>
|
||||||
<EditableBlockTitle title={title} eventId={eventId} placeholder='Event title' className={style.eventTitle} />
|
<EditableBlockTitle title={title} eventId={eventId} placeholder='Event title' className={style.eventTitle} />
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
|
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
||||||
|
import { IoPlayOutline } from '@react-icons/all-files/io5/IoPlayOutline';
|
||||||
|
import { IoReload } from '@react-icons/all-files/io5/IoReload';
|
||||||
|
import { IoRemoveCircle } from '@react-icons/all-files/io5/IoRemoveCircle';
|
||||||
|
import { IoRemoveCircleOutline } from '@react-icons/all-files/io5/IoRemoveCircleOutline';
|
||||||
|
|
||||||
|
import TooltipActionBtn from '../../../../common/components/buttons/TooltipActionBtn';
|
||||||
|
import { useEventAction } from '../../../../common/hooks/useEventAction';
|
||||||
|
import { setEventPlayback } from '../../../../common/hooks/useSocket';
|
||||||
|
import { tooltipDelayMid } from '../../../../ontimeConfig';
|
||||||
|
|
||||||
|
import style from '../EventBlock.module.scss';
|
||||||
|
|
||||||
|
const blockBtnStyle = {
|
||||||
|
size: 'sm',
|
||||||
|
};
|
||||||
|
|
||||||
|
const tooltipProps = {
|
||||||
|
openDelay: tooltipDelayMid,
|
||||||
|
};
|
||||||
|
|
||||||
|
interface EventBlockPlaybackProps {
|
||||||
|
eventId: string;
|
||||||
|
skip: boolean;
|
||||||
|
isPlaying: boolean;
|
||||||
|
selected: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventBlockPlayback = (props: EventBlockPlaybackProps) => {
|
||||||
|
const { eventId, skip, isPlaying, selected } = props;
|
||||||
|
const { updateEvent } = useEventAction();
|
||||||
|
|
||||||
|
const toggleSkip = () => {
|
||||||
|
updateEvent({ id: eventId, skip: !skip });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={style.playbackActions}>
|
||||||
|
<TooltipActionBtn
|
||||||
|
variant='ontime-subtle-white'
|
||||||
|
aria-label='Skip event'
|
||||||
|
tooltip='Skip event'
|
||||||
|
icon={skip ? <IoRemoveCircle /> : <IoRemoveCircleOutline />}
|
||||||
|
{...tooltipProps}
|
||||||
|
{...blockBtnStyle}
|
||||||
|
clickHandler={toggleSkip}
|
||||||
|
tabIndex={-1}
|
||||||
|
isDisabled={selected}
|
||||||
|
/>
|
||||||
|
<TooltipActionBtn
|
||||||
|
variant='ontime-subtle-white'
|
||||||
|
aria-label='Load event'
|
||||||
|
tooltip='Load event'
|
||||||
|
icon={<IoReload className={style.flip} />}
|
||||||
|
isDisabled={skip}
|
||||||
|
{...tooltipProps}
|
||||||
|
{...blockBtnStyle}
|
||||||
|
clickHandler={() => setEventPlayback.loadEvent(eventId)}
|
||||||
|
tabIndex={-1}
|
||||||
|
/>
|
||||||
|
<TooltipActionBtn
|
||||||
|
variant='ontime-subtle-white'
|
||||||
|
aria-label='Start event'
|
||||||
|
tooltip='Start event'
|
||||||
|
icon={isPlaying ? <IoPlay /> : <IoPlayOutline />}
|
||||||
|
isDisabled={skip}
|
||||||
|
{...tooltipProps}
|
||||||
|
{...blockBtnStyle}
|
||||||
|
clickHandler={() => setEventPlayback.startEvent(eventId)}
|
||||||
|
backgroundColor={isPlaying ? '#58A151' : undefined}
|
||||||
|
_hover={{ backgroundColor: isPlaying ? '#58A151' : undefined }}
|
||||||
|
tabIndex={-1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(EventBlockPlayback);
|
||||||
@@ -1,28 +1,53 @@
|
|||||||
import { useCallback, useState } from 'react';
|
import { memo, useCallback, useState } from 'react';
|
||||||
|
import { OntimeEvent } from 'ontime-types';
|
||||||
import { millisToString } from 'ontime-utils';
|
import { millisToString } from 'ontime-utils';
|
||||||
|
|
||||||
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
|
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
|
||||||
|
import { useEventAction } from '../../../../common/hooks/useEventAction';
|
||||||
import { millisToMinutes } from '../../../../common/utils/dateConfig';
|
import { millisToMinutes } from '../../../../common/utils/dateConfig';
|
||||||
import { TimeEntryField, validateEntry } from '../../../../common/utils/timesManager';
|
import { calculateDuration, TimeEntryField, validateEntry } from '../../../../common/utils/timesManager';
|
||||||
import { EventItemActions } from '../../RundownEntry';
|
|
||||||
|
|
||||||
import style from '../EventBlock.module.scss';
|
import style from '../EventBlock.module.scss';
|
||||||
|
|
||||||
interface EventBlockTimerProps {
|
interface EventBlockTimerProps {
|
||||||
|
eventId: string;
|
||||||
timeStart: number;
|
timeStart: number;
|
||||||
timeEnd: number;
|
timeEnd: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
delay: number;
|
delay: number;
|
||||||
actionHandler: (action: EventItemActions, payload?: any) => void;
|
|
||||||
previousEnd: number;
|
previousEnd: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function EventBlockTimers(props: EventBlockTimerProps) {
|
type TimeActions = 'timeStart' | 'timeEnd' | 'durationOverride';
|
||||||
const { timeStart, timeEnd, duration, delay, actionHandler, previousEnd } = props;
|
|
||||||
|
const EventBlockTimers = (props: EventBlockTimerProps) => {
|
||||||
|
const { eventId, timeStart, timeEnd, duration, delay, previousEnd } = props;
|
||||||
|
const { updateEvent } = useEventAction();
|
||||||
|
|
||||||
const [warning, setWarnings] = useState({ start: '', end: '', duration: '' });
|
const [warning, setWarnings] = useState({ start: '', end: '', duration: '' });
|
||||||
|
|
||||||
const delayTime = `${delay >= 0 ? '+' : '-'} ${millisToMinutes(Math.abs(delay))}`;
|
const handleSubmit = (field: TimeActions, value: number) => {
|
||||||
const newTime = millisToString(timeStart + delay);
|
const newEventData: Partial<OntimeEvent> = { id: eventId };
|
||||||
|
switch (field) {
|
||||||
|
case 'durationOverride': {
|
||||||
|
// duration defines timeEnd
|
||||||
|
newEventData.duration = value;
|
||||||
|
newEventData.timeEnd = timeStart + value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'timeStart': {
|
||||||
|
newEventData.duration = calculateDuration(value, timeEnd);
|
||||||
|
newEventData.timeStart = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'timeEnd': {
|
||||||
|
newEventData.duration = calculateDuration(timeStart, value);
|
||||||
|
newEventData.timeEnd = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateEvent(newEventData);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Validates a time input against its pair
|
* @description Validates a time input against its pair
|
||||||
@@ -39,12 +64,8 @@ export default function EventBlockTimers(props: EventBlockTimerProps) {
|
|||||||
[timeEnd, timeStart],
|
[timeEnd, timeStart],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSubmit = useCallback(
|
const delayTime = `${delay >= 0 ? '+' : '-'} ${millisToMinutes(Math.abs(delay))}`;
|
||||||
(field: TimeEntryField, value: number) => {
|
const newTime = millisToString(timeStart + delay);
|
||||||
actionHandler('update', { field, value });
|
|
||||||
},
|
|
||||||
[actionHandler],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.eventTimers}>
|
<div className={style.eventTimers}>
|
||||||
@@ -86,4 +107,6 @@ export default function EventBlockTimers(props: EventBlockTimerProps) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default memo(EventBlockTimers);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useRef } from 'react';
|
import { memo, useCallback, useRef } from 'react';
|
||||||
import { Button, Checkbox, Tooltip } from '@chakra-ui/react';
|
import { Button, Checkbox, Tooltip } from '@chakra-ui/react';
|
||||||
import { SupportedEvent } from 'ontime-types';
|
import { SupportedEvent } from 'ontime-types';
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ interface QuickAddBlockProps {
|
|||||||
disableAddBlock: boolean;
|
disableAddBlock: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function QuickAddBlock(props: QuickAddBlockProps) {
|
const QuickAddBlock = (props: QuickAddBlockProps) => {
|
||||||
const { showKbd, eventId, previousEventId, disableAddDelay = true, disableAddBlock } = props;
|
const { showKbd, eventId, previousEventId, disableAddDelay = true, disableAddBlock } = props;
|
||||||
const { addEvent } = useEventAction();
|
const { addEvent } = useEventAction();
|
||||||
const { emitError } = useEmitLog();
|
const { emitError } = useEmitLog();
|
||||||
@@ -117,4 +117,6 @@ export default function QuickAddBlock(props: QuickAddBlockProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default memo(QuickAddBlock);
|
||||||
|
|||||||
Reference in New Issue
Block a user