Skip to content

Commit 4175fd0

Browse files
authored
Merge pull request #1378 from bbc/upstream/allow-removing-pieceinstances-from-current-part
feat: allow adlib-actions to remove pieces from the current partInstance
2 parents c7f5208 + 33514b1 commit 4175fd0

File tree

10 files changed

+74
-34
lines changed

10 files changed

+74
-34
lines changed

packages/blueprints-integration/src/context/onSetAsNextContext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ export interface IOnSetAsNextContext extends IShowStyleUserContext, IEventContex
6767
/**
6868
* Destructive actions
6969
*/
70-
/** Remove piecesInstances by id. Returns ids of piecesInstances that were removed. Note: For now we only allow removing from the next, but this might change to include current if there is justification */
71-
removePieceInstances(part: 'next', pieceInstanceIds: string[]): Promise<string[]>
70+
/** Remove piecesInstances by id. Returns ids of piecesInstances that were removed. */
71+
removePieceInstances(part: 'current' | 'next', pieceInstanceIds: string[]): Promise<string[]>
7272

7373
/**
7474
* Move the next part through the rundown. Can move by either a number of parts, or segments in either direction.

packages/blueprints-integration/src/context/partsAndPieceActionContext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,6 @@ export interface IPartAndPieceActionContext {
6868
stopPiecesOnLayers(sourceLayerIds: string[], timeOffset?: number): Promise<string[]>
6969
/** Stop piecesInstances by id. Returns ids of piecesInstances that were removed */
7070
stopPieceInstances(pieceInstanceIds: string[], timeOffset?: number): Promise<string[]>
71-
/** Remove piecesInstances by id. Returns ids of piecesInstances that were removed. Note: For now we only allow removing from the next, but this might change to include current if there is justification */
72-
removePieceInstances(part: 'next', pieceInstanceIds: string[]): Promise<string[]>
71+
/** Remove piecesInstances by id. Returns ids of piecesInstances that were removed. */
72+
removePieceInstances(part: 'current' | 'next', pieceInstanceIds: string[]): Promise<string[]>
7373
}

packages/job-worker/src/blueprints/__tests__/context-OnSetAsNextContext.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ describe('Test blueprint api context', () => {
113113
await context.removePieceInstances('next', ['pieceInstanceId'])
114114
expect(mockActionService.removePieceInstances).toHaveBeenCalledTimes(1)
115115
expect(mockActionService.removePieceInstances).toHaveBeenCalledWith('next', ['pieceInstanceId'])
116+
117+
await context.removePieceInstances('current', ['pieceInstanceId'])
118+
expect(mockActionService.removePieceInstances).toHaveBeenCalledTimes(2)
119+
expect(mockActionService.removePieceInstances).toHaveBeenCalledWith('current', ['pieceInstanceId'])
116120
})
117121

