mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Graph range vector selectors as instant vector selectors with notice
Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
parent
1f1ca37fd7
commit
d23872ef30
|
@ -1,5 +1,5 @@
|
||||||
import { FC, useEffect, useId, useState } from "react";
|
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 { IconAlertTriangle, IconInfoCircle } from "@tabler/icons-react";
|
||||||
import { RangeQueryResult } from "../../api/responseTypes/query";
|
import { RangeQueryResult } from "../../api/responseTypes/query";
|
||||||
import { SuccessAPIResponse, useAPIQuery } from "../../api/api";
|
import { SuccessAPIResponse, useAPIQuery } from "../../api/api";
|
||||||
|
@ -13,9 +13,12 @@ import "uplot/dist/uPlot.min.css";
|
||||||
import "./uplot.css";
|
import "./uplot.css";
|
||||||
import { useElementSize } from "@mantine/hooks";
|
import { useElementSize } from "@mantine/hooks";
|
||||||
import UPlotChart, { UPlotChartRange } from "./UPlotChart";
|
import UPlotChart, { UPlotChartRange } from "./UPlotChart";
|
||||||
|
import ASTNode, { nodeType } from "../../promql/ast";
|
||||||
|
import serializeNode from "../../promql/serialize";
|
||||||
|
|
||||||
export interface GraphProps {
|
export interface GraphProps {
|
||||||
expr: string;
|
expr: string;
|
||||||
|
node: ASTNode | null;
|
||||||
endTime: number | null;
|
endTime: number | null;
|
||||||
range: number;
|
range: number;
|
||||||
resolution: GraphResolution;
|
resolution: GraphResolution;
|
||||||
|
@ -27,6 +30,7 @@ export interface GraphProps {
|
||||||
|
|
||||||
const Graph: FC<GraphProps> = ({
|
const Graph: FC<GraphProps> = ({
|
||||||
expr,
|
expr,
|
||||||
|
node,
|
||||||
endTime,
|
endTime,
|
||||||
range,
|
range,
|
||||||
resolution,
|
resolution,
|
||||||
|
@ -38,6 +42,22 @@ const Graph: FC<GraphProps> = ({
|
||||||
const { ref, width } = useElementSize();
|
const { ref, width } = useElementSize();
|
||||||
const [rerender, setRerender] = useState(true);
|
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 effectiveEndTime = (endTime !== null ? endTime : Date.now()) / 1000;
|
||||||
const startTime = effectiveEndTime - range / 1000;
|
const startTime = effectiveEndTime - range / 1000;
|
||||||
const effectiveResolution = getEffectiveResolution(resolution, range) / 1000;
|
const effectiveResolution = getEffectiveResolution(resolution, range) / 1000;
|
||||||
|
@ -47,12 +67,12 @@ const Graph: FC<GraphProps> = ({
|
||||||
key: [useId()],
|
key: [useId()],
|
||||||
path: "/query_range",
|
path: "/query_range",
|
||||||
params: {
|
params: {
|
||||||
query: expr,
|
query: effectiveExpr,
|
||||||
step: effectiveResolution.toString(),
|
step: effectiveResolution.toString(),
|
||||||
start: startTime.toString(),
|
start: startTime.toString(),
|
||||||
end: effectiveEndTime.toString(),
|
end: effectiveEndTime.toString(),
|
||||||
},
|
},
|
||||||
enabled: expr !== "",
|
enabled: effectiveExpr !== "",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Bundle the chart data and the displayed range together. This has two purposes:
|
// 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).
|
// Re-execute the query when the user presses Enter (or hits the Execute button).
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
expr !== "" && refetch();
|
effectiveExpr !== "" && refetch();
|
||||||
}, [retriggerIdx, refetch, expr, endTime, range, resolution]);
|
}, [retriggerIdx, refetch, effectiveExpr, endTime, range, resolution]);
|
||||||
|
|
||||||
// The useElementSize hook above only gets a valid size on the second render, so this
|
// 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.
|
// is a workaround to make the component render twice after mount.
|
||||||
|
@ -133,27 +153,39 @@ const Graph: FC<GraphProps> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box pos="relative" ref={ref} className={classes.chartWrapper}>
|
<Stack>
|
||||||
<LoadingOverlay
|
{node !== null && node.type === nodeType.matrixSelector && (
|
||||||
visible={isFetching}
|
<Alert
|
||||||
zIndex={1000}
|
color="orange"
|
||||||
h={570}
|
title="Graphing modified expression"
|
||||||
overlayProps={{ radius: "sm", blur: 0.5 }}
|
icon={<IconAlertTriangle size={14} />}
|
||||||
loaderProps={{ type: "dots", color: "gray.6" }}
|
>
|
||||||
// loaderProps={{
|
<strong>Note:</strong> Range vector selectors can't be graphed, so
|
||||||
// children: <Skeleton m={0} w="100%" h="100%" />,
|
graphing the equivalent instant vector selector instead.
|
||||||
// }}
|
</Alert>
|
||||||
// styles={{ loader: { width: "100%", height: "100%" } }}
|
)}
|
||||||
/>
|
<Box pos="relative" ref={ref} className={classes.chartWrapper}>
|
||||||
<UPlotChart
|
<LoadingOverlay
|
||||||
data={dataAndRange.data.data.result}
|
visible={isFetching}
|
||||||
range={dataAndRange.range}
|
zIndex={1000}
|
||||||
width={width}
|
h={570}
|
||||||
showExemplars={showExemplars}
|
overlayProps={{ radius: "sm", blur: 0.5 }}
|
||||||
displayMode={displayMode}
|
loaderProps={{ type: "dots", color: "gray.6" }}
|
||||||
onSelectRange={onSelectRange}
|
// loaderProps={{
|
||||||
/>
|
// children: <Skeleton m={0} w="100%" h="100%" />,
|
||||||
</Box>
|
// }}
|
||||||
|
// 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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -296,6 +296,7 @@ const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
|
||||||
<Space h="lg" />
|
<Space h="lg" />
|
||||||
<Graph
|
<Graph
|
||||||
expr={expr}
|
expr={expr}
|
||||||
|
node={selectedNode?.node ?? null}
|
||||||
endTime={panel.visualizer.endTime}
|
endTime={panel.visualizer.endTime}
|
||||||
range={panel.visualizer.range}
|
range={panel.visualizer.range}
|
||||||
resolution={panel.visualizer.resolution}
|
resolution={panel.visualizer.resolution}
|
||||||
|
|
Loading…
Reference in a new issue