mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-05-21 23:24:44 +02:00
refactor: simplify severity to 3 levels (routine/priority/immediate)
- Replace 6-level system (info/advisory/watch/warning/critical/emergency) with 3-level military precedence (routine/priority/immediate) - Every adapter remapped: NWS, NIFC, FIRMS, USGS, SWPC, avalanche, traffic, 511, mesh alerts - is_critical flag removed — severity covers it - Quiet hours: suppress routine only, priority+immediate always deliver - Dashboard: blue/amber/red for routine/priority/immediate - Fix hex node ID parsing in Mesh DM channel (!23261b70 format)
This commit is contained in:
parent
5b78e38d2e
commit
49f2838048
17 changed files with 3285 additions and 3265 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -82,28 +82,37 @@ function FeedStatusCard({ feed }: { feed: { source: string; is_loaded: boolean;
|
|||
function AlertEventCard({ event }: { event: EnvEvent }) {
|
||||
const getSeverityStyles = (severity: string) => {
|
||||
switch (severity.toLowerCase()) {
|
||||
// NWS native severity levels
|
||||
case 'extreme':
|
||||
case 'severe':
|
||||
// Our 3-level system
|
||||
case 'immediate':
|
||||
return {
|
||||
bg: 'bg-red-500/10',
|
||||
border: 'border-red-500',
|
||||
icon: AlertCircle,
|
||||
iconColor: 'text-red-500',
|
||||
}
|
||||
// NWS native
|
||||
case 'moderate':
|
||||
case 'warning':
|
||||
// Our 3-level system
|
||||
case 'priority':
|
||||
return {
|
||||
bg: 'bg-amber-500/10',
|
||||
border: 'border-amber-500',
|
||||
icon: AlertTriangle,
|
||||
iconColor: 'text-amber-500',
|
||||
}
|
||||
// NWS native
|
||||
case 'minor':
|
||||
// Our 3-level system
|
||||
case 'routine':
|
||||
return {
|
||||
bg: 'bg-yellow-500/10',
|
||||
border: 'border-yellow-500',
|
||||
bg: 'bg-blue-500/10',
|
||||
border: 'border-blue-500',
|
||||
icon: Info,
|
||||
iconColor: 'text-yellow-500',
|
||||
iconColor: 'text-blue-500',
|
||||
}
|
||||
default:
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -98,12 +98,9 @@ interface ChannelTestResult {
|
|||
|
||||
// Severity levels with descriptions
|
||||
const SEVERITY_OPTIONS = [
|
||||
{ value: 'info', label: 'Info', description: 'Routine updates (ducting detected, new router appeared)' },
|
||||
{ value: 'advisory', label: 'Advisory', description: 'Worth knowing (weather advisory, traffic slow, battery declining)' },
|
||||
{ value: 'watch', label: 'Watch', description: 'Pay attention (fire within 50km, weather watch, stream rising)' },
|
||||
{ value: 'warning', label: 'Warning', description: 'Act now (fire within 25km, severe weather, critical battery)' },
|
||||
{ value: 'critical', label: 'Critical', description: 'Serious issue (critical node down, battery emergency)' },
|
||||
{ value: 'emergency', label: 'Emergency', description: 'Life safety (extreme weather, fire at infrastructure, total blackout)' },
|
||||
{ value: 'routine', label: 'Routine', description: 'Informational, no time pressure (ducting, new node, weather advisory, battery declining)' },
|
||||
{ value: 'priority', label: 'Priority', description: 'Needs attention soon (severe weather, fire nearby, node offline, HF blackout)' },
|
||||
{ value: 'immediate', label: 'Immediate', description: 'Act now, drop everything (fire at infrastructure, extreme weather, region blackout)' },
|
||||
]
|
||||
|
||||
// Notification rule templates
|
||||
|
|
@ -117,7 +114,7 @@ const RULE_TEMPLATES = [
|
|||
enabled: true,
|
||||
trigger_type: "condition" as const,
|
||||
categories: ["infra_offline", "critical_node_down", "infra_recovery", "battery_warning", "battery_critical", "battery_emergency", "high_utilization", "packet_flood", "mesh_score_low"],
|
||||
min_severity: "advisory",
|
||||
min_severity: "routine",
|
||||
delivery_type: "mesh_broadcast",
|
||||
broadcast_channel: 0,
|
||||
cooldown_minutes: 30,
|
||||
|
|
@ -149,7 +146,7 @@ const RULE_TEMPLATES = [
|
|||
enabled: true,
|
||||
trigger_type: "condition" as const,
|
||||
categories: ["weather_warning", "fire_proximity", "new_ignition", "stream_flood_warning"],
|
||||
min_severity: "warning",
|
||||
min_severity: "priority",
|
||||
delivery_type: "mesh_broadcast",
|
||||
broadcast_channel: 0,
|
||||
cooldown_minutes: 15,
|
||||
|
|
@ -181,7 +178,7 @@ const RULE_TEMPLATES = [
|
|||
enabled: true,
|
||||
trigger_type: "condition" as const,
|
||||
categories: ["hf_blackout", "tropospheric_ducting", "geomagnetic_storm"],
|
||||
min_severity: "info",
|
||||
min_severity: "routine",
|
||||
delivery_type: "mesh_broadcast",
|
||||
broadcast_channel: 0,
|
||||
cooldown_minutes: 60,
|
||||
|
|
@ -213,7 +210,7 @@ const RULE_TEMPLATES = [
|
|||
enabled: true,
|
||||
trigger_type: "condition" as const,
|
||||
categories: ["road_closure", "traffic_congestion"],
|
||||
min_severity: "warning",
|
||||
min_severity: "routine",
|
||||
delivery_type: "mesh_broadcast",
|
||||
broadcast_channel: 0,
|
||||
cooldown_minutes: 30,
|
||||
|
|
@ -245,7 +242,7 @@ const RULE_TEMPLATES = [
|
|||
enabled: true,
|
||||
trigger_type: "condition" as const,
|
||||
categories: [] as string[],
|
||||
min_severity: "emergency",
|
||||
min_severity: "immediate",
|
||||
delivery_type: "mesh_broadcast",
|
||||
broadcast_channel: 0,
|
||||
cooldown_minutes: 5,
|
||||
|
|
@ -543,13 +540,13 @@ function SeveritySelector({ value, onChange }: {
|
|||
onChange: (v: string) => void
|
||||
}) {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const selected = SEVERITY_OPTIONS.find(s => s.value === value) || SEVERITY_OPTIONS[3]
|
||||
const selected = SEVERITY_OPTIONS.find(s => s.value === value) || SEVERITY_OPTIONS[0]
|
||||
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
<label className="flex items-center text-xs text-slate-500 uppercase tracking-wide">
|
||||
Severity Threshold
|
||||
<InfoButton info="Only alerts at or above this severity trigger this rule. Lower threshold = more notifications. 'Warning' is recommended for most rules." />
|
||||
<InfoButton info="Only alerts at or above this severity trigger this rule. ROUTINE = informational, PRIORITY = needs attention, IMMEDIATE = act now." />
|
||||
</label>
|
||||
<div className="relative">
|
||||
<button
|
||||
|
|
@ -1431,7 +1428,7 @@ export default function Notifications() {
|
|||
enabled: true,
|
||||
trigger_type: 'condition',
|
||||
categories: [],
|
||||
min_severity: 'warning',
|
||||
min_severity: 'routine',
|
||||
schedule_frequency: 'daily',
|
||||
schedule_time: '07:00',
|
||||
schedule_time_2: '19:00',
|
||||
|
|
@ -1779,7 +1776,7 @@ export default function Notifications() {
|
|||
checked={config.quiet_hours_enabled ?? true}
|
||||
onChange={(v) => setConfig({ ...config, quiet_hours_enabled: v })}
|
||||
helper="Suppress non-emergency alerts during sleeping hours"
|
||||
info="When enabled, alerts below emergency severity are held during quiet hours. When disabled, all alerts deliver anytime."
|
||||
info="When enabled, ROUTINE alerts are suppressed during quiet hours. PRIORITY and IMMEDIATE always deliver."
|
||||
/>
|
||||
|
||||
{config.quiet_hours_enabled && (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue