re-uploading work

This commit is contained in:
2026-02-04 17:46:30 -06:00
commit 3b14c65998
1388 changed files with 381262 additions and 0 deletions

View File

@@ -0,0 +1,346 @@
use anyhow::Result;
use clap::Subcommand;
use serde::{Deserialize, Serialize};
use crate::client::ApiClient;
use crate::config::CliConfig;
use crate::output::{self, OutputFormat};
#[derive(Subcommand)]
pub enum TriggerCommands {
/// List all triggers
List {
/// Filter by pack name
#[arg(long)]
pack: Option<String>,
},
/// Show details of a specific trigger
Show {
/// Trigger reference (pack.trigger or ID)
trigger_ref: String,
},
/// Update a trigger
Update {
/// Trigger reference (pack.trigger or ID)
trigger_ref: String,
/// Update label
#[arg(long)]
label: Option<String>,
/// Update description
#[arg(long)]
description: Option<String>,
/// Update enabled status
#[arg(long)]
enabled: Option<bool>,
},
/// Delete a trigger
Delete {
/// Trigger reference (pack.trigger or ID)
trigger_ref: String,
/// Skip confirmation prompt
#[arg(short, long)]
yes: bool,
},
}
#[derive(Debug, Serialize, Deserialize)]
struct Trigger {
id: i64,
#[serde(rename = "ref")]
trigger_ref: String,
#[serde(default)]
pack: Option<i64>,
#[serde(default)]
pack_ref: Option<String>,
label: String,
description: Option<String>,
enabled: bool,
#[serde(default)]
param_schema: Option<serde_json::Value>,
#[serde(default)]
out_schema: Option<serde_json::Value>,
#[serde(default)]
webhook_enabled: Option<bool>,
#[serde(default)]
webhook_key: Option<String>,
created: String,
updated: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct TriggerDetail {
id: i64,
#[serde(rename = "ref")]
trigger_ref: String,
#[serde(default)]
pack: Option<i64>,
#[serde(default)]
pack_ref: Option<String>,
label: String,
description: Option<String>,
enabled: bool,
#[serde(default)]
param_schema: Option<serde_json::Value>,
#[serde(default)]
out_schema: Option<serde_json::Value>,
#[serde(default)]
webhook_enabled: Option<bool>,
#[serde(default)]
webhook_key: Option<String>,
created: String,
updated: String,
}
pub async fn handle_trigger_command(
profile: &Option<String>,
command: TriggerCommands,
api_url: &Option<String>,
output_format: OutputFormat,
) -> Result<()> {
match command {
TriggerCommands::List { pack } => handle_list(pack, profile, api_url, output_format).await,
TriggerCommands::Show { trigger_ref } => {
handle_show(trigger_ref, profile, api_url, output_format).await
}
TriggerCommands::Update {
trigger_ref,
label,
description,
enabled,
} => {
handle_update(
trigger_ref,
label,
description,
enabled,
profile,
api_url,
output_format,
)
.await
}
TriggerCommands::Delete { trigger_ref, yes } => {
handle_delete(trigger_ref, yes, profile, api_url, output_format).await
}
}
}
async fn handle_list(
pack: Option<String>,
profile: &Option<String>,
api_url: &Option<String>,
output_format: OutputFormat,
) -> Result<()> {
let config = CliConfig::load_with_profile(profile.as_deref())?;
let mut client = ApiClient::from_config(&config, api_url);
let path = if let Some(pack_name) = pack {
format!("/triggers?pack={}", pack_name)
} else {
"/triggers".to_string()
};
let triggers: Vec<Trigger> = client.get(&path).await?;
match output_format {
OutputFormat::Json | OutputFormat::Yaml => {
output::print_output(&triggers, output_format)?;
}
OutputFormat::Table => {
if triggers.is_empty() {
output::print_info("No triggers found");
} else {
let mut table = output::create_table();
output::add_header(&mut table, vec!["ID", "Pack", "Name", "Description"]);
for trigger in triggers {
table.add_row(vec![
trigger.id.to_string(),
trigger.pack_ref.as_deref().unwrap_or("").to_string(),
trigger.label.clone(),
output::truncate(&trigger.description.unwrap_or_default(), 50),
]);
}
println!("{}", table);
}
}
}
Ok(())
}
async fn handle_show(
trigger_ref: String,
profile: &Option<String>,
api_url: &Option<String>,
output_format: OutputFormat,
) -> Result<()> {
let config = CliConfig::load_with_profile(profile.as_deref())?;
let mut client = ApiClient::from_config(&config, api_url);
let path = format!("/triggers/{}", trigger_ref);
let trigger: TriggerDetail = client.get(&path).await?;
match output_format {
OutputFormat::Json | OutputFormat::Yaml => {
output::print_output(&trigger, output_format)?;
}
OutputFormat::Table => {
output::print_section(&format!("Trigger: {}", trigger.trigger_ref));
output::print_key_value_table(vec![
("ID", trigger.id.to_string()),
("Ref", trigger.trigger_ref.clone()),
(
"Pack",
trigger.pack_ref.as_deref().unwrap_or("None").to_string(),
),
("Label", trigger.label.clone()),
(
"Description",
trigger.description.unwrap_or_else(|| "None".to_string()),
),
("Enabled", output::format_bool(trigger.enabled)),
(
"Webhook Enabled",
output::format_bool(trigger.webhook_enabled.unwrap_or(false)),
),
("Created", output::format_timestamp(&trigger.created)),
("Updated", output::format_timestamp(&trigger.updated)),
]);
if let Some(webhook_key) = &trigger.webhook_key {
output::print_section("Webhook");
output::print_info(&format!("Key: {}", webhook_key));
}
if let Some(param_schema) = &trigger.param_schema {
if !param_schema.is_null() {
output::print_section("Parameter Schema");
println!("{}", serde_json::to_string_pretty(param_schema)?);
}
}
if let Some(out_schema) = &trigger.out_schema {
if !out_schema.is_null() {
output::print_section("Output Schema");
println!("{}", serde_json::to_string_pretty(out_schema)?);
}
}
}
}
Ok(())
}
async fn handle_update(
trigger_ref: String,
label: Option<String>,
description: Option<String>,
enabled: Option<bool>,
profile: &Option<String>,
api_url: &Option<String>,
output_format: OutputFormat,
) -> Result<()> {
let config = CliConfig::load_with_profile(profile.as_deref())?;
let mut client = ApiClient::from_config(&config, api_url);
// Check that at least one field is provided
if label.is_none() && description.is_none() && enabled.is_none() {
anyhow::bail!("At least one field must be provided to update");
}
#[derive(Serialize)]
struct UpdateTriggerRequest {
#[serde(skip_serializing_if = "Option::is_none")]
label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
enabled: Option<bool>,
}
let request = UpdateTriggerRequest {
label,
description,
enabled,
};
let path = format!("/triggers/{}", trigger_ref);
let trigger: TriggerDetail = client.put(&path, &request).await?;
match output_format {
OutputFormat::Json | OutputFormat::Yaml => {
output::print_output(&trigger, output_format)?;
}
OutputFormat::Table => {
output::print_success(&format!(
"Trigger '{}' updated successfully",
trigger.trigger_ref
));
output::print_key_value_table(vec![
("ID", trigger.id.to_string()),
("Ref", trigger.trigger_ref.clone()),
(
"Pack",
trigger.pack_ref.as_deref().unwrap_or("None").to_string(),
),
("Label", trigger.label.clone()),
(
"Description",
trigger.description.unwrap_or_else(|| "None".to_string()),
),
("Enabled", output::format_bool(trigger.enabled)),
("Updated", output::format_timestamp(&trigger.updated)),
]);
}
}
Ok(())
}
async fn handle_delete(
trigger_ref: String,
yes: bool,
profile: &Option<String>,
api_url: &Option<String>,
output_format: OutputFormat,
) -> Result<()> {
let config = CliConfig::load_with_profile(profile.as_deref())?;
let mut client = ApiClient::from_config(&config, api_url);
// Confirm deletion unless --yes is provided
if !yes && matches!(output_format, OutputFormat::Table) {
let confirm = dialoguer::Confirm::new()
.with_prompt(format!(
"Are you sure you want to delete trigger '{}'?",
trigger_ref
))
.default(false)
.interact()?;
if !confirm {
output::print_info("Delete cancelled");
return Ok(());
}
}
let path = format!("/triggers/{}", trigger_ref);
client.delete_no_response(&path).await?;
match output_format {
OutputFormat::Json | OutputFormat::Yaml => {
let msg = serde_json::json!({"message": "Trigger deleted successfully"});
output::print_output(&msg, output_format)?;
}
OutputFormat::Table => {
output::print_success(&format!("Trigger '{}' deleted successfully", trigger_ref));
}
}
Ok(())
}