فهرست منبع

bin/tau: create log drawdown and rework taud to get stopped tasks as well

Dastan-glitch 4 سال پیش
والد
کامیت
636d4b5c72

+ 23 - 0
Cargo.lock

@@ -736,6 +736,17 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
 checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
 
 
+[[package]]
+name = "colored"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
+dependencies = [
+ "atty",
+ "lazy_static",
+ "winapi",
+]
+
 [[package]]
 [[package]]
 name = "concurrent-queue"
 name = "concurrent-queue"
 version = "1.2.4"
 version = "1.2.4"
@@ -3973,12 +3984,15 @@ dependencies = [
  "async-std",
  "async-std",
  "chrono",
  "chrono",
  "clap 3.2.16",
  "clap 3.2.16",
+ "colored",
  "darkfi",
  "darkfi",
+ "fxhash",
  "log",
  "log",
  "prettytable-rs",
  "prettytable-rs",
  "serde",
  "serde",
  "serde_json",
  "serde_json",
  "simplelog",
  "simplelog",
+ "term_grid",
  "url",
  "url",
 ]
 ]
 
 
@@ -4037,6 +4051,15 @@ dependencies = [
  "winapi",
  "winapi",
 ]
 ]
 
 
+[[package]]
+name = "term_grid"
+version = "0.2.0"
+source = "git+https://github.com/Dastan-glitch/rust-term-grid.git#51c28e47aad0fb9f67de558e9b80c525cd01a4ae"
+dependencies = [
+ "colored",
+ "unicode-width",
+]
+
 [[package]]
 [[package]]
 name = "termcolor"
 name = "termcolor"
 version = "1.1.3"
 version = "1.1.3"

+ 3 - 0
bin/tau/tau-cli/Cargo.toml

@@ -14,10 +14,13 @@ categories = ["command-line-utilities"]
 async-std = {version = "1.12.0", features = ["attributes"]}
 async-std = {version = "1.12.0", features = ["attributes"]}
 chrono = "0.4.19"
 chrono = "0.4.19"
 clap = {version = "3.2.16", features = ["derive"]}
 clap = {version = "3.2.16", features = ["derive"]}
+colored = "2.0.0"
 darkfi = { path = "../../../", features = ["rpc"]}
 darkfi = { path = "../../../", features = ["rpc"]}
+fxhash = "0.2.1"
 log = "0.4.17"
 log = "0.4.17"
 prettytable-rs = "0.8.0"
 prettytable-rs = "0.8.0"
 serde = {version = "1.0.142", features = ["derive"]}
 serde = {version = "1.0.142", features = ["derive"]}
 serde_json = "1.0.83"
 serde_json = "1.0.83"
 simplelog = "0.12.0"
 simplelog = "0.12.0"
+term_grid = { git = "https://github.com/Dastan-glitch/rust-term-grid.git" }
 url = "2.2.2"
 url = "2.2.2"

+ 132 - 0
bin/tau/tau-cli/src/drawdown.rs

