mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Add filtering to SD page and improve state processing
Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
parent
4ce71af1b9
commit
697327a51d
|
@ -41,6 +41,14 @@
|
|||
);
|
||||
}
|
||||
|
||||
.healthInfo {
|
||||
background-color: light-dark(
|
||||
var(--mantine-color-blue-1),
|
||||
var(--mantine-color-blue-9)
|
||||
);
|
||||
color: light-dark(var(--mantine-color-blue-9), var(--mantine-color-blue-1));
|
||||
}
|
||||
|
||||
.healthUnknown {
|
||||
background-color: light-dark(
|
||||
var(--mantine-color-gray-2),
|
||||
|
|
|
@ -14,7 +14,12 @@ import {
|
|||
import { Suspense } from "react";
|
||||
import { useAppDispatch, useAppSelector } from "../../state/hooks";
|
||||
|
||||
import { StringParam, useQueryParam, withDefault } from "use-query-params";
|
||||
import {
|
||||
ArrayParam,
|
||||
StringParam,
|
||||
useQueryParam,
|
||||
withDefault,
|
||||
} from "use-query-params";
|
||||
import ErrorBoundary from "../../components/ErrorBoundary";
|
||||
import ScrapePoolList from "./ServiceDiscoveryPoolsList";
|
||||
import { useSuspenseAPIQuery } from "../../api/api";
|
||||
|
@ -23,6 +28,8 @@ import {
|
|||
setCollapsedPools,
|
||||
setShowLimitAlert,
|
||||
} from "../../state/serviceDiscoveryPageSlice";
|
||||
import { StateMultiSelect } from "../../components/StateMultiSelect";
|
||||
import badgeClasses from "../../Badge.module.css";
|
||||
|
||||
export const targetPoolDisplayLimit = 20;
|
||||
|
||||
|
@ -38,9 +45,13 @@ export default function ServiceDiscoveryPage() {
|
|||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [scrapePool, setScrapePool] = useQueryParam("scrapePool", StringParam);
|
||||
const [scrapePool, setScrapePool] = useQueryParam("pool", StringParam);
|
||||
const [stateFilter, setStateFilter] = useQueryParam(
|
||||
"state",
|
||||
withDefault(ArrayParam, [])
|
||||
);
|
||||
const [searchFilter, setSearchFilter] = useQueryParam(
|
||||
"searchFilter",
|
||||
"search",
|
||||
withDefault(StringParam, "")
|
||||
);
|
||||
|
||||
|
@ -76,6 +87,15 @@ export default function ServiceDiscoveryPage() {
|
|||
}}
|
||||
searchable
|
||||
/>
|
||||
<StateMultiSelect
|
||||
options={["active", "dropped"]}
|
||||
optionClass={(o) =>
|
||||
o === "active" ? badgeClasses.healthOk : badgeClasses.healthInfo
|
||||
}
|
||||
placeholder="Filter by state"
|
||||
values={(stateFilter?.filter((v) => v !== null) as string[]) || []}
|
||||
onChange={(values) => setStateFilter(values)}
|
||||
/>
|
||||
<TextInput
|
||||
flex={1}
|
||||
leftSection={<IconSearch size={14} />}
|
||||
|
@ -118,6 +138,7 @@ export default function ServiceDiscoveryPage() {
|
|||
<ScrapePoolList
|
||||
poolNames={scrapePools}
|
||||
selectedPool={(limited && scrapePools[0]) || scrapePool || null}
|
||||
stateFilter={stateFilter as string[]}
|
||||
searchFilter={searchFilter}
|
||||
/>
|
||||
</Suspense>
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
Target,
|
||||
TargetsResult,
|
||||
} from "../../api/responseTypes/targets";
|
||||
import { FC } from "react";
|
||||
import { FC, useMemo } from "react";
|
||||
import { useAppDispatch, useAppSelector } from "../../state/hooks";
|
||||
import {
|
||||
setCollapsedPools,
|
||||
|
@ -62,10 +62,12 @@ const droppedTargetKVSearch = new KVSearch<DroppedTarget>({
|
|||
indexedKeys: ["discoveredLabels", ["discoveredLabels", /.*/]],
|
||||
});
|
||||
|
||||
const groupTargets = (
|
||||
const buildPoolsData = (
|
||||
poolNames: string[],
|
||||
activeTargets: Target[],
|
||||
droppedTargets: DroppedTarget[]
|
||||
droppedTargets: DroppedTarget[],
|
||||
search: string,
|
||||
stateFilter: (string | null)[]
|
||||
): ScrapePools => {
|
||||
const pools: ScrapePools = {};
|
||||
|
||||
|
@ -88,8 +90,19 @@ const groupTargets = (
|
|||
|
||||
pool.active++;
|
||||
pool.total++;
|
||||
}
|
||||
|
||||
pool.targets.push({
|
||||
const filteredActiveTargets =
|
||||
stateFilter.length !== 0 && !stateFilter.includes("active")
|
||||
? []
|
||||
: search === ""
|
||||
? activeTargets
|
||||
: activeTargetKVSearch
|
||||
.filter(search, activeTargets)
|
||||
.map((value) => value.original);
|
||||
|
||||
for (const target of filteredActiveTargets) {
|
||||
pools[target.scrapePool].targets.push({
|
||||
discoveredLabels: target.discoveredLabels,
|
||||
labels: target.labels,
|
||||
isDropped: false,
|
||||
|
@ -107,30 +120,39 @@ const groupTargets = (
|
|||
}
|
||||
|
||||
pool.total++;
|
||||
}
|
||||
|
||||
pool.targets.push({
|
||||
const filteredDroppedTargets =
|
||||
stateFilter.length !== 0 && !stateFilter.includes("dropped")
|
||||
? []
|
||||
: search === ""
|
||||
? droppedTargets
|
||||
: droppedTargetKVSearch
|
||||
.filter(search, droppedTargets)
|
||||
.map((value) => value.original);
|
||||
|
||||
for (const target of filteredDroppedTargets) {
|
||||
pools[target.discoveredLabels.job].targets.push({
|
||||
discoveredLabels: target.discoveredLabels,
|
||||
isDropped: true,
|
||||
labels: {},
|
||||
});
|
||||
}
|
||||
|
||||
// for (const target of shownTargets) {
|
||||
// pools[target.scrapePool].targets.push(target);
|
||||
// }
|
||||
|
||||
return pools;
|
||||
};
|
||||
|
||||
type ScrapePoolListProp = {
|
||||
poolNames: string[];
|
||||
selectedPool: string | null;
|
||||
stateFilter: string[];
|
||||
searchFilter: string;
|
||||
};
|
||||
|
||||
const ScrapePoolList: FC<ScrapePoolListProp> = ({
|
||||
poolNames,
|
||||
selectedPool,
|
||||
stateFilter,
|
||||
searchFilter,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
@ -157,24 +179,23 @@ const ScrapePoolList: FC<ScrapePoolListProp> = ({
|
|||
|
||||
const [debouncedSearch] = useDebouncedValue<string>(searchFilter, 250);
|
||||
|
||||
// TODO: Memoize all this computation, especially groupTargets().
|
||||
// const search = debouncedSearch.trim();
|
||||
// const healthFilteredTargets = activeTargets.filter(
|
||||
// (target) =>
|
||||
// healthFilter.length === 0 ||
|
||||
// healthFilter.includes(target.health.toLowerCase())
|
||||
// );
|
||||
// const filteredTargets =
|
||||
// search === ""
|
||||
// ? healthFilteredTargets
|
||||
// : kvSearch
|
||||
// .filter(search, healthFilteredTargets)
|
||||
// .map((value) => value.original);
|
||||
|
||||
const allPools = groupTargets(
|
||||
selectedPool ? [selectedPool] : poolNames,
|
||||
activeTargets,
|
||||
droppedTargets
|
||||
const allPools = useMemo(
|
||||
() =>
|
||||
buildPoolsData(
|
||||
selectedPool ? [selectedPool] : poolNames,
|
||||
activeTargets,
|
||||
droppedTargets,
|
||||
debouncedSearch,
|
||||
stateFilter
|
||||
),
|
||||
[
|
||||
selectedPool,
|
||||
poolNames,
|
||||
activeTargets,
|
||||
droppedTargets,
|
||||
debouncedSearch,
|
||||
stateFilter,
|
||||
]
|
||||
);
|
||||
const allPoolNames = Object.keys(allPools);
|
||||
const shownPoolNames = showEmptyPools
|
||||
|
@ -240,17 +261,22 @@ const ScrapePoolList: FC<ScrapePoolListProp> = ({
|
|||
<RingProgress
|
||||
size={25}
|
||||
thickness={5}
|
||||
sections={[
|
||||
{
|
||||
value: (pool.active / pool.total) * 100,
|
||||
color: "green.4",
|
||||
},
|
||||
{
|
||||
value:
|
||||
((pool.total - pool.active) / pool.total) * 100,
|
||||
color: "grape.4",
|
||||
},
|
||||
]}
|
||||
sections={
|
||||
pool.total === 0
|
||||
? []
|
||||
: [
|
||||
{
|
||||
value: (pool.active / pool.total) * 100,
|
||||
color: "green.4",
|
||||
},
|
||||
{
|
||||
value:
|
||||
((pool.total - pool.active) / pool.total) *
|
||||
100,
|
||||
color: "blue.6",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</Group>
|
||||
</Group>
|
||||
|
|
|
@ -254,22 +254,24 @@ const ScrapePoolList: FC<ScrapePoolListProp> = ({
|
|||
<RingProgress
|
||||
size={25}
|
||||
thickness={5}
|
||||
sections={[
|
||||
{
|
||||
value: (pool.upCount / pool.count) * 100,
|
||||
color: "green.4",
|
||||
},
|
||||
// Important that gray is the middle one, since the middle one seems to be
|
||||
// the default color if all three values are 0 (empty pool = gray).
|
||||
{
|
||||
value: (pool.unknownCount / pool.count) * 100,
|
||||
color: "gray.4",
|
||||
},
|
||||
{
|
||||
value: (pool.downCount / pool.count) * 100,
|
||||
color: "red.5",
|
||||
},
|
||||
]}
|
||||
sections={
|
||||
pool.count === 0
|
||||
? []
|
||||
: [
|
||||
{
|
||||
value: (pool.upCount / pool.count) * 100,
|
||||
color: "green.4",
|
||||
},
|
||||
{
|
||||
value: (pool.unknownCount / pool.count) * 100,
|
||||
color: "gray.4",
|
||||
},
|
||||
{
|
||||
value: (pool.downCount / pool.count) * 100,
|
||||
color: "red.5",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</Group>
|
||||
</Group>
|
||||
|
|
Loading…
Reference in a new issue