Skip to content

feat(alerts): rule editor as sentence cards with plain summaries - #2425

Merged
Makisuo merged 46 commits into
mainfrom
ux/rule-sentence-editor
Nov 10, 2026
Merged

Makisuo merged 46 commits into
mainfrom
ux/rule-sentence-editor

Conversation

@Makisuo

@Makisuo Makisuo commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #2420. The alert rule editor reads as one sentence instead of a numbered stepper: When (signal and scope), Alert when (threshold, checks, noise), Notify (destinations and escalation chains), Name.

What changed

  • Sentence cards. Each clause is a card with a lead word, joined by a connector line and a status dot. No step numbers.
  • One-line summaries. A complete card that isn't being edited shows a plain summary, for example "Error rate on checkout-api in production", "Above 5%, critical above 10%, in 3 checks in a row (5 min each)", "#checkout-oncall, critical escalates to Checkout on-call". Click to edit; Done or Escape closes it. Summaries come from pure functions in editor/summary.ts; the check phrasing is shared with the action bar sentence.
  • "Alert when" stays a sentence when open. Each tier is one row ("Warning when the value is above 5 %, and recovers below ..."), and the checks read "Look at the last 5 min, every Auto. Fire after 3 breaches in a row. Skip windows with fewer than 10 samples." Number fields are small, and the card body is capped so nothing stretches across the page.
  • Problems never hide, and never shout early. Card status comes from the same save-blocking list as the action bar (including "Query too slow for this check interval", which can arrive after load), so a card with a blocker opens and says what's missing. A fresh rule shows only the amber "Missing" notes; red field errors appear after you leave a field or press save.
  • Action bar says one thing: "No changes", "Ready to save", or "Fix before saving:" with each item a button that opens its card and focuses the field. Save is pressable with blockers (it saves nothing, shows the field errors and focuses the first one); it is disabled only when nothing changed.
  • A new rule opens every card; a saved rule opens on its summaries. The live chart stays on top as the preview. Anomaly rules have no Alert when card, as before.
  • Chart: the series is blue in both themes (it used to match the warning line in dark mode), no longer runs over the axis labels, and a rule with nothing to preview shows a line of text, not a drawn placeholder trend. The rule detail and incident pages share the chart and pick this up.
  • Destination and chain names say "removed" only once the lists have loaded.
  • Accessibility: the lead is always the card's heading, the summary is a disclosure button (aria-expanded, aria-controls), focus moves to the opened card and back to the summary on close.
  • New kit piece sentenceCard / sentenceChain; cardButton gains a label option. ruleStep (the numbered step) is deleted.

Before / after

Before After

Notify open, and phone (390px):

Lab: /lab/rule-editor?variant=populated|new|anomaly&theme=light|dark&open=condition,notify.

