Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions apps/desktop/src/routes/editor/Timeline/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@ export function Timeline() {
});
resume();
}

const checkBounds = () => {
if (timelineBounds.width && timelineBounds.width > 0) {
const minSegmentPixels = 80;
const secondsPerPixel = 1 / minSegmentPixels;
const desiredZoom = timelineBounds.width * secondsPerPixel;

if (transform().zoom > desiredZoom) {
transform().updateZoom(desiredZoom, 0);
}
} else {
setTimeout(checkBounds, 10);
}
};
Comment on lines +56 to +68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add safeguards to prevent infinite retry loop.

The checkBounds function will retry indefinitely if timelineBounds.width never becomes available (e.g., if the element is hidden or removed). Additionally, if the component unmounts while a retry is scheduled, the timeout will continue executing, potentially causing a memory leak.

Consider adding:

  1. A maximum retry count or timeout duration
  2. A cleanup mechanism in onCleanup to cancel pending timeouts
  3. Store the timeout ID to enable cancellation
+	const [checkBoundsTimeoutId, setCheckBoundsTimeoutId] = createSignal<number | null>(null);

 	onMount(() => {
 		if (!project.timeline) {
 			const resume = projectHistory.pause();
 			setProject("timeline", {
 				segments: [
 					{
 						timescale: 1,
 						start: 0,
 						end: duration(),
 					},
 				],
 			});
 			resume();
 		}
 
+		let retryCount = 0;
+		const MAX_RETRIES = 100; // 1 second total
+
 		const checkBounds = () => {
 			if (timelineBounds.width && timelineBounds.width > 0) {
 				const minSegmentPixels = 80;
 				const secondsPerPixel = 1 / minSegmentPixels;
 				const desiredZoom = timelineBounds.width * secondsPerPixel;
 
 				if (transform().zoom > desiredZoom) {
 					transform().updateZoom(desiredZoom, 0);
 				}
-			} else {
-				setTimeout(checkBounds, 10);
+			} else if (retryCount < MAX_RETRIES) {
+				retryCount++;
+				const timeoutId = setTimeout(checkBounds, 10);
+				setCheckBoundsTimeoutId(timeoutId);
 			}
 		};
 
 		checkBounds();
+		
+		onCleanup(() => {
+			const timeoutId = checkBoundsTimeoutId();
+			if (timeoutId !== null) {
+				clearTimeout(timeoutId);
+			}
+		});
 	});
🤖 Prompt for AI Agents
In apps/desktop/src/routes/editor/Timeline/index.tsx around lines 56 to 68,
checkBounds currently schedules infinite retries via setTimeout and never
cancels them if the component unmounts; add a max retry count (or deadline) and
track the timeout ID so retries stop after N attempts or a timeout duration,
store that ID in a ref/local variable, and clear it in the component's cleanup
(onCleanup) to avoid leaks; also guard scheduling so you only call setTimeout
when the component is still mounted (or use an isMounted flag) and prevent
further retries once width becomes available or max retries are reached.


checkBounds();
});

if (
Expand Down