@@ -0,0 +1,132 @@
+use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, Utc};
+use colored::Colorize;
+use fxhash::FxHashMap;
+use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
+
+use darkfi::{Error, Result};
+
+use crate::primitives::{TaskEvent, TaskInfo};
+
+pub fn drawdown(date: String, tasks: Vec<TaskInfo>, owner: String) -> Result<()> {
+    let mut ret = FxHashMap::default();
+    let all_owners = owners(tasks.clone());
+
+    for owner in all_owners {
+        let stopped_tasks = tasks
+            .clone()
+            .into_iter()
+            .filter(|t| {
+                t.events.last().unwrap_or(&TaskEvent::default()).action.clone() == "stop" &&
+                    t.owner == owner
+            })
+            .collect::<Vec<TaskInfo>>();
+        ret.insert(owner, stopped_tasks);
+    }
+
+    let mut naivedate = to_naivedate(date.clone())?;
+
+    println!("log drawdown for {} in {}", owner, naivedate.format("%b %Y").to_string());
+
+    let fdow = if naivedate.month() == 2 && !is_leap_year(naivedate.year()) {
+        ["   ", "1 ", "8 ", "15", "22", " "]
+    } else {
+        ["   ", "1 ", "8 ", "15", "22", "29"]
+    };
+
+    // Print first day of each week horizontally.
+    let mut dow_grid =
+        Grid::new(GridOptions { direction: Direction::LeftToRight, filling: Filling::Spaces(1) });
+    if ret.contains_key(&owner) {
+        for i in fdow {
+            let cell = Cell::from(i);
+            dow_grid.add(cell)
+        }
+        let grid_display = dow_grid.fit_into_rows(1);
+        print!("{}", grid_display);
+    }
+
+    let mut grid =
+        Grid::new(GridOptions { direction: Direction::TopToBottom, filling: Filling::Spaces(1) });
+
+    let days_in_month = get_days_from_month(date) as u32;
+
+    if ret.contains_key(&owner) {
+        for _ in 0..7 {
+            let dow = naivedate.weekday().to_string();
+            let wcell = Cell::from(dow);
+            grid.add(wcell);
+            naivedate = naivedate + Duration::days(1);
+        }
+        for day in 1..=days_in_month {
+            let owner_stopped_tasks = ret.get(&owner).unwrap().to_owned();
+            let date_tasks: Vec<TaskInfo> = owner_stopped_tasks
+                .into_iter()
+                .filter(|t| {
+                    let event_date = NaiveDateTime::from_timestamp(
+                        t.events.last().unwrap_or(&TaskEvent::default()).timestamp.0,
+                        0,
+                    );
+                    event_date.day() == day
+                })
+                .collect();
+
+            let red_scale = if date_tasks.is_empty() {
+                50
+            } else {
+                ((date_tasks.len() * 25) + 90).clamp(90, 255) as u8
+            };
+
+            let cell = Cell::from("▀▀".truecolor(red_scale, 40, 50));
+            grid.add(cell)
+        }
+    }
+
+    let grid_display = grid.fit_into_rows(7);
+    println!("{}", grid_display);
+
+    Ok(())
+}
+
+fn is_leap_year(year: i32) -> bool {
+    return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
+}
+
+pub fn to_naivedate(date: String) -> Result<NaiveDate> {
+    if date.len() != 4 || date.parse::<u32>().is_err() {
+        return Err(Error::MalformedPacket)
+    }
+    let (month, year) = (date[..2].parse::<u32>().unwrap(), date[2..].parse::<i32>().unwrap());
+    let year = year + (Utc::today().year() / 100) * 100;
+
+    Ok(NaiveDate::from_ymd(year, month, 1))
+}
+
+fn get_days_from_month(date: String) -> i64 {
+    let (month, year) = (date[..2].parse::<u32>().unwrap(), date[2..].parse::<i32>().unwrap());
+    let year = year + (Utc::today().year() / 100) * 100;
+
+    NaiveDate::from_ymd(
+        match month {
+            12 => year + 1,
+            _ => year,
+        },
+        match month {
+            12 => 1,
+            _ => month + 1,
+        },
+        1,
+    )
+    .signed_duration_since(NaiveDate::from_ymd(year, month, 1))
+    .num_days()
+}
+
+fn owners(tasks: Vec<TaskInfo>) -> Vec<String> {
+    let mut owners = vec![];
+    for task in tasks {
+        if !owners.contains(&task.owner) {
+            owners.push(task.owner)
+        }
+    }
+
+    owners
+}

+ 14 - 0
bin/tau/tau-cli/src/main.rs

@@ -11,12 +11,14 @@ use darkfi::{
     Result,
     Result,
 };
 };
 
 
