# SPEC-005: Machines List View — Dual Connection Indicators + Rich Rows **Status:** Proposed **Priority:** P2 **Requested By:** Mike (2026-05-30) **Estimated Effort:** Medium ## Overview Bring the Operator Console Machines list to ScreenConnect "Access"-list parity: each row gains (1) **dual connection indicators** — a two-segment bar showing Host and Guest connection state at a glance — and (2) **rich inline metadata** (company, site, device type, tags, logged-on user + idle, client version) instead of today's bare status-dot / hostname / OS / last-seen table. An operator should be able to scan the list and instantly see which machines are online, which have a tech actively connected, who's logged in, and which agents are running stale clients — without opening the detail drawer. Success = the list conveys the same at-a-glance operational state as the reference console. **Reference (screenshot 2026-05-30, "Arizona Computer Guru" company):** `GURU-BEAST-ROG` shows a green **Host** segment ("Computer Guru - SysAdmin") *and* a green **Guest** segment ("Guest - 9h 21m"); most rows show only a green "Guest - Xh Ym" (agent online, no tech connected); `ACG-TECH-01L` shows neither (offline). Rows carry "Company: …", "Site: …", "Device Type: …", "Tag …", "User: … (Idle …)", and "Client Version: …" (in red when out of date). > Terminology: the requester's "dial" was a typo for **dual** — two indicators > (Host + Guest), not a dial gauge. ## Scope ### Included in v1 - **Dual connection indicators per row:** - **Guest segment** (monitor icon): green when the endpoint agent is connected (`SessionInfo.is_online == true`); label "Guest - "; grey when offline. - **Host segment** (person icon): green when a viewer/operator is actively connected (`SessionInfo.viewer_count > 0`); label = the viewer name(s) (`SessionInfo.viewers[].viewer_name`) + duration since join; grey when none. - Both states come from **live** session state, refreshed on the existing dashboard poll/refresh. - **Rich inline row metadata** (from SPEC-003 inventory + existing columns): Company (`organization`), Site (`site`), Device Type (`device_type`), Tag(s) (`tags`), Logged-On User + Idle (`logged_on_user`, `idle_secs`), and **Client Version** (`agent_version`) rendered in a warning/red style when the agent build is **outdated** (below the latest stable `releases.version`, or below `min_version` → stronger "mandatory update" emphasis). - **Server enrichment:** extend the machines list response so each machine carries its live Host/Guest state and the inventory fields in one payload (avoid N client-side joins). See Architecture. ### Explicitly out of scope - The left-nav **"All Machines by Company" tree** with per-company counts (the screenshot's grouping sidebar) — captured as a follow-up sub-item in the roadmap; v1 may ship simple client-side grouping/sort by company but not the full tree nav. - Editable inline fields (rename, set device type/tag from the row) — display only in v1; editing is a separate concern (and overlaps SPEC-003's operator-editable note). - The per-row action menu beyond what exists (Join/Control/keys/remove already covered by other specs). - Native viewer changes — dashboard only. ## Architecture - **Data sources today are split:** `GET /api/machines` (`list_machines`, `main.rs:636`) returns `MachineInfo` from the **DB** (`connect_machines`), while live online/viewer state lives in the **in-memory `SessionManager`** and is exposed by `GET /api/sessions` (`SessionInfo`: `is_online`, `viewer_count`, `viewers`, `agent_name`, `started_at`). The list view needs both. - **Relay-server (preferred):** enrich the machines list with live state server-side — join each `connect_machines` row (by `agent_id`/`machine_uid`) to its current `SessionManager` session, and add to `MachineInfo` (`api/mod.rs:117`): `is_online`, `viewer_count`, `viewers` (names), `online_since`, `host_since`, plus the SPEC-003 inventory fields (`device_type`, `logged_on_user`, `idle_secs`, `agent_version`). Compute `client_outdated` / `client_update_mandatory` by comparing `agent_version` to the latest stable / `min_version` from `db::releases` (`releases.rs`). One request, fully-rendered rows. - Alternative (lighter, more chatter): dashboard fetches `/api/machines` + `/api/sessions` and joins client-side by agent_id. Acceptable for v1 if server enrichment is deferred, but the join + outdated-version logic then lives in TS. - **Dashboard:** replace the plain `DataTable` columns in `dashboard/src/features/machines/MachinesPage.tsx` with a richer row: a `ConnectionIndicator` component (Host/Guest two-segment bar) + a metadata block. Reuse `StatusDot`/`machineTone` semantics. New `dashboard/src/api/types.ts` fields mirror the enriched `MachineInfo`. - **Protobuf / DB:** none new — relies on SPEC-003's inventory columns and existing session state. (`online_since`/`host_since` may need a timestamp the SessionManager isn't tracking yet — see Open Questions.) ## Implementation details - Files to touch: `server/src/api/mod.rs:117,130` (enrich `MachineInfo` + `From`); `server/src/main.rs:636` (`list_machines` — join live `SessionManager` state, compute outdated flag via `db::releases`); `server/src/session/mod.rs` (expose a by-agent_id/`machine_uid` lookup + `online_since`/`host_since` if added); `dashboard/src/features/machines/MachinesPage.tsx` (row layout), new `dashboard/src/features/machines/ConnectionIndicator.tsx`, `dashboard/src/api/types.ts` / `machines.ts` (new fields), `machines`/`status` CSS. - Key logic: Guest green = `is_online`; Host green = `viewer_count > 0` (label from `viewers`); client-version tone = compare to latest stable release (red if below; stronger if below `min_version`). ## Security considerations - No new endpoints beyond enriching an already admin-authenticated list (`AuthenticatedUser` guard on `list_machines`); no new unauthenticated surface. - `logged_on_user`, viewer names, and inventory are already admin-only data — same trust level as the existing detail drawer; the list merely surfaces it earlier. - Treat agent-reported strings (user, version, device type) as untrusted display data — length-cap/escape in the dashboard (no HTML injection via a rogue agent's reported fields). ## Testing strategy - **Unit:** Host/Guest indicator state derives correctly (online+no viewer = Guest only; online+viewer = both; offline = neither). `client_outdated` flag true when `agent_version` < latest stable and when < `min_version`. - **Integration:** a machine with a live viewer returns `viewer_count>0` + viewer name in the enriched list payload; an offline machine returns `is_online=false`; the list joins DB machines to live sessions without dropping rows that have no session. - **Manual:** against the live console, confirm a row with an active Control session shows the green Host segment with the tech's name, agent-online rows show the green Guest segment + duration, and an out-of-date agent shows the client version in red. Cross-check a few rows against the reference screenshot's layout. ## Effort estimate & dependencies - **Size: Medium.** Most effort is the dashboard row redesign + the `ConnectionIndicator` component and the server-side machines/sessions join; the data largely exists. - **Depends on:** **SPEC-003** (inventory fields: device_type, logged_on_user, idle_secs, agent_version) for the rich metadata. Live Host/Guest state needs nothing new. Reads cleanest **after SPEC-004** (so the list isn't padded with duplicate ghost machines) and dovetails with **SPEC-002 Phase 2**'s dashboard work — coordinate so this is the machines-list increment of that surface, not a parallel rebuild. - **Unblocks:** at-a-glance fleet operability; foundation for the company-tree nav follow-up. ## Open questions 1. **`online_since` / `host_since` timestamps.** The dual-indicator durations ("Guest - 9h 21m", host join time) need an "online since" and "viewer joined at" the `SessionManager` may not track today (`started_at` is session creation, not last went-online). Add these timestamps, or approximate from `started_at`/`last_heartbeat`? 2. **Enrich server-side vs. join in the dashboard.** Preferred is one enriched `/api/machines` payload; confirm we don't want to keep the machines/sessions split and join in TS (simpler server, chattier client). 3. **"Outdated" definition.** Below latest *stable* release, below `min_version` (mandatory), or a configurable lag (e.g. > N versions behind)? Proposed: red if below latest stable, stronger emphasis if below `min_version`. 4. **Company grouping in v1.** Ship simple sort/group-by-company now, or defer all grouping to the company-tree follow-up?