From fb8a7e990d4251d14df71f2c184ea7703b3b60ec Mon Sep 17 00:00:00 2001 From: Mike Shi Date: Wed, 25 Mar 2026 19:20:55 -0700 Subject: [PATCH] Limit log pattern examples to 100 in side panel (#1990) ## Problem When a log pattern has thousands of sample events with large payloads, the `PatternSidePanel` renders all of them at once via `RawLogTable`, causing the page to freeze (HDX-3838). The root cause: up to 10,000 samples are fetched and grouped by pattern. A single pattern can accumulate thousands of rows, and passing all of them to `RawLogTable` at once causes excessive DOM rendering. ## Solution Limit the initial display in `PatternSidePanel` to **100 sample events**. If a pattern has more than 100 samples, a "Show all N samples" button is rendered below the table to let users load the full set on demand. ### Changes in `packages/app/src/components/PatternSidePanel.tsx`: - Added `INITIAL_LIMIT = 100` constant and `showAll` state - `displayedSamples` memo slices `pattern.samples` to the first 100 unless the user clicks "Show all" - Reset `showAll` to `false` when the `pattern` prop changes (user selects a different pattern) - Added a subtle Mantine `Button` below the table when there are more than 100 samples Linear Issue: [HDX-3838](https://linear.app/clickhouse/issue/HDX-3838/investigate-issues-with-large-log-payloads-causing-problems)
Open in Web Open in Cursor 
Co-authored-by: Cursor Agent <199161495+cursoragent@users.noreply.github.com> --- .../app/src/components/PatternSidePanel.tsx | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/app/src/components/PatternSidePanel.tsx b/packages/app/src/components/PatternSidePanel.tsx index de5cfa2c..570cc00b 100644 --- a/packages/app/src/components/PatternSidePanel.tsx +++ b/packages/app/src/components/PatternSidePanel.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { JSDataType } from '@hyperdx/common-utils/dist/clickhouse'; import { SourceKind, TSource } from '@hyperdx/common-utils/dist/types'; -import { Card, Drawer, Stack, Text } from '@mantine/core'; +import { Button, Card, Drawer, Stack, Text } from '@mantine/core'; import DBRowSidePanel from '@/components/DBRowSidePanel'; import { RawLogTable } from '@/components/DBRowTable'; @@ -92,6 +92,20 @@ export default function PatternSidePanel({ [getRowWhere], ); + const INITIAL_LIMIT = 100; + const [showAll, setShowAll] = React.useState(false); + + React.useEffect(() => { + setShowAll(false); + }, [pattern]); + + const displayedSamples = React.useMemo(() => { + if (showAll || pattern.samples.length <= INITIAL_LIMIT) { + return pattern.samples; + } + return pattern.samples.slice(0, INITIAL_LIMIT); + }, [pattern.samples, showAll]); + const handleCloseRowSidePanel = React.useCallback(() => { setSelectedRowWhere(null); }, []); @@ -126,7 +140,7 @@ export default function PatternSidePanel({ ~{pattern.count?.toLocaleString()} Sample Events ({ where: row.id, aliasWith: [] })} displayedColumns={displayedColumns} columnTypeMap={columnTypeMap} @@ -136,6 +150,17 @@ export default function PatternSidePanel({ showExpandButton={false} isLive={false} /> + {!showAll && pattern.samples.length > INITIAL_LIMIT && ( + + )}