mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-21 06:59:09 +00:00
V3 (#657)
* refactor: cleanup routes * style: smaller base font * chore: upgrade dependencies * chore: lock node version to electron * refactor: pass HTTP to integration controller (#652) * refactor: deprecate onair control * refactor: remove playback router * Several project files user folder (#617) * chore: automated screenshots (#667) * feat: app settings (#658) * refactor: remove deprecated event data (#674) * Studio clock (#663) --------- Co-authored-by: Carlos Valente <carlosvalente@pm.me> * Feat: reorder events with alt+ctrl + arrow up/down (#645) * Warning and danger per event (#677) --------- Co-authored-by: Fabian Posenau <fabian@fphome.de> * refactor: stabilise actionHandler (#683) Co-authored-by: Fabian Posenau <fabian@fphome.de> * improvement: hide seconds (#675) * wip: overview (#688) * fix: focus cursor (#695) * refactor: update lower third (#665) * Refactor/time formatting (#696) --------- Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Co-authored-by: Carlos Valente <carlosvalente@pm.me> * feat: multiple selection (#703) --------- Co-authored-by: asharonbaltazar <asharonbaltazar@outlook.com> Co-authored-by: Alex <ac@omnivox.dk> * fix: test - go to `Edit mode` befor tying to click `Event options` button (#708) * refactor: runtime service (#715) * fix: issue with loosing cursor position on message (#719) * remove info panel (#721) * Event editor continue (#722) * update API - part (#709) --------- Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com> Co-authored-by: Carlos Valente <carlosvalente@pm.me> * refactor: update timers (#729) * feat: many timers (#706) --------- Co-authored-by: arc-alex <ac@omnivox.dk> * refactor: excel cleanup (#734) * refactor: allow import of blocks and skip import (#735) * Project manager (#697) * refactor: UI for linking events (#763) * upgraded pipeline actions (#777) * Over under (#771) * custom fields (#744) --------- Co-authored-by: Carlos Valente <carlosvalente@pm.me> * Sheets settings (#774) --------- Co-authored-by: arc-alex <ac@omnivox.dk> * style: tweaks to lower thirds (#785) * refactor: delays account for gaps (#784) * refactor: partial state updates (#780) * feat: generate crash report (#787) * Sheet use limited input device auth flow (#782) --------- Co-authored-by: cv <34649812+cpvalente@users.noreply.github.com> Co-authored-by: Carlos Valente <carlosvalente@pm.me> * Custom fields views (#789) * refactor: deprecate presenter and subtitle (#795) * refactor: organise API around resources (#798) --------- Co-authored-by: Bianca Procopio <biancahprocopio@gmail.com> * Time to end (#804) * Skip fixes (#805) * fix: onair derives from playback * Param nav (#822) --------- Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk> * refactor: download files from interface (#831) * Quick options (#814) * End pause (#832) * chore: bump node version in docker (#834) * refactor: follow in run mode (#840) * fix: uncaught error in http integration (#837) * Apply project (#843) Co-authored-by: Matteo Gheza <matteo.gheza07@gmail.com> Co-authored-by: Ary <arylmoraesn@gmail.com> Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk> Co-authored-by: Fabian Posenau <19673098+kellhogs@users.noreply.github.com> Co-authored-by: Fabian Posenau <fabian@fphome.de> Co-authored-by: Alex Rohleder <alexrohleder96@gmail.com> Co-authored-by: asharonbaltazar <asharonbaltazar@outlook.com> Co-authored-by: Bianca Procopio <biancahprocopio@gmail.com> Co-authored-by: Fabian Posenau <fabianpos99+github@gmail.com>
This commit is contained in:
@@ -1,69 +1,58 @@
|
||||
import { memo, useCallback, useEffect, useState } from 'react';
|
||||
import { memo, useEffect, useState } from 'react';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { BiArrowToBottom } from '@react-icons/all-files/bi/BiArrowToBottom';
|
||||
import { IoArrowDown } from '@react-icons/all-files/io5/IoArrowDown';
|
||||
import { IoArrowUp } from '@react-icons/all-files/io5/IoArrowUp';
|
||||
import { IoOptions } from '@react-icons/all-files/io5/IoOptions';
|
||||
import { IoFlag } from '@react-icons/all-files/io5/IoFlag';
|
||||
import { IoPeople } from '@react-icons/all-files/io5/IoPeople';
|
||||
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
||||
import { IoPlayForward } from '@react-icons/all-files/io5/IoPlayForward';
|
||||
import { IoPlaySkipForward } from '@react-icons/all-files/io5/IoPlaySkipForward';
|
||||
import { IoStop } from '@react-icons/all-files/io5/IoStop';
|
||||
import { IoTime } from '@react-icons/all-files/io5/IoTime';
|
||||
import { EndAction, Playback, TimerType } from 'ontime-types';
|
||||
import { millisToString } from 'ontime-utils';
|
||||
import { EndAction, MaybeString, Playback, TimerType, TimeStrategy } from 'ontime-types';
|
||||
|
||||
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
|
||||
import { useAppMode } from '../../../common/stores/appModeStore';
|
||||
import { millisToDelayString } from '../../../common/utils/dateConfig';
|
||||
import { cx } from '../../../common/utils/styleUtils';
|
||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||
import EditableBlockTitle from '../common/EditableBlockTitle';
|
||||
import { EventItemActions } from '../RundownEntry';
|
||||
import TimeInputFlow from '../time-input-flow/TimeInputFlow';
|
||||
|
||||
import BlockActionMenu from './composite/BlockActionMenu';
|
||||
import EventBlockPlayback from './composite/EventBlockPlayback';
|
||||
import EventBlockProgressBar from './composite/EventBlockProgressBar';
|
||||
import EventBlockTimers from './composite/EventBlockTimers';
|
||||
|
||||
import style from './EventBlock.module.scss';
|
||||
|
||||
const blockBtnStyle = {
|
||||
size: 'sm',
|
||||
};
|
||||
|
||||
const tooltipProps = {
|
||||
openDelay: tooltipDelayMid,
|
||||
};
|
||||
|
||||
interface EventBlockInnerProps {
|
||||
isOpen: boolean;
|
||||
timeStart: number;
|
||||
timeEnd: number;
|
||||
duration: number;
|
||||
timeStrategy: TimeStrategy;
|
||||
linkStart: MaybeString;
|
||||
eventId: string;
|
||||
eventIndex: number;
|
||||
isPublic: boolean;
|
||||
endAction: EndAction;
|
||||
timerType: TimerType;
|
||||
title: string;
|
||||
note: string;
|
||||
delay: number;
|
||||
previousEnd: number;
|
||||
next: boolean;
|
||||
isNext: boolean;
|
||||
skip: boolean;
|
||||
selected: boolean;
|
||||
loaded: boolean;
|
||||
playback?: Playback;
|
||||
isRolling: boolean;
|
||||
actionHandler: (action: EventItemActions, payload?: any) => void;
|
||||
disableEdit: boolean;
|
||||
isFirstEvent: boolean;
|
||||
}
|
||||
|
||||
const EventBlockInner = (props: EventBlockInnerProps) => {
|
||||
const {
|
||||
isOpen,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
duration,
|
||||
timeStrategy,
|
||||
linkStart,
|
||||
eventId,
|
||||
isPublic = true,
|
||||
endAction,
|
||||
@@ -71,32 +60,19 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
|
||||
title,
|
||||
note,
|
||||
delay,
|
||||
previousEnd,
|
||||
next,
|
||||
isNext,
|
||||
skip = false,
|
||||
selected,
|
||||
loaded,
|
||||
playback,
|
||||
isRolling,
|
||||
actionHandler,
|
||||
disableEdit,
|
||||
isFirstEvent,
|
||||
} = props;
|
||||
|
||||
const [renderInner, setRenderInner] = useState(false);
|
||||
const setEditId = useAppMode((state) => state.setEditId);
|
||||
|
||||
useEffect(() => {
|
||||
setRenderInner(true);
|
||||
}, []);
|
||||
|
||||
const toggleOpenEvent = useCallback(() => {
|
||||
if (isOpen) {
|
||||
setEditId(null);
|
||||
} else {
|
||||
setEditId(eventId);
|
||||
}
|
||||
}, [eventId, isOpen, setEditId]);
|
||||
|
||||
const eventIsPlaying = playback === Playback.Play;
|
||||
const eventIsPaused = playback === Playback.Pause;
|
||||
|
||||
@@ -107,72 +83,39 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
|
||||
playBtnStyles._hover = {};
|
||||
}
|
||||
|
||||
const delayedStart = Math.max(0, timeStart + delay);
|
||||
const newTime = millisToString(delayedStart);
|
||||
const delayTime = delay !== 0 ? millisToDelayString(delay) : null;
|
||||
|
||||
const overlap = previousEnd - timeStart;
|
||||
const overlapTime = !isFirstEvent
|
||||
? overlap > 0
|
||||
? `Overlapping ${millisToDelayString(overlap)}`
|
||||
: overlap < 0
|
||||
? `Spacing ${millisToDelayString(overlap)}`
|
||||
: null
|
||||
: null;
|
||||
|
||||
return !renderInner ? null : (
|
||||
<>
|
||||
<EventBlockTimers
|
||||
eventId={eventId}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
duration={duration}
|
||||
delay={delay}
|
||||
previousEnd={previousEnd}
|
||||
/>
|
||||
<EditableBlockTitle title={title} eventId={eventId} placeholder='Event title' className={style.eventTitle} />
|
||||
{next ? (
|
||||
<Tooltip label='Next event' {...tooltipProps}>
|
||||
<span className={style.nextTag}>UP NEXT</span>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<span className={style.indicators}>
|
||||
{delayTime && (
|
||||
<Tooltip
|
||||
label={
|
||||
<div>
|
||||
{delayTime} <br />
|
||||
New Time: {newTime}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className={`${style.indicator} ${style.delay}`} />
|
||||
</Tooltip>
|
||||
)}
|
||||
{overlapTime && (
|
||||
<Tooltip label={overlapTime}>
|
||||
<div className={`${style.indicator} ${overlap > 0 ? style.overlap : style.spacing}`} />
|
||||
</Tooltip>
|
||||
)}
|
||||
{timeStart > timeEnd && (
|
||||
<Tooltip label='Start time is later than end'>
|
||||
<div className={`${style.indicator} ${style.nextDay}`} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
<div className={style.eventTimers}>
|
||||
<TimeInputFlow
|
||||
eventId={eventId}
|
||||
timeStart={timeStart}
|
||||
timeEnd={timeEnd}
|
||||
duration={duration}
|
||||
delay={delay}
|
||||
timeStrategy={timeStrategy}
|
||||
linkStart={linkStart}
|
||||
/>
|
||||
</div>
|
||||
<div className={style.titleSection}>
|
||||
<EditableBlockTitle title={title} eventId={eventId} placeholder='Event title' className={style.eventTitle} />
|
||||
{isNext && (
|
||||
<Tooltip label='Next event' {...tooltipProps}>
|
||||
<span className={style.nextTag}>UP NEXT</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<EventBlockPlayback
|
||||
eventId={eventId}
|
||||
skip={skip}
|
||||
isPlaying={eventIsPlaying}
|
||||
isPaused={eventIsPaused}
|
||||
selected={selected}
|
||||
loaded={loaded}
|
||||
disablePlayback={skip || isRolling}
|
||||
/>
|
||||
<div className={style.statusElements}>
|
||||
<div className={style.statusElements} id='block-status' data-ispublic={isPublic}>
|
||||
<span className={style.eventNote}>{note}</span>
|
||||
<div className={selected ? style.progressBg : `${style.progressBg} ${style.hidden}`}>
|
||||
{selected && <EventBlockProgressBar playback={playback} />}
|
||||
<div className={loaded ? style.progressBg : `${style.progressBg} ${style.hidden}`}>
|
||||
{loaded && <EventBlockProgressBar />}
|
||||
</div>
|
||||
<div className={style.eventStatus} tabIndex={-1}>
|
||||
<Tooltip label={`Time type: ${timerType}`} {...tooltipProps}>
|
||||
@@ -187,30 +130,11 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
|
||||
</Tooltip>
|
||||
<Tooltip label={`${isPublic ? 'Event is public' : 'Event is private'}`} {...tooltipProps}>
|
||||
<span>
|
||||
<IoPeople
|
||||
className={`${style.statusIcon} ${isPublic ? style.active : style.disabled}`}
|
||||
data-ispublic={isPublic}
|
||||
/>
|
||||
<IoPeople className={`${style.statusIcon} ${isPublic ? style.active : style.disabled}`} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className={style.eventActions}>
|
||||
<TooltipActionBtn
|
||||
{...blockBtnStyle}
|
||||
variant='ontime-subtle-white'
|
||||
size='sm'
|
||||
icon={<IoOptions />}
|
||||
clickHandler={toggleOpenEvent}
|
||||
tooltip='Event options'
|
||||
aria-label='Event options'
|
||||
tabIndex={-1}
|
||||
backgroundColor={isOpen ? '#2B5ABC' : undefined}
|
||||
color={isOpen ? 'white' : '#f6f6f6'}
|
||||
isDisabled={disableEdit}
|
||||
/>
|
||||
<BlockActionMenu showClone enableDelete={!selected} actionHandler={actionHandler} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -219,14 +143,16 @@ export default memo(EventBlockInner);
|
||||
|
||||
function EndActionIcon(props: { action: EndAction; className: string }) {
|
||||
const { action, className } = props;
|
||||
const maybeActiveClasses = cx([action !== EndAction.None && style.active, className]);
|
||||
|
||||
if (action === EndAction.LoadNext) {
|
||||
return <IoPlaySkipForward className={className} />;
|
||||
return <IoPlaySkipForward className={maybeActiveClasses} />;
|
||||
}
|
||||
if (action === EndAction.PlayNext) {
|
||||
return <IoPlayForward className={className} />;
|
||||
return <IoPlayForward className={maybeActiveClasses} />;
|
||||
}
|
||||
if (action === EndAction.Stop) {
|
||||
return <IoStop className={className} />;
|
||||
return <IoStop className={maybeActiveClasses} />;
|
||||
}
|
||||
return <IoPlay className={className} />;
|
||||
}
|
||||
@@ -240,7 +166,7 @@ function TimerIcon(props: { type: TimerType; className: string }) {
|
||||
return <IoTime className={className} />;
|
||||
}
|
||||
if (type === TimerType.TimeToEnd) {
|
||||
return <BiArrowToBottom className={className} />;
|
||||
return <IoFlag className={className} />;
|
||||
}
|
||||
return <IoArrowDown className={className} />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user