mirror of
https://github.com/prometheus/prometheus.git
synced 2025-02-21 03:16:00 -08:00
Various query page improvements
Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
parent
684698b827
commit
2be782df77
|
@ -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>
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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) => (
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue