Improve Clone (#1897)

* refactor(rundown): optimise copy-paste performance

* chore: configure opt-in compiler

* refactor(rundown): stabilise frequently accessed data

* feat(clone): allow cloning any element

* remove paste above and cue increment from test

---------

Co-authored-by: arc-alex <ac@omnivox.dk>
This commit is contained in:
Carlos Valente
2025-11-28 16:20:52 +01:00
committed by GitHub
parent a78586d2fa
commit 3f1f06f7c5
21 changed files with 321 additions and 250 deletions
@@ -1564,7 +1564,7 @@ describe('rundownMutation.swap()', () => {
});
describe('rundownMutation.clone()', () => {
it('clones an event and adds it to the rundown', () => {
it('clones at the top level of the rundown', () => {
const testRundown = makeRundown({
order: ['1'],
entries: {
@@ -1583,7 +1583,7 @@ describe('rundownMutation.clone()', () => {
});
});
it('clones an event inside a group and adds it to the rundown', () => {
it('clones an event inside a group', () => {
const testRundown = makeRundown({
order: ['1'],
entries: {
@@ -1621,6 +1621,55 @@ describe('rundownMutation.clone()', () => {
});
expect((testRundown.entries[newEntry.id] as OntimeGroup).entries[0]).not.toBe('1a');
});
it('clones an entry from a group inside another group', () => {
const testRundown = makeRundown({
order: ['group1', 'group2'],
entries: {
group1: makeOntimeGroup({ id: 'group1', entries: ['event1'] }),
group2: makeOntimeGroup({ id: 'group2', entries: ['event2'] }),
event1: makeOntimeEvent({ id: 'event1', cue: 'nested-event', parent: 'group1' }),
event2: makeOntimeEvent({ id: 'event2', cue: 'nested-event', parent: 'group2' }),
},
});
const newEntry = rundownMutation.clone(testRundown, testRundown.entries['event2'], {
after: 'event1',
}) as OntimeEvent;
// new event is added to group
expect(testRundown.entries['group1']).toMatchObject({
entries: ['event1', newEntry.id],
});
// new references the parent group
expect(newEntry.parent).toBe('group1');
// the flat rundown remains unchanged
expect(testRundown.order).toStrictEqual(['group1', 'group2']);
});
it('clones an event and inserts it before another event', () => {
const testRundown = makeRundown({
order: ['1', '2'],
entries: {
'1': makeOntimeEvent({ id: '1', cue: 'event1', parent: null }),
'2': makeOntimeEvent({ id: '2', cue: 'event2', parent: null }),
},
});
const newEntry = rundownMutation.clone(testRundown, testRundown.entries['1'], { before: '2' });
// Verify the rundown order is updated correctly
expect(testRundown.order).toStrictEqual(['1', newEntry.id, '2']);
// Verify the cloned entry is added to the rundown
expect(testRundown.entries[newEntry.id]).toMatchObject({
type: SupportedEntry.Event,
cue: 'event1',
parent: null,
});
});
});
describe('rundownMutation.group()', () => {
@@ -13,6 +13,7 @@ import {
duplicateRundown,
getInsertAfterId,
hasChanges,
makeDeepClone,
} from '../rundown.utils.js';
import { makeOntimeGroup, makeOntimeEvent, makeRundown } from '../__mocks__/rundown.mocks.js';
@@ -265,7 +266,7 @@ describe('getInsertAfterId()', () => {
});
describe('duplicateRundown', () => {
it("duplicates a given rundown", () => {
it('duplicates a given rundown', () => {
const demoRundown = demoDb.rundowns['default'];
const title = 'Duplicated Rundown';
const duplicatedRundown = duplicateRundown(demoRundown, title);
@@ -275,10 +276,51 @@ describe('duplicateRundown', () => {
entries: expect.any(Object),
order: expect.any(Array),
flatOrder: expect.any(Array),
})
});
expect(demoRundown.id).not.toEqual(duplicatedRundown.id);
expect(duplicatedRundown.order.length).toEqual(demoRundown.order.length);
expect(duplicatedRundown.flatOrder.length).toEqual(demoRundown.flatOrder.length);
expect(Object.keys(duplicatedRundown.entries).length).toEqual(Object.keys(demoRundown.entries).length);
})
})
});
});
describe('makeDeepClone()', () => {
it('deep clones a group along with its nested entries', () => {
const group1 = makeOntimeGroup({ id: 'group1', title: 'Group 1', entries: ['event1', 'event2'] });
const rundown = makeRundown({
entries: {
group1,
event1: makeOntimeEvent({ id: 'event1', title: 'Event 1', parent: 'group1' }),
event2: makeOntimeEvent({ id: 'event2', title: 'Event 2', parent: 'group1' }),
},
order: ['group1'],
flatOrder: ['group1', 'event1', 'event2'],
});
const { newGroup, nestedEntries } = makeDeepClone(group1, rundown);
expect(newGroup).toMatchObject({
id: expect.any(String),
title: 'Group 1 (copy)',
entries: [expect.any(String), expect.any(String)],
revision: 0,
});
expect(newGroup.id).not.toEqual('group1');
expect(newGroup.entries.length).toEqual(group1.entries.length);
expect(nestedEntries).toMatchObject([
{
id: expect.any(String),
title: 'Event 1',
parent: newGroup.id,
revision: 0,
},
{
id: expect.any(String),
title: 'Event 2',
parent: newGroup.id,
revision: 0,
},
]);
});
});