import { FC, ReactNode, useEffect, useId, useLayoutEffect, useState, } from "react"; import { Table, Alert, Skeleton, Box, LoadingOverlay, SegmentedControl, ScrollArea, Group, Stack, Text, Anchor, } from "@mantine/core"; import { IconAlertTriangle, IconInfoCircle } from "@tabler/icons-react"; import { InstantQueryResult, InstantSample, RangeSamples, } from "../../api/responseTypes/query"; 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 { formatTimestamp } from "../../lib/formatTime"; import HistogramChart from "./HistogramChart"; import { Histogram } from "../../types/types"; import { bucketRangeString } from "./HistogramHelpers"; import { useSettings } from "../../state/settingsSlice"; import { useAppDispatch, useAppSelector } from "../../state/hooks"; import { setVisualizer } from "../../state/queryPageSlice"; import TimeInput from "./TimeInput"; dayjs.extend(timezone); const maxFormattableSeries = 1000; const maxDisplayableSeries = 10000; const limitSeries = ( series: S[], limit: boolean ): S[] => { if (limit && series.length > maxDisplayableSeries) { return series.slice(0, maxDisplayableSeries); } return series; }; export interface DataTableProps { panelIdx: number; retriggerIdx: number; } const DataTable: FC = ({ panelIdx, retriggerIdx }) => { const [scale, setScale] = useState("exponential"); const [limitResults, setLimitResults] = useState(true); const [responseTime, setResponseTime] = useState(0); const { expr, visualizer } = useAppSelector( (state) => state.queryPage.panels[panelIdx] ); const dispatch = useAppDispatch(); const { endTime, range } = visualizer; const { data, error, isFetching, isLoading, refetch } = useAPIQuery({ key: useId(), path: "/query", params: { query: expr, time: `${(endTime !== null ? endTime : Date.now()) / 1000}`, }, enabled: expr !== "", recordResponseTime: setResponseTime, }); useEffect(() => { expr !== "" && refetch(); }, [retriggerIdx, refetch, expr, endTime]); useLayoutEffect(() => { setLimitResults(true); }, [data, isFetching]); const { useLocalTime } = useSettings(); // Show a skeleton only on the first load, not on subsequent ones. if (isLoading) { return ( {Array.from(Array(5), (_, i) => ( ))} ); } if (error) { return ( } > {error.message} ); } if (data === undefined) { return No data queried yet; } const { result, resultType } = data.data; if (result.length === 0) { return ( }> This query returned no data. ); } const doFormat = result.length <= maxFormattableSeries; return ( {isLoading ? ( {Array.from(Array(5), (_, i) => ( ))} ) : data === undefined ? ( No data queried yet ) : result.length === 0 ? ( }> This query returned no data. ) : ( <> dispatch( setVisualizer({ idx: panelIdx, visualizer: { ...visualizer, endTime: time }, }) ) } /> Load time: {responseTime}ms   Result series: {result.length} {limitResults && ["vector", "matrix"].includes(resultType) && result.length > maxDisplayableSeries && ( } title="Showing limited results" > Fetched {data.data.result.length} metrics, only displaying first{" "} {maxDisplayableSeries} for performance reasons. setLimitResults(false)}> Show all results )} {!doFormat && ( } > Showing more than {maxFormattableSeries} series, turning off label formatting for performance reasons. )} , }} styles={{ loader: { width: "100%", height: "100%" } }} /> {resultType === "vector" ? ( limitSeries(result, limitResults).map( (s, idx) => ( {s.value && s.value[1]} {s.histogram && ( Count:{" "} {s.histogram[1].count} Sum: {s.histogram[1].sum} x-axis scale: {histogramTable(s.histogram[1])} )} ) ) ) : resultType === "matrix" ? ( limitSeries(result, limitResults).map( (s, idx) => ( {s.values && s.values.map((v, idx) => (
{v[1]}{" "} @ {v[0]}
))}
) ) ) : resultType === "scalar" ? ( Scalar value {result[1]} ) : resultType === "string" ? ( String value {result[1]} ) : ( } > Invalid result value type )}
)}
); }; const histogramTable = (h: Histogram): ReactNode => ( Bucket range Count {h.buckets?.map((b, i) => ( {bucketRangeString(b)} {b[3]} ))}
); export default DataTable;