Skip to main content

singularity_cli/commands/
task_group.rs

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