update main to v0.10.0 #48

Merged
serversdown merged 32 commits from feature/sfm-integration into main 2026-05-14 16:56:43 -04:00
7 changed files with 36 additions and 27 deletions
Showing only changes of commit e15481884a - Show all commits
+19 -9
View File
@@ -548,7 +548,14 @@ def _empty_stats() -> dict:
def _compute_stats(events: list[dict]) -> dict: def _compute_stats(events: list[dict]) -> dict:
"""Roll up summary stats from a merged event list. Cheap O(N) pass.""" """Roll up summary stats from a merged event list. Cheap O(N) pass.
The "Overall Peak" stat (peak_pvs) EXCLUDES events flagged as false
triggers — operators care about the highest REAL event, not the
biggest sensor glitch. false_trigger_count still includes them so
operators can see how many were filtered out. last_event uses
every event regardless (it's about activity recency, not magnitude).
"""
if not events: if not events:
return _empty_stats() return _empty_stats()
@@ -559,19 +566,22 @@ def _compute_stats(events: list[dict]) -> dict:
false_trigger_count = 0 false_trigger_count = 0
for ev in events: for ev in events:
pvs = ev.get("peak_vector_sum") is_false_trigger = bool(ev.get("false_trigger"))
if pvs is not None and (peak_pvs is None or pvs > peak_pvs): if is_false_trigger:
peak_pvs = pvs false_trigger_count += 1
peak_pvs_at = ev.get("timestamp")
peak_pvs_serial = ev.get("serial") # Peak calculation: skip flagged false triggers.
if not is_false_trigger:
pvs = ev.get("peak_vector_sum")
if pvs is not None and (peak_pvs is None or pvs > peak_pvs):
peak_pvs = pvs
peak_pvs_at = ev.get("timestamp")
peak_pvs_serial = ev.get("serial")
ts = ev.get("timestamp") ts = ev.get("timestamp")
if ts and (last_event is None or ts > last_event): if ts and (last_event is None or ts > last_event):
last_event = ts last_event = ts
if ev.get("false_trigger"):
false_trigger_count += 1
return { return {
"event_count": len(events), "event_count": len(events),
"peak_pvs": peak_pvs, "peak_pvs": peak_pvs,
+11
View File
@@ -134,6 +134,17 @@
Projects Projects
</a> </a>
{# Events — fleet-wide event database (SFM). Cross-project
sortable/filterable event list. Day-to-day event browsing
for a specific location or unit lives on those detail
pages; this is the firehose for cross-cutting queries. #}
<a href="/sfm" class="flex items-center px-4 py-3 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 {% if request.url.path == '/sfm' %}bg-gray-100 dark:bg-gray-700{% endif %}">
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
</svg>
Events
</a>
{# Tools — operator workflow hub. Active when on /tools {# Tools — operator workflow hub. Active when on /tools
itself or any of the workflow pages it links into itself or any of the workflow pages it links into
(project tidy, metadata backfill, pair devices). #} (project tidy, metadata backfill, pair devices). #}
@@ -23,7 +23,7 @@
<span class="text-2xl font-bold text-gray-900 dark:text-white mt-1">{{ "{:,}".format(summary.total_events) }}</span> <span class="text-2xl font-bold text-gray-900 dark:text-white mt-1">{{ "{:,}".format(summary.total_events) }}</span>
</div> </div>
<div class="bg-gray-50 dark:bg-slate-900/50 rounded-lg p-3 flex flex-col"> <div class="bg-gray-50 dark:bg-slate-900/50 rounded-lg p-3 flex flex-col">
<span class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Peak PVS</span> <span class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Overall Peak</span>
{% if summary.peak_pvs is not none %} {% if summary.peak_pvs is not none %}
<span class="text-2xl font-bold text-gray-900 dark:text-white mt-1">{{ "%.4f"|format(summary.peak_pvs) }} <span class="text-sm font-normal">in/s</span></span> <span class="text-2xl font-bold text-gray-900 dark:text-white mt-1">{{ "%.4f"|format(summary.peak_pvs) }} <span class="text-sm font-normal">in/s</span></span>
<a href="/projects/{{ summary.project_id }}/nrl/{{ summary.peak_pvs_location_id }}" <a href="/projects/{{ summary.project_id }}/nrl/{{ summary.peak_pvs_location_id }}"
+1 -13
View File
@@ -561,19 +561,7 @@
</a> </a>
</div> </div>
<!-- SFM Admin (raw event database) --> {# SFM Admin moved back to main nav as "Events" — see sidebar. #}
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-slate-700 rounded-lg">
<div>
<div class="font-medium text-gray-900 dark:text-white">SFM Admin</div>
<div class="text-sm text-gray-500 dark:text-gray-400 mt-0.5">
Raw event database from SFM — cross-project event search, file downloads, debug view. Day-to-day event browsing lives on project / location / unit pages.
</div>
</div>
<a href="/sfm"
class="ml-6 px-4 py-2 bg-seismo-orange hover:bg-orange-600 text-white text-sm font-medium rounded-lg transition-colors whitespace-nowrap">
Open
</a>
</div>
{# Metadata Backfill + Project Tidy moved to Tools (they're {# Metadata Backfill + Project Tidy moved to Tools (they're
operator workflows, not admin/dev surfaces). Find them operator workflows, not admin/dev surfaces). Find them
+2 -2
View File
@@ -5,8 +5,8 @@
{% block content %} {% block content %}
<div class="mb-6 flex items-center justify-between"> <div class="mb-6 flex items-center justify-between">
<div> <div>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">SFM Event Data</h1> <h1 class="text-3xl font-bold text-gray-900 dark:text-white">Events</h1>
<p class="text-gray-600 dark:text-gray-400 mt-1">Blastware ACH events forwarded by series3-watcher</p> <p class="text-gray-600 dark:text-gray-400 mt-1">Fleet-wide event database. Filter by serial, date, false-trigger, or browse the units roster.</p>
</div> </div>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<span id="sfm-status-badge" class="px-3 py-1 rounded-full text-sm font-medium bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-400"> <span id="sfm-status-badge" class="px-3 py-1 rounded-full text-sm font-medium bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-400">
+1 -1
View File
@@ -313,7 +313,7 @@
<span class="text-xs text-gray-500 dark:text-gray-400 mt-1">outside any assignment window</span> <span class="text-xs text-gray-500 dark:text-gray-400 mt-1">outside any assignment window</span>
</div> </div>
<div class="bg-gray-50 dark:bg-slate-900/50 rounded-lg p-3 flex flex-col"> <div class="bg-gray-50 dark:bg-slate-900/50 rounded-lg p-3 flex flex-col">
<span class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Peak PVS</span> <span class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Overall Peak</span>
<span id="ue-stat-peak" class="text-2xl font-bold text-gray-900 dark:text-white mt-1"></span> <span id="ue-stat-peak" class="text-2xl font-bold text-gray-900 dark:text-white mt-1"></span>
<span id="ue-stat-peak-when" class="text-xs text-gray-500 dark:text-gray-400 mt-1"></span> <span id="ue-stat-peak-when" class="text-xs text-gray-500 dark:text-gray-400 mt-1"></span>
</div> </div>
+1 -1
View File
@@ -199,7 +199,7 @@
<span id="ev-stat-count" class="text-3xl font-bold text-gray-900 dark:text-white mt-1"></span> <span id="ev-stat-count" class="text-3xl font-bold text-gray-900 dark:text-white mt-1"></span>
</div> </div>
<div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-4 flex flex-col"> <div class="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-4 flex flex-col">
<span class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Peak PVS</span> <span class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wider">Overall Peak</span>
<span id="ev-stat-peak" class="text-3xl font-bold text-gray-900 dark:text-white mt-1"></span> <span id="ev-stat-peak" class="text-3xl font-bold text-gray-900 dark:text-white mt-1"></span>
<span id="ev-stat-peak-when" class="text-xs text-gray-500 dark:text-gray-400 mt-1"></span> <span id="ev-stat-peak-when" class="text-xs text-gray-500 dark:text-gray-400 mt-1"></span>
</div> </div>