Skip to content

Plan/1737 connection status indicator#4

Merged
bashrusakh merged 2 commits into
win-artifact-pr-fixes-v2from
plan/1737-connection-status-indicator
Jun 22, 2026
Merged

Plan/1737 connection status indicator#4
bashrusakh merged 2 commits into
win-artifact-pr-fixes-v2from
plan/1737-connection-status-indicator

Conversation

@bashrusakh

Copy link
Copy Markdown
Owner

No description provided.

Leonid Skorobogatyy and others added 2 commits June 22, 2026 01:43
…penchamber#1556)

- Hop-separated narrow state in useConfigStore (runtimeTransport,
  openCodeRuntime) driven by the existing SSE/WS reconnect pipeline
  and the existing opencodeClient.checkHealth() path. No new
  polling loop.
- Pure helper packages/ui/src/lib/connection-status/connectionStatus.ts
  that maps per-hop internal state + navigator.onLine to a single
  aggregated view model (connected / reconnecting / degraded /
  disconnected / unknown) and short i18n keys. Raw internal reason
  codes are kept in the view model for diagnostics only and never
  reach the UI.
- Compact header indicator packages/ui/src/components/layout/
  ConnectionStatusIndicator.tsx (one dot + hover tooltip with 2-3
  short lines, theme tokens only, React.memo on both layers,
  narrow leaf selectors). Wired into Header.tsx in the existing
  desktopSidebarActions cluster.
- 19 new connectionStatus.* i18n keys in all 9 dictionaries.
- 22 unit tests for the mapper covering all Phase 5 scenarios.
- One-line pre-existing fr.ts parity fix
  (sessions.scheduledTasks.editor.scheduleType.cron) so the i18n
  parity test passes; flagged in the PR body.

Validation: type-check + lint green in packages/ui, packages/web,
packages/electron. docs:validate green. 22 + 12 + 2 new/updated
tests pass. 5 pre-existing sync-pipeline test failures verified
unrelated to this diff.
@bashrusakh bashrusakh merged commit 9b7b23f into win-artifact-pr-fixes-v2 Jun 22, 2026
1 check failed

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a compact, aggregated ConnectionStatusIndicator component in the header to track and display connection health across two hops: Frontend to OpenChamber runtime, and OpenChamber runtime to OpenCode. It adds the corresponding state management in useConfigStore, integrates browser-level online/offline listeners in sync-context.tsx, and provides localized messages and unit tests. The review feedback highlights a bug where navigatorOfflineRef is never updated after mount, suggesting reading navigator.onLine dynamically instead. Additionally, the reviewer recommends avoiding prop-drilling the translation function t by using the useI18n hook directly inside the memoized body component, and suggests mirroring the active connectionPhase in sync-context.tsx rather than hardcoding a "disconnected" phase to prevent overriding active reconnection states.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +171 to +174
const navigatorOfflineRef = React.useRef<boolean>(
typeof navigator === 'object' && navigator !== null && navigator.onLine === false,
);
const navigatorOffline = navigatorOfflineRef.current;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The navigatorOfflineRef is initialized once on mount and its value is never updated. As a result, navigatorOffline remains constant throughout the component's lifecycle.

If the application is mounted while offline, navigatorOffline will be permanently stuck at true. Even after the network is restored and the transport successfully reconnects, the view model will continue to evaluate navigatorOffline as true and display the "Disconnected" status.

Since ConnectionStatusIndicator already re-renders whenever runtimeTransport or openCodeRuntime changes (which is guaranteed to happen on network changes due to the listeners in sync-context.tsx), we can safely read navigator.onLine dynamically during render instead of using a stale ref.

  const navigatorOffline =
    typeof navigator === 'object' && navigator !== null && navigator.onLine === false;

Comment on lines +56 to +64
type ConnectionStatusIndicatorBodyProps = {
viewModel: ConnectionStatusViewModel;
/**
* The i18n `t` function, passed down from the parent so the body can be
* memoized purely on `viewModel`. When the locale changes, the parent
* re-renders with a new `t` reference and the body picks it up.
*/
t: (key: I18nKey, params?: I18nParams) => string;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Simplify the ConnectionStatusIndicatorBodyProps type definition by removing the t translation function prop, as it will be consumed internally via the useI18n hook.

type ConnectionStatusIndicatorBodyProps = {
  viewModel: ConnectionStatusViewModel;
};

Comment on lines +73 to +76
const ConnectionStatusIndicatorBody = React.memo(function ConnectionStatusIndicatorBody({
viewModel,
t,
}: ConnectionStatusIndicatorBodyProps) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Instead of passing the t translation function as a prop from the parent, you can call useI18n() directly inside ConnectionStatusIndicatorBody.

Since ConnectionStatusIndicatorBody is wrapped in React.memo, removing the t prop ensures it is memoized purely on the viewModel reference. When the locale changes, the i18n context will automatically trigger a re-render of ConnectionStatusIndicatorBody anyway, keeping the translations up-to-date without prop-drilling.

Suggested change
const ConnectionStatusIndicatorBody = React.memo(function ConnectionStatusIndicatorBody({
viewModel,
t,
}: ConnectionStatusIndicatorBodyProps) {
const ConnectionStatusIndicatorBody = React.memo(function ConnectionStatusIndicatorBody({
viewModel,
}: ConnectionStatusIndicatorBodyProps) {
const { t } = useI18n();

[runtimeTransport, openCodeRuntime, navigatorOffline],
);

return <ConnectionStatusIndicatorBody viewModel={viewModel} t={t} />;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Remove the t prop passed to ConnectionStatusIndicatorBody to match the updated signature that uses useI18n() internally.

Suggested change
return <ConnectionStatusIndicatorBody viewModel={viewModel} t={t} />;
return <ConnectionStatusIndicatorBody viewModel={viewModel} />;

Comment on lines +1836 to +1840
useConfigStore.getState().setRuntimeTransportState({
phase: "disconnected",
reason,
updatedAt: Date.now(),
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Currently, when the transport disconnects, runtimeTransportState is updated with phase: "disconnected". However, the event pipeline is actually in a "reconnecting" or "connecting" phase (as tracked by connectionPhase).

By hardcoding "disconnected", the connection status indicator will immediately show the red "Disconnected" dot instead of the neutral/muted "Reconnecting" dot during active reconnection attempts. This makes the "reconnecting" and "connecting" phases in the view model dead code.

We should mirror the active connectionPhase (which uses hasEverConnected ? "reconnecting" : "connecting") so the indicator can accurately reflect the transitional states.

        useConfigStore.getState().setRuntimeTransportState({
          phase: hasEverConnected ? "reconnecting" : "connecting",
          reason,
          updatedAt: Date.now(),
        })

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.

1 participant