Skip to main content

singularity_cli/commands/
tag.rs

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