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,
10 common::ICONS,
11 ui::{render_element_to_string, views::area::AreaView},
12 wire::task::TaskStatus,
13};
14
15#[derive(Debug, Args)]
16#[command(about = "Show projects and tasks in an area")]
17pub struct AreaArgs {
18 pub area_id: String,
20 #[arg(long)]
22 pub detailed: bool,
23 #[arg(long)]
25 pub all: bool,
26}
27
28impl Command for AreaArgs {
29 fn run_with_ctx(
30 &self,
31 cli: &Cli,
32 out: &mut dyn std::io::Write,
33 ctx: &mut dyn crate::cmd_ctx::CmdCtx,
34 ) -> Result<()> {
35 let store = Arc::new(cli.load_store()?);
36 let today = ctx.today();
37 let (area_opt, err, ambiguous) = store.resolve_area_identifier(&self.area_id);
38 let Some(area) = area_opt else {
39 eprintln!("{err}");
40 for match_area in ambiguous {
41 eprintln!(
42 " {} {} ({})",
43 ICONS.area, match_area.title, match_area.uuid
44 );
45 }
46 return Ok(());
47 };
48
49 let status_filter = if self.all {
50 None
51 } else {
52 Some(TaskStatus::Incomplete)
53 };
54 let mut projects = store
55 .projects(status_filter)
56 .into_iter()
57 .filter(|p| p.area.as_ref() == Some(&area.uuid))
58 .collect::<Vec<_>>();
59 projects.sort_by_key(|p| p.index);
60
61 let mut loose_tasks = store
62 .tasks(status_filter, Some(false), None)
63 .into_iter()
64 .filter(|t| {
65 t.area.as_ref() == Some(&area.uuid)
66 && !t.is_project()
67 && store.effective_project_uuid(t).is_none()
68 })
69 .collect::<Vec<_>>();
70 loose_tasks.sort_by_key(|t| t.index);
71
72 let mut ui = element! {
73 ContextProvider(value: Context::owned(store.clone())) {
74 ContextProvider(value: Context::owned(today)) {
75 AreaView(
76 area: &area,
77 tasks: loose_tasks.iter().collect::<Vec<_>>(),
78 projects: projects.iter().collect::<Vec<_>>(),
79 detailed: self.detailed,
80 )
81 }
82 }
83 };
84 let rendered = render_element_to_string(&mut ui, cli.no_color);
85 writeln!(out, "{}", rendered)?;
86
87 Ok(())
88 }
89}