use crate::client::ClickUpClient;
use crate::commands::auth::resolve_token;
use crate::commands::workspace::resolve_workspace;
use crate::error::CliError;
use crate::output::OutputConfig;
use crate::Cli;
use clap::Subcommand;
#[derive(Subcommand)]
pub enum DocCommands {
List {
#[arg(long)]
creator: Option<String>,
#[arg(long)]
archived: bool,
},
Create {
#[arg(long)]
name: String,
#[arg(long)]
visibility: Option<String>,
#[arg(long)]
parent_type: Option<String>,
#[arg(long)]
parent_id: Option<String>,
},
Get {
id: String,
},
Pages {
id: String,
#[arg(long)]
content: bool,
#[arg(long)]
max_depth: Option<u32>,
},
#[command(name = "add-page")]
AddPage {
doc_id: String,
#[arg(long)]
name: String,
#[arg(long)]
parent_page: Option<String>,
#[arg(long)]
content: Option<String>,
},
Page {
doc_id: String,
page_id: String,
},
#[command(name = "edit-page")]
EditPage {
doc_id: String,
page_id: String,
#[arg(long)]
content: String,
#[arg(long, default_value = "replace")]
mode: String,
},
}
const DOC_FIELDS: &[&str] = &["id", "name", "visibility", "date_created"];
const PAGE_FIELDS: &[&str] = &["id", "name", "date_created", "date_updated"];
pub async fn execute(command: DocCommands, cli: &Cli) -> Result<(), CliError> {
let token = resolve_token(cli)?;
let client = ClickUpClient::new(&token, cli.timeout)?;
let ws_id = resolve_workspace(cli)?;
let output = OutputConfig::from_cli(&cli.output, &cli.fields, cli.no_header, cli.quiet);
let base = format!("/v3/workspaces/{}/docs", ws_id);
match command {
DocCommands::List { creator, archived } => {
let mut params = Vec::new();
if let Some(c) = &creator {
params.push(format!("creator_id={}", c));
}
if archived {
params.push("archived=true".to_string());
}
let query = if params.is_empty() {
String::new()
} else {
format!("?{}", params.join("&"))
};
let resp = client.get(&format!("{}{}", base, query)).await?;
let mut docs = resp
.get("docs")
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_default();
if let Some(limit) = cli.limit {
docs.truncate(limit);
}
output.print_items(&docs, DOC_FIELDS, "id");
Ok(())
}
DocCommands::Create {
name,
visibility,
parent_type,
parent_id,
} => {
let mut body = serde_json::json!({ "name": name });
if let Some(v) = visibility {
body["visibility"] = serde_json::Value::String(v);
}
if parent_type.is_some() || parent_id.is_some() {
let mut parent = serde_json::Map::new();
if let Some(pt) = parent_type {
parent.insert("type".into(), serde_json::Value::String(pt));
}
if let Some(pi) = parent_id {
parent.insert("id".into(), serde_json::Value::String(pi));
}
body["parent"] = serde_json::Value::Object(parent);
}
let resp = client.post(&base, &body).await?;
output.print_single(&resp, DOC_FIELDS, "id");
Ok(())
}
DocCommands::Get { id } => {
let resp = client.get(&format!("{}/{}", base, id)).await?;
output.print_single(&resp, DOC_FIELDS, "id");
Ok(())
}
DocCommands::Pages {
id,
content,
max_depth,
} => {
if content || max_depth.is_some() {
let mut params = Vec::new();
if content {
params.push("content=true".to_string());
}
if let Some(depth) = max_depth {
params.push(format!("max_page_depth={}", depth));
}
let query = if params.is_empty() {
String::new()
} else {
format!("?{}", params.join("&"))
};
let resp = client
.get(&format!("{}/{}/pages{}", base, id, query))
.await?;
let mut pages = resp
.get("pages")
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_else(|| resp.as_array().cloned().unwrap_or_default());
if let Some(limit) = cli.limit {
pages.truncate(limit);
}
output.print_items(&pages, PAGE_FIELDS, "id");
} else {
let resp = client.get(&format!("{}/{}/page_listing", base, id)).await?;
let mut pages = resp
.get("pages")
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_else(|| resp.as_array().cloned().unwrap_or_default());
if let Some(limit) = cli.limit {
pages.truncate(limit);
}
output.print_items(&pages, PAGE_FIELDS, "id");
}
Ok(())
}
DocCommands::AddPage {
doc_id,
name,
parent_page,
content,
} => {
let mut body = serde_json::json!({ "name": name });
if let Some(pp) = parent_page {
body["parent_page_id"] = serde_json::Value::String(pp);
}
if let Some(c) = content {
body["content"] = serde_json::Value::String(c);
}
let resp = client
.post(&format!("{}/{}/pages", base, doc_id), &body)
.await?;
output.print_single(&resp, PAGE_FIELDS, "id");
Ok(())
}
DocCommands::Page { doc_id, page_id } => {
let resp = client
.get(&format!("{}/{}/pages/{}", base, doc_id, page_id))
.await?;
output.print_single(&resp, PAGE_FIELDS, "id");
Ok(())
}
DocCommands::EditPage {
doc_id,
page_id,
content,
mode,
} => {
let body = serde_json::json!({
"content": content,
"content_edit_mode": mode,
});
let resp = client
.put(&format!("{}/{}/pages/{}", base, doc_id, page_id), &body)
.await?;
output.print_single(&resp, PAGE_FIELDS, "id");
Ok(())
}
}
}