Registry and Analytics: run, subnet, direction and protocol filters, successes-by-target chart

Registry (/registry):
- filters by run (slice by the address's cycle in that run), subnet
  (drop-down of configured subnets), direction (egress/ingress) and
  protocol (icmp, tcp, ssh, https, tls); status in scope is computed over
  the narrowed checks
- chart "successful checks per target (egress) / site (ingress)" when both
  direction and protocol are chosen; a row opens the list of addresses
  (dialog, CSV)
- API: direction/protocol parameters and run in GET /admin/registry,
  GET /admin/registry/breakdown and /breakdown/list
- subnet filter passes ids as one JSON parameter (SQLite variable limit)

Analytics (/analytics):
- subnet filter recomputes the whole page over the addresses of the run
  inside the subnet; only their checks are read; cache per run and subnet
- direction and protocol focus the page; with both set the registry chart
  is shown
- subnet parameter in GET /admin/analytics/runs/{id} and lists (JSON, CSV)

Docs: plans and summaries in docs/changes, README, API, USAGE.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ayurishchevandClaude Sonnet 5.5 committed 2026-10-06 14:23:48 +03:00
1 parent 068c10ea1c
commit ded196ec8d
40 files changed
+2545 -188

No files matched your search

+10
View File
@@ -36,6 +36,16 @@
.an select, .an .an-btn { font: 500 13px var(--font-mono); background: var(--surface); color: var(--text); border: 1px solid var(--border); border-radius: var(--an-radius); padding: 7px 10px; }
.an select { min-width: 0; max-width: 100%; flex: 1 1 160px; }
.an-btn { cursor: pointer; } .an-btn:hover { background: var(--surface-alt); }
.an [hidden] { display: none !important; }
.an-body { display: grid; gap: 16px; min-width: 0; align-content: start; }
#an-filter { display: grid; gap: 12px; }
/* filter fields: label above the select, wrapping as whole pairs; in a column the fields keep their own height */
.an-fields { display: flex; flex-wrap: wrap; gap: 10px 14px; align-items: flex-end; }
.an-field { display: flex; flex-direction: column; gap: 5px; flex: 1 1 160px; min-width: 0; }
.an-field label { font: 700 12px var(--font-mono); color: var(--text-muted); text-transform: uppercase; letter-spacing: .06em; }
.an-field select { flex: 0 0 auto; }
.an-reset { text-decoration: none; }
.an .bd-wrap { margin-bottom: 0; } /* the chart of the registry brings its own space; here the grid gap is enough */
.an-tabs { display: inline-flex; gap: 0; }
.an-tabs button { font: 500 12px var(--font-mono); background: var(--surface); color: var(--text-muted); border: 1px solid var(--border); padding: 5px 12px; cursor: pointer; }
.an-tabs button + button { border-left: 0; }