Skip to content

Conversation

@RohitR311
Copy link
Collaborator

@RohitR311 RohitR311 commented Nov 3, 2025

What this PR does?

Sunsets the old spinning browser loader. Introduces inline loading progress indicator for browser spin up.

2025-11-03.13-35-09.online-video-cutter.com.mp4

Summary by CodeRabbit

  • New Features

    • Visible initial-load progress reporting during page loads and a DOM-driven rendering path for recordings.
    • New /recording-setup route.
  • UI/UX Improvements

    • Persistent two-pane recording layout always shown.
    • DOM loading indicator and refined element highlight/overlay for clearer interactions.
    • Simplified click handling and more consistent playback rendering.
  • Bug Fixes

    • Tabs now initialize as "Loading..." and update only when fetched data is non-empty.

@RohitR311 RohitR311 requested a review from amhsirak November 3, 2025 10:33
@coderabbitai
Copy link

coderabbitai bot commented Nov 3, 2025

Walkthrough

Replaces canvas/screencast-based browser rendering with a DOM renderer and loading indicator, gates DOM snapshot emission behind an initial-load quiet period with progressive loading events, changes initial tabs from ["current"] to ["Loading..."], and enables DOM mode from RecordingPage via a new global setter.

Changes

Cohort / File(s) Change Summary
DOM rendering refactor
src/components/browser/BrowserWindow.tsx
Removed canvasRef, screenshot state, canvas/highlighter/screencast wiring and drawing logic. Added DOMBrowserRenderer-driven rendering, DOMLoadingIndicator, consolidated dom-highlight-overlay handling, simplified click handling and conditional branches to rely on currentSnapshot.
Tab initialization tweak
src/components/browser/BrowserContent.tsx
Changed initial tabs state from ["current"] to ["Loading..."] and only set tabs after fetch when response.length > 0.
Recording page / global state
src/pages/RecordingPage.tsx, src/context/globalInfo.ts
RecordingPage now calls setIsDOMMode(true) on mount, emits input:url when loaded with recordingUrl, always renders the two-pane layout, and the global info store exposes setIsDOMMode(value: boolean).
Initial-load progress & DOM snapshot gating
server/src/browser-management/classes/RemoteBrowser.ts
Added initial-load quiet-period state, progress timer, emitLoadingProgress(progress, pendingRequests), suppression of DOM snapshot during the initial quiet period, milestone progress emissions, and guarded interval management for the startup loading flow.
Routing addition
src/pages/PageWrapper.tsx
Added new route "/recording-setup" rendering an empty div.

Sequence Diagram(s)

sequenceDiagram
    participant RecordingPage
    participant GlobalInfoStore
    participant BrowserWindow
    participant DOMBrowserRenderer
    participant RemoteBrowser
    participant DOMLoadingIndicator

    RecordingPage->>GlobalInfoStore: setIsDOMMode(true)
    RecordingPage->>BrowserWindow: mount (DOM mode enabled)
    BrowserWindow->>RemoteBrowser: request/currentSnapshot?

    alt currentSnapshot available
        BrowserWindow->>DOMBrowserRenderer: render(snapshot)
        DOMBrowserRenderer->>BrowserWindow: rendered DOM + highlights
    else initial load / no snapshot
        RemoteBrowser->>BrowserWindow: domLoadingProgress events (0→100%)
        BrowserWindow->>DOMLoadingIndicator: show loading progress
    end

    Note over RemoteBrowser,BrowserWindow: RemoteBrowser emits progressive domLoadingProgress during initial quiet period and gates DOM snapshots until it completes
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • src/components/browser/BrowserWindow.tsx — verify DOM highlight overlay, click handling, and removal of canvas branches.
    • server/src/browser-management/classes/RemoteBrowser.ts — validate initial-load timing, progress calculation, interval lifecycle, and correct gating of DOM snapshots.
    • src/pages/RecordingPage.tsx & src/context/globalInfo.ts — confirm setIsDOMMode addition and its usage/integration.

