Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions crates/cli/src/commands/batch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::ui::error_summary::ErrorSummaryList;
use clap::Args;
use grat_core::types::config::NetworkConfig;

#[derive(Args)]
pub struct BatchArgs {
#[arg(required = true, num_args = 1..)]
pub tx_hashes: Vec<String>,
}

pub async fn run(args: BatchArgs, network: &NetworkConfig) -> anyhow::Result<()> {
let mut all_reports = Vec::new();

let spinner = indicatif::ProgressBar::new_spinner();
spinner.set_message(format!("Decoding {} transactions...", args.tx_hashes.len()));
spinner.enable_steady_tick(std::time::Duration::from_millis(100));

for hash in &args.tx_hashes {
if let Ok(reports) =
grat_core::decode::decode_transaction_with_op_filter(hash, network, None).await
{
all_reports.extend(reports);
}
}

spinner.finish_and_clear();

ErrorSummaryList::render(&all_reports);

Ok(())
}
1 change: 1 addition & 0 deletions crates/cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod auth;
pub mod batch;
pub mod clean;
pub mod db;
pub mod decode;
Expand Down
3 changes: 3 additions & 0 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ enum Commands {
#[command(next_help_heading = "Analysis Commands")]
Decode(commands::decode::DecodeArgs),

Batch(commands::batch::BatchArgs),

Inspect(commands::inspect::InspectArgs),

Trace(commands::trace::TraceArgs),
Expand Down Expand Up @@ -128,6 +130,7 @@ async fn main() -> anyhow::Result<()> {

match cli.command {
Commands::Decode(args) => commands::decode::run(args, &network, &cli.output, save).await?,
Commands::Batch(args) => commands::batch::run(args, &network).await?,
Commands::Inspect(args) => {
commands::inspect::run(args, &network, &cli.output, save).await?;
}
Expand Down
96 changes: 96 additions & 0 deletions crates/cli/src/ui/error_summary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use colored::Colorize;
use grat_core::types::report::{DiagnosticReport, Severity};
use std::collections::HashMap;
use tabled::{settings::Style, Table, Tabled};

pub struct ErrorSummaryList;

#[derive(Tabled)]
struct ErrorSummaryRow {
#[tabled(rename = "Severity")]
severity: String,
#[tabled(rename = "Category")]
category: String,
#[tabled(rename = "Error Name")]
name: String,
#[tabled(rename = "Count")]
count: usize,
#[tabled(rename = "Message")]
message: String,
}

impl ErrorSummaryList {
pub fn render(reports: &[DiagnosticReport]) {
if reports.is_empty() {
println!("No errors found in the provided batch.");
return;
}

// Group by category, name, and severity
let mut grouped: HashMap<(String, String, String), (usize, String)> = HashMap::new();

for report in reports {
let sev_str = match report.severity {
Severity::Fatal => "Fatal",
Severity::Error => "Error",
Severity::Warning => "Warning",
Severity::Info => "Info",
}
.to_string();

let key = (
report.error_category.clone(),
report.error_name.clone(),
sev_str,
);
let entry = grouped.entry(key).or_insert((0, report.summary.clone()));
entry.0 += 1;
}

let mut rows: Vec<ErrorSummaryRow> = grouped
.into_iter()
.map(|((category, name, severity), (count, message))| {
let sev_str = match severity.as_str() {
"Fatal" => "FATAL".red().bold().to_string(),
"Error" => "ERROR".red().to_string(),
"Warning" => "WARN".yellow().to_string(),
"Info" => "INFO".blue().to_string(),
_ => severity,
};

ErrorSummaryRow {
severity: sev_str,
category,
name,
count,
message,
}
})
.collect();

// Sort by severity (Fatal > Error > Warning > Info) then count descending
rows.sort_by(|a, b| {
let sev_a = severity_weight(&a.severity);
let sev_b = severity_weight(&b.severity);
sev_b.cmp(&sev_a).then(b.count.cmp(&a.count))
});

let mut table = Table::new(rows);
table.with(Style::rounded());

println!("\n=== Batch Decoding Summary ===");
println!("{}", table);
}
}

fn severity_weight(sev_str: &str) -> u8 {
if sev_str.contains("FATAL") {
4
} else if sev_str.contains("ERROR") {
3
} else if sev_str.contains("WARN") {
2
} else {
1
}
}
1 change: 1 addition & 0 deletions crates/cli/src/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod error_summary;
pub mod markdown;
Loading