118122
test('updatePartInstance', async () => {

packages/job-worker/src/blueprints/__tests__/context-OnTakeContext.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ describe('Test blueprint api context', () => {
129129
await context.removePieceInstances('next', ['pieceInstanceId'])
130130
expect(mockActionService.removePieceInstances).toHaveBeenCalledTimes(1)
131131
expect(mockActionService.removePieceInstances).toHaveBeenCalledWith('next', ['pieceInstanceId'])
132+
133+
await context.removePieceInstances('current', ['pieceInstanceId'])
134+
expect(mockActionService.removePieceInstances).toHaveBeenCalledTimes(2)
135+
expect(mockActionService.removePieceInstances).toHaveBeenCalledWith('current', ['pieceInstanceId'])
132136
})
133137

134138
test('updatePartInstance', async () => {

packages/job-worker/src/blueprints/__tests__/context-adlibActions.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ describe('Test blueprint api context', () => {
139139
await context.removePieceInstances('next', ['pieceInstanceId'])
140140
expect(mockActionService.removePieceInstances).toHaveBeenCalledTimes(1)
141141
expect(mockActionService.removePieceInstances).toHaveBeenCalledWith('next', ['pieceInstanceId'])
142+
143+
await context.removePieceInstances('current', ['pieceInstanceId'])
144+
expect(mockActionService.removePieceInstances).toHaveBeenCalledTimes(2)
145+
expect(mockActionService.removePieceInstances).toHaveBeenCalledWith('current', ['pieceInstanceId'])
142146
})
143147

144148
test('updatePartInstance', async () => {

packages/job-worker/src/blueprints/context/OnSetAsNextContext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ export class OnSetAsNextContext
117117
return this.partAndPieceInstanceService.updatePartInstance(part, props)
118118
}
119119

120-
async removePieceInstances(_part: 'next', pieceInstanceIds: string[]): Promise<string[]> {
121-
return this.partAndPieceInstanceService.removePieceInstances('next', pieceInstanceIds)
120+
async removePieceInstances(part: 'current' | 'next', pieceInstanceIds: string[]): Promise<string[]> {
121+
return this.partAndPieceInstanceService.removePieceInstances(part, pieceInstanceIds)
122122
}
123123

124124
async moveNextPart(partDelta: number, segmentDelta: number, ignoreQuickLoop?: boolean): Promise<boolean> {

packages/job-worker/src/blueprints/context/OnTakeContext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export class OnTakeContext extends ShowStyleUserContext implements IOnTakeContex
117117
async stopPieceInstances(pieceInstanceIds: string[], timeOffset?: number | undefined): Promise<string[]> {
118118
return this.partAndPieceInstanceService.stopPieceInstances(pieceInstanceIds, timeOffset)
119119
}
120-
async removePieceInstances(part: 'next', pieceInstanceIds: string[]): Promise<string[]> {
120+
async removePieceInstances(part: 'current' | 'next', pieceInstanceIds: string[]): Promise<string[]> {
121121
return this.partAndPieceInstanceService.removePieceInstances(part, pieceInstanceIds)
122122
}
123123

packages/job-worker/src/blueprints/context/adlibActions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct
183183
return this.partAndPieceInstanceService.stopPieceInstances(pieceInstanceIds, timeOffset)
184184
}
185185

186-
async removePieceInstances(part: 'next', pieceInstanceIds: string[]): Promise<string[]> {
186+
async removePieceInstances(part: 'current' | 'next', pieceInstanceIds: string[]): Promise<string[]> {
187187
return this.partAndPieceInstanceService.removePieceInstances(part, pieceInstanceIds)
188188
}
189189

packages/job-worker/src/blueprints/context/services/PartAndPieceInstanceActionService.ts

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,15 @@ export class PartAndPieceInstanceActionService {
9595
this.showStyleCompound = showStyle
9696
}
9797

98-
private _getPartInstance(part: 'current' | 'next'): PlayoutPartInstanceModel | null {
98+
#trackStateChange(part: 'current' | 'next', change: ActionPartChange): void {
99+
if (part === 'current') {
100+
this.currentPartState = Math.max(this.currentPartState, change)
101+
} else {
102+
this.nextPartState = Math.max(this.nextPartState, change)
103+
}
104+
}
105+
106+
#getPartInstance(part: 'current' | 'next'): PlayoutPartInstanceModel | null {
99107
switch (part) {
100108
case 'current':
101109
return this._playoutModel.currentPartInstance
@@ -109,16 +117,16 @@ export class PartAndPieceInstanceActionService {
109117
}
110118

111119
async getPartInstance(part: 'current' | 'next'): Promise<IBlueprintPartInstance | undefined> {
112-
const partInstance = this._getPartInstance(part)
120+
const partInstance = this.#getPartInstance(part)
113121

114122
return partInstance ? convertPartInstanceToBlueprints(partInstance.partInstance) : undefined
115123
}
116124
async getPieceInstances(part: 'current' | 'next'): Promise<IBlueprintPieceInstance[]> {
117-
const partInstance = this._getPartInstance(part)
125+
const partInstance = this.#getPartInstance(part)
118126
return partInstance?.pieceInstances?.map((p) => convertPieceInstanceToBlueprints(p.pieceInstance)) ?? []
119127
}
120128
async getResolvedPieceInstances(part: 'current' | 'next'): Promise<IBlueprintResolvedPieceInstance[]> {
121-
const partInstance = this._getPartInstance(part)
129+
const partInstance = this.#getPartInstance(part)
122130
if (!partInstance) {
123131
return []
124132
}
@@ -244,7 +252,7 @@ export class PartAndPieceInstanceActionService {
244252
}
245253

246254
async insertPiece(part: 'current' | 'next', rawPiece: IBlueprintPiece): Promise<IBlueprintPieceInstance> {
247-
const partInstance = this._getPartInstance(part)
255+
const partInstance = this.#getPartInstance(part)
248256
if (!partInstance) {
249257
throw new Error('Cannot insert piece when no active part')
250258
}
@@ -270,11 +278,7 @@ export class PartAndPieceInstanceActionService {
270278
// Do the work
271279
const newPieceInstance = partInstance.insertAdlibbedPiece(piece, undefined)
272280

273-
if (part === 'current') {
274-
this.currentPartState = Math.max(this.currentPartState, ActionPartChange.SAFE_CHANGE)
275-
} else {
276-
this.nextPartState = Math.max(this.nextPartState, ActionPartChange.SAFE_CHANGE)
277-
}
281+
this.#trackStateChange(part, ActionPartChange.SAFE_CHANGE)
278282

279283
return convertPieceInstanceToBlueprints(newPieceInstance.pieceInstance)
280284
}
@@ -330,8 +334,8 @@ export class PartAndPieceInstanceActionService {
330334

331335
// setupPieceInstanceInfiniteProperties(pieceInstance)
332336

333-
this.nextPartState = Math.max(this.nextPartState, updatesNextPart)
334-
this.currentPartState = Math.max(this.currentPartState, updatesCurrentPart)
337+
this.#trackStateChange('next', updatesNextPart)
338+
this.#trackStateChange('current', updatesCurrentPart)
335339

336340
return convertPieceInstanceToBlueprints(pieceInstance.pieceInstance)
337341
}
@@ -340,7 +344,7 @@ export class PartAndPieceInstanceActionService {
340344
part: 'current' | 'next',
341345
props: Partial<IBlueprintMutatablePart>
342346
): Promise<IBlueprintPartInstance> {
343-
const partInstance = this._getPartInstance(part)
347+
const partInstance = this.#getPartInstance(part)
344348
if (!partInstance) {
345349
throw new Error('PartInstance could not be found')
346350
}
@@ -351,14 +355,7 @@ export class PartAndPieceInstanceActionService {
351355
throw new Error('Some valid properties must be defined')
352356
}
353357

354-
this.nextPartState = Math.max(
355-
this.nextPartState,
356-
part === 'next' ? ActionPartChange.SAFE_CHANGE : ActionPartChange.NONE
357-
)
358-
this.currentPartState = Math.max(
359-
this.currentPartState,
360-
part === 'current' ? ActionPartChange.SAFE_CHANGE : ActionPartChange.NONE
361-
)
358+
this.#trackStateChange(part, ActionPartChange.SAFE_CHANGE)
362359

363360
return convertPartInstanceToBlueprints(partInstance.partInstance)
364361
}
@@ -450,8 +447,8 @@ export class PartAndPieceInstanceActionService {
450447
)
451448
}
452449

453-
async removePieceInstances(_part: 'next', pieceInstanceIds: string[]): Promise<string[]> {
454-
const partInstance = this._getPartInstance('next')
450+
async removePieceInstances(part: 'current' | 'next', pieceInstanceIds: string[]): Promise<string[]> {
451+
const partInstance = this.#getPartInstance(part)
455452
if (!partInstance) {
456453
throw new Error('Cannot remove pieceInstances when no selected partInstance')
457454
}
@@ -466,7 +463,7 @@ export class PartAndPieceInstanceActionService {
466463
}
467464
}
468465

469-
this.nextPartState = Math.max(this.nextPartState, ActionPartChange.SAFE_CHANGE)
466+
this.#trackStateChange(part, ActionPartChange.SAFE_CHANGE)
470467

471468
return unprotectStringArray(removedPieceInstanceIds)
472469
}
@@ -505,7 +502,7 @@ export class PartAndPieceInstanceActionService {
505502
)
506503

507504
if (stoppedIds.length > 0) {
508-
this.currentPartState = Math.max(this.currentPartState, ActionPartChange.SAFE_CHANGE)
505+
this.#trackStateChange('current', ActionPartChange.SAFE_CHANGE)
509506
}
510507

511508
return unprotectStringArray(stoppedIds)

packages/job-worker/src/blueprints/context/services/__tests__/PartAndPieceInstanceActionService.test.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1610,7 +1610,7 @@ describe('Test blueprint api context', () => {
16101610
})
16111611
})
16121612

1613-
test('good', async () => {
1613+
test('good - from next', async () => {
16141614
const { jobContext, playlistId, allPartInstances } = await setupMyDefaultRundown()
16151615

16161616
const partInstance = allPartInstances[0]
@@ -1638,6 +1638,37 @@ describe('Test blueprint api context', () => {
16381638
expect(service.nextPartState).toEqual(ActionPartChange.SAFE_CHANGE)
16391639
})
16401640
})
1641+
1642+
test('good - from current', async () => {
1643+
const { jobContext, playlistId, allPartInstances } = await setupMyDefaultRundown()
1644+
1645+
const partInstance = allPartInstances[0]
1646+
await setPartInstances(jobContext, playlistId, partInstance, undefined)
1647+
1648+
await wrapWithPlayoutModel(jobContext, playlistId, async (playoutModel) => {
1649+
const { service } = await getTestee(jobContext, playoutModel)
1650+
1651+
const beforePieceInstancesCounts = getPieceInstanceCounts(playoutModel)
1652+
expect(beforePieceInstancesCounts.previous).toEqual(0)
1653+
expect(beforePieceInstancesCounts.current).not.toEqual(0)
1654+
expect(beforePieceInstancesCounts.next).toEqual(0)
1655+
expect(beforePieceInstancesCounts.other).toEqual(0)
1656+
1657+
// Find the instance, and create its backing piece
1658+
const targetPieceInstance = playoutModel.currentPartInstance!.pieceInstances[0]
1659+
expect(targetPieceInstance).toBeTruthy()
1660+
1661+
await expect(
1662+
service.removePieceInstances('current', [
1663+
unprotectString(targetPieceInstance.pieceInstance._id),
1664+
])
1665+
).resolves.toEqual([unprotectString(targetPieceInstance.pieceInstance._id)])
1666+
1667+
// Ensure it was all removed
1668+
expect(playoutModel.findPieceInstance(targetPieceInstance.pieceInstance._id)).toBeFalsy()
1669+
expect(service.currentPartState).toEqual(ActionPartChange.SAFE_CHANGE)
1670+
})
1671+
})
16411672
})
16421673

16431674
describe('updatePartInstance', () => {

0 commit comments

Comments
 (0)