diff --git a/web/ui/mantine-ui/src/pages/AlertsPage.tsx b/web/ui/mantine-ui/src/pages/AlertsPage.tsx index 19bd631be..99ba58aee 100644 --- a/web/ui/mantine-ui/src/pages/AlertsPage.tsx +++ b/web/ui/mantine-ui/src/pages/AlertsPage.tsx @@ -15,16 +15,19 @@ import { Pill, Stack, Input, + Alert, } from "@mantine/core"; import { useSuspenseAPIQuery } from "../api/api"; import { AlertingRulesMap } from "../api/responseTypes/rules"; import badgeClasses from "../Badge.module.css"; import RuleDefinition from "../RuleDefinition"; -import { formatRelative, now } from "../lib/formatTime"; +import { humanizeDurationRelative, now } from "../lib/formatTime"; import { Fragment } from "react"; -import { AlertStateMultiSelect } from "./AlertStateMultiSelect"; -import { useAppSelector } from "../state/hooks"; -import { IconSearch } from "@tabler/icons-react"; +import { StateMultiSelect } from "../StateMultiSelect"; +import { useAppDispatch, useAppSelector } from "../state/hooks"; +import { IconInfoCircle, IconSearch } from "@tabler/icons-react"; +import { LabelBadges } from "../LabelBadges"; +import { updateAlertFilters } from "../state/alertsPageSlice"; export default function AlertsPage() { const { data } = useSuspenseAPIQuery({ @@ -33,9 +36,12 @@ export default function AlertsPage() { type: "alert", }, }); + + const dispatch = useAppDispatch(); const showAnnotations = useAppSelector( (state) => state.settings.showAnnotations ); + const filters = useAppSelector((state) => state.alertsPage.filters); const ruleStatsCount = { inactive: 0, @@ -50,7 +56,19 @@ export default function AlertsPage() { return ( <> - + + o === "inactive" + ? badgeClasses.healthOk + : o === "pending" + ? badgeClasses.healthWarn + : badgeClasses.healthErr + } + placeholder="Filter by alert state" + values={filters.state} + onChange={(values) => dispatch(updateAlertFilters({ state: values }))} + /> } @@ -58,163 +76,153 @@ export default function AlertsPage() { > - {data.data.groups.map((g, i) => ( - - - - - {g.name} - - - {g.file} - - - - - {g.rules.map((r, j) => { - const numFiring = r.alerts.filter( - (a) => a.state === "firing" - ).length; - const numPending = r.alerts.filter( - (a) => a.state === "pending" - ).length; - - return ( - 0 - ? "5px solid var(--mantine-color-red-4)" - : numPending > 0 - ? "5px solid var(--mantine-color-orange-5)" - : "5px solid var(--mantine-color-green-4)", - }} + {data.data.groups.map((g, i) => { + const filteredRules = g.rules.filter( + (r) => filters.state.length === 0 || filters.state.includes(r.state) + ); + return ( + + + + - - - {r.name} - - {numFiring > 0 && ( - - firing ({numFiring}) - - )} - {numPending > 0 && ( - - pending ({numPending}) - - )} - {/* {numFiring === 0 && numPending === 0 && ( - - inactive - - )} */} + {g.name} + + + {g.file} + + + + {filteredRules.length === 0 && ( + } + > + No rules found that match your filter criteria. + + )} + + {filteredRules.map((r, j) => { + const numFiring = r.alerts.filter( + (a) => a.state === "firing" + ).length; + const numPending = r.alerts.filter( + (a) => a.state === "pending" + ).length; + + return ( + 0 + ? "5px solid var(--mantine-color-red-4)" + : numPending > 0 + ? "5px solid var(--mantine-color-orange-5)" + : "5px solid var(--mantine-color-green-4)", + }} + > + + + {r.name} + + {numFiring > 0 && ( + + firing ({numFiring}) + + )} + {numPending > 0 && ( + + pending ({numPending}) + + )} + - - - - - {r.alerts.length > 0 && ( - - - - Alert labels - State - Active Since - Value - - - - {r.type === "alerting" && - r.alerts.map((a, k) => ( - - - - - {Object.entries(a.labels).map( - ([k, v]) => { - return ( - - {/* TODO: Proper quote escaping */} - {k}="{v}" - - ); - } - )} - - - - - {a.state} - - - - - - {formatRelative( - a.activeAt, - now(), - "" - )} - - - - {a.value} - - {showAnnotations && ( + + + + {r.alerts.length > 0 && ( +
+ + + Alert labels + State + Active Since + Value + + + + {r.type === "alerting" && + r.alerts.map((a, k) => ( + - -
- - {Object.entries(a.annotations).map( - ([k, v]) => ( + + + + + + {a.state} + + + + + + {humanizeDurationRelative( + a.activeAt, + now(), + "" + )} + + + + {a.value} + + {showAnnotations && ( + + +
+ + {Object.entries( + a.annotations + ).map(([k, v]) => ( {k} {v} - ) - )} - -
- - - )} - - ))} - - - )} -
-
- ); - })} -
-
- ))} + ))} + + + + + )} + + ))} + + + )} + +
+ ); + })} +
+
+ ); + })}
);