minor documentation edits; storing completed date; ordering for tracked stats and bug fixed

This commit is contained in:
aaron-jack-manning 2022-08-25 08:30:52 +10:00
parent 8fc2b9abd9
commit fef199cd52
5 changed files with 15 additions and 19 deletions

2
Cargo.lock generated
View File

@ -825,7 +825,7 @@ dependencies = [
[[package]] [[package]]
name = "toru" name = "toru"
version = "0.1.2" version = "0.1.3"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",

View File

@ -95,10 +95,6 @@ Then you can run `toru new` to create your first task.
- Error if any circular dependencies are introduced - Error if any circular dependencies are introduced
- Make sure dependencies written to file are only those that could be successfully created - Make sure dependencies written to file are only those that could be successfully created
- List dependencies as a tree on note view below info - List dependencies as a tree on note view below info
- Completed Date
- Keep track of completed date, and correctly update upon marking as complete or manual edit
- Disallow removing it in a manual edit unless complete is also marked to false
- Add to statistics
- Statistics - Statistics
- Completed tasks over last x days - Completed tasks over last x days
- Improve formatting to terminal to make easier to read for `tracked` command - Improve formatting to terminal to make easier to read for `tracked` command

View File

@ -41,7 +41,7 @@ enum Command {
View { View {
id_or_name : String, id_or_name : String,
}, },
/// Edit a note directly. /// Edit a task directly.
Edit { Edit {
id_or_name : String, id_or_name : String,
/// Edit the info specifically in its own file. /// Edit the info specifically in its own file.
@ -83,7 +83,7 @@ enum Command {
// - which columns to include // - which columns to include
// - filters which exclude values // - filters which exclude values
}, },
/// For tracking time against a note. /// For tracking time against a task.
Track { Track {
id_or_name : String, id_or_name : String,
#[clap(short='H', default_value_t=0)] #[clap(short='H', default_value_t=0)]
@ -294,7 +294,7 @@ fn program() -> Result<(), error::Error> {
Complete { id_or_name } => { Complete { id_or_name } => {
let id = state.name_or_id_to_id(&id_or_name)?; let id = state.name_or_id_to_id(&id_or_name)?;
let mut task = tasks::Task::load(id, vault_folder, false)?; let mut task = tasks::Task::load(id, vault_folder, false)?;
task.data.complete = true; task.data.completed = Some(chrono::Local::now().naive_local());
task.save()?; task.save()?;
println!("Marked task {} as complete", colour::id(&id.to_string())); println!("Marked task {} as complete", colour::id(&id.to_string()));
}, },

View File

@ -2,13 +2,13 @@ use crate::tasks;
use crate::error; use crate::error;
use std::path; use std::path;
use std::collections::HashMap; use std::collections::BTreeMap;
pub fn time_per_tag(days : u16, vault_folder : &path::Path) -> Result<(), error::Error> { pub fn time_per_tag(days : u16, vault_folder : &path::Path) -> Result<(), error::Error> {
let tasks = tasks::Task::load_all(vault_folder, true)?; let tasks = tasks::Task::load_all(vault_folder, true)?;
let mut times = HashMap::<String, tasks::Duration>::new(); let mut times = BTreeMap::<String, tasks::Duration>::new();
for task in &tasks { for task in &tasks {
if !task.data.discarded { if !task.data.discarded {
@ -29,7 +29,7 @@ pub fn time_per_tag(days : u16, vault_folder : &path::Path) -> Result<(), error:
*time = *time + time_per_tag; *time = *time + time_per_tag;
}, },
None => { None => {
times.insert(tag.clone(), time); times.insert(tag.clone(), time_per_tag);
} }
} }
} }
@ -43,8 +43,8 @@ pub fn time_per_tag(days : u16, vault_folder : &path::Path) -> Result<(), error:
.set_content_arrangement(comfy_table::ContentArrangement::Dynamic); .set_content_arrangement(comfy_table::ContentArrangement::Dynamic);
table.set_header(vec!["Tag", "Time"]); table.set_header(vec!["Tag", "Time"]);
for (tag, duration) in &times {
for (tag, duration) in times {
table.add_row( table.add_row(
vec![ vec![
tag.clone(), tag.clone(),

View File

@ -76,7 +76,7 @@ pub struct InternalTask {
pub priority : Priority, pub priority : Priority,
pub due : Option<chrono::NaiveDateTime>, pub due : Option<chrono::NaiveDateTime>,
pub created : chrono::NaiveDateTime, pub created : chrono::NaiveDateTime,
pub complete : bool, pub completed : Option<chrono::NaiveDateTime>,
pub discarded : bool, pub discarded : bool,
pub info : Option<String>, pub info : Option<String>,
pub time_entries : Vec<TimeEntry>, pub time_entries : Vec<TimeEntry>,
@ -109,7 +109,7 @@ impl Task {
due, due,
time_entries : Vec::new(), time_entries : Vec::new(),
created : chrono::Local::now().naive_local(), created : chrono::Local::now().naive_local(),
complete : false, completed : None,
discarded : false, discarded : false,
}; };
@ -235,7 +235,7 @@ impl Task {
let discarded = if self.data.discarded { String::from(" (discarded)") } else { String::new() }; let discarded = if self.data.discarded { String::from(" (discarded)") } else { String::new() };
( (
format!("[{}] {} {}{}", if self.data.complete {"X"} else {" "}, colour::id(id), colour::task_name(&self.data.name), colour::greyed_out(&discarded)), format!("[{}] {} {}{}", if self.data.completed.is_some() {"X"} else {" "}, colour::id(id), colour::task_name(&self.data.name), colour::greyed_out(&discarded)),
5 + self.data.name.chars().count() + id.chars().count() + discarded.chars().count() 5 + self.data.name.chars().count() + id.chars().count() + discarded.chars().count()
) )
}; };
@ -248,7 +248,7 @@ impl Task {
println!("Created: {}", self.data.created.round_subsecs(0)); println!("Created: {}", self.data.created.round_subsecs(0));
if let Some(due) = self.data.due { if let Some(due) = self.data.due {
let due = format_due_date(&due, !self.data.complete, true); let due = format_due_date(&due, self.data.completed.is_none(), true);
println!("Due: {}", due); println!("Due: {}", due);
} }
@ -373,7 +373,7 @@ pub fn list(vault_folder : &path::Path) -> Result<(), error::Error> {
tasks.sort_by(|t1, t2| t2.data.priority.cmp(&t1.data.priority)); tasks.sort_by(|t1, t2| t2.data.priority.cmp(&t1.data.priority));
for task in tasks { for task in tasks {
if !task.data.discarded && !task.data.complete { if !task.data.discarded && task.data.completed.is_none() {
let duration = TimeEntry::total(&task.data.time_entries); let duration = TimeEntry::total(&task.data.time_entries);
@ -384,7 +384,7 @@ pub fn list(vault_folder : &path::Path) -> Result<(), error::Error> {
format_hash_set(&task.data.tags)?, format_hash_set(&task.data.tags)?,
task.data.priority.to_string(), task.data.priority.to_string(),
if duration == Duration::zero() { String::new() } else { duration.to_string() }, if duration == Duration::zero() { String::new() } else { duration.to_string() },
match task.data.due { Some(due) => format_due_date(&due, !task.data.complete, false), None => String::new() }, match task.data.due { Some(due) => format_due_date(&due, task.data.completed.is_none(), false), None => String::new() },
] ]
); );
} }
@ -435,7 +435,7 @@ impl ops::Div<usize> for Duration {
fn div(self, divisor : usize) -> Self::Output { fn div(self, divisor : usize) -> Self::Output {
let total_mins = f64::from(self.hours * 60 + self.minutes); let total_mins = f64::from(self.hours * 60 + self.minutes);
let divided_mins = total_mins / divisor as f64; let divided_mins = total_mins / (divisor as f64);
let divided_mins = divided_mins.round() as u16; let divided_mins = divided_mins.round() as u16;
Self { Self {