Skip to content

Conversation

ameer2468
Copy link
Collaborator

@ameer2468 ameer2468 commented Oct 16, 2025

This PR: If you open or record a long or short recording, the zoom level will automatically be set on mount (initially) just enough so you can see your zoom segment well enough, whether adding or already for existing ones.

This deals with the pain of having to manually zoom in initially so you can add and control your newly added zoom segment properly or modify existing ones.

Summary by CodeRabbit

  • Bug Fixes
    • Timeline editor now automatically adjusts zoom levels on load to enforce a minimum segment width, ensuring timeline segments remain readable. Zoom is intelligently optimized based on timeline dimensions.

@ameer2468 ameer2468 added the Desktop Things affecting desktop app label Oct 16, 2025
Copy link
Contributor

coderabbitai bot commented Oct 16, 2025

Walkthrough

The Timeline component's onMount lifecycle now includes a runtime check that enforces a minimum segment width of 80 pixels by adjusting the zoom level. If timeline bounds are available, it computes desired zoom based on segment count; if not, it retries after 10 milliseconds.

Changes

Cohort / File(s) Change Summary
Timeline component zoom validation
apps/desktop/src/routes/editor/Timeline/index.tsx
Added checkBounds function in onMount lifecycle that validates timeline width and adjusts zoom level to enforce minimum 80-pixel segment width. Implements retry logic with 10ms delay if dimensions unavailable.

Sequence Diagram

sequenceDiagram
    participant React as React Lifecycle
    participant Mount as Timeline.onMount
    participant DOM as DOM/timelineBounds
    participant State as Transform State

    React->>Mount: Component mounting
    Mount->>Mount: Call checkBounds()
    Mount->>DOM: Check if timelineBounds.width exists
    
    alt Width available and > 0
        DOM-->>Mount: width > 0
        Mount->>Mount: Compute desiredZoom<br/>(80px min per segment)
        alt Current zoom exceeds desired
            Mount->>State: Update transform.zoom
            State-->>Mount: Zoom adjusted
        else Current zoom acceptable
            Mount-->>Mount: No adjustment needed
        end
    else Width not available yet
        DOM-->>Mount: width = 0 or undefined
        Mount->>Mount: Schedule retry<br/>(setTimeout 10ms)
        Mount->>Mount: Call checkBounds() again
    end
    
    Mount-->>React: onMount complete
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

The change is localized to a single file with straightforward conditional logic for zoom adjustment and retry scheduling. Review focuses on validating the minimum segment width calculation, timeout handling, and potential edge cases with DOM readiness.

Poem

🐰 A timeline grows tight, zoom must align,
Eighty pixels dancing, the segments align,
When bounds aren't ready, we wait just a tick—
Ten milliseconds of patience, a scheduling trick!
✨ The view now respects what the eye should behold.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly summarizes the primary change of automatically setting the initial zoom level in the desktop app and directly reflects the added runtime check in Timeline.onMount to enforce minimum segment width. It is concise, clear, and specific enough for teammates to understand the main intent without extra detail. It avoids vague wording and aligns with the PR’s objectives.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch improve-zoom-ux

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ameer2468 ameer2468 merged commit 5638a95 into main Oct 16, 2025
15 checks passed
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/desktop/src/routes/editor/Timeline/index.tsx (1)

58-60: Calculation doesn't consider segment count as mentioned in summary.

The AI-generated summary states that the code "computes desired zoom based on segment count," but the implementation only uses a fixed minSegmentPixels = 80 constant. This means:

  1. All segments will be 80 pixels wide regardless of how many segments exist
  2. For recordings with many segments, the timeline could become excessively wide
  3. For recordings with few segments, the zoom level might not be optimal

Consider incorporating the actual segment count into the calculation:

-		const minSegmentPixels = 80;
-		const secondsPerPixel = 1 / minSegmentPixels;
-		const desiredZoom = timelineBounds.width * secondsPerPixel;
+		const MIN_SEGMENT_PIXELS = 80;
+		const segmentCount = project.timeline?.zoomSegments?.length || 1;
+		const desiredZoom = (timelineBounds.width / segmentCount) * (1 / MIN_SEGMENT_PIXELS);

Also, extract the magic number 80 as a module-level constant for better maintainability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1ca80a and ec1ee46.

📒 Files selected for processing (1)
  • apps/desktop/src/routes/editor/Timeline/index.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Use strict TypeScript and avoid any; leverage shared types

Files:

  • apps/desktop/src/routes/editor/Timeline/index.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/desktop/src/routes/editor/Timeline/index.tsx
apps/desktop/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/desktop/src/**/*.{ts,tsx}: Desktop icons are auto-imported (unplugin-icons); do not import icons manually
Desktop IPC: Call generated tauri_specta commands/events; listen to generated events and use typed interfaces
Use @tanstack/solid-query for server state in the desktop app

Files:

  • apps/desktop/src/routes/editor/Timeline/index.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (javascript-typescript)

Comment on lines +56 to +68
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);
}
};
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Desktop Things affecting desktop app

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant