things3_cloud/commands/
area.rs1use std::sync::Arc;
2
3use anyhow::Result;
4use clap::Args;
5use iocraft::prelude::*;
6
7use crate::{
8 app::Cli,
9 commands::{Command, detailed_json_conflict, write_json},
10 common::ICONS,
11 ui::{
12 render_element_to_string,
13 views::{area::AreaView, json::common::build_tasks_json},
14 },
15 wire::task::TaskStatus,
16};
17
18#[derive(Debug, Args)]
19#[command(about = "Show projects and tasks in an area")]
20pub struct AreaArgs {
21 pub area_id: String,
23 #[arg(long, short = 'd')]
25 pub detailed: bool,
26 #[arg(long, short = 'a')]
28 pub all: bool,
29}
30
31impl Command for AreaArgs {
32 fn run_with_ctx(
33 &self,
34 cli: &Cli,
35 out: &mut dyn std::io::Write,
36 ctx: &mut dyn crate::cmd_ctx::CmdCtx,
37 ) -> Result<()> {
38 let store = Arc::new(cli.load_store()?);
39 let today = ctx.today();
40 let (area_opt, err, ambiguous) = store.resolve_area_identifier(&self.area_id);
41 let Some(area) = area_opt else {
42 eprintln!("{err}");
43 for match_area in ambiguous {
44 eprintln!(
45 " {} {} ({})",
46 ICONS.area, match_area.title, match_area.uuid
47 );
48 }
49 return Ok(());
50 };
51
52 let status_filter = if self.all {
53 None
54 } else {
55 Some(TaskStatus::Incomplete)
56 };
57 let mut projects = store
58 .projects(status_filter)
59 .into_iter()
60 .filter(|p| p.area.as_ref() == Some(&area.uuid))
61 .collect::<Vec<_>>();
62 projects.sort_by_key(|p| p.index);
63
64 let mut loose_tasks = store
65 .tasks(status_filter, Some(false), None)
66 .into_iter()
67 .filter(|t| {
68 t.area.as_ref() == Some(&area.uuid)
69 && !t.is_project()
70 && store.effective_project_uuid(t).is_none()
71 })
72 .collect::<Vec<_>>();
73 loose_tasks.sort_by_key(|t| t.index);
74
75 let json = cli.json;
76 if json {
77 if detailed_json_conflict(json, self.detailed) {
78 return Ok(());
79 }
80
81 let mut items = projects;
82 items.extend(loose_tasks);
83 items.sort_by(|a, b| {
84 let a_proj = if a.is_project() { 0 } else { 1 };
85 let b_proj = if b.is_project() { 0 } else { 1 };
86 (a_proj, a.index, &a.uuid).cmp(&(b_proj, b.index, &b.uuid))
87 });
88 write_json(out, &build_tasks_json(&items, &store, &today))?;
89 return Ok(());
90 }
91
92 let mut ui = element! {
93 ContextProvider(value: Context::owned(store.clone())) {
94 ContextProvider(value: Context::owned(today)) {
95 AreaView(
96 area: &area,
97 tasks: loose_tasks.iter().collect::<Vec<_>>(),
98 projects: projects.iter().collect::<Vec<_>>(),
99 detailed: self.detailed,
100 )
101 }
102 }
103 };
104 let rendered = render_element_to_string(&mut ui, cli.no_color);
105 writeln!(out, "{}", rendered)?;
106
107 Ok(())
108 }
109}