1use anyhow::Result;
2use comfy_table::presets::NOTHING;
3use comfy_table::{Cell, Color, Table};
4use std::path::Path;
5
6use crate::color::{cell_bold, cell_fg, stdout_use_color};
7use crate::db;
8
9pub fn run(root: &Path, json: bool) -> Result<()> {
10 let conn = db::open(root)?;
11
12 let mut stmt = conn.prepare(
13 "SELECT id, title, description, type, priority, status, effort, parent, created, updated
14 FROM tasks
15 WHERE status = 'open'
16 AND id NOT IN (
17 SELECT b.task_id FROM blockers b
18 JOIN tasks t ON b.blocker_id = t.id
19 WHERE t.status != 'closed'
20 )
21 ORDER BY priority, created",
22 )?;
23
24 let tasks: Vec<db::Task> = stmt
25 .query_map([], db::row_to_task)?
26 .collect::<rusqlite::Result<_>>()?;
27
28 if json {
29 let summary: Vec<serde_json::Value> = tasks
30 .iter()
31 .map(|t| {
32 serde_json::json!({
33 "id": t.id,
34 "title": t.title,
35 "priority": db::priority_label(t.priority),
36 "effort": db::effort_label(t.effort),
37 })
38 })
39 .collect();
40 println!("{}", serde_json::to_string(&summary)?);
41 } else {
42 let use_color = stdout_use_color();
43 let mut table = Table::new();
44 table.load_preset(NOTHING);
45 table.set_header(vec!["ID", "PRIORITY", "EFFORT", "TITLE"]);
46 for t in &tasks {
47 table.add_row(vec![
48 cell_bold(&t.id, use_color),
49 cell_fg(db::priority_label(t.priority), Color::Red, use_color),
50 cell_fg(db::effort_label(t.effort), Color::Blue, use_color),
51 Cell::new(&t.title),
52 ]);
53 }
54 if !tasks.is_empty() {
55 println!("{table}");
56 }
57 }
58
59 Ok(())
60}