Skip to content

feat(webview): add timeout state and retry UI for stalled embedded webview loads - #1043

Merged
senamakel merged 1 commit into
tinyhumansai:mainfrom
YellowSnnowmann:feat/add-loading-timeout
Apr 30, 2026
Merged

senamakel merged 1 commit into
tinyhumansai:mainfrom
YellowSnnowmann:feat/add-loading-timeout

Conversation

@YellowSnnowmann

@YellowSnnowmann YellowSnnowmann commented Apr 30, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Introduces a timeout account status when the 15s load watchdog expires:

    • Prevents blank or stalled webview display
  • On timeout or Chromium error-page detection:

    • Hide webview
    • Show "Retry loading" overlay
    • Allow recovery without re-authentication
  • Supports non-terminal timeout design:

    • Later Page.loadEventFired / on_page_load can still recover session
  • Handles Chromium error pages (chrome-error://chromewebdata) consistently:

    • Routed through timeout path (Rust + TypeScript)
  • Adds retryWebviewAccountLoad:

    • Reopens webview with cached bounds
    • Preserves session cookies

Problem

  • Webview failures (network issues, CEF hiccups, Chromium error pages):

    • Infinite spinner
    • Blank/dino-page view
    • No recovery path
  • Required restarting app or reopening account:

    • Risked losing session
    • Poor UX

Solution

Rust (webview_accounts/mod.rs, cdp/session.rs)

  • emit_load_finished:

    • Treats "timeout" as non-terminal
    • Emits event but does NOT mark account as loaded
  • Forward chrome-error:// URLs:

    • Treated as "timeout" instead of "finished"

TypeScript (webviewAccountService.ts)

  • Add looksLikeChromiumErrorUrl:

    • Detects error pages
  • On timeout:

    • Call webview_account_hide
    • Dispatch status: 'timeout'
    • Prevents native webview from bleeding through overlay

UI (WebviewHost.tsx)

  • Add timeout UI branch:

    • Message explaining issue
    • "Retry loading" button
  • Use PROVIDER_COPY:

    • Human-readable provider names

Account Status (accounts.ts)

  • Add new state:
    • 'timeout'
    • Positioned between 'loading' and 'open'

Submission Checklist

  • Tests

    • Added 4 Vitest cases:
      • Timeout skips reveal
      • Timeout → finished recovery
      • Chrome-error URL treated as timeout
      • Retry reopens with cached bounds
  • Coverage Matrix

    • Not updated (should be reflected in docs/TEST-COVERAGE-MATRIX.md)
  • Feature IDs

    • Not listed in ## Related
  • Network Dependencies

    • No new dependencies
    • Uses existing Tauri invoke mocks
  • Manual Smoke Checklist

    • Not updated (webview loading is a release surface)
  • Linked Issues

    • Not linked (Closes #NNN missing)

Impact

  • Platform

    • Desktop only (Tauri webview accounts)
    • No web/CLI impact
  • Data / Persistence

    • No migration required
    • timeout is ephemeral (not persisted)
  • Security

    • No new JS injection into CEF webviews
    • Changes limited to native handlers + React overlay
  • UX

    • Eliminates infinite spinner / blank states
    • Provides recovery path for:
      • flaky networks
      • restrictive proxies

Related

Summary by CodeRabbit

Release Notes

  • New Features

    • Added explicit timeout state for account loading with provider-specific messaging.
    • Introduced retry functionality for accounts that experience load timeouts.
    • Enhanced loading UI to display provider names during account initialization.
  • Bug Fixes

    • Improved distinction between connection timeouts and actual load errors.
    • Enabled account recovery after timeout events.

…and enhance timeout handling

- Added a retry button for users when a webview account fails to load within the expected time.
- Updated loading status to 'timeout' and displayed a user-friendly message with retry options.
- Enhanced the handling of Chromium error pages to trigger the timeout UI instead of showing a blank page.
- Updated tests to cover new timeout behavior and retry functionality.
@coderabbitai

coderabbitai Bot commented Apr 30, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

These changes implement a timeout and retry flow for slow-loading embedded webviews. They introduce a new 'timeout' account status distinct from 'loading', refine timeout event emission as non-terminal in the backend, update the frontend UI to display loading and timeout overlays with provider-specific copy, and add a retry mechanism that re-opens accounts using cached bounds and cookies.

Changes

Cohort / File(s) Summary
Backend Load Event Handling
app/src-tauri/src/webview_accounts/mod.rs, app/src-tauri/src/cdp/session.rs
Updated emit_load_finished to treat timeout as non-terminal (emits event without blocking later finished signals); refined webview_account_open to skip placeholder commit claims and classify Chromium error pages as timeout. Documentation clarified to reflect dedup semantics: only terminal finished acts as dedup marker.
Account Status Type & Service Layer
app/src/types/accounts.ts, app/src/services/webviewAccountService.ts
Added 'timeout' status to AccountStatus union type; updated load-event handler to hide webview and set status to 'timeout' on timeout-like errors; exported new retryWebviewAccountLoad() function to re-open accounts using cached bounds while preserving cookies.
Frontend UI & Loading State
app/src/components/accounts/WebviewHost.tsx
Enhanced loading overlay to display provider-specific "Loading ${providerName}..." messaging; added timeout-specific overlay with provider-driven messaging and retry button that invokes retryWebviewAccountLoad().
Test Coverage
app/src/services/__tests__/webviewAccountService.loadListener.test.ts
Updated load-listener tests to assert timeout sets status to 'timeout' without triggering reveal; added recovery scenario (subsequent finished after timeout can still reveal); extended coverage for Chromium error pages and retryWebviewAccountLoad() behavior.

Sequence Diagram

sequenceDiagram
    actor User
    participant WebviewHost as Frontend:<br/>WebviewHost
    participant Service as Service:<br/>webviewAccountService
    participant Backend as Backend:<br/>webview_accounts
    participant CDP as CDP:<br/>Session
    participant Store as Store:<br/>Account Status
    
    User->>WebviewHost: Open account
    activate WebviewHost
    WebviewHost->>Service: openWebviewAccount()
    deactivate WebviewHost
    activate Service
    Service->>Service: Set status: 'loading'
    Service->>Backend: webview_account_open()
    deactivate Service
    activate Backend
    Backend->>CDP: Monitor page load
    Note over CDP: Timer starts (LOAD_TIMEOUT)
    
    alt Load completes in time
        CDP->>Backend: Page load finished
        Backend->>Service: emit_load_finished(finished)
        activate Service
        Service->>Store: Update status: 'open'
        Service->>WebviewHost: Reveal webview
        deactivate Service
    else Load exceeds timeout
        CDP->>Backend: Timeout watchdog fires
        Backend->>Service: emit_load_finished(timeout)
        activate Service
        Service->>Store: Update status: 'timeout'
        Service->>Backend: webview_account_hide()
        deactivate Service
        deactivate Backend
        activate WebviewHost
        WebviewHost->>WebviewHost: Render timeout overlay
        WebviewHost->>User: Show "Loading...<br/>Retry" UI
        deactivate WebviewHost
        
        User->>WebviewHost: Click Retry
        activate WebviewHost
        WebviewHost->>Service: retryWebviewAccountLoad()
        deactivate WebviewHost
        activate Service
        Service->>Backend: webview_account_open()<br/>(with cached bounds)
        deactivate Service
        activate Backend
        Backend->>CDP: Resume/restart load
        CDP->>Backend: Page load finished
        Backend->>Service: emit_load_finished(finished)
        activate Service
        Service->>Store: Update status: 'open'
        Service->>WebviewHost: Reveal webview
        deactivate Service
        deactivate Backend
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested reviewers

  • senamakel

Poem

🐰 A timeout, once fearsome, now shows its kind face
With loading and retry, no more blank-screen case
The webview will wait, but won't leave you behind—
Just click to reload, your account's soon to find! 🔄✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature addition: a timeout state and retry UI for stalled webview loads, which aligns with the comprehensive changes across multiple layers of the codebase.
Linked Issues check ✅ Passed All core objectives from issue #1037 are met: loading UI on start, timeout detection at 15s, retry mechanism with session preservation, provider-specific friendly copy, and comprehensive logging across Rust and TypeScript layers.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #1037 objectives; no unrelated modifications detected beyond the documented scope of adding timeout state, retry UI, and supporting infrastructure.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Review rate limit: 4/5 reviews remaining, refill in 12 minutes.

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

@YellowSnnowmann
YellowSnnowmann marked this pull request as ready for review April 30, 2026 09:37
@YellowSnnowmann
YellowSnnowmann requested a review from a team April 30, 2026 09:37

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
app/src/components/accounts/WebviewHost.tsx (1)

22-32: ⚡ Quick win

Avoid duplicating provider labels in PROVIDER_COPY.

Line 22 introduces a second source of truth for provider display names. This can drift from app/src/types/accounts.ts (PROVIDERS labels).

♻️ Proposed refactor
 import { useAppSelector } from '../../store/hooks';
-import type { AccountProvider, AccountStatus } from '../../types/accounts';
+import { PROVIDERS } from '../../types/accounts';
+import type { AccountProvider, AccountStatus } from '../../types/accounts';
@@
-const PROVIDER_COPY: Record<AccountProvider, string> = {
-  whatsapp: 'WhatsApp',
-  telegram: 'Telegram',
-  linkedin: 'LinkedIn',
-  gmail: 'Gmail',
-  slack: 'Slack',
-  discord: 'Discord',
-  'google-meet': 'Google Meet',
-  zoom: 'Zoom',
-  browserscan: 'BrowserScan',
-};
+const PROVIDER_COPY: Record<AccountProvider, string> = Object.fromEntries(
+  PROVIDERS.map(p => [p.id, p.label])
+) as Record<AccountProvider, string>;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/accounts/WebviewHost.tsx` around lines 22 - 32,
PROVIDER_COPY duplicates display labels already defined in PROVIDERS; remove the
hardcoded PROVIDER_COPY and instead import the canonical PROVIDERS mapping from
app/src/types/accounts.ts (or re-use its label values) so the component uses the
single source of truth; update WebviewHost.tsx to reference
PROVIDERS[provider].label (or similar property) where PROVIDER_COPY was used and
ensure type compatibility with AccountProvider.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/src/components/accounts/WebviewHost.tsx`:
- Around line 22-32: PROVIDER_COPY duplicates display labels already defined in
PROVIDERS; remove the hardcoded PROVIDER_COPY and instead import the canonical
PROVIDERS mapping from app/src/types/accounts.ts (or re-use its label values) so
the component uses the single source of truth; update WebviewHost.tsx to
reference PROVIDERS[provider].label (or similar property) where PROVIDER_COPY
was used and ensure type compatibility with AccountProvider.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0572f5f8-6ded-413a-abad-1057a7f4b2e3

📥 Commits

Reviewing files that changed from the base of the PR and between 84d7814 and 2434168.

📒 Files selected for processing (6)
  • app/src-tauri/src/cdp/session.rs
  • app/src-tauri/src/webview_accounts/mod.rs
  • app/src/components/accounts/WebviewHost.tsx
  • app/src/services/__tests__/webviewAccountService.loadListener.test.ts
  • app/src/services/webviewAccountService.ts
  • app/src/types/accounts.ts

@senamakel
senamakel merged commit 126ffda into tinyhumansai:main Apr 30, 2026
15 checks passed
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
senamakel pushed a commit to nocstah/openhuman that referenced this pull request Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add loading/timeout UI for slow or blank embedded webviews

2 participants