ui: Add expandable scrape interval and timeout to targets page
Implements expand/collapse functionality for displaying final scrape configuration (interval + timeout) in the targets page timing column. - Add ScrapeDetails component with expand/collapse chevron - Keep existing "Last Scrape" and "Scrape Duration" badges always visible - Display "Scrape interval: every \<interval\>" and "Scrape timeout: after \<timeout\>" when expanded - Use IconRepeat for interval and IconPlugConnectedX for timeout - Follow TargetLabels.tsx pattern for consistency - Implement performance optimization with conditional DOM rendering - Maintain existing hover tooltip functionality Signed-off-by: ADITYATIWARI342005 <142050150+ADITYATIWARI342005@users.noreply.github.com>
This commit is contained in:
parent
c9e0e36701
commit
8eb8758925
|
@ -0,0 +1,109 @@
|
||||||
|
import { FC } from "react";
|
||||||
|
import { ActionIcon, Badge, Collapse, Group, Stack, Tooltip } from "@mantine/core";
|
||||||
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
|
import {
|
||||||
|
IconChevronDown,
|
||||||
|
IconChevronUp,
|
||||||
|
IconHourglass,
|
||||||
|
IconPlugConnectedX,
|
||||||
|
IconRefresh,
|
||||||
|
IconRepeat,
|
||||||
|
} from "@tabler/icons-react";
|
||||||
|
import { humanizeDuration, humanizeDurationRelative, now } from "../../lib/formatTime";
|
||||||
|
import { Target } from "../../api/responseTypes/targets";
|
||||||
|
import badgeClasses from "../../Badge.module.css";
|
||||||
|
import { actionIconStyle, badgeIconStyle } from "../../styles";
|
||||||
|
|
||||||
|
type ScrapeDetailsProps = {
|
||||||
|
target: Target;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ScrapeDetails: FC<ScrapeDetailsProps> = ({ target }) => {
|
||||||
|
const [showDetails, { toggle: toggleDetails }] = useDisclosure(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap="xs">
|
||||||
|
<Group wrap="nowrap" align="flex-start">
|
||||||
|
<Group gap="xs" wrap="wrap">
|
||||||
|
<Tooltip label="Last target scrape" withArrow>
|
||||||
|
<Badge
|
||||||
|
variant="light"
|
||||||
|
className={badgeClasses.statsBadge}
|
||||||
|
styles={{
|
||||||
|
label: { textTransform: "none" },
|
||||||
|
}}
|
||||||
|
leftSection={<IconRefresh style={badgeIconStyle} />}
|
||||||
|
>
|
||||||
|
{humanizeDurationRelative(target.lastScrape, now())}
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip
|
||||||
|
label={
|
||||||
|
<div style={{ lineHeight: 1.2 }}>
|
||||||
|
<div>Interval: {target.scrapeInterval}</div>
|
||||||
|
<div>Timeout: {target.scrapeTimeout}</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
withArrow
|
||||||
|
>
|
||||||
|
<Badge
|
||||||
|
variant="light"
|
||||||
|
className={badgeClasses.statsBadge}
|
||||||
|
styles={{
|
||||||
|
label: { textTransform: "none" },
|
||||||
|
}}
|
||||||
|
leftSection={<IconHourglass style={badgeIconStyle} />}
|
||||||
|
>
|
||||||
|
{humanizeDuration(target.lastScrapeDuration * 1000)}
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<ActionIcon
|
||||||
|
size="xs"
|
||||||
|
color="gray"
|
||||||
|
variant="light"
|
||||||
|
onClick={toggleDetails}
|
||||||
|
title={`${showDetails ? "Hide" : "Show"} scrape configuration details`}
|
||||||
|
>
|
||||||
|
{showDetails ? (
|
||||||
|
<IconChevronUp style={actionIconStyle} />
|
||||||
|
) : (
|
||||||
|
<IconChevronDown style={actionIconStyle} />
|
||||||
|
)}
|
||||||
|
</ActionIcon>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Collapse in={showDetails}>
|
||||||
|
{/* Additionally remove DOM elements when not expanded (helps performance) */}
|
||||||
|
{showDetails && (
|
||||||
|
<Group gap="xs" wrap="wrap">
|
||||||
|
<Tooltip label="Scrape interval" withArrow>
|
||||||
|
<Badge
|
||||||
|
variant="light"
|
||||||
|
className={badgeClasses.statsBadge}
|
||||||
|
styles={{ label: { textTransform: "none" } }}
|
||||||
|
leftSection={<IconRepeat style={badgeIconStyle} />}
|
||||||
|
>
|
||||||
|
every {target.scrapeInterval}
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip label="Scrape timeout" withArrow>
|
||||||
|
<Badge
|
||||||
|
variant="light"
|
||||||
|
className={badgeClasses.statsBadge}
|
||||||
|
styles={{ label: { textTransform: "none" } }}
|
||||||
|
leftSection={<IconPlugConnectedX style={badgeIconStyle} />}
|
||||||
|
>
|
||||||
|
after {target.scrapeTimeout}
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
|
</Collapse>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ScrapeDetails;
|
|
@ -8,23 +8,15 @@ import {
|
||||||
Stack,
|
Stack,
|
||||||
Table,
|
Table,
|
||||||
Text,
|
Text,
|
||||||
Tooltip,
|
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { KVSearch } from "@nexucis/kvsearch";
|
import { KVSearch } from "@nexucis/kvsearch";
|
||||||
import {
|
import {
|
||||||
IconAlertTriangle,
|
IconAlertTriangle,
|
||||||
IconHourglass,
|
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
IconRefresh,
|
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import { useSuspenseAPIQuery } from "../../api/api";
|
import { useSuspenseAPIQuery } from "../../api/api";
|
||||||
import { Target, TargetsResult } from "../../api/responseTypes/targets";
|
import { Target, TargetsResult } from "../../api/responseTypes/targets";
|
||||||
import React, { FC, memo, useMemo } from "react";
|
import React, { FC, memo, useMemo } from "react";
|
||||||
import {
|
|
||||||
humanizeDurationRelative,
|
|
||||||
humanizeDuration,
|
|
||||||
now,
|
|
||||||
} from "../../lib/formatTime";
|
|
||||||
import { useLocalStorage } from "@mantine/hooks";
|
import { useLocalStorage } from "@mantine/hooks";
|
||||||
import { useAppDispatch, useAppSelector } from "../../state/hooks";
|
import { useAppDispatch, useAppSelector } from "../../state/hooks";
|
||||||
import {
|
import {
|
||||||
|
@ -37,8 +29,8 @@ import CustomInfiniteScroll from "../../components/CustomInfiniteScroll";
|
||||||
import badgeClasses from "../../Badge.module.css";
|
import badgeClasses from "../../Badge.module.css";
|
||||||
import panelClasses from "../../Panel.module.css";
|
import panelClasses from "../../Panel.module.css";
|
||||||
import TargetLabels from "./TargetLabels";
|
import TargetLabels from "./TargetLabels";
|
||||||
|
import ScrapeDetails from "./ScrapeDetails";
|
||||||
import { targetPoolDisplayLimit } from "./TargetsPage";
|
import { targetPoolDisplayLimit } from "./TargetsPage";
|
||||||
import { badgeIconStyle } from "../../styles";
|
|
||||||
|
|
||||||
type ScrapePool = {
|
type ScrapePool = {
|
||||||
targets: Target[];
|
targets: Target[];
|
||||||
|
@ -332,52 +324,7 @@ const ScrapePoolList: FC<ScrapePoolListProp> = memo(
|
||||||
/>
|
/>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td valign="top">
|
<Table.Td valign="top">
|
||||||
<Group gap="xs" wrap="wrap">
|
<ScrapeDetails target={target} />
|
||||||
<Tooltip
|
|
||||||
label="Last target scrape"
|
|
||||||
withArrow
|
|
||||||
>
|
|
||||||
<Badge
|
|
||||||
variant="light"
|
|
||||||
className={badgeClasses.statsBadge}
|
|
||||||
styles={{
|
|
||||||
label: { textTransform: "none" },
|
|
||||||
}}
|
|
||||||
leftSection={
|
|
||||||
<IconRefresh
|
|
||||||
style={badgeIconStyle}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{humanizeDurationRelative(
|
|
||||||
target.lastScrape,
|
|
||||||
now()
|
|
||||||
)}
|
|
||||||
</Badge>
|
|
||||||
</Tooltip>
|
|
||||||
|
|
||||||
<Tooltip
|
|
||||||
label="Duration of last target scrape"
|
|
||||||
withArrow
|
|
||||||
>
|
|
||||||
<Badge
|
|
||||||
variant="light"
|
|
||||||
className={badgeClasses.statsBadge}
|
|
||||||
styles={{
|
|
||||||
label: { textTransform: "none" },
|
|
||||||
}}
|
|
||||||
leftSection={
|
|
||||||
<IconHourglass
|
|
||||||
style={badgeIconStyle}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{humanizeDuration(
|
|
||||||
target.lastScrapeDuration * 1000
|
|
||||||
)}
|
|
||||||
</Badge>
|
|
||||||
</Tooltip>
|
|
||||||
</Group>
|
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td valign="top">
|
<Table.Td valign="top">
|
||||||
<Badge
|
<Badge
|
||||||
|
|
Loading…
Reference in New Issue