Verification

  • bunx vitest run src/page/alerts src/page/kit src/page/dashboards/widget src/lab src/*.test.ts: 898 tests pass with feat(query-builder): condition builder for the where clause #2420's latest merged in (summary unit tests; scene tests for collapse and expand, missing cards staying open, a late timing blocker opening its card, the clean / dirty / blocked action bar, jump links, no red on a pristine form, Escape, the templates overlay unmounting after "Start blank").
  • Typecheck clean; oxlint -c .oxlintrc.effect.json clean on changed files; ui:index, ui:patterns:check pass.
  • In a real browser: opening a card focuses its heading, Escape closes an open select before the card, a jump link focuses its field, a blocked save focuses the name field.
  • An independent code review (8 issues) and a design critique at 1440, 1280 and 390px (10 issues) are both fixed.

Not verified: 36px touch heights on a real phone, and the editor against a live org (preview test pending).

🤖 Generated with Claude Code

The query panel's where clause now edits as [field] [operator] [values] rows by default, with a Builder/Text switch back to the text editor. Rows map both ways to the same where-clause string (parse/print over the existing grammar), and every edit leaves as the existing whereClause text change, so previews and saving are unchanged. A clause the rows can't show stays in the text editor with a note.

Fields come from the editor's autocomplete vocabulary: common fields, then resource and source attributes in a drill-down picker (new kit ComboboxPicker). Several values OR only on attribute fields, the only filters the query engine ORs; 'is not' AND-s any number. Adds /lab/condition-builder.
Operators come from one engine table (where-key-rules, held to the clause handlers by test), so the builder offers only clauses the query applies. Text mode is explicit state once typed in. Edits rewrite only their own clause and Add condition emits nothing. Single-value rows use a single picker; product-events excludes and user/group ids take one value; values with both quote kinds are refused. Traces intrinsics are named fields and root_only is left to the span select. Rows lay out on a grid where only the values cell wraps, controls carry row-specific labels, and builder state clears when rows re-parse.
…ries

Replaces the numbered stepper with When / Alert when / Notify / Name cards on a connected rail. A complete card closes to a one-line summary derived from the form; a card with something missing stays open. The live chart sits above the cards as the preview.
Card issues come from saveIssues with the query timing, so a slow SQL check opens Alert when; destination and chain names are loading, found or removed; a critical-only route reads "Critical: ..."; the Alert when summary shares the action bar's checks phrase and says recovery and no data. Cards keep the lead as the heading with the summary as a disclosure (cardButton), move focus on open and close, render their body only when open, and wrap summaries on phones.
@coderabbitai

coderabbitai Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3ed923c0-fc74-4ba3-bdfe-392626decf29
Commits

Reviewing files that changed from the base of the PR and between 2fc0469 and 145b4c4.

Files selected for processing: 44

  • apps/web/e2e/tests/alert-rules.e2e.ts
  • apps/web/src/lab/entries/rule-editor.ts
  • apps/web/src/lab/registry.ts
  • apps/web/src/lab/rule-editor-lab.ts
  • apps/web/src/page/alerts/editor/actions.ts
  • apps/web/src/page/alerts/editor/command.ts
  • apps/web/src/page/alerts/editor/derive-rows.ts
  • apps/web/src/page/alerts/editor/derive.ts
  • apps/web/src/page/alerts/editor/editor-anomaly.scene.test.ts
  • apps/web/src/page/alerts/editor/editor-cards.scene.test.ts
  • apps/web/src/page/alerts/editor/editor-chains.scene.test.ts
  • apps/web/src/page/alerts/editor/editor.scene.test.ts
  • apps/web/src/page/alerts/editor/form-steps.ts
  • apps/web/src/page/alerts/editor/form.ts
  • apps/web/src/page/alerts/editor/init.ts
  • apps/web/src/page/alerts/editor/interval.ts
  • apps/web/src/page/alerts/editor/message.ts
  • apps/web/src/page/alerts/editor/model.ts
  • apps/web/src/page/alerts/editor/steps.ts
  • apps/web/src/page/alerts/editor/sub-steps.ts
  • apps/web/src/page/alerts/editor/summary.test.ts
  • apps/web/src/page/alerts/editor/summary.ts
  • apps/web/src/page/alerts/editor/update.ts
  • apps/web/src/page/alerts/editor/view-action-bar.ts
  • apps/web/src/page/alerts/editor/view-condition.ts
  • apps/web/src/page/alerts/editor/view-details.ts
  • apps/web/src/page/alerts/editor/view-fields.ts
  • apps/web/src/page/alerts/editor/view-hero.ts
  • apps/web/src/page/alerts/editor/view-noise.ts
  • apps/web/src/page/alerts/editor/view-notifications.ts
  • apps/web/src/page/alerts/editor/view-notify.ts
  • apps/web/src/page/alerts/editor/view-query.ts
  • apps/web/src/page/alerts/editor/view-select.ts
  • apps/web/src/page/alerts/editor/view-step.ts
  • apps/web/src/page/alerts/editor/view.ts
  • apps/web/src/page/alerts/shared/preview.ts
  • apps/web/src/page/alerts/shared/rule-chart.ts
  • apps/web/src/page/kit/sentence-card.ts
  • packages/views/src/charts/definitions/alert-rule.ts
  • packages/views/src/ui/INDEX.md
  • packages/views/src/ui/card-button.ts
  • packages/web-data/src/alerts/preview-insights.test.ts
  • packages/web-data/src/alerts/preview-insights.ts
  • scripts/oxlint-plugins/ui-kit-baseline.json
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@maple-review-bot

This comment has been minimized.

Select takes alignItemWithTrigger={false} to open below its trigger. The chips field takes a size. ComboboxPicker's list is 360px wide and its trigger takes a tooltip. A popup with its own search input keeps focus there when an option is pressed, so typing, Enter and Escape go on working after a mouse pick that leaves the list open.
Rows read as sentences: the field and operator are as wide as their text, the field shows its key without the attr./resource. prefix (the group named only when two fields read the same, the full key in the tooltip and label). A narrow editor puts each row on two lines so the field name always shows, and value inputs are 16px on phones. Every row has one value control of one height: chips where it may hold several values, a combobox with suggestions otherwise.

The field list is 360px wide, always has a highlight (the first option on open, the picked field after drilling in), and Enter picks it. The operator list opens below its trigger. The Builder/Text switch is a 28px control at the top right, level with the first row. A clause the rows can't show gets one line saying why, and the dropped OR group warning says only that it is not applied.
… after touch

Alert when reads as sentences: each tier is one row with the same severity chip, and the checks and noise settings are inline sentences with short number fields, capped near max-w-3xl. The check interval and breach mode are selects inside the sentence; the mode switch is a select on a phone.

The action bar says one thing (No changes, Ready to save, or what to fix as jump links that open the card and focus the field). Field errors show only after the field was left or save was pressed. An open card keeps one border around header and body, Done sits last in it, and Escape collapses a complete card.

Notify no longer says no one is notified while a chain routes the tier. The rule chart clips to its window, leaves room for the last tick, draws the series apart from the threshold tones, and says what it is waiting for in text instead of a drawn trend. The lab runs the templates dialog's exit and answers previews from fixtures.
@maple-review-bot

This comment has been minimized.

@maple-review-bot

This comment has been minimized.

@Makisuo

Makisuo commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

Both notes fixed in d3e87a1. F1: sentenceCard takes problems beside issues; the two interval blockers are said in full ("Query too slow for this check interval"), missing fields keep "Missing: ...", and a card with both reads "Missing: Threshold. Query too slow ...". F2: the idle chart says "Enter a number for the threshold to preview it ..." when the threshold is not a number (the preview's own readiness check; a blank threshold still previews as 0), and "Pick a signal ..." otherwise; scene test added.

@maple-review-bot

This comment has been minimized.

@maple-review-bot

This comment has been minimized.

A pressed option took focus to the listbox, where Escape and Enter reached
nothing, so a chips picker stayed open until a press outside. Presses in any
combobox list now leave focus in the input that handles the keys, and a
field's list closes once focus leaves the field (Tab).
…inds is refused

The note sat under the field, covered by the open list, which still said
"Type a value and press Enter".
The grammar reads `service.name ==` as the value "=", so the builder showed
the row "Service is =". A bare value that is the rest of a mistyped operator
now keeps the clause in Text with the syntax reason.
Number("") is 0, so clearing the threshold previewed the rule against 0 and
drew "Breach above 0%". A blank threshold now sends no preview and the chart
asks for a number.
…ed by

The invalid input pointed aria-describedby at rule-name-error, which nothing
rendered.
The rule diff compared the builder draft's JSON, add-on flags included, so
opening Group by on a saved rule read as "1 unsaved change". It now compares
the draft as the query reads it: an add-on left empty counts as closed.
It was hidden below sm; from sm the header is unchanged.
@maple-review-bot

This comment has been minimized.

@Makisuo

Makisuo commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

Preview test

Tested on the combined preview of the whole stack (#2466, app-pr-2466.maple.dev) by a separate test agent in a real browser: happy paths, break attempts, light and dark, and a 390x844 viewport. No uncaught page errors.

Passed: a new rule opens as When, Alert when, Notify and Name cards with no step numbers; a threshold rule previews against the chosen range with the dashed threshold and a "Would have fired" verdict; validation marks missing fields amber and real problems (tiers in the wrong order, an interval longer than the window) on the card and in the action bar, whose items focus their field; the bar counts unsaved changes and Cancel returns to the Rules section; save, edit, a filter added with the condition builder and a group-by all persist; the anomaly type drops the condition card and the chart.

Found and fixed in this push:

  • A blank threshold was previewed as 0, with a line and "Breach above 0%". A blank threshold is now missing: no preview request, no line, and the chart says what to enter (4fab01963d).
  • The rule name pointed aria-describedby at an error element that did not exist. The error is rendered now (b6039bcb30).
  • Opening an empty add-on such as Group by counted as an unsaved change (91061a3fe0, f3c1222195).
  • The "Would have fired" verdict was hidden on a phone. It wraps under the chart title (b0d1169d17).
  • The preview's end-to-end suite failed on this branch: two alert rule tests looked for fields that now sit inside closed cards and for a renamed control. The tests follow the new editor (a4f05c413c).

Still open: leaving the editor with unsaved edits gives no warning; the rule detail page words the same threshold differently (> 0.04 against the editor's 4%); the app has no way to delete a rule (also true on main).

Traces (preview environment pr-2466, about 1,900 API requests during the test): no 5xx on any route and no error spans in the API, web worker or alerting services. POST /v2/alerts/rules/preview p50 54 ms, p95 253 ms over 67 calls; PATCH /v2/alerts/rules/:id p95 281 ms.

rule ready to save
validation
phone layout

@maple-review-bot

This comment has been minimized.

Base automatically changed from ux/condition-builder to main November 10, 2026 14:29
# Conflicts:
#	apps/web/src/page/alerts/editor/view-action-bar.ts
@maple-review-bot

maple-review-bot Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 10/10 · safe to merge. No defect found in the editor state, summaries, card a11y or chart paths I read; the lab fixtures and the new scene-test files were only partly read.
no findings · tests covered · risk medium

The alert rule editor becomes sentence cards with plain one-line summaries, cards that stay open while they hold a save blocker, and one action bar that turns Save into a validation attempt. Presentation and editor state only; safe to merge.

  • sentenceCard/sentenceChain kit primitive with disclosure button, header h2 and focus return to the summary
  • summary.ts pure summaries per card: watch, condition, notify, name
  • Save is pressable with blockers: ClickedSave reveals field errors and focuses the first one
  • ruleChart gets a real empty/loading text state and clips its series to the range

145b4c4 · What was checked, coverage and telemetry details are on the Maple / review check. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@Makisuo
Makisuo merged commit bc6d39e into main Nov 10, 2026
42 checks passed
@Makisuo
Makisuo deleted the ux/rule-sentence-editor branch November 10, 2026 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant