Skip to content

fix(web): prefer live Hub connectivity over navigator status#1051

Open
Aqi77su wants to merge 3 commits into
tiann:mainfrom
Aqi77su:fix/offline-banner-hub-connectivity
Open

fix(web): prefer live Hub connectivity over navigator status#1051
Aqi77su wants to merge 3 commits into
tiann:mainfrom
Aqi77su:fix/offline-banner-hub-connectivity

Conversation

@Aqi77su

@Aqi77su Aqi77su commented Jul 16, 2026

Copy link
Copy Markdown

Summary

  • suppress the offline banner when the global Hub SSE subscription is connected
  • show the reconnecting banner from the actual SSE state even when navigator.onLine is false
  • add focused coverage for false offline reports and banner precedence

Closes #1050.

Rationale

navigator.onLine is only a browser hint and can remain false with working proxy, VPN/TUN, embedded-browser, or platform networking. A live Hub SSE subscription is stronger evidence of connectivity and should take precedence.

Testing

  • Added focused Vitest coverage for OfflineBanner and ReconnectingBanner.
  • Local execution was attempted with the repository's CI Bun version, but dependency installation stalled on the Windows host before the test runner became available. GitHub CI should run the full typecheck and test suite.

AI disclosure

Implementation and tests were produced with OpenAI Codex (GPT-5) and manually scoped against the existing Hub/SSE state flow.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Findings

  • [Minor] Keep offline suppression aligned with the visible reconnect banner — OfflineBanner now suppresses itself for raw sseDisconnected, but ReconnectingBanner only renders for sseDisconnected && !isSyncing. During an SSE disconnect while isSyncing is true and navigator.onLine is false, SyncingBanner is also hidden by the online check, so all connection banners disappear until syncing clears. Evidence: web/src/App.tsx:450.
    Suggested fix:
    const showReconnectingBanner = sseDisconnected && !isSyncing
    
    <PwaUpdateBannerWithStatusOffset
        isSyncing={isSyncing}
        isReconnecting={showReconnectingBanner}
    />
    <ReconnectingBanner
        isReconnecting={showReconnectingBanner}
        reason={sseDisconnectReason}
    />
    <OfflineBanner
        isHubConnected={globalSubscriptionId !== null}
        isReconnecting={showReconnectingBanner}
    />

Summary

  • Review mode: initial
  • One banner-precedence edge case found in the App wiring.

Testing

  • Not run (automation; static review only).

HAPI Bot

Comment thread web/src/App.tsx Outdated
<OfflineBanner />
<OfflineBanner
isHubConnected={globalSubscriptionId !== null}
isReconnecting={sseDisconnected}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Minor] OfflineBanner now suppresses itself for raw sseDisconnected, but the reconnecting banner is only visible for sseDisconnected && !isSyncing. If an SSE disconnect happens while sync is active and navigator.onLine is false, SyncingBanner is hidden by its online check, ReconnectingBanner is hidden by isSyncing, and this banner is hidden by sseDisconnected, leaving no connection banner until sync clears.

Suggested fix:

const showReconnectingBanner = sseDisconnected && !isSyncing

<OfflineBanner
    isHubConnected={globalSubscriptionId !== null}
    isReconnecting={showReconnectingBanner}
/>

@Aqi77su

Aqi77su commented Jul 16, 2026

Copy link
Copy Markdown
Author

Addressed the banner-precedence finding in 452e4c4. OfflineBanner, ReconnectingBanner, and the PWA status offset now share showReconnectingBanner, so the offline fallback is only suppressed when the reconnecting banner is actually eligible to render.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Findings

  • [Major] Wrap the new banner tests in the i18n provider — both added test files render components that call useTranslation(), and that hook throws unless an I18nProvider is in the React tree. As written, the first render(<OfflineBanner ... />) fails before the assertion runs, and ReconnectingBanner.test.tsx has the same setup issue. Evidence: web/src/components/OfflineBanner.test.tsx:17 and web/src/components/ReconnectingBanner.test.tsx:6.
    Suggested fix:
    import { I18nProvider } from '@/lib/i18n-context'
    
    render(
        <I18nProvider>
            <OfflineBanner isHubConnected={false} isReconnecting={false} />
        </I18nProvider>,
    )

Summary

  • Review mode: follow-up after new commits
  • The follow-up commit fixed the prior banner-precedence concern, but the added component tests need the same i18n wrapper used by existing web component tests.

Testing

  • Not run (automation; local bun is unavailable in this runner: /bin/bash: line 1: bun: command not found).

HAPI Bot

})

it('shows when the browser and hub are offline', () => {
useOnlineStatusMock.mockReturnValue(false)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Major] This render path is missing I18nProvider. OfflineBanner calls useTranslation(), and that hook throws when there is no provider, so this test fails before reaching the assertion. ReconnectingBanner.test.tsx has the same issue at its first render.

Suggested fix:

import { I18nProvider } from '@/lib/i18n-context'

render(
    <I18nProvider>
        <OfflineBanner isHubConnected={false} isReconnecting={false} />
    </I18nProvider>,
)

@Aqi77su

Aqi77su commented Jul 16, 2026

Copy link
Copy Markdown
Author

Addressed the follow-up test failure in 9f2e50d. Both banner test suites now render their components inside the repository's I18nProvider, so useTranslation() has the required context.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Findings

  • No issues found.

Summary

  • Review mode: follow-up after new commits
  • Full diff reviewed. The prior i18n-provider test failure is fixed in the latest head. Residual risk is limited to runtime SSE/browser connectivity behavior that is not covered by an App-level integration test.

Testing

  • Not run (automation; review policy avoids executing PR code).

HAPI Bot

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.

Offline banner shows while the Hub is reachable

1 participant