Files
boc/backups/2026-07-12-1023/landvex-prod/admin/real-data.html
T

184 lines
6.7 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LIFE — Real Data Status</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif; background: #000; color: #fff; line-height: 1.6; }
.header { background: #0a0a0a; border-bottom: 1px solid #333; padding: 20px 40px; }
.header h1 { font-size: 1.5rem; color: #00d4ff; }
.header p { color: #888; font-size: 0.9rem; }
.main { padding: 40px; max-width: 1200px; margin: 0 auto; }
.section { background: #111; border: 1px solid #333; border-radius: var(--radius-md); padding: 24px; margin-bottom: 24px; }
.section h2 { font-size: 1.2rem; margin-bottom: 16px; color: #00d4ff; }
.source { display: flex; justify-content: space-between; align-items: center; padding: 12px; border-bottom: 1px solid #222; }
.source:last-child { border-bottom: none; }
.source-name { font-weight: 600; }
.source-type { font-size: 0.8rem; padding: 2px 8px; border-radius: var(--radius-sm); }
.type-real { background: #1a3a1a; color: #4ade80; }
.type-simulated { background: #3a1a1a; color: #f87171; }
.source-count { font-size: 1.2rem; font-weight: 700; }
.metric { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; margin-bottom: 24px; }
.metric-card { background: #111; border: 1px solid #333; border-radius: var(--radius-md); padding: 20px; }
.metric-value { font-size: 2rem; font-weight: 700; color: #00d4ff; }
.metric-label { font-size: 0.85rem; color: #888; }
.status { display: inline-block; width: 8px; height: 8px; border-radius: var(--radius-full); margin-right: 8px; }
.status-active { background: #4ade80; }
.status-inactive { background: #f87171; }
</style>
</head>
<body>
<div class="header">
<h1>LIFE — Real Data Status</h1>
<p>Honest overview of what data is real vs simulated</p>
</div>
<div class="main">
<div class="metric">
<div class="metric-card">
<div class="metric-value" id="real-count"></div>
<div class="metric-label">Real Observations</div>
</div>
<div class="metric-card">
<div class="metric-value" id="sim-count"></div>
<div class="metric-label">Simulated Observations</div>
</div>
<div class="metric-card">
<div class="metric-value" id="real-percent"></div>
<div class="metric-label">Real Data %</div>
</div>
</div>
<div class="section">
<h2>Data Sources</h2>
<div id="sources">
<div style="color:#666;text-align:center;padding:20px;">Loading...</div>
</div>
</div>
<div class="section">
<h2>Real Data Pipeline</h2>
<div class="source">
<div>
<div class="source-name"><span class="status status-active"></span>SMHI Weather</div>
<div style="color:#888;font-size:0.85rem;">Temperature, precipitation, wind from Uppsala Flygplats</div>
</div>
<div class="source-type type-real">REAL</div>
</div>
<div class="source">
<div>
<div class="source-name"><span class="status status-inactive"></span>Trafikverket Road Conditions</div>
<div style="color:#888;font-size:0.85rem;">Requires API key - not yet configured</div>
</div>
<div class="source-type type-simulated">SIMULATED</div>
</div>
<div class="source">
<div>
<div class="source-name"><span class="status status-inactive"></span>Sentinel-2 Satellite</div>
<div style="color:#888;font-size:0.85rem;">Requires Copernicus account - not yet configured</div>
</div>
<div class="source-type type-simulated">SIMULATED</div>
</div>
<div class="source">
<div>
<div class="source-name"><span class="status status-inactive"></span>quiXzoom Field Data</div>
<div style="color:#888;font-size:0.85rem;">No active field contributors in area</div>
</div>
<div class="source-type type-simulated">SIMULATED</div>
</div>
</div>
<div class="section">
<h2>Latest Real Data</h2>
<table style="width:100%;border-collapse:collapse;">
<thead>
<tr style="border-bottom:1px solid #333;">
<th style="text-align:left;padding:8px;color:#888;">Time</th>
<th style="text-align:left;padding:8px;color:#888;">Road</th>
<th style="text-align:left;padding:8px;color:#888;">Type</th>
<th style="text-align:left;padding:8px;color:#888;">Value</th>
</tr>
</thead>
<tbody id="latest-real">
<tr><td colspan="4" style="text-align:center;color:#666;padding:20px;">Loading...</td></tr>
</tbody>
</table>
</div>
</div>
<script>
async function loadData() {
try {
const response = await fetch('/api/v1/live/public/status');
const data = await response.json();
const sources = data.sources;
const total = Object.values(sources).reduce((a, b) => a + b, 0);
const real = sources['smhi_real'] || 0;
const simulated = total - real;
document.getElementById('real-count').textContent = real;
document.getElementById('sim-count').textContent = simulated;
document.getElementById('real-percent').textContent = ((real / total) * 100).toFixed(1) + '%';
// Sources list
const container = document.getElementById('sources');
container.innerHTML = Object.entries(sources).map(([name, count]) => {
const isReal = name === 'smhi_real';
return `
<div class="source">
<div>
<div class="source-name">${name}</div>
</div>
<div style="display:flex;align-items:center;gap:12px;">
<div class="source-count">${count}</div>
<div class="source-type ${isReal ? 'type-real' : 'type-simulated'}">${isReal ? 'REAL' : 'SIMULATED'}</div>
</div>
</div>
`;
}).join('');
} catch (e) {
console.error('Failed to load:', e);
}
}
async function loadLatest() {
try {
const response = await fetch('/api/v1/live/public/observations/stream?limit=10');
const data = await response.json();
const tbody = document.getElementById('latest-real');
const realObs = data.observations.filter(o => o.source === 'smhi_real');
if (realObs.length === 0) {
tbody.innerHTML = '<tr><td colspan="4" style="text-align:center;color:#666;padding:20px;">No real data yet</td></tr>';
return;
}
tbody.innerHTML = realObs.slice(0, 5).map(obs => `
<tr style="border-bottom:1px solid #222;">
<td style="padding:8px;">${obs.detected_date}</td>
<td style="padding:8px;">${obs.road_name}</td>
<td style="padding:8px;">${obs.observation_type}</td>
<td style="padding:8px;color:#4ade80;">${obs.severity}</td>
</tr>
`).join('');
} catch (e) {
console.error('Failed to load latest:', e);
}
}
loadData();
loadLatest();
</script>
</body>
</html>