Add the remaining 22 simple-CRUD resources
Finishes the mechanical rollout: every resource using resource_methods!/crud_methods! in the SDK (list/get/create/update/ delete, no bulk/uploads/entity-actions) is now wired up, 33 in total. recurring_quotes.rs mirrors recurring_invoices.rs the same way quotes.rs mirrors invoices.rs, since RecurringQuote is also a type alias for RecurringInvoice in the SDK. client_gateway_tokens, companies, and system_logs use the SDK's crud_methods! rather than resource_methods! (no /bulk route in Invoice Ninja for these) - doesn't change anything here, since this CLI doesn't expose bulk actions yet either way. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
//! `task-schedulers` subcommand. Same shape as `clients.rs` — see the
|
||||
//! "Adding a resource" section in CLAUDE.md.
|
||||
|
||||
use invoiceninja_sdk::models::{ListParams, TaskScheduler};
|
||||
use invoiceninja_sdk::InvoiceNinjaClient;
|
||||
|
||||
use crate::body;
|
||||
use crate::cli::{Action, BodyArgs, ListArgs, OutputFormat, ResourceArgs};
|
||||
use crate::output;
|
||||
|
||||
pub async fn run(
|
||||
client: &InvoiceNinjaClient,
|
||||
args: ResourceArgs,
|
||||
format: OutputFormat,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match args.action {
|
||||
Action::List(list_args) => list(client, list_args, format).await,
|
||||
Action::Get { id } => get(client, &id, format).await,
|
||||
Action::Create(body_args) => create(client, body_args, format).await,
|
||||
Action::Update { id, body } => update(client, &id, body, format).await,
|
||||
Action::Delete { id } => delete(client, &id).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn list(
|
||||
client: &InvoiceNinjaClient,
|
||||
args: ListArgs,
|
||||
format: OutputFormat,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut params = ListParams::new();
|
||||
if let Some(page) = args.page {
|
||||
params = params.page(page);
|
||||
}
|
||||
if let Some(per_page) = args.per_page {
|
||||
params = params.per_page(per_page);
|
||||
}
|
||||
if let Some(sort) = args.sort {
|
||||
params = params.sort(sort);
|
||||
}
|
||||
if let Some(filter) = args.filter {
|
||||
params = params.filter(filter);
|
||||
}
|
||||
if let Some(status) = args.status {
|
||||
params = params.status(status);
|
||||
}
|
||||
if let Some(include) = args.include {
|
||||
params = params.include(include);
|
||||
}
|
||||
for (k, v) in args.params {
|
||||
params = params.param(k, v);
|
||||
}
|
||||
|
||||
let task_schedulers = if args.all {
|
||||
client.list_all_task_schedulers(¶ms).await?
|
||||
} else {
|
||||
client.list_task_schedulers(¶ms).await?
|
||||
};
|
||||
|
||||
render(&task_schedulers, format)
|
||||
}
|
||||
|
||||
async fn get(
|
||||
client: &InvoiceNinjaClient,
|
||||
id: &str,
|
||||
format: OutputFormat,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let found = client.get_task_scheduler(id).await?;
|
||||
render(std::slice::from_ref(&found), format)
|
||||
}
|
||||
|
||||
async fn create(
|
||||
client: &InvoiceNinjaClient,
|
||||
body_args: BodyArgs,
|
||||
format: OutputFormat,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let value = body::load(&body_args)?;
|
||||
let model: TaskScheduler = serde_json::from_value(value)?;
|
||||
let created = client.create_task_scheduler(&model).await?;
|
||||
render(std::slice::from_ref(&created), format)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
client: &InvoiceNinjaClient,
|
||||
id: &str,
|
||||
body_args: BodyArgs,
|
||||
format: OutputFormat,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let patch = body::load(&body_args)?;
|
||||
let current = client.get_task_scheduler(id).await?;
|
||||
let merged = body::merge_shallow(serde_json::to_value(¤t)?, patch);
|
||||
let model: TaskScheduler = serde_json::from_value(merged)?;
|
||||
let updated = client.update_task_scheduler(id, &model).await?;
|
||||
render(std::slice::from_ref(&updated), format)
|
||||
}
|
||||
|
||||
async fn delete(client: &InvoiceNinjaClient, id: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
client.delete_task_scheduler(id).await?;
|
||||
println!("deleted {id}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render(
|
||||
task_schedulers: &[TaskScheduler],
|
||||
format: OutputFormat,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match format {
|
||||
OutputFormat::Json => output::print_json(task_schedulers)?,
|
||||
OutputFormat::Table => print_table(task_schedulers),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_table(task_schedulers: &[TaskScheduler]) {
|
||||
if task_schedulers.is_empty() {
|
||||
println!("(no records)");
|
||||
return;
|
||||
}
|
||||
println!(
|
||||
"{:<20} {:<20} {:<12} {:<8}",
|
||||
"id", "job", "repeat_every", "paused"
|
||||
);
|
||||
for s in task_schedulers {
|
||||
println!(
|
||||
"{:<20} {:<20} {:<12} {:<8}",
|
||||
s.id.as_deref().unwrap_or(""),
|
||||
truncate(&s.job, 20),
|
||||
s.repeat_every,
|
||||
s.paused
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn truncate(s: &str, max: usize) -> String {
|
||||
if s.chars().count() <= max {
|
||||
s.to_string()
|
||||
} else {
|
||||
s.chars().take(max.saturating_sub(1)).collect::<String>() + "…"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user