Skip to content

Implement Server Info modal wired to the connection handshake's InitializeResult #1364

@cliffhall

Description

@cliffhall

Summary

The Server Info action on ServerCard is currently a no-op — App.tsx wires onServerInfo={todoNoop} (App.tsx:908). The presentational ServerInfoContent component already exists (clients/web/src/components/groups/ServerInfoContent/) and accepts the right props (initializeResult, clientCapabilities, transport, oauth?), but there is no modal that hosts it and no wiring from the click handler to a real popup.

This issue is to implement a ServerInfoModal that hosts the existing ServerInfoContent, gate the Server Info entry point on ServerCard so it only appears when the server is connected, and wire the modal to the InitializeResult produced by the active InspectorClient's connection handshake.

Current state

  • ServerInfoContent (clients/web/src/components/groups/ServerInfoContent/ServerInfoContent.tsx) — presentational, fully built, has its own test and story files.
  • ServerCard.tsx:161-168 — always renders the Server Info button regardless of connection status.
  • App.tsx:328-336 — already computes an InitializeResult from the connected InspectorClient (protocolVersion, capabilities, serverInfo, optional instructions). This is the data source the modal needs.
  • App.tsx:908onServerInfo={todoNoop}, so clicking the button does nothing.
  • Modal pattern to mirror: ServerSettingsModal (clients/web/src/components/groups/ServerSettingsModal/) — same shape (Mantine Modal wrapping a presentational content component, opened by a target-id state in App.tsx).

Proposed change

1. Create ServerInfoModal

clients/web/src/components/groups/ServerInfoModal/ServerInfoModal.tsx — a Mantine Modal wrapper around ServerInfoContent. Props:

interface ServerInfoModalProps {
  opened: boolean;
  onClose: () => void;
  initializeResult: InitializeResult;
  clientCapabilities: ClientCapabilities;
  transport: ServerType;
  oauth?: OAuthDetails;
}

The modal owns the framing (title, close button, sizing) and forwards everything else straight to ServerInfoContent. Mirror the structure of ServerSettingsModal for consistency.

2. Gate the Server Info button on ServerCard

In ServerCard.tsx:161-168, only render the Server Info SubtleButton when connection.status === \"connected\". The Settings button stays unconditional. The popup is only meaningful after a successful handshake — capabilities, instructions, and protocolVersion are all handshake-derived.

3. Wire the modal in App.tsx

  • Add a serverInfoModalOpen (or serverInfoTargetId) piece of state, parallel to settingsModalTargetId.
  • Replace onServerInfo={todoNoop} (App.tsx:908) with a handler that opens the modal for the active server. Since Server Info is gated on connection.status === \"connected\" (acceptance criterion above), the active server is the only valid target — no need to thread an id through.
  • Pass the already-computed initializeResult (App.tsx:328-336) into the modal. If initializeResult is undefined at render time (race between disconnect and modal close), the modal should close itself or render nothing rather than crash.
  • Source clientCapabilities and transport from the same place the connected ViewHeader already reads them (initializeResult is built right next to those). OAuth details are optional and can be threaded later if not readily available — leave a TODO if so.

Acceptance criteria

  • ServerInfoModal exists at clients/web/src/components/groups/ServerInfoModal/ with .tsx, .test.tsx, and .stories.tsx files mirroring the ServerSettingsModal layout.
  • Server Info button on ServerCard renders only when connection.status === \"connected\"; Settings button continues to render in all states.
  • Clicking Server Info on a connected card opens the modal, which displays the data from the active connection's InitializeResult (serverInfo, capabilities, protocolVersion, instructions).
  • Closing the modal (X button, ESC, click outside) returns to the Servers screen with no stale state.
  • ServerCard.test.tsx covers both branches (connected → Server Info present; disconnected/connecting/error → Server Info absent).
  • ServerInfoModal.test.tsx covers: open with a sample InitializeResult renders ServerInfoContent, close handler fires on the standard close paths.
  • ServerCard and ServerInfoModal stories cover the connected/non-connected variants and the modal-open state, so npm run test:storybook exercises the rendered UI.
  • Per-file coverage gate (lines ≥ 90, statements ≥ 85, functions ≥ 80, branches ≥ 50) passes for the new files.

Metadata

Metadata

Assignees

No one assigned

    Labels

    v2Issues and PRs for v2

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions