Skip to main content

ytcli/cli/
field.rs

1//! Organisation-wide field and template listings.
2//!
3//! Read-only. `queue fields` answers what a queue accepts; these answer what
4//! the organisation defines, which is the question behind a field a queue does
5//! not show and a template somebody else made.
6
7use clap::{Subcommand, ValueEnum};
8
9use crate::api::TemplateKind;
10use crate::cli::{Session, emit, report};
11use crate::exit::ExitCode;
12use crate::render::{Format, machine, queue as render};
13
14#[derive(Debug, Subcommand)]
15pub enum FieldCommand {
16    /// List every field defined in the organisation.
17    #[command(long_about = crate::cli::help::md(crate::cli::help::FIELD_LIST))]
18    List,
19    /// Show one field: what it holds and what values it accepts.
20    #[command(long_about = crate::cli::help::md(crate::cli::help::FIELD_GET))]
21    Get {
22        /// Field key, as printed by `queue fields` or `field list`.
23        key: String,
24        /// List every accepted value, however many there are.
25        #[arg(long)]
26        all: bool,
27    },
28}
29
30#[derive(Debug, Subcommand)]
31pub enum TemplateCommand {
32    /// List templates.
33    #[command(long_about = crate::cli::help::md(crate::cli::help::TEMPLATE_LIST))]
34    List {
35        /// Which templates to list.
36        #[arg(long, value_enum, default_value_t = Kind::Issue)]
37        kind: Kind,
38    },
39}
40
41#[derive(Debug, Clone, Copy, ValueEnum)]
42pub enum Kind {
43    Issue,
44    Comment,
45}
46
47impl From<Kind> for TemplateKind {
48    fn from(kind: Kind) -> Self {
49        match kind {
50            Kind::Issue => Self::Issue,
51            Kind::Comment => Self::Comment,
52        }
53    }
54}
55
56pub async fn run(command: &FieldCommand, session: &Session) -> ExitCode {
57    let client = match session.client() {
58        Ok(client) => client,
59        Err(code) => return code,
60    };
61
62    match command {
63        FieldCommand::List => match client.fields().await {
64            Ok(fields) => finish(&fields, session, |fields| {
65                render::fields(fields, &session.render)
66            }),
67            Err(error) => {
68                let code = error.exit_code();
69                report(&error, code)
70            }
71        },
72        FieldCommand::Get { key, all } => match client.field(key).await {
73            Ok(field) => {
74                let rendered = match session.render.format {
75                    Format::Text => Ok(render::field_spec(&field, *all, &session.render)),
76                    Format::JsonRaw => machine(&field, Format::Json),
77                    other => machine(&field, other),
78                };
79                match rendered {
80                    Ok(text) => {
81                        emit(&text);
82                        ExitCode::Success
83                    }
84                    Err(error) => report(&error, ExitCode::Failure),
85                }
86            }
87            Err(error) => {
88                let code = error.exit_code();
89                report(&error, code)
90            }
91        },
92    }
93}
94
95pub async fn run_templates(command: &TemplateCommand, session: &Session) -> ExitCode {
96    let client = match session.client() {
97        Ok(client) => client,
98        Err(code) => return code,
99    };
100
101    let TemplateCommand::List { kind } = command;
102    match client.templates((*kind).into()).await {
103        Ok(templates) => finish(&templates, session, |templates| {
104            render::templates(templates, &session.render)
105        }),
106        Err(error) => {
107            let code = error.exit_code();
108            report(&error, code)
109        }
110    }
111}
112
113fn finish<T: serde::Serialize>(
114    value: &[T],
115    session: &Session,
116    as_text: impl Fn(&[T]) -> String,
117) -> ExitCode {
118    let rendered = match session.render.format {
119        Format::Text => Ok(as_text(value)),
120        Format::JsonRaw => machine(&value, Format::Json),
121        other => machine(&value, other),
122    };
123
124    match rendered {
125        Ok(text) => {
126            emit(&text);
127            ExitCode::Success
128        }
129        Err(error) => report(&error, ExitCode::Failure),
130    }
131}