Fix notification system with proper rate limiting and aggregation
All checks were successful
Build and Release / build-and-release (push) Successful in 1m51s

- Add rate limiting using rate_limit_minutes config (was ignored)
- Add aggregation using aggregation_interval_seconds config (was ignored)
- Use smtp_host and smtp_port from config (was hardcoded localhost:25)
- Add trigger_on_warnings and trigger_on_failures config options
- Add recovery_requires_all_ok and suppress_individual_recoveries
- Use check_interval_seconds from config (was hardcoded 30s)
- Expand status tracking to all components (drives, pools, services, backup)
- Move notification checks from every collection to dedicated interval
- Separate alert and recovery notifications with proper email formatting
- Only notify on failed services (Critical), not inactive
This commit is contained in:
2025-12-15 13:44:06 +01:00
parent 516d159d2f
commit 76931f0457
9 changed files with 572 additions and 135 deletions

View File

@@ -514,14 +514,6 @@ impl TuiApp {
true // No host selected is considered offline
};
// If host is offline, render wake-up message instead of panels
if current_host_offline {
self.render_offline_host_message(frame, main_chunks[1]);
self.render_btop_title(frame, main_chunks[0], metric_store);
self.render_statusbar(frame, main_chunks[2], metric_store);
return (main_chunks[0], Rect::default(), Rect::default()); // Return title area and empty areas when offline
}
// Left side: system panel only (full height)
let left_chunks = ratatui::layout::Layout::default()
.direction(Direction::Vertical)
@@ -531,9 +523,13 @@ impl TuiApp {
// Render title bar
self.render_btop_title(frame, main_chunks[0], metric_store);
// Render system panel
// Render system panel or offline message in system panel area
let system_area = left_chunks[0];
self.render_system_panel(frame, system_area, metric_store);
if current_host_offline {
self.render_offline_host_message(frame, system_area);
} else {
self.render_system_panel(frame, system_area, metric_store);
}
// Render right panel with tabs (Services | Hosts)
let services_area = content_chunks[1];
@@ -829,9 +825,8 @@ impl TuiApp {
}
/// Render offline host message with wake-up option
/// Render offline host message in system panel area
fn render_offline_host_message(&self, frame: &mut Frame, area: Rect) {
use ratatui::layout::Alignment;
use ratatui::style::Modifier;
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Paragraph};
@@ -849,8 +844,9 @@ impl TuiApp {
// Create message content
let mut lines = vec![
Line::from(""),
Line::from(Span::styled(
format!("Host '{}' is offline", hostname),
format!(" Host '{}' is offline", hostname),
Style::default().fg(Theme::muted_text()).add_modifier(Modifier::BOLD),
)),
Line::from(""),
@@ -858,46 +854,26 @@ impl TuiApp {
if has_mac {
lines.push(Line::from(Span::styled(
"Press 'w' to wake up host",
Style::default().fg(Theme::primary_text()).add_modifier(Modifier::BOLD),
" Press 'w' to wake up host",
Style::default().fg(Theme::primary_text()),
)));
} else {
lines.push(Line::from(Span::styled(
"No MAC address configured - cannot wake up",
" No MAC address configured",
Style::default().fg(Theme::muted_text()),
)));
}
// Create centered message
// Render message in system panel with border
let message = Paragraph::new(lines)
.block(Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(Theme::muted_text()))
.title(" Offline Host ")
.title(" Offline ")
.title_style(Style::default().fg(Theme::muted_text()).add_modifier(Modifier::BOLD)))
.style(Style::default().bg(Theme::background()).fg(Theme::primary_text()))
.alignment(Alignment::Center);
.style(Style::default().bg(Theme::background()).fg(Theme::primary_text()));
// Center the message in the available area
let popup_area = ratatui::layout::Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Percentage(40),
Constraint::Length(6),
Constraint::Percentage(40),
])
.split(area)[1];
let popup_area = ratatui::layout::Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage(25),
Constraint::Percentage(50),
Constraint::Percentage(25),
])
.split(popup_area)[1];
frame.render_widget(message, popup_area);
frame.render_widget(message, area);
}
/// Parse MAC address string (e.g., "AA:BB:CC:DD:EE:FF") to [u8; 6]