feat(monitor): add search, status filter, and bulk invalid toggle

- Add search input to filter alerts by alertName or label values
- Add status filter dropdown (All/Resolved/Unresolved)
- Add Select All checkbox with indeterminate state for bulk invalid toggle
- Add indeterminate prop support to Checkbox component
- Add Monitor link to header navigation
- Fix KPI dashboard padding for empty state
This commit is contained in:
Syahdan 2025-12-29 07:12:31 +07:00
parent 22aee93fb3
commit c145d3fb07
8 changed files with 155 additions and 21 deletions

View file

@ -106,6 +106,31 @@ pub struct ProcessedAlert {
pub is_invalid: bool,
pub attached_incident_id: Option<String>,
pub values: HashMap<String, f64>,
pub labels: HashMap<String, String>,
}
fn parse_labels_from_text(text: &str) -> HashMap<String, String> {
let mut labels = HashMap::new();
if let Some(start) = text.find('{') {
if let Some(end) = text.rfind('}') {
if start < end {
let content = &text[start + 1..end];
for pair in content.split(',') {
let pair = pair.trim();
if let Some(eq_pos) = pair.find('=') {
let key = pair[..eq_pos].trim().to_string();
let value = pair[eq_pos + 1..].trim().to_string();
if !key.is_empty() {
labels.insert(key, value);
}
}
}
}
}
}
labels
}
pub fn pair_alerts(raw_alerts: Vec<GrafanaAlert>) -> Vec<ProcessedAlert> {
@ -126,6 +151,8 @@ pub fn pair_alerts(raw_alerts: Vec<GrafanaAlert>) -> Vec<ProcessedAlert> {
let current = &alerts[i];
if current.new_state == "Alerting" {
let labels = parse_labels_from_text(&current.text);
if i + 1 < alerts.len() && alerts[i + 1].new_state == "Normal" {
let resolve = &alerts[i + 1];
let duration_ms = resolve.time.saturating_sub(current.time);
@ -142,6 +169,7 @@ pub fn pair_alerts(raw_alerts: Vec<GrafanaAlert>) -> Vec<ProcessedAlert> {
is_invalid: false,
attached_incident_id: None,
values: current.data.clone().map(|d| d.values).unwrap_or_default(),
labels,
});
i += 2;
} else {
@ -157,6 +185,7 @@ pub fn pair_alerts(raw_alerts: Vec<GrafanaAlert>) -> Vec<ProcessedAlert> {
is_invalid: false,
attached_incident_id: None,
values: current.data.clone().map(|d| d.values).unwrap_or_default(),
labels,
});
i += 1;
}
@ -208,7 +237,7 @@ pub fn calculate_kpis(alerts: &[ProcessedAlert], incidents: &[Incident]) -> KpiM
let overall_downtime_ms: u64 = alerts
.iter()
.filter(|a| !a.is_invalid)
.filter(|a| !a.is_invalid && a.attached_incident_id.is_some())
.map(|a| a.duration_ms)
.sum();