mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-08 08:53:51 +00:00
chore: rename blocks to groups
This commit is contained in:
committed by
Carlos Valente
parent
486d89ecf4
commit
e5d2457717
@@ -46,7 +46,7 @@ describe('test parseDatabaseModel() with demo project (valid)', () => {
|
||||
// remove time-related fields from the comparison
|
||||
// these are not calculated in the parser
|
||||
Object.values(filteredDemoProject.rundowns.default.entries).forEach((entry: any) => {
|
||||
if (entry.type === SupportedEntry.Block) {
|
||||
if (entry.type === SupportedEntry.Group) {
|
||||
delete entry.timeStart;
|
||||
delete entry.timeEnd;
|
||||
delete entry.duration;
|
||||
@@ -54,7 +54,7 @@ describe('test parseDatabaseModel() with demo project (valid)', () => {
|
||||
}
|
||||
});
|
||||
Object.values(data.rundowns.default.entries).forEach((entry: any) => {
|
||||
if (entry.type === SupportedEntry.Block) {
|
||||
if (entry.type === SupportedEntry.Group) {
|
||||
delete entry.timeStart;
|
||||
delete entry.timeEnd;
|
||||
delete entry.duration;
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
EndAction,
|
||||
EntryCustomFields,
|
||||
NormalisedAutomation,
|
||||
OntimeBlock,
|
||||
OntimeGroup,
|
||||
OntimeEntry,
|
||||
ProjectData,
|
||||
ProjectRundowns,
|
||||
@@ -317,7 +317,8 @@ export function migrateAutomations(jsonData: object): AutomationSettings | undef
|
||||
* - add parent
|
||||
*
|
||||
* - block:
|
||||
* - add all the new blocks of the block that is now a group
|
||||
* - rename to group
|
||||
* - create group data
|
||||
*/
|
||||
export function migrateRundown(
|
||||
jsonData: object,
|
||||
@@ -392,13 +393,13 @@ export function migrateRundown(
|
||||
});
|
||||
} else if (entry.type === 'block') {
|
||||
if (parent) {
|
||||
(newRundown.entries[parent] as OntimeBlock).entries = [...children];
|
||||
(newRundown.entries[parent] as OntimeGroup).entries = [...children];
|
||||
children = [];
|
||||
}
|
||||
parent = entry.id;
|
||||
append({
|
||||
id: entry.id,
|
||||
type: SupportedEntry.Block,
|
||||
type: SupportedEntry.Group,
|
||||
title: entry.title,
|
||||
note: '', // leave blank
|
||||
entries: [], // leave empty
|
||||
@@ -418,7 +419,7 @@ export function migrateRundown(
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
(newRundown.entries[parent] as OntimeBlock).entries = [...children];
|
||||
(newRundown.entries[parent] as OntimeGroup).entries = [...children];
|
||||
children = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ describe('v3 to v4', () => {
|
||||
dayOffset: 0,
|
||||
gap: 0,
|
||||
},
|
||||
{ id: 'block0', type: 'block', title: 'BLOCK 0' },
|
||||
{ id: 'group0', type: 'block', title: 'GROUP 0' },
|
||||
{
|
||||
id: 'event2',
|
||||
type: SupportedEntry.Event,
|
||||
@@ -107,7 +107,7 @@ describe('v3 to v4', () => {
|
||||
dayOffset: 0,
|
||||
gap: 0,
|
||||
},
|
||||
{ id: 'block1', type: 'block', title: 'BLOCK 1' },
|
||||
{ id: 'group1', type: 'block', title: 'GROUP 1' },
|
||||
{ id: 'delay', type: 'delay', duration: 1000 },
|
||||
],
|
||||
project: {
|
||||
@@ -268,8 +268,8 @@ describe('v3 to v4', () => {
|
||||
const expectedRundown: Rundown = {
|
||||
id: 'default',
|
||||
title: 'Default',
|
||||
order: ['event1', 'block0', 'block1'],
|
||||
flatOrder: ['event1', 'block0', 'event2', 'event3', 'block1', 'delay'],
|
||||
order: ['event1', 'group0', 'group1'],
|
||||
flatOrder: ['event1', 'group0', 'event2', 'event3', 'group1', 'delay'],
|
||||
entries: {
|
||||
event1: {
|
||||
id: 'event1',
|
||||
@@ -298,10 +298,10 @@ describe('v3 to v4', () => {
|
||||
dayOffset: 0,
|
||||
gap: 0,
|
||||
},
|
||||
block0: {
|
||||
id: 'block0',
|
||||
type: SupportedEntry.Block,
|
||||
title: 'BLOCK 0',
|
||||
group0: {
|
||||
id: 'group0',
|
||||
type: SupportedEntry.Group,
|
||||
title: 'GROUP 0',
|
||||
colour: '',
|
||||
custom: {},
|
||||
duration: 0,
|
||||
@@ -337,7 +337,7 @@ describe('v3 to v4', () => {
|
||||
},
|
||||
triggers: [{ id: 'testTrig', title: 'Test trigger', trigger: TimerLifeCycle.onStart, automationId: '1' }],
|
||||
flag: false,
|
||||
parent: 'block0',
|
||||
parent: 'group0',
|
||||
revision: -1,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
@@ -368,16 +368,16 @@ describe('v3 to v4', () => {
|
||||
},
|
||||
triggers: [{ id: 'testTrig', title: 'Test trigger', trigger: TimerLifeCycle.onStart, automationId: '1' }],
|
||||
flag: false,
|
||||
parent: 'block0',
|
||||
parent: 'group0',
|
||||
revision: -1,
|
||||
delay: 0,
|
||||
dayOffset: 0,
|
||||
gap: 0,
|
||||
},
|
||||
block1: {
|
||||
id: 'block1',
|
||||
type: SupportedEntry.Block,
|
||||
title: 'BLOCK 1',
|
||||
group1: {
|
||||
id: 'group1',
|
||||
type: SupportedEntry.Group,
|
||||
title: 'GROUP 1',
|
||||
colour: '',
|
||||
custom: {},
|
||||
duration: 0,
|
||||
@@ -393,7 +393,7 @@ describe('v3 to v4', () => {
|
||||
type: SupportedEntry.Delay,
|
||||
id: 'delay',
|
||||
duration: 1000,
|
||||
parent: 'block1',
|
||||
parent: 'group1',
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -156,10 +156,10 @@ describe('parseExcel()', () => {
|
||||
expect((firstEvent as OntimeEvent).title).toBe('A song from the hearth');
|
||||
});
|
||||
|
||||
it('imports blocks', () => {
|
||||
it('imports groups', () => {
|
||||
const testdata = [
|
||||
['Title', 'Timer type'],
|
||||
['a block', 'block'],
|
||||
['a group', 'group'],
|
||||
['an event', 'clock'],
|
||||
];
|
||||
|
||||
@@ -171,7 +171,7 @@ describe('parseExcel()', () => {
|
||||
const firstEvent = result.rundown.entries[result.rundown.order[0]];
|
||||
|
||||
expect(result.rundown.order.length).toBe(2);
|
||||
expect((firstEvent as OntimeEvent).type).toBe(SupportedEntry.Block);
|
||||
expect((firstEvent as OntimeEvent).type).toBe(SupportedEntry.Group);
|
||||
});
|
||||
|
||||
it('imports as events if there is no timer type column', () => {
|
||||
@@ -301,8 +301,8 @@ describe('parseExcel()', () => {
|
||||
['9:45:00', '10:56:00', 'B', 'x', 'count-down'],
|
||||
['10:00:00', '16:36:00', 'C', 'x', 'count-down'],
|
||||
['21:45:00', '22:56:00', 'D', '', 'count-down'],
|
||||
['', '', 'BLOCK', 'x', 'block'], // <-- block with link
|
||||
['00:0:00', '23:56:00', 'E', 'x', 'count-down'], // <-- link past blocks
|
||||
['', '', 'GROUP', 'x', 'group'], // <-- group with link
|
||||
['00:0:00', '23:56:00', 'E', 'x', 'count-down'], // <-- must link past previous group
|
||||
];
|
||||
|
||||
const importMap = {
|
||||
@@ -315,7 +315,7 @@ describe('parseExcel()', () => {
|
||||
|
||||
const result = parseExcel(testData, {}, 'testSheet', importMap);
|
||||
expect(result.rundown.order.length).toBe(6);
|
||||
expect(result.rundown.order).toMatchObject(['A', 'B', 'C', 'D', 'BLOCK', 'E']);
|
||||
expect(result.rundown.order).toMatchObject(['A', 'B', 'C', 'D', 'GROUP', 'E']);
|
||||
|
||||
expect(result.rundown.entries).toMatchObject({
|
||||
A: {
|
||||
@@ -330,8 +330,8 @@ describe('parseExcel()', () => {
|
||||
D: {
|
||||
linkStart: false,
|
||||
},
|
||||
BLOCK: {
|
||||
type: SupportedEntry.Block,
|
||||
GROUP: {
|
||||
type: SupportedEntry.Group,
|
||||
},
|
||||
E: {
|
||||
linkStart: true,
|
||||
|
||||
@@ -2,10 +2,10 @@ import {
|
||||
CustomFields,
|
||||
Rundown,
|
||||
OntimeEvent,
|
||||
OntimeBlock,
|
||||
OntimeGroup,
|
||||
EntryCustomFields,
|
||||
SupportedEntry,
|
||||
isOntimeBlock,
|
||||
isOntimeGroup,
|
||||
TimerType,
|
||||
CustomFieldKey,
|
||||
} from 'ontime-types';
|
||||
@@ -31,6 +31,7 @@ import { parseExcelDate } from '../../utils/time.js';
|
||||
* @param {array} excelData - array with excel sheet
|
||||
* @param {ImportOptions} options - an object that contains the import map
|
||||
* @returns {object} - parsed object
|
||||
* TODO: import milestones
|
||||
*/
|
||||
export const parseExcel = (
|
||||
excelData: unknown[][],
|
||||
@@ -170,7 +171,7 @@ export const parseExcel = (
|
||||
},
|
||||
} as const;
|
||||
|
||||
const entry: Partial<Merge<OntimeEvent, OntimeBlock>> = {};
|
||||
const entry: Partial<Merge<OntimeEvent, OntimeGroup>> = {};
|
||||
const entryCustomFields: EntryCustomFields = {};
|
||||
|
||||
for (let j = 0; j < row.length; j++) {
|
||||
@@ -178,16 +179,16 @@ export const parseExcel = (
|
||||
// 1. we check if we have set a flag for a known field
|
||||
if (j === timerTypeIndex) {
|
||||
const maybeTimeType = makeString(column, '');
|
||||
if (maybeTimeType === 'block') {
|
||||
if (maybeTimeType === 'group') {
|
||||
// we leave this as a clue for the object filtering later on
|
||||
entry.type = SupportedEntry.Block;
|
||||
entry.type = SupportedEntry.Group;
|
||||
entry.entries = [];
|
||||
} else if (maybeTimeType === '' || maybeTimeType === 'event' || isKnownTimerType(maybeTimeType)) {
|
||||
// @ts-expect-error -- we leave this as a clue for the object filtering later on
|
||||
entry.type = SupportedEntry.Event;
|
||||
entry.timerType = validateTimerType(maybeTimeType);
|
||||
} else {
|
||||
// if it is not a block or a known type, we dont import it
|
||||
// if it is not a group or a known type, we dont import it
|
||||
return;
|
||||
}
|
||||
} else if (j === titleIndex) {
|
||||
@@ -258,11 +259,11 @@ export const parseExcel = (
|
||||
}
|
||||
|
||||
const id = entry.id || generateId();
|
||||
// from excel, we can only get blocks and events
|
||||
if (isOntimeBlock(entry)) {
|
||||
const block: OntimeBlock = { ...entry, custom: { ...entryCustomFields } };
|
||||
// from excel, we can only get groups, milestones and events
|
||||
if (isOntimeGroup(entry)) {
|
||||
const group: OntimeGroup = { ...entry, custom: { ...entryCustomFields } };
|
||||
rundown.order.push(id);
|
||||
rundown.entries[id] = block;
|
||||
rundown.entries[id] = group;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
SupportedEntry,
|
||||
OntimeEvent,
|
||||
OntimeDelay,
|
||||
OntimeBlock,
|
||||
OntimeGroup,
|
||||
Rundown,
|
||||
CustomField,
|
||||
OntimeMilestone,
|
||||
@@ -16,8 +16,8 @@ const baseEvent = {
|
||||
revision: 1,
|
||||
};
|
||||
|
||||
const baseBlock = {
|
||||
type: SupportedEntry.Block,
|
||||
const baseGroup = {
|
||||
type: SupportedEntry.Group,
|
||||
entries: [],
|
||||
};
|
||||
|
||||
@@ -28,7 +28,7 @@ const baseMilestone = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility to create a Ontime event
|
||||
* Utility to create an Ontime event
|
||||
*/
|
||||
export function makeOntimeEvent(patch: Partial<OntimeEvent>): OntimeEvent {
|
||||
return {
|
||||
@@ -38,21 +38,21 @@ export function makeOntimeEvent(patch: Partial<OntimeEvent>): OntimeEvent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to create a delay event
|
||||
* Utility to create a delay entry
|
||||
*/
|
||||
export function makeOntimeDelay(patch: Partial<OntimeDelay>): OntimeDelay {
|
||||
return { id: 'delay', type: SupportedEntry.Delay, duration: 0, ...patch } as OntimeDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to create a block event
|
||||
* Utility to create a group entry
|
||||
*/
|
||||
export function makeOntimeBlock(patch: Partial<OntimeBlock>): OntimeBlock {
|
||||
return { id: 'block', ...baseBlock, ...patch } as OntimeBlock;
|
||||
export function makeOntimeGroup(patch: Partial<OntimeGroup>): OntimeGroup {
|
||||
return { id: 'group', ...baseGroup, ...patch } as OntimeGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to create a block event
|
||||
* Utility to create a milestone entry
|
||||
*/
|
||||
export function makeOntimeMilestone(patch: Partial<OntimeMilestone>): OntimeMilestone {
|
||||
return { id: 'milestone', ...baseMilestone, ...patch } as OntimeMilestone;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { CustomFields, OntimeBlock, OntimeDelay, OntimeEvent, SupportedEntry, TimeStrategy } from 'ontime-types';
|
||||
import { CustomFields, OntimeGroup, OntimeDelay, OntimeEvent, SupportedEntry, TimeStrategy } from 'ontime-types';
|
||||
import { dayInMs, MILLIS_PER_HOUR, MILLIS_PER_MINUTE } from 'ontime-utils';
|
||||
|
||||
import {
|
||||
makeOntimeEvent,
|
||||
makeRundown,
|
||||
makeOntimeBlock,
|
||||
makeOntimeGroup,
|
||||
makeOntimeDelay,
|
||||
makeCustomField,
|
||||
} from '../__mocks__/rundown.mocks.js';
|
||||
@@ -112,7 +112,7 @@ describe('processRundown()', () => {
|
||||
order: ['1', '2', '3'],
|
||||
entries: {
|
||||
'1': makeOntimeEvent({ id: '1' }),
|
||||
'2': makeOntimeBlock({ id: '2' }),
|
||||
'2': makeOntimeGroup({ id: '2' }),
|
||||
'3': makeOntimeDelay({ id: '3' }),
|
||||
},
|
||||
});
|
||||
@@ -121,7 +121,7 @@ describe('processRundown()', () => {
|
||||
expect(initResult.order.length).toBe(3);
|
||||
expect(initResult.order).toStrictEqual(['1', '2', '3']);
|
||||
expect(initResult.entries['1'].type).toBe(SupportedEntry.Event);
|
||||
expect(initResult.entries['2'].type).toBe(SupportedEntry.Block);
|
||||
expect(initResult.entries['2'].type).toBe(SupportedEntry.Group);
|
||||
expect(initResult.entries['3'].type).toBe(SupportedEntry.Delay);
|
||||
});
|
||||
|
||||
@@ -142,14 +142,14 @@ describe('processRundown()', () => {
|
||||
|
||||
it('accounts for gaps in rundown when calculating delays', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', 'delay', '2', 'block', '3', 'another-block', '4'],
|
||||
order: ['1', 'delay', '2', 'group', '3', 'another-group', '4'],
|
||||
entries: {
|
||||
'1': makeOntimeEvent({ id: '1', timeStart: 100, timeEnd: 200, duration: 100 }),
|
||||
delay: makeOntimeDelay({ id: 'delay', duration: 200 }),
|
||||
'2': makeOntimeEvent({ id: '2', timeStart: 200, timeEnd: 300, duration: 100 }),
|
||||
block: makeOntimeBlock({ id: 'block', title: 'break' }),
|
||||
group: makeOntimeGroup({ id: 'group', title: 'break' }),
|
||||
'3': makeOntimeEvent({ id: '3', timeStart: 400, timeEnd: 500, duration: 100 }),
|
||||
'another-block': makeOntimeBlock({ id: 'another-block', title: 'another-break' }),
|
||||
'another-group': makeOntimeGroup({ id: 'another-group', title: 'another-break' }),
|
||||
'4': makeOntimeEvent({ id: '4', timeStart: 600, timeEnd: 700, duration: 100 }),
|
||||
},
|
||||
});
|
||||
@@ -297,14 +297,14 @@ describe('processRundown()', () => {
|
||||
|
||||
it('handles negative delays', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', 'delay', '2', 'block', '3', 'another-block', '4'],
|
||||
order: ['1', 'delay', '2', 'group', '3', 'another-group', '4'],
|
||||
entries: {
|
||||
'1': makeOntimeEvent({ id: '1', timeStart: 100, timeEnd: 200, duration: 100 }),
|
||||
delay: makeOntimeDelay({ id: 'delay', duration: -200 }),
|
||||
'2': makeOntimeEvent({ id: '2', timeStart: 200, timeEnd: 300, duration: 100 }),
|
||||
block: makeOntimeBlock({ id: 'block', title: 'break' }),
|
||||
group: makeOntimeGroup({ id: 'group', title: 'break' }),
|
||||
'3': makeOntimeEvent({ id: '3', timeStart: 400, timeEnd: 500, duration: 100 }),
|
||||
'another-block': makeOntimeBlock({ id: 'another-block', title: 'another-break' }),
|
||||
'another-group': makeOntimeGroup({ id: 'another-group', title: 'another-break' }),
|
||||
'4': makeOntimeEvent({ id: '4', timeStart: 600, timeEnd: 700, duration: 100 }),
|
||||
},
|
||||
});
|
||||
@@ -321,7 +321,7 @@ describe('processRundown()', () => {
|
||||
|
||||
it('links times across events', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '2', 'block', 'delay', '3'],
|
||||
order: ['1', '2', 'group', 'delay', '3'],
|
||||
entries: {
|
||||
'1': makeOntimeEvent({
|
||||
id: '1',
|
||||
@@ -338,7 +338,7 @@ describe('processRundown()', () => {
|
||||
linkStart: true,
|
||||
timeStrategy: TimeStrategy.LockEnd,
|
||||
}),
|
||||
block: makeOntimeBlock({ id: 'block' }),
|
||||
group: makeOntimeGroup({ id: 'group' }),
|
||||
delay: makeOntimeDelay({ id: 'delay' }),
|
||||
'3': makeOntimeEvent({
|
||||
id: '3',
|
||||
@@ -570,7 +570,7 @@ describe('processRundown()', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['100', '200', '300'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['100', '200', '300'] }),
|
||||
'100': makeOntimeEvent({ id: '100', timeStart: 100, timeEnd: 200, duration: 100, linkStart: false }),
|
||||
'200': makeOntimeEvent({ id: '200', timeStart: 200, timeEnd: 300, duration: 100 }),
|
||||
'300': makeOntimeEvent({ id: '300', timeStart: 300, timeEnd: 400, duration: 100 }),
|
||||
@@ -583,7 +583,7 @@ describe('processRundown()', () => {
|
||||
expect(generatedRundown.totalDelay).toBe(0);
|
||||
expect(generatedRundown.entries).toMatchObject({
|
||||
'1': {
|
||||
type: SupportedEntry.Block,
|
||||
type: SupportedEntry.Group,
|
||||
entries: ['100', '200', '300'],
|
||||
timeStart: 100,
|
||||
timeEnd: 400,
|
||||
@@ -601,15 +601,15 @@ describe('processRundown()', () => {
|
||||
order: ['0', '1', '2', '3'],
|
||||
entries: {
|
||||
'0': makeOntimeEvent({ id: '0', timeStart: 0, timeEnd: 10, duration: 10, linkStart: false }),
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['101', '102', '103'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['101', '102', '103'] }),
|
||||
'101': makeOntimeEvent({ id: '101', timeStart: 100, timeEnd: 200, duration: 100, linkStart: false }),
|
||||
'102': makeOntimeEvent({ id: '102', timeStart: 200, timeEnd: 300, duration: 100, linkStart: true }),
|
||||
'103': makeOntimeEvent({ id: '103', timeStart: 300, timeEnd: 400, duration: 100, linkStart: true }),
|
||||
'2': makeOntimeBlock({ id: '2', entries: ['201', '202', '203'] }),
|
||||
'2': makeOntimeGroup({ id: '2', entries: ['201', '202', '203'] }),
|
||||
'201': makeOntimeEvent({ id: '201', timeStart: 500, timeEnd: 600, duration: 100, linkStart: false }),
|
||||
'202': makeOntimeEvent({ id: '202', timeStart: 600, timeEnd: 700, duration: 100, linkStart: true }),
|
||||
'203': makeOntimeEvent({ id: '203', timeStart: 700, timeEnd: 800, duration: 100, linkStart: true }),
|
||||
'3': makeOntimeBlock({ id: '3', entries: ['301', '302', '303'] }),
|
||||
'3': makeOntimeGroup({ id: '3', entries: ['301', '302', '303'] }),
|
||||
'301': makeOntimeEvent({ id: '301', timeStart: 900, timeEnd: 1000, duration: 100, linkStart: false }),
|
||||
'302': makeOntimeEvent({ id: '302', timeStart: 1000, timeEnd: 1100, duration: 100, linkStart: true }),
|
||||
'303': makeOntimeEvent({ id: '303', timeStart: 1100, timeEnd: 1200, duration: 100, linkStart: true }),
|
||||
@@ -623,7 +623,7 @@ describe('processRundown()', () => {
|
||||
expect(generatedRundown.entries).toMatchObject({
|
||||
'0': { type: SupportedEntry.Event, parent: null },
|
||||
'1': {
|
||||
type: SupportedEntry.Block,
|
||||
type: SupportedEntry.Group,
|
||||
entries: ['101', '102', '103'],
|
||||
timeStart: 100,
|
||||
timeEnd: 400,
|
||||
@@ -634,7 +634,7 @@ describe('processRundown()', () => {
|
||||
'102': { parent: '1' },
|
||||
'103': { parent: '1' },
|
||||
'2': {
|
||||
type: SupportedEntry.Block,
|
||||
type: SupportedEntry.Group,
|
||||
entries: ['201', '202', '203'],
|
||||
timeStart: 500,
|
||||
timeEnd: 800,
|
||||
@@ -645,7 +645,7 @@ describe('processRundown()', () => {
|
||||
'202': { id: '202', timeStart: 600, timeEnd: 700, duration: 100 },
|
||||
'203': { id: '203', timeStart: 700, timeEnd: 800, duration: 100 },
|
||||
'3': {
|
||||
type: SupportedEntry.Block,
|
||||
type: SupportedEntry.Group,
|
||||
entries: ['301', '302', '303'],
|
||||
timeStart: 900,
|
||||
timeEnd: 1200,
|
||||
@@ -688,36 +688,36 @@ describe('rundownMutation.add()', () => {
|
||||
expect(rundown.entries['mock']).toMatchObject(mockEvent);
|
||||
});
|
||||
|
||||
test('adds an event at the top of the block if no after is given', () => {
|
||||
test('adds an event at the top of the group if no after is given', () => {
|
||||
const mockEvent = makeOntimeEvent({ id: 'mock', cue: 'mock' });
|
||||
const rundown = makeRundown({
|
||||
flatOrder: ['1', '1a'],
|
||||
order: ['1'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1' }),
|
||||
'1': makeOntimeGroup({ id: '1' }),
|
||||
'1a': makeOntimeEvent({ id: '1a', parent: '1' }),
|
||||
},
|
||||
});
|
||||
|
||||
rundownMutation.add(rundown, mockEvent, null, rundown.entries['1'] as OntimeBlock);
|
||||
rundownMutation.add(rundown, mockEvent, null, rundown.entries['1'] as OntimeGroup);
|
||||
|
||||
expect(rundown.order).toStrictEqual(['1']);
|
||||
expect(rundown.flatOrder).toStrictEqual(['1', 'mock', '1a']);
|
||||
expect(rundown.entries['mock']).toMatchObject(mockEvent);
|
||||
});
|
||||
|
||||
test('adds an event at the a given location inside a block', () => {
|
||||
test('adds an event at the a given location inside a group', () => {
|
||||
const mockEvent = makeOntimeEvent({ id: 'mock', cue: 'mock' });
|
||||
const rundown = makeRundown({
|
||||
flatOrder: ['1', '1a'],
|
||||
order: ['1'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1' }),
|
||||
'1': makeOntimeGroup({ id: '1' }),
|
||||
'1a': makeOntimeEvent({ id: '1a', parent: '1' }),
|
||||
},
|
||||
});
|
||||
|
||||
rundownMutation.add(rundown, mockEvent, '1a', rundown.entries['1'] as OntimeBlock);
|
||||
rundownMutation.add(rundown, mockEvent, '1a', rundown.entries['1'] as OntimeGroup);
|
||||
|
||||
expect(rundown.order).toStrictEqual(['1']);
|
||||
expect(rundown.flatOrder).toStrictEqual(['1', '1a', 'mock']);
|
||||
@@ -785,11 +785,11 @@ describe('rundownMutation.remove()', () => {
|
||||
expect(rundown.entries['3']).not.toBeUndefined();
|
||||
});
|
||||
|
||||
it('deletes a block and its children', () => {
|
||||
it('deletes a group and its children', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '4'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['2', '3'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['2', '3'] }),
|
||||
'2': makeOntimeEvent({ id: '2', parent: '1' }),
|
||||
'3': makeOntimeDelay({ id: '3', parent: '1' }),
|
||||
'4': makeOntimeEvent({ id: '4', parent: null }),
|
||||
@@ -811,7 +811,7 @@ describe('rundownMutation.remove()', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '4'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['2', '3'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['2', '3'] }),
|
||||
'2': makeOntimeEvent({ id: '2', parent: '1' }),
|
||||
'3': makeOntimeDelay({ id: '3', parent: '1' }),
|
||||
'4': makeOntimeEvent({ id: '4', parent: null }),
|
||||
@@ -849,11 +849,11 @@ describe('rundownMutation.removeAll()', () => {
|
||||
});
|
||||
|
||||
describe('rundownMutation.reorder()', () => {
|
||||
it('moves an event into a block', () => {
|
||||
it('moves an event into a group', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '2', '3'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: [] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: [] }),
|
||||
'2': makeOntimeEvent({ id: '2', parent: null }),
|
||||
'3': makeOntimeEvent({ id: '3', parent: null }),
|
||||
},
|
||||
@@ -870,12 +870,12 @@ describe('rundownMutation.reorder()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('adds an event into a block', () => {
|
||||
it('adds an event into a group', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '2'],
|
||||
flatOrder: ['1', '11', '2'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['11'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['11'] }),
|
||||
'11': makeOntimeEvent({ id: '11', parent: '1' }),
|
||||
'2': makeOntimeEvent({ id: '2', parent: null }),
|
||||
},
|
||||
@@ -926,12 +926,12 @@ describe('rundownMutation.reorder()', () => {
|
||||
expect(rundown.order).toStrictEqual(['3', '1', '2']);
|
||||
});
|
||||
|
||||
it('moves an event out and before a block', () => {
|
||||
it('moves an event out and before a group', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '2'],
|
||||
flatOrder: ['1', '11', '2'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['11'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['11'] }),
|
||||
'11': makeOntimeEvent({ id: '11', parent: '1' }),
|
||||
'2': makeOntimeEvent({ id: '2', parent: null }),
|
||||
},
|
||||
@@ -951,22 +951,22 @@ describe('rundownMutation.reorder()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('moves an event out and after a block', () => {
|
||||
it('moves an event out and after a group', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', 'block', '2'],
|
||||
flatOrder: ['1', 'block', '11', '2'],
|
||||
order: ['1', 'group', '2'],
|
||||
flatOrder: ['1', 'group', '11', '2'],
|
||||
entries: {
|
||||
'1': makeOntimeEvent({ id: '1', parent: null }),
|
||||
block: makeOntimeBlock({ id: 'block', entries: ['11'] }),
|
||||
'11': makeOntimeEvent({ id: '11', parent: 'block' }),
|
||||
group: makeOntimeGroup({ id: 'group', entries: ['11'] }),
|
||||
'11': makeOntimeEvent({ id: '11', parent: 'group' }),
|
||||
'2': makeOntimeEvent({ id: '2', parent: null }),
|
||||
},
|
||||
});
|
||||
|
||||
rundownMutation.reorder(rundown, rundown.entries['11'], rundown.entries['block'], 'after');
|
||||
rundownMutation.reorder(rundown, rundown.entries['11'], rundown.entries['group'], 'after');
|
||||
|
||||
expect(rundown.order).toStrictEqual(['1', 'block', '11', '2']);
|
||||
expect(rundown.entries['block']).toMatchObject({
|
||||
expect(rundown.order).toStrictEqual(['1', 'group', '11', '2']);
|
||||
expect(rundown.entries['group']).toMatchObject({
|
||||
entries: [],
|
||||
});
|
||||
expect(rundown.entries['11']).toMatchObject({
|
||||
@@ -977,14 +977,14 @@ describe('rundownMutation.reorder()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('moves an event between blocks', () => {
|
||||
it('moves an event between groups', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '2'],
|
||||
flatOrder: ['1', '11', '2', '22'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['11'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['11'] }),
|
||||
'11': makeOntimeEvent({ id: '11', parent: '1' }),
|
||||
'2': makeOntimeBlock({ id: '2', entries: ['22'] }),
|
||||
'2': makeOntimeGroup({ id: '2', entries: ['22'] }),
|
||||
'22': makeOntimeEvent({ id: '22', parent: '2' }),
|
||||
},
|
||||
});
|
||||
@@ -1003,13 +1003,13 @@ describe('rundownMutation.reorder()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('moves an event into an empty block', () => {
|
||||
it('moves an event into an empty group', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '2'],
|
||||
flatOrder: ['1', '2', '22'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: [] }),
|
||||
'2': makeOntimeBlock({ id: '2', entries: ['22'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: [] }),
|
||||
'2': makeOntimeGroup({ id: '2', entries: ['22'] }),
|
||||
'22': makeOntimeEvent({ id: '22', parent: '2' }),
|
||||
},
|
||||
});
|
||||
@@ -1028,14 +1028,14 @@ describe('rundownMutation.reorder()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('moves an event out of a block (up)', () => {
|
||||
it('moves an event out of a group (up)', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '2'],
|
||||
flatOrder: ['1', '11', '2', '22'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['11'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['11'] }),
|
||||
'11': makeOntimeEvent({ id: '11', parent: '1' }),
|
||||
'2': makeOntimeBlock({ id: '2', entries: ['22'] }),
|
||||
'2': makeOntimeGroup({ id: '2', entries: ['22'] }),
|
||||
'22': makeOntimeEvent({ id: '22', parent: '2' }),
|
||||
},
|
||||
});
|
||||
@@ -1059,14 +1059,14 @@ describe('rundownMutation.reorder()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('moves an event out of a block (down)', () => {
|
||||
it('moves an event out of a group (down)', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '2'],
|
||||
flatOrder: ['1', '11', '2', '22'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['11'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['11'] }),
|
||||
'11': makeOntimeEvent({ id: '11', parent: '1' }),
|
||||
'2': makeOntimeBlock({ id: '2', entries: ['22'] }),
|
||||
'2': makeOntimeGroup({ id: '2', entries: ['22'] }),
|
||||
'22': makeOntimeEvent({ id: '22', parent: '2' }),
|
||||
},
|
||||
});
|
||||
@@ -1088,14 +1088,14 @@ describe('rundownMutation.reorder()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('moves a block (up)', () => {
|
||||
it('moves a group (up)', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '2'],
|
||||
flatOrder: ['1', '11', '2', '22'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['11'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['11'] }),
|
||||
'11': makeOntimeEvent({ id: '11', parent: '1' }),
|
||||
'2': makeOntimeBlock({ id: '2', entries: ['22'] }),
|
||||
'2': makeOntimeGroup({ id: '2', entries: ['22'] }),
|
||||
'22': makeOntimeEvent({ id: '22', parent: '2' }),
|
||||
},
|
||||
});
|
||||
@@ -1105,14 +1105,14 @@ describe('rundownMutation.reorder()', () => {
|
||||
expect(rundown.order).toStrictEqual(['2', '1']);
|
||||
});
|
||||
|
||||
it('moves a block (down)', () => {
|
||||
it('moves a group (down)', () => {
|
||||
const rundown = makeRundown({
|
||||
order: ['1', '2'],
|
||||
flatOrder: ['1', '11', '2', '22'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['11'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['11'] }),
|
||||
'11': makeOntimeEvent({ id: '11', parent: '1' }),
|
||||
'2': makeOntimeBlock({ id: '2', entries: ['22'] }),
|
||||
'2': makeOntimeGroup({ id: '2', entries: ['22'] }),
|
||||
'22': makeOntimeEvent({ id: '22', parent: '2' }),
|
||||
},
|
||||
});
|
||||
@@ -1132,7 +1132,7 @@ describe('rundownMutation.applyDelay()', () => {
|
||||
delay: makeOntimeDelay({ id: 'delay', duration: 10 }),
|
||||
'1': makeOntimeEvent({ id: '1', timeStart: 0, timeEnd: 10, duration: 10 }),
|
||||
'2': makeOntimeEvent({ id: '2', timeStart: 10, timeEnd: 20, duration: 10, linkStart: true }),
|
||||
'3': makeOntimeBlock({ id: '3' }),
|
||||
'3': makeOntimeGroup({ id: '3' }),
|
||||
'4': makeOntimeEvent({ id: '4', timeStart: 20, timeEnd: 30, duration: 10, linkStart: false }),
|
||||
'5': makeOntimeEvent({ id: '5', timeStart: 30, timeEnd: 40, duration: 10, linkStart: true }),
|
||||
},
|
||||
@@ -1158,7 +1158,7 @@ describe('rundownMutation.applyDelay()', () => {
|
||||
delay: makeOntimeDelay({ id: 'delay', duration: -10 }),
|
||||
'1': makeOntimeEvent({ id: '1', timeStart: 0, timeEnd: 10, duration: 10 }),
|
||||
'2': makeOntimeEvent({ id: '2', timeStart: 10, timeEnd: 20, duration: 10, linkStart: true }),
|
||||
'3': makeOntimeBlock({ id: '3' }),
|
||||
'3': makeOntimeGroup({ id: '3' }),
|
||||
'4': makeOntimeEvent({ id: '4', timeStart: 20, timeEnd: 30, duration: 10, linkStart: false }),
|
||||
'5': makeOntimeEvent({ id: '5', timeStart: 30, timeEnd: 40, duration: 10, linkStart: true }),
|
||||
},
|
||||
@@ -1398,13 +1398,13 @@ describe('rundownMutation.applyDelay()', () => {
|
||||
expect(testRundown.entries).toMatchObject({ '1': { id: '1', timeStart: 0, timeEnd: 100, duration: 100 } });
|
||||
});
|
||||
|
||||
it('unlinks events to across blocks is it is the first event after the delay', () => {
|
||||
it('unlinks events to across groups is it is the first event after the delay', () => {
|
||||
const testRundown = makeRundown({
|
||||
order: ['1', 'delay', 'block', '2'],
|
||||
order: ['1', 'delay', 'group', '2'],
|
||||
entries: {
|
||||
'1': makeOntimeEvent({ id: '1', timeStart: 0, timeEnd: 100, duration: 100, revision: 1 }),
|
||||
delay: makeOntimeDelay({ id: 'delay', duration: 50 }),
|
||||
block: makeOntimeBlock({ id: 'block' }),
|
||||
group: makeOntimeGroup({ id: 'group' }),
|
||||
'2': makeOntimeEvent({ id: '2', timeStart: 100, timeEnd: 150, duration: 50, revision: 1, linkStart: true }),
|
||||
},
|
||||
});
|
||||
@@ -1420,7 +1420,7 @@ describe('rundownMutation.applyDelay()', () => {
|
||||
duration: 100,
|
||||
revision: 1,
|
||||
},
|
||||
block: { id: 'block' },
|
||||
group: { id: 'group' },
|
||||
'2': {
|
||||
id: '2',
|
||||
timeStart: 150,
|
||||
@@ -1432,13 +1432,13 @@ describe('rundownMutation.applyDelay()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('applies a delay from inside a block', () => {
|
||||
it('applies a delay from inside a group', () => {
|
||||
const testRundown = makeRundown({
|
||||
order: ['1', 'block', '2', '3'],
|
||||
order: ['1', 'group', '2', '3'],
|
||||
entries: {
|
||||
'1': makeOntimeEvent({ id: '1', timeStart: 0, timeEnd: 100, duration: 100 }),
|
||||
block: makeOntimeBlock({ id: 'block', entries: ['delay'] }),
|
||||
delay: makeOntimeDelay({ id: 'delay', duration: 100, parent: 'block' }),
|
||||
group: makeOntimeGroup({ id: 'group', entries: ['delay'] }),
|
||||
delay: makeOntimeDelay({ id: 'delay', duration: 100, parent: 'group' }),
|
||||
'2': makeOntimeEvent({ id: '2', timeStart: 100, timeEnd: 200, duration: 100, linkStart: true }),
|
||||
'3': makeOntimeEvent({ id: '3', timeStart: 200, timeEnd: 300, duration: 100, linkStart: true }),
|
||||
},
|
||||
@@ -1476,18 +1476,18 @@ describe('rundownMutation.applyDelay()', () => {
|
||||
|
||||
it('applies a delay from across nested orders', () => {
|
||||
const testRundown = makeRundown({
|
||||
order: ['1', 'delay', 'block', '2', '3'],
|
||||
order: ['1', 'delay', 'group', '2', '3'],
|
||||
entries: {
|
||||
'1': makeOntimeEvent({ id: '1', timeStart: 0, timeEnd: 100, duration: 100 }),
|
||||
delay: makeOntimeDelay({ id: 'delay', duration: 100 }),
|
||||
block: makeOntimeBlock({ id: 'block', entries: ['block-1'] }),
|
||||
'block-1': makeOntimeEvent({
|
||||
id: 'block-1',
|
||||
group: makeOntimeGroup({ id: 'group', entries: ['group-1'] }),
|
||||
'group-1': makeOntimeEvent({
|
||||
id: 'group-1',
|
||||
timeStart: 100,
|
||||
timeEnd: 200,
|
||||
duration: 100,
|
||||
linkStart: true,
|
||||
parent: 'block',
|
||||
parent: 'group',
|
||||
}),
|
||||
'2': makeOntimeEvent({ id: '2', timeStart: 200, timeEnd: 300, duration: 100, linkStart: true }),
|
||||
'3': makeOntimeEvent({ id: '3', timeStart: 300, timeEnd: 400, duration: 100, linkStart: true }),
|
||||
@@ -1504,7 +1504,7 @@ describe('rundownMutation.applyDelay()', () => {
|
||||
duration: 100,
|
||||
revision: 1,
|
||||
},
|
||||
'block-1': {
|
||||
'group-1': {
|
||||
timeStart: 200,
|
||||
timeEnd: 300,
|
||||
duration: 100,
|
||||
@@ -1579,11 +1579,11 @@ describe('rundownMutation.clone()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('clones an event inside a block and adds it to the rundown', () => {
|
||||
it('clones an event inside a group and adds it to the rundown', () => {
|
||||
const testRundown = makeRundown({
|
||||
order: ['1'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', entries: ['1a'] }),
|
||||
'1': makeOntimeGroup({ id: '1', entries: ['1a'] }),
|
||||
'1a': makeOntimeEvent({ id: '1a', cue: 'nested', parent: '1' }),
|
||||
},
|
||||
});
|
||||
@@ -1599,11 +1599,11 @@ describe('rundownMutation.clone()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('clones a block and its nested elements', () => {
|
||||
it('clones a group and its nested elements', () => {
|
||||
const testRundown = makeRundown({
|
||||
order: ['1'],
|
||||
entries: {
|
||||
'1': makeOntimeBlock({ id: '1', title: 'top', entries: ['1a'] }),
|
||||
'1': makeOntimeGroup({ id: '1', title: 'top', entries: ['1a'] }),
|
||||
'1a': makeOntimeEvent({ id: '1a', cue: 'nested', parent: '1' }),
|
||||
},
|
||||
});
|
||||
@@ -1612,10 +1612,10 @@ describe('rundownMutation.clone()', () => {
|
||||
|
||||
expect(testRundown.order).toStrictEqual(['1', newEntry.id]);
|
||||
expect(testRundown.entries[newEntry.id]).toMatchObject({
|
||||
type: SupportedEntry.Block,
|
||||
type: SupportedEntry.Group,
|
||||
entries: [expect.any(String)],
|
||||
});
|
||||
expect((testRundown.entries[newEntry.id] as OntimeBlock).entries[0]).not.toBe('1a');
|
||||
expect((testRundown.entries[newEntry.id] as OntimeGroup).entries[0]).not.toBe('1a');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1632,34 +1632,34 @@ describe('rundownMutation.group()', () => {
|
||||
|
||||
rundownMutation.group(rundown, ['1', '2']);
|
||||
|
||||
const blockId = rundown.order[0];
|
||||
expect(blockId).toStrictEqual(expect.any(String));
|
||||
const groupId = rundown.order[0];
|
||||
expect(groupId).toStrictEqual(expect.any(String));
|
||||
expect(rundown.order).toStrictEqual([expect.any(String), '3']);
|
||||
expect(rundown.entries).toMatchObject({
|
||||
[blockId]: {
|
||||
type: SupportedEntry.Block,
|
||||
[groupId]: {
|
||||
type: SupportedEntry.Group,
|
||||
entries: ['1', '2'],
|
||||
},
|
||||
'1': { id: '1', type: SupportedEntry.Event, parent: blockId },
|
||||
'2': { id: '2', type: SupportedEntry.Event, parent: blockId },
|
||||
'1': { id: '1', type: SupportedEntry.Event, parent: groupId },
|
||||
'2': { id: '2', type: SupportedEntry.Event, parent: groupId },
|
||||
'3': { id: '3', type: SupportedEntry.Event, parent: null },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('rundownMutation.ungroup()', () => {
|
||||
it('should correctly dissolve a block into its events', () => {
|
||||
it('should correctly dissolve a group into its events', () => {
|
||||
const testRundown = makeRundown({
|
||||
order: ['1', '2'],
|
||||
entries: {
|
||||
'1': makeOntimeEvent({ id: '1', cue: 'data1', parent: null }),
|
||||
'2': makeOntimeBlock({ id: '2', entries: ['21', '22'] }),
|
||||
'2': makeOntimeGroup({ id: '2', entries: ['21', '22'] }),
|
||||
'21': makeOntimeEvent({ id: '21', cue: 'data21', parent: '2' }),
|
||||
'22': makeOntimeEvent({ id: '22', cue: 'data22', parent: '2' }),
|
||||
},
|
||||
});
|
||||
|
||||
rundownMutation.ungroup(testRundown, testRundown.entries['2'] as OntimeBlock);
|
||||
rundownMutation.ungroup(testRundown, testRundown.entries['2'] as OntimeGroup);
|
||||
|
||||
expect(testRundown.order).toStrictEqual(['1', '21', '22']);
|
||||
expect(testRundown.entries['2']).toBeUndefined();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SupportedEntry, OntimeEvent, OntimeBlock, Rundown, CustomFields } from 'ontime-types';
|
||||
import { SupportedEntry, OntimeEvent, OntimeGroup, Rundown, CustomFields } from 'ontime-types';
|
||||
|
||||
import { defaultRundown } from '../../../models/dataModel.js';
|
||||
import { makeOntimeBlock, makeOntimeEvent, makeOntimeMilestone } from '../__mocks__/rundown.mocks.js';
|
||||
import { makeOntimeGroup, makeOntimeEvent, makeOntimeMilestone } from '../__mocks__/rundown.mocks.js';
|
||||
|
||||
import { parseRundowns, parseRundown, handleCustomField, addToCustomAssignment } from '../rundown.parser.js';
|
||||
|
||||
@@ -47,7 +47,7 @@ describe('parseRundown()', () => {
|
||||
flatOrder: ['1', '2', '3', '4'],
|
||||
entries: {
|
||||
'1': { id: '1', type: SupportedEntry.Event, title: 'test', skip: false } as OntimeEvent, // OK
|
||||
'2': { id: '1', type: SupportedEntry.Block, title: 'test 2' } as OntimeBlock, // duplicate ID
|
||||
'2': { id: '1', type: SupportedEntry.Group, title: 'test 2' } as OntimeGroup, // duplicate ID
|
||||
'3': {} as OntimeEvent, // no data
|
||||
'4': { id: '4', title: 'test 2', skip: false } as OntimeEvent, // no type
|
||||
},
|
||||
@@ -221,7 +221,7 @@ describe('parseRundown()', () => {
|
||||
flatOrder: ['1', '2', '21'],
|
||||
entries: {
|
||||
'1': makeOntimeEvent({ id: '1', custom: { lighting: 'yes' } }),
|
||||
'2': makeOntimeBlock({ id: '2', entries: ['21'], custom: { lighting: '' } }),
|
||||
'2': makeOntimeGroup({ id: '2', entries: ['21'], custom: { lighting: '' } }),
|
||||
'21': makeOntimeEvent({ id: '21', custom: { lighting: '' } }),
|
||||
},
|
||||
revision: 1,
|
||||
@@ -237,7 +237,7 @@ describe('parseRundown()', () => {
|
||||
|
||||
const parsedRundown = parseRundown(rundown, customFields);
|
||||
expect((parsedRundown.entries['1'] as OntimeEvent).custom).toStrictEqual({ lighting: 'yes' });
|
||||
expect((parsedRundown.entries['2'] as OntimeBlock).custom).not.toHaveProperty('lighting');
|
||||
expect((parsedRundown.entries['2'] as OntimeGroup).custom).not.toHaveProperty('lighting');
|
||||
expect((parsedRundown.entries['21'] as OntimeEvent).custom).not.toHaveProperty('lighting');
|
||||
});
|
||||
|
||||
@@ -245,41 +245,41 @@ describe('parseRundown()', () => {
|
||||
const rundown = {
|
||||
id: 'test',
|
||||
title: '',
|
||||
order: ['block'],
|
||||
flatOrder: ['block'],
|
||||
order: ['group'],
|
||||
flatOrder: ['group'],
|
||||
isNextDay: false,
|
||||
entries: {
|
||||
block: makeOntimeBlock({
|
||||
id: 'block',
|
||||
title: 'block-title',
|
||||
note: 'block-note',
|
||||
group: makeOntimeGroup({
|
||||
id: 'group',
|
||||
title: 'group-title',
|
||||
note: 'group-note',
|
||||
colour: 'red',
|
||||
entries: ['1', '2', '3'],
|
||||
}),
|
||||
'1': makeOntimeEvent({ id: '1', parent: 'block' }),
|
||||
'2': makeOntimeMilestone({ id: '2', parent: 'block' }),
|
||||
'1': makeOntimeEvent({ id: '1', parent: 'group' }),
|
||||
'2': makeOntimeMilestone({ id: '2', parent: 'group' }),
|
||||
},
|
||||
revision: 1,
|
||||
} as Rundown;
|
||||
|
||||
const parsedRundown = parseRundown(rundown, {});
|
||||
expect(parsedRundown.order).toStrictEqual(['block']);
|
||||
expect(parsedRundown.flatOrder).toStrictEqual(['block', '1', '2']);
|
||||
expect(parsedRundown.order).toStrictEqual(['group']);
|
||||
expect(parsedRundown.flatOrder).toStrictEqual(['group', '1', '2']);
|
||||
expect(parsedRundown.entries).toMatchObject({
|
||||
block: { id: 'block', type: SupportedEntry.Block, entries: ['1', '2'] },
|
||||
group: { id: 'group', type: SupportedEntry.Group, entries: ['1', '2'] },
|
||||
'1': { id: '1', type: SupportedEntry.Event },
|
||||
'2': { id: '2', type: SupportedEntry.Milestone },
|
||||
});
|
||||
});
|
||||
|
||||
it('parses events nested in blocks', () => {
|
||||
it('parses events nested in groups', () => {
|
||||
const rundown = {
|
||||
id: 'test',
|
||||
title: '',
|
||||
order: ['block'],
|
||||
flatOrder: ['block'],
|
||||
order: ['group'],
|
||||
flatOrder: ['group'],
|
||||
entries: {
|
||||
block: makeOntimeBlock({ id: 'block', entries: ['1', '2'] }),
|
||||
group: makeOntimeGroup({ id: 'group', entries: ['1', '2'] }),
|
||||
'1': makeOntimeEvent({ id: '1' }),
|
||||
'2': makeOntimeEvent({ id: '2' }),
|
||||
},
|
||||
@@ -288,7 +288,7 @@ describe('parseRundown()', () => {
|
||||
|
||||
const parsedRundown = parseRundown(rundown, {});
|
||||
expect(parsedRundown.order.length).toEqual(1);
|
||||
expect(parsedRundown.entries.block).toMatchObject({ entries: ['1', '2'] });
|
||||
expect(parsedRundown.entries.group).toMatchObject({ entries: ['1', '2'] });
|
||||
expect(Object.keys(parsedRundown.entries).length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TimeStrategy, EndAction, TimerType, OntimeEvent, OntimeBlock } from 'ontime-types';
|
||||
import { TimeStrategy, EndAction, TimerType, OntimeEvent, OntimeGroup } from 'ontime-types';
|
||||
import { MILLIS_PER_HOUR } from 'ontime-utils';
|
||||
|
||||
import { assertType } from 'vitest';
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
getInsertAfterId,
|
||||
hasChanges,
|
||||
} from '../rundown.utils.js';
|
||||
import { makeOntimeBlock, makeOntimeEvent, makeRundown } from '../__mocks__/rundown.mocks.js';
|
||||
import { makeOntimeGroup, makeOntimeEvent, makeRundown } from '../__mocks__/rundown.mocks.js';
|
||||
|
||||
describe('test event validator', () => {
|
||||
it('validates a good object', () => {
|
||||
@@ -227,13 +227,13 @@ describe('getInsertAfterId()', () => {
|
||||
entries: {
|
||||
'1': makeOntimeEvent({ id: '1', parent: null }),
|
||||
'2': makeOntimeEvent({ id: '2', parent: null }),
|
||||
block: makeOntimeBlock({ id: 'block', entries: ['31', '32'] }),
|
||||
'31': makeOntimeEvent({ id: '31', parent: 'block' }),
|
||||
'32': makeOntimeEvent({ id: '32', parent: 'block' }),
|
||||
'4': makeOntimeEvent({ id: '31', parent: null }),
|
||||
group: makeOntimeGroup({ id: 'group', entries: ['31', '32'] }),
|
||||
'31': makeOntimeEvent({ id: '31', parent: 'group' }),
|
||||
'32': makeOntimeEvent({ id: '32', parent: 'group' }),
|
||||
'4': makeOntimeEvent({ id: '4', parent: null }),
|
||||
},
|
||||
order: ['1', '2', 'block', '4'],
|
||||
flatOrder: ['1', '2', 'block', '31', '32', '4'],
|
||||
order: ['1', '2', 'group', '4'],
|
||||
flatOrder: ['1', '2', 'group', '31', '32', '4'],
|
||||
});
|
||||
|
||||
it('returns afterId if provided', () => {
|
||||
@@ -251,12 +251,12 @@ describe('getInsertAfterId()', () => {
|
||||
|
||||
it('returns the previous id of an entry in the rundown', () => {
|
||||
expect(getInsertAfterId(rundown, null, undefined, '2')).toBe('1');
|
||||
expect(getInsertAfterId(rundown, null, undefined, '4')).toBe('block');
|
||||
expect(getInsertAfterId(rundown, null, undefined, 'block')).toBe('2');
|
||||
expect(getInsertAfterId(rundown, null, undefined, '4')).toBe('group');
|
||||
expect(getInsertAfterId(rundown, null, undefined, 'group')).toBe('2');
|
||||
});
|
||||
|
||||
it('returns the previous id of an event in a block', () => {
|
||||
expect(getInsertAfterId(rundown, rundown.entries.block as OntimeBlock, undefined, '31')).toBeNull();
|
||||
expect(getInsertAfterId(rundown, rundown.entries.block as OntimeBlock, undefined, '32')).toBe('31');
|
||||
it('returns the previous id of an event in a group', () => {
|
||||
expect(getInsertAfterId(rundown, rundown.entries.group as OntimeGroup, undefined, '31')).toBeNull();
|
||||
expect(getInsertAfterId(rundown, rundown.entries.group as OntimeGroup, undefined, '32')).toBe('31');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,10 +15,10 @@ import {
|
||||
CustomFieldKey,
|
||||
CustomFields,
|
||||
EntryId,
|
||||
isOntimeBlock,
|
||||
isOntimeGroup,
|
||||
isOntimeEvent,
|
||||
isPlayableEvent,
|
||||
OntimeBlock,
|
||||
OntimeGroup,
|
||||
OntimeDelay,
|
||||
OntimeEntry,
|
||||
OntimeEvent,
|
||||
@@ -32,9 +32,9 @@ import { getDataProvider } from '../../classes/data-provider/DataProvider.js';
|
||||
import type { AssignedMap, CustomFieldsMetadata, RundownMetadata } from './rundown.types.js';
|
||||
import {
|
||||
applyPatchToEntry,
|
||||
cloneBlock,
|
||||
cloneGroup,
|
||||
cloneEntry,
|
||||
createBlock,
|
||||
createGroup,
|
||||
deleteById,
|
||||
doesInvalidateMetadata,
|
||||
getUniqueId,
|
||||
@@ -176,14 +176,14 @@ export function createTransaction(options: TransactionOptions): Transaction {
|
||||
|
||||
/**
|
||||
* Add entry to rundown, handles the following cases:
|
||||
* - 1a. add entry in block, after a given entry
|
||||
* - 1b. add entry in block, at the beginning
|
||||
* - 1a. add entry in group, after a given entry
|
||||
* - 1b. add entry in group, at the beginning
|
||||
* - 2a. add entry to the rundown, after a given entry
|
||||
* - 2b. add entry to the rundown, at the beginning
|
||||
*/
|
||||
function add(rundown: Rundown, entry: OntimeEntry, afterId: EntryId | null, parent: OntimeBlock | null): OntimeEntry {
|
||||
function add(rundown: Rundown, entry: OntimeEntry, afterId: EntryId | null, parent: OntimeGroup | null): OntimeEntry {
|
||||
if (parent) {
|
||||
// 1. inserting an entry inside a block
|
||||
// 1. inserting an entry inside a group
|
||||
if (afterId) {
|
||||
const atEventsIndex = parent.entries.indexOf(afterId) + 1;
|
||||
const atFlatIndex = rundown.flatOrder.indexOf(afterId) + 1;
|
||||
@@ -232,31 +232,31 @@ function edit(rundown: Rundown, patch: PatchWithId): { entry: OntimeEntry; didIn
|
||||
|
||||
/**
|
||||
* Deletes an entry from the rundown
|
||||
* - if the entry is an ontime block, we delete it along with its children
|
||||
* - if the entry is inside a block, we delete it and remove the reference from the parent block
|
||||
* - if the entry is an ontime group, we delete it along with its children
|
||||
* - if the entry is inside a group, we delete it and remove the reference from the parent group
|
||||
*/
|
||||
function remove(rundown: Rundown, entry: OntimeEntry) {
|
||||
if (isOntimeBlock(entry)) {
|
||||
// for ontime blocks, we need to iterate through the children and delete them
|
||||
if (isOntimeGroup(entry)) {
|
||||
// for ontime groups, we need to iterate through the children and delete them
|
||||
for (let i = 0; i < entry.entries.length; i++) {
|
||||
const nestedEntryId = entry.entries[i];
|
||||
deleteEntry(nestedEntryId);
|
||||
}
|
||||
} else if (entry.parent) {
|
||||
// at this point, we are handling entries inside a block, so we need to remove the reference
|
||||
const parentBlock = rundown.entries[entry.parent];
|
||||
// at this point, we are handling entries inside a group, so we need to remove the reference
|
||||
const parentGroup = rundown.entries[entry.parent];
|
||||
|
||||
// eslint-disable-next-line no-unused-labels -- dev code path
|
||||
DEV: {
|
||||
if (parentBlock && !isOntimeBlock(parentBlock)) {
|
||||
consoleError(`Parent block with ID ${entry.parent} is not a valid OntimeBlock`);
|
||||
if (parentGroup && !isOntimeGroup(parentGroup)) {
|
||||
consoleError(`Parent group with ID ${entry.parent} is not a valid Group`);
|
||||
}
|
||||
}
|
||||
|
||||
if (parentBlock && isOntimeBlock(parentBlock)) {
|
||||
if (parentGroup && isOntimeGroup(parentGroup)) {
|
||||
// we call a mutation to the parent event to remove the entry from the events
|
||||
const filteredEvents = deleteById(parentBlock.entries, entry.id);
|
||||
edit(rundown, { id: parentBlock.id, entries: filteredEvents });
|
||||
const filteredEvents = deleteById(parentGroup.entries, entry.id);
|
||||
edit(rundown, { id: parentGroup.id, entries: filteredEvents });
|
||||
}
|
||||
}
|
||||
deleteEntry(entry.id);
|
||||
@@ -281,22 +281,22 @@ function removeAll(rundown: Rundown): Rundown {
|
||||
/**
|
||||
* Reorders an entry in the rundown
|
||||
* Handle moving across order lists
|
||||
* @param order - 'before' | 'after' | 'insert' - where to add the entry, insert serves to add the entry into an empty block
|
||||
* @throws if we insert a block inside another
|
||||
* @param order - 'before' | 'after' | 'insert' - where to add the entry, insert serves to add the entry into an empty group
|
||||
* @throws if we insert a group inside another
|
||||
*/
|
||||
function reorder(rundown: Rundown, eventFrom: OntimeEntry, eventTo: OntimeEntry, order: 'before' | 'after' | 'insert') {
|
||||
// handle moving across parents
|
||||
const fromParent: EntryId | null = (eventFrom as { parent?: EntryId })?.parent ?? null;
|
||||
const toParent = (() => {
|
||||
if (isOntimeBlock(eventTo)) {
|
||||
// Special case: if we're moving relative to our own parent block, remove from block
|
||||
if (isOntimeGroup(eventTo)) {
|
||||
// Special case: if we're moving relative to our own parent group, remove from group
|
||||
if ('parent' in eventFrom && eventFrom.parent === eventTo.id) {
|
||||
return null;
|
||||
}
|
||||
if (order === 'insert') {
|
||||
// prevent blocks from being inserted into other blocks
|
||||
if (isOntimeBlock(eventFrom)) {
|
||||
throw new Error('Cannot insert a block into another block');
|
||||
// prevent groups from being inserted into other groups
|
||||
if (isOntimeGroup(eventFrom)) {
|
||||
throw new Error('Cannot insert a group into another group');
|
||||
}
|
||||
return eventTo.id;
|
||||
}
|
||||
@@ -310,8 +310,8 @@ function reorder(rundown: Rundown, eventFrom: OntimeEntry, eventTo: OntimeEntry,
|
||||
eventFrom.parent = toParent;
|
||||
}
|
||||
|
||||
const sourceArray = fromParent === null ? rundown.order : (rundown.entries[fromParent] as OntimeBlock).entries;
|
||||
const destinationArray = toParent === null ? rundown.order : (rundown.entries[toParent] as OntimeBlock).entries;
|
||||
const sourceArray = fromParent === null ? rundown.order : (rundown.entries[fromParent] as OntimeGroup).entries;
|
||||
const destinationArray = toParent === null ? rundown.order : (rundown.entries[toParent] as OntimeGroup).entries;
|
||||
|
||||
const fromIndex = sourceArray.indexOf(eventFrom.id);
|
||||
const toIndex = (() => {
|
||||
@@ -450,11 +450,11 @@ function swap(rundown: Rundown, eventFrom: OntimeEvent, eventTo: OntimeEvent) {
|
||||
|
||||
/**
|
||||
* Inserts a clone of the given entry into the rundown
|
||||
* Handles cloning children if the entry is a block
|
||||
* Handles cloning children if the entry is a group
|
||||
*/
|
||||
function clone(rundown: Rundown, entry: OntimeEntry): OntimeEntry {
|
||||
if (isOntimeBlock(entry)) {
|
||||
const newBlock = cloneBlock(entry, getUniqueId(rundown));
|
||||
if (isOntimeGroup(entry)) {
|
||||
const newGroup = cloneGroup(entry, getUniqueId(rundown));
|
||||
const nestedIds: EntryId[] = [];
|
||||
|
||||
for (let i = 0; i < entry.entries.length; i++) {
|
||||
@@ -464,83 +464,83 @@ function clone(rundown: Rundown, entry: OntimeEntry): OntimeEntry {
|
||||
continue;
|
||||
}
|
||||
|
||||
// clone the event and assign it to the new block
|
||||
// clone the event and assign it to the new group
|
||||
const newNestedEntry = cloneEntry(nestedEntry, getUniqueId(rundown));
|
||||
(newNestedEntry as OntimeEvent | OntimeDelay).parent = newBlock.id;
|
||||
(newNestedEntry as OntimeEvent | OntimeDelay).parent = newGroup.id;
|
||||
|
||||
nestedIds.push(newNestedEntry.id);
|
||||
// we immediately insert the nested entries into the rundown
|
||||
rundown.entries[newNestedEntry.id] = newNestedEntry;
|
||||
}
|
||||
|
||||
// indexes + 1 since we are inserting after the cloned block
|
||||
// indexes + 1 since we are inserting after the cloned group
|
||||
const atIndex = rundown.order.indexOf(entry.id) + 1;
|
||||
|
||||
newBlock.entries = nestedIds;
|
||||
newBlock.title = `${entry.title || 'Untitled'} (copy)`;
|
||||
newGroup.entries = nestedIds;
|
||||
newGroup.title = `${entry.title || 'Untitled'} (copy)`;
|
||||
|
||||
rundown.entries[newBlock.id] = newBlock;
|
||||
rundown.order = insertAtIndex(atIndex, newBlock.id, rundown.order);
|
||||
rundown.entries[newGroup.id] = newGroup;
|
||||
rundown.order = insertAtIndex(atIndex, newGroup.id, rundown.order);
|
||||
|
||||
return newBlock;
|
||||
return newGroup;
|
||||
} else {
|
||||
const parent: OntimeBlock | null = entry.parent ? (rundown.entries[entry.parent] as OntimeBlock) : null;
|
||||
const parent: OntimeGroup | null = entry.parent ? (rundown.entries[entry.parent] as OntimeGroup) : null;
|
||||
return add(rundown, cloneEntry(entry, getUniqueId(rundown)), entry.id, parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups a list of entries
|
||||
* It ensures that the entries get reassigned parent and the block gets a list of events
|
||||
* It ensures that the entries get reassigned parent and the group gets a list of events
|
||||
* The group will be created at the index of the first event in the order, not at the lowest index
|
||||
* Mutates the given rundown
|
||||
*/
|
||||
function group(rundown: Rundown, entryIds: EntryId[]): OntimeBlock {
|
||||
const newBlock = createBlock({ id: getUniqueId(rundown) });
|
||||
function group(rundown: Rundown, entryIds: EntryId[]): OntimeGroup {
|
||||
const newGroup = createGroup({ id: getUniqueId(rundown) });
|
||||
|
||||
const nestedEvents: EntryId[] = [];
|
||||
let firstIndex = -1;
|
||||
for (let i = 0; i < entryIds.length; i++) {
|
||||
const entryId = entryIds[i];
|
||||
const entry = rundown.entries[entryId];
|
||||
if (!entry || isOntimeBlock(entry)) {
|
||||
if (!entry || isOntimeGroup(entry)) {
|
||||
// invalid operation, we skip this entry
|
||||
continue;
|
||||
}
|
||||
|
||||
// the block will be created at the first selected event position
|
||||
// the group will be created at the first selected event position
|
||||
// note that this is not the lowest index
|
||||
if (firstIndex === -1) {
|
||||
firstIndex = rundown.flatOrder.indexOf(entryId);
|
||||
}
|
||||
|
||||
nestedEvents.push(entryId);
|
||||
entry.parent = newBlock.id;
|
||||
entry.parent = newGroup.id;
|
||||
rundown.flatOrder = rundown.flatOrder.filter((id) => id !== entryId);
|
||||
rundown.order = rundown.order.filter((id) => id !== entryId);
|
||||
}
|
||||
|
||||
newBlock.entries = nestedEvents;
|
||||
newGroup.entries = nestedEvents;
|
||||
const insertIndex = Math.max(0, firstIndex);
|
||||
// we have filtered the items from the order
|
||||
// we will insert them now, with only the block at top level ...
|
||||
rundown.order = insertAtIndex(insertIndex, newBlock.id, rundown.order);
|
||||
rundown.entries[newBlock.id] = newBlock;
|
||||
// we will insert them now, with only the group at top level ...
|
||||
rundown.order = insertAtIndex(insertIndex, newGroup.id, rundown.order);
|
||||
rundown.entries[newGroup.id] = newGroup;
|
||||
|
||||
return newBlock;
|
||||
return newGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a block and moves all its children to the top level order
|
||||
* Deletes a group and moves all its children to the top level order
|
||||
*/
|
||||
function ungroup(rundown: Rundown, block: OntimeBlock) {
|
||||
// get the events from the block and merge them into the order where the block was
|
||||
const nestedEvents = block.entries;
|
||||
const blockIndex = rundown.order.indexOf(block.id);
|
||||
rundown.order.splice(blockIndex, 1, ...nestedEvents);
|
||||
function ungroup(rundown: Rundown, group: OntimeGroup) {
|
||||
// get the events from the group and merge them into the order where the group was
|
||||
const nestedEvents = group.entries;
|
||||
const groupIndex = rundown.order.indexOf(group.id);
|
||||
rundown.order.splice(groupIndex, 1, ...nestedEvents);
|
||||
|
||||
// delete block from entries and remove its reference from the child events
|
||||
delete rundown.entries[block.id];
|
||||
// delete the group from entries and remove its reference from the child events
|
||||
delete rundown.entries[group.id];
|
||||
for (let i = 0; i < nestedEvents.length; i++) {
|
||||
const eventId = nestedEvents[i];
|
||||
const entry = rundown.entries[eventId];
|
||||
@@ -720,16 +720,16 @@ export function processRundown(
|
||||
}
|
||||
const { processedEntry } = process(currentEntry, null);
|
||||
|
||||
// if the event is a block, we process the nested entries
|
||||
// if the event is a group, we process the nested entries
|
||||
// the code here is a copy of the processing of top level events
|
||||
if (isOntimeBlock(processedEntry)) {
|
||||
let blockStartTime = null;
|
||||
let blockEndTime = null;
|
||||
if (isOntimeGroup(processedEntry)) {
|
||||
let groupStartTime = null;
|
||||
let groupEndTime = null;
|
||||
let isFirstLinked = false;
|
||||
const blockEvents: EntryId[] = [];
|
||||
const groupEvents: EntryId[] = [];
|
||||
processedEntry.duration = 0;
|
||||
|
||||
// check if the block contains nested entries
|
||||
// check if the group contains nested entries
|
||||
for (let j = 0; j < processedEntry.entries.length; j++) {
|
||||
const nestedEntryId = processedEntry.entries[j];
|
||||
const nestedEntry = initialRundown.entries[nestedEntryId];
|
||||
@@ -738,7 +738,7 @@ export function processRundown(
|
||||
continue;
|
||||
}
|
||||
|
||||
blockEvents.push(nestedEntry.id);
|
||||
groupEvents.push(nestedEntry.id);
|
||||
const { processedEntry: processedNestedEntry } = process(nestedEntry, processedEntry.id);
|
||||
|
||||
// we dont extract metadata of skipped events,
|
||||
@@ -748,24 +748,24 @@ export function processRundown(
|
||||
}
|
||||
|
||||
// first start is always the first event
|
||||
if (blockStartTime === null) {
|
||||
blockStartTime = processedNestedEntry.timeStart;
|
||||
if (groupStartTime === null) {
|
||||
groupStartTime = processedNestedEntry.timeStart;
|
||||
isFirstLinked = Boolean(processedNestedEntry.linkStart);
|
||||
}
|
||||
|
||||
// lastEntry is the event with the latest end time
|
||||
blockEndTime = processedNestedEntry.timeEnd;
|
||||
groupEndTime = processedNestedEntry.timeEnd;
|
||||
if (j > 0) {
|
||||
processedEntry.duration += processedNestedEntry.gap;
|
||||
}
|
||||
processedEntry.duration = processedEntry.duration + processedNestedEntry.duration;
|
||||
}
|
||||
|
||||
// update block metadata
|
||||
processedEntry.timeStart = blockStartTime;
|
||||
processedEntry.timeEnd = blockEndTime;
|
||||
// update group metadata
|
||||
processedEntry.timeStart = groupStartTime;
|
||||
processedEntry.timeEnd = groupEndTime;
|
||||
processedEntry.isFirstLinked = isFirstLinked;
|
||||
processedEntry.entries = blockEvents;
|
||||
processedEntry.entries = groupEvents;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
OntimeEvent,
|
||||
isOntimeEvent,
|
||||
isOntimeDelay,
|
||||
isOntimeBlock,
|
||||
isOntimeGroup,
|
||||
CustomFieldKey,
|
||||
EntryId,
|
||||
OntimeEntry,
|
||||
@@ -21,7 +21,7 @@ import { defaultRundown } from '../../models/dataModel.js';
|
||||
import { delay as delayDef } from '../../models/eventsDefinition.js';
|
||||
import type { ErrorEmitter } from '../../utils/parserUtils.js';
|
||||
|
||||
import { calculateDayOffset, cleanupCustomFields, createBlock, createEvent, createMilestone } from './rundown.utils.js';
|
||||
import { calculateDayOffset, cleanupCustomFields, createGroup, createEvent, createMilestone } from './rundown.utils.js';
|
||||
import { RundownMetadata } from './rundown.types.js';
|
||||
|
||||
/**
|
||||
@@ -110,7 +110,11 @@ export function parseRundown(
|
||||
} else if (isOntimeMilestone(event)) {
|
||||
newEvent = createMilestone({ ...event, id });
|
||||
cleanupCustomFields(newEvent.custom, parsedCustomFields);
|
||||
} else if (isOntimeBlock(event)) {
|
||||
/**
|
||||
* We leave here an entry point for blocks for the alpha testers, should remove this after a while
|
||||
*/
|
||||
// @ts-expect-error -- we are checking a legacy type
|
||||
} else if (event.type === 'block' || isOntimeGroup(event)) {
|
||||
for (let i = 0; i < event.entries.length; i++) {
|
||||
const nestedEventId = event.entries[i];
|
||||
const nestedEvent = rundown.entries[nestedEventId];
|
||||
@@ -143,7 +147,7 @@ export function parseRundown(
|
||||
}
|
||||
}
|
||||
|
||||
newEvent = createBlock({ ...structuredClone(event), id });
|
||||
newEvent = createGroup({ ...structuredClone(event), id });
|
||||
// ensure entries exist
|
||||
if (event.entries?.length > 0) {
|
||||
newEvent.entries = event.entries.filter((eventId) => Object.hasOwn(rundown.entries, eventId));
|
||||
@@ -240,9 +244,9 @@ export function makeRundownMetadata(customFields: CustomFields) {
|
||||
|
||||
function process<T extends OntimeEntry>(
|
||||
entry: T,
|
||||
childOfBlock: EntryId | null,
|
||||
childOfGroup: EntryId | null,
|
||||
): { processedData: ProcessedRundownMetadata; processedEntry: T } {
|
||||
const data = processEntry(rundownMeta, customFields, entry, childOfBlock);
|
||||
const data = processEntry(rundownMeta, customFields, entry, childOfGroup);
|
||||
rundownMeta = data.processedData;
|
||||
return data;
|
||||
}
|
||||
@@ -261,7 +265,7 @@ function processEntry<T extends OntimeEntry>(
|
||||
rundownMetadata: ProcessedRundownMetadata,
|
||||
customFields: CustomFields,
|
||||
entry: T,
|
||||
childOfBlock: EntryId | null,
|
||||
childOfGroup: EntryId | null,
|
||||
): { processedData: ProcessedRundownMetadata; processedEntry: T } {
|
||||
const processedData = { ...rundownMetadata };
|
||||
const currentEntry = structuredClone(entry);
|
||||
@@ -294,7 +298,7 @@ function processEntry<T extends OntimeEntry>(
|
||||
currentEntry.dayOffset = processedData.totalDays;
|
||||
currentEntry.delay = 0; // this means we dont calculate delays or gaps for skipped events
|
||||
currentEntry.gap = 0; // this means we dont calculate delays or gaps for skipped events
|
||||
currentEntry.parent = childOfBlock;
|
||||
currentEntry.parent = childOfGroup;
|
||||
|
||||
// update rundown metadata, it only concerns playable events
|
||||
if (isPlayableEvent(currentEntry)) {
|
||||
@@ -353,10 +357,10 @@ function processEntry<T extends OntimeEntry>(
|
||||
} else if (isOntimeDelay(currentEntry)) {
|
||||
// !!! this must happen after handling the links
|
||||
processedData.totalDelay += currentEntry.duration;
|
||||
currentEntry.parent = childOfBlock;
|
||||
currentEntry.parent = childOfGroup;
|
||||
}
|
||||
|
||||
if (!childOfBlock) {
|
||||
if (!childOfGroup) {
|
||||
processedData.order.push(currentEntry.id);
|
||||
}
|
||||
processedData.entries[currentEntry.id] = currentEntry;
|
||||
|
||||
@@ -4,10 +4,10 @@ import {
|
||||
CustomFields,
|
||||
EntryId,
|
||||
EventPostPayload,
|
||||
isOntimeBlock,
|
||||
isOntimeGroup,
|
||||
isOntimeDelay,
|
||||
isOntimeEvent,
|
||||
OntimeBlock,
|
||||
OntimeGroup,
|
||||
OntimeEntry,
|
||||
PatchWithId,
|
||||
RefetchKey,
|
||||
@@ -35,12 +35,12 @@ export async function addEntry(eventData: EventPostPayload): Promise<OntimeEntry
|
||||
}
|
||||
|
||||
// the parent can be provided or inferred from position
|
||||
let parent: OntimeBlock | null = null;
|
||||
let parent: OntimeGroup | null = null;
|
||||
|
||||
if ('parent' in eventData && eventData.parent != null) {
|
||||
// if the user provides a parent (inside a group), we make sure it exists and it is a group
|
||||
const maybeParent = rundown.entries[eventData.parent];
|
||||
if (!maybeParent || !isOntimeBlock(maybeParent)) {
|
||||
if (!maybeParent || !isOntimeGroup(maybeParent)) {
|
||||
throw new Error(`Invalid parent event with ID ${eventData.parent}`);
|
||||
}
|
||||
parent = maybeParent;
|
||||
@@ -51,7 +51,7 @@ export async function addEntry(eventData: EventPostPayload): Promise<OntimeEntry
|
||||
const maybeSibling = rundown.entries[referenceId];
|
||||
if (maybeSibling && 'parent' in maybeSibling && maybeSibling.parent) {
|
||||
const maybeParent = rundown.entries[maybeSibling.parent];
|
||||
if (maybeParent && isOntimeBlock(maybeParent)) {
|
||||
if (maybeParent && isOntimeGroup(maybeParent)) {
|
||||
parent = maybeParent;
|
||||
}
|
||||
}
|
||||
@@ -241,7 +241,7 @@ export async function deleteAllEntries(): Promise<Rundown> {
|
||||
|
||||
/**
|
||||
* Moves an event to a new position in the rundown
|
||||
* Handles moving across root orders (a block order and top level order)
|
||||
* Handles moving across root orders (a group order and top level order)
|
||||
* @throws if entryId or destinationId not found
|
||||
*/
|
||||
export function reorderEntry(entryId: EntryId, destinationId: EntryId, order: 'before' | 'after' | 'insert') {
|
||||
@@ -356,7 +356,7 @@ export async function cloneEntry(entryId: EntryId): Promise<Rundown> {
|
||||
updateRuntimeOnChange(rundownMetadata);
|
||||
|
||||
// notify timer and external services of change
|
||||
if (isOntimeBlock(newEntry)) {
|
||||
if (isOntimeGroup(newEntry)) {
|
||||
notifyChanges(rundownMetadata, revision, { timer: newEntry.entries, external: true });
|
||||
} else if (isOntimeEvent(newEntry)) {
|
||||
notifyChanges(rundownMetadata, revision, { timer: [newEntry.id], external: true });
|
||||
@@ -370,7 +370,7 @@ export async function cloneEntry(entryId: EntryId): Promise<Rundown> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups a list of entries into a new block
|
||||
* Groups a list of entries into a new group
|
||||
*/
|
||||
export async function groupEntries(entryIds: EntryId[]): Promise<Rundown> {
|
||||
const { rundown, commit } = createTransaction({ mutableRundown: true, mutableCustomFields: false });
|
||||
@@ -391,17 +391,17 @@ export async function groupEntries(entryIds: EntryId[]): Promise<Rundown> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a block and moves all its children to the top level
|
||||
* Deletes a group and moves all its children to the top level
|
||||
*/
|
||||
export async function ungroupEntries(blockId: EntryId): Promise<Rundown> {
|
||||
export async function ungroupEntries(groupId: EntryId): Promise<Rundown> {
|
||||
const { rundown, commit } = createTransaction({ mutableRundown: true, mutableCustomFields: false });
|
||||
|
||||
const block = rundown.entries[blockId];
|
||||
if (!block || !isOntimeBlock(block)) {
|
||||
throw new Error(`Block with ID ${blockId} not found or is not a block`);
|
||||
const group = rundown.entries[groupId];
|
||||
if (!group || !isOntimeGroup(group)) {
|
||||
throw new Error(`Group with ID ${groupId} not found or is not a group`);
|
||||
}
|
||||
|
||||
rundownMutation.ungroup(rundown, block);
|
||||
rundownMutation.ungroup(rundown, group);
|
||||
const { rundown: rundownResult, rundownMetadata, revision } = commit();
|
||||
|
||||
// schedule the side effects
|
||||
|
||||
@@ -2,12 +2,12 @@ import {
|
||||
CustomFields,
|
||||
EntryCustomFields,
|
||||
EntryId,
|
||||
isOntimeBlock,
|
||||
isOntimeGroup,
|
||||
isOntimeDelay,
|
||||
isOntimeEvent,
|
||||
isOntimeMilestone,
|
||||
OntimeBaseEvent,
|
||||
OntimeBlock,
|
||||
OntimeGroup,
|
||||
OntimeDelay,
|
||||
OntimeEntry,
|
||||
OntimeEvent,
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
|
||||
import {
|
||||
event as eventDef,
|
||||
block as blockDef,
|
||||
group as groupDef,
|
||||
delay as delayDef,
|
||||
milestone as milestoneDef,
|
||||
} from '../../models/eventsDefinition.js';
|
||||
@@ -39,8 +39,8 @@ type CompleteEntry<T> =
|
||||
? OntimeEvent
|
||||
: T extends Partial<OntimeDelay>
|
||||
? OntimeDelay
|
||||
: T extends Partial<OntimeBlock>
|
||||
? OntimeBlock
|
||||
: T extends Partial<OntimeGroup>
|
||||
? OntimeGroup
|
||||
: T extends Partial<OntimeMilestone>
|
||||
? OntimeMilestone
|
||||
: never;
|
||||
@@ -49,7 +49,7 @@ type CompleteEntry<T> =
|
||||
* Generates a fully formed RundownEntry of the patch type
|
||||
*/
|
||||
export function generateEvent<
|
||||
T extends Partial<OntimeEvent> | Partial<OntimeDelay> | Partial<OntimeBlock> | Partial<OntimeMilestone>,
|
||||
T extends Partial<OntimeEvent> | Partial<OntimeDelay> | Partial<OntimeGroup> | Partial<OntimeMilestone>,
|
||||
>(rundown: Rundown, eventData: T, afterId: EntryId | null): CompleteEntry<T> {
|
||||
if (isOntimeEvent(eventData)) {
|
||||
return createEvent(eventData, getCueCandidate(rundown.entries, rundown.order, afterId)) as CompleteEntry<T>;
|
||||
@@ -61,9 +61,9 @@ export function generateEvent<
|
||||
return { ...delayDef, duration: eventData.duration ?? 0, id } as CompleteEntry<T>;
|
||||
}
|
||||
|
||||
// TODO(v4): allow user to provide a larger patch of the block entry
|
||||
if (isOntimeBlock(eventData)) {
|
||||
return createBlock({ id, title: eventData.title ?? '' }) as CompleteEntry<T>;
|
||||
// TODO(v4): allow user to provide a larger patch of the group entry
|
||||
if (isOntimeGroup(eventData)) {
|
||||
return createGroup({ id, title: eventData.title ?? '' }) as CompleteEntry<T>;
|
||||
}
|
||||
|
||||
if (isOntimeMilestone(eventData)) {
|
||||
@@ -115,35 +115,35 @@ export function createEventPatch(originalEvent: OntimeEvent, patchEvent: Partial
|
||||
};
|
||||
}
|
||||
|
||||
export function createBlockPatch(originalBlock: OntimeBlock, patchBlock: Partial<OntimeBlock>): OntimeBlock {
|
||||
if (Object.keys(patchBlock).length === 0) {
|
||||
return originalBlock;
|
||||
export function createGroupPatch(originalGroup: OntimeGroup, patchGroup: Partial<OntimeGroup>): OntimeGroup {
|
||||
if (Object.keys(patchGroup).length === 0) {
|
||||
return originalGroup;
|
||||
}
|
||||
|
||||
const maybeTargetDuration = () => {
|
||||
if (typeof patchBlock.targetDuration === 'number') {
|
||||
return patchBlock.targetDuration;
|
||||
if (typeof patchGroup.targetDuration === 'number') {
|
||||
return patchGroup.targetDuration;
|
||||
}
|
||||
if (patchBlock.targetDuration === null || patchBlock.targetDuration === '') {
|
||||
if (patchGroup.targetDuration === null || patchGroup.targetDuration === '') {
|
||||
return null;
|
||||
}
|
||||
return originalBlock.targetDuration;
|
||||
return originalGroup.targetDuration;
|
||||
};
|
||||
|
||||
return {
|
||||
id: originalBlock.id,
|
||||
type: SupportedEntry.Block,
|
||||
title: makeString(patchBlock.title, originalBlock.title),
|
||||
note: makeString(patchBlock.note, originalBlock.note),
|
||||
entries: patchBlock.entries ?? originalBlock.entries,
|
||||
id: originalGroup.id,
|
||||
type: SupportedEntry.Group,
|
||||
title: makeString(patchGroup.title, originalGroup.title),
|
||||
note: makeString(patchGroup.note, originalGroup.note),
|
||||
entries: patchGroup.entries ?? originalGroup.entries,
|
||||
targetDuration: maybeTargetDuration(),
|
||||
colour: makeString(patchBlock.colour, originalBlock.colour),
|
||||
revision: originalBlock.revision,
|
||||
timeStart: originalBlock.timeStart,
|
||||
timeEnd: originalBlock.timeEnd,
|
||||
duration: originalBlock.duration,
|
||||
isFirstLinked: originalBlock.isFirstLinked,
|
||||
custom: { ...originalBlock.custom, ...patchBlock.custom },
|
||||
colour: makeString(patchGroup.colour, originalGroup.colour),
|
||||
revision: originalGroup.revision,
|
||||
timeStart: originalGroup.timeStart,
|
||||
timeEnd: originalGroup.timeEnd,
|
||||
duration: originalGroup.duration,
|
||||
isFirstLinked: originalGroup.isFirstLinked,
|
||||
custom: { ...originalGroup.custom, ...patchGroup.custom },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -179,10 +179,10 @@ export function applyPatchToEntry(eventFromRundown: OntimeEntry, patch: Partial<
|
||||
return newEvent;
|
||||
}
|
||||
|
||||
if (isOntimeBlock(eventFromRundown)) {
|
||||
const newBlock = createBlockPatch(eventFromRundown as OntimeBlock, patch as Partial<OntimeBlock>);
|
||||
newBlock.revision++;
|
||||
return newBlock;
|
||||
if (isOntimeGroup(eventFromRundown)) {
|
||||
const newGroup = createGroupPatch(eventFromRundown as OntimeGroup, patch as Partial<OntimeGroup>);
|
||||
newGroup.revision++;
|
||||
return newGroup;
|
||||
}
|
||||
|
||||
if (isOntimeMilestone(eventFromRundown)) {
|
||||
@@ -218,16 +218,16 @@ export const createEvent = (eventArgs: Partial<OntimeEvent>, eventIndex: number
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new block from an optional patch
|
||||
* Creates a new group from an optional patch
|
||||
*/
|
||||
export function createBlock(patch?: Partial<OntimeBlock>): OntimeBlock {
|
||||
export function createGroup(patch?: Partial<OntimeGroup>): OntimeGroup {
|
||||
if (!patch) {
|
||||
return { ...blockDef, id: generateId() };
|
||||
return { ...groupDef, id: generateId() };
|
||||
}
|
||||
|
||||
return {
|
||||
id: patch.id ?? generateId(),
|
||||
type: SupportedEntry.Block,
|
||||
type: SupportedEntry.Group,
|
||||
title: patch.title ?? '',
|
||||
note: patch.note ?? '',
|
||||
entries: patch.entries ?? [],
|
||||
@@ -385,13 +385,13 @@ export function cloneMilestone(entry: OntimeMilestone, newId: EntryId): OntimeMi
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers business logic for how to clone an OntimeBlock
|
||||
* Gathers business logic for how to clone an OntimeGroup
|
||||
*/
|
||||
export function cloneBlock(entry: OntimeBlock, newId: EntryId): OntimeBlock {
|
||||
export function cloneGroup(entry: OntimeGroup, newId: EntryId): OntimeGroup {
|
||||
const newEntry = structuredClone(entry);
|
||||
newEntry.id = newId;
|
||||
|
||||
// in blocks, we need to remove the events references
|
||||
// in groups, we need to remove the events references
|
||||
newEntry.entries = [];
|
||||
newEntry.revision = 0;
|
||||
return newEntry;
|
||||
@@ -405,8 +405,8 @@ export function cloneEntry(entry: OntimeEntry, newId: EntryId): OntimeEntry {
|
||||
return cloneEvent(entry, newId);
|
||||
} else if (isOntimeDelay(entry)) {
|
||||
return cloneDelay(entry, newId);
|
||||
} else if (isOntimeBlock(entry)) {
|
||||
return cloneBlock(entry, newId);
|
||||
} else if (isOntimeGroup(entry)) {
|
||||
return cloneGroup(entry, newId);
|
||||
} else if (isOntimeMilestone(entry)) {
|
||||
return cloneMilestone(entry, newId);
|
||||
}
|
||||
@@ -452,7 +452,7 @@ export function calculateDayOffset(
|
||||
*/
|
||||
export function getInsertAfterId(
|
||||
rundown: Rundown,
|
||||
parent: OntimeBlock | null,
|
||||
parent: OntimeGroup | null,
|
||||
afterId?: EntryId,
|
||||
beforeId?: EntryId,
|
||||
): EntryId | null {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { body, param } from 'express-validator';
|
||||
import { requestValidationFunction } from '../validation-utils/validationFunction.js';
|
||||
|
||||
export const rundownPostValidator = [
|
||||
body('type').isString().isIn(['event', 'delay', 'block', 'milestone']),
|
||||
body('type').isString().isIn(['event', 'delay', 'group', 'milestone']),
|
||||
body('after').optional().isString(),
|
||||
body('before').optional().isString(),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user