Skip to content

Commit e1577ef

Browse files
committed
Merge branch 'fix-memory-leaks' into bbc-main-autonext
2 parents 9c828a6 + fd1f4c5 commit e1577ef

6 files changed

Lines changed: 55 additions & 10 deletions

File tree

packages/webui/src/client/lib/VirtualElement.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ export function VirtualElement({
199199
}
200200
}
201201
} else {
202-
if (ref) {
202+
if (ref) {
203203
resizeObserverManager.unobserve(ref)
204204
isCurrentlyObserving.current = false
205205
}
@@ -463,6 +463,7 @@ export class ElementObserverManager {
463463

464464
public observe(element: HTMLElement, callback: () => void): void {
465465
if (!element) return
466+
if (!document.contains(element)) return
466467

467468
this.observedElements.set(element, callback)
468469
this.resizeObserver.observe(element)
@@ -481,6 +482,13 @@ export class ElementObserverManager {
481482

482483
// Disconnect and reconnect mutation observer to refresh the list of observed elements
483484
this.mutationObserver.disconnect()
485+
for (const observedElement of this.observedElements.keys()) {
486+
if (!document.contains(observedElement)) {
487+
this.observedElements.delete(observedElement)
488+
this.resizeObserver.unobserve(observedElement)
489+
}
490+
}
491+
484492
if (this.observedElements.size === 0) {
485493
this.resizeObserver.disconnect()
486494
return

packages/webui/src/client/ui/ClockView/CameraScreen/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,15 @@ export function CameraScreen({ playlist, studioId }: Readonly<IProps>): JSX.Elem
147147
useSetDocumentDarkTheme()
148148

149149
useEffect(() => {
150-
const containerEl = document.querySelector('#render-target > .container-fluid.header-clear')
150+
const getContainerEl = () => document.querySelector('#render-target > .container-fluid.header-clear')
151+
const containerEl = getContainerEl()
151152
if (containerEl) containerEl.classList.remove('header-clear')
152153

153154
return () => {
154-
if (containerEl) containerEl.classList.add('header-clear')
155+
const currentContainerEl = getContainerEl()
156+
if (currentContainerEl && currentContainerEl === containerEl) {
157+
currentContainerEl.classList.add('header-clear')
158+
}
155159
}
156160
}, [])
157161

packages/webui/src/client/ui/SegmentList/LinePartPieceIndicator/LinePartAdLibIndicator.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useMemo } from 'react'
1+
import { useCallback, useEffect, useMemo, useRef } from 'react'
22
import type { PartId } from '@sofie-automation/corelib/dist/dataModel/Ids'
33
import type { AdLibAction } from '@sofie-automation/corelib/dist/dataModel/AdlibAction'
44
import type { AdLibPiece } from '@sofie-automation/corelib/dist/dataModel/AdLibPiece'
@@ -20,6 +20,7 @@ interface IProps {
2020

2121
export const LinePartAdLibIndicator: React.FC<IProps> = function LinePartAdLibIndicator({ sourceLayers, partId }) {
2222
const { t } = useTranslation()
23+
const revealTimeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
2324

2425
const sourceLayerIds = useMemo(() => sourceLayers.map((sourceLayer) => sourceLayer._id), [sourceLayers])
2526
const label = useMemo(() => sourceLayers[0]?.name ?? '', [sourceLayers])
@@ -64,13 +65,22 @@ export const LinePartAdLibIndicator: React.FC<IProps> = function LinePartAdLibIn
6465
RundownViewEventBus.emit(RundownViewEvents.SHELF_STATE, {
6566
state: true,
6667
})
67-
setTimeout(() => {
68+
revealTimeoutRef.current = setTimeout(() => {
6869
RundownViewEventBus.emit(RundownViewEvents.REVEAL_IN_SHELF, {
6970
pieceId: pieceId,
7071
})
7172
}, 100)
7273
}, [adLibPieces, adLibActions])
7374

75+
useEffect(() => {
76+
return () => {
77+
if (revealTimeoutRef.current) {
78+
clearTimeout(revealTimeoutRef.current)
79+
revealTimeoutRef.current = undefined
80+
}
81+
}
82+
}, [])
83+
7484
return (
7585
<StudioContext.Consumer>
7686
{(studio) => {

packages/webui/src/client/ui/SegmentList/LinePartPieceIndicator/LinePartIndicator.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export function LinePartIndicator({
6565
return () => {
6666
window.removeEventListener('mousedown', onClickAway)
6767
}
68-
}, [])
68+
}, [onClickAway])
6969

7070
return (
7171
<>

packages/webui/src/client/ui/SegmentTimeline/Renderers/VTSourceRenderer.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class VTSourceRendererBase extends CustomLayerItemRenderer<IProps & WithTranslat
8181

8282
private mountAuxiliaryNode(node: HTMLSpanElement | null, target: HTMLElement | null): void {
8383
if (!node || !target) return
84+
if (!document.contains(target)) return
8485

8586
if (node.parentElement !== target) {
8687
this.removeAuxiliaryNode(node)
@@ -92,7 +93,15 @@ class VTSourceRendererBase extends CustomLayerItemRenderer<IProps & WithTranslat
9293
if (!itemElement) return null
9394

9495
if (this.getItemDuration(true) === Number.POSITIVE_INFINITY) {
95-
return itemElement.parentElement?.parentElement?.parentElement ?? null
96+
const target = itemElement.parentElement?.parentElement?.parentElement ?? null
97+
if (target && !document.contains(target)) {
98+
return null
99+
}
100+
return target
101+
}
102+
103+
if (!document.contains(itemElement)) {
104+
return null
96105
}
97106

98107
return itemElement
@@ -101,12 +110,19 @@ class VTSourceRendererBase extends CustomLayerItemRenderer<IProps & WithTranslat
101110
private getCountdownTarget(itemElement: HTMLElement | null): HTMLElement | null {
102111
if (!itemElement) return null
103112

104-
105113
const liveLine =
106114
itemElement.parentElement?.parentElement?.parentElement?.parentElement?.parentElement?.querySelector(
107115
'.segment-timeline__liveline'
108116
)
109-
return liveLine instanceof HTMLElement ? liveLine : null
117+
if (!(liveLine instanceof HTMLElement)) {
118+
return null
119+
}
120+
121+
if (!document.contains(liveLine)) {
122+
return null
123+
}
124+
125+
return liveLine
110126
}
111127

112128
getItemLabelOffsetRight(): React.CSSProperties {

packages/webui/src/client/ui/SegmentTimeline/SegmentTimelineContainer.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
import { UIStateStorage } from '../../lib/UIStateStorage.js'
1010
import { SpeechSynthesiser } from '../../lib/speechSynthesis.js'
1111
import { getElementWidth } from '../../utils/dimensions.js'
12-
import { isMaintainingFocus, scrollToSegment, getHeaderHeight } from '../../lib/viewPort.js'
12+
import { isMaintainingFocus, scrollToSegment, getHeaderHeight, resetViewportScrollState } from '../../lib/viewPort.js'
1313
import { unprotectString } from '@sofie-automation/shared-lib/dist/lib/protectedString'
1414
import { equivalentArrays } from '@sofie-automation/shared-lib/dist/lib/lib'
1515
import { Settings } from '../../lib/Settings.js'
@@ -353,6 +353,13 @@ const SegmentTimelineContainerContent = withResolvedSegment(
353353
if (typeof this.props.onSegmentScroll === 'function') this.props.onSegmentScroll()
354354
}
355355

356+
if (this.visibilityChangeTimeout) {
357+
clearTimeout(this.visibilityChangeTimeout)
358+
this.visibilityChangeTimeout = undefined
359+
}
360+
361+
resetViewportScrollState()
362+
356363
this.stopLive()
357364
RundownViewEventBus.off(RundownViewEvents.REWIND_SEGMENTS, this.onRewindSegment)
358365
RundownViewEventBus.off(RundownViewEvents.GO_TO_PART, this.onGoToPart)

0 commit comments

Comments
 (0)