Implement initial time check and fetching of metric names

Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
Julius Volz 2024-03-08 15:15:49 +01:00
parent 33a753c2f8
commit d2f913ac1e
3 changed files with 93 additions and 6 deletions

View file

@ -108,12 +108,14 @@ export class HistoryCompleteStrategy implements CompleteStrategy {
interface ExpressionInputProps {
initialExpr: string;
metricNames: string[];
executeQuery: (expr: string) => void;
removePanel: () => void;
}
const ExpressionInput: FC<ExpressionInputProps> = ({
initialExpr,
metricNames,
executeQuery,
removePanel,
}) => {
@ -175,13 +177,13 @@ const ExpressionInput: FC<ExpressionInputProps> = ({
newCompleteStrategy({
remote: {
url: pathPrefix,
//cache: { initialMetricList: metricNames },
cache: { initialMetricList: metricNames },
},
}),
queryHistory
),
});
}, []); // TODO: Make this depend on external settings changes, maybe use dynamic config compartment again.
}, [metricNames, enableAutocomplete, enableLinter, queryHistory]); // TODO: Make this depend on external settings changes, maybe use dynamic config compartment again.
return (
<Group align="flex-start" wrap="nowrap" gap="xs">

View file

@ -1,18 +1,101 @@
import { Button, Stack } from "@mantine/core";
import { IconPlus } from "@tabler/icons-react";
import { Alert, Button, Notification, Stack, rem } from "@mantine/core";
import {
IconAlertCircle,
IconAlertTriangle,
IconPlus,
IconX,
} from "@tabler/icons-react";
import { useAppDispatch, useAppSelector } from "../../state/hooks";
import { addPanel } from "../../state/queryPageSlice";
import Panel from "./QueryPanel";
import { LabelValuesResult } from "../../api/responseTypes/labelValues";
import { useAPIQuery } from "../../api/api";
import { useEffect, useState } from "react";
import { InstantQueryResult } from "../../api/responseTypes/query";
import { humanizeDuration } from "../../lib/formatTime";
export default function QueryPage() {
const panels = useAppSelector((state) => state.queryPage.panels);
const dispatch = useAppDispatch();
const [timeDelta, setTimeDelta] = useState(0);
const { data: metricNamesResult, error: metricNamesError } =
useAPIQuery<LabelValuesResult>({
path: "/label/__name__/values",
});
const { data: timeResult, error: timeError } =
useAPIQuery<InstantQueryResult>({
path: "/query",
params: {
query: "time()",
},
});
useEffect(() => {
if (timeResult) {
if (timeResult.data.resultType !== "scalar") {
throw new Error("Unexpected result type from time query");
}
const browserTime = new Date().getTime() / 1000;
const serverTime = timeResult.data.result[0];
console.log(browserTime, serverTime, Math.abs(browserTime - serverTime));
setTimeDelta(Math.abs(browserTime - serverTime));
}
}, [timeResult]);
return (
<>
<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>
<Stack gap="xl">
{panels.map((p, idx) => (
<Panel key={p.id} idx={idx} />
<Panel
key={p.id}
idx={idx}
metricNames={metricNamesResult?.data || []}
/>
))}
</Stack>

View file

@ -30,12 +30,13 @@ import ExpressionInput from "./ExpressionInput";
export interface PanelProps {
idx: number;
metricNames: string[];
}
// TODO: This is duplicated everywhere, unify it.
const iconStyle = { width: "0.9rem", height: "0.9rem" };
const QueryPanel: FC<PanelProps> = ({ idx }) => {
const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
// Used to indicate to the selected display component that it should retrigger
// the query, even if the expression has not changed (e.g. when the user presses
// the "Execute" button or hits <Enter> again).
@ -48,6 +49,7 @@ const QueryPanel: FC<PanelProps> = ({ idx }) => {
<Stack gap="lg" mt="sm">
<ExpressionInput
initialExpr={panel.expr}
metricNames={metricNames}
executeQuery={(expr: string) => {
setRetriggerIdx((idx) => idx + 1);
dispatch(setExpr({ idx, expr }));