Possibly related PRs

Suggested labels

Type: Feature, Scope: Recorder

Suggested reviewers

  • amhsirak

Poem

🐰 I hopped from canvas to DOM's warm glow,
Quiet loads slow, then progress does show.
Snapshots held tight, then released with cheer,
Highlights and tabs — the recorder draws near.
Thump-thump, a rabbit’s small applause.

Pre-merge checks and finishing touches

✅ 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 'feat: faster remote browser loading' accurately captures the main objective of the PR: improving browser startup performance by replacing a spinner with an inline loading progress indicator.
✨ 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 fast-loader

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.

@RohitR311 RohitR311 added Type: Enhancement Improvements to existing features Scope: UI/UX Issues/PRs related to UI/UX labels Nov 3, 2025
Copy link

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56aeb5e and 1f99295.

📒 Files selected for processing (3)
  • src/components/browser/BrowserContent.tsx (2 hunks)
  • src/components/browser/BrowserWindow.tsx (4 hunks)
  • src/pages/RecordingPage.tsx (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/pages/RecordingPage.tsx (2)
src/context/globalInfo.tsx (1)
  • useGlobalInfoStore (186-186)
src/components/recorder/RightSidePanel.tsx (1)
  • RightSidePanel (38-790)
src/components/browser/BrowserWindow.tsx (1)
src/components/recorder/DOMBrowserRenderer.tsx (1)
  • DOMBrowserRenderer (147-1060)

const { socket } = useSocketStore();

const [tabs, setTabs] = useState<string[]>(["current"]);
const [tabs, setTabs] = useState<string[]>(["Loading..."]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Prevent phantom “Loading...” tab from breaking tab indices.

By keeping the placeholder when getCurrentTabs() returns an empty list you end up appending the first real tab after "Loading...". UI indices (1, 2, …) then no longer match the backend’s tab indices (0, 1, …), so actions like changeTab(1) or closeTab(1) target the wrong tab or fail outright. Please allow the empty array to overwrite the placeholder (or otherwise drop the placeholder before appending) so the frontend stays in sync with the backend.

Apply this diff to restore the previous behavior:

-        if (response && response.length > 0) {
-          setTabs(response);
-        }
+        if (Array.isArray(response)) {
+          setTabs(response);
+        }

Also applies to: 128-130

🤖 Prompt for AI Agents
In src/components/browser/BrowserContent.tsx around lines 16 and 128-130, the
initial state uses a "Loading..." placeholder which is kept when
getCurrentTabs() returns an empty array, causing frontend tab indices to shift;
remove the placeholder by initializing tabs to an empty array ([]) and/or change
the logic that applies backend results so that when getCurrentTabs() returns []
it overwrites any placeholder instead of appending to it (i.e., replace the tabs
array wholesale with the backend array or drop the placeholder before
concatenation) so frontend indices stay aligned with backend indices.

Copy link

@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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1f99295 and 58aa5f5.

📒 Files selected for processing (1)
  • server/src/browser-management/classes/RemoteBrowser.ts (6 hunks)
🔇 Additional comments (5)
server/src/browser-management/classes/RemoteBrowser.ts (5)

204-208: LGTM - clear state management for initial load tracking.

The new fields appropriately track the initial load progress flow with clear naming and correct types.


440-444: Appropriate guard to prevent duplicate snapshots during initial load.

The condition correctly suppresses DOM snapshots until the initial load sequence completes, which aligns with the new progress indicator flow.


450-452: Verify intended behavior: initial load progress shows only once per browser instance.

The hasShownInitialLoader flag is set to true on the first document request but never reset. This means the initial load progress indicator will only display during the first navigation after browser startup, not for subsequent navigations within the same session.

If this is intentional (progress indicator only for browser spin-up, not subsequent navigations), consider adding a comment explaining this behavior. If subsequent navigations should also show progress, the flag needs to be reset appropriately.


499-506: LGTM - clean progress emission helper.

The method appropriately encapsulates progress event emission with all necessary context (rounded progress, pending requests, user ID, timestamp).


557-696: Well-structured initialization progress milestones.

The progress emissions at key initialization steps (0% → 20% → 40% → 60%) provide clear feedback during browser startup. These milestones transition smoothly into the 60-95% range during initial page load, culminating in 100% when complete.

) {
const isDocumentRequest = response.request().resourceType() === "document";

if (!this.hasShownInitialLoader && isDocumentRequest && !url.includes("about:blank")) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fragile URL check could match unintended substrings.

Using url.includes("about:blank") could incorrectly match legitimate URLs that contain "about:blank" as a substring (e.g., https://example.com/page?redirect=about:blank).

Consider using a more precise check:

-        if (!this.hasShownInitialLoader && isDocumentRequest && !url.includes("about:blank")) {
+        if (!this.hasShownInitialLoader && isDocumentRequest && url !== "about:blank") {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!this.hasShownInitialLoader && isDocumentRequest && !url.includes("about:blank")) {
if (!this.hasShownInitialLoader && isDocumentRequest && url !== "about:blank") {

Comment on lines +466 to +471
this.progressInterval = setInterval(() => {
const elapsed = Date.now() - this.networkWaitStartTime;
const navigationProgress = Math.min((elapsed / this.INITIAL_LOAD_QUIET_PERIOD) * 40, 35);
const totalProgress = 60 + navigationProgress;
this.emitLoadingProgress(totalProgress, this.pendingNetworkRequests.length);
}, 500);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Memory leak: progressInterval not cleaned up in shutdown/cleanup methods.

The progressInterval is created here but only cleared within the setTimeout callback (lines 482-485). If switchOff(), stopDOM(), or other cleanup methods are called before the timeout fires, the interval will continue running indefinitely.

Add cleanup in the relevant methods:

// In switchOff() method around line 1738
if (this.progressInterval) {
  clearInterval(this.progressInterval);
  this.progressInterval = null;
}

// In stopDOM() method around line 1703
if (this.progressInterval) {
  clearInterval(this.progressInterval);
  this.progressInterval = null;
}
🤖 Prompt for AI Agents
In server/src/browser-management/classes/RemoteBrowser.ts around lines 466 to
471, an interval (progressInterval) is started but only cleared inside a later
setTimeout callback, causing a potential memory leak if shutdown/cleanup methods
run first; add code in switchOff() (around line 1738) and stopDOM() (around line
1703) to check if this.progressInterval is set, call
clearInterval(this.progressInterval) and then set this.progressInterval to null
so the interval is always cleaned up during shutdown.

Copy link

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58aa5f5 and d7da903.

📒 Files selected for processing (1)
  • src/pages/PageWrapper.tsx (1 hunks)

Comment on lines +119 to +122
<Route
path="/recording-setup"
element={<div />}
/>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add loading state and fallback handling for better UX.

The empty div provides no user feedback during the redirect flow and contradicts this PR's objective of introducing inline loading progress indicators. Additionally, if the redirect conditions at lines 58-68 fail (e.g., missing or mismatched session parameters), users are left staring at a blank page with no guidance.

Consider showing a loading indicator or message while the redirect logic executes, and add a fallback for cases where the redirect doesn't occur.

Example improvement:

-              <Route
-                path="/recording-setup"
-                element={<div />}
-              />
+              <Route
+                path="/recording-setup"
+                element={
+                  <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
+                    <div>Setting up recording session...</div>
+                  </div>
+                }
+              />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Route
path="/recording-setup"
element={<div />}
/>
<Route
path="/recording-setup"
element={
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
<div>Setting up recording session...</div>
</div>
}
/>

@amhsirak
Copy link
Member

amhsirak commented Nov 5, 2025

@RohitR311 resolve conflicts

@RohitR311
Copy link
Collaborator Author

@amhsirak Resolved

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

Labels

Scope: UI/UX Issues/PRs related to UI/UX Type: Enhancement Improvements to existing features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants