Various query page improvements

Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
Julius Volz 2024-04-03 14:45:35 +02:00
parent 684698b827
commit 2be782df77
6 changed files with 69 additions and 61 deletions

View file

@ -9,6 +9,11 @@ import {
import SeriesName from "./SeriesName";
import { useAPIQuery } from "../../api/api";
import classes from "./DataTable.module.css";
import dayjs from "dayjs";
import timezone from "dayjs/plugin/timezone";
import { useAppSelector } from "../../state/hooks";
import { formatTimestamp } from "../../lib/formatTime";
dayjs.extend(timezone);
const maxFormattableSeries = 1000;
const maxDisplayableSeries = 10000;
@ -44,6 +49,8 @@ const DataTable: FC<DataTableProps> = ({ expr, evalTime, retriggerIdx }) => {
expr !== "" && refetch();
}, [retriggerIdx, refetch, expr, evalTime]);
const useLocalTime = useAppSelector((state) => state.settings.useLocalTime);
// Show a skeleton only on the first load, not on subsequent ones.
if (isLoading) {
return (
@ -118,7 +125,12 @@ const DataTable: FC<DataTableProps> = ({ expr, evalTime, retriggerIdx }) => {
{s.values &&
s.values.map((v, idx) => (
<div key={idx}>
{v[1]} @ {v[0]}
{v[1]} @{" "}
{
<span title={formatTimestamp(v[0], useLocalTime)}>
{v[0]}
</span>
}
</div>
))}
</Table.Td>

View file

@ -189,6 +189,8 @@ const ExpressionInput: FC<ExpressionInputProps> = ({
return (
<Group align="flex-start" wrap="nowrap" gap="xs">
{/* TODO: For wrapped long lines, the input grows in width more and more, the
longer the line is. Figure out why and fix it. */}
<InputBase<any>
leftSection={
isFormatting ? <Loader size="xs" color="gray.5" /> : <IconTerminal />

View file

@ -46,47 +46,46 @@ export default function QueryPage() {
return (
<Box mt="xs">
<Stack gap="sm">
{metricNamesError && (
<Alert
icon={
<IconAlertTriangle style={{ width: rem(14), height: rem(14) }} />
}
color="red"
title="Error fetching metrics list"
withCloseButton
>
Unable to fetch list of metric names: {metricNamesError.message}
</Alert>
)}
{timeError && (
<Alert
icon={
<IconAlertTriangle style={{ width: rem(14), height: rem(14) }} />
}
color="red"
title="Error fetching server time"
withCloseButton
>
{timeError.message}
</Alert>
)}
{timeDelta > 30 && (
<Alert
title="Server time is out of sync"
color="red"
icon={
<IconAlertCircle style={{ width: rem(14), height: rem(14) }} />
}
onClose={() => setTimeDelta(0)}
>
Detected a time difference of{" "}
<strong>{humanizeDuration(timeDelta * 1000)}</strong> between your
browser and the server. You may see unexpected time-shifted query
results due to the time drift.
</Alert>
)}
</Stack>
{metricNamesError && (
<Alert
mb="sm"
icon={
<IconAlertTriangle style={{ width: rem(14), height: rem(14) }} />
}
color="red"
title="Error fetching metrics list"
withCloseButton
>
Unable to fetch list of metric names: {metricNamesError.message}
</Alert>
)}
{timeError && (
<Alert
mb="sm"
icon={
<IconAlertTriangle style={{ width: rem(14), height: rem(14) }} />
}
color="red"
title="Error fetching server time"
withCloseButton
>
{timeError.message}
</Alert>
)}
{timeDelta > 30 && (
<Alert
mb="sm"
title="Server time is out of sync"
color="red"
icon={<IconAlertCircle style={{ width: rem(14), height: rem(14) }} />}
onClose={() => setTimeDelta(0)}
>
Detected a time difference of{" "}
<strong>{humanizeDuration(timeDelta * 1000)}</strong> between your
browser and the server. You may see unexpected time-shifted query
results due to the time drift.
</Alert>
)}
<Stack gap="xl">
{panels.map((p, idx) => (

View file

@ -214,18 +214,6 @@ const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
/>
</Tabs.Panel>
</Tabs>
{/* Link button to remove this panel. */}
{/* <Group justify="right">
<Button
variant="subtle"
size="sm"
fw={500}
// color="red"
onClick={() => dispatch(removePanel(idx))}
>
Remove query
</Button>
</Group> */}
</Stack>
);
};

View file

@ -1,7 +1,10 @@
import { FC, useState } from "react";
import { ActionIcon, Group, Input } from "@mantine/core";
import { IconMinus, IconPlus } from "@tabler/icons-react";
import { formatDuration, parseDuration } from "../../lib/formatTime";
import {
formatPrometheusDuration,
parsePrometheusDuration,
} from "../../lib/formatTime";
interface RangeInputProps {
range: number;
@ -36,12 +39,14 @@ const rangeSteps = [
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>(formatDuration(range));
const [rangeInput, setRangeInput] = useState<string>(
formatPrometheusDuration(range)
);
const onChangeRangeInput = (rangeText: string): void => {
const newRange = parseDuration(rangeText);
const newRange = parsePrometheusDuration(rangeText);
if (newRange === null) {
setRangeInput(formatDuration(range));
setRangeInput(formatPrometheusDuration(range));
} else {
onChangeRange(newRange);
}
@ -50,7 +55,7 @@ const RangeInput: FC<RangeInputProps> = ({ range, onChangeRange }) => {
const increaseRange = (): void => {
for (const step of rangeSteps) {
if (range < step) {
setRangeInput(formatDuration(step));
setRangeInput(formatPrometheusDuration(step));
onChangeRange(step);
return;
}
@ -60,7 +65,7 @@ const RangeInput: FC<RangeInputProps> = ({ range, onChangeRange }) => {
const decreaseRange = (): void => {
for (const step of rangeSteps.slice().reverse()) {
if (range > step) {
setRangeInput(formatDuration(step));
setRangeInput(formatPrometheusDuration(step));
onChangeRange(step);
return;
}

View file

@ -2,6 +2,7 @@ import { Group, ActionIcon, CloseButton } from "@mantine/core";
import { DatesProvider, DateTimePicker } from "@mantine/dates";
import { IconChevronLeft, IconChevronRight } from "@tabler/icons-react";
import { FC } from "react";
import { useAppSelector } from "../../state/hooks";
interface TimeInputProps {
time: number | null; // Timestamp in milliseconds.
@ -19,10 +20,11 @@ const TimeInput: FC<TimeInputProps> = ({
onChangeTime,
}) => {
const baseTime = () => (time !== null ? time : Date.now().valueOf());
const useLocalTime = useAppSelector((state) => state.settings.useLocalTime);
return (
<Group gap={5}>
<DatesProvider settings={{ timezone: "UTC" }}>
<DatesProvider settings={{ timezone: useLocalTime ? undefined : "UTC" }}>
<DateTimePicker
w={230}
valueFormat="YYYY-MM-DD HH:mm:ss"