feat: station search in side panel; DB stats cover HII tables
CI/CD Pipeline - Northern Thailand Ping River Monitor / Test Suite (3.11) (push) Failing after 38s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Build Docker Image (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Integration Test with Services (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Staging (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Production (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Performance Test (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Code Quality (push) Successful in 16s
Documentation / Validate Documentation (push) Failing after 9s
Documentation / Generate API Documentation (push) Successful in 10s
Documentation / Build Sphinx Documentation (push) Successful in 16s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Cleanup (push) Successful in 0s
Documentation / Documentation Summary (push) Successful in 2s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Test Suite (3.11) (push) Failing after 38s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Build Docker Image (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Integration Test with Services (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Staging (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Production (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Performance Test (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Code Quality (push) Successful in 16s
Documentation / Validate Documentation (push) Failing after 9s
Documentation / Generate API Documentation (push) Successful in 10s
Documentation / Build Sphinx Documentation (push) Successful in 16s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Cleanup (push) Successful in 0s
Documentation / Documentation Summary (push) Successful in 2s
A search box above the station lists filters both the RID flow list and the basin-station list by code, name (Thai included), or river, and persists across refreshes. /api/stats now reports whole-DB totals — RID + hii_rainfall + hii_waterlevel counts, combined station count, and a date range spanning all sources — with per-source breakdown fields the stats strip shows as tile notes. Sensor section renamed to 'Additional basin stations · ThaiWater/HII'.
This commit is contained in:
@@ -234,9 +234,11 @@
|
||||
</article>
|
||||
|
||||
<aside class="side-card">
|
||||
<div class="side-head"><h2>Current station flow</h2><p>Select a station to locate it and load its history</p></div>
|
||||
<div class="side-head"><h2>Current station flow</h2><p>Select a station to locate it and load its history</p>
|
||||
<input type="search" id="station-search" placeholder="Search stations · code, name, river…" aria-label="Search stations" style="margin-top:10px;width:100%;box-sizing:border-box;padding:9px 12px;border:1px solid var(--border);border-radius:10px;background:white;font-size:.8rem">
|
||||
</div>
|
||||
<div class="station-list" id="river-flow" aria-live="polite"></div>
|
||||
<div class="side-head"><h2>Additional ThaiWater sensors</h2><p id="thaiwater-count">Loading Ping basin sensors…</p></div>
|
||||
<div class="side-head"><h2>Additional basin stations</h2><p id="thaiwater-count">Loading ThaiWater/HII stations…</p></div>
|
||||
<div class="station-list" id="thaiwater-sensors" aria-live="polite"></div>
|
||||
</aside>
|
||||
</section>
|
||||
@@ -273,11 +275,11 @@
|
||||
</section>
|
||||
|
||||
<section class="stats" id="db-stats" aria-label="Database statistics" style="margin-top:14px;display:none;grid-template-columns:repeat(auto-fit,minmax(170px,1fr))">
|
||||
<article class="stat"><div class="stat-label">Total datapoints</div><div class="stat-value" id="db-total">—</div><div class="stat-note">measurements stored</div></article>
|
||||
<article class="stat"><div class="stat-label">Total datapoints</div><div class="stat-value" id="db-total">—</div><div class="stat-note" id="db-total-note">measurements stored</div></article>
|
||||
<article class="stat"><div class="stat-label">Date range</div><div class="stat-value" id="db-range" style="font-size:1.05rem;line-height:1.3;white-space:normal">—</div><div class="stat-note">first to last record</div></article>
|
||||
<article class="stat"><div class="stat-label">Days spanned</div><div class="stat-value" id="db-days">—</div><div class="stat-note">between first and last</div></article>
|
||||
<article class="stat"><div class="stat-label">Stations</div><div class="stat-value" id="db-stations">—</div><div class="stat-note">distinct in database</div></article>
|
||||
<article class="stat"><div class="stat-label">Coverage</div><div class="stat-value" id="db-coverage">—</div><div class="stat-note">of hourly slots recorded</div></article>
|
||||
<article class="stat"><div class="stat-label">Stations</div><div class="stat-value" id="db-stations">—</div><div class="stat-note" id="db-stations-note">distinct in database</div></article>
|
||||
<article class="stat"><div class="stat-label">Coverage</div><div class="stat-value" id="db-coverage">—</div><div class="stat-note">of RID hourly slots recorded</div></article>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@@ -623,6 +625,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Filters both station lists by any text on the row (code, names, river —
|
||||
// Thai included, since it matches against the rendered text).
|
||||
function applyStationSearch() {
|
||||
const query = $('station-search').value.trim().toLowerCase();
|
||||
['river-flow', 'thaiwater-sensors'].forEach((id) => {
|
||||
[...$(id).children].forEach((row) => {
|
||||
row.style.display = !query || row.textContent.toLowerCase().includes(query) ? '' : 'none';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderList(stations, readings) {
|
||||
const container = $('river-flow');
|
||||
container.replaceChildren();
|
||||
@@ -654,7 +667,7 @@
|
||||
const additional = sensors
|
||||
.filter((sensor) => !existingCodes.has(sensor.station_code))
|
||||
.sort((a, b) => (Number(b.bank_percent) || -1) - (Number(a.bank_percent) || -1));
|
||||
$('thaiwater-count').textContent = `${additional.length} additional Ping basin stations · water level`;
|
||||
$('thaiwater-count').textContent = `${additional.length} Ping basin stations · ThaiWater/HII water level`;
|
||||
additional.forEach((sensor) => {
|
||||
const percent = sensor.bank_percent == null ? null : Number(sensor.bank_percent);
|
||||
// ThaiWater situation bands by % of bank capacity: over-bank red,
|
||||
@@ -751,6 +764,7 @@
|
||||
renderRainLayer(rainRecords);
|
||||
renderList(stations, readings);
|
||||
renderThaiWaterSensors(sensors, new Set(stations.map((station) => station.station_code)));
|
||||
applyStationSearch(); // keep an active search applied across refreshes
|
||||
loadCustomMarkers();
|
||||
renderSummary(stations, readings);
|
||||
$('loading').style.display = 'none';
|
||||
@@ -1134,6 +1148,11 @@
|
||||
const stats = await response.json();
|
||||
const fmtDate = (value) => new Date(value).toLocaleDateString([], { day: 'numeric', month: 'short', year: 'numeric' });
|
||||
$('db-total').textContent = Number(stats.total_measurements).toLocaleString();
|
||||
if (stats.rid_measurements != null) {
|
||||
const fmtNum = (value) => Number(value || 0).toLocaleString();
|
||||
$('db-total-note').textContent = `${fmtNum(stats.rid_measurements)} RID · ${fmtNum(stats.hii_waterlevel_measurements)} HII level · ${fmtNum(stats.hii_rainfall_measurements)} rain`;
|
||||
$('db-stations-note').textContent = `${stats.rid_station_count} RID · ${stats.hii_station_count} ThaiWater/HII`;
|
||||
}
|
||||
$('db-range').textContent = `${fmtDate(stats.first_timestamp)} – ${fmtDate(stats.last_timestamp)}`;
|
||||
$('db-days').textContent = Number(stats.days_spanned).toLocaleString();
|
||||
$('db-stations').textContent = String(stats.station_count);
|
||||
@@ -1154,6 +1173,7 @@
|
||||
? 'Hide station forecasts ▴'
|
||||
: `Show all ${count} station forecasts ▾`;
|
||||
});
|
||||
$('station-search').addEventListener('input', applyStationSearch);
|
||||
$('rain-toggle').addEventListener('change', (event) => {
|
||||
if (!state.rainLayer) return;
|
||||
if (event.target.checked) state.rainLayer.addTo(state.map);
|
||||
|
||||
Reference in New Issue
Block a user