mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-03 13:29:06 +00:00
style: editor tweaks (#736)
* style: menu tweaks * style: editor tweaks * style: freeze
This commit is contained in:
@@ -10,14 +10,12 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { FiPower } from '@react-icons/all-files/fi/FiPower';
|
import { IoPowerOutline } from '@react-icons/all-files/io5/IoPowerOutline';
|
||||||
|
|
||||||
import { Size } from '../../models/Util.type';
|
|
||||||
import { useEmitLog } from '../../stores/logger';
|
import { useEmitLog } from '../../stores/logger';
|
||||||
|
|
||||||
interface QuitIconBtnProps {
|
interface QuitIconBtnProps {
|
||||||
clickHandler: () => void;
|
clickHandler: () => void;
|
||||||
size?: Size;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +40,7 @@ const quitBtnStyle = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function QuitIconBtn(props: QuitIconBtnProps) {
|
export default function QuitIconBtn(props: QuitIconBtnProps) {
|
||||||
const { clickHandler, size = 'lg', disabled, ...rest } = props;
|
const { clickHandler, disabled, ...rest } = props;
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const { emitInfo } = useEmitLog();
|
const { emitInfo } = useEmitLog();
|
||||||
const onClose = () => setIsOpen(false);
|
const onClose = () => setIsOpen(false);
|
||||||
@@ -67,8 +65,8 @@ export default function QuitIconBtn(props: QuitIconBtnProps) {
|
|||||||
<Tooltip label='Quit Application'>
|
<Tooltip label='Quit Application'>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label='Quit Application'
|
aria-label='Quit Application'
|
||||||
size={size}
|
size='lg'
|
||||||
icon={<FiPower />}
|
icon={<IoPowerOutline />}
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
isDisabled={disabled}
|
isDisabled={disabled}
|
||||||
{...quitBtnStyle}
|
{...quitBtnStyle}
|
||||||
@@ -81,7 +79,7 @@ export default function QuitIconBtn(props: QuitIconBtnProps) {
|
|||||||
<AlertDialogHeader fontSize='lg' fontWeight='bold'>
|
<AlertDialogHeader fontSize='lg' fontWeight='bold'>
|
||||||
Ontime Shutdown
|
Ontime Shutdown
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogBody>This will shutdown the program and all running servers. Are you sure?</AlertDialogBody>
|
<AlertDialogBody>This will shutdown the Ontime server. Are you sure?</AlertDialogBody>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<Button ref={cancelRef} onClick={onClose} variant='ghost'>
|
<Button ref={cancelRef} onClick={onClose} variant='ghost'>
|
||||||
Cancel
|
Cancel
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
.header {
|
|
||||||
font-size: $inner-section-text-size;
|
|
||||||
font-weight: 600;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
color: $section-white;
|
|
||||||
margin-top: $main-spacing;
|
|
||||||
border-bottom: 1px solid $border-color-ondark;
|
|
||||||
padding-bottom: $element-inner-spacing;
|
|
||||||
margin-bottom: $element-spacing;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.moreExpanded {
|
|
||||||
transform: scaleY(-1);
|
|
||||||
transition: transform $transition-time-feedback;
|
|
||||||
}
|
|
||||||
|
|
||||||
.moreCollapsed {
|
|
||||||
transform: scaleY(1);
|
|
||||||
transition: transform $transition-time-feedback;
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import { FiChevronUp } from '@react-icons/all-files/fi/FiChevronUp';
|
|
||||||
|
|
||||||
import style from './CollapseBar.module.scss';
|
|
||||||
|
|
||||||
interface CollapseBarProps {
|
|
||||||
title: string;
|
|
||||||
isCollapsed: boolean;
|
|
||||||
onClick: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function CollapseBar(props: CollapseBarProps) {
|
|
||||||
const { title = 'Collapse bar', isCollapsed, onClick } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={style.header} onClick={onClick}>
|
|
||||||
{title}
|
|
||||||
<FiChevronUp className={isCollapsed ? style.moreCollapsed : style.moreExpanded} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
.contextMenuButton {
|
.contextMenuButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.contextMenuBackdrop {
|
.contextMenuBackdrop {
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import { PropsWithChildren, useState } from 'react';
|
|
||||||
|
|
||||||
import CollapseBar from '../../common/components/collapse-bar/CollapseBar';
|
|
||||||
|
|
||||||
interface CollapsableInfoProps {
|
|
||||||
title: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function CollapsableInfo(props: PropsWithChildren<CollapsableInfoProps>) {
|
|
||||||
const { title, children } = props;
|
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<CollapseBar title={title} isCollapsed={collapsed} onClick={() => setCollapsed((prev) => !prev)} />
|
|
||||||
{!collapsed && children}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
|
padding-bottom: 1rem
|
||||||
}
|
}
|
||||||
|
|
||||||
.gap {
|
.gap {
|
||||||
@@ -13,3 +14,7 @@
|
|||||||
.open {
|
.open {
|
||||||
background: $blue-700;
|
background: $blue-700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { memo, useCallback, useEffect, useState } from 'react';
|
import { memo, useCallback, useEffect, useState } from 'react';
|
||||||
|
import { IconButton, MenuButton, Tooltip } from '@chakra-ui/react';
|
||||||
|
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
||||||
import { IoCloud } from '@react-icons/all-files/io5/IoCloud';
|
import { IoCloud } from '@react-icons/all-files/io5/IoCloud';
|
||||||
import { IoCloudOutline } from '@react-icons/all-files/io5/IoCloudOutline';
|
import { IoCloudOutline } from '@react-icons/all-files/io5/IoCloudOutline';
|
||||||
import { IoColorWand } from '@react-icons/all-files/io5/IoColorWand';
|
import { IoColorWand } from '@react-icons/all-files/io5/IoColorWand';
|
||||||
@@ -10,14 +12,18 @@ import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
|||||||
import { IoPushOutline } from '@react-icons/all-files/io5/IoPushOutline';
|
import { IoPushOutline } from '@react-icons/all-files/io5/IoPushOutline';
|
||||||
import { IoSaveOutline } from '@react-icons/all-files/io5/IoSaveOutline';
|
import { IoSaveOutline } from '@react-icons/all-files/io5/IoSaveOutline';
|
||||||
import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline';
|
import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline';
|
||||||
|
import { IoSnowOutline } from '@react-icons/all-files/io5/IoSnowOutline';
|
||||||
|
|
||||||
import { downloadCSV, downloadRundown } from '../../common/api/ontimeApi';
|
import { downloadCSV, downloadRundown } from '../../common/api/ontimeApi';
|
||||||
import QuitIconBtn from '../../common/components/buttons/QuitIconBtn';
|
import QuitIconBtn from '../../common/components/buttons/QuitIconBtn';
|
||||||
import TooltipActionBtn from '../../common/components/buttons/TooltipActionBtn';
|
import TooltipActionBtn from '../../common/components/buttons/TooltipActionBtn';
|
||||||
import useElectronEvent from '../../common/hooks/useElectronEvent';
|
import useElectronEvent from '../../common/hooks/useElectronEvent';
|
||||||
import { AppMode, useAppMode } from '../../common/stores/appModeStore';
|
import { AppMode, useAppMode } from '../../common/stores/appModeStore';
|
||||||
|
import { cx } from '../../common/utils/styleUtils';
|
||||||
import ExportModal, { ExportType } from '../modals/export-modal/ExportModal';
|
import ExportModal, { ExportType } from '../modals/export-modal/ExportModal';
|
||||||
|
|
||||||
|
import RundownMenu from './RundownMenu';
|
||||||
|
|
||||||
import style from './MenuBar.module.scss';
|
import style from './MenuBar.module.scss';
|
||||||
|
|
||||||
interface MenuBarProps {
|
interface MenuBarProps {
|
||||||
@@ -40,7 +46,7 @@ interface MenuBarProps {
|
|||||||
|
|
||||||
const buttonStyle = {
|
const buttonStyle = {
|
||||||
fontSize: '1.25em',
|
fontSize: '1.25em',
|
||||||
size: 'lg',
|
size: 'md',
|
||||||
colorScheme: 'white',
|
colorScheme: 'white',
|
||||||
_hover: {
|
_hover: {
|
||||||
background: 'rgba(255, 255, 255, 0.10)', // $white-10
|
background: 'rgba(255, 255, 255, 0.10)', // $white-10
|
||||||
@@ -128,8 +134,7 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.menu}>
|
<div className={style.menu}>
|
||||||
<QuitIconBtn disabled={!isElectron} clickHandler={sendShutdown} size='md' />
|
<QuitIconBtn disabled={!isElectron} clickHandler={sendShutdown} />
|
||||||
|
|
||||||
<div className={style.gap} />
|
<div className={style.gap} />
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
{...buttonStyle}
|
{...buttonStyle}
|
||||||
@@ -148,7 +153,6 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
clickHandler={onUploadOpen}
|
clickHandler={onUploadOpen}
|
||||||
tooltip='Import project file'
|
tooltip='Import project file'
|
||||||
aria-label='Import project file'
|
aria-label='Import project file'
|
||||||
size='sm'
|
|
||||||
/>
|
/>
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
{...buttonStyle}
|
{...buttonStyle}
|
||||||
@@ -157,12 +161,22 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
clickHandler={() => setIsModalOpen(true)}
|
clickHandler={() => setIsModalOpen(true)}
|
||||||
tooltip='Export project file'
|
tooltip='Export project file'
|
||||||
aria-label='Export project file'
|
aria-label='Export project file'
|
||||||
size='sm'
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ExportModal onClose={onModalClose} isOpen={isModalOpen} />
|
<ExportModal onClose={onModalClose} isOpen={isModalOpen} />
|
||||||
|
|
||||||
<div className={style.gap} />
|
<div className={style.gap} />
|
||||||
|
<RundownMenu>
|
||||||
|
<Tooltip label='Rundown...'>
|
||||||
|
<MenuButton as={IconButton} icon={<IoAdd />} {...buttonStyle} aria-label='Rundown menu' />
|
||||||
|
</Tooltip>
|
||||||
|
</RundownMenu>
|
||||||
|
<TooltipActionBtn
|
||||||
|
{...buttonStyle}
|
||||||
|
icon={<IoSnowOutline />}
|
||||||
|
className={appMode === AppMode.Run ? style.open : ''}
|
||||||
|
clickHandler={setRunMode}
|
||||||
|
tooltip='Freeze rundown'
|
||||||
|
aria-label='Freeze rundown'
|
||||||
|
/>
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
{...buttonStyle}
|
{...buttonStyle}
|
||||||
icon={<IoPlay />}
|
icon={<IoPlay />}
|
||||||
@@ -170,7 +184,6 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
clickHandler={setRunMode}
|
clickHandler={setRunMode}
|
||||||
tooltip='Run mode'
|
tooltip='Run mode'
|
||||||
aria-label='Run mode'
|
aria-label='Run mode'
|
||||||
size='sm'
|
|
||||||
/>
|
/>
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
{...buttonStyle}
|
{...buttonStyle}
|
||||||
@@ -179,9 +192,7 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
clickHandler={setEditMode}
|
clickHandler={setEditMode}
|
||||||
tooltip='Edit mode'
|
tooltip='Edit mode'
|
||||||
aria-label='Edit mode'
|
aria-label='Edit mode'
|
||||||
size='sm'
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={style.gap} />
|
<div className={style.gap} />
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
{...buttonStyle}
|
{...buttonStyle}
|
||||||
@@ -191,7 +202,6 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
clickHandler={onSheetsOpen}
|
clickHandler={onSheetsOpen}
|
||||||
tooltip='Sheets'
|
tooltip='Sheets'
|
||||||
aria-label='Sheets'
|
aria-label='Sheets'
|
||||||
size='sm'
|
|
||||||
/>
|
/>
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
{...buttonStyle}
|
{...buttonStyle}
|
||||||
@@ -201,7 +211,6 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
clickHandler={onIntegrationOpen}
|
clickHandler={onIntegrationOpen}
|
||||||
tooltip='Integrations'
|
tooltip='Integrations'
|
||||||
aria-label='Integrations'
|
aria-label='Integrations'
|
||||||
size='sm'
|
|
||||||
/>
|
/>
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
{...buttonStyle}
|
{...buttonStyle}
|
||||||
@@ -211,7 +220,6 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
clickHandler={onSettingsOpen}
|
clickHandler={onSettingsOpen}
|
||||||
tooltip='Settings'
|
tooltip='Settings'
|
||||||
aria-label='Settings'
|
aria-label='Settings'
|
||||||
size='sm'
|
|
||||||
/>
|
/>
|
||||||
<div className={style.gap} />
|
<div className={style.gap} />
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
@@ -226,12 +234,11 @@ const MenuBar = (props: MenuBarProps) => {
|
|||||||
<div className={style.gap} />
|
<div className={style.gap} />
|
||||||
<TooltipActionBtn
|
<TooltipActionBtn
|
||||||
{...buttonStyle}
|
{...buttonStyle}
|
||||||
className={isSettingsOpen ? style.open : ''}
|
className={cx([isSettingsOpen ? style.open : null, style.bottom])}
|
||||||
icon={<IoSettingsOutline />}
|
icon={<IoSettingsOutline />}
|
||||||
clickHandler={() => openSettings()}
|
clickHandler={() => openSettings()}
|
||||||
tooltip='About'
|
tooltip='About'
|
||||||
aria-label='About'
|
aria-label='About'
|
||||||
size='sm'
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
import { memo, useCallback } from 'react';
|
import { memo, ReactNode, useCallback } from 'react';
|
||||||
import { Button, Menu, MenuButton, MenuDivider, MenuItem, MenuList } from '@chakra-ui/react';
|
import { Menu, MenuDivider, MenuItem, MenuList } from '@chakra-ui/react';
|
||||||
import { FiMinusCircle } from '@react-icons/all-files/fi/FiMinusCircle';
|
|
||||||
import { FiTrash2 } from '@react-icons/all-files/fi/FiTrash2';
|
|
||||||
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
|
||||||
|
import { IoRemoveCircleOutline } from '@react-icons/all-files/io5/IoRemoveCircleOutline';
|
||||||
import { IoTimerOutline } from '@react-icons/all-files/io5/IoTimerOutline';
|
import { IoTimerOutline } from '@react-icons/all-files/io5/IoTimerOutline';
|
||||||
|
import { IoTrashOutline } from '@react-icons/all-files/io5/IoTrashOutline';
|
||||||
import { SupportedEvent } from 'ontime-types';
|
import { SupportedEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { useEventAction } from '../../common/hooks/useEventAction';
|
import { useEventAction } from '../../common/hooks/useEventAction';
|
||||||
import { useEventSelection } from '../../features/rundown/useEventSelection';
|
import { useEventSelection } from '../../features/rundown/useEventSelection';
|
||||||
|
|
||||||
import style from './RundownMenu.module.scss';
|
const RundownMenu = ({ children }: { children: ReactNode }) => {
|
||||||
|
|
||||||
const RundownMenu = () => {
|
|
||||||
const { clearSelectedEvents } = useEventSelection();
|
const { clearSelectedEvents } = useEventSelection();
|
||||||
|
|
||||||
const { addEvent, deleteAllEvents } = useEventAction();
|
const { addEvent, deleteAllEvents } = useEventAction();
|
||||||
@@ -35,28 +33,24 @@ const RundownMenu = () => {
|
|||||||
}, [deleteAllEvents, clearSelectedEvents]);
|
}, [deleteAllEvents, clearSelectedEvents]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.headerButtons}>
|
<Menu isLazy lazyBehavior='unmount' variant='ontime-on-dark' placement='right-start'>
|
||||||
<Menu isLazy lazyBehavior='unmount' variant='ontime-on-dark'>
|
{children}
|
||||||
<MenuButton as={Button} leftIcon={<IoAdd />} size='sm' variant='ontime-subtle'>
|
<MenuList>
|
||||||
Event...
|
<MenuItem icon={<IoAdd />} onClick={newEvent}>
|
||||||
</MenuButton>
|
Add event at start
|
||||||
<MenuList>
|
</MenuItem>
|
||||||
<MenuItem icon={<IoAdd />} onClick={newEvent}>
|
<MenuItem icon={<IoTimerOutline />} onClick={newDelay}>
|
||||||
Add event at start
|
Add delay at start
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem icon={<IoTimerOutline />} onClick={newDelay}>
|
<MenuItem icon={<IoRemoveCircleOutline />} onClick={newBlock}>
|
||||||
Add delay at start
|
Add block at start
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem icon={<FiMinusCircle />} onClick={newBlock}>
|
<MenuDivider />
|
||||||
Add block at start
|
<MenuItem icon={<IoTrashOutline />} onClick={deleteAll} color='#D20300'>
|
||||||
</MenuItem>
|
Delete all events
|
||||||
<MenuDivider />
|
</MenuItem>
|
||||||
<MenuItem icon={<FiTrash2 />} onClick={deleteAll} color='#D20300'>
|
</MenuList>
|
||||||
Delete all events
|
</Menu>
|
||||||
</MenuItem>
|
|
||||||
</MenuList>
|
|
||||||
</Menu>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { HttpSettings, TimerLifeCycle } from 'ontime-types';
|
|||||||
import { useEmitLog } from '../../../../common/stores/logger';
|
import { useEmitLog } from '../../../../common/stores/logger';
|
||||||
import { startsWithHttp } from '../../../../common/utils/regex';
|
import { startsWithHttp } from '../../../../common/utils/regex';
|
||||||
|
|
||||||
import collapseStyles from '../../../../common/components/collapse-bar/CollapseBar.module.scss';
|
|
||||||
import styles from '../../Modal.module.scss';
|
import styles from '../../Modal.module.scss';
|
||||||
|
|
||||||
interface SubscriptionRowProps {
|
interface SubscriptionRowProps {
|
||||||
@@ -52,7 +51,7 @@ export default function SubscriptionRow(props: SubscriptionRowProps) {
|
|||||||
<span className={`${styles.sectionTitle} ${styles.main}`}>{sectionTitle}</span>
|
<span className={`${styles.sectionTitle} ${styles.main}`}>{sectionTitle}</span>
|
||||||
{visible && <span className={styles.sectionSubtitle}>{subtitle}</span>}
|
{visible && <span className={styles.sectionSubtitle}>{subtitle}</span>}
|
||||||
</div>
|
</div>
|
||||||
<FiChevronUp className={visible ? collapseStyles.moreCollapsed : collapseStyles.moreExpanded} />
|
<FiChevronUp />
|
||||||
</div>
|
</div>
|
||||||
{visible && (
|
{visible && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import type { OscSubscription, TimerLifeCycle } from 'ontime-types';
|
|||||||
|
|
||||||
import { useEmitLog } from '../../../../common/stores/logger';
|
import { useEmitLog } from '../../../../common/stores/logger';
|
||||||
|
|
||||||
import collapseStyles from '../../../../common/components/collapse-bar/CollapseBar.module.scss';
|
|
||||||
import styles from '../../Modal.module.scss';
|
import styles from '../../Modal.module.scss';
|
||||||
|
|
||||||
interface OscSubscriptionRowProps {
|
interface OscSubscriptionRowProps {
|
||||||
@@ -51,7 +50,7 @@ export default function OscSubscriptionRow(props: OscSubscriptionRowProps) {
|
|||||||
<span className={`${styles.sectionTitle} ${styles.main}`}>{sectionTitle}</span>
|
<span className={`${styles.sectionTitle} ${styles.main}`}>{sectionTitle}</span>
|
||||||
{visible && <span className={styles.sectionSubtitle}>{subtitle}</span>}
|
{visible && <span className={styles.sectionSubtitle}>{subtitle}</span>}
|
||||||
</div>
|
</div>
|
||||||
<FiChevronUp className={visible ? collapseStyles.moreCollapsed : collapseStyles.moreExpanded} />
|
<FiChevronUp />
|
||||||
</div>
|
</div>
|
||||||
{visible && (
|
{visible && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
.rundownWrapper {
|
.rundownWrapper {
|
||||||
height: calc(100% - 1.5rem);
|
height: calc(100% - 1.5rem);
|
||||||
overflow: hidden;
|
width: 100%;
|
||||||
padding-top: 0.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.eventContainer {
|
.eventContainer {
|
||||||
|
|||||||
@@ -248,7 +248,6 @@ export default function Rundown(props: RundownProps) {
|
|||||||
previousEventId={previousEventId}
|
previousEventId={previousEventId}
|
||||||
playback={isSelected ? featureData.playback : undefined}
|
playback={isSelected ? featureData.playback : undefined}
|
||||||
isRolling={featureData.playback === Playback.Roll}
|
isRolling={featureData.playback === Playback.Roll}
|
||||||
disableEdit={appMode === AppMode.Run}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -37,23 +37,11 @@ interface RundownEntryProps {
|
|||||||
previousEventId?: string;
|
previousEventId?: string;
|
||||||
playback?: Playback; // we only care about this if this event is playing
|
playback?: Playback; // we only care about this if this event is playing
|
||||||
isRolling: boolean; // we need to know even if not related to this event
|
isRolling: boolean; // we need to know even if not related to this event
|
||||||
disableEdit: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RundownEntry(props: RundownEntryProps) {
|
export default function RundownEntry(props: RundownEntryProps) {
|
||||||
const {
|
const { isPast, data, selected, hasCursor, next, previousEnd, previousEventId, playback, isRolling, eventIndex } =
|
||||||
isPast,
|
props;
|
||||||
data,
|
|
||||||
selected,
|
|
||||||
hasCursor,
|
|
||||||
next,
|
|
||||||
previousEnd,
|
|
||||||
previousEventId,
|
|
||||||
playback,
|
|
||||||
isRolling,
|
|
||||||
disableEdit,
|
|
||||||
eventIndex,
|
|
||||||
} = props;
|
|
||||||
const { emitError } = useEmitLog();
|
const { emitError } = useEmitLog();
|
||||||
const { addEvent, updateEvent, batchUpdateEvents, deleteEvent, swapEvents } = useEventAction();
|
const { addEvent, updateEvent, batchUpdateEvents, deleteEvent, swapEvents } = useEventAction();
|
||||||
const { cursor } = useAppMode();
|
const { cursor } = useAppMode();
|
||||||
@@ -173,7 +161,6 @@ export default function RundownEntry(props: RundownEntryProps) {
|
|||||||
playback={playback}
|
playback={playback}
|
||||||
isRolling={isRolling}
|
isRolling={isRolling}
|
||||||
actionHandler={actionHandler}
|
actionHandler={actionHandler}
|
||||||
disableEdit={disableEdit}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (data.type === SupportedEvent.Block) {
|
} else if (data.type === SupportedEvent.Block) {
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
@use '../editors//EditorMixin' as editor;
|
||||||
|
|
||||||
|
$rundown-width: 44.5rem;
|
||||||
|
$editor-width: 25rem;
|
||||||
|
|
||||||
|
.rundownExport {
|
||||||
|
grid-area: rundown;
|
||||||
|
max-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rundown {
|
||||||
|
display: flex;
|
||||||
|
max-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.corner {
|
||||||
|
@include editor.corner;
|
||||||
|
display: inline;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
@include editor.panel;
|
||||||
|
height: inherit;
|
||||||
|
box-shadow: $box-shadow-right;
|
||||||
|
min-width: $rundown-width;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side {
|
||||||
|
margin: 2rem 0;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: $gray-1325;
|
||||||
|
border-radius: 0 8px 8px 0;
|
||||||
|
min-width: $editor-width;
|
||||||
|
flex: 1;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
@@ -7,21 +7,25 @@ import { handleLinks } from '../../common/utils/linkUtils';
|
|||||||
import EventEditor from './event-editor/EventEditor';
|
import EventEditor from './event-editor/EventEditor';
|
||||||
import RundownWrapper from './RundownWrapper';
|
import RundownWrapper from './RundownWrapper';
|
||||||
|
|
||||||
import style from './RundownWrapper.module.scss';
|
import style from './RundownExport.module.scss';
|
||||||
|
|
||||||
const RundownExport = () => {
|
const RundownExport = () => {
|
||||||
const isExtracted = window.location.pathname.includes('/rundown');
|
const isExtracted = window.location.pathname.includes('/rundown');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.rundownExport} data-testid='panel-rundown'>
|
<div className={style.rundownExport} data-testid='panel-rundown'>
|
||||||
{!isExtracted && <IoArrowUp className={style.corner} onClick={(event) => handleLinks(event, 'rundown')} />}
|
|
||||||
<div className={style.rundown}>
|
<div className={style.rundown}>
|
||||||
<ErrorBoundary>
|
<div className={style.list}>
|
||||||
<RundownWrapper />
|
<ErrorBoundary>
|
||||||
</ErrorBoundary>
|
{!isExtracted && <IoArrowUp className={style.corner} onClick={(event) => handleLinks(event, 'rundown')} />}
|
||||||
<ErrorBoundary>
|
<RundownWrapper />
|
||||||
<EventEditor />
|
</ErrorBoundary>
|
||||||
</ErrorBoundary>
|
</div>
|
||||||
|
<div className={style.side}>
|
||||||
|
<ErrorBoundary>
|
||||||
|
<EventEditor />
|
||||||
|
</ErrorBoundary>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
@use '../editors//EditorMixin' as editor;
|
|
||||||
|
|
||||||
$rundown-width: 44.5rem;
|
|
||||||
$editor-width: 25rem;
|
|
||||||
|
|
||||||
.rundownExport {
|
|
||||||
grid-area: rundown;
|
|
||||||
min-width: calc($rundown-width + $editor-width);
|
|
||||||
max-height: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rundown {
|
|
||||||
@include editor.panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
.corner {
|
|
||||||
@include editor.corner;
|
|
||||||
display: inline;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import Empty from '../../common/components/state/Empty';
|
import Empty from '../../common/components/state/Empty';
|
||||||
import useRundown from '../../common/hooks-query/useRundown';
|
import useRundown from '../../common/hooks-query/useRundown';
|
||||||
import RundownMenu from '../menu/RundownMenu';
|
|
||||||
|
|
||||||
import Rundown from './Rundown';
|
import Rundown from './Rundown';
|
||||||
|
|
||||||
@@ -10,11 +9,8 @@ export default function RundownWrapper() {
|
|||||||
const { data, status } = useRundown();
|
const { data, status } = useRundown();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={styles.rundownWrapper}>
|
||||||
<RundownMenu />
|
{status === 'success' && data ? <Rundown entries={data} /> : <Empty text='Connecting to server' />}
|
||||||
<div className={styles.rundownWrapper}>
|
|
||||||
{status === 'success' && data ? <Rundown entries={data} /> : <Empty text='Connecting to server' />}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ interface EventBlockProps {
|
|||||||
value: unknown;
|
value: unknown;
|
||||||
},
|
},
|
||||||
) => void;
|
) => void;
|
||||||
disableEdit: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function EventBlock(props: EventBlockProps) {
|
export default function EventBlock(props: EventBlockProps) {
|
||||||
@@ -93,7 +92,6 @@ export default function EventBlock(props: EventBlockProps) {
|
|||||||
playback,
|
playback,
|
||||||
isRolling,
|
isRolling,
|
||||||
actionHandler,
|
actionHandler,
|
||||||
disableEdit,
|
|
||||||
} = props;
|
} = props;
|
||||||
const { selectedEventId, setSelectedEventId, clearSelectedEventId } = useEventIdSwapping();
|
const { selectedEventId, setSelectedEventId, clearSelectedEventId } = useEventIdSwapping();
|
||||||
const { selectedEvents, setSelectedEvents } = useEventSelection();
|
const { selectedEvents, setSelectedEvents } = useEventSelection();
|
||||||
@@ -280,7 +278,6 @@ export default function EventBlock(props: EventBlockProps) {
|
|||||||
playback={playback}
|
playback={playback}
|
||||||
isRolling={isRolling}
|
isRolling={isRolling}
|
||||||
actionHandler={actionHandler}
|
actionHandler={actionHandler}
|
||||||
disableEdit={disableEdit}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { memo, MouseEvent, useCallback, useEffect, useState } from 'react';
|
import { memo, useEffect, useState } from 'react';
|
||||||
import { Tooltip } from '@chakra-ui/react';
|
import { Tooltip } from '@chakra-ui/react';
|
||||||
import { BiArrowToBottom } from '@react-icons/all-files/bi/BiArrowToBottom';
|
import { BiArrowToBottom } from '@react-icons/all-files/bi/BiArrowToBottom';
|
||||||
import { IoArrowDown } from '@react-icons/all-files/io5/IoArrowDown';
|
import { IoArrowDown } from '@react-icons/all-files/io5/IoArrowDown';
|
||||||
import { IoArrowUp } from '@react-icons/all-files/io5/IoArrowUp';
|
import { IoArrowUp } from '@react-icons/all-files/io5/IoArrowUp';
|
||||||
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 { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
||||||
import { IoPlayForward } from '@react-icons/all-files/io5/IoPlayForward';
|
import { IoPlayForward } from '@react-icons/all-files/io5/IoPlayForward';
|
||||||
@@ -12,11 +11,9 @@ import { IoStop } from '@react-icons/all-files/io5/IoStop';
|
|||||||
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 { 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 { useEventSelection } from '../useEventSelection';
|
|
||||||
|
|
||||||
import BlockActionMenu from './composite/BlockActionMenu';
|
import BlockActionMenu from './composite/BlockActionMenu';
|
||||||
import EventBlockPlayback from './composite/EventBlockPlayback';
|
import EventBlockPlayback from './composite/EventBlockPlayback';
|
||||||
@@ -25,10 +22,6 @@ import EventBlockTimers from './composite/EventBlockTimers';
|
|||||||
|
|
||||||
import style from './EventBlock.module.scss';
|
import style from './EventBlock.module.scss';
|
||||||
|
|
||||||
const blockBtnStyle = {
|
|
||||||
size: 'sm',
|
|
||||||
};
|
|
||||||
|
|
||||||
const tooltipProps = {
|
const tooltipProps = {
|
||||||
openDelay: tooltipDelayMid,
|
openDelay: tooltipDelayMid,
|
||||||
};
|
};
|
||||||
@@ -51,7 +44,6 @@ interface EventBlockInnerProps {
|
|||||||
playback?: Playback;
|
playback?: Playback;
|
||||||
isRolling: boolean;
|
isRolling: boolean;
|
||||||
actionHandler: (action: EventItemActions, payload?: any) => void;
|
actionHandler: (action: EventItemActions, payload?: any) => void;
|
||||||
disableEdit: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const EventBlockInner = (props: EventBlockInnerProps) => {
|
const EventBlockInner = (props: EventBlockInnerProps) => {
|
||||||
@@ -72,29 +64,14 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
|
|||||||
playback,
|
playback,
|
||||||
isRolling,
|
isRolling,
|
||||||
actionHandler,
|
actionHandler,
|
||||||
disableEdit,
|
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [renderInner, setRenderInner] = useState(false);
|
const [renderInner, setRenderInner] = useState(false);
|
||||||
const { clearSelectedEvents, selectedEvents } = useEventSelection();
|
|
||||||
|
|
||||||
const isOpen = selectedEvents.size === 1 && selectedEvents.has(eventId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRenderInner(true);
|
setRenderInner(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
//TODO: fix this
|
|
||||||
const toggleOpenEvent = useCallback(
|
|
||||||
(_event: MouseEvent) => {
|
|
||||||
// if (isOpen) {
|
|
||||||
// event.stopPropagation();
|
|
||||||
// clearSelectedEvents();
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
[clearSelectedEvents, isOpen],
|
|
||||||
);
|
|
||||||
|
|
||||||
const eventIsPlaying = playback === Playback.Play;
|
const eventIsPlaying = playback === Playback.Play;
|
||||||
const eventIsPaused = playback === Playback.Pause;
|
const eventIsPaused = playback === Playback.Pause;
|
||||||
|
|
||||||
@@ -149,19 +126,6 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={style.eventActions}>
|
<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} />
|
<BlockActionMenu showClone enableDelete={!selected} actionHandler={actionHandler} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
// TODO: unify with RundownWrapper.module.scss
|
|
||||||
$editor-width: 25rem;
|
|
||||||
|
|
||||||
.eventEditor {
|
.eventEditor {
|
||||||
min-width: $editor-width;
|
|
||||||
background-color: $gray-1350;
|
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@@ -28,19 +18,23 @@ $editor-width: 25rem;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
padding: 1rem;
|
border-top: 1px solid $white-10;
|
||||||
|
padding-top: 1rem;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeSettings {
|
.timeSettings {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.5rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.column {
|
.column {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.5rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputLabel {
|
.inputLabel {
|
||||||
@@ -74,11 +68,5 @@ $editor-width: 25rem;
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
column-gap: 1.5rem;
|
column-gap: 1.5rem;
|
||||||
row-gap: 0.5rem;
|
row-gap: 1rem;
|
||||||
}
|
|
||||||
|
|
||||||
.eventActions {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ export default function EventEditor() {
|
|||||||
|
|
||||||
if (event && isOntimeEvent(event)) {
|
if (event && isOntimeEvent(event)) {
|
||||||
setEvent(event);
|
setEvent(event);
|
||||||
|
} else {
|
||||||
|
setEvent(null);
|
||||||
}
|
}
|
||||||
}, [data, selectedEvents]);
|
}, [data, selectedEvents]);
|
||||||
|
|
||||||
@@ -61,7 +63,11 @@ export default function EventEditor() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!event) {
|
if (!event) {
|
||||||
return <span data-testid='editor-container'>Loading...</span>;
|
return (
|
||||||
|
<div className={style.eventEditor} data-testid='editor-container'>
|
||||||
|
Select an event to edit
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compositing user fields by hand
|
// Compositing user fields by hand
|
||||||
@@ -81,7 +87,6 @@ export default function EventEditor() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.eventEditor} data-testid='editor-container'>
|
<div className={style.eventEditor} data-testid='editor-container'>
|
||||||
<div>HEADER ACTIONS?</div>
|
|
||||||
<div className={style.content}>
|
<div className={style.content}>
|
||||||
<EventEditorTimes
|
<EventEditorTimes
|
||||||
key={`${event.id}-times`}
|
key={`${event.id}-times`}
|
||||||
@@ -109,7 +114,7 @@ export default function EventEditor() {
|
|||||||
/>
|
/>
|
||||||
<EventEditorUser key={`${event.id}-user`} userFields={userFields} handleSubmit={handleSubmit} />
|
<EventEditorUser key={`${event.id}-user`} userFields={userFields} handleSubmit={handleSubmit} />
|
||||||
</div>
|
</div>
|
||||||
<div className={style.eventActions}>
|
<div className={style.footer}>
|
||||||
<CopyTag label='OSC trigger by id'>{`/ontime/load/id "${event.id}"`}</CopyTag>
|
<CopyTag label='OSC trigger by id'>{`/ontime/load/id "${event.id}"`}</CopyTag>
|
||||||
<CopyTag label='OSC trigger by cue'>{`/ontime/load/cue "${event.cue}"`}</CopyTag>
|
<CopyTag label='OSC trigger by cue'>{`/ontime/load/cue "${event.cue}"`}</CopyTag>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ option {
|
|||||||
/* width */
|
/* width */
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Track */
|
/* Track */
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ $gray-1100: #2d2d2d;
|
|||||||
$gray-1200: #262626;
|
$gray-1200: #262626;
|
||||||
$gray-1250: #202020;
|
$gray-1250: #202020;
|
||||||
$gray-1300: #1a1a1a;
|
$gray-1300: #1a1a1a;
|
||||||
|
$gray-1325: #151515;
|
||||||
$gray-1350: #101010;
|
$gray-1350: #101010;
|
||||||
$pure-white: #fff;
|
$pure-white: #fff;
|
||||||
$ui-white: $gray-50;
|
$ui-white: $gray-50;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ $bg-container-onlight: $gray-100;
|
|||||||
|
|
||||||
$box-shadow-l1: rgba(0, 0, 0, 0.15) 0 3px 3px 0;
|
$box-shadow-l1: rgba(0, 0, 0, 0.15) 0 3px 3px 0;
|
||||||
$box-shadow-l2: rgba(0, 0, 0, 0.15) 0 3px 3px 0;
|
$box-shadow-l2: rgba(0, 0, 0, 0.15) 0 3px 3px 0;
|
||||||
|
$box-shadow-right: rgba(0, 0, 0, 0.15) 3px 0 3px 0;
|
||||||
$large-bottom-drawer-shadow: rgba(0, 0, 0, 0.35) 0 3px 6px 6px;
|
$large-bottom-drawer-shadow: rgba(0, 0, 0, 0.35) 0 3px 6px 6px;
|
||||||
$large-top-drawer-shadow: rgba(0, 0, 0, 0.35) 0 1px 6px 3px;
|
$large-top-drawer-shadow: rgba(0, 0, 0, 0.35) 0 1px 6px 3px;
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export class TimerService {
|
|||||||
* @param {number} amount
|
* @param {number} amount
|
||||||
*/
|
*/
|
||||||
addTime(amount: number) {
|
addTime(amount: number) {
|
||||||
if (state.eventNow === null) {
|
if (state.timer.current === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
stateMutations.timer.addTime(amount);
|
stateMutations.timer.addTime(amount);
|
||||||
|
|||||||
@@ -340,7 +340,30 @@ describe('getCurrent()', () => {
|
|||||||
const current = getCurrent(state);
|
const current = getCurrent(state);
|
||||||
expect(current).toBe(35);
|
expect(current).toBe(35);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('on timers of type time-to-end', () => {
|
describe('on timers of type time-to-end', () => {
|
||||||
|
it('current time is the time to end even if it hasnt started, this is weird, but by design', () => {
|
||||||
|
const state = {
|
||||||
|
eventNow: {
|
||||||
|
timeEnd: 100,
|
||||||
|
timerType: TimerType.TimeToEnd,
|
||||||
|
},
|
||||||
|
clock: 30,
|
||||||
|
timer: {
|
||||||
|
addedTime: 0,
|
||||||
|
duration: 100,
|
||||||
|
startedAt: null,
|
||||||
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
|
},
|
||||||
|
} as TState;
|
||||||
|
|
||||||
|
const current = getCurrent(state);
|
||||||
|
expect(current).toBe(70);
|
||||||
|
});
|
||||||
|
|
||||||
it('current time is the time to end', () => {
|
it('current time is the time to end', () => {
|
||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import { LogOrigin, OntimeBaseEvent, OntimeBlock, OntimeDelay, OntimeEvent, SupportedEvent, isOntimeEvent } from 'ontime-types';
|
import {
|
||||||
|
LogOrigin,
|
||||||
|
OntimeBaseEvent,
|
||||||
|
OntimeBlock,
|
||||||
|
OntimeDelay,
|
||||||
|
OntimeEvent,
|
||||||
|
SupportedEvent,
|
||||||
|
isOntimeEvent,
|
||||||
|
} from 'ontime-types';
|
||||||
import { generateId, getCueCandidate } from 'ontime-utils';
|
import { generateId, getCueCandidate } from 'ontime-utils';
|
||||||
import { DataProvider } from '../../classes/data-provider/DataProvider.js';
|
import { DataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||||
import { block as blockDef, delay as delayDef } from '../../models/eventsDefinition.js';
|
import { block as blockDef, delay as delayDef } from '../../models/eventsDefinition.js';
|
||||||
|
|||||||
@@ -315,10 +315,6 @@ export const stateMutations = {
|
|||||||
addTime(amount: number) {
|
addTime(amount: number) {
|
||||||
mutate((state) => {
|
mutate((state) => {
|
||||||
// TODO: what kind of validation go here or in the consumer?
|
// TODO: what kind of validation go here or in the consumer?
|
||||||
if (state.timer.startedAt === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.timer.addedTime += amount;
|
state.timer.addedTime += amount;
|
||||||
state.timer.expectedFinish += amount;
|
state.timer.expectedFinish += amount;
|
||||||
state.timer.current += amount;
|
state.timer.current += amount;
|
||||||
@@ -407,6 +403,7 @@ export const stateMutations = {
|
|||||||
// TODO: can we simplify the didUpdate and shouldNotify
|
// TODO: can we simplify the didUpdate and shouldNotify
|
||||||
_didUpdate = true;
|
_didUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
didUpdate: _didUpdate,
|
didUpdate: _didUpdate,
|
||||||
doRoll: _doRoll,
|
doRoll: _doRoll,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const fileToUpload = 'e2e/tests/fixtures/test-db.json';
|
|||||||
|
|
||||||
test('test project file upload', async ({ page }) => {
|
test('test project file upload', async ({ page }) => {
|
||||||
await page.goto('http://localhost:4001/editor');
|
await page.goto('http://localhost:4001/editor');
|
||||||
await page.getByRole('button', { name: 'Event...' }).click();
|
await page.getByRole('button', { name: 'Rundown menu' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Import project file' }).click();
|
await page.getByRole('button', { name: 'Import project file' }).click();
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ test('delay blocks add time to events', async ({ page }) => {
|
|||||||
await page.goto('http://localhost:4001/editor');
|
await page.goto('http://localhost:4001/editor');
|
||||||
|
|
||||||
// delete all events and add a new one
|
// delete all events and add a new one
|
||||||
await page.getByRole('button', { name: 'Event...' }).click();
|
await page.getByRole('button', { name: 'Rundown menu' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
||||||
await page.getByRole('button', { name: 'Event...' }).click();
|
await page.getByRole('button', { name: 'Rundown menu' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'Add event at start' }).click();
|
await page.getByRole('menuitem', { name: 'Add event at start' }).click();
|
||||||
|
|
||||||
// add data to new event
|
// add data to new event
|
||||||
@@ -18,7 +18,7 @@ test('delay blocks add time to events', async ({ page }) => {
|
|||||||
await page.getByTestId('rundown').getByPlaceholder('End').press('Enter');
|
await page.getByTestId('rundown').getByPlaceholder('End').press('Enter');
|
||||||
|
|
||||||
// add delay block
|
// add delay block
|
||||||
await page.getByRole('button', { name: 'Event...' }).click();
|
await page.getByRole('button', { name: 'Rundown menu' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'Add delay at start' }).click();
|
await page.getByRole('menuitem', { name: 'Add delay at start' }).click();
|
||||||
|
|
||||||
// fill positive delay
|
// fill positive delay
|
||||||
@@ -37,7 +37,7 @@ test('delay blocks add time to events', async ({ page }) => {
|
|||||||
|
|
||||||
// add new delay
|
// add new delay
|
||||||
await page.getByTestId('rundown').getByPlaceholder('Start').click();
|
await page.getByTestId('rundown').getByPlaceholder('Start').click();
|
||||||
await page.getByRole('button', { name: 'Event...' }).click();
|
await page.getByRole('button', { name: 'Rundown menu' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'Add delay at start' }).click();
|
await page.getByRole('menuitem', { name: 'Add delay at start' }).click();
|
||||||
await page.getByTestId('delay-input').click();
|
await page.getByTestId('delay-input').click();
|
||||||
await page.getByTestId('delay-input').fill('10m');
|
await page.getByTestId('delay-input').fill('10m');
|
||||||
@@ -54,7 +54,7 @@ test('delays are show correctly', async ({ page }) => {
|
|||||||
await page.goto('http://localhost:4001/editor');
|
await page.goto('http://localhost:4001/editor');
|
||||||
|
|
||||||
// add a test event
|
// add a test event
|
||||||
await page.getByRole('button', { name: 'Event...' }).click();
|
await page.getByRole('button', { name: 'Rundown menu' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
||||||
await page.getByRole('button', { name: 'Create Event' }).click();
|
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||||
await page.getByTestId('time-input-timeStart').click();
|
await page.getByTestId('time-input-timeStart').click();
|
||||||
@@ -72,7 +72,7 @@ test('delays are show correctly', async ({ page }) => {
|
|||||||
await page.getByRole('menuitem', { name: 'Toggle public' }).click();
|
await page.getByRole('menuitem', { name: 'Toggle public' }).click();
|
||||||
|
|
||||||
// add a delay
|
// add a delay
|
||||||
await page.getByRole('button', { name: 'Event...' }).click();
|
await page.getByRole('button', { name: 'Rundown menu' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'Add delay at start' }).click();
|
await page.getByRole('menuitem', { name: 'Add delay at start' }).click();
|
||||||
await page.getByTestId('delay-input').click();
|
await page.getByTestId('delay-input').click();
|
||||||
await page.getByTestId('delay-input').fill('1');
|
await page.getByTestId('delay-input').fill('1');
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ test('CRUD operations on the rundown', async ({ page }) => {
|
|||||||
|
|
||||||
// clear rundown
|
// clear rundown
|
||||||
await page.getByRole('button', { name: 'Run mode' }).click();
|
await page.getByRole('button', { name: 'Run mode' }).click();
|
||||||
await page.getByRole('button', { name: 'Event...' }).click();
|
await page.getByRole('button', { name: 'Rundown menu' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
||||||
|
|
||||||
// create event from the rundown empty button
|
// create event from the rundown empty button
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ test('smoke test operator', async ({ page }) => {
|
|||||||
// make some boilerplate
|
// make some boilerplate
|
||||||
await page.goto('http://localhost:4001/editor');
|
await page.goto('http://localhost:4001/editor');
|
||||||
await page.getByRole('button', { name: 'Run mode' }).click();
|
await page.getByRole('button', { name: 'Run mode' }).click();
|
||||||
await page.getByRole('button', { name: 'Event...' }).click();
|
await page.getByRole('button', { name: 'Rundown menu' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
await page.getByRole('menuitem', { name: 'Delete all events' }).click();
|
||||||
await page.getByRole('button', { name: 'Create Event' }).click();
|
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ test('smoke test operator', async ({ page }) => {
|
|||||||
await page.getByTestId('entry-3').getByTestId('time-input-durationOverride').fill('1m');
|
await page.getByTestId('entry-3').getByTestId('time-input-durationOverride').fill('1m');
|
||||||
await page.getByTestId('entry-3').getByTestId('time-input-durationOverride').press('Enter');
|
await page.getByTestId('entry-3').getByTestId('time-input-durationOverride').press('Enter');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Event...' }).click();
|
await page.getByRole('button', { name: 'Rundown menu' }).click();
|
||||||
await page.getByRole('menuitem', { name: 'Add block at start' }).click();
|
await page.getByRole('menuitem', { name: 'Add block at start' }).click();
|
||||||
await page.getByTestId('quick-add-block').click();
|
await page.getByTestId('quick-add-block').click();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user