[Alerting V2] Episode table actions#260195
Conversation
- snooze/unsnooze - activate/deactivate - acknowledge/unacknowledge
|
Pinging @elastic/response-ops (Team:ResponseOps) |
f74919e to
bb9c735
Compare
8db3f7b to
6516e49
Compare
| @@ -165,10 +202,53 @@ export function AlertsV2Page() { | |||
| onSetColumns={onSetColumns} | |||
| canDragAndDropColumns | |||
| showTimeCol={!!dataView.timeFieldName} | |||
| customGridColumnsConfiguration={{ | |||
| actions: ({ column }) => ({ | |||
There was a problem hiding this comment.
Not suggesting to use those, but FYI UnifiedDataGrid has built-in support for row actions (see the rowAdditionalLeadingControls and trailingControlColumns props). Row leading controls are displayed as icon buttons by default, collapsing extra actions in a ⠇ menu. I think it would require changes on the data table side to show full buttons instead, so again not suggesting to use these, but pointing this out since we'll want to open episodes in a flyout at some point, which is built-in the unified data table, and triggered through a default leading control. I guess we'll have to find a way to trigger that from one of these action buttons then, (perhaps forwarding clicks on the entire row like @joana-cps was suggesting).
There was a problem hiding this comment.
Also, personal aesthetic nit: how about aligning the buttons to the left and the more menu to the right?
I had that initially :D design boss @joana-cps said no! and tbf after seeing both I agree with her 😅
There was a problem hiding this comment.
If UnifiedDataGrid built-in support for row actions only supports icon buttons, we can move to it. It will help with this visual disalignment that only happens because of the text changes. We can evaluate it's used after M1.
...form/packages/shared/response-ops/alerting-v2-episodes-ui/hooks/use_fetch_episode_actions.ts
Outdated
Show resolved
Hide resolved
...atform/packages/shared/response-ops/alerting-v2-episodes-ui/hooks/use_fetch_group_actions.ts
Outdated
Show resolved
Hide resolved
x-pack/platform/packages/shared/response-ops/alerting-v2-schemas/src/alert_action_schema.ts
Outdated
Show resolved
Hide resolved
...plugins/shared/alerting_v2/server/routes/alert_actions/create_alert_action_route_for_type.ts
Show resolved
Hide resolved
|
@macroscope-app review |
|
Code review started. Results will be posted as check runs on this PR. |
baileycash-elastic
left a comment
There was a problem hiding this comment.
looks good aside from merge conflicts
Good point. Is your suggestion to move to the first column as we have in V1? I saw some EUI work on tables lately that allows us to fix columns and add horizontal scroll to help with the responsiveness issues. I'll see if it covers |
c114e2c to
c8f69bb
Compare
...alerting-v2-episodes-ui/components/alert_episodes/actions/acknowledge_action_button.test.tsx
Outdated
Show resolved
Hide resolved
341d2d6 to
73971b3
Compare
cnasikas
left a comment
There was a problem hiding this comment.
LGMT! I left some comments. Mostly are nits. Also, should we remove x-pack/platform/plugins/shared/alerting_v2/server/routes/alert_actions/create_alert_action_route.ts now that we have the CreateTypedAlertActionRoute?
x-pack/solutions/observability/plugins/observability/public/pages/alerts_v2/alerts_v2.tsx
Show resolved
Hide resolved
...plugins/shared/alerting_v2/server/routes/alert_actions/create_alert_action_route_for_type.ts
Outdated
Show resolved
Hide resolved
...alerting-v2-episodes-ui/components/alert_episodes/actions/acknowledge_action_button.test.tsx
Outdated
Show resolved
Hide resolved
...-ops/alerting-v2-episodes-ui/components/alert_episodes/actions/acknowledge_action_button.tsx
Show resolved
Hide resolved
| }); | ||
| }} | ||
| isLoading={isLoading} | ||
| isDisabled={!episodeId || !groupHash} |
There was a problem hiding this comment.
Wondering if we should hide the button instead by returning null. Wdyt? Not sure under which scenarios the episodeId or the groupHash can be undefined. If we are waiting for queries to return data, maybe the parent component can handle that, and this component always assumes that the episodeId or the groupHash is defined.
...plugins/shared/alerting_v2/server/routes/alert_actions/create_ack_alert_action_route.test.ts
Show resolved
Hide resolved
...onse-ops/alerting-v2-episodes-ui/components/alert_episodes/actions/resolve_action_button.tsx
Show resolved
Hide resolved
...esponse-ops/alerting-v2-episodes-ui/components/alert_episodes/actions/alert_episode_tags.tsx
Outdated
Show resolved
Hide resolved
...esponse-ops/alerting-v2-episodes-ui/components/alert_episodes/actions/alert_episode_tags.tsx
Outdated
Show resolved
Hide resolved
...-ops/alerting-v2-episodes-ui/components/alert_episodes/actions/alert_episode_snooze_form.tsx
Show resolved
Hide resolved
⏳ Build in-progress, with failures
Failed CI StepsHistory
cc @adcoelho |
There was a problem hiding this comment.
When I snoozed one episode, another episode was also snoozed. I can't really tell what makes up this episode, since we don't have the grouping information yet.
Elastic.mp4
Here's the test data I used https://gist.github.com/dominiqueclarke/62affbd65e64daa362f22643fc8edd33
dominiqueclarke
left a comment
There was a problem hiding this comment.
After re-checking, I noticed my original test data had condition split, and we don't currently support condition. Put the condition in the base query and this worked as expected. LGTM
…heck * commit 'af66aadafa7470ca8ba3e3edd3793bde81fa4596': (31 commits) [Scout] Update test config manifests (elastic#260850) [SLO]: register alerts schema embeddable (elastic#256570) [Discover][Flyout] Update overview fields table with new prop headerVisibility set to false (elastic#260692) [AiButton/Security] Migrate ai-related buttons to use custom styles (elastic#259847) [One Workflow] Fix connector step icons falling back to generic plugs in YAML editor (elastic#260785) [Agent Builder] Dashboard skill: Guard against editing non-ESQL based panels (elastic#260714) Security quality gate Cypress cleanup - Periodic Pipeline (elastic#260820) [Search] Deprecate search indices in favour of index management (elastic#260210) Upgrade dependency @elastic/charts to v71.4.0 (elastic#260593) [Security Solution] [HDQ]: integration-based targeting and descriptor versioning (elastic#258418) docs(saved-objects): consolidate docs and document scoped vs system client (elastic#260743) Fix observability UIAM config and add CPS observability variant (elastic#260485) [Security Solution] Add "matched_indices_count" rule execution metric (elastic#259938) [SigEvents] Add callout with working promote action. (elastic#260433) [Alerting V2] Episode table actions (elastic#260195) [Automatic Migration] Add ability to skip Reference Set step in QRadar upload workflow (elastic#259959) [Rules] KQL-to-DSL conversion without data view produces incorrect queries for keyword fields for Metric threshold rule (elastic#260046) Update dependency lightningcss to v1.32.0 (main) (elastic#259017) Update postcss (main) (elastic#255420) Migrate server-side apm.addLabels to OTel dual-write helpers (elastic#259619) ...
Closes elastic#258318 Closes elastic#258319 ## Summary Adds logic to the alert episodes table to display `.alert_actions` information. This includes: - New action-specific API paths. - Snooze - **Per group hash.** - Button in the actions column opens a popover where an `until` can be picked. - **When snoozed** - A bell shows up in the status column. - Mouse over the bell icon to see until when the snooze is in effect. - Unsnooze - **Per group hash.** - Clicking the button removes the snooze. - Ack/Unack - **Per episode.** - Button in the actions column - When "acked", an icon shows in the status column. - Tags - This PR only handles displaying tags. They need to be created via API. - Resolve/Unresolve - **Per group hash.** - Button inside the ellipsis always - The status is turned to `inactive` **regardless of the "real" status.** <img width="1704" height="672" alt="Screenshot 2026-03-25 at 16 04 12" src="https://github.com/user-attachments/assets/5ef4111a-6e0c-4114-a60e-ce5f81a86ac6" /> ## Testing <details> <summary>POST mock episodes</summary> ``` POST _bulk { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:00:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-1", "episode": { "id": "ep-001", "status": "pending" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:01:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-1", "episode": { "id": "ep-001", "status": "pending" }, "status": "no_data" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:02:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-1", "episode": { "id": "ep-001", "status": "inactive" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:03:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-1", "episode": { "id": "ep-001", "status": "inactive" }, "status": "no_data" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:04:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-1", "episode": { "id": "ep-001", "status": "inactive" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:05:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-1", "episode": { "id": "ep-001", "status": "pending" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:06:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-1", "episode": { "id": "ep-001", "status": "active" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:07:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-2", "episode": { "id": "ep-002", "status": "active" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:08:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-2", "episode": { "id": "ep-002", "status": "active" }, "status": "no_data" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:09:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-2", "episode": { "id": "ep-002", "status": "recovering" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:10:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-2", "episode": { "id": "ep-002", "status": "recovering" }, "status": "no_data" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:11:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-2", "episode": { "id": "ep-002", "status": "active" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:12:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-2", "episode": { "id": "ep-002", "status": "recovering" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:13:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-2", "episode": { "id": "ep-002", "status": "inactive" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:14:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-1", "episode": { "id": "ep-003", "status": "pending" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:15:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "gh-1", "episode": { "id": "ep-003", "status": "inactive" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:16:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-4", "episode": { "id": "ep-004", "status": "pending" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:17:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-4", "episode": { "id": "ep-004", "status": "active" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:18:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-4", "episode": { "id": "ep-004", "status": "recovering" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:19:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-4", "episode": { "id": "ep-004", "status": "inactive" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:20:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-5", "episode": { "id": "ep-005", "status": "pending" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:21:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-5", "episode": { "id": "ep-005", "status": "pending" }, "status": "no_data" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:22:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-5", "episode": { "id": "ep-005", "status": "inactive" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:23:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-9", "episode": { "id": "ep-006", "status": "pending" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:24:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-9", "episode": { "id": "ep-006", "status": "active" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:25:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-9", "episode": { "id": "ep-006", "status": "active" }, "status": "no_data" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:26:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-1" }, "group_hash": "elasticgh-9", "episode": { "id": "ep-006", "status": "inactive" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:14:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-2" }, "group_hash": "elasticgh-7", "episode": { "id": "ep-007", "status": "pending" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:15:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-2" }, "group_hash": "elasticgh-7", "episode": { "id": "ep-007", "status": "inactive" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:16:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-3" }, "group_hash": "elasticgh-8", "episode": { "id": "ep-008", "status": "pending" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:17:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-3" }, "group_hash": "elasticgh-8", "episode": { "id": "ep-008", "status": "active" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:18:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-3" }, "group_hash": "elasticgh-8", "episode": { "id": "ep-008", "status": "recovering" }, "status": "recovered" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:20:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-4" }, "group_hash": "elasticgh-9", "episode": { "id": "ep-009", "status": "pending" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:21:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-4" }, "group_hash": "elasticgh-9", "episode": { "id": "ep-009", "status": "pending" }, "status": "no_data" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:23:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-5" }, "group_hash": "elasticgh-10", "episode": { "id": "ep-010", "status": "pending" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:24:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-5" }, "group_hash": "elasticgh-10", "episode": { "id": "ep-010", "status": "active" }, "status": "breached" } { "create": { "_index": ".rule-events" }} { "@timestamp": "2026-01-27T16:25:00.000Z", "source": "internal", "type": "alert", "rule": { "id": "rule-5" }, "group_hash": "elasticgh-10", "episode": { "id": "ep-010", "status": "active" }, "status": "no_data" } ``` </details> - In the POST above, episodes 1 and 3, and episodes 6 and 9 have the same group hashes. - Go to `https://localhost:5601/app/observability/alerts-v2` and try all buttons. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>

Closes #258318
Closes #258319
Summary
Adds logic to the alert episodes table to display
.alert_actionsinformation.This includes:
untilcan be picked.inactiveregardless of the "real" status.Testing
POST mock episodes
https://localhost:5601/app/observability/alerts-v2and try all buttons.