refactor: expose editor panels in small device

This commit is contained in:
Carlos Valente
2025-06-23 06:59:34 +02:00
committed by Carlos Valente
parent b991627cb7
commit 984dcb0181
52 changed files with 336 additions and 131 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ import ViewLoader from './views/ViewLoader';
import { ONTIME_VERSION } from './ONTIME_VERSION';
import { sentryDsn, sentryRecommendedIgnore } from './sentry.config';
const Editor = React.lazy(() => import('./features/editors/ProtectedEditor'));
const Editor = React.lazy(() => import('./views/editor/ProtectedEditor'));
const Cuesheet = React.lazy(() => import('./views/cuesheet/ProtectedCuesheet'));
const Operator = React.lazy(() => import('./features/operator/OperatorExport'));
@@ -53,14 +53,46 @@
}
}
.destructive {
background: $red-700;
color: $ui-white;
&:hover:not(:disabled):not(:active) {
background: $red-600;
color: $ui-white;
}
&:active:not(:disabled) {
background: $red-800;
border-color: $red-900;
}
}
.subtle-destructive {
background: $gray-1050;
color: $red-400;
&:hover:not(:disabled):not(:active) {
background: $gray-1000;
color: $red-500;
}
&:active:not(:disabled) {
background: $gray-1100;
border-color: $gray-1250;
}
}
.medium {
height: 2rem;
}
.large {
height: 2.5rem;
font-weight: 600;
}
.xlarge {
height: 3rem;
font-weight: 600;
}
@@ -5,7 +5,7 @@ import { cx } from '../../utils/styleUtils';
import style from './Button.module.scss';
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'subtle' | 'primary';
variant?: 'subtle' | 'primary' | 'destructive' | 'subtle-destructive';
size?: 'medium' | 'large' | 'xlarge';
}
@@ -16,8 +16,22 @@
border: 1px solid $gray-1200;
}
.backdrop {
position: fixed;
inset: 0;
z-index: $zindex-backdrop;
background-color: $backdrop-color;
transition: opacity 300ms cubic-bezier(0.45, 1.005, 0, 1.005);
&[data-starting-style],
&[data-ending-style] {
opacity: 0;
}
}
.title {
font-size: 1.25rem;
font-size: 1rem;
font-weight: 600;
padding-block: 1rem;
display: flex;
@@ -10,12 +10,21 @@ interface DialogProps {
isOpen: boolean;
title: string;
showCloseButton?: boolean;
showBackdrop?: boolean;
bodyElements: ReactNode;
footerElements: ReactNode;
onClose: () => void;
}
export default function Dialog({ isOpen, title, showCloseButton, bodyElements, footerElements, onClose }: DialogProps) {
export default function Dialog({
isOpen,
title,
showCloseButton,
showBackdrop,
bodyElements,
footerElements,
onClose,
}: DialogProps) {
return (
<BaseDialog.Root
open={isOpen}
@@ -24,6 +33,7 @@ export default function Dialog({ isOpen, title, showCloseButton, bodyElements, f
}}
>
<BaseDialog.Portal>
{showBackdrop && <BaseDialog.Backdrop className={style.backdrop} />}
<BaseDialog.Popup className={style.dialog}>
<div className={style.title}>
{title}
@@ -40,3 +40,9 @@
margin-bottom: $element-inner-spacing;
max-width: max-content; // prevent label from taking entire row
}
.separator {
width: 1px;
height: 0.75em;
background-color: $border-color-ondark;
}
@@ -2,7 +2,7 @@ import type { HTMLAttributes, LabelHTMLAttributes } from 'react';
import { IconBaseProps } from 'react-icons';
import { IoArrowUp } from 'react-icons/io5';
import { cx } from '../../../common/utils/styleUtils';
import { cx } from '../../utils/styleUtils';
import style from './EditorUtils.module.scss';
@@ -27,3 +27,7 @@ export function Label({ children, className, ...elementProps }: LabelHTMLAttribu
</label>
);
}
export function Separator({ className, ...elementProps }: HTMLAttributes<HTMLDivElement>) {
return <div className={cx([style.separator, className])} {...elementProps} />;
}
@@ -3,7 +3,6 @@ import { create } from 'zustand';
export enum AppMode {
Run = 'run',
Edit = 'edit',
Freeze = 'freeze',
}
const appModeKey = 'ontime-app-mode';
@@ -1,7 +1,11 @@
import { IoEye, IoEyeOffOutline } from 'react-icons/io5';
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
import { setMessage, useExternalMessageInput as useSecondaryMessageInput, useTimerMessageInput } from '../../../common/hooks/useSocket';
import {
setMessage,
useExternalMessageInput as useSecondaryMessageInput,
useTimerMessageInput,
} from '../../../common/hooks/useSocket';
import { tooltipDelayMid } from '../../../ontimeConfig';
import InputRow from './InputRow';
@@ -1,15 +1,15 @@
import { memo } from 'react';
import { Corner } from '../../../common/components/editor-utils/EditorUtils';
import ErrorBoundary from '../../../common/components/error-boundary/ErrorBoundary';
import ViewNavigationMenu from '../../../common/components/navigation-menu/ViewNavigationMenu';
import ProtectRoute from '../../../common/components/protect-route/ProtectRoute';
import { handleLinks } from '../../../common/utils/linkUtils';
import { cx } from '../../../common/utils/styleUtils';
import { Corner } from '../../editors/editor-utils/EditorUtils';
import MessageControl from './MessageControl';
import style from '../../editors/Editor.module.scss';
import style from '../../../views/editor/Editor.module.scss';
export default memo(MessageControlExport);
function MessageControlExport() {
@@ -2,12 +2,12 @@ import { IoArrowDown, IoArrowUp, IoBan, IoFlag, IoTime } from 'react-icons/io5';
import { Tooltip } from '@chakra-ui/react';
import { TimerPhase, TimerType } from 'ontime-types';
import { Corner } from '../../../common/components/editor-utils/EditorUtils';
import { useMessagePreview } from '../../../common/hooks/useSocket';
import useViewSettings from '../../../common/hooks-query/useViewSettings';
import { handleLinks } from '../../../common/utils/linkUtils';
import { cx, timerPlaceholder } from '../../../common/utils/styleUtils';
import { tooltipDelayMid } from '../../../ontimeConfig';
import { Corner } from '../../editors/editor-utils/EditorUtils';
import style from './MessageControl.module.scss';
@@ -1,14 +1,14 @@
import { memo } from 'react';
import { Corner } from '../../../common/components/editor-utils/EditorUtils';
import ErrorBoundary from '../../../common/components/error-boundary/ErrorBoundary';
import ViewNavigationMenu from '../../../common/components/navigation-menu/ViewNavigationMenu';
import ProtectRoute from '../../../common/components/protect-route/ProtectRoute';
import { handleLinks } from '../../../common/utils/linkUtils';
import { Corner } from '../../editors/editor-utils/EditorUtils';
import PlaybackControl from './PlaybackControl';
import style from '../../editors/Editor.module.scss';
import style from '../../../views/editor/Editor.module.scss';
export default memo(TimerControlExport);
function TimerControlExport() {
@@ -7,5 +7,5 @@
display: flex;
align-items: center;
justify-content: center;
gap: 2rem;
gap: 1rem;
}
@@ -16,6 +16,11 @@
display: flex;
flex-direction: column;
padding-inline: 1rem;
:is([data-target='small-device']) & {
padding-inline: 0;
overflow-x: auto;
}
}
.empty {
@@ -1,7 +1,8 @@
import { IoAdd } from 'react-icons/io5';
import { Button } from '@chakra-ui/react';
import { SupportedEntry } from 'ontime-types';
import Button from '../../common/components/buttons/Button';
import * as Editor from '../../common/components/editor-utils/EditorUtils';
import Empty from '../../common/components/state/Empty';
import style from './Empty.module.scss';
@@ -17,12 +18,15 @@ export default function RundownEmpty(props: RundownEmptyProps) {
<div className={style.empty}>
<Empty style={{ marginTop: '5vh', marginBottom: '3rem' }} />
<div className={style.inline}>
<Button onClick={() => handleAddNew(SupportedEntry.Event)} variant='ontime-filled' leftIcon={<IoAdd />}>
<Button onClick={() => handleAddNew(SupportedEntry.Event)} variant='primary' size='large'>
<IoAdd />
Create Event
</Button>
<Button onClick={() => handleAddNew(SupportedEntry.Block)} variant='ontime-filled' leftIcon={<IoAdd />}>
Create Block
<Editor.Separator />
<Button onClick={() => handleAddNew(SupportedEntry.Block)} variant='primary' size='large'>
<IoAdd /> Create Block
</Button>
</div>
</div>
@@ -1,4 +1,4 @@
@use '../editors/EditorMixin' as editor;
@use '../../views/editor/EditorMixin' as editor;
.rundownExport {
height: 100%;
@@ -1,6 +1,7 @@
import { memo } from 'react';
import { ContextMenu } from '../../common/components/context-menu/ContextMenu';
import { Corner } from '../../common/components/editor-utils/EditorUtils';
import ErrorBoundary from '../../common/components/error-boundary/ErrorBoundary';
import ViewNavigationMenu from '../../common/components/navigation-menu/ViewNavigationMenu';
import ProtectRoute from '../../common/components/protect-route/ProtectRoute';
@@ -8,7 +9,6 @@ import { useIsSmallDevice } from '../../common/hooks/useIsSmallDevice';
import { useAppMode } from '../../common/stores/appModeStore';
import { handleLinks } from '../../common/utils/linkUtils';
import { cx } from '../../common/utils/styleUtils';
import { Corner } from '../editors/editor-utils/EditorUtils';
import RundownEventEditor from './event-editor/RundownEventEditor';
import FinderPlacement from './placements/FinderPlacement';
@@ -26,13 +26,17 @@ function RundownExport() {
if (isSmallDevice && isExtracted) {
return (
<ProtectRoute permission='editor'>
<div className={cx([style.rundownExport, style.extracted])} data-testid='panel-rundown'>
<div
className={cx([style.rundownExport, style.extracted])}
data-target='small-device'
data-testid='panel-rundown'
>
<FinderPlacement />
<ViewNavigationMenu supressSettings />
<div className={style.content}>
<ErrorBoundary>
<ContextMenu>
<RundownWrapper />
<RundownWrapper isSmallDevice />
</ContextMenu>
</ErrorBoundary>
</div>
@@ -2,16 +2,21 @@ import Empty from '../../common/components/state/Empty';
import useRundown from '../../common/hooks-query/useRundown';
import RundownHeader from './rundown-header/RundownHeader';
import RundownHeaderMobile from './rundown-header/RundownHeaderMobile';
import Rundown from './Rundown';
import styles from './Rundown.module.scss';
export default function RundownWrapper() {
interface RundownWrapperProps {
isSmallDevice?: boolean;
}
export default function RundownWrapper({ isSmallDevice }: RundownWrapperProps) {
const { data, status } = useRundown();
return (
<div className={styles.rundownWrapper}>
<RundownHeader />
{isSmallDevice ? <RundownHeaderMobile /> : <RundownHeader />}
{status === 'success' && data ? <Rundown data={data} /> : <Empty text='Connecting to server' />}
</div>
);
@@ -1,10 +1,10 @@
import { useCallback } from 'react';
import { OntimeEvent } from 'ontime-types';
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
import AppLink from '../../../common/components/link/app-link/AppLink';
import { useEntryActions } from '../../../common/hooks/useEntryAction';
import useCustomFields from '../../../common/hooks-query/useCustomFields';
import * as Editor from '../../editors/editor-utils/EditorUtils';
import EventCustom from './composite/EventEditorCustom';
import EventEditorTimes from './composite/EventEditorTimes';
@@ -1,8 +1,8 @@
import { memo, PropsWithChildren } from 'react';
import { Kbd } from '@chakra-ui/react';
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
import { deviceAlt, deviceMod } from '../../../common/utils/deviceUtils';
import * as Editor from '../../editors/editor-utils/EditorUtils';
import style from './EventEditorEmpty.module.scss';
@@ -4,10 +4,10 @@ import { Select, Switch, Tooltip } from '@chakra-ui/react';
import { EndAction, TimerType, TimeStrategy } from 'ontime-types';
import { millisToString, parseUserTime } from 'ontime-utils';
import * as Editor from '../../../../common/components/editor-utils/EditorUtils';
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
import { useEntryActions } from '../../../../common/hooks/useEntryAction';
import { millisToDelayString } from '../../../../common/utils/dateConfig';
import * as Editor from '../../../editors/editor-utils/EditorUtils';
import TimeInputFlow from '../../time-input-flow/TimeInputFlow';
import style from '../EventEditor.module.scss';
@@ -2,8 +2,8 @@ import { memo } from 'react';
import { Input } from '@chakra-ui/react';
import { sanitiseCue } from 'ontime-utils';
import * as Editor from '../../../../common/components/editor-utils/EditorUtils';
import SwatchSelect from '../../../../common/components/input/colour-input/SwatchSelect';
import * as Editor from '../../../editors/editor-utils/EditorUtils';
import { type EditorUpdateFields } from '../EventEditor';
import EventTextArea from './EventTextArea';
@@ -1,8 +1,8 @@
import { type CSSProperties, useCallback, useRef } from 'react';
import * as Editor from '../../../../common/components/editor-utils/EditorUtils';
import { AutoTextArea } from '../../../../common/components/input/auto-text-area/AutoTextArea';
import useReactiveTextInput from '../../../../common/components/input/text-input/useReactiveTextInput';
import * as Editor from '../../../editors/editor-utils/EditorUtils';
import { EditorUpdateFields } from '../EventEditor';
interface CountedTextAreaProps {
@@ -1,8 +1,8 @@
import { useCallback, useRef } from 'react';
import { Input, InputProps } from '@chakra-ui/react';
import * as Editor from '../../../../common/components/editor-utils/EditorUtils';
import useReactiveTextInput from '../../../../common/components/input/text-input/useReactiveTextInput';
import * as Editor from '../../../editors/editor-utils/EditorUtils';
import { EditorUpdateFields } from '../EventEditor';
interface EventTextInputProps extends InputProps {
@@ -2,7 +2,7 @@ import { memo } from 'react';
import { useDisclosure } from '@chakra-ui/react';
import { useHotkeys } from '@mantine/hooks';
import Finder from '../../editors/finder/Finder';
import Finder from '../../../views/editor/finder/Finder';
export default memo(FinderPlacement);
@@ -1,7 +1,59 @@
.header {
padding-inline: 1rem 2rem;
padding-inline: calc(2.5rem - 6px) calc(1rem + 2px);
display: flex;
align-items: center;
justify-content: space-between;
gap: 1px;
:is([data-target='small-device']) & {
padding-inline: 0;
overflow-x: auto;
}
}
.group {
display: flex;
gap: 0.25rem;
}
.button {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
height: 2rem;
padding-inline: 1em;
border: 1px solid transparent;
border-radius: $component-border-radius-md;
color: $gray-400;
font-size: calc(1rem - 2px);
font-weight: 600;
&:focus-visible {
background: transparent;
}
&:hover:not(:disabled):not(:active) {
background: $gray-1000;
}
&:active {
background: $gray-1100;
}
&[data-pressed] {
background: $blue-700;
color: $ui-white;
&:hover:not(:disabled):not(:active) {
background: $blue-600;
}
}
}
.apart {
margin-left: auto;
}
.separator {
margin-inline: 1rem;
}
@@ -1,6 +1,10 @@
import { Button, ButtonGroup } from '@chakra-ui/react';
import { memo } from 'react';
import { Toggle } from '@base-ui-components/react/toggle';
import { ToggleGroup } from '@base-ui-components/react/toggle-group';
import { Toolbar } from '@base-ui-components/react/toolbar';
import { OffsetMode } from 'ontime-types';
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
import { setOffsetMode, useOffsetMode } from '../../../common/hooks/useSocket';
import { AppMode, useAppMode } from '../../../common/stores/appModeStore';
@@ -8,41 +12,50 @@ import RundownMenu from './RundownMenu';
import style from './RundownHeader.module.scss';
export default function RundownHeader() {
export default memo(RundownHeader);
function RundownHeader() {
const appMode = useAppMode((state) => state.mode);
const setAppMode = useAppMode((state) => state.setMode);
const setRunMode = () => setAppMode(AppMode.Run);
const setEditMode = () => setAppMode(AppMode.Edit);
const { offsetMode } = useOffsetMode();
const toggleAppMode = (mode: AppMode[]) => {
// we need to stop user from deselecting a mode
const newValue = mode.at(0);
if (!newValue) return;
setAppMode(newValue);
};
const toggleOffsetMode = (mode: OffsetMode[]) => {
// we need to stop user from deselecting a mode
const newValue = mode.at(0);
if (!newValue) return;
setOffsetMode(newValue);
};
return (
<div className={style.header}>
<ButtonGroup isAttached>
<Button size='sm' variant={appMode === AppMode.Run ? 'ontime-filled' : 'ontime-subtle'} onClick={setRunMode}>
<Toolbar.Root className={style.header}>
<ToggleGroup value={[appMode]} onValueChange={toggleAppMode} className={style.group}>
<Toolbar.Button render={<Toggle />} value={AppMode.Run} className={style.button}>
Run
</Button>
<Button size='sm' variant={appMode === AppMode.Edit ? 'ontime-filled' : 'ontime-subtle'} onClick={setEditMode}>
</Toolbar.Button>
<Toolbar.Button render={<Toggle />} value={AppMode.Edit} className={style.button}>
Edit
</Button>
</ButtonGroup>
<ButtonGroup isAttached>
<Button
size='sm'
variant={offsetMode === OffsetMode.Absolute ? 'ontime-filled' : 'ontime-subtle'}
onClick={() => setOffsetMode(OffsetMode.Absolute)}
>
</Toolbar.Button>
</ToggleGroup>
<Editor.Separator className={style.separator} />
<ToggleGroup value={[offsetMode]} onValueChange={toggleOffsetMode} className={style.group}>
<Toolbar.Button render={<Toggle />} value={OffsetMode.Absolute} className={style.button}>
Absolute
</Button>
<Button
size='sm'
variant={offsetMode === OffsetMode.Relative ? 'ontime-filled' : 'ontime-subtle'}
onClick={() => setOffsetMode(OffsetMode.Relative)}
>
</Toolbar.Button>
<Toolbar.Button render={<Toggle />} value={OffsetMode.Relative} className={style.button}>
Relative
</Button>
</ButtonGroup>
</Toolbar.Button>
</ToggleGroup>
<RundownMenu />
</div>
</Toolbar.Root>
);
}
@@ -0,0 +1,57 @@
import { memo } from 'react';
import { Toggle } from '@base-ui-components/react/toggle';
import { ToggleGroup } from '@base-ui-components/react/toggle-group';
import { Toolbar } from '@base-ui-components/react/toolbar';
import { OffsetMode } from 'ontime-types';
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
import { setOffsetMode, useOffsetMode } from '../../../common/hooks/useSocket';
import { AppMode, useAppMode } from '../../../common/stores/appModeStore';
import style from './RundownHeader.module.scss';
export default memo(RundownHeader);
function RundownHeader() {
const appMode = useAppMode((state) => state.mode);
const setAppMode = useAppMode((state) => state.setMode);
const { offsetMode } = useOffsetMode();
const toggleAppMode = (mode: AppMode[]) => {
// we need to stop user from deselecting a mode
const newValue = mode.at(0);
if (!newValue) return;
setAppMode(newValue);
};
const toggleOffsetMode = (mode: OffsetMode[]) => {
// we need to stop user from deselecting a mode
const newValue = mode.at(0);
if (!newValue) return;
setOffsetMode(newValue);
};
return (
<Toolbar.Root className={style.header}>
<ToggleGroup value={[appMode]} onValueChange={toggleAppMode} className={style.group}>
<Toolbar.Button render={<Toggle />} value={AppMode.Run} className={style.button}>
Run
</Toolbar.Button>
<Toolbar.Button render={<Toggle />} value={AppMode.Edit} className={style.button}>
Edit
</Toolbar.Button>
</ToggleGroup>
<Editor.Separator className={style.separator} />
<ToggleGroup value={[offsetMode]} onValueChange={toggleOffsetMode} className={style.group}>
<Toolbar.Button render={<Toggle />} value={OffsetMode.Absolute} className={style.button}>
Absolute
</Toolbar.Button>
<Toolbar.Button render={<Toggle />} value={OffsetMode.Relative} className={style.button}>
Relative
</Toolbar.Button>
</ToggleGroup>
</Toolbar.Root>
);
}
@@ -1,66 +1,62 @@
import { useCallback, useRef } from 'react';
import { memo, useCallback } from 'react';
import { IoTrash } from 'react-icons/io5';
import {
AlertDialog,
AlertDialogBody,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogOverlay,
Button,
useDisclosure,
} from '@chakra-ui/react';
import { useDisclosure } from '@mantine/hooks';
import Button from '../../../common/components/buttons/Button';
import Dialog from '../../../common/components/dialog/Dialog';
import { useEntryActions } from '../../../common/hooks/useEntryAction';
import { useAppMode } from '../../../common/stores/appModeStore';
import { AppMode, useAppMode } from '../../../common/stores/appModeStore';
import { useEventSelection } from '../useEventSelection';
export default function RundownMenu() {
import style from './RundownHeader.module.scss';
export default memo(RundownMenu);
function RundownMenu() {
const [isOpen, handlers] = useDisclosure();
const clearSelectedEvents = useEventSelection((state) => state.clearSelectedEvents);
const appMode = useAppMode((state) => state.mode);
const { deleteAllEntries } = useEntryActions();
const { isOpen, onOpen, onClose } = useDisclosure();
const cancelRef = useRef<HTMLButtonElement | null>(null);
const deleteAll = useCallback(() => {
deleteAllEntries();
clearSelectedEvents();
onClose();
}, [clearSelectedEvents, deleteAllEntries, onClose]);
handlers.close();
}, [clearSelectedEvents, deleteAllEntries, handlers]);
return (
<>
<Button
size='sm'
variant='ontime-outlined'
leftIcon={<IoTrash />}
onClick={onOpen}
color='#FA5656'
isDisabled={appMode === 'run'}
variant='subtle-destructive'
className={style.apart}
onClick={() => handlers.open()}
disabled={appMode === AppMode.Run}
>
Clear rundown
<IoTrash />
Clear All
</Button>
<AlertDialog variant='ontime' isOpen={isOpen} leastDestructiveRef={cancelRef} onClose={onClose}>
<AlertDialogOverlay>
<AlertDialogContent>
<AlertDialogHeader fontSize='lg' fontWeight='bold'>
Clear rundown
</AlertDialogHeader>
<AlertDialogBody>
You will lose all data in your rundown. <br /> Are you sure?
</AlertDialogBody>
<AlertDialogFooter>
<Button ref={cancelRef} onClick={onClose} variant='ontime-ghosted-white'>
Cancel
</Button>
<Button colorScheme='red' onClick={deleteAll} ml={4}>
Delete all
</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialogOverlay>
</AlertDialog>
<Dialog
isOpen={isOpen}
onClose={handlers.close}
title='Clear Rundown'
showBackdrop
showCloseButton
bodyElements={
<>
You will lose all data in your rundown. <br /> Are you sure?
</>
}
footerElements={
<>
<Button size='large' onClick={handlers.close}>
Cancel
</Button>
<Button variant='destructive' size='large' onClick={deleteAll}>
Delete all
</Button>
</>
}
/>
</>
);
}
@@ -4,11 +4,11 @@ import { InputRightElement, Tooltip } from '@chakra-ui/react';
import { TimeField, TimeStrategy } from 'ontime-types';
import { dayInMs } from 'ontime-utils';
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
import TimeInputWithButton from '../../../common/components/input/time-input/TimeInputWithButton';
import { useEntryActions } from '../../../common/hooks/useEntryAction';
import { cx } from '../../../common/utils/styleUtils';
import { tooltipDelayFast, tooltipDelayMid } from '../../../ontimeConfig';
import * as Editor from '../../editors/editor-utils/EditorUtils';
import style from './TimeInputFlow.module.scss';
@@ -3,7 +3,7 @@ import { Button, Checkbox } from '@chakra-ui/react';
import { Column } from '@tanstack/react-table';
import { OntimeEntry } from 'ontime-types';
import * as Editor from '../../../../features/editors/editor-utils/EditorUtils';
import * as Editor from '../../../../common/components/editor-utils/EditorUtils';
import style from './CuesheetTableSettings.module.scss';
@@ -6,17 +6,17 @@ import { useHotkeys } from '@mantine/hooks';
import NavigationMenu from '../../common/components/navigation-menu/NavigationMenu';
import { useElectronListener } from '../../common/hooks/useElectronEvent';
import { useWindowTitle } from '../../common/hooks/useWindowTitle';
import AppSettings from '../app-settings/AppSettings';
import useAppSettingsNavigation from '../app-settings/useAppSettingsNavigation';
import { EditorOverview } from '../overview/Overview';
import AppSettings from '../../features/app-settings/AppSettings';
import useAppSettingsNavigation from '../../features/app-settings/useAppSettingsNavigation';
import { EditorOverview } from '../../features/overview/Overview';
import WelcomePlacement from './welcome/WelcomePlacement';
import styles from './Editor.module.scss';
const Rundown = lazy(() => import('../rundown/RundownExport'));
const TimerControl = lazy(() => import('../control/playback/TimerControlExport'));
const MessageControl = lazy(() => import('../control/message/MessageControlExport'));
const Rundown = lazy(() => import('../../features/rundown/RundownExport'));
const TimerControl = lazy(() => import('../../features/control/playback/TimerControlExport'));
const MessageControl = lazy(() => import('../../features/control/message/MessageControlExport'));
export default function Editor() {
const { isOpen: isSettingsOpen, setLocation, close } = useAppSettingsNavigation();
@@ -3,7 +3,7 @@ import { Input, Modal, ModalBody, ModalContent, ModalFooter, ModalOverlay } from
import { useDebouncedCallback } from '@mantine/hooks';
import { SupportedEntry } from 'ontime-types';
import { useEventSelection } from '../../rundown/useEventSelection';
import { useEventSelection } from '../../../features/rundown/useEventSelection';
import useFinder from './useFinder';
@@ -4,9 +4,9 @@ import { Button, Checkbox, Modal, ModalBody, ModalCloseButton, ModalContent, Mod
import { loadDemo, loadProject } from '../../../common/api/db';
import { postShowWelcomeDialog } from '../../../common/api/settings';
import { invalidateAllCaches } from '../../../common/api/utils';
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
import ExternalLink from '../../../common/components/link/external-link/ExternalLink';
import { appVersion, discordUrl, documentationUrl, websiteUrl } from '../../../externals';
import * as Editor from '../editor-utils/EditorUtils';
import ImportProjectButton from './composite/ImportProjectButton';
import WelcomeProjectList from './composite/WelcomeProjectList';
+1 -1
View File
@@ -14,7 +14,7 @@ test('project file upload', async ({ page }) => {
}
await page.getByRole('button', { name: 'Edit' }).click();
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
await page.getByRole('button', { name: 'toggle settings' }).click();
+2 -2
View File
@@ -5,7 +5,7 @@ test('delay blocks add time to events', async ({ page }) => {
// delete all events and add a new one
await page.getByRole('button', { name: 'Edit' }).click();
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
await page.getByRole('button', { name: 'Create event' }).click();
@@ -53,7 +53,7 @@ test('delays are show correctly', async ({ page }) => {
// add a test event
await page.getByRole('button', { name: 'Edit' }).click();
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
await page.getByRole('button', { name: 'Create Event' }).click();
+1 -1
View File
@@ -4,7 +4,7 @@ test('CRUD operations on the rundown', async ({ page }) => {
await page.goto('http://localhost:4001/editor');
await page.getByRole('button', { name: 'Edit' }).click();
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
// create event from the rundown empty button
+1 -1
View File
@@ -4,7 +4,7 @@ test('smoke test operator', async ({ page }) => {
// make some boilerplate
await page.goto('http://localhost:4001/editor');
await page.getByRole('button', { name: 'Edit' }).click();
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
await page.getByRole('button', { name: 'Create Event' }).click();
@@ -4,7 +4,7 @@ test('Copy-paste', async ({ page }) => {
await page.goto('http://localhost:4001/rundown');
// clear rundown
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
// create event
@@ -43,7 +43,7 @@ test('Move', async ({ page }) => {
await page.goto('http://localhost:4001/rundown');
// clear rundown
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
// create events
@@ -67,7 +67,7 @@ test('Add block', async ({ page }) => {
await page.goto('http://localhost:4001/rundown');
// clear rundown
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
// create events
@@ -95,7 +95,7 @@ test('Add delay', async ({ page }) => {
await page.goto('http://localhost:4001/rundown');
// clear rundown
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
//create events
@@ -116,7 +116,7 @@ test('Add event', async ({ page }) => {
await page.goto('http://localhost:4001/rundown');
// clear rundown
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
//create events
@@ -138,7 +138,7 @@ test('Delete event', async ({ page }) => {
// clear rundown
await page.goto('http://localhost:4001/rundown');
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
//create event
+2 -2
View File
@@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test';
test('show warning when event crosses midnight', async ({ page }) => {
await page.goto('http://localhost:4001/editor');
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
await page.getByRole('button', { name: 'Create Event' }).click();
@@ -23,7 +23,7 @@ test('show warning when event crosses midnight', async ({ page }) => {
test('show warning when event starts next day midnight', async ({ page }) => {
await page.goto('http://localhost:4001/editor');
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
await page.getByRole('button', { name: 'Create Event' }).click();
+2 -2
View File
@@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test';
test('time until absolute', async ({ page }) => {
await page.goto('http://localhost:4001/editor');
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
await page.getByRole('button', { name: 'Create Event' }).click();
@@ -40,7 +40,7 @@ test('time until absolute', async ({ page }) => {
test('time until relative', async ({ page }) => {
await page.goto('http://localhost:4001/editor');
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
await page.getByRole('button', { name: 'Create Event' }).click();
@@ -4,7 +4,7 @@ test('Rearrange while playing', async ({ page }) => {
await page.goto('http://localhost:4001/rundown');
// clear rundown
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
// create events
@@ -5,7 +5,7 @@ const fileToUpload = 'e2e/tests/fixtures/test-sheet.xlsx';
test('sheet file upload', async ({ page }) => {
await page.goto('http://localhost:4001/editor');
await page.getByRole('button', { name: 'Edit' }).click();
await page.getByRole('button', { name: 'Clear rundown' }).click();
await page.getByRole('button', { name: 'Clear all' }).click();
await page.getByRole('button', { name: 'Delete all' }).click();
await page.getByRole('button', { name: 'Toggle settings' }).click();