Clarify explain view, add tree view close button, fix callback bug

Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
Julius Volz 2024-09-08 15:17:00 +02:00
parent 7e0cd2e0b4
commit 8b4291537b
4 changed files with 69 additions and 58 deletions

View file

@ -11,32 +11,35 @@ import classes from "./ExplainView.module.css";
import SelectorExplainView from "./Selector";
import AggregationExplainView from "./Aggregation";
import BinaryExprExplainView from "./BinaryExpr/BinaryExpr";
import { IconInfoCircle } from "@tabler/icons-react";
interface ExplainViewProps {
node: ASTNode | null;
treeShown: boolean;
setShowTree: () => void;
showTree: () => void;
}
const ExplainView: FC<ExplainViewProps> = ({
node,
treeShown,
setShowTree,
showTree: setShowTree,
}) => {
if (node === null) {
return (
<Alert>
<>
To use the Explain view,{" "}
{!treeShown && (
<>
<Anchor fz="unset" onClick={setShowTree}>
enable the query tree view
</Anchor>{" "}
(also available via the expression input dropdown) and then
</>
)}{" "}
select a node in the tree above.
</>
<Alert title="How to use the Explain view" icon={<IconInfoCircle />}>
This tab can help you understand the behavior of individual components
of a query.
<br />
<br />
To use the Explain view,{" "}
{!treeShown && (
<>
<Anchor fz="unset" onClick={setShowTree}>
enable the query tree view
</Anchor>{" "}
(also available via the expression input menu) and then
</>
)}{" "}
select a node in the tree above.
</Alert>
);
}

View file

@ -6,16 +6,13 @@ import {
Box,
SegmentedControl,
Stack,
Button,
Skeleton,
} from "@mantine/core";
import {
IconChartAreaFilled,
IconChartLine,
IconCheckbox,
IconGraph,
IconInfoCircle,
IconSquare,
IconTable,
} from "@tabler/icons-react";
import { FC, Suspense, useCallback, useMemo, useState } from "react";
@ -129,6 +126,10 @@ const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
retriggerIdx={retriggerIdx}
selectedNode={selectedNode}
setSelectedNode={setSelectedNode}
closeTreeView={() => {
dispatch(setShowTree({ idx, showTree: false }));
setSelectedNode(null);
}}
/>
</Suspense>
</ErrorBoundary>
@ -165,11 +166,7 @@ const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
<Tabs.Panel pt="sm" value="table">
<TableTab expr={expr} panelIdx={idx} retriggerIdx={retriggerIdx} />
</Tabs.Panel>
<Tabs.Panel
pt="sm"
value="graph"
// style={{ border: "1px solid lightgrey", borderTop: "none" }}
>
<Tabs.Panel pt="sm" value="graph">
<Group mt="xs" justify="space-between">
<Group>
<RangeInput
@ -214,7 +211,7 @@ const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
</Group>
<Group gap="lg">
<Button
{/* <Button
variant="subtle"
color="gray.9"
size="xs"
@ -249,7 +246,7 @@ const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
}
>
Show exemplars
</Button>
</Button> */}
<SegmentedControl
onChange={(value) =>
@ -325,7 +322,7 @@ const QueryPanel: FC<PanelProps> = ({ idx, metricNames }) => {
<ExplainView
node={selectedNode?.node ?? null}
treeShown={panel.showTree}
setShowTree={() => {
showTree={() => {
dispatch(setShowTree({ idx, showTree: true }));
}}
/>

View file

@ -1,5 +1,6 @@
import {
FC,
useCallback,
useEffect,
useLayoutEffect,
useMemo,
@ -57,8 +58,10 @@ const TreeNode: FC<{
selectedNode: { id: string; node: ASTNode } | null;
setSelectedNode: (Node: { id: string; node: ASTNode } | null) => void;
parentRef?: React.RefObject<HTMLDivElement>;
reportNodeState?: (state: NodeState) => void;
reportNodeState?: (childIdx: number, state: NodeState) => void;
reverse: boolean;
// The index of this node in its parent's children.
childIdx: number;
}> = ({
node,
selectedNode,
@ -66,6 +69,7 @@ const TreeNode: FC<{
parentRef,
reportNodeState,
reverse,
childIdx,
}) => {
const nodeID = useId();
const nodeRef = useRef<HTMLDivElement>(null);
@ -130,21 +134,32 @@ const TreeNode: FC<{
useEffect(() => {
if (mergedChildState === "error") {
reportNodeState && reportNodeState("error");
reportNodeState && reportNodeState(childIdx, "error");
}
}, [mergedChildState, reportNodeState]);
}, [mergedChildState, reportNodeState, childIdx]);
useEffect(() => {
if (error) {
reportNodeState && reportNodeState("error");
reportNodeState && reportNodeState(childIdx, "error");
}
}, [error, reportNodeState]);
}, [error, reportNodeState, childIdx]);
useEffect(() => {
if (isFetching) {
reportNodeState && reportNodeState("running");
reportNodeState && reportNodeState(childIdx, "running");
}
}, [isFetching, reportNodeState]);
}, [isFetching, reportNodeState, childIdx]);
const childReportNodeState = useCallback(
(childIdx: number, state: NodeState) => {
setChildStates((prev) => {
const newStates = [...prev];
newStates[childIdx] = state;
return newStates;
});
},
[setChildStates]
);
// Update the size and position of tree connector lines based on the node's and its parent's position.
useLayoutEffect(() => {
@ -185,7 +200,7 @@ const TreeNode: FC<{
return;
}
reportNodeState && reportNodeState("success");
reportNodeState && reportNodeState(childIdx, "success");
let resultSeries = 0;
const labelValuesByName: Record<string, Record<string, number>> = {};
@ -228,7 +243,7 @@ const TreeNode: FC<{
),
labelExamples,
});
}, [data, reportNodeState]);
}, [data, reportNodeState, childIdx]);
const innerNode = (
<Group
@ -367,13 +382,8 @@ const TreeNode: FC<{
setSelectedNode={setSelectedNode}
parentRef={nodeRef}
reverse={true}
reportNodeState={(state: NodeState) => {
setChildStates((prev) => {
const newStates = [...prev];
newStates[0] = state;
return newStates;
});
}}
childIdx={0}
reportNodeState={childReportNodeState}
/>
</Box>
{innerNode}
@ -384,13 +394,8 @@ const TreeNode: FC<{
setSelectedNode={setSelectedNode}
parentRef={nodeRef}
reverse={false}
reportNodeState={(state: NodeState) => {
setChildStates((prev) => {
const newStates = [...prev];
newStates[1] = state;
return newStates;
});
}}
childIdx={1}
reportNodeState={childReportNodeState}
/>
</Box>
</div>
@ -407,13 +412,8 @@ const TreeNode: FC<{
setSelectedNode={setSelectedNode}
parentRef={nodeRef}
reverse={false}
reportNodeState={(state: NodeState) => {
setChildStates((prev) => {
const newStates = [...prev];
newStates[idx] = state;
return newStates;
});
}}
childIdx={idx}
reportNodeState={childReportNodeState}
/>
</Box>
))}

View file

@ -3,7 +3,7 @@ import { useSuspenseAPIQuery } from "../../api/api";
import { useAppSelector } from "../../state/hooks";
import ASTNode from "../../promql/ast";
import TreeNode from "./TreeNode";
import { Card } from "@mantine/core";
import { Card, CloseButton } from "@mantine/core";
const TreeView: FC<{
panelIdx: number;
@ -19,7 +19,8 @@ const TreeView: FC<{
node: ASTNode;
} | null
) => void;
}> = ({ panelIdx, selectedNode, setSelectedNode }) => {
closeTreeView: () => void;
}> = ({ panelIdx, selectedNode, setSelectedNode, closeTreeView }) => {
const { expr } = useAppSelector((state) => state.queryPage.panels[panelIdx]);
const { data } = useSuspenseAPIQuery<ASTNode>({
@ -32,7 +33,17 @@ const TreeView: FC<{
return (
<Card withBorder fz="sm" style={{ overflowX: "auto" }} pl="sm">
<CloseButton
aria-label="Close tree view"
title="Close tree view"
pos="absolute"
top={7}
size="sm"
right={7}
onClick={closeTreeView}
/>
<TreeNode
childIdx={0}
node={data.data}
selectedNode={selectedNode}
setSelectedNode={setSelectedNode}