Skip to main content

clickup_cli/commands/
space.rs

1use clap::Subcommand;
2use crate::client::ClickUpClient;
3use crate::commands::auth::resolve_token;
4use crate::commands::workspace::resolve_workspace;
5use crate::error::CliError;
6use crate::output::OutputConfig;
7use crate::Cli;
8
9#[derive(Subcommand)]
10pub enum SpaceCommands {
11    /// List spaces in workspace
12    List {
13        /// Include archived spaces
14        #[arg(long)]
15        archived: bool,
16    },
17    /// Get space details
18    Get {
19        /// Space ID
20        id: String,
21    },
22    /// Create a new space
23    Create {
24        /// Space name
25        #[arg(long)]
26        name: String,
27        /// Make space private
28        #[arg(long)]
29        private: bool,
30        /// Allow multiple assignees
31        #[arg(long)]
32        multiple_assignees: bool,
33    },
34    /// Update a space
35    Update {
36        /// Space ID
37        id: String,
38        /// New name
39        #[arg(long)]
40        name: Option<String>,
41        /// Color hex
42        #[arg(long)]
43        color: Option<String>,
44    },
45    /// Delete a space
46    Delete {
47        /// Space ID
48        id: String,
49    },
50}
51
52pub async fn execute(command: SpaceCommands, cli: &Cli) -> Result<(), CliError> {
53    let token = resolve_token(cli)?;
54    let client = ClickUpClient::new(&token, cli.timeout)?;
55    let output = OutputConfig::from_cli(&cli.output, &cli.fields, cli.no_header, cli.quiet);
56
57    match command {
58        SpaceCommands::List { archived } => {
59            let ws_id = resolve_workspace(cli)?;
60            let resp = client
61                .get(&format!("/v2/team/{}/space?archived={}", ws_id, archived))
62                .await?;
63            let spaces = resp
64                .get("spaces")
65                .and_then(|s| s.as_array())
66                .cloned()
67                .unwrap_or_default();
68            output.print_items(&spaces, &["id", "name", "private", "archived"], "id");
69            Ok(())
70        }
71        SpaceCommands::Get { id } => {
72            let resp = client.get(&format!("/v2/space/{}", id)).await?;
73            output.print_single(&resp, &["id", "name", "private", "archived"], "id");
74            Ok(())
75        }
76        SpaceCommands::Create {
77            name,
78            private,
79            multiple_assignees,
80        } => {
81            let ws_id = resolve_workspace(cli)?;
82            let body = serde_json::json!({
83                "name": name,
84                "multiple_assignees": multiple_assignees,
85                "features": {
86                    "due_dates": { "enabled": true },
87                    "priorities": { "enabled": true },
88                    "tags": { "enabled": true },
89                    "time_estimates": { "enabled": true },
90                },
91                "private": private,
92            });
93            let resp = client
94                .post(&format!("/v2/team/{}/space", ws_id), &body)
95                .await?;
96            output.print_single(&resp, &["id", "name", "private"], "id");
97            Ok(())
98        }
99        SpaceCommands::Update { id, name, color } => {
100            let mut body = serde_json::Map::new();
101            if let Some(n) = name {
102                body.insert("name".into(), serde_json::Value::String(n));
103            }
104            if let Some(c) = color {
105                body.insert("color".into(), serde_json::Value::String(c));
106            }
107            let resp = client
108                .put(&format!("/v2/space/{}", id), &serde_json::Value::Object(body))
109                .await?;
110            output.print_single(&resp, &["id", "name", "private"], "id");
111            Ok(())
112        }
113        SpaceCommands::Delete { id } => {
114            client.delete(&format!("/v2/space/{}", id)).await?;
115            output.print_message(&format!("Space {} deleted", id));
116            Ok(())
117        }
118    }
119}