diff --git a/src/dashboard/widgets/browser_tabs.rs b/src/dashboard/widgets/browser_tabs.rs index bf6bb736..34c5c70f 100644 --- a/src/dashboard/widgets/browser_tabs.rs +++ b/src/dashboard/widgets/browser_tabs.rs @@ -20,6 +20,8 @@ fn default_refresh_interval() -> f32 { pub struct BrowserTabsConfig { #[serde(default = "default_refresh_interval")] pub refresh_interval_secs: f32, + #[serde(default)] + pub manual_refresh_only: bool, #[serde(default = "default_limit")] pub limit: usize, } @@ -28,6 +30,7 @@ impl Default for BrowserTabsConfig { fn default() -> Self { Self { refresh_interval_secs: default_refresh_interval(), + manual_refresh_only: false, limit: default_limit(), } } @@ -37,6 +40,7 @@ pub struct BrowserTabsWidget { cfg: BrowserTabsConfig, cache: TimedCache>, error: Option, + refresh_pending: bool, } impl BrowserTabsWidget { @@ -46,6 +50,7 @@ impl BrowserTabsWidget { cfg, cache: TimedCache::new(Vec::new(), interval), error: None, + refresh_pending: false, } } @@ -66,6 +71,7 @@ impl BrowserTabsWidget { changed |= refresh_interval_setting( ui, &mut cfg.refresh_interval_secs, + &mut cfg.manual_refresh_only, "Tab enumeration is cached. The widget will skip refreshing until this many seconds have passed. Use Refresh to update immediately.", ); changed @@ -89,7 +95,10 @@ impl BrowserTabsWidget { fn maybe_refresh(&mut self, ctx: &DashboardContext<'_>) { self.update_interval(); - if self.cache.should_refresh() { + if self.refresh_pending { + self.refresh_pending = false; + self.refresh(ctx); + } else if !self.cfg.manual_refresh_only && self.cache.should_refresh() { self.refresh(ctx); } } @@ -156,6 +165,7 @@ impl Widget for BrowserTabsWidget { self.cfg = cfg; self.update_interval(); self.cache.invalidate(); + self.refresh_pending = true; } } diff --git a/src/dashboard/widgets/mod.rs b/src/dashboard/widgets/mod.rs index 16d59d05..97e2dba9 100644 --- a/src/dashboard/widgets/mod.rs +++ b/src/dashboard/widgets/mod.rs @@ -541,6 +541,7 @@ impl TimedCache { pub(crate) fn refresh_interval_setting( ui: &mut egui::Ui, seconds: &mut f32, + manual_refresh_only: &mut bool, tooltip: &str, ) -> bool { let mut changed = false; @@ -556,6 +557,10 @@ pub(crate) fn refresh_interval_setting( changed |= resp.changed(); ui.label("seconds"); }); + changed |= ui + .checkbox(manual_refresh_only, "Only manual refresh") + .on_hover_text("Disable automatic refreshes. Use the Refresh button or update settings to fetch new data.") + .changed(); changed } diff --git a/src/dashboard/widgets/pinned_query_results.rs b/src/dashboard/widgets/pinned_query_results.rs index 2d151b3f..bb2f3867 100644 --- a/src/dashboard/widgets/pinned_query_results.rs +++ b/src/dashboard/widgets/pinned_query_results.rs @@ -48,6 +48,8 @@ pub struct PinnedQueryResultsConfig { #[serde(default = "default_refresh_interval")] pub refresh_interval_secs: f32, #[serde(default)] + pub manual_refresh_only: bool, + #[serde(default)] pub click_behavior: ClickBehavior, } @@ -58,6 +60,7 @@ impl Default for PinnedQueryResultsConfig { query: default_query(), limit: default_limit(), refresh_interval_secs: default_refresh_interval(), + manual_refresh_only: false, click_behavior: ClickBehavior::default(), } } @@ -67,6 +70,7 @@ pub struct PinnedQueryResultsWidget { cfg: PinnedQueryResultsConfig, cache: TimedCache>, error: Option, + refresh_pending: bool, } impl PinnedQueryResultsWidget { @@ -76,6 +80,7 @@ impl PinnedQueryResultsWidget { cfg, cache: TimedCache::new(Vec::new(), interval), error: None, + refresh_pending: false, } } @@ -208,6 +213,7 @@ impl PinnedQueryResultsWidget { changed |= refresh_interval_setting( ui, &mut cfg.refresh_interval_secs, + &mut cfg.manual_refresh_only, "Query results are cached. The widget refreshes after this many seconds unless you click Refresh.", ); @@ -255,7 +261,10 @@ impl PinnedQueryResultsWidget { fn maybe_refresh(&mut self, ctx: &DashboardContext<'_>) { self.update_interval(); - if self.cache.should_refresh() { + if self.refresh_pending { + self.refresh_pending = false; + self.refresh(ctx); + } else if !self.cfg.manual_refresh_only && self.cache.should_refresh() { self.refresh(ctx); } } @@ -375,6 +384,7 @@ impl Widget for PinnedQueryResultsWidget { self.cfg = cfg; self.update_interval(); self.cache.invalidate(); + self.refresh_pending = true; } } diff --git a/src/dashboard/widgets/process_list.rs b/src/dashboard/widgets/process_list.rs index fff254af..69c447e4 100644 --- a/src/dashboard/widgets/process_list.rs +++ b/src/dashboard/widgets/process_list.rs @@ -20,6 +20,8 @@ fn default_refresh_interval() -> f32 { pub struct ProcessesConfig { #[serde(default = "default_refresh_interval")] pub refresh_interval_secs: f32, + #[serde(default)] + pub manual_refresh_only: bool, #[serde(default = "default_limit")] pub limit: usize, } @@ -28,6 +30,7 @@ impl Default for ProcessesConfig { fn default() -> Self { Self { refresh_interval_secs: default_refresh_interval(), + manual_refresh_only: false, limit: default_limit(), } } @@ -35,11 +38,15 @@ impl Default for ProcessesConfig { pub struct ProcessesWidget { cfg: ProcessesConfig, + refresh_pending: bool, } impl ProcessesWidget { pub fn new(cfg: ProcessesConfig) -> Self { - Self { cfg } + Self { + cfg, + refresh_pending: false, + } } pub fn settings_ui( @@ -59,6 +66,7 @@ impl ProcessesWidget { changed |= refresh_interval_setting( ui, &mut cfg.refresh_interval_secs, + &mut cfg.manual_refresh_only, "Process enumeration is cached. The widget will skip refreshing until this many seconds have passed. Use Refresh to update immediately.", ); changed @@ -105,8 +113,13 @@ impl Widget for ProcessesWidget { ctx: &DashboardContext<'_>, _activation: WidgetActivation, ) -> Option { - ctx.data_cache - .maybe_refresh_processes(ctx.plugins, self.refresh_interval()); + if self.refresh_pending { + ctx.data_cache.refresh_processes(ctx.plugins); + self.refresh_pending = false; + } else if !self.cfg.manual_refresh_only { + ctx.data_cache + .maybe_refresh_processes(ctx.plugins, self.refresh_interval()); + } let snapshot = ctx.data_cache.snapshot(); if let Some(err) = &snapshot.process_error { @@ -153,6 +166,7 @@ impl Widget for ProcessesWidget { fn on_config_updated(&mut self, settings: &serde_json::Value) { if let Ok(cfg) = serde_json::from_value::(settings.clone()) { self.cfg = cfg; + self.refresh_pending = true; } } diff --git a/src/dashboard/widgets/query_list.rs b/src/dashboard/widgets/query_list.rs index a1c5c1da..ab234541 100644 --- a/src/dashboard/widgets/query_list.rs +++ b/src/dashboard/widgets/query_list.rs @@ -24,6 +24,8 @@ fn default_show_desc() -> bool { pub struct QueryListConfig { #[serde(default = "default_refresh_ms")] pub refresh_ms: u64, + #[serde(default)] + pub manual_refresh_only: bool, #[serde(default = "default_count")] pub count: usize, #[serde(default = "default_show_desc")] @@ -36,6 +38,7 @@ impl Default for QueryListConfig { fn default() -> Self { Self { refresh_ms: default_refresh_ms(), + manual_refresh_only: false, count: default_count(), show_desc: true, query: String::new(), @@ -47,6 +50,7 @@ pub struct QueryListWidget { cfg: QueryListConfig, cache: TimedCache>, last_query: String, + refresh_pending: bool, } impl QueryListWidget { @@ -57,6 +61,7 @@ impl QueryListWidget { cfg, cache: TimedCache::new(Vec::new(), interval), last_query, + refresh_pending: false, } } @@ -82,6 +87,7 @@ impl QueryListWidget { changed |= refresh_interval_setting( ui, &mut refresh_secs, + &mut cfg.manual_refresh_only, "Results are cached between refreshes.", ); cfg.refresh_ms = (refresh_secs * 1000.0) as u64; @@ -108,9 +114,12 @@ impl QueryListWidget { self.cache.set_interval(self.refresh_interval()); if self.last_query != self.cfg.query { self.last_query = self.cfg.query.clone(); - self.cache.invalidate(); + self.refresh_pending = true; } - if self.cache.should_refresh() { + if self.refresh_pending { + self.refresh_pending = false; + self.refresh(ctx); + } else if !self.cfg.manual_refresh_only && self.cache.should_refresh() { self.refresh(ctx); } } @@ -173,6 +182,7 @@ impl Widget for QueryListWidget { self.cfg = cfg; self.cache.set_interval(self.refresh_interval()); self.cache.invalidate(); + self.refresh_pending = true; } } diff --git a/src/dashboard/widgets/system_actions.rs b/src/dashboard/widgets/system_actions.rs index 5f666849..abbbdb17 100644 --- a/src/dashboard/widgets/system_actions.rs +++ b/src/dashboard/widgets/system_actions.rs @@ -16,12 +16,15 @@ fn default_refresh_interval() -> f32 { pub struct SystemConfig { #[serde(default = "default_refresh_interval")] pub refresh_interval_secs: f32, + #[serde(default)] + pub manual_refresh_only: bool, } impl Default for SystemConfig { fn default() -> Self { Self { refresh_interval_secs: default_refresh_interval(), + manual_refresh_only: false, } } } @@ -30,6 +33,7 @@ pub struct SystemWidget { cfg: SystemConfig, cache: TimedCache>, error: Option, + refresh_pending: bool, } impl SystemWidget { @@ -39,6 +43,7 @@ impl SystemWidget { cfg, cache: TimedCache::new(Vec::new(), interval), error: None, + refresh_pending: false, } } @@ -51,6 +56,7 @@ impl SystemWidget { refresh_interval_setting( ui, &mut cfg.refresh_interval_secs, + &mut cfg.manual_refresh_only, "System actions are cached. The widget will skip refreshing until this many seconds have passed. Use Refresh to update immediately.", ) }) @@ -73,7 +79,10 @@ impl SystemWidget { fn maybe_refresh(&mut self, ctx: &DashboardContext<'_>) { self.update_interval(); - if self.cache.should_refresh() { + if self.refresh_pending { + self.refresh_pending = false; + self.refresh(ctx); + } else if !self.cfg.manual_refresh_only && self.cache.should_refresh() { self.refresh(ctx); } } @@ -128,6 +137,7 @@ impl Widget for SystemWidget { self.cfg = cfg; self.update_interval(); self.cache.invalidate(); + self.refresh_pending = true; } } diff --git a/src/dashboard/widgets/system_status.rs b/src/dashboard/widgets/system_status.rs index 3248c618..46af2ee4 100644 --- a/src/dashboard/widgets/system_status.rs +++ b/src/dashboard/widgets/system_status.rs @@ -19,6 +19,8 @@ fn default_true() -> bool { pub struct SystemStatusConfig { #[serde(default = "default_refresh_interval")] pub refresh_interval_secs: f32, + #[serde(default)] + pub manual_refresh_only: bool, #[serde(default = "default_true")] pub show_cpu: bool, #[serde(default = "default_true")] @@ -37,6 +39,7 @@ impl Default for SystemStatusConfig { fn default() -> Self { Self { refresh_interval_secs: default_refresh_interval(), + manual_refresh_only: false, show_cpu: true, show_memory: true, show_disk: true, @@ -49,11 +52,15 @@ impl Default for SystemStatusConfig { pub struct SystemStatusWidget { cfg: SystemStatusConfig, + refresh_pending: bool, } impl SystemStatusWidget { pub fn new(cfg: SystemStatusConfig) -> Self { - Self { cfg } + Self { + cfg, + refresh_pending: false, + } } pub fn settings_ui( @@ -66,6 +73,7 @@ impl SystemStatusWidget { changed |= refresh_interval_setting( ui, &mut cfg.refresh_interval_secs, + &mut cfg.manual_refresh_only, "System stats are cached between refreshes.", ); ui.separator(); @@ -110,8 +118,13 @@ impl Widget for SystemStatusWidget { ctx: &DashboardContext<'_>, _activation: WidgetActivation, ) -> Option { - ctx.data_cache - .maybe_refresh_system_status(self.refresh_interval()); + if self.refresh_pending { + ctx.data_cache.refresh_system_status(); + self.refresh_pending = false; + } else if !self.cfg.manual_refresh_only { + ctx.data_cache + .maybe_refresh_system_status(self.refresh_interval()); + } let snapshot = ctx.data_cache.snapshot(); let Some(status) = snapshot.system_status.as_ref() else { ui.label("System data unavailable."); @@ -154,6 +167,7 @@ impl Widget for SystemStatusWidget { fn on_config_updated(&mut self, settings: &serde_json::Value) { if let Ok(cfg) = serde_json::from_value::(settings.clone()) { self.cfg = cfg; + self.refresh_pending = true; } } } diff --git a/src/dashboard/widgets/window_list.rs b/src/dashboard/widgets/window_list.rs index 5760a10a..3bccf7f9 100644 --- a/src/dashboard/widgets/window_list.rs +++ b/src/dashboard/widgets/window_list.rs @@ -20,6 +20,8 @@ fn default_refresh_interval() -> f32 { pub struct WindowsConfig { #[serde(default = "default_refresh_interval")] pub refresh_interval_secs: f32, + #[serde(default)] + pub manual_refresh_only: bool, #[serde(default = "default_limit")] pub limit: usize, } @@ -28,6 +30,7 @@ impl Default for WindowsConfig { fn default() -> Self { Self { refresh_interval_secs: default_refresh_interval(), + manual_refresh_only: false, limit: default_limit(), } } @@ -37,6 +40,7 @@ pub struct WindowsWidget { cfg: WindowsConfig, cache: TimedCache>, error: Option, + refresh_pending: bool, } impl WindowsWidget { @@ -46,6 +50,7 @@ impl WindowsWidget { cfg, cache: TimedCache::new(Vec::new(), interval), error: None, + refresh_pending: false, } } @@ -66,6 +71,7 @@ impl WindowsWidget { changed |= refresh_interval_setting( ui, &mut cfg.refresh_interval_secs, + &mut cfg.manual_refresh_only, "Window enumeration is cached. The widget will skip refreshing until this many seconds have passed. Use Refresh to update immediately.", ); changed @@ -89,7 +95,10 @@ impl WindowsWidget { fn maybe_refresh(&mut self, ctx: &DashboardContext<'_>) { self.update_interval(); - if self.cache.should_refresh() { + if self.refresh_pending { + self.refresh_pending = false; + self.refresh(ctx); + } else if !self.cfg.manual_refresh_only && self.cache.should_refresh() { self.refresh(ctx); } } @@ -183,6 +192,7 @@ impl Widget for WindowsWidget { self.cfg = cfg; self.update_interval(); self.cache.invalidate(); + self.refresh_pending = true; } } diff --git a/src/dashboard/widgets/windows_overview.rs b/src/dashboard/widgets/windows_overview.rs index 19c9c029..a9b5fdbc 100644 --- a/src/dashboard/widgets/windows_overview.rs +++ b/src/dashboard/widgets/windows_overview.rs @@ -24,6 +24,8 @@ fn default_true() -> bool { pub struct WindowsOverviewConfig { #[serde(default = "default_refresh_interval")] pub refresh_interval_secs: f32, + #[serde(default)] + pub manual_refresh_only: bool, #[serde(default = "default_limit")] pub limit: usize, #[serde(default = "default_true")] @@ -34,6 +36,7 @@ impl Default for WindowsOverviewConfig { fn default() -> Self { Self { refresh_interval_secs: default_refresh_interval(), + manual_refresh_only: false, limit: default_limit(), show_close: true, } @@ -44,6 +47,7 @@ pub struct WindowsOverviewWidget { cfg: WindowsOverviewConfig, cache: TimedCache>, error: Option, + refresh_pending: bool, } impl WindowsOverviewWidget { @@ -53,6 +57,7 @@ impl WindowsOverviewWidget { cfg, cache: TimedCache::new(Vec::new(), interval), error: None, + refresh_pending: false, } } @@ -74,6 +79,7 @@ impl WindowsOverviewWidget { changed |= refresh_interval_setting( ui, &mut cfg.refresh_interval_secs, + &mut cfg.manual_refresh_only, "Window enumeration is cached. The widget will skip refreshing until this many seconds have passed. Use Refresh to update immediately.", ); changed @@ -97,7 +103,10 @@ impl WindowsOverviewWidget { fn maybe_refresh(&mut self, ctx: &DashboardContext<'_>) { self.update_interval(); - if self.cache.should_refresh() { + if self.refresh_pending { + self.refresh_pending = false; + self.refresh(ctx); + } else if !self.cfg.manual_refresh_only && self.cache.should_refresh() { self.refresh(ctx); } } @@ -193,6 +202,7 @@ impl Widget for WindowsOverviewWidget { self.cfg = cfg; self.update_interval(); self.cache.invalidate(); + self.refresh_pending = true; } }