prometheus/web/ui/mantine-ui/src/pages/query/RangeInput.tsx
Julius Volz 8ef66c41a0 A lot of work around uPlot and resolution picking
Signed-off-by: Julius Volz <julius.volz@gmail.com>
2024-07-21 23:55:08 +02:00

121 lines
3 KiB
TypeScript

import { FC, useEffect, useState } from "react";
import { ActionIcon, Group, Input } from "@mantine/core";
import { IconMinus, IconPlus } from "@tabler/icons-react";
import {
formatPrometheusDuration,
parsePrometheusDuration,
} from "../../lib/formatTime";
interface RangeInputProps {
range: number;
onChangeRange: (range: number) => void;
}
const iconStyle = { width: "0.9rem", height: "0.9rem" };
const rangeSteps = [
1,
10,
60,
5 * 60,
15 * 60,
30 * 60,
60 * 60,
2 * 60 * 60,
6 * 60 * 60,
12 * 60 * 60,
24 * 60 * 60,
48 * 60 * 60,
7 * 24 * 60 * 60,
14 * 24 * 60 * 60,
28 * 24 * 60 * 60,
56 * 24 * 60 * 60,
112 * 24 * 60 * 60,
182 * 24 * 60 * 60,
365 * 24 * 60 * 60,
730 * 24 * 60 * 60,
].map((s) => s * 1000);
const RangeInput: FC<RangeInputProps> = ({ range, onChangeRange }) => {
// TODO: Make sure that when "range" changes externally (like via the URL),
// the input is updated, either via useEffect() or some better architecture.
const [rangeInput, setRangeInput] = useState<string>(
formatPrometheusDuration(range)
);
useEffect(() => {
setRangeInput(formatPrometheusDuration(range));
}, [range]);
const onChangeRangeInput = (rangeText: string): void => {
const newRange = parsePrometheusDuration(rangeText);
if (newRange === null) {
setRangeInput(formatPrometheusDuration(range));
} else {
onChangeRange(newRange);
}
};
const increaseRange = (): void => {
for (const step of rangeSteps) {
if (range < step) {
setRangeInput(formatPrometheusDuration(step));
onChangeRange(step);
return;
}
}
};
const decreaseRange = (): void => {
for (const step of rangeSteps.slice().reverse()) {
if (range > step) {
setRangeInput(formatPrometheusDuration(step));
onChangeRange(step);
return;
}
}
};
return (
<Group gap={5}>
<Input
title="Range"
value={rangeInput}
onChange={(event) => setRangeInput(event.currentTarget.value)}
onBlur={() => onChangeRangeInput(rangeInput)}
onKeyDown={(event) =>
event.key === "Enter" && onChangeRangeInput(rangeInput)
}
aria-label="Range"
style={{ width: `calc(44px + ${rangeInput.length + 3}ch)` }}
leftSection={
<ActionIcon
size="lg"
variant="transparent"
color="gray"
aria-label="Decrease range"
onClick={decreaseRange}
>
<IconMinus style={iconStyle} />
</ActionIcon>
}
rightSection={
<ActionIcon
size="lg"
variant="transparent"
color="gray"
aria-label="Increase range"
onClick={increaseRange}
>
<IconPlus style={iconStyle} />
</ActionIcon>
}
leftSectionPointerEvents="all"
rightSectionPointerEvents="all"
/>
</Group>
);
};
export default RangeInput;