cli/sync/status: Refactor output table

A new table style that is more narrow, and follows the recent change
to `rad node status`.
This commit is contained in:
Lorenz Leutgeb 2025-08-13 09:49:15 +02:00 committed by Fintan Halpenny
parent c089727e90
commit c8b6a13d64
2 changed files with 81 additions and 56 deletions

View File

@ -12,13 +12,13 @@ change has not yet been announced.
``` ```
$ rad sync status --sort-by alias $ rad sync status --sort-by alias
╭────────────────────────────────────────────────────────────────────────────────────────────── ╭───────────────────────────────────────────────────╮
● Node Address Status Tip Timestamp │ Node ID Alias ? SigRefs Timestamp │
├────────────────────────────────────────────────────────────────────────────────────────────── ├───────────────────────────────────────────────────┤
● alice (you) alice.radicle.example:8776 unannounced 056b1db [ ... ] (you) alice ! 056b1db [..]
● bob z6Mkt67…v4N1tRk bob.radicle.example:8776 out-of-sync 99c5497 [ ... ] z6Mkt67…v4N1tRk bob ✗ 99c5497 [..]
● eve z6Mkux1…nVhib7Z eve.radicle.example:8776 out-of-sync 99c5497 [ ... ] z6Mkux1…nVhib7Z eve ✗ 99c5497 [..]
╰────────────────────────────────────────────────────────────────────────────────────────────── ╰───────────────────────────────────────────────────╯
``` ```
Now let's run `rad sync`. This will announce the issue refs to the network and Now let's run `rad sync`. This will announce the issue refs to the network and
@ -34,13 +34,13 @@ Now, when we run `rad sync status` again, we can see that `bob` and
``` ```
$ rad sync status --sort-by alias $ rad sync status --sort-by alias
╭───────────────────────────────────────────────────────────────────────────────────────── ╭───────────────────────────────────────────────────╮
● Node Address Status Tip Timestamp │ Node ID Alias ? SigRefs Timestamp │
├───────────────────────────────────────────────────────────────────────────────────────── ├───────────────────────────────────────────────────┤
● alice (you) alice.radicle.example:8776 056b1db [ ... ] (you) alice ✓ 056b1db [..]
● bob z6Mkt67…v4N1tRk bob.radicle.example:8776 synced 056b1db [ ... ] z6Mkt67…v4N1tRk bob ✓ 056b1db [..]
● eve z6Mkux1…nVhib7Z eve.radicle.example:8776 synced 056b1db [ ... ] z6Mkux1…nVhib7Z eve ✓ 056b1db [..]
╰───────────────────────────────────────────────────────────────────────────────────────── ╰───────────────────────────────────────────────────╯
``` ```
If we try to sync again after the nodes have synced, we will already If we try to sync again after the nodes have synced, we will already

View File

