From 20b5f32c7158fb7c68c47e4215d21b780889f45e Mon Sep 17 00:00:00 2001 From: didier amyot Date: Sun, 9 Apr 2023 06:38:07 -0400 Subject: [PATCH] Implemented better ui. --- Cargo.lock | 306 ++++++++++++++++++++++++++-- Cargo.toml | 1 + resources/templates/account.html | 6 +- resources/templates/accounts.html | 6 +- resources/templates/securities.html | 2 +- src/db/_external_id.rs | 29 ++- src/webui/minininja_utils.rs | 95 ++++++--- src/webui/mod.rs | 3 + 8 files changed, 399 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9ca8572..5d71352 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,7 +190,7 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2", - "time", + "time 0.3.17", "url", ] @@ -350,6 +350,15 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "apache-avro" version = "0.14.0" @@ -487,6 +496,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + [[package]] name = "byteorder" version = "1.4.3" @@ -523,6 +538,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time 0.1.45", + "wasm-bindgen", + "winapi", +] + [[package]] name = "cipher" version = "0.4.3" @@ -580,6 +610,16 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "colored" version = "2.0.0" @@ -620,10 +660,16 @@ dependencies = [ "rand", "sha2", "subtle", - "time", + "time 0.3.17", "version_check", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + [[package]] name = "cpufeatures" version = "0.2.5" @@ -693,6 +739,50 @@ dependencies = [ "cipher", ] +[[package]] +name = "cxx" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -743,6 +833,7 @@ dependencies = [ "apache-avro", "async-channel", "base64 0.21.0", + "chrono", "clap", "clap-verbosity-flag", "cookie", @@ -958,7 +1049,7 @@ checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -1100,6 +1191,30 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "iana-time-zone" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "idna" version = "0.3.0" @@ -1194,6 +1309,15 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "kqueue" version = "1.0.7" @@ -1263,6 +1387,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + [[package]] name = "local-channel" version = "0.1.3" @@ -1373,7 +1506,7 @@ checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys", ] @@ -1789,6 +1922,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" + [[package]] name = "self_cell" version = "0.10.2" @@ -1907,7 +2046,7 @@ dependencies = [ "atty", "colored", "log", - "time", + "time 0.3.17", "windows-sys", ] @@ -2021,6 +2160,17 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + [[package]] name = "time" version = "0.3.17" @@ -2190,6 +2340,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + [[package]] name = "universal-hash" version = "0.5.0" @@ -2244,12 +2400,72 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + [[package]] name = "winapi" version = "0.3.9" @@ -2281,19 +2497,43 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.0", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm 0.42.0", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] @@ -2302,42 +2542,84 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "zerocopy" version = "0.6.1" diff --git a/Cargo.toml b/Cargo.toml index be67032..2a56655 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ async-channel = "1.8.0" base64 = "0.21.0" r2d2_sqlite = "0.21.0" r2d2 = "0.8.10" +chrono = "0.4.24" [dependencies.uuid] version = "1.3.0" diff --git a/resources/templates/account.html b/resources/templates/account.html index c88f976..0f36d73 100644 --- a/resources/templates/account.html +++ b/resources/templates/account.html @@ -7,11 +7,11 @@ - + - + - +
Summary
ID{{ account.id }}
ID{{ account.id | micro_id }}
Label{{ account.label }}
Amount{{ account.amount }}
Amount{{ account.amount | thousand_separator }}
Account Type{{ account.account_type | replace("_", " ") | lower}}
Last Update{{ account.last_update }}
Last Update{{ account.last_update | utc_date }}
Security{{ account.security.symbol }}
diff --git a/resources/templates/accounts.html b/resources/templates/accounts.html index 486d6c1..0d27a1e 100644 --- a/resources/templates/accounts.html +++ b/resources/templates/accounts.html @@ -21,11 +21,11 @@ {% for account in accounts %} - {{ account.id }} + {{ account.id | micro_id}} {{ account.label }} - {{ account.amount }} + {{ account.amount | thousand_separator }} {{ account.account_type | replace("_", " ") | lower}} - {{ account.last_update }} + {{ account.last_update | utc_date }} {{ account.security.symbol }} {% endfor %} diff --git a/resources/templates/securities.html b/resources/templates/securities.html index d91d10d..51f9a34 100644 --- a/resources/templates/securities.html +++ b/resources/templates/securities.html @@ -20,7 +20,7 @@ {% for sec in securities %} - {{ sec.id }} + {{ sec.id | micro_id }} {{ sec.name }} {{ sec.symbol }} {{ sec.security_type }} diff --git a/src/db/_external_id.rs b/src/db/_external_id.rs index aabb68e..d5a2be4 100644 --- a/src/db/_external_id.rs +++ b/src/db/_external_id.rs @@ -2,6 +2,7 @@ use std::fmt; use regex::{Captures, Regex}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use sha2::{Sha256, Digest}; #[derive(PartialEq, Debug, Clone, Serialize, Deserialize)] struct SafeId { @@ -15,6 +16,7 @@ pub trait Id { fn from_string(s: &String) -> Option; fn from_id(id: i64) -> Self::Output; fn get_id(&self) -> i64; + fn micro_id(&self) -> String; } impl fmt::Display for SafeId { @@ -58,6 +60,13 @@ impl Id for SafeId { fn get_id(&self) -> i64 { return i64::from_be_bytes(self.encrypted_id); } + + fn micro_id(&self) -> String { + let mut hasher = Sha256::new(); + hasher.update(self.encrypted_id.as_slice()); + let ret = hex::encode(hasher.finalize()); + ret.get(0..6).unwrap_or(ret.as_str()).to_string() + } } macro_rules! impl_ids { @@ -100,6 +109,10 @@ macro_rules! impl_ids { fn get_id(&self) -> i64 { self.0.get_id() } + + fn micro_id(&self) -> String { + format!("{}-{}", $prefix, self.0.micro_id()) + } } @@ -136,7 +149,7 @@ impl_ids!(UserId, "u"); impl_ids!(SecurityId, "s"); #[derive(PartialEq, Debug)] -enum ExternalId { // todo: perhaps this abstraction is useless.. duno +pub enum ExternalId { AccountId(AccountId), UserId(UserId), SecurityId(SecurityId), @@ -185,6 +198,14 @@ impl ExternalId { ExternalId::SecurityId(x) => x.get_id(), } } + + pub fn micro_id(&self) -> String{ + match self{ + ExternalId::UserId(sid) => sid.micro_id(), + ExternalId::AccountId(sid) => sid.micro_id(), + ExternalId::SecurityId(sid) => sid.micro_id(), + } + } } #[cfg(test)] @@ -209,6 +230,12 @@ pub mod test_external_ids { ); } + #[test] + fn test_micro_id() { + let sid = SecurityId::from_id(33); + assert_eq!(sid.micro_id(), "s-ea676268") + } + #[test] fn safe_id_happy_path_1() { let sid = SafeId { diff --git a/src/webui/minininja_utils.rs b/src/webui/minininja_utils.rs index 9b65638..8da541b 100644 --- a/src/webui/minininja_utils.rs +++ b/src/webui/minininja_utils.rs @@ -1,30 +1,67 @@ +use chrono::{DateTime, NaiveDateTime, Utc}; use regex::Regex; -// -// fn is_number(value: String) -> bool{ -// true -// } -// -// fn pretty_number(value: String) -> String { -// let re = Regex::new(r"\d+").unwrap(); -// let cap = re.captures(&value); -// if cap.is_none() { -// return value; -// } -// let mut ret = "".to_string(); -// for (idx, letter) in value.as_bytes().iter().enumerate() { -// ret.push(letter); -// } -// "foo".to_string() -// -// } -// -// -// #[cfg(test)] -// pub mod test_minininja_utils { -// use super::*; -// -// #[test] -// fn test_pretty_number() { -// assert_eq!(pretty_number("foo".to_string()), "foo"); -// } -// } +use lazy_static::lazy_static; +use crate::db::external_id::ExternalId; + + +pub fn add_thousand_separators(value: String) -> String { + lazy_static! { + static ref is_number: Regex = Regex::new(r"\d+").unwrap(); + } + let cap = is_number.captures(&value); + if cap.is_none() { + return value; + } + let start = value.len() % 3; + let n_blocks = value.len() / 3; + let mut ret = String::new(); + ret += value.get(0..start).unwrap_or(""); + for i in 0..n_blocks { + ret += " "; + ret += value.get((start + i * 3)..(start + (i + 1) * 3)).unwrap_or(""); + } + ret +} + + +pub fn utc_date(value: String) -> String { + let timestamp = value.parse::(); + if timestamp.is_err() { + return value; + } + let naive = NaiveDateTime::from_timestamp_opt(timestamp.unwrap(), 0); + if naive.is_none() { + return value; + } + let datetime: DateTime = DateTime::from_utc(naive.unwrap(), Utc); + + datetime.format("%Y-%m-%d %H:%M:%S").to_string() +} + +pub fn micro_id(value: String) -> String { + ExternalId::from_string(&value).map(|id| id.micro_id()).unwrap_or(value) + +} + +#[cfg(test)] +pub mod test_minininja_utils { + use super::*; + + #[test] + fn test_add_thousand_separator() { + assert_eq!(add_thousand_separators("foo".to_string()), "foo"); + assert_eq!(add_thousand_separators("💖💖".to_string()), "💖💖"); + assert_eq!(add_thousand_separators("10".to_string()), "10"); + assert_eq!(add_thousand_separators("1000".to_string()), "1 000"); + assert_eq!(add_thousand_separators("1000".to_string()), "1 000"); + assert_eq!(add_thousand_separators("12345".to_string()), "12 345"); + assert_eq!(add_thousand_separators("12345678901234".to_string()), "12 345 678 901 234"); + } + + #[test] + fn test_utc_date() { + assert_eq!(utc_date("foo".to_string()), "foo"); + assert_eq!(utc_date("💖💖".to_string()), "💖💖"); + assert_eq!(utc_date("1524820690".to_string()), "2018-04-27 09:18:10"); + } +} diff --git a/src/webui/mod.rs b/src/webui/mod.rs index 90f9a22..8aeb540 100644 --- a/src/webui/mod.rs +++ b/src/webui/mod.rs @@ -49,6 +49,9 @@ fn create_auto_reloader(enable_template_autoreload: bool) -> AutoReloader { notifier.watch_path(&tmpl_path, true); } env.set_source(minijinja::Source::from_path(tmpl_path)); + env.add_filter("thousand_separator", minininja_utils::add_thousand_separators); + env.add_filter("utc_date", minininja_utils::utc_date); + env.add_filter("micro_id", minininja_utils::micro_id); Ok(env) }) }