1use super::Command;
2use crate::context::AppContext;
3use crate::repo_utils::find_repository_root;
4use crate::task::TaskStatus;
5use crate::task_storage::get_task_storage;
6use async_trait::async_trait;
7use std::error::Error;
8use std::path::Path;
9use tabled::settings::Style;
10use tabled::{Table, Tabled};
11
12pub struct ListCommand;
13
14#[derive(Tabled)]
15struct TaskRow {
16 #[tabled(rename = "ID")]
17 id: String,
18 #[tabled(rename = "Name")]
19 name: String,
20 #[tabled(rename = "Type")]
21 task_type: String,
22 #[tabled(rename = "Status")]
23 status: String,
24 #[tabled(rename = "Agent")]
25 agent: String,
26 #[tabled(rename = "Created")]
27 created: String,
28}
29
30#[async_trait]
31impl Command for ListCommand {
32 async fn execute(&self, ctx: &AppContext) -> Result<(), Box<dyn Error>> {
33 let _repo_root = find_repository_root(Path::new("."))?;
34
35 let client = ctx.tsk_client();
37 let tasks = if client.is_server_available().await {
38 match client.list_tasks().await {
39 Ok(tasks) => tasks,
40 Err(_) => {
41 eprintln!("Failed to list tasks via server");
42 eprintln!("Falling back to direct file read...");
43
44 let storage = get_task_storage(ctx.xdg_directories(), ctx.file_system());
46 storage
47 .list_tasks()
48 .await
49 .map_err(|e| e as Box<dyn Error>)?
50 }
51 }
52 } else {
53 let storage = get_task_storage(ctx.xdg_directories(), ctx.file_system());
55 storage
56 .list_tasks()
57 .await
58 .map_err(|e| e as Box<dyn Error>)?
59 };
60
61 if tasks.is_empty() {
62 println!("No tasks in queue");
63 } else {
64 let rows: Vec<TaskRow> = tasks
65 .iter()
66 .map(|task| TaskRow {
67 id: task.id.clone(),
68 name: task.name.clone(),
69 task_type: task.task_type.clone(),
70 status: match &task.status {
71 TaskStatus::Queued => "QUEUED".to_string(),
72 TaskStatus::Running => "RUNNING".to_string(),
73 TaskStatus::Failed => "FAILED".to_string(),
74 TaskStatus::Complete => "COMPLETE".to_string(),
75 },
76 agent: task.agent.clone(),
77 created: task.created_at.format("%Y-%m-%d %H:%M").to_string(),
78 })
79 .collect();
80
81 let table = Table::new(rows).with(Style::modern()).to_string();
82 println!("{table}");
83
84 let queued = tasks
86 .iter()
87 .filter(|t| t.status == TaskStatus::Queued)
88 .count();
89 let running = tasks
90 .iter()
91 .filter(|t| t.status == TaskStatus::Running)
92 .count();
93 let complete = tasks
94 .iter()
95 .filter(|t| t.status == TaskStatus::Complete)
96 .count();
97 let failed = tasks
98 .iter()
99 .filter(|t| t.status == TaskStatus::Failed)
100 .count();
101
102 println!(
103 "\nSummary: {queued} queued, {running} running, {complete} complete, {failed} failed"
104 );
105 }
106
107 Ok(())
108 }
109}