feat(map): self-hosted PMTiles map tiles, remove alert toast spam
- Replace OpenStreetMap CDN with self-hosted Protomaps PMTiles (Wisconsin + Florida regional extracts, served from nginx) - Add protomaps-leaflet for vector tile rendering in dark theme - Update CSP to remove openstreetmap.org, add blob: for vector workers - Add nginx location block for /tiles/ with byte range support - Mount tiles directory as volume (not baked into image) - Remove alert_fired/alert_resolved toast notifications that spammed "undefined" at fleet scale — dashboard still updates via query invalidation - Add *.pmtiles to .gitignore (large binaries) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ import { useCallback } from 'react'
|
||||
import { createFileRoute, Outlet, Navigate, redirect, useNavigate, useRouterState } from '@tanstack/react-router'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { AnimatePresence } from 'framer-motion'
|
||||
import { toast } from 'sonner'
|
||||
// toast import removed — alert toasts were noisy at fleet scale
|
||||
import { useAuth } from '@/lib/auth'
|
||||
import { useUIStore } from '@/lib/store'
|
||||
import { useEventStream, type SSEEvent } from '@/hooks/useEventStream'
|
||||
@@ -72,27 +72,8 @@ function AuthenticatedLayout() {
|
||||
|
||||
// ── Alert fired (RT-03) ───────────────────────────────────────────
|
||||
case 'alert_fired': {
|
||||
const { severity, rule_name, device_name, metric, current_value, threshold } =
|
||||
event.data as {
|
||||
severity: string
|
||||
rule_name: string
|
||||
device_name?: string
|
||||
metric?: string
|
||||
current_value?: string | number
|
||||
threshold?: string | number
|
||||
}
|
||||
const toastFn =
|
||||
severity === 'critical'
|
||||
? toast.error
|
||||
: severity === 'warning'
|
||||
? toast.warning
|
||||
: toast.info
|
||||
toastFn(`Alert: ${rule_name}`, {
|
||||
description: device_name
|
||||
? `${device_name} — ${metric ?? 'unknown'}: ${current_value ?? '?'} (threshold: ${threshold ?? '?'})`
|
||||
: `${metric ?? 'unknown'}: ${current_value ?? '?'}`,
|
||||
duration: severity === 'critical' ? 10000 : 5000,
|
||||
})
|
||||
// Invalidate alert queries so dashboard/alert pages update in real-time.
|
||||
// No toast — at fleet scale these fire constantly and become noise.
|
||||
void queryClient.invalidateQueries({ queryKey: ['active-alerts'] })
|
||||
void queryClient.invalidateQueries({ queryKey: ['alert-events'] })
|
||||
void queryClient.invalidateQueries({ queryKey: ['dashboard-alerts'] })
|
||||
@@ -101,14 +82,6 @@ function AuthenticatedLayout() {
|
||||
|
||||
// ── Alert resolved ────────────────────────────────────────────────
|
||||
case 'alert_resolved': {
|
||||
const { metric } = event.data as {
|
||||
device_id?: string
|
||||
metric?: string
|
||||
}
|
||||
toast.info('Alert resolved', {
|
||||
description: `${metric ?? 'Condition'} returned to normal`,
|
||||
duration: 3000,
|
||||
})
|
||||
void queryClient.invalidateQueries({ queryKey: ['active-alerts'] })
|
||||
void queryClient.invalidateQueries({ queryKey: ['alert-events'] })
|
||||
void queryClient.invalidateQueries({ queryKey: ['dashboard-alerts'] })
|
||||
|
||||
Reference in New Issue
Block a user