Repository navigation
[Nightshift] Add the Detections Events tab and header redesign - #299123
achyutjhunjhunwala merged 22 commits into
Conversation
eba95ae to
e676ffe
Compare
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
- Fall back to the default time range when the URL range is malformed, and skip duplicate history entries on refresh. - Show an error callout with retry when the events list fails to load. - Tab links carry only the time range. - Keep flyout investigation completions in the Detection list cache, not only the landing cache. - Share status labels, severity colours and query keys instead of copying them; label the flyout timestamp as last updated. - Remove the unused chat footer and the showTitle props. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e676ffe to
4005687
Compare
- Rename the page to Detections at /detections; /detection links redirect. - Show Sources and Settings in the header; Settings opens the detection settings tab. - Restyle the overview as the Detection engine panel: Monitoring/Paused badge and icon tiles for knowledge indicators, sources, rules, discoveries and significant events. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the events list - GET /internal/significant_events/events accepts sort_field (created_at, severity, status), sort_order and investigation_state. - New GET /internal/significant_events/events/_facets counts the latest event states per severity, status and investigation state; each dimension ignores its own filter. - Investigation state comes from the stored investigations entries: none, at least one without completed_at, or all completed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Columns: event (title and two-line summary), time, status, severity, investigation and a single action. - Sort by time, status or severity (default: most severe first), stored in the URL and done on the server. - Severity, Status and Investigation filters show per-option counts from the new facets endpoint. - The row action starts an investigation when none exists, otherwise opens the event; restart and mark inactive stay in the event flyout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Use chevronSingleDown on the filter buttons; arrowDown isn't an EUI icon. - Move Automations into the overflow menu on Detections so Sources and Settings stay visible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Event column: plain bold title, two-line summary and a Significant event badge.
- Time shows short numeric ages ("6 min. ago") with the exact time in a tooltip.
- Severity uses regular text size; one action opens the event (Investigate or View investigation).
- Compact date picker and compressed search and filters.
- Overview tiles: tinted icon squares and small one-line labels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Avatar - Each tile is an EuiAvatar icon square plus an EuiStat count and label, with no tooltips. - Tiles take their natural width so labels stay on one line. - Drop the Significant event badge from the events table. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page is still unlinked, so no /detection links need to keep working. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Reset the page when the time range changes, and move back to the last page when the URL points past it. - Write the search to the URL only from typing, so Back and Forward keep their search. - Drop a dead ?eventId= link with replace, so Back doesn't reopen it. - Use FormattedRelativeTime and reactRouterNavigate instead of local versions. - Share the investigation state rule, sort guard and search limit. - Keep EBT tracking on meaningful actions only, and remove low-value tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Describe the second investigation run as a queued follow-up, which is what the server does. - Scope pending investigation completions to a round, so a re-run doesn't show as completed. - Hide facet counts when they're unavailable instead of showing zeroes. - Cancel a pending search write on Back/Forward. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…time - Render the Monitoring dot as an inline icon in the badge, so it centres at the standard badge height. - Explain in the Time column header that the range shows events live during it. - Widen the Status column so "Recovering" stays on one line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ader and tab Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tions header and tab" This reverts commit 1429e11. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
crespocarlos
left a comment
There was a problem hiding this comment.
Left a few comments
| // A missing alert.status decodes as active (see decodeSignificantEvent). | ||
| return query.pipe`EVAL ${esql.col(SORT_RANK_COLUMN)} = CASE(${esql.col( | ||
| 'alert.status' | ||
| )} == ${esql.str('inactive')}, 1, ${esql.col('alert.status')} == ${esql.str( |
There was a problem hiding this comment.
We have constants for these statuses in ALERT_EPISODE_STATUS
There was a problem hiding this comment.
Good call, switched the status CASE and the status facet COALESCE to ALERT_EPISODE_STATUS.* in 453c042.
| }: { | ||
| timeRange: DetectionTimeRange; | ||
| onTimeRangeChange: (timeRange: DetectionTimeRange) => void; | ||
| }): React.ReactElement => { |
There was a problem hiding this comment.
Do we need this ReactElement here?
There was a problem hiding this comment.
Kept it for consistency: the repo guidelines ask for explicit return types on exported functions, and every component in pages/detection declares React.ReactElement.
| }, | ||
| }} | ||
| /> | ||
| ) : !eventsQuery.isLoading && eventsQuery.data && events.length === 0 && !isPastLastPage ? ( |
There was a problem hiding this comment.
Should we add a loading indicator here?
There was a problem hiding this comment.
Good call. EuiBasicTable's loading only draws a thin line, so the first load looked empty. Added a "Loading events…" noItemsMessage in 453c042, the same pattern SLO and Synthetics use.
| }, [event.event_id]); | ||
|
|
||
| useEffect(() => { | ||
| if (latestInvestigation == null || latestInvestigation.completed_at != null) { |
There was a problem hiding this comment.
Are we treating possible failures the same way as no investigations and complete investigations here?
There was a problem hiding this comment.
Today a failed or unreadable investigation is closed out in the cache so the row doesn't spin "In progress" forever, since the server has no failed state yet (moved unchanged from main). #299456 fixes this properly: failed runs are recorded on the event and read errors no longer count as finished.
| const investigationActionProps = { | ||
| label: investigationRunning ? FOLLOW_UP_INVESTIGATION_LABEL : RUN_INVESTIGATION_LABEL, | ||
| iconType: 'inspect' as const, | ||
| tooltip: | ||
| activityBlockTooltip ?? (investigationRunning ? FOLLOW_UP_INVESTIGATION_TOOLTIP : undefined), | ||
| onClick: () => triggerInvestigation(event.event_id), | ||
| isDisabled: blocksActivity || triggeringEventId != null, | ||
| isLoading: triggeringEventId === event.event_id, | ||
| 'data-test-subj': 'nightshiftEventFlyoutRunInvestigationButton', | ||
| ...getEbtProps({ | ||
| action: NIGHTSHIFT_EBT_ACTIONS.START_INVESTIGATION, | ||
| element: NIGHTSHIFT_EBT_ELEMENTS.EVENT_FLYOUT, | ||
| detail: isNeedsActionStatus(event.status) | ||
| ? NIGHTSHIFT_EBT_DETAILS.NEEDS_ACTION | ||
| : NIGHTSHIFT_EBT_DETAILS.RESOLVED, | ||
| }), | ||
| }; |
There was a problem hiding this comment.
nit: you could do it the other way around:
Conditionally pick either <FlyoutTemplate.Footer.SecondaryAction> or <FlyoutTemplate.Footer.PrimaryAction> and pass the props once. IMHO, it would make it easier to understand, but it's up to you.
There was a problem hiding this comment.
Fair. This footer is replaced by a single Actions menu in #299456, so I'll leave it as is here.
| const SEARCH_QUERY_PARAM = 'search'; | ||
| const STATUS_QUERY_PARAM = 'status'; | ||
| const SEVERITY_QUERY_PARAM = 'severity'; | ||
| const INVESTIGATION_QUERY_PARAM = 'investigation'; | ||
| const SORT_FIELD_QUERY_PARAM = 'sortField'; | ||
| const SORT_ORDER_QUERY_PARAM = 'sortOrder'; | ||
| // The design leads with the most severe events. | ||
| const DEFAULT_SORT: EventsSort = { field: 'severity', order: 'desc' }; |
There was a problem hiding this comment.
Don't we have a query param for the current page?
There was a problem hiding this comment.
We do, PAGE_QUERY_PARAM is imported at the top. It lives in pages/detection/constants.ts because the time range hook also resets it; added a comment pointing to it in 453c042.
- Use ALERT_EPISODE_STATUS for the status sort and facet count. - Show "Loading events…" in the table while the first page loads. - Point to the shared page query param. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-events-tab # Conflicts: # x-pack/solutions/observability/plugins/significant_events/server/routes/internal/events/route.ts
💚 Build Succeeded
Metrics [docs]Async chunks
Page load bundle
Unknown metric groupsasync chunk count
shared chunks total size
total optimizer output size
warm start memory
History
|
Summary
Adds the Events tab to the Nightshift Detections page and updates the page header to the new design. Part of nightshift-program#1789 and nightshift-program#1787.
/app/nightshift/detections. It's still unlinked, so there's no redirect from/detection.?eventId=link opens that event's flyout whatever the time range; if the event no longer exists, the page drops the id and shows the table with a warning toast.sort_field,sort_orderandinvestigation_state, plus a new_facetsendpoint for the filter counts.components/entities/significant_event/. Management is unchanged.How to test
/app/nightshift/detections, change the time range, sort and filter.Known gaps
Screenshot
The design takes inspiration from the Kate's Design present here. This does not matches 1:1 of-course specially we are only catering SigEvents and not Discoveries