Skip to content

feat(app): unify alert actions and make the alert source legible - #3015

Merged
jordan-simonovski merged 4 commits into
mainfrom
jordansimonovski/alerts-summary-ux
Aug 28, 2026
Merged

feat(app): unify alert actions and make the alert source legible#3015
jordan-simonovski merged 4 commits into
mainfrom
jordansimonovski/alerts-summary-ux

Conversation

@jordan-simonovski

@jordan-simonovski jordan-simonovski commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Alert actions were split across two surfaces that disagreed: the list could delete and export to Terraform but not edit, the detail page could edit and delete but not export, and each had its own delete confirmation. Nothing on a list row said whether an alert watched a saved search or a dashboard tile — the icon carried that distinction silently. This gives both surfaces the same overflow menu and makes the alert's source legible and filterable.

CleanShot.2026-08-28.at.16.04.24.mp4

What changed

Alerts list

  • Edit from the row menu. The overflow menu opens the existing alert editor in place, so changing a threshold no longer means navigating into the alert first.
  • Source is legible and filterable. Each row's source icon gains a tooltip and accessible label ("Saved search" / "Dashboard tile"), a filter narrows the list to one source, and free-text search matches the source label too, so typing "tile" works without opening the dropdown.
  • Creator demoted out of the properties line into its own dimmed sub-line; the remaining segments no longer break mid-phrase.

Alert detail page

  • Edit, Delete and Terraform export move into that same shared menu. Terraform export is new to this page.
  • The source link becomes an icon beside the alert name, with a tooltip naming the destination.
  • The properties block separates configuration from provenance: the creator joins the created and updated timestamps in a dimmed line beneath.

Team settings tabs also gain icons.

Key decisions

One shared menu, not two parallel ones. The detail page's own edit modal, delete handler and confirmation are deleted in favour of the list's. Two surfaces maintaining separate action sets is how they drifted apart. The menu takes an optional dateRange (the detail page has a picked range for the editor's threshold preview; a list row does not, and derives one from the alert's evaluation interval) and an onDeleted callback so the page can navigate away after deletion.

"Alert source", not "type" or "source". "Type" already means detection type (anomaly vs static threshold) in the alerts UI, and a bare "source" reads as a data source (Logs/Traces/Metrics). The filter is labelled "Filter by alert source" and its query param is alertSource.

One label helper, three consumers. The tooltip, the filter options, and search all call getAlertSourceLabel. The filter compares against the label text, so if these drifted the filter would silently match nothing.

Creator out of the shared summary entirely. Both surfaces render it themselves now. Keeping it in the shared line at equal weight with the alert's configuration is what pushed the line into a second row that wrapped mid-phrase.

Source link beside the title, not among the actions. It navigates to the alert's subject, so it belongs with the identity rather than the verbs acting on the alert. The menu's own source-link item is suppressed on that page to avoid offering it twice.

Impact

Frontend only, no API or schema changes. The detail page's delete confirmation changes from ConfirmDeleteMenu to the shared useConfirm dialog, and deletion returns you to /alerts. The filter's value is a human-readable label carried in the URL (?alertSource=Saved%20search), so renaming a label invalidates shared links.

Two commits, one per surface, if that reads more easily than the combined diff.

Implementation detail
  • The empty state distinguishes "No alerts" from "No matching alerts" via hasFilters, which now includes the source filter.
  • The filter renders when more than one source kind is present, or whenever a value is active — otherwise a stale URL value would hide the control while still excluding every alert, with no way to clear it.
  • Source matching in search is whole-token prefix, not substring: both labels contain an "s", so a substring match on a single character matched everything.
  • The labelled icon uses role="img" (naming is not exposed on a role-less span) and the glyphs are aria-hidden.
  • Delete keeps the same query invalidations (alerts, saved-search, dashboards) as the removed detail-page handler; navigation moved into onDeleted.
  • Known limitation, unchanged here: neither delete path invalidates the single-alert query key, so back-navigation renders cached data until the refetch 404s.
  • The edit modal now mounts per row on the alerts list. Its queries are key-shared so there is no fetch storm, but the modal state lives inside a virtualised row — Mantine's scroll lock makes unmount-while-open unlikely, though hoisting one modal above the virtualiser would remove the risk entirely.
  • Tests: getAlertSourceLabel including its fallback, the menu opening the editor, and the summary omitting the creator in both variants. Full app suite passes (3385).