@ -12,6 +12,7 @@ use radicle::node;
use radicle::node::address::Store; use radicle::node::address::Store;
use radicle::node::sync; use radicle::node::sync;
use radicle::node::sync::fetch::SuccessfulOutcome; use radicle::node::sync::fetch::SuccessfulOutcome;
use radicle::node::SyncedAt;
use radicle::node::{AliasStore, Handle as _, Node, Seed, SyncStatus}; use radicle::node::{AliasStore, Handle as _, Node, Seed, SyncStatus};
use radicle::prelude::{NodeId, Profile, RepoId}; use radicle::prelude::{NodeId, Profile, RepoId};
use radicle::storage::ReadRepository; use radicle::storage::ReadRepository;
@ -340,71 +341,63 @@ fn sync_status(
profile: &Profile, profile: &Profile,
options: &Options, options: &Options,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let mut table = Table::<7, term::Label>::new(TableOptions::bordered()); const SYMBOL_STATE: &str = "?";
const SYMBOL_STATE_UNKNOWN: &str = "";
let mut table = Table::<5, term::Label>::new(TableOptions::bordered());
let mut seeds: Vec<_> = node.seeds(rid)?.into(); let mut seeds: Vec<_> = node.seeds(rid)?.into();
let local_nid = node.nid()?; let local_nid = node.nid()?;
let aliases = profile.aliases(); let aliases = profile.aliases();
table.header([ table.header([
term::format::dim(String::from("")).into(), term::format::bold("Node ID").into(),
term::format::bold(String::from("Node")).into(), term::format::bold("Alias").into(),
term::Label::blank(), term::format::bold(SYMBOL_STATE).into(),
term::format::bold(String::from("Address")).into(), term::format::bold("SigRefs").into(),
term::format::bold(String::from("Status")).into(), term::format::bold("Timestamp").into(),
term::format::bold(String::from("Tip")).into(),
term::format::bold(String::from("Timestamp")).into(),
]); ]);
table.divider(); table.divider();
sort_seeds_by(local_nid, &mut seeds, &aliases, &options.sort_by); sort_seeds_by(local_nid, &mut seeds, &aliases, &options.sort_by);
for seed in seeds { for seed in seeds {
let (icon, status, head, time) = match seed.sync { let (status, head, time) = match seed.sync {
Some(SyncStatus::Synced { at }) => ( Some(SyncStatus::Synced {
term::format::positive(""), at: SyncedAt { oid, timestamp },
term::format::positive(if seed.nid != local_nid { "synced" } else { "" }), }) => (
term::format::oid(at.oid), term::PREFIX_SUCCESS,
term::format::timestamp(at.timestamp), term::format::oid(oid),
term::format::timestamp(timestamp),
), ),
Some(SyncStatus::OutOfSync { remote, local, .. }) => ( Some(SyncStatus::OutOfSync {
if seed.nid != local_nid { remote: SyncedAt { timestamp, .. },
term::format::negative("") local,
} else { ..
term::format::yellow("") }) if seed.nid == local_nid => (
}, term::PREFIX_WARNING,
if seed.nid != local_nid { term::format::oid(local.oid),
term::format::negative("out-of-sync") term::format::timestamp(timestamp),
} else { ),
term::format::yellow("unannounced") Some(SyncStatus::OutOfSync {
}, remote: SyncedAt { oid, timestamp },
term::format::oid(if seed.nid != local_nid { ..
remote.oid }) => (
} else { term::PREFIX_ERROR,
local.oid term::format::oid(oid),
}), term::format::timestamp(timestamp),
term::format::timestamp(remote.timestamp),
), ),
None if options.verbose => ( None if options.verbose => (
term::format::dim(""), term::format::dim(SYMBOL_STATE_UNKNOWN),
term::format::dim("unknown"),
term::paint(String::new()), term::paint(String::new()),
term::paint(String::new()), term::paint(String::new()),
), ),
None => continue, None => continue,
}; };
let addr = seed
.addrs
.first()
.map(|a| a.addr.to_string())
.unwrap_or_default()
.into();
let (alias, nid) = Author::new(&seed.nid, profile).labels(); let (alias, nid) = Author::new(&seed.nid, profile).labels();
table.push([ table.push([
icon.into(),
alias,
nid, nid,
addr, alias,
status.into(), status.into(),
term::format::secondary(head).into(), term::format::secondary(head).into(),
time.dim().italic().into(), time.dim().italic().into(),
@ -412,6 +405,38 @@ fn sync_status(
} }
table.print(); table.print();
if profile.hints() {
const COLUMN_WIDTH: usize = 16;
let status = format!(
"\n{:>4} … {}\n {} {}\n {} {}",
term::Paint::from(SYMBOL_STATE.to_string()).fg(radicle_term::Color::White),
term::format::dim("Status:"),
format_args!(
"{} {:width$}",
term::PREFIX_SUCCESS,
term::format::dim("… in sync"),
width = COLUMN_WIDTH,
),
format_args!(
"{} {}",
term::PREFIX_ERROR,
term::format::dim("… out of sync")
),
format_args!(
"{} {:width$}",
term::PREFIX_WARNING,
term::format::dim("… not announced"),
width = COLUMN_WIDTH,
),
format_args!(
"{} {}",
term::format::dim(SYMBOL_STATE_UNKNOWN),
term::format::dim("… unknown")
),
);
term::hint(status);
}
Ok(()) Ok(())
} }