mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-10 23:27:56 -05:00
bin/tau: review taskwarrior CLI and cleanup tau usage
This commit is contained in:
@@ -1,44 +1,95 @@
|
||||
use chrono::{Datelike, NaiveDateTime, Utc};
|
||||
use std::{
|
||||
io::{stdin, stdout, Write},
|
||||
process::exit,
|
||||
};
|
||||
|
||||
use chrono::{Datelike, Local, NaiveDateTime, Utc};
|
||||
use log::error;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::primitives::{State, TaskInfo};
|
||||
use darkfi::Result;
|
||||
|
||||
use crate::{
|
||||
primitives::{State, TaskInfo},
|
||||
util::due_as_timestamp,
|
||||
};
|
||||
|
||||
pub fn apply_filter(tasks: &mut Vec<TaskInfo>, filter: &str) {
|
||||
match filter {
|
||||
"open" => tasks.retain(|task| task.state == State::Open.to_string()),
|
||||
"start" => tasks.retain(|task| task.state == State::Start.to_string()),
|
||||
"pause" => tasks.retain(|task| task.state == State::Pause.to_string()),
|
||||
|
||||
_ if filter.len() == 4 && filter.parse::<u32>().is_ok() => {
|
||||
let (month, year) =
|
||||
(filter[..2].parse::<u32>().unwrap(), filter[2..].parse::<i32>().unwrap());
|
||||
|
||||
let year = year + (Utc::today().year() / 100) * 100;
|
||||
tasks.retain(|task| {
|
||||
let date = task.created_at;
|
||||
let task_date = NaiveDateTime::from_timestamp(date, 0).date();
|
||||
task_date.month() == month && task_date.year() == year
|
||||
})
|
||||
"all" => {}
|
||||
// Filter by state.
|
||||
_ if filter.contains("state:") => {
|
||||
let kv: Vec<&str> = filter.split(':').collect();
|
||||
if let Some(state) = Value::from(kv[1]).as_str() {
|
||||
match state {
|
||||
"open" => tasks.retain(|task| task.state == State::Open.to_string()),
|
||||
"start" => tasks.retain(|task| task.state == State::Start.to_string()),
|
||||
"pause" => tasks.retain(|task| task.state == State::Pause.to_string()),
|
||||
"stop" => tasks.retain(|task| task.state == State::Stop.to_string()),
|
||||
_ => {
|
||||
error!("Not implemented, states are open,start,pause and stop");
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by month
|
||||
_ if filter.contains("month:") => {
|
||||
let kv: Vec<&str> = filter.split(':').collect();
|
||||
if kv.len() == 2 {
|
||||
if let Some(value) = Value::from(kv[1]).as_str() {
|
||||
if value.len() != 4 || value.parse::<u32>().is_err() {
|
||||
error!(
|
||||
"Please provide month date as \"MMYY\" (e.g. 0922 for September 2022)"
|
||||
);
|
||||
exit(1)
|
||||
}
|
||||
let (month, year) =
|
||||
(value[..2].parse::<u32>().unwrap(), value[2..].parse::<i32>().unwrap());
|
||||
|
||||
let year = year + (Utc::today().year() / 100) * 100;
|
||||
tasks.retain(|task| {
|
||||
let date = task.created_at;
|
||||
let task_date = NaiveDateTime::from_timestamp(date, 0).date();
|
||||
task_date.month() == month && task_date.year() == year
|
||||
})
|
||||
} else {
|
||||
error!("Please provide month date as \"MMYY\" (e.g. 0922 for September 2022)");
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by assignee(s).
|
||||
_ if filter.contains("assign:") => {
|
||||
let kv: Vec<&str> = filter.split(':').collect();
|
||||
if kv.len() == 2 {
|
||||
if let Some(value) = Value::from(kv[1]).as_str() {
|
||||
tasks.retain(|task| task.assign.contains(&value.to_string()))
|
||||
if value.is_empty() {
|
||||
tasks.retain(|task| task.assign.is_empty())
|
||||
} else {
|
||||
tasks.retain(|task| task.assign.contains(&value.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by project(s).
|
||||
_ if filter.contains("project:") => {
|
||||
let kv: Vec<&str> = filter.split(':').collect();
|
||||
if kv.len() == 2 {
|
||||
if let Some(value) = Value::from(kv[1]).as_str() {
|
||||
tasks.retain(|task| task.project.contains(&value.to_string()))
|
||||
if value.is_empty() {
|
||||
tasks.retain(|task| task.project.is_empty())
|
||||
} else {
|
||||
tasks.retain(|task| task.project.contains(&value.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by rank.
|
||||
_ if filter.contains("rank:") => {
|
||||
let kv: Vec<&str> = filter.split(':').collect();
|
||||
if kv.len() == 3 {
|
||||
@@ -53,8 +104,118 @@ pub fn apply_filter(tasks: &mut Vec<TaskInfo>, filter: &str) {
|
||||
}
|
||||
})
|
||||
}
|
||||
tasks.retain(|task| task.rank.is_none())
|
||||
}
|
||||
|
||||
_ => {}
|
||||
// Filter by due date.
|
||||
_ if filter.contains("due:") || filter.contains("due.") => {
|
||||
let kv: Vec<&str> = filter.split(':').collect();
|
||||
let due_op = if filter.contains('.') {
|
||||
let due_op: Vec<&str> = kv[0].split('.').collect();
|
||||
due_op[1]
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
if kv.len() == 2 {
|
||||
if let Some(value) = Value::from(kv[1]).as_str() {
|
||||
if value.is_empty() {
|
||||
tasks.retain(|task| task.due.is_none())
|
||||
} else {
|
||||
let filter_date = if value == "today" {
|
||||
Local::today().naive_local()
|
||||
} else {
|
||||
let due_date = due_as_timestamp(value).unwrap_or(0);
|
||||
NaiveDateTime::from_timestamp(due_date, 0).date()
|
||||
};
|
||||
|
||||
tasks.retain(|task| {
|
||||
let date = task.due.unwrap_or(0);
|
||||
let task_date = NaiveDateTime::from_timestamp(date, 0).date();
|
||||
|
||||
match due_op {
|
||||
"not" => task_date != filter_date,
|
||||
"after" => task_date > filter_date,
|
||||
"before" => task_date < filter_date,
|
||||
"" | "is" => task_date == filter_date,
|
||||
_ => true,
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
error!("Please provide due date as \"DDMM\" (e.g. 2210 for October 22nd)");
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
println!("No matches.");
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn no_filter_warn() {
|
||||
let mut s = String::new();
|
||||
print!("This command has no filter, and will modify all tasks. Are you sure? (yes/no) ");
|
||||
let _ = stdout().flush();
|
||||
stdin().read_line(&mut s).unwrap_or(0);
|
||||
match s.trim() {
|
||||
"y" | "yes" => {}
|
||||
_ => {
|
||||
println!("Command prevented from running.");
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_ids(filters: &mut Vec<String>) -> Result<Vec<u64>> {
|
||||
let mut vec_ids = vec![];
|
||||
let mut matching_id = String::new();
|
||||
if let Some(index) = filters.iter().position(|t| {
|
||||
t.parse::<u64>().is_ok() || !t.contains(':') && (t.contains(',') || t.contains('-'))
|
||||
}) {
|
||||
matching_id.push_str(&filters.remove(index));
|
||||
}
|
||||
|
||||
match matching_id {
|
||||
_ if matching_id.parse::<u64>().is_ok() => {
|
||||
let id = matching_id.parse::<u64>().unwrap();
|
||||
vec_ids.push(id)
|
||||
}
|
||||
_ if !matching_id.contains(':') &&
|
||||
(matching_id.contains(',') || matching_id.contains('-')) =>
|
||||
{
|
||||
let num = matching_id.replace(&[',', '-'][..], "");
|
||||
if num.parse::<u64>().is_err() {
|
||||
error!("Invalid ID number");
|
||||
exit(1)
|
||||
}
|
||||
if matching_id.contains(',') {
|
||||
let ids: Vec<&str> = matching_id.split(',').collect();
|
||||
for id in ids {
|
||||
if id.contains('-') {
|
||||
let range: Vec<&str> = id.split('-').collect();
|
||||
let range =
|
||||
range[0].parse::<u64>().unwrap()..=range[1].parse::<u64>().unwrap();
|
||||
for rid in range {
|
||||
vec_ids.push(rid)
|
||||
}
|
||||
} else {
|
||||
vec_ids.push(id.parse::<u64>().unwrap())
|
||||
}
|
||||
}
|
||||
} else if matching_id.contains('-') {
|
||||
let range: Vec<&str> = matching_id.split('-').collect();
|
||||
let range = range[0].parse::<u64>().unwrap()..=range[1].parse::<u64>().unwrap();
|
||||
for rid in range {
|
||||
vec_ids.push(rid)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(vec_ids)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{process::exit, str::FromStr};
|
||||
use std::process::exit;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use log::{error, info};
|
||||
@@ -19,6 +19,7 @@ mod util;
|
||||
mod view;
|
||||
|
||||
use drawdown::{drawdown, to_naivedate};
|
||||
use filter::{apply_filter, get_ids, no_filter_warn};
|
||||
use primitives::{task_from_cli, State, TaskEvent};
|
||||
use util::{desc_in_editor, due_as_timestamp};
|
||||
use view::{comments_as_string, print_task_info, print_task_list};
|
||||
@@ -27,6 +28,7 @@ const DEFAULT_PATH: &str = "~/tau_exported_tasks";
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(name = "tau", version)]
|
||||
#[clap(subcommand_precedence_over_arg = true)]
|
||||
struct Args {
|
||||
#[clap(short, parse(from_occurrences))]
|
||||
/// Increase verbosity (-vvv supported)
|
||||
@@ -72,32 +74,35 @@ enum TauSubcommand {
|
||||
values: Vec<String>,
|
||||
},
|
||||
|
||||
/// Update/Edit an existing task by ID.
|
||||
Update {
|
||||
/// Task ID.
|
||||
task_id: u64,
|
||||
/// Modify/Edit an existing task.
|
||||
Modify {
|
||||
/// Values (e.g. project:blockchain).
|
||||
values: Vec<String>,
|
||||
},
|
||||
|
||||
/// Set or Get task state.
|
||||
State {
|
||||
/// Task ID.
|
||||
task_id: u64,
|
||||
/// Set task state if provided (Get state otherwise).
|
||||
state: Option<String>,
|
||||
},
|
||||
/// List tasks.
|
||||
List,
|
||||
|
||||
/// Set or Get comment for a task.
|
||||
/// Start task(s).
|
||||
Start,
|
||||
|
||||
/// Open task(s).
|
||||
Open,
|
||||
|
||||
/// Pause task(s).
|
||||
Pause,
|
||||
|
||||
/// Stop task(s).
|
||||
Stop,
|
||||
|
||||
/// Set or Get comment for task(s).
|
||||
Comment {
|
||||
/// Task ID.
|
||||
task_id: u64,
|
||||
/// Set comment content if provided (Get comments otherwise).
|
||||
content: Vec<String>,
|
||||
},
|
||||
|
||||
/// Get task info by ID.
|
||||
Info { task_id: u64 },
|
||||
/// Get all data about selected task(s).
|
||||
Info,
|
||||
|
||||
/// Switch workspace.
|
||||
Switch {
|
||||
@@ -120,7 +125,7 @@ enum TauSubcommand {
|
||||
/// Log drawdown.
|
||||
Log {
|
||||
/// The month in which we want to draw a heatmap (e.g. 0822 for August 2022).
|
||||
month: String,
|
||||
month: Option<String>,
|
||||
/// The person of which we want to draw a heatmap
|
||||
/// (if not provided we list all assignees).
|
||||
assignee: Option<String>,
|
||||
@@ -142,6 +147,28 @@ async fn main() -> Result<()> {
|
||||
let rpc_client = RpcClient::new(args.endpoint).await?;
|
||||
let tau = Tau { rpc_client };
|
||||
|
||||
let mut filters = args.filters.clone();
|
||||
|
||||
// If IDs are provided in filter we use them to get the tasks from the daemon
|
||||
// then remove IDs from filter so we can do apply_filter() normally.
|
||||
// If not provided we use get_ids() to get them from the daemon.
|
||||
let ids = get_ids(&mut filters)?;
|
||||
let task_ids = if ids.is_empty() { tau.get_ids().await? } else { ids };
|
||||
|
||||
let mut tasks =
|
||||
if filters.contains(&"state:stop".to_string()) || filters.contains(&"all".to_string()) {
|
||||
tau.get_stop_tasks(None).await?
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
for id in task_ids {
|
||||
tasks.push(tau.get_task_by_id(id).await?);
|
||||
}
|
||||
|
||||
for filter in filters {
|
||||
apply_filter(&mut tasks, &filter);
|
||||
}
|
||||
|
||||
// Parse subcommands
|
||||
match args.command {
|
||||
Some(sc) => match sc {
|
||||
@@ -159,50 +186,86 @@ async fn main() -> Result<()> {
|
||||
return tau.add(task).await
|
||||
}
|
||||
|
||||
TauSubcommand::Update { task_id, values } => {
|
||||
let task = task_from_cli(values)?;
|
||||
tau.update(task_id, task).await
|
||||
}
|
||||
|
||||
TauSubcommand::State { task_id, state } => match state {
|
||||
Some(state) => {
|
||||
let state = state.trim().to_lowercase();
|
||||
if let Ok(st) = State::from_str(&state) {
|
||||
tau.set_state(task_id, &st).await
|
||||
} else {
|
||||
error!("State can only be one of the following: open start stop pause",);
|
||||
Ok(())
|
||||
}
|
||||
TauSubcommand::Modify { values } => {
|
||||
if args.filters.is_empty() {
|
||||
no_filter_warn()
|
||||
}
|
||||
None => {
|
||||
let task = tau.get_task_by_id(task_id).await?;
|
||||
let state = State::from_str(&task.state)?;
|
||||
println!("Task {}: {}", task_id, state);
|
||||
Ok(())
|
||||
let base_task = task_from_cli(values)?;
|
||||
for task in tasks {
|
||||
tau.update(task.id.into(), base_task.clone()).await?;
|
||||
}
|
||||
},
|
||||
|
||||
TauSubcommand::Comment { task_id, content } => {
|
||||
if content.is_empty() {
|
||||
let task = tau.get_task_by_id(task_id).await?;
|
||||
let comments = comments_as_string(task.comments);
|
||||
println!("Comments {}:\n{}", task_id, comments);
|
||||
Ok(())
|
||||
} else {
|
||||
tau.set_comment(task_id, &content.join(" ")).await
|
||||
}
|
||||
}
|
||||
|
||||
TauSubcommand::Info { task_id } => {
|
||||
let task = tau.get_task_by_id(task_id).await?;
|
||||
print_task_info(task)
|
||||
}
|
||||
|
||||
TauSubcommand::Switch { workspace } => {
|
||||
tau.switch_ws(workspace).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
TauSubcommand::Start => {
|
||||
if args.filters.is_empty() {
|
||||
no_filter_warn()
|
||||
}
|
||||
let state = State::Start;
|
||||
for task in tasks {
|
||||
tau.set_state(task.id.into(), &state).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
TauSubcommand::Open => {
|
||||
if args.filters.is_empty() {
|
||||
no_filter_warn()
|
||||
}
|
||||
let state = State::Open;
|
||||
for task in tasks {
|
||||
tau.set_state(task.id.into(), &state).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
TauSubcommand::Pause => {
|
||||
if args.filters.is_empty() {
|
||||
no_filter_warn()
|
||||
}
|
||||
let state = State::Pause;
|
||||
for task in tasks {
|
||||
tau.set_state(task.id.into(), &state).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
TauSubcommand::Stop => {
|
||||
if args.filters.is_empty() {
|
||||
no_filter_warn()
|
||||
}
|
||||
let state = State::Stop;
|
||||
for task in tasks {
|
||||
tau.set_state(task.id.into(), &state).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
TauSubcommand::Comment { content } => {
|
||||
if args.filters.is_empty() {
|
||||
no_filter_warn()
|
||||
}
|
||||
for task in tasks {
|
||||
if content.is_empty() {
|
||||
let task = tau.get_task_by_id(task.id.into()).await?;
|
||||
let comments = comments_as_string(task.comments);
|
||||
println!("Comments {}:\n{}", task.id, comments);
|
||||
} else {
|
||||
tau.set_comment(task.id.into(), &content.join(" ")).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
TauSubcommand::Info => {
|
||||
for task in tasks {
|
||||
let task = tau.get_task_by_id(task.id.into()).await?;
|
||||
print_task_info(task)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
TauSubcommand::Switch { workspace } => tau.switch_ws(workspace).await,
|
||||
|
||||
TauSubcommand::Export { path } => {
|
||||
let path = path.unwrap_or_else(|| DEFAULT_PATH.into());
|
||||
let res = tau.export_to(path.clone()).await?;
|
||||
@@ -230,22 +293,30 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
TauSubcommand::Log { month, assignee } => {
|
||||
let ts = to_naivedate(month.clone())?.and_hms(12, 0, 0).timestamp();
|
||||
let tasks = tau.get_stop_tasks(ts).await?;
|
||||
drawdown(month, tasks, assignee)?;
|
||||
match month {
|
||||
Some(date) => {
|
||||
let ts = to_naivedate(date.clone())?.and_hms(12, 0, 0).timestamp();
|
||||
let tasks = tau.get_stop_tasks(Some(ts)).await?;
|
||||
drawdown(date, tasks, assignee)?;
|
||||
}
|
||||
None => {
|
||||
let ws = tau.get_ws().await?;
|
||||
let tasks = tau.get_stop_tasks(None).await?;
|
||||
print_task_list(tasks, ws)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
TauSubcommand::List => {
|
||||
let ws = tau.get_ws().await?;
|
||||
print_task_list(tasks, ws)
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let ws = tau.get_ws().await?;
|
||||
let task_ids = tau.get_ids().await?;
|
||||
let mut tasks = vec![];
|
||||
for id in task_ids {
|
||||
tasks.push(tau.get_task_by_id(id).await?);
|
||||
}
|
||||
print_task_list(tasks, ws, args.filters)?;
|
||||
Ok(())
|
||||
print_task_list(tasks, ws)
|
||||
}
|
||||
}?;
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ impl State {
|
||||
pub const fn is_pause(&self) -> bool {
|
||||
matches!(*self, Self::Pause)
|
||||
}
|
||||
pub const fn is_stop(&self) -> bool {
|
||||
matches!(*self, Self::Stop)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for State {
|
||||
@@ -46,7 +49,7 @@ impl FromStr for State {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct BaseTask {
|
||||
pub title: String,
|
||||
pub desc: Option<String>,
|
||||
@@ -56,7 +59,7 @@ pub struct BaseTask {
|
||||
pub rank: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct TaskInfo {
|
||||
pub ref_id: String,
|
||||
pub workspace: String,
|
||||
@@ -74,7 +77,7 @@ pub struct TaskInfo {
|
||||
pub comments: Vec<Comment>,
|
||||
}
|
||||
|
||||
#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct TaskEvent {
|
||||
pub action: String,
|
||||
pub author: String,
|
||||
@@ -99,7 +102,7 @@ impl Default for TaskEvent {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Comment {
|
||||
content: String,
|
||||
author: String,
|
||||
|
||||
@@ -71,7 +71,7 @@ impl Tau {
|
||||
}
|
||||
|
||||
/// Get month's stopped tasks.
|
||||
pub async fn get_stop_tasks(&self, month: i64) -> Result<Vec<TaskInfo>> {
|
||||
pub async fn get_stop_tasks(&self, month: Option<i64>) -> Result<Vec<TaskInfo>> {
|
||||
let req = JsonRequest::new("get_stop_tasks", json!([month]));
|
||||
let rep = self.rpc_client.request(req).await?;
|
||||
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
use std::{fmt::Write, str::FromStr};
|
||||
use std::{cmp::Ordering, fmt::Write, str::FromStr};
|
||||
|
||||
use prettytable::{
|
||||
cell,
|
||||
format::{consts::FORMAT_NO_COLSEP, FormatBuilder, LinePosition, LineSeparator},
|
||||
row, table, Cell, Row, Table,
|
||||
};
|
||||
use textwrap::fill;
|
||||
|
||||
use darkfi::{
|
||||
util::time::{timestamp_to_date, DateFormat},
|
||||
Result,
|
||||
};
|
||||
use textwrap::fill;
|
||||
|
||||
use crate::{
|
||||
filter::apply_filter,
|
||||
primitives::{Comment, State, TaskInfo},
|
||||
TaskEvent,
|
||||
};
|
||||
|
||||
pub fn print_task_list(tasks: Vec<TaskInfo>, ws: String, filters: Vec<String>) -> Result<()> {
|
||||
pub fn print_task_list(tasks: Vec<TaskInfo>, ws: String) -> Result<()> {
|
||||
let mut tasks = tasks;
|
||||
|
||||
let mut table = Table::new();
|
||||
@@ -30,11 +28,18 @@ pub fn print_task_list(tasks: Vec<TaskInfo>, ws: String, filters: Vec<String>) -
|
||||
);
|
||||
table.set_titles(row!["ID", "Title", "Project", "Assigned", "Due", "Rank"]);
|
||||
|
||||
for filter in filters {
|
||||
apply_filter(&mut tasks, &filter);
|
||||
}
|
||||
// group tasks by state.
|
||||
tasks.sort_by_key(|task| task.state.clone());
|
||||
|
||||
tasks.sort_by(|a, b| b.rank.partial_cmp(&a.rank).unwrap());
|
||||
// sort tasks by there rank only if they are not stopped.
|
||||
tasks.sort_by(|a, b| {
|
||||
if a.state != "stop" && b.state != "stop" {
|
||||
b.rank.partial_cmp(&a.rank).unwrap()
|
||||
} else {
|
||||
// because sort_by does not reorder equal elements
|
||||
Ordering::Equal
|
||||
}
|
||||
});
|
||||
|
||||
let mut min_rank = None;
|
||||
let mut max_rank = None;
|
||||
@@ -54,6 +59,8 @@ pub fn print_task_list(tasks: Vec<TaskInfo>, ws: String, filters: Vec<String>) -
|
||||
("bFg", "Fc", "Fg", "Fg")
|
||||
} else if state.is_pause() {
|
||||
("iFYBd", "iFYBd", "iFYBd", "iFYBd")
|
||||
} else if state.is_stop() {
|
||||
("Fr", "Fr", "Fr", "Fr")
|
||||
} else {
|
||||
("", "", "", "")
|
||||
};
|
||||
|
||||
@@ -238,21 +238,18 @@ impl JsonRpcInterface {
|
||||
|
||||
// RPCAPI:
|
||||
// Get all tasks.
|
||||
// --> {"jsonrpc": "2.0", "method": "get_all_tasks", "params": [task_id], "id": 1}
|
||||
// --> {"jsonrpc": "2.0", "method": "get_stop_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);
|
||||
debug!(target: "tau", "JsonRpc::get_stop_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 month = params[0].as_i64().map(Timestamp);
|
||||
let ws = self.workspace.lock().await.clone();
|
||||
|
||||
let tasks = MonthTasks::load_stop_tasks(&self.dataset_path, ws, &month)?;
|
||||
let tasks = MonthTasks::load_stop_tasks(&self.dataset_path, ws, month.as_ref())?;
|
||||
|
||||
Ok(json!(tasks))
|
||||
}
|
||||
|
||||
@@ -161,9 +161,9 @@ impl MonthTasks {
|
||||
pub fn load_stop_tasks(
|
||||
dataset_path: &Path,
|
||||
ws: String,
|
||||
date: &Timestamp,
|
||||
date: Option<&Timestamp>,
|
||||
) -> TaudResult<Vec<TaskInfo>> {
|
||||
let mt = Self::load_or_create(Some(date), dataset_path)?;
|
||||
let mt = Self::load_or_create(date, dataset_path)?;
|
||||
Ok(mt
|
||||
.objects(dataset_path)?
|
||||
.into_iter()
|
||||
|
||||
Reference in New Issue
Block a user