|
|
|
@ -1,5 +1,5 @@
|
|
|
|
|
import { FC, useEffect, useId, useState } from "react"; |
|
|
|
|
import { Alert, Skeleton, Box, LoadingOverlay } from "@mantine/core"; |
|
|
|
|
import { Alert, Skeleton, Box, LoadingOverlay, Stack } from "@mantine/core"; |
|
|
|
|
import { IconAlertTriangle, IconInfoCircle } from "@tabler/icons-react"; |
|
|
|
|
import { RangeQueryResult } from "../../api/responseTypes/query"; |
|
|
|
|
import { SuccessAPIResponse, useAPIQuery } from "../../api/api"; |
|
|
|
@ -13,9 +13,12 @@ import "uplot/dist/uPlot.min.css";
|
|
|
|
|
import "./uplot.css"; |
|
|
|
|
import { useElementSize } from "@mantine/hooks"; |
|
|
|
|
import UPlotChart, { UPlotChartRange } from "./UPlotChart"; |
|
|
|
|
import ASTNode, { nodeType } from "../../promql/ast"; |
|
|
|
|
import serializeNode from "../../promql/serialize"; |
|
|
|
|
|
|
|
|
|
export interface GraphProps { |
|
|
|
|
expr: string; |
|
|
|
|
node: ASTNode | null; |
|
|
|
|
endTime: number | null; |
|
|
|
|
range: number; |
|
|
|
|
resolution: GraphResolution; |
|
|
|
@ -27,6 +30,7 @@ export interface GraphProps {
|
|
|
|
|
|
|
|
|
|
const Graph: FC<GraphProps> = ({ |
|
|
|
|
expr, |
|
|
|
|
node, |
|
|
|
|
endTime, |
|
|
|
|
range, |
|
|
|
|
resolution, |
|
|
|
@ -38,6 +42,22 @@ const Graph: FC<GraphProps> = ({
|
|
|
|
|
const { ref, width } = useElementSize(); |
|
|
|
|
const [rerender, setRerender] = useState(true); |
|
|
|
|
|
|
|
|
|
const effectiveExpr = |
|
|
|
|
node === null |
|
|
|
|
? expr |
|
|
|
|
: serializeNode( |
|
|
|
|
node.type === nodeType.matrixSelector |
|
|
|
|
? { |
|
|
|
|
type: nodeType.vectorSelector, |
|
|
|
|
name: node.name, |
|
|
|
|
matchers: node.matchers, |
|
|
|
|
offset: node.offset, |
|
|
|
|
timestamp: node.timestamp, |
|
|
|
|
startOrEnd: node.startOrEnd, |
|
|
|
|
} |
|
|
|
|
: node |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const effectiveEndTime = (endTime !== null ? endTime : Date.now()) / 1000; |
|
|
|
|
const startTime = effectiveEndTime - range / 1000; |
|
|
|
|
const effectiveResolution = getEffectiveResolution(resolution, range) / 1000; |
|
|
|
@ -47,12 +67,12 @@ const Graph: FC<GraphProps> = ({
|
|
|
|
|
key: [useId()], |
|
|
|
|
path: "/query_range", |
|
|
|
|
params: { |
|
|
|
|
query: expr, |
|
|
|
|
query: effectiveExpr, |
|
|
|
|
step: effectiveResolution.toString(), |
|
|
|
|
start: startTime.toString(), |
|
|
|
|
end: effectiveEndTime.toString(), |
|
|
|
|
}, |
|
|
|
|
enabled: expr !== "", |
|
|
|
|
enabled: effectiveExpr !== "", |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// Bundle the chart data and the displayed range together. This has two purposes:
|
|
|
|
@ -82,8 +102,8 @@ const Graph: FC<GraphProps> = ({
|
|
|
|
|
|
|
|
|
|
// Re-execute the query when the user presses Enter (or hits the Execute button).
|
|
|
|
|
useEffect(() => { |
|
|
|
|
expr !== "" && refetch(); |
|
|
|
|
}, [retriggerIdx, refetch, expr, endTime, range, resolution]); |
|
|
|
|
effectiveExpr !== "" && refetch(); |
|
|
|
|
}, [retriggerIdx, refetch, effectiveExpr, endTime, range, resolution]); |
|
|
|
|
|
|
|
|
|
// The useElementSize hook above only gets a valid size on the second render, so this
|
|
|
|
|
// is a workaround to make the component render twice after mount.
|
|
|
|
@ -133,27 +153,39 @@ const Graph: FC<GraphProps> = ({
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<Box pos="relative" ref={ref} className={classes.chartWrapper}> |
|
|
|
|
<LoadingOverlay |
|
|
|
|
visible={isFetching} |
|
|
|
|
zIndex={1000} |
|
|
|
|
h={570} |
|
|
|
|
overlayProps={{ radius: "sm", blur: 0.5 }} |
|
|
|
|
loaderProps={{ type: "dots", color: "gray.6" }} |
|
|
|
|
// loaderProps={{
|
|
|
|
|
// children: <Skeleton m={0} w="100%" h="100%" />,
|
|
|
|
|
// }}
|
|
|
|
|
// styles={{ loader: { width: "100%", height: "100%" } }}
|
|
|
|
|
/> |
|
|
|
|
<UPlotChart |
|
|
|
|
data={dataAndRange.data.data.result} |
|
|
|
|
range={dataAndRange.range} |
|
|
|
|
width={width} |
|
|
|
|
showExemplars={showExemplars} |
|
|
|
|
displayMode={displayMode} |
|
|
|
|
onSelectRange={onSelectRange} |
|
|
|
|
/> |
|
|
|
|
</Box> |
|
|
|
|
<Stack> |
|
|
|
|
{node !== null && node.type === nodeType.matrixSelector && ( |
|
|
|
|
<Alert |
|
|
|
|
color="orange" |
|
|
|
|
title="Graphing modified expression" |
|
|
|
|
icon={<IconAlertTriangle size={14} />} |
|
|
|
|
> |
|
|
|
|
<strong>Note:</strong> Range vector selectors can't be graphed, so |
|
|
|
|
graphing the equivalent instant vector selector instead. |
|
|
|
|
</Alert> |
|
|
|
|
)} |
|
|
|
|
<Box pos="relative" ref={ref} className={classes.chartWrapper}> |
|
|
|
|
<LoadingOverlay |
|
|
|
|
visible={isFetching} |
|
|
|
|
zIndex={1000} |
|
|
|
|
h={570} |
|
|
|
|
overlayProps={{ radius: "sm", blur: 0.5 }} |
|
|
|
|
loaderProps={{ type: "dots", color: "gray.6" }} |
|
|
|
|
// loaderProps={{
|
|
|
|
|
// children: <Skeleton m={0} w="100%" h="100%" />,
|
|
|
|
|
// }}
|
|
|
|
|
// styles={{ loader: { width: "100%", height: "100%" } }}
|
|
|
|
|
/> |
|
|
|
|
<UPlotChart |
|
|
|
|
data={dataAndRange.data.data.result} |
|
|
|
|
range={dataAndRange.range} |
|
|
|
|
width={width} |
|
|
|
|
showExemplars={showExemplars} |
|
|
|
|
displayMode={displayMode} |
|
|
|
|
onSelectRange={onSelectRange} |
|
|
|
|
/> |
|
|
|
|
</Box> |
|
|
|
|
</Stack> |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|