Skip to content

Instantly share code, notes, and snippets.

@cemoody
Last active March 27, 2026 18:19
Show Gist options
  • Select an option

  • Save cemoody/7dd4b6b2aada090637b9f6af7be238eb to your computer and use it in GitHub Desktop.

Select an option

Save cemoody/7dd4b6b2aada090637b9f6af7be238eb to your computer and use it in GitHub Desktop.
Signal Collector Health Dashboard
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Signal Collector Health</title>
<link href="https://fonts.googleapis.com/css2?family=STIX+Two+Text:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Source+Code+Pro:wght@400;500&display=swap" rel="stylesheet">
<style>
:root {
--green: #3a7d44;
--green-bg: rgba(58,125,68,0.06);
--red: #8b3a3a;
--red-bg: rgba(139,58,58,0.06);
--amber: #8a7030;
--amber-bg: rgba(138,112,48,0.06);
--text: #1a1a1a;
--text2: #555;
--text3: #999;
--rule: #d4d4d4;
--rule-light: #ebebeb;
--bg: #fafaf8;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'STIX Two Text', Georgia, serif;
font-size: 11.5px;
line-height: 1.45;
color: var(--text);
background: var(--bg);
padding: 1.8rem 2.2rem;
max-width: 1200px;
margin: 0 auto;
}
.mono { font-family: 'Source Code Pro', monospace; font-size: 0.92em; }
/* Header */
header {
display: flex;
justify-content: space-between;
align-items: baseline;
border-bottom: 1.5px solid var(--text);
padding-bottom: 0.5rem;
margin-bottom: 0.8rem;
}
header h1 { font-size: 1.35rem; font-weight: 600; letter-spacing: -0.01em; }
header .meta { font-size: 0.85em; color: var(--text3); font-style: italic; }
/* Summary strip */
.summary {
display: flex;
gap: 1.8rem;
margin-bottom: 1rem;
padding: 0.45rem 0;
border-bottom: 0.75px solid var(--rule);
font-size: 0.92em;
}
.summary .s { color: var(--text2); }
.summary .v { font-weight: 600; margin-left: 0.25rem; font-variant-numeric: tabular-nums; }
.summary .v.g { color: var(--green); }
.summary .v.r { color: var(--red); }
.summary .v.a { color: var(--amber); }
/* Source group */
.group {
margin-bottom: 0.7rem;
}
.group-header {
display: flex;
align-items: center;
gap: 0.6rem;
padding: 0.3rem 0;
border-bottom: 0.75px solid var(--rule);
margin-bottom: 1px;
}
.group-name {
font-weight: 700;
font-size: 0.95em;
}
.group-count {
font-size: 0.8em;
color: var(--text3);
}
.group-status-summary {
margin-left: auto;
display: flex;
gap: 0.5rem;
font-size: 0.8em;
}
.group-status-summary .gs {
display: flex;
align-items: center;
gap: 0.2rem;
}
/* Table */
table {
width: 100%;
border-collapse: collapse;
font-variant-numeric: tabular-nums;
}
th {
font-size: 0.7em;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--text3);
text-align: right;
padding: 0.15rem 0.5rem 0.15rem 0;
border-bottom: 0.5px solid var(--rule-light);
}
th:first-child, th:nth-child(2) { text-align: left; }
td {
padding: 0.25rem 0.5rem 0.25rem 0;
text-align: right;
border-bottom: 0.5px solid var(--rule-light);
font-size: 0.92em;
}
td:first-child { text-align: center; width: 1.2rem; padding-right: 0.3rem; }
td:nth-child(2) { text-align: left; font-weight: 500; }
tr:last-child td { border-bottom: none; }
tr.healthy td:first-child .dot { background: var(--green); }
tr.stale td:first-child .dot { background: var(--amber); }
tr.down td:first-child .dot { background: var(--red); }
tr.down { background: var(--red-bg); }
tr.stale { background: var(--amber-bg); }
.dot {
display: inline-block;
width: 7px;
height: 7px;
border-radius: 50%;
}
/* Inline uptime bar */
.uptime-cell {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 0.35rem;
}
.uptime-num {
min-width: 2.5em;
text-align: right;
font-size: 0.9em;
}
.ubar {
width: 40px;
height: 4px;
background: rgba(0,0,0,0.06);
border-radius: 2px;
overflow: hidden;
flex-shrink: 0;
}
.ubar .fill { height: 100%; border-radius: 2px; }
tr.healthy .ubar .fill { background: var(--green); }
tr.stale .ubar .fill { background: var(--amber); }
tr.down .ubar .fill { background: var(--red); }
.dim { color: var(--text3); }
/* Footer */
footer {
margin-top: 0.8rem;
padding-top: 0.5rem;
border-top: 0.75px solid var(--rule);
font-size: 0.78em;
color: var(--text3);
display: flex;
gap: 1.5rem;
flex-wrap: wrap;
}
footer .note { max-width: 45em; }
footer .note b { font-weight: 600; color: var(--text2); }
</style>
</head>
<body>
<header>
<h1>Signal Collector Health</h1>
<div class="meta" id="ts"></div>
</header>
<div class="summary" id="summary"></div>
<div id="groups"></div>
<footer>
<div class="note"><b>Status.</b> Thresholds per grain: daily &le;48h / &le;7d; weekly &le;14d / &le;30d; monthly &le;60d / &le;120d; quarterly &le;120d / &le;180d.</div>
<div class="note"><b>Uptime.</b> Fraction of last 30 days with at least one insert. &gt;100% = multiple inserts/day.</div>
</footer>
<script>
const DATA = [
{"signal_id":5,"signal_name":"Shovels Building Permits","source_system":"Shovels AI","date_grain":"daily","total_rows":31562506,"last_observation":"2025-12-31 00:00:00+00:00","last_inserted_at":"2026-02-06 05:06:11.433276+00:00","hours_since_last_insert":1188,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":16,"signal_name":"Google Trends Search Interest","source_system":"google_trends","date_grain":"weekly","total_rows":26014,"last_observation":"2026-02-08 00:00:00+00:00","last_inserted_at":"2026-02-14 23:21:50.693703+00:00","hours_since_last_insert":978,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":57,"signal_name":"GTrends Gutters/Drainage","source_system":"Google","date_grain":"weekly","total_rows":73340,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 15:57:37.565130+00:00","hours_since_last_insert":890,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":56,"signal_name":"GTrends Fire/Smoke","source_system":"Google","date_grain":"weekly","total_rows":4215,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 15:54:54.406346+00:00","hours_since_last_insert":890,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":59,"signal_name":"GTrends Financing","source_system":"Google","date_grain":"weekly","total_rows":47050,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 15:56:56.895504+00:00","hours_since_last_insert":890,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":61,"signal_name":"GTrends Solar Bundling","source_system":"Google","date_grain":"weekly","total_rows":4126,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 15:49:18.267040+00:00","hours_since_last_insert":890,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":63,"signal_name":"GTrends Near Me Intent","source_system":"Google","date_grain":"weekly","total_rows":32964,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 15:51:33.162959+00:00","hours_since_last_insert":890,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":60,"signal_name":"GTrends Permits/Codes","source_system":"Google","date_grain":"weekly","total_rows":21236,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 15:55:15.220877+00:00","hours_since_last_insert":890,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":62,"signal_name":"GTrends Storm Events","source_system":"Google","date_grain":"weekly","total_rows":251179,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 16:11:58.820261+00:00","hours_since_last_insert":889,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":54,"signal_name":"GTrends Wind/Tree Damage","source_system":"Google","date_grain":"weekly","total_rows":39047,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 16:10:38.335421+00:00","hours_since_last_insert":889,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":51,"signal_name":"GTrends Insurance/Claims","source_system":"Google","date_grain":"weekly","total_rows":20339,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 16:11:36.662938+00:00","hours_since_last_insert":889,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":52,"signal_name":"GTrends Replacement Intent","source_system":"Google","date_grain":"weekly","total_rows":158170,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 16:10:36.634057+00:00","hours_since_last_insert":889,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":55,"signal_name":"GTrends Ice/Winter","source_system":"Google","date_grain":"weekly","total_rows":29737,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 16:08:05.320276+00:00","hours_since_last_insert":889,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":58,"signal_name":"GTrends Mold/Moisture","source_system":"Google","date_grain":"weekly","total_rows":45906,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 16:03:16.250101+00:00","hours_since_last_insert":889,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":53,"signal_name":"GTrends Roofing Materials","source_system":"Google","date_grain":"weekly","total_rows":175807,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 16:23:22.013000+00:00","hours_since_last_insert":889,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":50,"signal_name":"GTrends Leak/Intrusion","source_system":"Google","date_grain":"weekly","total_rows":73826,"last_observation":"2026-02-16 00:00:00+00:00","last_inserted_at":"2026-02-18 16:10:06.742113+00:00","hours_since_last_insert":889,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":70,"signal_name":"GDELT News Events","source_system":"GDELT","date_grain":"daily","total_rows":1342722,"last_observation":"2026-02-18 00:00:00+00:00","last_inserted_at":"2026-02-19 03:41:53.194987+00:00","hours_since_last_insert":878,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"down","uptime_pct_30d":0.0},
{"signal_id":111,"signal_name":"Lowes Original Price","source_system":"Lowes","date_grain":"daily","total_rows":12,"last_observation":"2026-03-05 06:00:00+00:00","last_inserted_at":"2026-03-05 06:26:29.002459+00:00","hours_since_last_insert":539,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":12,"active_days_last_30":2,"status":"down","uptime_pct_30d":6.7},
{"signal_id":113,"signal_name":"Lowes Quantity","source_system":"Lowes","date_grain":"daily","total_rows":2566,"last_observation":"2026-03-09 21:00:00+00:00","last_inserted_at":"2026-03-09 21:32:40.525591+00:00","hours_since_last_insert":428,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":2566,"active_days_last_30":3,"status":"down","uptime_pct_30d":10.0},
{"signal_id":112,"signal_name":"Lowes In Stock","source_system":"Lowes","date_grain":"daily","total_rows":2566,"last_observation":"2026-03-09 21:00:00+00:00","last_inserted_at":"2026-03-09 21:32:40.525591+00:00","hours_since_last_insert":428,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":2566,"active_days_last_30":3,"status":"down","uptime_pct_30d":10.0},
{"signal_id":100,"signal_name":"GDELT News Signals","source_system":"GDELT","date_grain":"daily","total_rows":3888332,"last_observation":"2026-03-14 00:00:00+00:00","last_inserted_at":"2026-03-16 04:38:17.217681+00:00","hours_since_last_insert":277,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":3397,"active_days_last_30":5,"status":"down","uptime_pct_30d":16.7},
{"signal_id":22,"signal_name":"Flood Claims","source_system":"FEMA NFIP","date_grain":"monthly","total_rows":58320,"last_observation":"2026-02-01 00:00:00+00:00","last_inserted_at":"2026-02-06 02:22:22.099327+00:00","hours_since_last_insert":1191,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"healthy","uptime_pct_30d":0.0},
{"signal_id":39,"signal_name":"BLS Roofing Employment","source_system":"BLS QCEW","date_grain":"monthly","total_rows":31008,"last_observation":"2026-02-01 00:00:00+00:00","last_inserted_at":"2026-02-08 01:48:29.880993+00:00","hours_since_last_insert":1144,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":0,"active_days_last_30":0,"status":"healthy","uptime_pct_30d":0.0},
{"signal_id":110,"signal_name":"BuildZoom Roofing Permits","source_system":"BuildZoom","date_grain":"monthly","total_rows":462628,"last_observation":"2026-03-09 21:00:00+00:00","last_inserted_at":"2026-03-10 18:09:16.500752+00:00","hours_since_last_insert":407,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":462628,"active_days_last_30":6,"status":"healthy","uptime_pct_30d":20.0},
{"signal_id":26,"signal_name":"RMA Liability","source_system":"USDA RMA","date_grain":"monthly","total_rows":987317,"last_observation":"2026-03-01 00:00:00+00:00","last_inserted_at":"2026-03-15 01:07:07.855135+00:00","hours_since_last_insert":304,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":785,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":35,"signal_name":"Lumber Futures","source_system":"FRED","date_grain":"monthly","total_rows":1953,"last_observation":"2026-03-01 00:00:00+00:00","last_inserted_at":"2026-03-15 01:06:11.089190+00:00","hours_since_last_insert":304,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":3,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":36,"signal_name":"Mortgage Rates","source_system":"FRED","date_grain":"weekly","total_rows":15869,"last_observation":"2026-03-12 00:00:00+00:00","last_inserted_at":"2026-03-15 01:05:24.859095+00:00","hours_since_last_insert":304,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":19,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":38,"signal_name":"Adzuna Adjuster Jobs","source_system":"Adzuna","date_grain":"weekly","total_rows":168,"last_observation":"2026-03-09 00:00:00+00:00","last_inserted_at":"2026-03-15 01:05:34.380415+00:00","hours_since_last_insert":304,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":80,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":25,"signal_name":"RMA Total Premium","source_system":"USDA RMA","date_grain":"monthly","total_rows":987317,"last_observation":"2026-03-01 00:00:00+00:00","last_inserted_at":"2026-03-15 01:07:07.855135+00:00","hours_since_last_insert":304,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":785,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":13,"signal_name":"FRED Material Prices","source_system":"FRED","date_grain":"monthly","total_rows":2602,"last_observation":"2026-03-01 00:00:00+00:00","last_inserted_at":"2026-03-15 01:05:23.235353+00:00","hours_since_last_insert":304,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":4,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":24,"signal_name":"RMA Policies Indemnified","source_system":"USDA RMA","date_grain":"monthly","total_rows":986186,"last_observation":"2026-03-01 00:00:00+00:00","last_inserted_at":"2026-03-15 01:07:07.855135+00:00","hours_since_last_insert":304,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":785,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":23,"signal_name":"RMA Loss Acres","source_system":"USDA RMA","date_grain":"monthly","total_rows":829777,"last_observation":"2026-02-01 00:00:00+00:00","last_inserted_at":"2026-03-15 01:07:07.855135+00:00","hours_since_last_insert":304,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":249,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":18,"signal_name":"RMA Indemnity Amount","source_system":"USDA RMA","date_grain":"monthly","total_rows":1032385,"last_observation":"2026-03-01 00:00:00+00:00","last_inserted_at":"2026-03-15 01:07:07.855135+00:00","hours_since_last_insert":304,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":785,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":73,"signal_name":"Census ACS Vacancy Status","source_system":"Census ACS","date_grain":"quarterly","total_rows":3273249,"last_observation":"2024-01-01 00:00:00+00:00","last_inserted_at":"2026-03-16 04:58:06.242727+00:00","hours_since_last_insert":277,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":472808,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":72,"signal_name":"Census ACS Occupancy","source_system":"Census ACS","date_grain":"quarterly","total_rows":935214,"last_observation":"2024-01-01 00:00:00+00:00","last_inserted_at":"2026-03-16 04:58:06.242727+00:00","hours_since_last_insert":277,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":135088,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":71,"signal_name":"Census ACS Housing Units","source_system":"Census ACS","date_grain":"quarterly","total_rows":467607,"last_observation":"2024-01-01 00:00:00+00:00","last_inserted_at":"2026-03-16 04:58:06.242727+00:00","hours_since_last_insert":277,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":67544,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":37,"signal_name":"Redfin Home Sales","source_system":"Redfin","date_grain":"monthly","total_rows":1206214,"last_observation":"2026-01-01 00:00:00+00:00","last_inserted_at":"2026-03-16 04:40:54.466723+00:00","hours_since_last_insert":277,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":72252,"active_days_last_30":1,"status":"healthy","uptime_pct_30d":3.3},
{"signal_id":2,"signal_name":"Diesel Price","source_system":"FRED","date_grain":"weekly","total_rows":539,"last_observation":"2026-03-09 00:00:00+00:00","last_inserted_at":"2026-03-16 13:51:32.385497+00:00","hours_since_last_insert":268,"rows_last_24h":0,"rows_last_7d":0,"rows_last_30d":7,"active_days_last_30":3,"status":"healthy","uptime_pct_30d":10.0},
{"signal_id":80,"signal_name":"Census Building Permits","source_system":"Census BPS","date_grain":"monthly","total_rows":3428,"last_observation":"2026-03-01 00:00:00+00:00","last_inserted_at":"2026-03-22 21:00:35.447556+00:00","hours_since_last_insert":117,"rows_last_24h":0,"rows_last_7d":28,"rows_last_30d":3428,"active_days_last_30":4,"status":"healthy","uptime_pct_30d":13.3},
{"signal_id":20,"signal_name":"Drought Level","source_system":"NIDIS","date_grain":"weekly","total_rows":362520,"last_observation":"2026-03-17 00:00:00+00:00","last_inserted_at":"2026-03-24 22:00:56.738328+00:00","hours_since_last_insert":68,"rows_last_24h":0,"rows_last_7d":265,"rows_last_30d":1060,"active_days_last_30":4,"status":"healthy","uptime_pct_30d":13.3},
{"signal_id":14,"signal_name":"Weather Temperature","source_system":"Open-Meteo","date_grain":"daily","total_rows":903,"last_observation":"2026-03-26 00:00:00+00:00","last_inserted_at":"2026-03-27 07:00:28.541906+00:00","hours_since_last_insert":11,"rows_last_24h":21,"rows_last_7d":147,"rows_last_30d":903,"active_days_last_30":17,"status":"healthy","uptime_pct_30d":56.7},
{"signal_id":15,"signal_name":"Storm Events","source_system":"NOAA NCEI","date_grain":"daily","total_rows":172633,"last_observation":"2026-03-26 00:00:00+00:00","last_inserted_at":"2026-03-27 07:00:25.629512+00:00","hours_since_last_insert":11,"rows_last_24h":7,"rows_last_7d":49,"rows_last_30d":238,"active_days_last_30":21,"status":"healthy","uptime_pct_30d":70.0},
{"signal_id":42,"signal_name":"HD Online Availability","source_system":"Home Depot","date_grain":"daily","total_rows":1617458,"last_observation":"2026-03-26 00:00:00+00:00","last_inserted_at":"2026-03-27 09:00:18.341438+00:00","hours_since_last_insert":9,"rows_last_24h":175695,"rows_last_7d":1081243,"rows_last_30d":1122330,"active_days_last_30":11,"status":"healthy","uptime_pct_30d":36.7},
{"signal_id":40,"signal_name":"Home Depot Quantity","source_system":"Home Depot","date_grain":"daily","total_rows":729276450,"last_observation":"2026-03-27 18:00:00+00:00","last_inserted_at":"2026-03-27 18:02:43.587393+00:00","hours_since_last_insert":0,"rows_last_24h":16417992,"rows_last_7d":125094846,"rows_last_30d":722251194,"active_days_last_30":31,"status":"healthy","uptime_pct_30d":103.3},
{"signal_id":10,"signal_name":"Home Depot Price","source_system":"Home Depot","date_grain":"daily","total_rows":744297742,"last_observation":"2026-03-27 18:00:00+00:00","last_inserted_at":"2026-03-27 18:02:43.587393+00:00","hours_since_last_insert":0,"rows_last_24h":24147602,"rows_last_7d":183988542,"rows_last_30d":737551308,"active_days_last_30":31,"status":"healthy","uptime_pct_30d":103.3},
{"signal_id":41,"signal_name":"Home Depot Discontinued","source_system":"Home Depot","date_grain":"daily","total_rows":834347534,"last_observation":"2026-03-27 18:00:00+00:00","last_inserted_at":"2026-03-27 18:02:43.587393+00:00","hours_since_last_insert":0,"rows_last_24h":26963892,"rows_last_7d":205450908,"rows_last_30d":827322507,"active_days_last_30":31,"status":"healthy","uptime_pct_30d":103.3},
{"signal_id":12,"signal_name":"Home Depot In Stock","source_system":"Home Depot","date_grain":"daily","total_rows":834348037,"last_observation":"2026-03-27 18:00:00+00:00","last_inserted_at":"2026-03-27 18:02:43.587393+00:00","hours_since_last_insert":0,"rows_last_24h":26963896,"rows_last_7d":205450920,"rows_last_30d":827322717,"active_days_last_30":31,"status":"healthy","uptime_pct_30d":103.3},
{"signal_id":11,"signal_name":"Home Depot Original Price","source_system":"Home Depot","date_grain":"daily","total_rows":742678007,"last_observation":"2026-03-27 18:00:00+00:00","last_inserted_at":"2026-03-27 18:02:43.587393+00:00","hours_since_last_insert":0,"rows_last_24h":23971901,"rows_last_7d":182906541,"rows_last_30d":736427386,"active_days_last_30":31,"status":"healthy","uptime_pct_30d":103.3}
];
// Helpers
const fmt = n => {
if (n === 0) return '<span class="dim">--</span>';
if (n >= 1e9) return (n/1e9).toFixed(2) + 'B';
if (n >= 1e6) return (n/1e6).toFixed(1) + 'M';
if (n >= 1e3) return (n/1e3).toFixed(1) + 'K';
return n.toLocaleString();
};
const age = h => {
if (h < 1) return 'now';
if (h < 48) return Math.round(h) + 'h';
const d = Math.round(h/24);
return d < 60 ? d + 'd' : Math.round(d/30) + 'mo';
};
// Group by source (merge Google + google_trends)
const SOURCE_MAP = {
'Google': 'Google Trends', 'google_trends': 'Google Trends',
'Home Depot': 'Home Depot', 'Lowes': "Lowe's",
'FRED': 'FRED', 'USDA RMA': 'USDA RMA',
'Census ACS': 'US Census', 'Census BPS': 'US Census',
'GDELT': 'GDELT', 'FEMA NFIP': 'FEMA',
'BLS QCEW': 'BLS', 'BuildZoom': 'BuildZoom',
'Shovels AI': 'Shovels AI', 'Open-Meteo': 'Open-Meteo',
'NOAA NCEI': 'NOAA', 'NIDIS': 'NIDIS',
'Redfin': 'Redfin', 'Adzuna': 'Adzuna',
};
const groups = {};
DATA.forEach(d => {
const g = SOURCE_MAP[d.source_system] || d.source_system;
(groups[g] = groups[g] || []).push(d);
});
// Sort groups: most-down first, then by total rows desc
const groupOrder = Object.keys(groups).sort((a, b) => {
const aDown = groups[a].filter(d => d.status === 'down').length;
const bDown = groups[b].filter(d => d.status === 'down').length;
if (aDown !== bDown) return bDown - aDown;
const aRows = groups[a].reduce((s, d) => s + d.total_rows, 0);
const bRows = groups[b].reduce((s, d) => s + d.total_rows, 0);
return bRows - aRows;
});
// Summary
const nH = DATA.filter(d => d.status==='healthy').length;
const nS = DATA.filter(d => d.status==='stale').length;
const nD = DATA.filter(d => d.status==='down').length;
const tot = DATA.reduce((a,d) => a + d.total_rows, 0);
const r24 = DATA.reduce((a,d) => a + d.rows_last_24h, 0);
document.getElementById('ts').textContent = new Date().toISOString().slice(0,19).replace('T',' ') + ' UTC';
document.getElementById('summary').innerHTML = `
<span class="s">Signals</span><span class="v">${DATA.length}</span>
<span class="s">Healthy</span><span class="v g">${nH}</span>
<span class="s">Down</span><span class="v r">${nD}</span>
<span class="s">Total rows</span><span class="v">${fmt(tot)}</span>
<span class="s">Last 24h</span><span class="v">${fmt(r24)}</span>
<span class="s">Sources</span><span class="v">${groupOrder.length}</span>
`;
// Render
const container = document.getElementById('groups');
groupOrder.forEach(gName => {
const signals = groups[gName].sort((a,b) => a.hours_since_last_insert - b.hours_since_last_insert);
const gH = signals.filter(d=>d.status==='healthy').length;
const gD = signals.filter(d=>d.status==='down').length;
const gS = signals.filter(d=>d.status==='stale').length;
let statusHtml = '';
if (gH) statusHtml += `<span class="gs"><span class="dot" style="background:var(--green)"></span>${gH}</span>`;
if (gS) statusHtml += `<span class="gs"><span class="dot" style="background:var(--amber)"></span>${gS}</span>`;
if (gD) statusHtml += `<span class="gs"><span class="dot" style="background:var(--red)"></span>${gD}</span>`;
const rows = signals.map(d => {
const up = Math.min(d.uptime_pct_30d, 100);
const upLabel = d.uptime_pct_30d > 100 ? '>100' : d.uptime_pct_30d.toFixed(0);
return `<tr class="${d.status}">
<td><span class="dot"></span></td>
<td>${d.signal_name}</td>
<td class="mono">${d.date_grain}</td>
<td>${fmt(d.total_rows)}</td>
<td>${age(d.hours_since_last_insert)}</td>
<td>${fmt(d.rows_last_24h)}</td>
<td>${fmt(d.rows_last_7d)}</td>
<td><div class="uptime-cell"><span class="uptime-num">${upLabel}%</span><div class="ubar"><div class="fill" style="width:${up}%"></div></div></div></td>
</tr>`;
}).join('');
container.innerHTML += `
<div class="group">
<div class="group-header">
<span class="group-name">${gName}</span>
<span class="group-count">${signals.length} signal${signals.length>1?'s':''}</span>
<div class="group-status-summary">${statusHtml}</div>
</div>
<table>
<tr><th></th><th>Signal</th><th>Grain</th><th>Total</th><th>Last</th><th>24h</th><th>7d</th><th>30d uptime</th></tr>
${rows}
</table>
</div>`;
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment