diff --git a/web/ui/mantine-ui/src/App.tsx b/web/ui/mantine-ui/src/App.tsx index 02160e460b..2ca61761fa 100644 --- a/web/ui/mantine-ui/src/App.tsx +++ b/web/ui/mantine-ui/src/App.tsx @@ -20,6 +20,7 @@ import { } from "@mantine/core"; import { useDisclosure } from "@mantine/hooks"; import { + IconBell, IconBellFilled, IconChevronDown, IconChevronRight, @@ -62,6 +63,7 @@ import ReadinessWrapper from "./components/ReadinessWrapper"; import { QueryParamProvider } from "use-query-params"; import { ReactRouter6Adapter } from "use-query-params/adapters/react-router-6"; import ServiceDiscoveryPage from "./pages/service-discovery/ServiceDiscoveryPage"; +import AlertmanagerDiscoveryPage from "./pages/AlertmanagerDiscoveryPage"; const queryClient = new QueryClient(); @@ -106,6 +108,13 @@ const monitoringStatusPages = [ element: , inAgentMode: true, }, + { + title: "Alertmanager discovery", + path: "/discovered-alertmanagers", + icon: , + element: , + inAgentMode: false, + }, ]; const serverStatusPages = [ diff --git a/web/ui/mantine-ui/src/api/responseTypes/alertmanagers.ts b/web/ui/mantine-ui/src/api/responseTypes/alertmanagers.ts new file mode 100644 index 0000000000..2fcb8c23a3 --- /dev/null +++ b/web/ui/mantine-ui/src/api/responseTypes/alertmanagers.ts @@ -0,0 +1,10 @@ +export type AlertmanagerTarget = { + url: string; +}; + +// Result type for /api/v1/alertmanagers endpoint. +// See: https://prometheus.io/docs/prometheus/latest/querying/api/#alertmanagers +export type AlertmanagersResult = { + activeAlertmanagers: AlertmanagerTarget[]; + droppedAlertmanagers: AlertmanagerTarget[]; +}; diff --git a/web/ui/mantine-ui/src/pages/AlertmanagerDiscoveryPage.tsx b/web/ui/mantine-ui/src/pages/AlertmanagerDiscoveryPage.tsx new file mode 100644 index 0000000000..8fd12511ee --- /dev/null +++ b/web/ui/mantine-ui/src/pages/AlertmanagerDiscoveryPage.tsx @@ -0,0 +1,115 @@ +import { + ActionIcon, + Alert, + Box, + Card, + Group, + Select, + Skeleton, + Stack, + Table, + Text, +} from "@mantine/core"; +import { + IconBell, + IconBellOff, + IconInfoCircle, + IconLayoutNavbarCollapse, + IconLayoutNavbarExpand, + IconSearch, +} from "@tabler/icons-react"; +import { Suspense } from "react"; +import { useAppDispatch, useAppSelector } from "../state/hooks"; + +import { + ArrayParam, + StringParam, + useQueryParam, + withDefault, +} from "use-query-params"; +import ErrorBoundary from "../components/ErrorBoundary"; +import ScrapePoolList from "./ServiceDiscoveryPoolsList"; +import { useSuspenseAPIQuery } from "../api/api"; +import { ScrapePoolsResult } from "../api/responseTypes/scrapePools"; +import { + setCollapsedPools, + setShowLimitAlert, +} from "../state/serviceDiscoveryPageSlice"; +import { StateMultiSelect } from "../components/StateMultiSelect"; +import badgeClasses from "../Badge.module.css"; +import { AlertmanagersResult } from "../api/responseTypes/alertmanagers"; +import EndpointLink from "../components/EndpointLink"; + +export const targetPoolDisplayLimit = 20; + +export default function AlertmanagerDiscoveryPage() { + // Load the list of all available scrape pools. + const { + data: { + data: { activeAlertmanagers, droppedAlertmanagers }, + }, + } = useSuspenseAPIQuery({ + path: `/alertmanagers`, + }); + + return ( + + + + + + Active Alertmanagers + + + {activeAlertmanagers.length === 0 ? ( + }> + No active alertmanagers found. + + ) : ( + + + {activeAlertmanagers.map((alertmanager) => ( + + + + + + ))} + +
+ )} +
+ + + + + Dropped Alertmanagers + + + {droppedAlertmanagers.length === 0 ? ( + }> + No dropped alertmanagers found. + + ) : ( + + + {droppedAlertmanagers.map((alertmanager) => ( + + + + + + ))} + +
+ )} +
+
+ ); +} diff --git a/web/ui/mantine-ui/src/pages/service-discovery/ServiceDiscoveryPoolsList.tsx b/web/ui/mantine-ui/src/pages/service-discovery/ServiceDiscoveryPoolsList.tsx index 537468944a..d29808d99a 100644 --- a/web/ui/mantine-ui/src/pages/service-discovery/ServiceDiscoveryPoolsList.tsx +++ b/web/ui/mantine-ui/src/pages/service-discovery/ServiceDiscoveryPoolsList.tsx @@ -25,7 +25,6 @@ import { } from "../../state/serviceDiscoveryPageSlice"; import CustomInfiniteScroll from "../../components/CustomInfiniteScroll"; -import TargetLabels from "./TargetLabels"; import { useDebouncedValue } from "@mantine/hooks"; import { targetPoolDisplayLimit } from "./ServiceDiscoveryPage"; import { BooleanParam, useQueryParam, withDefault } from "use-query-params"; diff --git a/web/ui/mantine-ui/src/pages/service-discovery/TargetLabels.tsx b/web/ui/mantine-ui/src/pages/service-discovery/TargetLabels.tsx deleted file mode 100644 index 54e944f8cf..0000000000 --- a/web/ui/mantine-ui/src/pages/service-discovery/TargetLabels.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { FC } from "react"; -import { Labels } from "../../api/responseTypes/targets"; -import { LabelBadges } from "../../components/LabelBadges"; -import { ActionIcon, Collapse, Group, Stack, Text } from "@mantine/core"; -import { useDisclosure } from "@mantine/hooks"; -import { IconChevronDown, IconChevronUp } from "@tabler/icons-react"; - -type TargetLabelsProps = { - labels: Labels; - discoveredLabels: Labels; -}; - -const TargetLabels: FC = ({ discoveredLabels, labels }) => { - const [showDiscovered, { toggle: toggleDiscovered }] = useDisclosure(false); - - return ( - - - - - - {showDiscovered ? ( - - ) : ( - - )} - - - - - - Discovered labels: - - - - - ); -}; - -export default TargetLabels;