diff --git a/packages/app/src/components/DBDeltaChart.tsx b/packages/app/src/components/DBDeltaChart.tsx
index 61865a360..ba8899c72 100644
--- a/packages/app/src/components/DBDeltaChart.tsx
+++ b/packages/app/src/components/DBDeltaChart.tsx
@@ -5,6 +5,7 @@ import {
Filter,
} from '@hyperdx/common-utils/dist/types';
import {
+ ActionIcon,
Box,
Code,
Container,
@@ -12,8 +13,10 @@ import {
Flex,
Pagination,
Text,
+ Tooltip,
} from '@mantine/core';
import { useElementSize } from '@mantine/hooks';
+import { IconX } from '@tabler/icons-react';
import { isAggregateFunction } from '@/ChartUtils';
import { useQueriedChartConfig } from '@/hooks/useChartConfig';
@@ -52,6 +55,7 @@ export default function DBDeltaChart({
yMin: rawYMin,
yMax: rawYMax,
onAddFilter,
+ onClearSelection,
spanIdExpression,
legendPrefix,
}: {
@@ -62,6 +66,7 @@ export default function DBDeltaChart({
yMin?: number | null;
yMax?: number | null;
onAddFilter?: AddFilterFn;
+ onClearSelection?: () => void;
spanIdExpression?: string;
legendPrefix?: React.ReactNode;
}) {
@@ -516,6 +521,19 @@ export default function DBDeltaChart({
Background
+ {onClearSelection && (
+
+
+
+
+
+ )}
>
) : (
<>
diff --git a/packages/app/src/components/DBHeatmapChart.tsx b/packages/app/src/components/DBHeatmapChart.tsx
index bad724eb8..256aa90b5 100644
--- a/packages/app/src/components/DBHeatmapChart.tsx
+++ b/packages/app/src/components/DBHeatmapChart.tsx
@@ -1,4 +1,4 @@
-import { useCallback, useMemo, useRef, useState } from 'react';
+import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import dynamic from 'next/dynamic';
import type { Plugin } from 'uplot';
import uPlot from 'uplot';
@@ -341,6 +341,7 @@ function HeatmapContainer({
config,
enabled = true,
onFilter,
+ clearSelectionVersion = 0,
title,
toolbarPrefix,
toolbarSuffix,
@@ -349,6 +350,7 @@ function HeatmapContainer({
config: HeatmapChartConfig;
enabled?: boolean;
onFilter?: (xMin: number, xMax: number, yMin: number, yMax: number) => void;
+ clearSelectionVersion?: number;
title?: React.ReactNode;
toolbarPrefix?: React.ReactNode[];
toolbarSuffix?: React.ReactNode[];
@@ -661,6 +663,7 @@ function HeatmapContainer({
key={JSON.stringify(config)}
data={[time, bucket, count]}
numberFormat={config.numberFormat}
+ clearSelectionVersion={clearSelectionVersion}
onFilter={
onFilter
? (xMin, xMax, yMin, yMax) => {
@@ -791,12 +794,14 @@ function Heatmap({
data,
numberFormat,
onFilter,
+ clearSelectionVersion = 0,
scaleType = 'linear',
palette,
}: {
data: Mode2DataArray;
numberFormat?: NumberFormat;
onFilter?: (xMin: number, xMax: number, yMin: number, yMax: number) => void;
+ clearSelectionVersion?: number;
scaleType?: HeatmapScaleType;
palette: string[];
}) {
@@ -834,9 +839,21 @@ function Heatmap({
// Gate tooltip display on actual mouse interaction. uPlot fires setCursor
// on init (before user hovers), which would show the tooltip on page load.
const mouseInsideRef = useRef(false);
+ const uplotRef = useRef(null);
const { ref, width, height } = useElementSize();
+ useEffect(() => {
+ setSelectingInfo(undefined);
+ if (uplotRef.current != null) {
+ // Clear persisted uPlot drag rectangle when parent resets selection.
+ uplotRef.current.setSelect(
+ { left: 0, top: 0, width: 0, height: 0 },
+ false,
+ );
+ }
+ }, [clearSelectionVersion]);
+
const tickFormatter = useCallback(
(value: number) => {
// y-values are stored in log space for log scale; exponentiate back
@@ -1048,6 +1065,12 @@ function Heatmap({
// @ts-expect-error TODO: uPlot types are wrong for mode 2 data
data={[[], data]}
resetScales={true}
+ onCreate={chart => {
+ uplotRef.current = chart;
+ }}
+ onDelete={() => {
+ uplotRef.current = null;
+ }}
/>
{highlightedPoint != null && (
<>
diff --git a/packages/app/src/components/Search/DBSearchHeatmapChart.tsx b/packages/app/src/components/Search/DBSearchHeatmapChart.tsx
index 9c5db111d..97bc1d403 100644
--- a/packages/app/src/components/Search/DBSearchHeatmapChart.tsx
+++ b/packages/app/src/components/Search/DBSearchHeatmapChart.tsx
@@ -69,6 +69,7 @@ export function DBSearchHeatmapChart({
yMax: parseAsFloat,
});
const [container, setContainer] = useState(null);
+ const [clearSelectionVersion, setClearSelectionVersion] = useState(0);
const scaleType = (fields.scaleType ?? 'log') as HeatmapScaleType;
const setScaleType = useCallback(
(v: HeatmapScaleType) => {
@@ -80,16 +81,21 @@ export function DBSearchHeatmapChart({
const { colorScheme } = useMantineColorScheme();
const palette = colorScheme === 'light' ? lightPalette : darkPalette;
+ const clearSelection = useCallback(() => {
+ setFields({ xMin: null, xMax: null, yMin: null, yMax: null });
+ setClearSelectionVersion(version => version + 1);
+ }, [setFields]);
+
// After applying a filter, clear the heatmap selection so the delta chart
// resets instead of staying in comparison mode.
const handleAddFilterAndClearSelection = useCallback<
NonNullable
>(
(property, value, action) => {
- setFields({ xMin: null, xMax: null, yMin: null, yMax: null });
+ clearSelection();
onAddFilter?.(property, value, action);
},
- [onAddFilter, setFields],
+ [clearSelection, onAddFilter],
);
return (
@@ -125,6 +131,7 @@ export function DBSearchHeatmapChart({
: undefined,
}}
enabled={isReady}
+ clearSelectionVersion={clearSelectionVersion}
scaleType={scaleType}
onFilter={(xMin, xMax, yMin, yMax) => {
setFields({ xMin, xMax, yMin, yMax });
@@ -180,6 +187,7 @@ export function DBSearchHeatmapChart({
onAddFilter={
onAddFilter ? handleAddFilterAndClearSelection : undefined
}
+ onClearSelection={clearSelection}
spanIdExpression={source.spanIdExpression}
legendPrefix={}
/>