<#1010 Alerting system Stage 6: SPA 'Alerts' secti...
# osctrl
g
#1010 Alerting system Stage 6: SPA 'Alerts' section Pull request opened by javuto Alerting system Stage 6: SPA "Alerts" section Problem Stages 1–5 delivered the complete alerting backend — rule matching on ingested logs, node liveness transitions, webhook/email delivery, a management API, and instant hot-reload — but managing it required the CLI or direct database edits. This PR adds the operator UI: a full "Alerts" section in the SPA, feature-gated the same way as Log Sinks and Auth Providers. Change Feature gating •
cmd/api/handlers/features.go
— new
alerts
flag in
GET /api/v1/features
, driven by the alerts manager's presence (off when
--alerts-enabled
is unset); regression test added for the off-by-default case •
frontend/src/api/features.ts
—
alerts?: boolean
in the
Features
type API client — new
frontend/src/api/alerts.ts
• Typed wrappers for every Stage-4 endpoint: rules CRUD, channels CRUD plus the channel-type registry, history, and apply — mirroring the log-sinks client conventions (wire shapes matching the API DTOs) Alerts page — new
frontend/src/features/alerts/AlertsPage.tsx
(~1,100 lines, LogSinksPage visual/structural conventions: sticky header, SkeletonRow loading, EmptyState, ModalShell, CSS-var tokens only): • Three tabs — Rules, Channels, History — with an environment selector (Global fallback + per-environment), matching log sinks semantics • Rule editor modal: source picker covering all five sources with help text; pattern inputs (type/field/value) render only for pattern sources and disappear for node-state sources; severity floor for status logs; cooldown with default hint; channel checkboxes; client-side validation • Channel editor modal: registry-driven dynamic form from
/channels/types
— typed inputs (string / integer / boolean / secret) with defaults prefilled on create, password-masked secret fields on edit,
***
placeholder semantics preserved server-side; type locked while editing • Apply changes: queues the reload-alerts service command and polls it to consumption — the same UX as the log-sinks apply flow • Disabled-feature shell explaining
alertsEnabled: false
and how to enable, with zero endpoint calls when the feature is off Wiring •
routes/_app/alerts.tsx
route + router registration • SideNav "Alerts" item (bell icon, amber tone) in the Admin section, gated on
features?.alerts
— hidden entirely on deployments with alerting off Validation • Frontend: full suite 303/303 tests passing (292 pre-existing + 11 new),
npm run check
(tsc) clean • New AlertsPage tests: empty state + fetch wiring, disabled shell (asserts the alerts endpoints are never called), rules table rendering (source, pattern, channel attribution, node-state em-dash), channels tab with registry description, history tab, rule create round-trip (payload asserted), pattern-required validation, pattern inputs hidden for node-state sources, channel create with registry defaults asserted in the payload, rule delete, apply triggering the reload command • Backend:
go build ./...
clean;
go test ./cmd/api/... ./pkg/alerts/
green, including the updated features regression test • A rules-of-hooks violation (memoized data after early returns) was caught by the new tests and fixed before merge — the page now orders hooks correctly for the disabled-feature early return path Roadmap position Stage 6 of 7 (
alerts-frontend
). The alerting system is now fully operable from the UI: create rules and channels through typed forms, watch dispatched alerts land in history, and hot-reload osctrl-tls with one click. Remaining: Stage 7 — load hardening (ingest regression benchmark under rule load) and the alert-history retention sweep. jmpsec/osctrl