crates/nornir-wire/src/view/rows.rs
//! **Warehouse-row** view-model DTOs that cross the wire — the exact rows the
//! server ships to a thin viz client (serialize → JSON → deserialize), so the
//! remote 🧬 nornir pane renders the identical data the embedded (warehouse) path
//! reads. Plain serde, relocated from their nornir home; `nornir` re-exports each
//! from its original path so the Arrow encode/decode (free functions over the
//! public fields) and the panes compile unchanged.
/// One row of the `workspace ls` roster — the projection BOTH the fat (registry
/// `Workspace`) and thin (proto) faces map into, so they render identically
/// (CLI⟺UI parity, the Nornir-tab roster's data). AUT9. Relocated from
/// `nornir/src/registry.rs`; `nornir::registry` re-exports it.
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct RosterRow {
pub name: String,
pub mode: String,
pub members: usize,
pub last_synced: String,
/// PO1 — the rolled-up POPULATE verdict for this workspace (latest clone/fetch
/// outcome per member → a workspace state). `"green"` (all members' latest ok),
/// `"red"` (≥1 member's latest is an error), `"stale"` (never populated — no
/// clone_events), or `""` when the populate roll-up wasn't requested
/// (`workspace ls` without `--status`). The roster's red/green badge.
#[serde(default, skip_serializing_if = "String::is_empty")]
pub populate: String,
/// The first failing member (when `populate == "red"`), else empty.
#[serde(default, skip_serializing_if = "String::is_empty")]
pub failing_member: String,
/// That member's latest error detail (when `populate == "red"`), else empty.
#[serde(default, skip_serializing_if = "String::is_empty")]
pub last_error: String,
}
/// One row of the `clone_events` table — a single member's clone/fetch (or the
/// workspace republish) outcome.
///
/// `serde` derives let the server ship the exact rows to a thin viz client over
/// the `Viz.CloneEvents` RPC (serialize → JSON → deserialize), so the remote 🧬
/// nornir pane + `nornir --server workspace events` render the identical populate
/// status the embedded path reads from the warehouse. Relocated from
/// `nornir/src/warehouse/clone_events.rs`; that module re-exports it and keeps the
/// Arrow sink over its public fields.
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct CloneEventRow {
/// Event time, microseconds since the Unix epoch (UTC).
pub ts_micros: i64,
/// The workspace this fetch belonged to.
pub workspace: String,
/// The member that was fetched (or `*` for a workspace-level `republish`).
pub member: String,
/// The git remote that was cloned/fetched (empty for a republish row).
pub remote: String,
/// `clone-fetch` | `republish`.
pub op: String,
/// `ok` | `error`.
pub status: String,
/// On error: the error chain (`{e:#}`). On ok: the resolved SHA (clone-fetch)
/// or the snapshot id (republish). Stored as "" never null so SQL readers see
/// no surprise nulls.
pub detail: String,
/// Wall-clock duration of the op, milliseconds.
pub elapsed_ms: i64,
}