Compare commits
2 commits
d614d678af
...
b322c0307d
| Author | SHA1 | Date | |
|---|---|---|---|
| b322c0307d | |||
| 0533c7777a |
4 changed files with 80 additions and 11 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "streamd"
|
name = "streamd"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Personal knowledge management and time-tracking CLI using @Tag annotations"
|
description = "Personal knowledge management and time-tracking CLI using @Tag annotations"
|
||||||
license = "AGPL-3.0-only"
|
license = "AGPL-3.0-only"
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,10 @@ pub enum Commands {
|
||||||
/// Display time as minutes (HH:MM) instead of decimal hours (H.Hh)
|
/// Display time as minutes (HH:MM) instead of decimal hours (H.Hh)
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
minutes: bool,
|
minutes: bool,
|
||||||
|
|
||||||
|
/// Show all timecards grouped by day instead of the summary report
|
||||||
|
#[arg(short, long)]
|
||||||
|
debug: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Generate shell completions
|
/// Generate shell completions
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use chrono::Datelike;
|
use chrono::Datelike;
|
||||||
|
use chrono::NaiveDate;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::config::Settings;
|
use crate::config::Settings;
|
||||||
|
|
@ -11,7 +13,7 @@ const COLUMN_SEPARATOR_WIDTH: usize = 65;
|
||||||
use crate::error::StreamdError;
|
use crate::error::StreamdError;
|
||||||
use crate::extract::parse_markdown_file;
|
use crate::extract::parse_markdown_file;
|
||||||
use crate::localize::localize_stream_file;
|
use crate::localize::localize_stream_file;
|
||||||
use crate::models::LocalizedShard;
|
use crate::models::{LocalizedShard, Timesheet};
|
||||||
use crate::timesheet::{
|
use crate::timesheet::{
|
||||||
extract_timesheets, generate_report, load_repository_config, BasicTimesheetConfiguration,
|
extract_timesheets, generate_report, load_repository_config, BasicTimesheetConfiguration,
|
||||||
DayType, DayWarning, MonthReport, TimesheetReport,
|
DayType, DayWarning, MonthReport, TimesheetReport,
|
||||||
|
|
@ -237,7 +239,65 @@ fn print_warnings(report: &TimesheetReport, use_minutes: bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(use_minutes: bool) -> Result<(), StreamdError> {
|
/// Print debug view: all timecards grouped and sorted by day.
|
||||||
|
fn print_debug(report: &TimesheetReport, timesheets: &[Timesheet]) {
|
||||||
|
let timesheets_by_date: HashMap<NaiveDate, &Timesheet> =
|
||||||
|
timesheets.iter().map(|ts| (ts.date, ts)).collect();
|
||||||
|
|
||||||
|
for month in &report.months {
|
||||||
|
let month_title = format!("{} {}", month.month_name(), month.year);
|
||||||
|
let separator = "\u{2550}".repeat(SEPARATOR_WIDTH);
|
||||||
|
println!("{}", separator);
|
||||||
|
println!(" {}", month_title);
|
||||||
|
println!("{}", separator);
|
||||||
|
println!();
|
||||||
|
|
||||||
|
for day in &month.days {
|
||||||
|
let date_str = day.date.format("%Y-%m-%d").to_string();
|
||||||
|
let weekday = weekday_abbrev(day.date);
|
||||||
|
|
||||||
|
let mut parts: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
// Add day type label for non-regular days
|
||||||
|
let type_label = match day.day_type {
|
||||||
|
DayType::Regular => None,
|
||||||
|
DayType::SickLeave => Some("Sick Leave"),
|
||||||
|
DayType::Vacation => Some("Vacation"),
|
||||||
|
DayType::Holiday => Some("Holiday"),
|
||||||
|
DayType::FlexDay => Some("Flex Day"),
|
||||||
|
DayType::Weekend => Some("Weekend"),
|
||||||
|
DayType::Missing => Some("Missing"),
|
||||||
|
DayType::OutsidePeriod => Some("Outside Period"),
|
||||||
|
};
|
||||||
|
if let Some(label) = type_label {
|
||||||
|
parts.push(label.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add timecards
|
||||||
|
if let Some(ts) = timesheets_by_date.get(&day.date) {
|
||||||
|
for tc in &ts.timecards {
|
||||||
|
parts.push(format!(
|
||||||
|
"{} - {}",
|
||||||
|
tc.from_time.format("%H:%M"),
|
||||||
|
tc.to_time.format("%H:%M")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = if parts.is_empty() {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
parts.join(", ")
|
||||||
|
};
|
||||||
|
|
||||||
|
println!(" {} ({}): {}", date_str, weekday, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(use_minutes: bool, debug: bool) -> Result<(), StreamdError> {
|
||||||
let settings = Settings::load()?;
|
let settings = Settings::load()?;
|
||||||
let base_folder = Path::new(&settings.base_folder);
|
let base_folder = Path::new(&settings.base_folder);
|
||||||
|
|
||||||
|
|
@ -273,7 +333,9 @@ pub fn run(use_minutes: bool) -> Result<(), StreamdError> {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the report
|
if debug {
|
||||||
|
print_debug(&report, ×heets);
|
||||||
|
} else {
|
||||||
print_header();
|
print_header();
|
||||||
|
|
||||||
for month in &report.months {
|
for month in &report.months {
|
||||||
|
|
@ -282,6 +344,7 @@ pub fn run(use_minutes: bool) -> Result<(), StreamdError> {
|
||||||
|
|
||||||
print_cumulative_balance(report.cumulative_balance, use_minutes);
|
print_cumulative_balance(report.cumulative_balance, use_minutes);
|
||||||
print_warnings(&report, use_minutes);
|
print_warnings(&report, use_minutes);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ fn main() -> miette::Result<()> {
|
||||||
Some(TodoAction::Done { number }) => streamd::cli::commands::todo::run_done(number)?,
|
Some(TodoAction::Done { number }) => streamd::cli::commands::todo::run_done(number)?,
|
||||||
},
|
},
|
||||||
Some(Commands::Edit { number }) => streamd::cli::commands::edit::run(number)?,
|
Some(Commands::Edit { number }) => streamd::cli::commands::edit::run(number)?,
|
||||||
Some(Commands::Timesheet { minutes }) => streamd::cli::commands::timesheet::run(minutes)?,
|
Some(Commands::Timesheet { minutes, debug }) => {
|
||||||
|
streamd::cli::commands::timesheet::run(minutes, debug)?
|
||||||
|
}
|
||||||
Some(Commands::Completions { shell }) => {
|
Some(Commands::Completions { shell }) => {
|
||||||
streamd::cli::commands::completions::run(shell);
|
streamd::cli::commands::completions::run(shell);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue