Skip to main content

clickup_cli/commands/
template.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 TemplateCommands {
11    /// List task templates for the workspace
12    List {
13        /// Page number
14        #[arg(long, default_value = "0")]
15        page: u32,
16    },
17    /// Apply a task template to a list
18    #[command(name = "apply-task")]
19    ApplyTask {
20        /// Template ID
21        template_id: String,
22        /// List ID to create the task in
23        #[arg(long)]
24        list: String,
25        /// Task name
26        #[arg(long)]
27        name: String,
28    },
29    /// Apply a list template to a folder or space
30    #[command(name = "apply-list")]
31    ApplyList {
32        /// Template ID
33        template_id: String,
34        /// Folder ID (mutually exclusive with --space)
35        #[arg(long, conflicts_with = "space")]
36        folder: Option<String>,
37        /// Space ID (mutually exclusive with --folder)
38        #[arg(long)]
39        space: Option<String>,
40        /// List name
41        #[arg(long)]
42        name: String,
43    },
44    /// Apply a folder template to a space
45    #[command(name = "apply-folder")]
46    ApplyFolder {
47        /// Template ID
48        template_id: String,
49        /// Space ID
50        #[arg(long)]
51        space: String,
52        /// Folder name
53        #[arg(long)]
54        name: String,
55    },
56}
57
58const TEMPLATE_FIELDS: &[&str] = &["id", "name"];
59
60pub async fn execute(command: TemplateCommands, cli: &Cli) -> Result<(), CliError> {
61    let token = resolve_token(cli)?;
62    let client = ClickUpClient::new(&token, cli.timeout)?;
63    let output = OutputConfig::from_cli(&cli.output, &cli.fields, cli.no_header, cli.quiet);
64
65    match command {
66        TemplateCommands::List { page } => {
67            let ws_id = resolve_workspace(cli)?;
68            let resp = client
69                .get(&format!("/v2/team/{}/taskTemplate?page={}", ws_id, page))
70                .await?;
71            let mut templates = resp
72                .get("templates")
73                .and_then(|v| v.as_array())
74                .cloned()
75                .unwrap_or_default();
76            if let Some(limit) = cli.limit {
77                templates.truncate(limit);
78            }
79            output.print_items(&templates, TEMPLATE_FIELDS, "id");
80            Ok(())
81        }
82        TemplateCommands::ApplyTask {
83            template_id,
84            list,
85            name,
86        } => {
87            let body = serde_json::json!({ "name": name });
88            let resp = client
89                .post(
90                    &format!("/v2/list/{}/taskTemplate/{}", list, template_id),
91                    &body,
92                )
93                .await?;
94            println!("{}", serde_json::to_string_pretty(&resp).unwrap());
95            Ok(())
96        }
97        TemplateCommands::ApplyList {
98            template_id,
99            folder,
100            space,
101            name,
102        } => {
103            let body = serde_json::json!({ "name": name });
104            let path = if let Some(f) = folder {
105                format!("/v2/folder/{}/list_template/{}", f, template_id)
106            } else if let Some(s) = space {
107                format!("/v2/space/{}/list_template/{}", s, template_id)
108            } else {
109                return Err(CliError::ClientError {
110                    message: "Specify --folder or --space".into(),
111                    status: 0,
112                });
113            };
114            let resp = client.post(&path, &body).await?;
115            println!("{}", serde_json::to_string_pretty(&resp).unwrap());
116            Ok(())
117        }
118        TemplateCommands::ApplyFolder {
119            template_id,
120            space,
121            name,
122        } => {
123            let body = serde_json::json!({ "name": name });
124            let resp = client
125                .post(
126                    &format!("/v2/space/{}/folder_template/{}", space, template_id),
127                    &body,
128                )
129                .await?;
130            println!("{}", serde_json::to_string_pretty(&resp).unwrap());
131            Ok(())
132        }
133    }
134}