feat(tasks): display details on task without subtasks

This commit is contained in:
xeruf 2024-08-19 17:30:05 +03:00
parent 12b7c909ab
commit 3b9fedd9a3
2 changed files with 26 additions and 17 deletions

View File

@ -456,12 +456,12 @@ async fn main() {
Some('(') => { Some('(') => {
if let Some(arg) = arg { if let Some(arg) = arg {
if tasks.track_from(arg) { if tasks.track_from(arg) {
let (prefix, tracked) = tasks.times_tracked(); let (label, times) = tasks.times_tracked();
println!("{}\n{}", prefix.bold(), tracked.rev().take(15).join("\n")); println!("{}\n{}", label.italic(), times.rev().take(15).join("\n"));
} }
} else { } else {
let (prefix, mut tracked) = tasks.times_tracked(); let (label, mut times) = tasks.times_tracked();
println!("{}\n{}", prefix.bold(), tracked.join("\n")); println!("{}\n{}", label.italic(), times.join("\n"));
} }
continue; continue;
} }

View File

@ -37,7 +37,6 @@ pub(crate) struct Tasks {
/// A filtered view of the current tasks /// A filtered view of the current tasks
view: Vec<EventId>, view: Vec<EventId>,
/// Negative: Only Leaf nodes
/// Zero: Only Active node /// Zero: Only Active node
/// Positive: Go down the respective level /// Positive: Go down the respective level
depth: i8, depth: i8,
@ -187,10 +186,11 @@ impl Tasks {
.map(|str| EventId::from_str(str).ok().map_or(str.to_string(), |id| self.get_task_title(&id))) .map(|str| EventId::from_str(str).ok().map_or(str.to_string(), |id| self.get_task_title(&id)))
.join(" ")); .join(" "));
if new.as_ref() != full.last() { if new.as_ref() != full.last() {
// TODO alternating color for days
full.push(format!("{:>15} {}", relative_datetimestamp(&event.created_at), new.as_ref().unwrap_or(&"---".to_string()))); full.push(format!("{:>15} {}", relative_datetimestamp(&event.created_at), new.as_ref().unwrap_or(&"---".to_string())));
} }
} }
("Your Time Tracking History:".to_string(), Box::from(full.into_iter())) ("Your Time-Tracking History:".to_string(), Box::from(full.into_iter()))
} else { } else {
("You have nothing tracked yet".to_string(), Box::from(empty())) ("You have nothing tracked yet".to_string(), Box::from(empty()))
} }
@ -217,14 +217,14 @@ impl Tasks {
vec.push(format!("{} started by {}", local_datetimestamp(stamp), key))); vec.push(format!("{} started by {}", local_datetimestamp(stamp), key)));
vec vec
}).sorted_unstable(); // TODO sorting depends on timestamp format - needed to interleave different people }).sorted_unstable(); // TODO sorting depends on timestamp format - needed to interleave different people
(format!("Times tracked on {}", self.get_task_title(&id)), Box::from(history)) (format!("Times Tracked on {:?}", self.get_task_title(&id)), Box::from(history))
} }
} }
} }
/// Total time in seconds tracked on this task by the current user. /// Total time in seconds tracked on this task by the current user.
pub(crate) fn time_tracked(&self, id: EventId) -> u64 { pub(crate) fn time_tracked(&self, id: EventId) -> u64 {
TimesTracked::from(self.history.get(&self.sender.pubkey()).into_iter().flatten(), &vec![&id]).sum::<Duration>().as_secs() Durations::from(self.history.get(&self.sender.pubkey()).into_iter().flatten(), &vec![&id]).sum::<Duration>().as_secs()
} }
@ -234,7 +234,7 @@ impl Tasks {
let children = self.get_task_tree(&id).get_all(); let children = self.get_task_tree(&id).get_all();
for user in self.history.values() { for user in self.history.values() {
total += TimesTracked::from(user, &children).into_iter().sum::<Duration>().as_secs(); total += Durations::from(user, &children).sum::<Duration>().as_secs();
} }
total total
} }
@ -381,7 +381,7 @@ impl Tasks {
pub(crate) fn visible_tasks(&self) -> Vec<&Task> { pub(crate) fn visible_tasks(&self) -> Vec<&Task> {
if self.depth == 0 { if self.depth == 0 {
return self.get_current_task().into_iter().collect(); return vec![];
} }
if self.view.len() > 0 { if self.view.len() > 0 {
return self.resolve_tasks(self.view.iter()).collect(); return self.resolve_tasks(self.view.iter()).collect();
@ -413,11 +413,21 @@ impl Tasks {
)?; )?;
writeln!(lock, "{}", t.descriptions().join("\n"))?; writeln!(lock, "{}", t.descriptions().join("\n"))?;
} }
let mut tasks = self.visible_tasks();
if tasks.is_empty() {
let (label, times) = self.times_tracked();
let mut times_recent = times.rev().take(6).collect_vec();
times_recent.reverse();
// TODO Add recent prefix
writeln!(lock, "{}\n{}", label.italic(), times_recent.join("\n"))?;
return Ok(());
}
// TODO proper column alignment // TODO proper column alignment
// TODO hide empty columns // TODO hide empty columns
writeln!(lock, "{}", self.properties.join("\t").bold())?; writeln!(lock, "{}", self.properties.join("\t").bold())?;
let mut total_time = 0; let mut total_time = 0;
let mut tasks = self.visible_tasks();
let count = tasks.len(); let count = tasks.len();
tasks.sort_by_cached_key(|task| { tasks.sort_by_cached_key(|task| {
self.sorting self.sorting
@ -951,22 +961,21 @@ fn timestamps<'a>(events: impl Iterator<Item=&'a Event>, ids: &'a Vec<&'a EventI
/// Iterates Events to accumulate times tracked /// Iterates Events to accumulate times tracked
/// Expects a sorted iterator /// Expects a sorted iterator
struct TimesTracked<'a> { struct Durations<'a> {
events: Box<dyn Iterator<Item=&'a Event> + 'a>, events: Box<dyn Iterator<Item=&'a Event> + 'a>,
ids: &'a Vec<&'a EventId>, ids: &'a Vec<&'a EventId>,
threshold: Option<Timestamp>, threshold: Option<Timestamp>,
} }
impl TimesTracked<'_> { impl Durations<'_> {
fn from<'b>(events: impl IntoIterator<Item=&'b Event> + 'b, ids: &'b Vec<&EventId>) -> TimesTracked<'b> { fn from<'b>(events: impl IntoIterator<Item=&'b Event> + 'b, ids: &'b Vec<&EventId>) -> Durations<'b> {
TimesTracked { Durations {
events: Box::new(events.into_iter()), events: Box::new(events.into_iter()),
ids, ids,
threshold: Some(Timestamp::now()), threshold: Some(Timestamp::now()),
} }
} }
} }
impl Iterator for Durations<'_> {
impl Iterator for TimesTracked<'_> {
type Item = Duration; type Item = Duration;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {