feat: date-range picker on the station history panel; drop PostgreSQL naming
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 14s
Documentation / Validate Documentation (push) Failing after 8s
Documentation / Generate API Documentation (push) Successful in 10s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Test Suite (3.11) (push) Failing after 24s
Documentation / Build Sphinx Documentation (push) Successful in 19s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Cleanup (push) Successful in 0s
Documentation / Documentation Summary (push) Successful in 2s

/measurements/history/{code} accepts optional start/end date params that
override the hours window (end date inclusive). The dashboard history
card gains from/to date inputs beside the quick-range dropdown —
explicit dates win, changing the dropdown clears them. All user-facing
'PostgreSQL history' labels renamed to 'Station history'.
This commit is contained in:
2026-08-11 15:52:40 +07:00
parent d29d49eac7
commit 9516857d44
3 changed files with 43 additions and 14 deletions
+23 -7
View File
@@ -234,7 +234,7 @@
</article>
<aside class="side-card">
<div class="side-head"><h2>Current station flow</h2><p>Select a station to locate it and load PostgreSQL history</p></div>
<div class="side-head"><h2>Current station flow</h2><p>Select a station to locate it and load its history</p></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="station-list" id="thaiwater-sensors" aria-live="polite"></div>
@@ -261,8 +261,13 @@
<section class="map-card" id="history-card" style="margin-top:14px;padding:20px">
<div style="display:flex;justify-content:space-between;align-items:center;gap:14px;flex-wrap:wrap">
<div><h2 id="history-title" style="margin:0;font-size:1rem">PostgreSQL history</h2><p id="history-status" class="subtitle">Select a RID flow station to load the last 7 days</p></div>
<select id="history-range" style="padding:9px 12px;border:1px solid var(--border);border-radius:10px;background:white"><option value="24">24 hours</option><option value="168" selected>7 days</option><option value="720">30 days</option><option value="2160">90 days</option><option value="876000">All time</option></select>
<div><h2 id="history-title" style="margin:0;font-size:1rem">Station history</h2><p id="history-status" class="subtitle">Select a station to load the last 7 days</p></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<select id="history-range" style="padding:9px 12px;border:1px solid var(--border);border-radius:10px;background:white"><option value="24">24 hours</option><option value="168" selected>7 days</option><option value="720">30 days</option><option value="2160">90 days</option><option value="876000">All time</option></select>
<input type="date" id="history-start" title="From date" style="padding:8px 10px;border:1px solid var(--border);border-radius:10px;background:white">
<span style="color:var(--muted)"></span>
<input type="date" id="history-end" title="To date" style="padding:8px 10px;border:1px solid var(--border);border-radius:10px;background:white">
</div>
</div>
<div style="height:260px;margin-top:14px;overflow:hidden;position:relative"><canvas id="history-chart" aria-label="Historical water level and discharge chart" style="display:block"></canvas></div>
</section>
@@ -524,10 +529,15 @@
state.selectedStation = stationCode;
state.historyRequestId++;
const reqId = state.historyRequestId;
$('history-title').textContent = `${stationCode} · PostgreSQL history`;
$('history-title').textContent = `${stationCode} · station history`;
$('history-status').textContent = 'Loading historical measurements…';
try {
const response = await fetch(`/measurements/history/${encodeURIComponent(stationCode)}?hours=${$('history-range').value}`);
// Explicit dates win over the quick-range dropdown
const startDate = $('history-start').value, endDate = $('history-end').value;
const query = startDate || endDate
? [startDate && `start=${startDate}`, endDate && `end=${endDate}`].filter(Boolean).join('&')
: `hours=${$('history-range').value}`;
const response = await fetch(`/measurements/history/${encodeURIComponent(stationCode)}?${query}`);
if (!response.ok) throw new Error((await response.json()).detail || `HTTP ${response.status}`);
const rows = await response.json();
if (reqId !== state.historyRequestId) return;
@@ -605,7 +615,7 @@
}
}]
});
$('history-status').textContent = rows.length ? `${rows.length} measurements (${sampled.length} daily) from PostgreSQL` : 'No PostgreSQL measurements in this period';
$('history-status').textContent = rows.length ? `${rows.length} measurements${sampled.length !== rows.length ? ` (${sampled.length} daily averages)` : ''}` : 'No measurements in this period';
$('history-card').scrollIntoView({ behavior: 'smooth', block: 'nearest' });
} catch (error) {
$('history-status').textContent = `History unavailable: ${error.message}`;
@@ -1149,7 +1159,13 @@
else state.map.removeLayer(state.rainLayer);
});
$('replay-2024').addEventListener('click', replayFlood2024);
$('history-range').addEventListener('change', () => { if (state.selectedStation) loadHistory(state.selectedStation); });
$('history-range').addEventListener('change', () => {
$('history-start').value = ''; $('history-end').value = '';
if (state.selectedStation) loadHistory(state.selectedStation);
});
['history-start', 'history-end'].forEach((id) => $(id).addEventListener('change', () => {
if (state.selectedStation) loadHistory(state.selectedStation);
}));
loadDashboard();
window.setInterval(loadDashboard, 5 * 60 * 1000);
})();