mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-19 22:24:11 +00:00
Fix: rearrange playing event (#1640)
* creat failing test * find and pass index of eventNow in case it moved * fix cache invalidate edits should also recalculate timer * use coluor as test indicator * fixed empty cue guard Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com> --------- Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
fb93063b47
commit
4e561cf01f
@@ -8,6 +8,7 @@ import {
|
|||||||
isOntimeDelay,
|
isOntimeDelay,
|
||||||
isOntimeEvent,
|
isOntimeEvent,
|
||||||
OntimeEntry,
|
OntimeEntry,
|
||||||
|
OntimeEvent,
|
||||||
PatchWithId,
|
PatchWithId,
|
||||||
Rundown,
|
Rundown,
|
||||||
} from 'ontime-types';
|
} from 'ontime-types';
|
||||||
@@ -84,7 +85,7 @@ export async function editEntry(patch: PatchWithId): Promise<OntimeEntry> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we dont allow the user to change the cue to empty string
|
// we dont allow the user to change the cue to empty string
|
||||||
if (isOntimeEvent(patch) && patch?.cue === '') {
|
if ((patch as Partial<OntimeEvent>)?.cue === '') {
|
||||||
throw new Error('Cue value invalid');
|
throw new Error('Cue value invalid');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +108,7 @@ export async function editEntry(patch: PatchWithId): Promise<OntimeEntry> {
|
|||||||
updateRuntimeOnChange(rundownMetadata);
|
updateRuntimeOnChange(rundownMetadata);
|
||||||
|
|
||||||
// notify timer and external services of change
|
// notify timer and external services of change
|
||||||
notifyChanges(rundownMetadata, revision, { timer: [entry.id], external: true });
|
notifyChanges(rundownMetadata, revision, { timer: didInvalidate ? true : [entry.id], external: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
@@ -171,7 +172,7 @@ export async function batchEditEntries(ids: EntryId[], patch: Partial<OntimeEntr
|
|||||||
updateRuntimeOnChange(rundownMetadata);
|
updateRuntimeOnChange(rundownMetadata);
|
||||||
|
|
||||||
// notify timer and external services of change
|
// notify timer and external services of change
|
||||||
notifyChanges(rundownMetadata, revision, { timer: changedIds, external: true });
|
notifyChanges(rundownMetadata, revision, { timer: batchDidInvalidate ? true : changedIds, external: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
return rundownResult;
|
return rundownResult;
|
||||||
|
|||||||
@@ -379,8 +379,9 @@ export function updateLoaded(event?: PlayableEvent): string | undefined {
|
|||||||
export function updateAll(rundown: Rundown, timedEventsOrder: EntryId[]) {
|
export function updateAll(rundown: Rundown, timedEventsOrder: EntryId[]) {
|
||||||
const timedEvents = filterTimedEvents(rundown, timedEventsOrder);
|
const timedEvents = filterTimedEvents(rundown, timedEventsOrder);
|
||||||
// TODO(remove public): we dont need to make the timedEvents object, we pass primitives and let the functions handle it
|
// TODO(remove public): we dont need to make the timedEvents object, we pass primitives and let the functions handle it
|
||||||
loadNow(timedEvents);
|
const eventNowIndex = timedEventsOrder.findIndex((id) => id === runtimeState.eventNow?.id);
|
||||||
loadNext(timedEvents);
|
loadNow(timedEvents, eventNowIndex >= 0 ? eventNowIndex : undefined);
|
||||||
|
loadNext(timedEvents, eventNowIndex >= 0 ? eventNowIndex : undefined);
|
||||||
updateLoaded(runtimeState.eventNow ?? undefined);
|
updateLoaded(runtimeState.eventNow ?? undefined);
|
||||||
loadBlock(rundown);
|
loadBlock(rundown);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
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: '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();
|
||||||
|
|
||||||
|
// start event 2
|
||||||
|
await page.getByTestId('entry-2').getByRole('button', { name: 'Start event' }).click();
|
||||||
|
await expect(page.getByTestId('entry-2').locator('#event-block')).toHaveCSS('background-color', 'rgb(8, 122, 39)');
|
||||||
|
|
||||||
|
// move event 2 up
|
||||||
|
await page.getByTestId('entry-2').locator('#event-block').getByText('2').click();
|
||||||
|
await page.getByTestId('entry-2').locator('#event-block div').filter({ hasText: '2' }).press('Alt+Control+ArrowUp');
|
||||||
|
|
||||||
|
// event CUE1 should new be entry 2
|
||||||
|
await expect(page.getByTestId('entry-2').locator('#event-block')).toContainText('1');
|
||||||
|
// but entry 1 should be the one playing (it will be unlinked as it will be the first event)
|
||||||
|
await expect(page.getByTestId('entry-1').locator('#event-block')).toHaveCSS('background-color', 'rgb(8, 122, 39)');
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user