Adds inline waveform plots to the shared event-detail modal, ported
from sfm/sfm_webapp.html:2555-2880. The standalone SFM webapp's
plot logic moves into event-modal.js with Tailwind-friendly grid +
tick colors (theme-aware via the `dark` class on <html>).
Channels render in BW Event Report order — MicL on top, Tran on
bottom. Mic channel auto-converts psi → dB(L) when the operator's
mic_unit_pref is "dBL" (the default), using _psiToDblForChart with
a MIC_DBL_FLOOR=60 floor so the chart shows an SPL-vs-time curve
instead of a sparse pattern of "moments above floor".
Histograms render as bars with HH:MM:SS x-axis labels when the
sidecar carries time_axis.interval_times (events ingested with the
v0.20 parser); falls back to interval index for older events.
Geo + mic histogram channels enforce minimum Y ranges (0.05 in/s
and 0.001 psi respectively) so quiet events don't fill the panel.
Waveform events get the trigger-line + zero-baseline overlay; the
histogram branch suppresses it (no trigger concept). Downsampling
kicks in at >3000 samples to keep render time bounded.
Modal partial widened max-w-3xl → max-w-5xl to fit the chart panels
without horizontal clipping. Chart.js 4.4.1 loaded from cdn.jsdelivr
at the bottom of the partial, matching the standalone webapp's
reference version pin.
Side-yard: docker-compose bind-mounts ../seismo-relay-prod-snap into
the SFM container so the symlinked DB + waveform store inside
bridges/captures resolve. Without it SFM 500s on every /db/* call
because the symlink target was outside the container's filesystem
view. Read-write (not :ro) because SFM opens the DB in WAL mode
which requires creating -wal and -shm sidecar files even for reads.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Event modal (event-modal.js):
- Record Type now derived from Blastware filename's last-char code
(H=Histogram, W=Waveform, M=Manual, E=Event, C=Combo). Falls back to
whatever SFM reported if the code isn't recognized. Client-side
workaround — SFM still hardcodes "Waveform" server-side and needs a
proper fix in its sidecar parser.
- PSI mic tile dropped; mic section now renders 3 tiles (dB(L), ZC
Frequency, Time of Peak) instead of 4.
- New "View JSON" toggle exposes a prettified inline JSON viewer with
a Copy-to-clipboard button alongside the existing "Download sidecar
JSON" link.
- "Project Info" section header renamed to "User Notes" to reflect
that these are operator-typed fields, not the terra-view project
assignment.
Sortable tables (sfm.html + unit_detail.html):
- Both Events tables now have clickable column headers with ↕/↓/↑
indicators. Default sort is Timestamp DESC. Clicking the same
column toggles direction; clicking a different column switches and
resets to DESC. Sort is purely client-side over the cached rowset,
so no extra fetches.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two new action buttons at the top of the Source File section of the
event-detail modal:
1. Download Blastware file — primary orange button. Pulls the raw .AB0
/.G10/.6R0/etc. binary from SFM (/db/events/{id}/blastware_file) via
terra-view's /api/sfm proxy. The browser saves it with the original
on-disk filename (using the HTML5 `download` attribute pointed at
sidecar.blastware.filename). Operator can then open the file
directly in Blastware on a Windows box for full waveform analysis,
archive it, or attach it to a compliance report.
Greyed-out "Blastware file unavailable" placeholder shown when
sidecar.blastware.available is false (rare — would mean SFM stored
the metadata but lost the binary).
2. Download sidecar JSON — secondary outlined button. Pulls the same
.sfm.json the modal renders from. Saved as <binary>.sfm.json.
Useful for ops/diagnostics and for the future metadata-driven
project parser (Phase 5) which can chew on these directly.
End-to-end verified through the proxy: 8882-byte Blastware binary
intact with "Instantel" magic header preserved.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Clicking any event row in any of the three event tables (/sfm Events,
project-location Events tab, unit detail SFM Events) now opens a modal
populated from the SFM .sfm.json sidecar. Previously the /sfm page had
a basic inline modal showing only the columns already in the table;
this rebuilds it as a shared component and exposes the rich fields
that the BW ASCII report unlocks.
Shared component:
- backend/static/event-modal.js — single ~250-line module. Public API:
showEventDetail(eventId) fetches /api/sfm/db/events/{id}/sidecar
live (no extra terra-view caching) and renders sections for:
• Event (serial, timestamp, record type, sample rate, rec time,
waveform key)
• Project Info (operator-typed user notes — project / client /
operator / sensor_location — flagged in the UI as "as typed
into the seismograph at session start", not the terra-view
assignment)
• Peak Particle Velocity (per-channel + vector sum, with the
time-of-vector-sum-peak when bw_report is available)
• Microphone (Peak dB(L) + psi, ZC frequency, time of peak)
• Sensor Self-Check table (per-channel freq + ratio/amplitude +
pass/fail)
• Device & Recording Metadata (firmware, battery, calibration
date + by-whom, geo range, stop mode, units)
• Source File (Blastware filename, size, SHA-256, capture time)
closeEventDetailModal() closes; Escape key also closes.
- templates/partials/event_detail_modal.html — modal shell partial
(sticky title bar, scrollable body, click-outside-to-close).
Wired into three pages:
- templates/sfm.html: removed the old inline modal + showEventDetail /
ppvCard / closeEventModal functions (replaced by the shared module).
Row onclick now passes just the event id instead of the full JSON.
- templates/vibration_location_detail.html: row click on the Events
tab opens the modal. The /unit/{serial} link inside the row has
event.stopPropagation() so the link navigates instead of opening
the modal.
- templates/unit_detail.html: row click on the SFM Events table opens
the modal. The attribution-cell project/location links also got
stopPropagation.
Graceful degradation: older events forwarded before the watcher's
_ASCII.TXT pairing fix don't have a bw_report block in their sidecar.
The modal renders an amber banner explaining that and shows just the
event + project_info + peak_values + source-file sections.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>