Skip to content

TUI side pane: list of connected clients with per-connection metrics #31

Description

@sunng87

Goal

Add a toggleable side pane to the --tui view that lists every tracked connection (the connected PostgreSQL clients) with per-connection state and traffic counters, so you can see who is connected at a glance and act on a specific client.

Today the TUI shows only aggregate metrics in the header (conns_live, totals, rate sparkline via metrics.summary() in src/state.rs:303). The per-connection data already exists — MetricsSnapshot::connections: Vec<ConnSnapshot> (src/state.rs:53) — but it is never rendered. This issue surfaces it.

Data source (already available)

The registry already retains everything the pane needs:

  • ConnSnapshot { id, client: SocketAddr, server: SocketAddr, lifecycle, encrypted, msgs_in, msgs_out, bytes_in, bytes_out } (src/state.rs:45)
  • ConnectionLifecycle::{ Open { since }, Closed { since, ended } } (src/state.rs:27)

The pane should read metrics.snapshot() (src/state.rs:317) rather than summary(). Performance note / design point: unlike summary() (which deliberately avoids touching connection records), snapshot() walks the registry under its lock and allocates a Vec every frame. Decide how to keep this cheap:

  • Only call snapshot() while the pane is open (preferred — closed pane pays nothing), and/or
  • Throttle to a few times per second rather than every frame.

The default connection cap is large (DEFAULT_CONNECTION_CAP = 10_000, src/state.rs:15), so the pane must virtualise/scroll rather than render thousands of rows.

Layout

The current layout is purely vertical: title(5) / log(Fill) / footer(3) (src/tui.rs:486). The pane splits the middle row horizontally, keeping the title and footer full-width:

  • Position — left vs right. Right keeps the existing left-aligned message flow anchored and matches the "detail rail" convention. Left surfaces clients first. Slight preference for right.
  • Width — a bounded Constraint, e.g. Min(24)..Max(40) or a percentage with sensible small-terminal fallback (collapse/hide below a threshold width).
  • Resize — optional, follow-up; a fixed sensible default is fine for v1.

Per-client row content

For each connection, show:

  • Client endpointclient.ip and client.port (the primary identity; the display filter keys off these, src/filter.rs:74).
  • LifecycleOpen/Closed with colour (e.g. green live, dim/grey closed) and age from since. Decide whether closed connections appear at all; if so, how they are sorted/dimmed relative to live ones.
  • Encryption — a marker for encrypted (relevant in mitm mode; distinguishes the decrypted sessions from cleartext pcap ones).
  • Traffic — compact per-connection bytes_in/bytes_out (reuse the human() formatter, src/tui.rs:711) and/or message counts.

server addr and per-connection message counts are secondary; show server addr only when width allows or when it differs from the default upstream.

Interaction / scoping the log

The display-filter subsystem (#13) already parses client.ip == ... and client.port == ... (src/filter.rs:8). Make the pane the ergonomic entry point for that:

  • j/k (or arrows) to move the selection within the pane.
  • Enter on a client applies a client.ip == <ip> and client.port == <port> display filter, scoping the message log to that one connection. Esc/clear returns to the unfiltered view.
  • Optionally, the header's existing conns_live counter links to the pane (e.g. it becomes the pane's title/cap summary).

Decide whether selecting a client filters immediately on Enter (explicit) or on navigation (live preview). Preference: explicit Enter, consistent with the existing filter UX.

Keybinding

The pane needs a toggle. The keyspace is getting crowded — relevant existing bindings in normal mode: c clears events, f follow, r rich, w wrap, y filter-edit (src/tui.rs:418). Candidates:

  • Tab / Shift-Tab to focus-cycle into the pane (clean, no letter conflict, scales if more panes are added later), or
  • C (capital) / s for clients/side.

Preference: Tab to toggle, with the pane collapsing to a thin status column when unfocused (so a key like j/k always maps to log scroll unless the pane is focused). No startup flag needed for v1; default off to preserve current behaviour.

Scope

TUI only. The line-oriented stdout output (pcap/mitm without --tui) is unaffected. No change to the metrics/state layer's public API beyond (optionally) reading snapshot() from the TUI.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions