diff --git a/frontend/src/features/alerts/components/alert-row.tsx b/frontend/src/features/alerts/components/alert-row.tsx
index 4bbbbda68..1df71b9b2 100644
--- a/frontend/src/features/alerts/components/alert-row.tsx
+++ b/frontend/src/features/alerts/components/alert-row.tsx
@@ -111,7 +111,12 @@ export function AlertRow({
e.stopPropagation()}>
-
+ onCreateRule(a)}
+ />
|
{a.technique || '—'}
diff --git a/frontend/src/features/alerts/components/status-change-menu.tsx b/frontend/src/features/alerts/components/status-change-menu.tsx
index 878c65ff8..404d552c7 100644
--- a/frontend/src/features/alerts/components/status-change-menu.tsx
+++ b/frontend/src/features/alerts/components/status-change-menu.tsx
@@ -14,10 +14,12 @@ export function StatusChangeMenu({
status,
onStatus,
variant,
+ onCreateRule,
}: {
status: StatusKey
onStatus: (status: number, observation: string, fp: boolean) => void
variant: Variant
+ onCreateRule?: () => void
}) {
const { t } = useTranslation()
const [open, setOpen] = useState(false)
@@ -77,7 +79,7 @@ export function StatusChangeMenu({
{open && (
e.stopPropagation()}
- className="absolute left-0 top-full z-30 mt-1 w-48 rounded-md border border-border bg-popover py-1 shadow-lg"
+ className="absolute left-0 top-full z-30 mt-1 w-max min-w-[12rem] rounded-md border border-border bg-popover py-1 shadow-lg"
>
{(['open', 'in_review', 'completed'] as StatusKey[]).map((k) => (
+ {onCreateRule && (
+
+ )}
)}
{pending && (
diff --git a/frontend/src/features/alerts/pages/AlertsPage.tsx b/frontend/src/features/alerts/pages/AlertsPage.tsx
index 818209403..0cecccb00 100644
--- a/frontend/src/features/alerts/pages/AlertsPage.tsx
+++ b/frontend/src/features/alerts/pages/AlertsPage.tsx
@@ -1,6 +1,6 @@
import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { AlertTriangle, Loader2 } from 'lucide-react'
-import { useLocation, useNavigate } from 'react-router-dom'
+import { useLocation, useNavigate, useParams } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { Button } from '@/shared/components/ui/button'
import { InfiniteScrollSentinel } from '@/shared/components/ui/infinite-scroll'
@@ -65,7 +65,25 @@ export function AlertsPage() {
// SOC-AI chat navigation: seed the filters + time window the agent emitted.
const location = useLocation()
const navigate = useNavigate()
+ const { id: routeAlertName } = useParams<{ id: string }>()
+ const pendingOpenNameRef = useRef(null)
const seededRef = useRef(false)
+
+ // Deep-link (/threat-management/alerts/:alertName): seed as name filter + open drawer once loaded.
+ useEffect(() => {
+ if (!routeAlertName) return
+ const decoded = decodeURIComponent(routeAlertName)
+ pendingOpenNameRef.current = decoded
+ setCustomFilters((c) =>
+ c.some((f) => f.field === 'name' && f.value === decoded)
+ ? c
+ : [...c, { field: 'name', label: 'name', operator: 'IS', value: decoded }],
+ )
+ setPage(0)
+ // Drop the name from the URL so future edits to filters aren't fought by re-seeding.
+ navigate('/threat-management/alerts', { replace: true })
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [routeAlertName])
useEffect(() => {
const state = location.state as { socaiFilters?: FilterType[]; socaiTime?: string } | null
if (!state?.socaiFilters?.length || seededRef.current) return
@@ -117,6 +135,15 @@ export function AlertsPage() {
}, [scopeFilters, statusTab, severity])
const { alerts, total, loading, error, refresh: refreshList } = useAlertsList(page, pageSize, listFilters)
+
+ useEffect(() => {
+ const name = pendingOpenNameRef.current
+ if (!name) return
+ const match = alerts.find((a) => a.name === name)
+ if (!match) return
+ pendingOpenNameRef.current = null
+ setOpenAlert(match)
+ }, [alerts])
const { sevCounts, statusCounts, timeline, openCount, refresh: refreshStats } = useAlertStats(scopeFilters, range.interval)
const { tagCatalog, createTag, updateTag, deleteTag } = useAlertTagCatalog((deletedName) =>
setTagFilter((tf) => tf.filter((tn) => tn !== deletedName))
@@ -162,7 +189,7 @@ export function AlertsPage() {
}
return (
-
+
diff --git a/frontend/src/features/alerts/pages/TaggingRulesPage.tsx b/frontend/src/features/alerts/pages/TaggingRulesPage.tsx
index 387db46ea..547f57ce4 100644
--- a/frontend/src/features/alerts/pages/TaggingRulesPage.tsx
+++ b/frontend/src/features/alerts/pages/TaggingRulesPage.tsx
@@ -137,7 +137,7 @@ export function TaggingRulesPage() {
}
return (
- |