forked from janek/mostr
feat(tasks): display details on task without subtasks
This commit is contained in:
parent
12b7c909ab
commit
3b9fedd9a3
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
35
src/tasks.rs
35
src/tasks.rs
|
@ -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> {
|
||||||
|
|
Loading…
Reference in New Issue