Skip to main content

ytcli/render/
user.rs

1//! People.
2//!
3//! `LOGIN` leads because it is the value every other command takes and returns;
4//! the display name is what makes the row recognisable, not what makes it
5//! usable.
6
7use std::fmt::Write as _;
8
9use crate::api::models::Person;
10use crate::render::Context;
11use crate::render::style::Palette;
12use crate::render::table::{Column, render, tally};
13
14/// A page of the directory.
15#[must_use]
16pub fn users(
17    people: &[Person],
18    total: Option<u64>,
19    next_page: Option<u32>,
20    ctx: &Context,
21) -> String {
22    let columns = [
23        Column::whole("LOGIN", 28, Palette::key()),
24        Column::new("NAME", 30, anstyle::Style::new()),
25        Column::new("EMAIL", 30, Palette::label()),
26        // A dismissed account still owns everything it was ever assigned, so it
27        // has to be listed — but assigning new work to one is a mistake, and
28        // this column is the only warning of it there is.
29        Column::by_value("STATE", 10, |state| match state {
30            "active" => Palette::label(),
31            _ => Palette::warn(),
32        }),
33    ];
34
35    let rows: Vec<Vec<String>> = people
36        .iter()
37        .map(|person| {
38            vec![
39                person.login.clone(),
40                person.display.clone(),
41                person.email.clone().unwrap_or_else(|| "-".to_owned()),
42                state(person).to_owned(),
43            ]
44        })
45        .collect();
46
47    let mut out = render(&columns, &rows, ctx);
48    out.push_str(&tally(people.len(), total, next_page, ctx));
49    out
50}
51
52/// One person.
53#[must_use]
54pub fn user(person: &Person, ctx: &Context) -> String {
55    let paint = ctx.painter();
56    let label = |text: &str| paint.paint(text, Palette::label());
57    let mut out = String::with_capacity(200);
58
59    let _ = writeln!(
60        out,
61        "{}  {}",
62        paint.paint(&person.login, Palette::key()),
63        person.display
64    );
65    let _ = writeln!(
66        out,
67        "{} {}   {} {}",
68        label("email:"),
69        person.email.as_deref().unwrap_or("-"),
70        label("uid:"),
71        person.uid,
72    );
73    let _ = writeln!(out, "{} {}", label("state:"), state(person));
74
75    out
76}
77
78/// What to say about an account in one word.
79///
80/// Three states rather than two flags: an external contributor and a departed
81/// colleague are different answers to "can I assign this to them", and a row
82/// carrying two booleans makes the reader do that reasoning.
83fn state(person: &Person) -> &'static str {
84    if person.dismissed {
85        "dismissed"
86    } else if person.external {
87        "external"
88    } else {
89        "active"
90    }
91}