Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 2 additions & 40 deletions frontend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'hyperscript.org';
import * as _hyperscript from "hyperscript.org";
import hotkeys from "hotkeys-js";
import * as theme from "./theme.ts";
import * as timer from "./timer.ts";

_hyperscript.browserInit();

Expand Down Expand Up @@ -146,46 +147,7 @@ document.addEventListener('click', function (event) {

document.addEventListener("DOMContentLoaded", function () {
theme.init();

let n = setInterval(
() => {
let whichOne = 0;
// document.getElementById('active-timer').querySelectorAll('span.timer-duration')[0]
let dd = document.getElementById('active-timer');
if (dd === undefined || dd === null) {
return
}
let timeBox = dd.children[1].children[whichOne];
let s = timeBox.textContent.split(":");
let second = parseInt(s.pop());
let minute = parseInt(s.pop());
if (isNaN(minute)) {
minute = 0;
}
let hour = parseInt(s.pop());
if (isNaN(hour)) {
hour = 0;
}
second += 1;
if (second >= 60) {
second = 0;
minute += 1;
if (minute > 60) {
hour += 1;
}
}
timeBox.textContent = hour.toString()
// @ts-ignore
.padStart(2, "0") + ":" +
minute.toString()
// @ts-ignore
.padStart(2, "0") + ":" +
second.toString()
// @ts-ignore
.padStart(2, "0");
}, 1000
)

timer.init();
let day_progress = setInterval(
() => {
const dd = document.getElementById('time_of_the_day');
Expand Down
42 changes: 42 additions & 0 deletions frontend/src/timer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
var global_twk_timer: number|null = null;

function updateTimer() {
let timer_dom = document.getElementById('active-timer');
if (timer_dom === null) {
return;
}

let timer_box_dom = timer_dom.querySelector(".timer-duration");
if (timer_box_dom === null) {
return;
}

let task_start = timer_dom?.getAttribute("data-task-start");
if (task_start === null || task_start === undefined) {
return;
}
let task_start_dt = Date.parse(task_start);
let now_utc = Date.now();
let diff_s = Math.floor((now_utc - task_start_dt)/1000);
let hours = Math.floor(diff_s/3600);
let minutes = Math.floor((diff_s - (hours*3600))/60);
let seconds = Math.floor((diff_s - (hours*3600)) - (minutes*60));
timer_box_dom.textContent =
hours.toString().padStart(2, "0") + ":" +
minutes.toString().padStart(2, "0") + ":" +
seconds.toString().padStart(2, "0")
}

export function init() {
global_twk_timer = setInterval(
updateTimer,
1000
)
}

export function stop() {
if (global_twk_timer != null && global_twk_timer != undefined) {
clearInterval(global_twk_timer);
global_twk_timer = null;
}
}
2 changes: 1 addition & 1 deletion frontend/templates/active_task.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

</div>
<div class="pl-2.5 pr-6 py-1.5 bg-green-900 text-green-200 shadow-xl rounded-sm flex flex-wrap " id="active-timer"
data-task-id="{{ active_task.uuid }}" data-task-start="{{ active_task.start }}">
data-task-id="{{ active_task.uuid }}" data-task-start="{{ datetime_iso(datetime=active_task.start) }}">
<span class="flex-grow">{{ active_task.description }}</span>
<div class="join">
<span class="badge badge-success badge-md badge-soft join-item timer-duration">
Expand Down
39 changes: 36 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

use crate::endpoints::tasks::task_query_builder::{TaskQuery, TaskReport};
use crate::endpoints::tasks::{is_a_tag, is_tag_keyword};

#[cfg(test)]
mod tests;
use chrono::TimeZone;

Check failure on line 23 in src/lib.rs

View workflow job for this annotation

GitHub Actions / build

unused import: `chrono::TimeZone`
use chrono::{DateTime, TimeDelta};
use linkify::LinkKind;
use rand::distr::{Alphanumeric, SampleString};
Expand All @@ -25,6 +29,7 @@
use tera::{escape_html, Context};
use tracing::{trace, warn};


lazy_static::lazy_static! {
pub static ref TEMPLATES: tera::Tera = {
let mut tera = match tera::Tera::new("dist/templates/**/*") {
Expand All @@ -37,6 +42,7 @@
tera.register_function("project_name", get_project_name_link());
tera.register_function("date_proper", get_date_proper());
tera.register_function("timer_value", get_timer());
tera.register_function("datetime_iso", get_datetime_iso());
tera.register_function("date", get_date());
tera.register_function("obj", obj());
tera.register_function("remove_project_tag", remove_project_from_tag());
Expand Down Expand Up @@ -367,6 +373,17 @@
)
}

#[cfg(not(test))]
#[allow(dead_code)]
fn get_utc_now() -> DateTime<Utc> {

Check failure on line 378 in src/lib.rs

View workflow job for this annotation

GitHub Actions / build

cannot find type `Utc` in this scope
chrono::prelude::Utc::now()
}
#[cfg(test)]
#[allow(dead_code)]
fn get_utc_now() -> DateTime<Utc> {
chrono::Utc.with_ymd_and_hms(2025, 5, 1, 3, 55, 0).unwrap()
}

pub struct DeltaNow {
pub now: DateTime<chrono::Utc>,
pub delta: TimeDelta,
Expand All @@ -380,7 +397,7 @@
// Try taskchampions variant.
chrono::prelude::NaiveDateTime::parse_from_str(time, "%Y-%m-%dT%H:%M:%SZ").unwrap())
.and_utc();
let now = chrono::prelude::Utc::now();
let now = get_utc_now();
let delta = now - time;
Self { now, delta, time }
}
Expand Down Expand Up @@ -424,6 +441,22 @@
)
}

fn get_datetime_iso() -> impl tera::Function {
Box::new(
move |args: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {
let date_time_str = args.get("datetime").unwrap().as_str().unwrap();
// we are working with utc time
let date_time = chrono::prelude::NaiveDateTime::parse_from_str(date_time_str, "%Y%m%dT%H%M%SZ")
.unwrap_or_else(|_|
// Try taskchampions variant.
chrono::prelude::NaiveDateTime::parse_from_str(date_time_str, "%Y-%m-%dT%H:%M:%SZ").unwrap()
)
.and_utc();
Ok(tera::to_value(date_time.to_rfc3339()).unwrap())
},
)
}

fn get_date() -> impl tera::Function {
Box::new(
move |args: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {
Expand Down Expand Up @@ -485,7 +518,7 @@

let s = if delta.num_hours() > 0 {
format!(
"{:>02}:{:>02}",
"{:>02}:{:>02}:00",
delta.num_hours(),
delta.num_minutes() - (delta.num_hours() * 60)
)
Expand All @@ -497,7 +530,7 @@
num_seconds % 60
)
} else {
format!("{}s", num_seconds)
format!("00:00:{:>02}", num_seconds)
};
Ok(tera::to_value(s).unwrap())
},
Expand All @@ -505,7 +538,7 @@
}

#[cfg(test)]
mod tests {

Check failure on line 541 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Test and create coverage report.

the name `tests` is defined multiple times

use serde_json::value::Value;
use tera::Filter;
Expand Down
54 changes: 54 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use tera::Function;

use super::*;

#[test]
fn test_get_timer() {
let get_timer_func = get_timer();
let time_seconds: HashMap<String, tera::Value> = HashMap::from([
("date".to_string(), serde_json::to_value("20250501T035408Z").unwrap())
]);

let result = get_timer_func.call(&time_seconds);
assert_eq!(result.is_ok(), true);
let result_value = result.unwrap();
assert_eq!(result_value, serde_json::to_value("00:00:52").unwrap());

let time_seconds: HashMap<String, tera::Value> = HashMap::from([
("date".to_string(), serde_json::to_value("20250501T033408Z").unwrap())
]);

let result = get_timer_func.call(&time_seconds);
assert_eq!(result.is_ok(), true);
let result_value = result.unwrap();
assert_eq!(result_value, serde_json::to_value("00:20:52").unwrap());

let time_seconds: HashMap<String, tera::Value> = HashMap::from([
("date".to_string(), serde_json::to_value("20250501T023408Z").unwrap())
]);

let result = get_timer_func.call(&time_seconds);
assert_eq!(result.is_ok(), true);
let result_value = result.unwrap();
assert_eq!(result_value, serde_json::to_value("01:20:00").unwrap());
}

#[test]
fn test_get_datetime_iso() {
let get_datetime_iso_func = get_datetime_iso();
let datetime: HashMap<String, tera::Value> = HashMap::from([
("datetime".to_string(), serde_json::to_value("20250501T035408Z").unwrap())
]);
let result = get_datetime_iso_func.call(&datetime);
assert_eq!(result.is_ok(), true);
let result_value = result.unwrap();
assert_eq!(result_value, serde_json::to_value("2025-05-01T03:54:08+00:00").unwrap());

let datetime: HashMap<String, tera::Value> = HashMap::from([
("datetime".to_string(), serde_json::to_value("2025-05-01T03:54:08Z").unwrap())
]);
let result = get_datetime_iso_func.call(&datetime);
assert_eq!(result.is_ok(), true);
let result_value = result.unwrap();
assert_eq!(result_value, serde_json::to_value("2025-05-01T03:54:08+00:00").unwrap());
}
Loading