feat: show error details in search event patterns (#2065)

## Summary

- Shows query errors in search page event patterns in the same way as for event deltas.
- Previously, a loading state was shown indefinitely if there was an error.

### Screenshots or video



<img width="1375" height="554" alt="Screenshot 2026-04-07 at 16 14 37" src="https://github.com/user-attachments/assets/25417f1a-bfd3-44ca-bcd6-aa24156fad14" />


### How to test locally or on Vercel



1. Easiest to test locally by manually throwing from the `useQueriedChartConfig` query function.


### References



- Linear Issue: Closes HDX-3933
- Related PRs:
This commit is contained in:
Karl Power 2026-04-07 17:26:06 +02:00 committed by GitHub
parent f8d2edde5a
commit 3ffafced5e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 63 additions and 10 deletions

View file

@ -0,0 +1,5 @@
---
"@hyperdx/app": patch
---
feat: show error details in search event patterns

View file

@ -1,10 +1,13 @@
import { useMemo, useState } from 'react';
import { ClickHouseQueryError } from '@hyperdx/common-utils/dist/clickhouse';
import {
BuilderChartConfigWithDateRange,
SourceKind,
TSource,
} from '@hyperdx/common-utils/dist/types';
import { Box, Code, Container, Text } from '@mantine/core';
import { SQLPreview } from '@/components/ChartSQLPreview';
import { RawLogTable } from '@/components/DBRowTable';
import { useSearchTotalCount } from '@/components/SearchTotalCountChart';
import { Pattern, useGroupedPatterns } from '@/hooks/usePatterns';
@ -31,14 +34,16 @@ export default function PatternTable({
const [selectedPattern, setSelectedPattern] = useState<Pattern | null>(null);
const {
totalCount,
error: totalCountError,
isLoading: isTotalCountLoading,
isTotalCountComplete,
totalCount,
} = useSearchTotalCount(totalCountConfig, totalCountQueryKeyPrefix);
const {
data: groupedResults,
isLoading: isGroupedPatternsLoading,
error: groupedPatternsError,
patternQueryConfig,
} = useGroupedPatterns({
config,
@ -54,13 +59,46 @@ export default function PatternTable({
const isLoading =
isTotalCountLoading || !isTotalCountComplete || isGroupedPatternsLoading;
const error = totalCountError || groupedPatternsError;
const sortedGroupedResults = useMemo(() => {
return Object.values(groupedResults).sort(
(a, b) => b.count - a.count,
) as Pattern[];
}, [groupedResults]);
return (
return error ? (
<Container style={{ overflow: 'auto' }}>
<Box mt="lg">
<Text my="sm" size="sm">
Error Message:
</Text>
<Code
block
style={{
whiteSpace: 'pre-wrap',
}}
>
{error.message}
</Code>
</Box>
{error instanceof ClickHouseQueryError && (
<Box mt="lg">
<Text my="sm" size="sm">
Original Query:
</Text>
<Code
block
style={{
whiteSpace: 'pre-wrap',
}}
>
<SQLPreview data={error.query} formatData />
</Code>
</Box>
)}
</Container>
) : (
<>
<RawLogTable
isLive={false}

View file

@ -46,6 +46,7 @@ export function useSearchTotalCount(
data: totalCountData,
isLoading,
isError,
error,
} = useQueriedChartConfig(queriedConfig, {
queryKey: [
queryKeyPrefix,
@ -78,6 +79,7 @@ export function useSearchTotalCount(
totalCount,
isLoading,
isError,
error,
isTotalCountComplete,
};
}

View file

@ -152,15 +152,20 @@ function usePatterns({
limit: { limit: samples },
});
const { data: sampleRows, isLoading: isSampleLoading } =
useQueriedChartConfig(
configWithPrimaryAndPartitionKey ?? config, // `config` satisfying type, never used due to `enabled` check
{ enabled: configWithPrimaryAndPartitionKey != null && enabled },
);
const {
data: sampleRows,
isLoading: isSampleLoading,
error: sampleError,
} = useQueriedChartConfig(
configWithPrimaryAndPartitionKey ?? config, // `config` satisfying type, never used due to `enabled` check
{ enabled: configWithPrimaryAndPartitionKey != null && enabled },
);
const { data: pyodide, isLoading: isLoadingPyodide } = usePyodide({
enabled,
});
const {
data: pyodide,
isLoading: isLoadingPyodide,
error: pyodideError,
} = usePyodide({ enabled });
const query = useQuery({
queryKey: ['patterns', config],
@ -203,6 +208,7 @@ function usePatterns({
return {
...query,
error: sampleError || pyodideError || query.error,
isLoading: query.isLoading || isSampleLoading || isLoadingPyodide,
patternQueryConfig: configWithPrimaryAndPartitionKey,
};
@ -228,6 +234,7 @@ export function useGroupedPatterns({
const {
data: results,
isLoading,
error,
patternQueryConfig,
} = usePatterns({
config,
@ -315,6 +322,7 @@ export function useGroupedPatterns({
return {
data: groupedResults,
isLoading,
error,
miner: results?.miner,
sampledRowCount,
patternQueryConfig,