Repository navigation
Add the custom-alert web authoring editor (#3285, Component 7) - #3357
Merged
Merged
Conversation
Ports the custom-views editor to author custom alert rules over the already-shipped /api/alerts CRUD + /validate + /test surface, mirroring pages/views.js / views-api.js / editor.js exactly. - alerts-api.js: the /api/alerts client, the twin of views-api.js (list / get / create / update / delete with version optimistic concurrency, plus the alert-only validate + test POSTs). Re-exports the shared getSession / getCatalog so one cache backs every composer surface. - pages/alert-rules.js: the rule list (name, enabled/paused, and per-card metric / condition / scope chips enriched from the definition) + a first- run hero + a "New from template" menu, the twin of renderViewList. - alert-editor.js: the rule editor. Reuses the shared composer body for the metric (locked to a Scalar metric), plus predicate (gt/ge/lt/le + warn / critical thresholds), hysteresis, scope (all / specific servers), and an optional cadence. Inline validation via POST /api/alerts/validate and a live "current value / would-fire per server" preview via POST /api/alerts/test, both debounced. Mirrors the composer's save-blocker for the cheap structural rules (window ceiling, warn/critical ordering, the count-with-'<' trap) so the operator gets a reason without a round-trip. - editor.js: buildComposedPanelBody gains a metricOnly mode (a scalar metric picker: metric + aggregate + unit + filters, no shape/group/chart/identity or preview) and a generic panelExtraAction hook. No alert knowledge added. - alert-seed.js: a leaf module for the "Create alert from this metric" handoff (a copy, not a live binding), offered on a scalar panel in both the dashboard and notebook composers via the panelExtraAction hook — a clean DAG, no editor.js <-> alert-editor.js import cycle. - app.js / index.html / editor.css: the #/alert-rules + #/alert-rule routes, the nav entry, the poll-clobber guard, and the styles. Templates are read from the existing GET /api/alert-templates (the server- authored, drift-guarded CustomAlertTemplates set) rather than hardcoded in JS, since — unlike views' client-side template constants — the alert set is C# validated against the live catalog on every build. Build: 0 Warning(s) / 0 Error(s). Air-gap self-containment + the composer probe-failed pin verified green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WejwpgWF5Xfm3fAmoEbFz4
Review summaryReviewed the new custom-alert-rule web editor (Darling-only: No T-SQL is touched by this PR, so the T-SQL style rules don't apply here. Lite has no web dashboard at all (it's WPF-only), so there's no Lite counterpart for this surface — no parity drift to flag. Checked and confirmed correct:
Nothing else stood out as a correctness, security, or performance concern. This is a solid, well cross-checked port of the composer pattern onto the alert-rule surface. |
This was referenced Sep 12, 2026
pull Bot
pushed a commit
to ehtick/PerformanceMonitor
that referenced
this pull request
Sep 18, 2026
…in the changelog The erikdarlingdata#3285 [Unreleased] "Added" bullet said "a visual web editor is a follow-up" -- it shipped in erikdarlingdata#3357, so this flips it to describe the editor (Scalar compose picker, inline validation, live per-server would-fire preview, start-from-template, create-from-panel). Also corrects "a server/tag scope" to "a scope of all servers or a chosen few": tag scope is deferred (erikdarlingdata#3350), so the bullet should not claim it. Documentation only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WejwpgWF5Xfm3fAmoEbFz4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Custom-alert web authoring editor (#3285, Component 7)
The one remaining unbuilt piece of custom alerting — the web rule authoring editor. The backend, MCP tools, templates, and the
/api/alertsendpoints all already shipped; this is a faithful front-end port of the custom-views editor onto that surface.What's here
wwwroot/js/alerts-api.js— the/api/alertsclient, the twin ofviews-api.js: list / get / create / update / delete with the sameversionoptimistic-concurrency + response classification, plus the alert-onlyvalidateandtestPOSTs. Re-exports the sharedgetSession/getCatalogso one cache backs every composer surface.wwwroot/js/pages/alert-rules.js— the rule list, the twin ofrenderViewList: cards (name, enabled/paused, and per-card metric / condition / scope chips enriched from the definition), a first-run hero, and a "New from template" menu.wwwroot/js/alert-editor.js— the rule editor. Reuses the shared composer body for the metric (a Scalar metric), plus predicate (gt/ge/lt/le+ warn/critical thresholds), hysteresis (breach/clear samples), scope (all / specific servers), and an optional evaluation cadence (Advanced). Inline validation viaPOST /api/alerts/validate, and a live "current value / would-fire per server" preview viaPOST /api/alerts/test, both debounced. Mirrors the composer's save-blocker for the cheap structural rules — window ceiling (24h), warn/critical ordering, and the count-with-<trap — so the operator gets a reason without a round-trip, with the server re-validating on every write.wwwroot/js/editor.js—buildComposedPanelBodygains ametricOnlymode (a Scalar metric picker: metric + aggregate + unit + filters; no shape/group/chart/identity or preview) and a genericpanelExtraActionhook. No alert knowledge added to the shared composer.wwwroot/js/alert-seed.js— a leaf module for the "Create alert from this metric" handoff (a copy, not a live binding), offered on a Scalar panel in both the dashboard and notebook composers via thepanelExtraActionhook. A leaf so there's noeditor.js↔alert-editor.jsimport cycle (callers pass their owncomposedPanelToDesc).app.js/index.html/editor.css— the#/alert-rules+#/alert-rule/new[/{template}]+#/alert-rule/{id}routes, the "Alert Rules" nav entry, the poll-clobber guard (alertEditornever re-rendered mid-edit), and the styles.Template-serving approach (the decision you asked me to make + note)
Templates are read from the existing
GET /api/alert-templates(which wraps thelist_custom_alert_templatesMCP tool), not hardcoded in JS. Rationale: unlike custom-views' templates — which are client-side JS constants (view-templates.js) — the alert starter set is server-authored C# (CustomAlertTemplates.All), drift-guarded against the live catalog on every build. Re-hardcoding it in JS would duplicate that set and let it drift. A dedicated fetch endpoint already ships and is the exact analog of how the views template picker gets its ready-made set, so mirroring "how views serves templates" here means consuming the server's set. Clicking a template opens the editor pre-filled (not an immediate save), because the starters are deliberately conservative and want tuning — mirroring the notebook-template flow.For a reviewer to eyeball
metricOnlyon the shared composer body — the load-bearing reuse. It hides shape/group/chart/identity and the compose preview, forces the Scalar metric, and reuses the same measure/aggregate/unit/filter controls. Worth confirming it reads as a restriction of the existing picker, not a fork.panelExtraActionhook +alert-seed.js— the cycle-free way both composers offer "Create alert from this metric". It's rebuilt on each structural change, so the action reveals/hides live as the panel's shape flips to/from Single value.CustomAlertRuleDefinition.SeverityFor). Labels + help text carry that.validategives the inline verdict (cheap, no DB);testruns only when valid, for the per-server preview. Mirrors the composer's saveBlocker-then-preview shape.Verification
dotnet build …Darling.Service.csproj -c Debug→ 0 Warning(s) / 0 Error(s).node --checkas ES modules; every cross-module import resolves to a real export.DarlingWebSelfContainmentTests(air-gap) andDarlingWebEditorAttributionTests(incl. the composer probe-failed pin, which now discoversalert-editor.jsas a third composer and requires it to distinguish a read-only seat from a failed probe — it does).* text=auto eol=crlf); no mixed-ending files.Deferrals / gaps
config_alert_logto a rule would need a backend change outside this front-end lane, plus a design decision on the correlation/endpoint shape). The spec said "last-fired if available"; flagging rather than filing an issue unilaterally — say the word if you want a tracked backend enhancement.gt/ge/lt/leand all/specific-servers), per the plan; both already have issues.🤖 Generated with Claude Code
https://claude.ai/code/session_01WejwpgWF5Xfm3fAmoEbFz4