diff --git a/cmd/server/db.go b/cmd/server/db.go index 8719f2d..71021b5 100644 --- a/cmd/server/db.go +++ b/cmd/server/db.go @@ -1781,6 +1781,7 @@ func (db *DB) GetObserverMetrics(observerID, since, until string) ([]MetricsSamp type MetricsSummaryRow struct { ObserverID string `json:"observer_id"` ObserverName *string `json:"observer_name"` + IATA string `json:"iata,omitempty"` CurrentNF *float64 `json:"current_noise_floor"` AvgNF *float64 `json:"avg_noise_floor_24h"` MaxNF *float64 `json:"max_noise_floor_24h"` @@ -1800,7 +1801,7 @@ func (db *DB) GetMetricsSummary(since string) ([]MetricsSummaryRow, error) { FROM observer_metrics WHERE timestamp >= ? ) - SELECT m.observer_id, o.name, + SELECT m.observer_id, o.name, COALESCE(o.iata, '') as iata, r.noise_floor as current_nf, AVG(m.noise_floor) as avg_nf, MAX(m.noise_floor) as max_nf, @@ -1822,7 +1823,7 @@ func (db *DB) GetMetricsSummary(since string) ([]MetricsSummaryRow, error) { var result []MetricsSummaryRow for rows.Next() { var s MetricsSummaryRow - if err := rows.Scan(&s.ObserverID, &s.ObserverName, &s.CurrentNF, &s.AvgNF, &s.MaxNF, &s.CurrentBattMv, &s.SampleCount); err != nil { + if err := rows.Scan(&s.ObserverID, &s.ObserverName, &s.IATA, &s.CurrentNF, &s.AvgNF, &s.MaxNF, &s.CurrentBattMv, &s.SampleCount); err != nil { return nil, err } result = append(result, s) diff --git a/cmd/server/routes.go b/cmd/server/routes.go index 4ef2de8..bcadc15 100644 --- a/cmd/server/routes.go +++ b/cmd/server/routes.go @@ -2193,6 +2193,7 @@ func (s *Server) handleMetricsSummary(w http.ResponseWriter, r *http.Request) { if window == "" { window = "24h" } + region := r.URL.Query().Get("region") // Parse window duration dur, err := parseWindowDuration(window) @@ -2211,6 +2212,17 @@ func (s *Server) handleMetricsSummary(w http.ResponseWriter, r *http.Request) { summary = []MetricsSummaryRow{} } + // Filter by region if specified + if region != "" { + filtered := make([]MetricsSummaryRow, 0) + for _, row := range summary { + if strings.EqualFold(row.IATA, region) { + filtered = append(filtered, row) + } + } + summary = filtered + } + writeJSON(w, map[string]interface{}{ "observers": summary, }) diff --git a/public/analytics.js b/public/analytics.js index 55e2a56..2a29ead 100644 --- a/public/analytics.js +++ b/public/analytics.js @@ -2700,7 +2700,7 @@ function destroy() { _analyticsData = {}; _channelData = null; if (_ngState && _ // Compute window string for summary endpoint const windowMap = { '1h':'1h', '3h':'3h', '6h':'6h', '12h':'12h', '24h':'24h', '3d':'3d', '7d':'7d', '30d':'30d' }; const window = windowMap[_rfHealthState.range] || '24h'; - const summaryData = await api('/observers/metrics/summary?window=' + window); + const summaryData = await api('/observers/metrics/summary?window=' + window + (RegionFilter.regionQueryString() || '')); const observers = summaryData.observers || []; // Filter to observers with sufficient sparkline data (≥2 non-null noise_floor values)