Skip to main content

singularity_cli/commands/
tag.rs

1use anyhow::Result;
2use clap::Subcommand;
3use tabled::Table;
4
5use crate::client::ApiClient;
6use crate::models::tag::{Tag, TagCreate, TagListResponse, TagUpdate};
7
8#[derive(Subcommand)]
9pub enum TagCmd {
10    #[command(about = "List all tags")]
11    List {
12        #[arg(long, help = "Filter by parent tag ID")]
13        parent: Option<String>,
14        #[arg(long, help = "Maximum number of tags to return (max 1000)")]
15        max_count: Option<u32>,
16        #[arg(long, help = "Number of tags to skip for pagination")]
17        offset: Option<u32>,
18        #[arg(long, help = "Include soft-deleted tags")]
19        include_removed: bool,
20    },
21    #[command(about = "Get a single tag by ID")]
22    Get {
23        #[arg(help = "Tag ID")]
24        id: String,
25    },
26    #[command(about = "Create a new tag")]
27    Create {
28        #[arg(long, help = "Tag title (required)")]
29        title: String,
30        #[arg(long, help = "Parent tag ID for nesting")]
31        parent: Option<String>,
32        #[arg(long, help = "Display order")]
33        order: Option<f64>,
34    },
35    #[command(about = "Update an existing tag (only specified fields are changed)")]
36    Update {
37        #[arg(help = "Tag ID to update")]
38        id: String,
39        #[arg(long, help = "New tag title")]
40        title: Option<String>,
41        #[arg(long, help = "New parent tag ID")]
42        parent: Option<String>,
43        #[arg(long, help = "New display order")]
44        order: Option<f64>,
45    },
46    #[command(about = "Delete a tag by ID (soft-delete)")]
47    Delete {
48        #[arg(help = "Tag ID to delete")]
49        id: String,
50    },
51}
52
53pub fn run(client: &ApiClient, cmd: TagCmd, json: bool) -> Result<()> {
54    match cmd {
55        TagCmd::List {
56            parent,
57            max_count,
58            offset,
59            include_removed,
60        } => {
61            let mut query: Vec<(&str, String)> = Vec::new();
62            if let Some(ref v) = parent {
63                query.push(("parent", v.to_string()));
64            }
65            if let Some(v) = max_count {
66                query.push(("maxCount", v.to_string()));
67            }
68            if let Some(v) = offset {
69                query.push(("offset", v.to_string()));
70            }
71            if include_removed {
72                query.push(("includeRemoved", "true".to_string()));
73            }
74
75            if json {
76                let resp: serde_json::Value = client.get("/v2/tag", &query)?;
77                println!("{}", serde_json::to_string_pretty(&resp)?);
78            } else {
79                let resp: TagListResponse = client.get("/v2/tag", &query)?;
80                if resp.tags.is_empty() {
81                    println!("No tags found.");
82                } else {
83                    println!("{}", Table::new(&resp.tags));
84                }
85            }
86        }
87        TagCmd::Get { id } => {
88            if json {
89                let resp: serde_json::Value = client.get(&format!("/v2/tag/{}", id), &[])?;
90                println!("{}", serde_json::to_string_pretty(&resp)?);
91            } else {
92                let tag: Tag = client.get(&format!("/v2/tag/{}", id), &[])?;
93                tag.display_detail();
94            }
95        }
96        TagCmd::Create {
97            title,
98            parent,
99            order,
100        } => {
101            let data = TagCreate {
102                title,
103                parent,
104                order,
105            };
106            if json {
107                let resp: serde_json::Value = client.post("/v2/tag", &data)?;
108                println!("{}", serde_json::to_string_pretty(&resp)?);
109            } else {
110                let tag: Tag = client.post("/v2/tag", &data)?;
111                println!("Created tag {}", tag.id);
112            }
113        }
114        TagCmd::Update {
115            id,
116            title,
117            parent,
118            order,
119        } => {
120            let data = TagUpdate {
121                title,
122                parent,
123                order,
124            };
125            if json {
126                let resp: serde_json::Value = client.patch(&format!("/v2/tag/{}", id), &data)?;
127                println!("{}", serde_json::to_string_pretty(&resp)?);
128            } else {
129                let tag: Tag = client.patch(&format!("/v2/tag/{}", id), &data)?;
130                println!("Updated tag {}", tag.id);
131            }
132        }
133        TagCmd::Delete { id } => {
134            client.delete(&format!("/v2/tag/{}", id))?;
135            println!("Deleted tag {}", id);
136        }
137    }
138    Ok(())
139}