mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-07 07:19:16 +00:00
fix: insert above shortcut (#1020)
refactor: unify setCursor and useEventSelection
This commit is contained in:
committed by
GitHub
parent
c2039866b4
commit
8b3abe9d61
@@ -19,13 +19,10 @@ function persistModeToSession(mode: AppMode) {
|
|||||||
type AppModeStore = {
|
type AppModeStore = {
|
||||||
mode: AppMode;
|
mode: AppMode;
|
||||||
setMode: (mode: AppMode) => void;
|
setMode: (mode: AppMode) => void;
|
||||||
cursor: string | null;
|
|
||||||
setCursor: (cursor: string | null) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useAppMode = create<AppModeStore>()((set) => ({
|
export const useAppMode = create<AppModeStore>()((set) => ({
|
||||||
mode: getModeFromSession(),
|
mode: getModeFromSession(),
|
||||||
cursor: null,
|
|
||||||
setMode: (mode: AppMode) => {
|
setMode: (mode: AppMode) => {
|
||||||
persistModeToSession(mode);
|
persistModeToSession(mode);
|
||||||
|
|
||||||
@@ -33,5 +30,4 @@ export const useAppMode = create<AppModeStore>()((set) => ({
|
|||||||
return { mode };
|
return { mode };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setCursor: (cursor: string | null) => set({ cursor }),
|
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { cloneEvent } from '../../common/utils/eventsManager';
|
|||||||
|
|
||||||
import QuickAddBlock from './quick-add-block/QuickAddBlock';
|
import QuickAddBlock from './quick-add-block/QuickAddBlock';
|
||||||
import RundownEmpty from './RundownEmpty';
|
import RundownEmpty from './RundownEmpty';
|
||||||
|
import { useEventSelection } from './useEventSelection';
|
||||||
|
|
||||||
import style from './Rundown.module.scss';
|
import style from './Rundown.module.scss';
|
||||||
|
|
||||||
@@ -33,7 +34,9 @@ export default function Rundown({ data }: RundownProps) {
|
|||||||
const { entryCopyId, setEntryCopyId } = useEntryCopy();
|
const { entryCopyId, setEntryCopyId } = useEntryCopy();
|
||||||
|
|
||||||
// cursor
|
// cursor
|
||||||
const { cursor, mode: appMode, setCursor } = useAppMode();
|
const { mode: appMode } = useAppMode();
|
||||||
|
const { clearSelectedEvents, setSelectedEvents, cursor } = useEventSelection();
|
||||||
|
|
||||||
const cursorRef = useRef<HTMLDivElement | null>(null);
|
const cursorRef = useRef<HTMLDivElement | null>(null);
|
||||||
const scrollRef = useRef<HTMLDivElement | null>(null);
|
const scrollRef = useRef<HTMLDivElement | null>(null);
|
||||||
useFollowComponent({ followRef: cursorRef, scrollRef, doFollow: appMode === AppMode.Run });
|
useFollowComponent({ followRef: cursorRef, scrollRef, doFollow: appMode === AppMode.Run });
|
||||||
@@ -44,34 +47,42 @@ export default function Rundown({ data }: RundownProps) {
|
|||||||
const deleteAtCursor = useCallback(
|
const deleteAtCursor = useCallback(
|
||||||
(cursor: string | null) => {
|
(cursor: string | null) => {
|
||||||
if (!cursor) return;
|
if (!cursor) return;
|
||||||
const previous = getPreviousNormal(rundown, order, cursor).entry?.id ?? null;
|
const { entry, index } = getPreviousNormal(rundown, order, cursor);
|
||||||
deleteEvent([cursor]);
|
deleteEvent([cursor]);
|
||||||
setCursor(previous);
|
if (entry && index !== null) {
|
||||||
|
setSelectedEvents({ id: entry.id, selectMode: 'click', index });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[deleteEvent, order, rundown, setCursor],
|
[rundown, order, deleteEvent, setSelectedEvents],
|
||||||
);
|
);
|
||||||
|
|
||||||
const insertAtCursor = useCallback(
|
const insertCopyAtId = useCallback(
|
||||||
(type: SupportedEvent | 'clone', cursor: string | null, above = false) => {
|
(atId: string | null, copyId: string | null, above = false) => {
|
||||||
const adjustedCursor = above ? getPreviousNormal(rundown, order, cursor ?? '').entry?.id ?? null : cursor;
|
const adjustedCursor = above ? getPreviousNormal(rundown, order, atId ?? '').entry?.id ?? null : atId;
|
||||||
|
if (copyId === null) {
|
||||||
if (adjustedCursor === null) {
|
|
||||||
// we cant clone without selection
|
// we cant clone without selection
|
||||||
if (type === 'clone') {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
const cloneEntry = rundown[copyId];
|
||||||
|
if (cloneEntry?.type === SupportedEvent.Event) {
|
||||||
|
//if we don't have a cursor add the new event on top
|
||||||
|
const newEvent = cloneEvent(cloneEntry, adjustedCursor ?? undefined);
|
||||||
|
addEvent(newEvent);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[addEvent, order, rundown],
|
||||||
|
);
|
||||||
|
|
||||||
|
const insertAtId = useCallback(
|
||||||
|
(type: SupportedEvent, id: string | null, above = false) => {
|
||||||
|
const adjustedCursor = above ? getPreviousNormal(rundown, order, id ?? '').entry?.id ?? null : id;
|
||||||
|
if (adjustedCursor === null) {
|
||||||
// the only thing to do is adding an event at top
|
// the only thing to do is adding an event at top
|
||||||
addEvent({ type });
|
addEvent({ type });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'clone') {
|
if (type === SupportedEvent.Event) {
|
||||||
const cursorEvent = rundown[adjustedCursor];
|
|
||||||
if (cursorEvent?.type === SupportedEvent.Event) {
|
|
||||||
const newEvent = cloneEvent(cursorEvent, cursorEvent.id);
|
|
||||||
addEvent(newEvent);
|
|
||||||
}
|
|
||||||
} else if (type === SupportedEvent.Event) {
|
|
||||||
const newEvent = {
|
const newEvent = {
|
||||||
type: SupportedEvent.Event,
|
type: SupportedEvent.Event,
|
||||||
};
|
};
|
||||||
@@ -92,23 +103,26 @@ export default function Rundown({ data }: RundownProps) {
|
|||||||
if (order.length < 1) {
|
if (order.length < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let newCursor: string | undefined;
|
let newCursor: string | null;
|
||||||
|
let newIndex: number | null;
|
||||||
if (cursor === null) {
|
if (cursor === null) {
|
||||||
// there is no cursor, we select the first or last depending on direction if it exists
|
// there is no cursor, we select the first or last depending on direction if it exists
|
||||||
newCursor = direction === 'up' ? getLastNormal(rundown, order)?.id : getFirstNormal(rundown, order)?.id;
|
newCursor =
|
||||||
|
(direction === 'up' ? getLastNormal(rundown, order)?.id : getFirstNormal(rundown, order)?.id) ?? null;
|
||||||
|
newIndex = direction === 'up' ? order.length : 0;
|
||||||
} else {
|
} else {
|
||||||
// otherwise we select the next or previous
|
// otherwise we select the next or previous
|
||||||
newCursor =
|
const selected =
|
||||||
direction === 'up'
|
direction === 'up' ? getPreviousNormal(rundown, order, cursor) : getNextNormal(rundown, order, cursor);
|
||||||
? getPreviousNormal(rundown, order, cursor).entry?.id
|
newCursor = selected.entry?.id ?? null;
|
||||||
: getNextNormal(rundown, order, cursor).entry?.id;
|
newIndex = selected.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newCursor) {
|
if (newCursor && newIndex !== null) {
|
||||||
setCursor(newCursor);
|
setSelectedEvents({ id: newCursor, selectMode: 'click', index: newIndex });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[order, rundown, setCursor],
|
[order, rundown, setSelectedEvents],
|
||||||
);
|
);
|
||||||
|
|
||||||
const moveEntry = useCallback(
|
const moveEntry = useCallback(
|
||||||
@@ -134,22 +148,22 @@ export default function Rundown({ data }: RundownProps) {
|
|||||||
['alt + mod + ArrowDown', () => moveEntry(cursor, 'down'), { preventDefault: true }],
|
['alt + mod + ArrowDown', () => moveEntry(cursor, 'down'), { preventDefault: true }],
|
||||||
['alt + mod + ArrowUp', () => moveEntry(cursor, 'up'), { preventDefault: true }],
|
['alt + mod + ArrowUp', () => moveEntry(cursor, 'up'), { preventDefault: true }],
|
||||||
|
|
||||||
['Escape', () => setCursor(null), { preventDefault: true }],
|
['Escape', () => clearSelectedEvents(), { preventDefault: true }],
|
||||||
|
|
||||||
['mod + Backspace', () => deleteAtCursor(cursor), { preventDefault: true }],
|
['mod + Backspace', () => deleteAtCursor(cursor), { preventDefault: true }],
|
||||||
|
|
||||||
['alt + E', () => insertAtCursor(SupportedEvent.Event, cursor), { preventDefault: true }],
|
['alt + E', () => insertAtId(SupportedEvent.Event, cursor), { preventDefault: true }],
|
||||||
['alt + shift + E', () => insertAtCursor(SupportedEvent.Event, cursor, true), { preventDefault: true }],
|
['alt + shift + E', () => insertAtId(SupportedEvent.Event, cursor, true), { preventDefault: true }],
|
||||||
|
|
||||||
['alt + B', () => insertAtCursor(SupportedEvent.Block, cursor), { preventDefault: true }],
|
['alt + B', () => insertAtId(SupportedEvent.Block, cursor), { preventDefault: true }],
|
||||||
['alt + shift + B', () => insertAtCursor(SupportedEvent.Block, cursor, true), { preventDefault: true }],
|
['alt + shift + B', () => insertAtId(SupportedEvent.Block, cursor, true), { preventDefault: true }],
|
||||||
|
|
||||||
['alt + D', () => insertAtCursor(SupportedEvent.Delay, cursor), { preventDefault: true }],
|
['alt + D', () => insertAtId(SupportedEvent.Delay, cursor), { preventDefault: true }],
|
||||||
['alt + shift + D', () => insertAtCursor(SupportedEvent.Delay, cursor, true), { preventDefault: true }],
|
['alt + shift + D', () => insertAtId(SupportedEvent.Delay, cursor, true), { preventDefault: true }],
|
||||||
|
|
||||||
['mod + C', () => setEntryCopyId(cursor), { preventDefault: true }],
|
['mod + C', () => setEntryCopyId(cursor), { preventDefault: true }],
|
||||||
['mod + V', () => insertAtCursor('clone', entryCopyId), { preventDefault: true }],
|
['mod + V', () => insertCopyAtId(cursor, entryCopyId), { preventDefault: true }],
|
||||||
['mod + shift + V', () => insertAtCursor('clone', entryCopyId, true), { preventDefault: true }],
|
['mod + shift + V', () => insertCopyAtId(cursor, entryCopyId, true), { preventDefault: true }],
|
||||||
|
|
||||||
['alt + backspace', () => deleteAtCursor(cursor), { preventDefault: true }],
|
['alt + backspace', () => deleteAtCursor(cursor), { preventDefault: true }],
|
||||||
]);
|
]);
|
||||||
@@ -165,8 +179,9 @@ export default function Rundown({ data }: RundownProps) {
|
|||||||
if (appMode !== AppMode.Run || !featureData?.selectedEventId) {
|
if (appMode !== AppMode.Run || !featureData?.selectedEventId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setCursor(featureData.selectedEventId);
|
const index = order.findIndex((id) => id === featureData.selectedEventId);
|
||||||
}, [appMode, featureData.selectedEventId, setCursor]);
|
setSelectedEvents({ id: featureData.selectedEventId, selectMode: 'click', index });
|
||||||
|
}, [appMode, featureData.selectedEventId, order, setSelectedEvents]);
|
||||||
|
|
||||||
const handleOnDragEnd = (event: DragEndEvent) => {
|
const handleOnDragEnd = (event: DragEndEvent) => {
|
||||||
const { active, over } = event;
|
const { active, over } = event;
|
||||||
@@ -185,7 +200,7 @@ export default function Rundown({ data }: RundownProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (statefulEntries.length < 1) {
|
if (statefulEntries.length < 1) {
|
||||||
return <RundownEmpty handleAddNew={() => insertAtCursor(SupportedEvent.Event, null)} />;
|
return <RundownEmpty handleAddNew={() => insertAtId(SupportedEvent.Event, cursor)} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
let previousStart: MaybeNumber = null;
|
let previousStart: MaybeNumber = null;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { MaybeNumber, OntimeEvent, OntimeRundownEntry, Playback, SupportedEvent
|
|||||||
|
|
||||||
import { useEventAction } from '../../common/hooks/useEventAction';
|
import { useEventAction } from '../../common/hooks/useEventAction';
|
||||||
import useMemoisedFn from '../../common/hooks/useMemoisedFn';
|
import useMemoisedFn from '../../common/hooks/useMemoisedFn';
|
||||||
import { useAppMode } from '../../common/stores/appModeStore';
|
|
||||||
import { useEmitLog } from '../../common/stores/logger';
|
import { useEmitLog } from '../../common/stores/logger';
|
||||||
import { cloneEvent } from '../../common/utils/eventsManager';
|
import { cloneEvent } from '../../common/utils/eventsManager';
|
||||||
|
|
||||||
@@ -56,22 +55,15 @@ export default function RundownEntry(props: RundownEntryProps) {
|
|||||||
} = props;
|
} = props;
|
||||||
const { emitError } = useEmitLog();
|
const { emitError } = useEmitLog();
|
||||||
const { addEvent, updateEvent, batchUpdateEvents, deleteEvent, swapEvents } = useEventAction();
|
const { addEvent, updateEvent, batchUpdateEvents, deleteEvent, swapEvents } = useEventAction();
|
||||||
const cursor = useAppMode((state) => state.cursor);
|
|
||||||
const setCursor = useAppMode((state) => state.setCursor);
|
|
||||||
const { selectedEvents, unselect, clearSelectedEvents } = useEventSelection();
|
const { selectedEvents, unselect, clearSelectedEvents } = useEventSelection();
|
||||||
|
|
||||||
const removeOpenEvent = useCallback(() => {
|
const removeOpenEvent = useCallback(() => {
|
||||||
unselect(data.id);
|
unselect(data.id);
|
||||||
// clear cursor if we are deleting the event that is currently selected
|
}, [unselect, data.id]);
|
||||||
if (cursor === data.id) {
|
|
||||||
setCursor(null);
|
|
||||||
}
|
|
||||||
}, [unselect, data.id, cursor, setCursor]);
|
|
||||||
|
|
||||||
const clearMultiSelection = useCallback(() => {
|
const clearMultiSelection = useCallback(() => {
|
||||||
clearSelectedEvents();
|
clearSelectedEvents();
|
||||||
setCursor(null);
|
}, [clearSelectedEvents]);
|
||||||
}, [clearSelectedEvents, setCursor]);
|
|
||||||
|
|
||||||
// Create / delete new events
|
// Create / delete new events
|
||||||
type FieldValue = {
|
type FieldValue = {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { IoTrash } from '@react-icons/all-files/io5/IoTrash';
|
|||||||
import { EndAction, MaybeNumber, MaybeString, OntimeEvent, Playback, TimerType, TimeStrategy } from 'ontime-types';
|
import { EndAction, MaybeNumber, MaybeString, OntimeEvent, Playback, TimerType, TimeStrategy } from 'ontime-types';
|
||||||
|
|
||||||
import { useContextMenu } from '../../../common/hooks/useContextMenu';
|
import { useContextMenu } from '../../../common/hooks/useContextMenu';
|
||||||
import { useAppMode } from '../../../common/stores/appModeStore';
|
|
||||||
import { cx, getAccessibleColour } from '../../../common/utils/styleUtils';
|
import { cx, getAccessibleColour } from '../../../common/utils/styleUtils';
|
||||||
import type { EventItemActions } from '../RundownEntry';
|
import type { EventItemActions } from '../RundownEntry';
|
||||||
import { useEventIdSwapping } from '../useEventIdSwapping';
|
import { useEventIdSwapping } from '../useEventIdSwapping';
|
||||||
@@ -88,7 +87,6 @@ export default function EventBlock(props: EventBlockProps) {
|
|||||||
} = props;
|
} = props;
|
||||||
const { selectedEventId, setSelectedEventId, clearSelectedEventId } = useEventIdSwapping();
|
const { selectedEventId, setSelectedEventId, clearSelectedEventId } = useEventIdSwapping();
|
||||||
const { selectedEvents, setSelectedEvents } = useEventSelection();
|
const { selectedEvents, setSelectedEvents } = useEventSelection();
|
||||||
const setCursor = useAppMode((state) => state.setCursor);
|
|
||||||
const handleRef = useRef<null | HTMLSpanElement>(null);
|
const handleRef = useRef<null | HTMLSpanElement>(null);
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
|
||||||
@@ -231,7 +229,6 @@ export default function EventBlock(props: EventBlockProps) {
|
|||||||
const index = eventIndex - 1;
|
const index = eventIndex - 1;
|
||||||
const editMode = getSelectionMode(event);
|
const editMode = getSelectionMode(event);
|
||||||
setSelectedEvents({ id: eventId, index, selectMode: editMode });
|
setSelectedEvents({ id: eventId, index, selectMode: editMode });
|
||||||
setCursor(eventId);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import { useEventSelection } from '../useEventSelection';
|
|||||||
|
|
||||||
export default function RundownMenu() {
|
export default function RundownMenu() {
|
||||||
const clearSelectedEvents = useEventSelection((state) => state.clearSelectedEvents);
|
const clearSelectedEvents = useEventSelection((state) => state.clearSelectedEvents);
|
||||||
const setCursor = useAppMode((state) => state.setCursor);
|
|
||||||
const appMode = useAppMode((state) => state.mode);
|
const appMode = useAppMode((state) => state.mode);
|
||||||
const { deleteAllEvents } = useEventAction();
|
const { deleteAllEvents } = useEventAction();
|
||||||
|
|
||||||
@@ -27,9 +26,8 @@ export default function RundownMenu() {
|
|||||||
const deleteAll = useCallback(() => {
|
const deleteAll = useCallback(() => {
|
||||||
deleteAllEvents();
|
deleteAllEvents();
|
||||||
clearSelectedEvents();
|
clearSelectedEvents();
|
||||||
setCursor(null);
|
|
||||||
onClose();
|
onClose();
|
||||||
}, [clearSelectedEvents, deleteAllEvents, onClose, setCursor]);
|
}, [clearSelectedEvents, deleteAllEvents, onClose]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { MouseEvent } from 'react';
|
import { MouseEvent } from 'react';
|
||||||
import { isOntimeEvent, OntimeEvent, RundownCached } from 'ontime-types';
|
import { isOntimeEvent, MaybeNumber, MaybeString, OntimeEvent, RundownCached } from 'ontime-types';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
|
||||||
import { RUNDOWN } from '../../common/api/constants';
|
import { RUNDOWN } from '../../common/api/constants';
|
||||||
@@ -10,7 +10,8 @@ export type SelectionMode = 'shift' | 'click' | 'ctrl';
|
|||||||
|
|
||||||
interface EventSelectionStore {
|
interface EventSelectionStore {
|
||||||
selectedEvents: Set<string>;
|
selectedEvents: Set<string>;
|
||||||
anchoredIndex: number | null;
|
anchoredIndex: MaybeNumber;
|
||||||
|
cursor: MaybeString;
|
||||||
setSelectedEvents: (selectionArgs: { id: string; index: number; selectMode: SelectionMode }) => void;
|
setSelectedEvents: (selectionArgs: { id: string; index: number; selectMode: SelectionMode }) => void;
|
||||||
clearSelectedEvents: () => void;
|
clearSelectedEvents: () => void;
|
||||||
clearMultiSelect: () => void;
|
clearMultiSelect: () => void;
|
||||||
@@ -20,13 +21,14 @@ interface EventSelectionStore {
|
|||||||
export const useEventSelection = create<EventSelectionStore>()((set, get) => ({
|
export const useEventSelection = create<EventSelectionStore>()((set, get) => ({
|
||||||
selectedEvents: new Set(),
|
selectedEvents: new Set(),
|
||||||
anchoredIndex: null,
|
anchoredIndex: null,
|
||||||
|
cursor: null,
|
||||||
setSelectedEvents: (selectionArgs) => {
|
setSelectedEvents: (selectionArgs) => {
|
||||||
const { id, index, selectMode } = selectionArgs;
|
const { id, index, selectMode } = selectionArgs;
|
||||||
const { selectedEvents, anchoredIndex } = get();
|
const { selectedEvents, anchoredIndex } = get();
|
||||||
|
|
||||||
// on click, we replace selection with event
|
// on click, we replace selection with event
|
||||||
if (selectMode === 'click') {
|
if (selectMode === 'click') {
|
||||||
return set({ selectedEvents: new Set([id]), anchoredIndex: index });
|
return set({ selectedEvents: new Set([id]), anchoredIndex: index, cursor: id });
|
||||||
}
|
}
|
||||||
|
|
||||||
// on ctrl + click, we toggle the selection of that event
|
// on ctrl + click, we toggle the selection of that event
|
||||||
@@ -39,6 +41,7 @@ export const useEventSelection = create<EventSelectionStore>()((set, get) => ({
|
|||||||
return set({
|
return set({
|
||||||
selectedEvents: selectedEvents.add(id),
|
selectedEvents: selectedEvents.add(id),
|
||||||
anchoredIndex: index,
|
anchoredIndex: index,
|
||||||
|
cursor: id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +86,7 @@ export const useEventSelection = create<EventSelectionStore>()((set, get) => ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clearSelectedEvents: () => set({ selectedEvents: new Set(), anchoredIndex: null }),
|
clearSelectedEvents: () => set({ selectedEvents: new Set(), anchoredIndex: null, cursor: null }),
|
||||||
clearMultiSelect: () => {
|
clearMultiSelect: () => {
|
||||||
const { selectedEvents } = get();
|
const { selectedEvents } = get();
|
||||||
const [firstSelected] = selectedEvents;
|
const [firstSelected] = selectedEvents;
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test('Copy Past', async ({ page }) => {
|
||||||
|
await page.goto('http://localhost:4001/rundown');
|
||||||
|
|
||||||
|
// clear rundown
|
||||||
|
await page.getByRole('button', { name: 'Clear rundown' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Delete all' }).click();
|
||||||
|
|
||||||
|
//create event
|
||||||
|
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||||
|
await page.getByTestId('entry-1').click();
|
||||||
|
await page.getByLabel('Cue', { exact: true }).click();
|
||||||
|
await page.getByLabel('Cue', { exact: true }).fill('4');
|
||||||
|
await page.getByLabel('Cue', { exact: true }).press('Enter');
|
||||||
|
await page.getByTestId('entry-1').click();
|
||||||
|
await page.getByTestId('block__title').click();
|
||||||
|
await page.getByTestId('block__title').fill('test');
|
||||||
|
await page.getByTestId('block__title').press('Enter');
|
||||||
|
|
||||||
|
//copy past below
|
||||||
|
await page.locator('div').filter({ hasText: /^4$/ }).click();
|
||||||
|
await page.locator('div').filter({ hasText: /^4$/ }).press('Control+c');
|
||||||
|
await page.locator('div').filter({ hasText: /^4$/ }).press('Control+v');
|
||||||
|
|
||||||
|
//assert
|
||||||
|
await expect(page.getByTestId('entry-2')).toBeVisible();
|
||||||
|
await expect(page.getByTestId('entry-2').getByTestId('block__title')).toHaveValue('test');
|
||||||
|
await expect(page.getByTestId('entry-2').locator('#event-block')).toContainText('5');
|
||||||
|
|
||||||
|
//copy past above
|
||||||
|
await page.locator('div').filter({ hasText: /^5$/ }).click();
|
||||||
|
await page.locator('div').filter({ hasText: /^5$/ }).press('Control+c');
|
||||||
|
await page.locator('div').filter({ hasText: /^5$/ }).press('Control+Shift+v');
|
||||||
|
|
||||||
|
//assert
|
||||||
|
await expect(page.getByTestId('entry-2')).toBeVisible();
|
||||||
|
await expect(page.getByTestId('entry-2').getByTestId('block__title')).toHaveValue('test');
|
||||||
|
await expect(page.getByTestId('entry-2').locator('#event-block')).toContainText('4.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
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: 'Delete all' }).click();
|
||||||
|
|
||||||
|
//create events
|
||||||
|
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Event' }).nth(4).click();
|
||||||
|
await page.getByRole('button', { name: 'Event', exact: true }).nth(1).click();
|
||||||
|
|
||||||
|
//copy move down
|
||||||
|
await page.getByTestId('entry-1').locator('#event-block').getByText('1').click();
|
||||||
|
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+Control+ArrowDown');
|
||||||
|
await expect(page.getByTestId('entry-2').locator('#event-block')).toContainText('1');
|
||||||
|
|
||||||
|
//copy move up
|
||||||
|
await page.getByTestId('entry-3').locator('#event-block').getByText('3').click();
|
||||||
|
await page.getByTestId('entry-3').locator('#event-block div').filter({ hasText: '3' }).press('Alt+Control+ArrowUp');
|
||||||
|
await page.getByTestId('entry-2').locator('div').filter({ hasText: /^3$/ }).press('Alt+Control+ArrowUp');
|
||||||
|
await expect(page.getByTestId('entry-1').locator('#event-block')).toContainText('3');
|
||||||
|
});
|
||||||
|
|
||||||
|
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: 'Delete all' }).click();
|
||||||
|
|
||||||
|
//create events
|
||||||
|
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||||
|
await page.getByTestId('entry-1').click();
|
||||||
|
await page.getByTestId('block__title').press('Escape');
|
||||||
|
|
||||||
|
//add block below
|
||||||
|
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+B');
|
||||||
|
await expect(page.getByPlaceholder('Block title')).toBeVisible();
|
||||||
|
|
||||||
|
//add block above
|
||||||
|
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+Shift+B');
|
||||||
|
await expect(page.getByTestId('entry-0').getByTestId('block__title')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
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: 'Delete all' }).click();
|
||||||
|
|
||||||
|
//create events
|
||||||
|
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||||
|
await page.getByTestId('entry-1').click();
|
||||||
|
await page.getByTestId('block__title').press('Escape');
|
||||||
|
|
||||||
|
//add delay below
|
||||||
|
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+D');
|
||||||
|
await expect(page.getByTestId('delay-input')).toBeVisible();
|
||||||
|
|
||||||
|
//add delay above
|
||||||
|
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+Shift+D');
|
||||||
|
await expect(page.getByTestId('entry-0').getByTestId('delay-input')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
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: 'Delete all' }).click();
|
||||||
|
|
||||||
|
//create events
|
||||||
|
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||||
|
await page.getByTestId('entry-1').click();
|
||||||
|
await page.getByTestId('block__title').press('Escape');
|
||||||
|
|
||||||
|
//add event below
|
||||||
|
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+E');
|
||||||
|
await expect(page.getByTestId('entry-2').locator('#event-block').getByText('2')).toBeVisible();
|
||||||
|
|
||||||
|
//add event above
|
||||||
|
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+Shift+E');
|
||||||
|
await expect(page.getByTestId('entry-1').locator('#event-block')).toContainText('0.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Delete event', async ({ page }) => {
|
||||||
|
await page.goto('http://localhost:4001/rundown');
|
||||||
|
|
||||||
|
// clear rundown
|
||||||
|
await page.goto('http://localhost:4001/rundown');
|
||||||
|
await page.getByRole('button', { name: 'Clear rundown' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Delete all' }).click();
|
||||||
|
|
||||||
|
//create event
|
||||||
|
await page.getByRole('button', { name: 'Create Event' }).click();
|
||||||
|
|
||||||
|
//delete event
|
||||||
|
await page.locator('#event-block div').filter({ hasText: '1' }).click();
|
||||||
|
await page.getByTestId('entry-1').locator('#event-block div').filter({ hasText: '1' }).press('Alt+Backspace');
|
||||||
|
await expect(page.getByRole('button', { name: 'Create Event' })).toBeVisible();
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user