app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit e257818f68174fb537741369704be17243790e4e
parent 95f0b2a4ff18ad4f3212a6025fd7a0646199f9dd
Author: triesap <triesap@radroots.dev>
Date:   Tue, 20 Jan 2026 15:52:55 +0000

app: add logs auto-refresh

- add refresh interval constant and helper

- wire gloo-timers interval to refresh logs list

- keep manual refresh button behavior

- add unit test for refresh interval helper

Diffstat:
MCargo.lock | 1+
Mapp/Cargo.toml | 1+
Mapp/src/logs.rs | 28++++++++++++++++++++++++++++
3 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -1643,6 +1643,7 @@ dependencies = [ "async-trait", "console_error_panic_hook", "futures", + "gloo-timers", "js-sys", "leptos", "leptos_router", diff --git a/app/Cargo.toml b/app/Cargo.toml @@ -16,6 +16,7 @@ wasm-bindgen.workspace = true wasm-bindgen-futures.workspace = true js-sys.workspace = true web-sys.workspace = true +gloo-timers.workspace = true radroots-app-core = { path = "../crates/core" } radroots-log = { path = "../refs/crates/log", default-features = false } tracing-wasm = "0.2" diff --git a/app/src/logs.rs b/app/src/logs.rs @@ -1,5 +1,6 @@ #![forbid(unsafe_code)] +use gloo_timers::callback::Interval; use leptos::prelude::*; use leptos::task::spawn_local; use std::rc::Rc; @@ -16,6 +17,12 @@ use crate::{ AppLogLevel, }; +const LOGS_AUTO_REFRESH_MS: u32 = 5000; + +fn logs_auto_refresh_ms() -> u32 { + LOGS_AUTO_REFRESH_MS +} + fn log_level_color(level: AppLogLevel) -> &'static str { match level { AppLogLevel::Debug => "#6b7280", @@ -31,6 +38,7 @@ pub fn LogsPage() -> impl IntoView { let dump = RwSignal::new_local(String::new()); let loading = RwSignal::new_local(false); let did_load = RwSignal::new_local(false); + let interval_started = RwSignal::new_local(false); let context = Rc::new(app_context()); let refresh = { let context = Rc::clone(&context); @@ -105,6 +113,16 @@ pub fn LogsPage() -> impl IntoView { did_load.set(true); refresh_effect(); }); + let interval_effect = Rc::clone(&refresh); + Effect::new(move || { + if interval_started.get() { + return; + } + interval_started.set(true); + let refresh = Rc::clone(&interval_effect); + let interval = Interval::new(logs_auto_refresh_ms(), move || refresh()); + interval.forget(); + }); let status_label = move || if loading.get() { "loading" } else { "idle" }; view! { <main> @@ -173,3 +191,13 @@ pub fn LogsPage() -> impl IntoView { </main> } } + +#[cfg(test)] +mod tests { + use super::logs_auto_refresh_ms; + + #[test] + fn logs_auto_refresh_is_positive() { + assert!(logs_auto_refresh_ms() > 0); + } +}