+mod drawdown;
 mod filter;
 mod filter;
 mod primitives;
 mod primitives;
 mod rpc;
 mod rpc;
 mod util;
 mod util;
 mod view;
 mod view;
 
 
+use drawdown::{drawdown, to_naivedate};
 use primitives::{task_from_cli, State, TaskEvent};
 use primitives::{task_from_cli, State, TaskEvent};
 use util::{desc_in_editor, due_as_timestamp};
 use util::{desc_in_editor, due_as_timestamp};
 use view::{comments_as_string, print_task_info, print_task_list};
 use view::{comments_as_string, print_task_info, print_task_list};
@@ -84,6 +86,9 @@ enum TauSubcommand {
 
 
     /// Export tasks to a specified directory.
     /// Export tasks to a specified directory.
     Export { path: Option<String> },
     Export { path: Option<String> },
+
+    /// Drawdown.
+    Log { month: String, owner: String },
 }
 }
 
 
 pub struct Tau {
 pub struct Tau {
@@ -174,6 +179,7 @@ async fn main() -> Result<()> {
 
 
                 Ok(())
                 Ok(())
             }
             }
+
             TauSubcommand::Import { path } => {
             TauSubcommand::Import { path } => {
                 let path = path.unwrap_or(DEFAULT_PATH.into());
                 let path = path.unwrap_or(DEFAULT_PATH.into());
                 let res = tau.import_from(path.clone()).await?;
                 let res = tau.import_from(path.clone()).await?;
@@ -186,6 +192,14 @@ async fn main() -> Result<()> {
 
 
                 Ok(())
                 Ok(())
             }
             }
+
+            TauSubcommand::Log { month, owner } => {
+                let ts = to_naivedate(month.clone())?.and_hms(12, 0, 0).timestamp();
+                let tasks = tau.get_stop_tasks(ts).await?;
+                drawdown(month, tasks, owner)?;
+
+                Ok(())
+            }
         },
         },
         None => {
         None => {
             let task_ids = tau.get_ids().await?;
             let task_ids = tau.get_ids().await?;

+ 3 - 3
bin/tau/tau-cli/src/primitives.rs

@@ -56,7 +56,7 @@ pub struct BaseTask {
     pub rank: Option<f32>,
     pub rank: Option<f32>,
 }
 }
 
 
-#[derive(serde::Serialize, serde::Deserialize, Debug)]
+#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
 pub struct TaskInfo {
 pub struct TaskInfo {
     pub ref_id: String,
     pub ref_id: String,
     pub workspace: String,
     pub workspace: String,
@@ -73,7 +73,7 @@ pub struct TaskInfo {
     pub comments: Vec<Comment>,
     pub comments: Vec<Comment>,
 }
 }
 
 
-#[derive(serde::Serialize, serde::Deserialize, Debug)]
+#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
 pub struct TaskEvent {
 pub struct TaskEvent {
     pub action: String,
     pub action: String,
     pub timestamp: Timestamp,
     pub timestamp: Timestamp,
@@ -91,7 +91,7 @@ impl Default for TaskEvent {
     }
     }
 }
 }
 
 
-#[derive(serde::Serialize, serde::Deserialize, Debug)]
+#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
 pub struct Comment {
 pub struct Comment {
     content: String,
     content: String,
     author: String,
     author: String,

+ 9 - 1
bin/tau/tau-cli/src/rpc.rs

@@ -22,7 +22,7 @@ impl Tau {
         Ok(())
         Ok(())
     }
     }
 
 
-    /// Get all task ids.
+    /// Get current open tasks ids.
     pub async fn get_ids(&self) -> Result<Vec<u64>> {
     pub async fn get_ids(&self) -> Result<Vec<u64>> {
         let req = JsonRequest::new("get_ids", json!([]));
         let req = JsonRequest::new("get_ids", json!([]));
         let rep = self.rpc_client.request(req).await?;
         let rep = self.rpc_client.request(req).await?;
@@ -70,6 +70,14 @@ impl Tau {
         Ok(serde_json::from_value(rep)?)
         Ok(serde_json::from_value(rep)?)
     }
     }
 
 
+    /// Get month's stopped tasks.
+    pub async fn get_stop_tasks(&self, month: i64) -> Result<Vec<TaskInfo>> {
+        let req = JsonRequest::new("get_stop_tasks", json!([month]));
+        let rep = self.rpc_client.request(req).await?;
+
+        Ok(serde_json::from_value(rep)?)
+    }
+
     /// Switch workspace.
     /// Switch workspace.
     pub async fn switch_ws(&self, workspace: String) -> Result<()> {
     pub async fn switch_ws(&self, workspace: String) -> Result<()> {
         let req = JsonRequest::new("switch_ws", json!([workspace]));
         let req = JsonRequest::new("switch_ws", json!([workspace]));

+ 31 - 6
bin/tau/taud/src/jsonrpc.rs

@@ -60,6 +60,7 @@ impl RequestHandler for JsonRpcInterface {
             Some("switch_ws") => self.switch_ws(params).await,
             Some("switch_ws") => self.switch_ws(params).await,
             Some("export") => self.export_to(params).await,
             Some("export") => self.export_to(params).await,
             Some("import") => self.import_from(params).await,
             Some("import") => self.import_from(params).await,
+            Some("get_stop_tasks") => self.get_stop_tasks(params).await,
             Some(_) | None => return JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(),
             Some(_) | None => return JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(),
         };
         };
 
 
@@ -121,7 +122,7 @@ impl JsonRpcInterface {
     async fn get_ids(&self, params: &[Value]) -> TaudResult<Value> {
     async fn get_ids(&self, params: &[Value]) -> TaudResult<Value> {
         debug!(target: "tau", "JsonRpc::get_ids() params {:?}", params);
         debug!(target: "tau", "JsonRpc::get_ids() params {:?}", params);
         let ws = self.workspace.lock().await.clone();
         let ws = self.workspace.lock().await.clone();
-        let tasks = MonthTasks::load_current_open_tasks(&self.dataset_path, ws)?;
+        let tasks = MonthTasks::load_current_tasks(&self.dataset_path, ws, false)?;
         let task_ids: Vec<u32> = tasks.iter().map(|task| task.get_id()).collect();
         let task_ids: Vec<u32> = tasks.iter().map(|task| task.get_id()).collect();
         Ok(json!(task_ids))
         Ok(json!(task_ids))
     }
     }
@@ -210,6 +211,27 @@ impl JsonRpcInterface {
         Ok(json!(task))
         Ok(json!(task))
     }
     }
 
 
+    // RPCAPI:
+    // Get all tasks.
+    // --> {"jsonrpc": "2.0", "method": "get_all_tasks", "params": [task_id], "id": 1}
+    // <-- {"jsonrpc": "2.0", "result": "task", "id": 1}
+    async fn get_stop_tasks(&self, params: &[Value]) -> TaudResult<Value> {
+        debug!(target: "tau", "JsonRpc::get_all_tasks() params {:?}", params);
+
+        if params.len() != 1 {
+            return Err(TaudError::InvalidData("len of params should be 1".into()))
+        }
+        if !params[0].is_i64() {
+            return Err(TaudError::InvalidData("Invalid month".into()))
+        }
+        let month = Timestamp(params[0].as_i64().unwrap());
+        let ws = self.workspace.lock().await.clone();
+
+        let tasks = MonthTasks::load_stop_tasks(&self.dataset_path, ws, &month)?;
+
+        Ok(json!(tasks))
+    }
+
     // RPCAPI:
     // RPCAPI:
     // Switch tasks workspace.
     // Switch tasks workspace.
     // --> {"jsonrpc": "2.0", "method": "switch_ws", "params": [workspace], "id": 1}
     // --> {"jsonrpc": "2.0", "method": "switch_ws", "params": [workspace], "id": 1}
@@ -252,15 +274,18 @@ impl JsonRpcInterface {
             return Err(TaudError::InvalidData("Invalid path".into()))
             return Err(TaudError::InvalidData("Invalid path".into()))
         }
         }
 
 
+        let ws = self.workspace.lock().await.clone();
         let path = expand_path(params[0].as_str().unwrap())?.join("exported_tasks");
         let path = expand_path(params[0].as_str().unwrap())?.join("exported_tasks");
         // mkdir datastore_path if not exists
         // mkdir datastore_path if not exists
         create_dir_all(path.join("month")).map_err(Error::from)?;
         create_dir_all(path.join("month")).map_err(Error::from)?;
         create_dir_all(path.join("task")).map_err(Error::from)?;
         create_dir_all(path.join("task")).map_err(Error::from)?;
-        let mt = MonthTasks::load_or_create(None, &self.dataset_path)?;
-        let tasks = mt.objects(&self.dataset_path)?;
+
+        let tasks = MonthTasks::load_current_tasks(&self.dataset_path, ws, true)?;
 
 
         for task in tasks {
         for task in tasks {
             task.save(&path)?;
             task.save(&path)?;
+            // save_json_file::<TaskInfo>(&TaskInfo::get_path(&task.ref_id, &path), &task)
+            //     .map_err(TaudError::Darkfi)?;
         }
         }
 
 
         Ok(json!(true))
         Ok(json!(true))
@@ -281,9 +306,9 @@ impl JsonRpcInterface {
             return Err(TaudError::InvalidData("Invalid path".into()))
             return Err(TaudError::InvalidData("Invalid path".into()))
         }
         }
 
 
+        let ws = self.workspace.lock().await.clone();
         let path = expand_path(params[0].as_str().unwrap())?.join("exported_tasks");
         let path = expand_path(params[0].as_str().unwrap())?.join("exported_tasks");
-        let mt = MonthTasks::load_or_create(None, &path)?;
-        let tasks = mt.objects(&path)?;
+        let tasks = MonthTasks::load_current_tasks(&path, ws, true)?;
 
 
         for task in tasks {
         for task in tasks {
             self.notify_queue_sender.send(task).await.map_err(Error::from)?;
             self.notify_queue_sender.send(task).await.map_err(Error::from)?;
@@ -293,7 +318,7 @@ impl JsonRpcInterface {
 
 
     fn load_task_by_id(&self, task_id: &Value, ws: String) -> TaudResult<TaskInfo> {
     fn load_task_by_id(&self, task_id: &Value, ws: String) -> TaudResult<TaskInfo> {
         let task_id: u64 = serde_json::from_value(task_id.clone())?;
         let task_id: u64 = serde_json::from_value(task_id.clone())?;
-        let tasks = MonthTasks::load_current_open_tasks(&self.dataset_path, ws)?;
+        let tasks = MonthTasks::load_current_tasks(&self.dataset_path, ws, false)?;
         let task = tasks.into_iter().find(|t| (t.get_id() as u64) == task_id);
         let task = tasks.into_iter().find(|t| (t.get_id() as u64) == task_id);
 
 
         task.ok_or(TaudError::InvalidId)
         task.ok_or(TaudError::InvalidId)

+ 57 - 18
bin/tau/taud/src/month_tasks.rs

@@ -20,18 +20,23 @@ use crate::{
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
 pub struct MonthTasks {
 pub struct MonthTasks {
     created_at: Timestamp,
     created_at: Timestamp,
-    task_tks: Vec<String>,
+    active_tks: Vec<String>,
+    deactive_tks: Vec<String>,
 }
 }
 
 
 impl MonthTasks {
 impl MonthTasks {
-    pub fn new(task_tks: &[String]) -> Self {
-        Self { created_at: Timestamp::current_time(), task_tks: task_tks.to_owned() }
+    pub fn new(active_tks: &[String], deactive_tks: &[String]) -> Self {
+        Self {
+            created_at: Timestamp::current_time(),
+            active_tks: active_tks.to_owned(),
+            deactive_tks: deactive_tks.to_owned(),
+        }
     }
     }
 
 
     pub fn add(&mut self, ref_id: &str) {
     pub fn add(&mut self, ref_id: &str) {
         debug!(target: "tau", "MonthTasks::add()");
         debug!(target: "tau", "MonthTasks::add()");
-        if !self.task_tks.contains(&ref_id.into()) {
-            self.task_tks.push(ref_id.into());
+        if !self.active_tks.contains(&ref_id.into()) {
+            self.active_tks.push(ref_id.into());
         }
         }
     }
     }
 
 
@@ -39,7 +44,11 @@ impl MonthTasks {
         debug!(target: "tau", "MonthTasks::objects()");
         debug!(target: "tau", "MonthTasks::objects()");
         let mut tks: Vec<TaskInfo> = vec![];
         let mut tks: Vec<TaskInfo> = vec![];
 
 
-        for ref_id in self.task_tks.iter() {
+        for ref_id in self.active_tks.iter() {
+            tks.push(TaskInfo::load(ref_id, dataset_path)?);
+        }
+
+        for ref_id in self.deactive_tks.iter() {
             tks.push(TaskInfo::load(ref_id, dataset_path)?);
             tks.push(TaskInfo::load(ref_id, dataset_path)?);
         }
         }
 
 
@@ -48,8 +57,12 @@ impl MonthTasks {
 
 
     pub fn remove(&mut self, ref_id: &str) {
     pub fn remove(&mut self, ref_id: &str) {
         debug!(target: "tau", "MonthTasks::remove()");
         debug!(target: "tau", "MonthTasks::remove()");
-        if let Some(index) = self.task_tks.iter().position(|t| *t == ref_id) {
-            self.task_tks.remove(index);
+        if self.active_tks.contains(&ref_id.to_string()) {
+            if let Some(index) = self.active_tks.iter().position(|t| *t == ref_id) {
+                self.deactive_tks.push(self.active_tks.remove(index));
+            }
+        } else {
+            self.deactive_tks.push(ref_id.to_owned());
         }
         }
     }
     }
 
 
@@ -84,7 +97,7 @@ impl MonthTasks {
     fn create(date: &Timestamp, dataset_path: &Path) -> TaudResult<Self> {
     fn create(date: &Timestamp, dataset_path: &Path) -> TaudResult<Self> {
         debug!(target: "tau", "MonthTasks::create()");
         debug!(target: "tau", "MonthTasks::create()");
 
 
-        let mut mt = Self::new(&[]);
+        let mut mt = Self::new(&[], &[]);
         mt.set_date(date);
         mt.set_date(date);
         mt.save(dataset_path)?;
         mt.save(dataset_path)?;
         Ok(mt)
         Ok(mt)
@@ -106,14 +119,19 @@ impl MonthTasks {
                     Err(_) => vec![],
                     Err(_) => vec![],
                 };
                 };
 
 
-                let mut loaded_mt = Self::new(&[]);
+                let mut loaded_mt = Self::new(&[], &[]);
 
 
                 for path in path_all {
                 for path in path_all {
                     let mt = load_json_file::<Self>(&path)?;
                     let mt = load_json_file::<Self>(&path)?;
                     loaded_mt.created_at = mt.created_at;
                     loaded_mt.created_at = mt.created_at;
-                    for tks in mt.task_tks {
-                        if !loaded_mt.task_tks.contains(&tks) {
-                            loaded_mt.task_tks.push(tks)
+                    for tks in mt.active_tks {
+                        if !loaded_mt.active_tks.contains(&tks) {
+                            loaded_mt.active_tks.push(tks)
+                        }
+                    }
+                    for dtks in mt.deactive_tks {
+                        if !loaded_mt.deactive_tks.contains(&dtks) {
+                            loaded_mt.deactive_tks.push(dtks)
                         }
                         }
                     }
                     }
                 }
                 }
@@ -122,13 +140,34 @@ impl MonthTasks {
         }
         }
     }
     }
 
 
-    pub fn load_current_open_tasks(dataset_path: &Path, ws: String) -> TaudResult<Vec<TaskInfo>> {
+    pub fn load_current_tasks(
+        dataset_path: &Path,
+        ws: String,
+        all: bool,
+    ) -> TaudResult<Vec<TaskInfo>> {
         let mt = Self::load_or_create(None, dataset_path)?;
         let mt = Self::load_or_create(None, dataset_path)?;
+
+        if all {
+            Ok(mt.objects(dataset_path)?.into_iter().filter(|t| t.workspace == ws).collect())
+        } else {
+            Ok(mt
+                .objects(dataset_path)?
+                .into_iter()
+                .filter(|t| t.get_state() != "stop" && t.workspace == ws)
+                .collect())
+        }
+    }
+
+    pub fn load_stop_tasks(
+        dataset_path: &Path,
+        ws: String,
+        date: &Timestamp,
+    ) -> TaudResult<Vec<TaskInfo>> {
+        let mt = Self::load_or_create(Some(date), dataset_path)?;
         Ok(mt
         Ok(mt
             .objects(dataset_path)?
             .objects(dataset_path)?
             .into_iter()
             .into_iter()
-            .filter(|t| t.get_state() != "stop")
-            .filter(|t| t.workspace == ws)
+            .filter(|t| t.get_state() == "stop" && t.workspace == ws)
             .collect())
             .collect())
     }
     }
 }
 }
@@ -192,7 +231,7 @@ mod tests {
 
 
         let task_tks = vec![];
         let task_tks = vec![];
 
 
-        let mut mt = MonthTasks::new(&task_tks);
+        let mut mt = MonthTasks::new(&task_tks, &[]);
 
 
         mt.save(&dataset_path)?;
         mt.save(&dataset_path)?;
 
 
@@ -225,7 +264,7 @@ mod tests {
 
 
         let mt_load = MonthTasks::load_or_create(Some(&Timestamp::current_time()), &dataset_path)?;
         let mt_load = MonthTasks::load_or_create(Some(&Timestamp::current_time()), &dataset_path)?;
 
 
-        assert!(mt_load.task_tks.contains(&task.ref_id));
+        assert!(mt_load.active_tks.contains(&task.ref_id));
 
 
         remove_dir_all(TEST_DATA_PATH).ok();
         remove_dir_all(TEST_DATA_PATH).ok();
 
 

+ 2 - 2
bin/tau/taud/src/task_info.rs

@@ -90,7 +90,7 @@ impl TaskInfo {
         let created_at = Timestamp::current_time();
         let created_at = Timestamp::current_time();
 
 
         let task_ids: Vec<u32> =
         let task_ids: Vec<u32> =
-            MonthTasks::load_current_open_tasks(dataset_path, workspace.clone())?
+            MonthTasks::load_current_tasks(dataset_path, workspace.clone(), false)?
                 .into_iter()
                 .into_iter()
                 .map(|t| t.id)
                 .map(|t| t.id)
                 .collect();
                 .collect();
@@ -163,7 +163,7 @@ impl TaskInfo {
         }
         }
     }
     }
 
 
-    fn get_path(ref_id: &str, dataset_path: &Path) -> PathBuf {
+    pub fn get_path(ref_id: &str, dataset_path: &Path) -> PathBuf {
         debug!(target: "tau", "TaskInfo::get_path()");
         debug!(target: "tau", "TaskInfo::get_path()");
         dataset_path.join("task").join(ref_id)
         dataset_path.join("task").join(ref_id)
     }
     }