…ource icons

The alerts page row menu now opens the alert editor, so changing a threshold
no longer means navigating into the alert first. The modal needs a range for
its threshold preview; a list row has none, so it derives one from the alert's
interval when the modal opens.

Each row's source icon gains a tooltip and accessible label naming what the
alert watches, a new filter narrows the list by that source, and free-text
search matches it too. All three read one getAlertSourceLabel helper so their
wording cannot drift. Named 'alert source' rather than 'type' (taken by
detection type) or bare 'source' (reads as a data source).

The creator moves out of the shared properties line into its own dimmed
sub-line: it is provenance, not configuration, and at equal weight it pushed
the line into a second row that broke mid-phrase. Remaining segments no longer
wrap mid-phrase. Team settings tabs gain icons.
Edit, Delete and Terraform export move behind the overflow menu the alerts
list already uses, so the header stops spreading four buttons across the top
and the two surfaces cannot drift apart on which actions an alert offers. The
menu gains an optional dateRange (the detail page has a picked range for the
edit modal's threshold preview, where a list row does not) and an onDeleted
callback so the page can navigate away once the alert is gone.

The link to what the alert watches becomes an icon beside the alert name: it
navigates to the alert's subject, so it belongs with the identity rather than
with the verbs acting on the alert.

The properties block separates configuration from provenance, moving the
creator down to join the created and updated timestamps in one dimmed line.
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview Aug 28, 2026 6:38am
hyperdx-storybook Ready Ready Preview Aug 28, 2026 6:38am

Request Review

@changeset-bot

changeset-bot Bot commented Aug 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d23adc8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@hyperdx/app Minor
@hyperdx/api Minor
@hyperdx/otel-collector Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added the review/tier-2 Low risk — AI review + quick human skim label Aug 28, 2026
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

🟡 Tier 3 — Standard

Introduces new logic, modifies core functionality, or touches areas with non-trivial risk.

Why this tier:

  • Diff size: 366 production lines changed (Tier 2 max: < 250)

Review process: Full human review — logic, architecture, edge cases.
SLA: First-pass feedback within 1 business day.

Stats
  • Production files changed: 9
  • Production lines changed: 366 (+ 76 in test files, excluded from tier calculation)
  • Branch: jordansimonovski/alerts-summary-ux
  • Author: jordan-simonovski

To override this classification, remove the review/tier-3 label and apply a different review/tier-* label. Manual overrides are preserved on subsequent pushes.

@github-actions github-actions Bot added review/tier-3 Standard — full human review required and removed review/tier-2 Low risk — AI review + quick human skim labels Aug 28, 2026
@jordan-simonovski jordan-simonovski changed the title feat(app): edit alerts from the list and filter them by source feat(app): unify alert actions and make the alert source legible Aug 28, 2026
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

E2E Test Results

All tests passed • 321 passed • 1 skipped • 1354s

Status Count
✅ Passed 321
❌ Failed 0
⚠️ Flaky 2
⏭️ Skipped 1

Tests ran across 4 shards in parallel.

View full report →

@greptile-apps

greptile-apps Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR unifies alert actions across list and detail views while making each alert’s source visible and filterable.

  • Adds shared edit, delete, and Terraform-export actions through AlertRowMenu.
  • Adds alert-source labels, filtering, search matching, tooltips, and accessible icon names.
  • Reorganizes alert metadata presentation and adds icons to team settings tabs.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/app/src/AlertDetailPage.tsx Replaces separate detail-page actions with the shared alert menu and moves source navigation beside the alert title; the previously flagged styling issue is resolved.
packages/app/src/AlertsPage.tsx Adds URL-backed alert-source filtering and source-label matching to free-text search.
packages/app/src/components/alerts/AlertRowMenu.tsx Extends the shared row menu with alert editing, configurable preview ranges, and a post-deletion callback.
packages/app/src/components/alerts/AlertDetails.tsx Adds accessible source labeling and separates creator provenance from the configuration summary.
packages/app/src/utils/alerts.ts Introduces the shared alert-source label helper used by filtering, search, and source tooltips.

Reviews (3): Last reviewed commit: "Merge branch 'main' into jordansimonovsk..." | Re-trigger Greptile

<ActionIcon
component={Link}
href={alertUrl}
variant="subtle"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Styling bypasses semantic conventions

The new source action uses the raw Mantine gray palette, while the related summary changes introduce repeated raw style objects. This bypasses the repository's semantic color and Mantine style-prop conventions, making the new alert UI harder to keep consistent across themes.

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Deep Review

Frontend-only PR unifying alert actions into one shared overflow menu across the alerts list and detail page, making the alert source legible/filterable/searchable, and reorganizing creator/provenance metadata. Scope verified against base 0558f77e: 8 production files + 3 test files + 1 changeset + 1 stylesheet. No API or schema changes. The prior Greptile styling comment (AlertDetailPage.tsx:157, raw Mantine palette / repeated inline style objects) is already resolved by the final commit 02085b5f, which moved the source ActionIcon to variant="subtle" and replaced inline style objects with .propertiesSummary / .propertySegment module classes.

✅ No critical issues found. No P0/P1 defects: imports are cleaned correctly (AlertSource removed from AlertDetailPage, ReactNode imported in TeamPage), the shared AlertRowMenu correctly suppresses its own source-link item on the detail page (no alertUrl passed), and the unresolvable-source path (getAlertSourceLabel → "Unknown source", linkTitle guarded on alert.source) is internally consistent.

🟡 P2 -- recommended

  • packages/app/src/components/alerts/AlertRowMenu.tsx:210 -- EditAlertModal now mounts inside each virtualized alerts-list row, so if a row scrolls out of the virtualizer window while its editor is open the modal unmounts and any unsaved edits are lost.
    • Fix: Hoist a single edit modal above the virtualized list and drive it from row-level menu state so it survives row recycling.
  • packages/app/src/AlertsPage.tsx:69 -- New behavior lacks tests: the alert-source filter, the whole-token-prefix source search branch, and the accessible source icon/tooltip are untested even though the source label, editor-open, and creator-omission cases are covered.
    • Fix: Add tests asserting the source filter narrows the list, that free-text search matches a source token, and that the source icon exposes its accessible label.
🔵 P3 nitpicks (2)
  • packages/app/src/AlertsPage.tsx:31 -- The source filter value is persisted to the URL as a human-readable label (?alertSource=Saved%20search), so renaming a label silently invalidates previously shared links.
    • Fix: Carry a stable AlertSource enum key in the URL and map it to the display label at render time.
  • packages/app/src/AlertsPage.tsx:79 -- The search query q = search.toLowerCase() is compared with startsWith/includes without trimming, so a leading space entered in the box matches nothing (pre-existing pattern, now extended to the source-label branch).
    • Fix: Use search.trim().toLowerCase() for q.

Reviewers (10): correctness, testing, maintainability, project-standards, kieran-typescript, julik-frontend-races, adversarial, previous-comments, agent-native, learnings-researcher.

Testing gaps: source filter, source-label search matching, and the accessible source-icon/tooltip in AlertDetails have no direct test coverage; the delete→onDeleted navigation path on the detail page is exercised only indirectly.

The source-link icon paired variant="subtle" with the raw Mantine gray
palette, which the code style forbids; the variant already carries the
intended treatment across themes. The properties line's repeated inline style
objects move into AlertsPage.module.scss, matching how the other alert
components style themselves.

Also raises the AlertRowMenu suite's timeout above the 5s its own openMenu
helper waits for the dropdown. The two were equal, so under parallel workers a
slow transition consumed the whole per-test budget and timed the test out
before its assertions ran.

@wrn14897 wrn14897 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good stuff!

@jordan-simonovski
jordan-simonovski merged commit db6ee45 into main Aug 28, 2026
40 of 42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review/tier-3 Standard — full human review required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants