spec: add SPEC-005 machines list view (dual indicators + rich rows)
ScreenConnect "Access"-list parity for the Operator Console machines list: per-row dual Host/Guest connection indicators (Guest=agent is_online, Host=viewer_count>0 with viewer names + durations) and rich inline metadata (company, site, device type, tags, logged-on user + idle, client version in red when outdated). Live Host/Guest state already exists on SessionInfo (is_online, viewer_count, viewers); main work is enriching /api/machines with that + SPEC-003 inventory and redesigning MachinesPage rows. Depends on SPEC-003 (data), reads cleanest after SPEC-004 (dedup), dovetails SPEC-002 Phase 2. Company-tree nav split out as a P3 follow-up. Requested by Mike 2026-05-30. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,8 @@ Bringing GC to parity with GuruRMM's release engineering. Full plan: [SPEC-001](
|
||||
- [x] Sessions / machines / support-codes / events
|
||||
- [ ] **Full machine inventory in the connection DB** — P2 — persist per-machine device inventory (OS+locale+install, CPU/RAM, mfr/model/serial, external WAN IP captured server-side + private LAN IP + MAC, logged-on user, idle, time zone, uptime, local-admin) on `connect_machines`, refreshed each `AgentStatus`, shown in the dashboard machine detail (ScreenConnect "Guest Info" parity). Data layer for SPEC-002 Phase 2; closes GC side of agent-IP gap (todo 7459428e). ([SPEC-003](specs/SPEC-003-machine-inventory.md))
|
||||
- [ ] **Stable machine identity + session lifecycle reaping + operator removal** — P1 — give the agent a deterministic machine-derived `machine_uid` (Windows `MachineGuid`-based) so the same box can't register duplicates (root cause: `agent_id` is a config-file random UUID that a portable/misconfigured run regenerates each launch); key registration on it; add TTL reaping + same-machine supersede as defense-in-depth; and admin-gated per-row + multi-select bulk removal of stale sessions/units. Identity must be bound to the per-machine agent key (spoof guard). Fixes ghost-session accumulation seen on the live console (15 sessions / 0 live, ~10 orphans for one machine). ([SPEC-004](specs/SPEC-004-session-lifecycle-and-removal.md))
|
||||
- [ ] **Machines list view — dual connection indicators + rich rows** — P2 — ScreenConnect "Access"-list parity: per-row Host/Guest two-segment connection bar (Guest=agent online, Host=viewer connected, with names + durations) and rich inline metadata (company, site, device type, tags, logged-on user + idle, client version in red when outdated). Server-enriches `/api/machines` with live session state + SPEC-003 inventory. ([SPEC-005](specs/SPEC-005-machines-list-view-parity.md))
|
||||
- [ ] Machines "by Company" tree nav with per-company counts — P3 — left-nav grouping sidebar (screenshot parity). Follow-up sub-item of SPEC-005.
|
||||
- [ ] Programmatic session pre-create + viewer-token (integration contract) — P2
|
||||
|
||||
## Security & Infrastructure
|
||||
|
||||
153
docs/specs/SPEC-005-machines-list-view-parity.md
Normal file
153
docs/specs/SPEC-005-machines-list-view-parity.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# 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 - <duration online>"; 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?
|
||||
Reference in New Issue
Block a user