Skip to content

Commit 730ea6f

Browse files
feat(logs): switch LogsInfiniteTable to toggle-able bound scrolling
1 parent abb2fe5 commit 730ea6f

File tree

9 files changed

+75
-55
lines changed

9 files changed

+75
-55
lines changed

static/app/components/events/ourlogs/ourlogsDrawer.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {useMemo, useRef} from 'react';
1+
import {useMemo} from 'react';
22
import moment from 'moment-timezone';
33

44
import {ProjectAvatar} from '@sentry/scraps/avatar';
@@ -83,7 +83,6 @@ export function OurlogsDrawer({
8383
const searchQueryBuilderProps = useTraceItemSearchQueryBuilderProps(
8484
tracesItemSearchQueryBuilderProps
8585
);
86-
const containerRef = useRef<HTMLDivElement>(null);
8786

8887
const additionalData = useMemo(
8988
() => ({
@@ -156,11 +155,10 @@ export function OurlogsDrawer({
156155
)}
157156
</Flex>
158157
</EventNavigator>
159-
<EventDrawerBody ref={containerRef}>
158+
<EventDrawerBody>
160159
<Stack gap="xl">
161160
<LogsInfiniteTable
162161
embedded
163-
scrollContainer={containerRef}
164162
embeddedOptions={embeddedOptions}
165163
additionalData={additionalData}
166164
/>

static/app/views/explore/logs/styles.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ export const LogTableBodyCell = styled(TableBodyCell)`
128128

129129
export const LogTableBody = styled(TableBody)<{
130130
disableBodyPadding?: boolean;
131+
expanded?: boolean;
131132
showHeader?: boolean;
132133
}>`
133134
${p =>
@@ -139,6 +140,13 @@ export const LogTableBody = styled(TableBody)<{
139140
padding-top: ${space(1)};
140141
padding-bottom: ${space(1)};
141142
`}
143+
${p =>
144+
p.expanded
145+
? ``
146+
: `
147+
overflow-y: scroll;
148+
max-height: 70vh;
149+
min-height: 5rem;`}
142150
`;
143151

144152
export const LogDetailTableBodyCell = styled(TableBodyCell)`

static/app/views/explore/logs/tables/logsInfiniteTable.tsx

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {Fragment, useCallback, useEffect, useMemo, useRef, useState} from 'react
33
import styled from '@emotion/styled';
44
import * as Sentry from '@sentry/react';
55
import type {Virtualizer} from '@tanstack/react-virtual';
6-
import {useVirtualizer, useWindowVirtualizer} from '@tanstack/react-virtual';
6+
import {useVirtualizer} from '@tanstack/react-virtual';
77

88
import {Button} from '@sentry/scraps/button';
99
import {Flex, Stack} from '@sentry/scraps/layout';
@@ -49,6 +49,7 @@ import {
4949
LogTableRow,
5050
} from 'sentry/views/explore/logs/styles';
5151
import {LogRowContent} from 'sentry/views/explore/logs/tables/logsTableRow';
52+
import {useExpandoButton} from 'sentry/views/explore/logs/tables/useExpandoButton';
5253
import {
5354
OurLogKnownFieldKey,
5455
type OurLogsResponseItem,
@@ -95,7 +96,6 @@ type LogsTableProps = {
9596
filteredItems: OurLogsResponseItem[];
9697
};
9798
numberAttributes?: TagCollection;
98-
scrollContainer?: React.RefObject<HTMLElement | null>;
9999
stringAttributes?: TagCollection;
100100
};
101101

@@ -111,7 +111,6 @@ export function LogsInfiniteTable({
111111
numberAttributes,
112112
stringAttributes,
113113
booleanAttributes,
114-
scrollContainer,
115114
embeddedStyling,
116115
embeddedOptions,
117116
additionalData,
@@ -254,23 +253,14 @@ export function LogsInfiniteTable({
254253
return terms;
255254
}, [search, localOnlyItemFilters?.filterText]);
256255

257-
const windowVirtualizer = useWindowVirtualizer({
256+
const virtualizer = useVirtualizer({
258257
count: data?.length ?? 0,
259258
estimateSize,
260259
overscan: LOGS_OVERSCAN_AMOUNT,
260+
getScrollElement: () => tableBodyRef?.current,
261261
getItemKey: (index: number) => data?.[index]?.[OurLogKnownFieldKey.ID] ?? index,
262-
scrollMargin: tableBodyRef.current?.offsetTop ?? 0,
263262
});
264263

265-
const containerVirtualizer = useVirtualizer({
266-
count: data?.length ?? 0,
267-
estimateSize,
268-
overscan: LOGS_OVERSCAN_AMOUNT,
269-
getScrollElement: () => scrollContainer?.current ?? null,
270-
getItemKey: (index: number) => data?.[index]?.[OurLogKnownFieldKey.ID] ?? index,
271-
});
272-
273-
const virtualizer = scrollContainer?.current ? containerVirtualizer : windowVirtualizer;
274264
const virtualItems = virtualizer.getVirtualItems();
275265

276266
const firstItem = virtualItems[0]?.start;
@@ -291,22 +281,22 @@ export function LogsInfiniteTable({
291281
useEffect(() => {
292282
if (
293283
pseudoRowIndex !== -1 &&
294-
scrollContainer?.current &&
284+
tableBodyRef?.current &&
295285
!additionalData?.scrollToDisabled
296286
) {
297287
setTimeout(() => {
298288
const scrollToIndex =
299289
pseudoRowIndex === -2 ? baseDataLength.current : pseudoRowIndex;
300-
containerVirtualizer.scrollToIndex(scrollToIndex, {
290+
virtualizer.scrollToIndex(scrollToIndex, {
301291
behavior: 'smooth',
302292
align: 'center',
303293
});
304294
}, 100);
305295
}
306296
}, [
307297
pseudoRowIndex,
308-
containerVirtualizer,
309-
scrollContainer,
298+
virtualizer,
299+
tableBodyRef,
310300
baseDataLength,
311301
additionalData?.scrollToDisabled,
312302
]);
@@ -335,9 +325,7 @@ export function LogsInfiniteTable({
335325
]
336326
: [0, 0];
337327

338-
const {scrollDirection, scrollOffset, isScrolling} = scrollContainer
339-
? containerVirtualizer
340-
: virtualizer;
328+
const {scrollDirection, scrollOffset, isScrolling} = virtualizer;
341329

342330
useEffect(() => {
343331
if (isFunctionScrolling && !isScrolling && scrollOffset === 0) {
@@ -427,6 +415,10 @@ export function LogsInfiniteTable({
427415
};
428416
}, []);
429417

418+
const {expanded, expando} = useExpandoButton(() => {
419+
virtualizer.measure();
420+
});
421+
430422
// For replay context, render empty states outside the table for proper centering
431423
if (hasReplay && (isPending || isError || isEmpty)) {
432424
return (
@@ -467,10 +459,12 @@ export function LogsInfiniteTable({
467459
onResizeMouseDown={onResizeMouseDown}
468460
/>
469461
)}
462+
<div style={{position: 'absolute', top: 8, right: 8}}>{expando}</div>
470463
<LogTableBody
471464
showHeader={!embedded}
472465
ref={tableBodyRef}
473466
disableBodyPadding={embeddedStyling?.disableBodyPadding}
467+
expanded={expanded}
474468
>
475469
{paddingTop > 0 && (
476470
<TableRow>
@@ -774,7 +768,10 @@ function BackToTopButton({
774768
}: {
775769
hidden: boolean;
776770
setIsFunctionScrolling: (isScrolling: boolean) => void;
777-
virtualizer: Virtualizer<HTMLElement, Element> | Virtualizer<Window, Element>;
771+
virtualizer:
772+
| Virtualizer<HTMLTableSectionElement, Element>
773+
| Virtualizer<HTMLElement, Element>
774+
| Virtualizer<Window, Element>;
778775
}) {
779776
if (hidden) {
780777
return null;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {useState} from 'react';
2+
3+
import {Button} from '@sentry/scraps/button';
4+
5+
import {IconContract, IconExpand} from 'sentry/icons';
6+
import {t} from 'sentry/locale';
7+
import {TableActionButton} from 'sentry/views/explore/components/tableActionButton';
8+
9+
export function useExpandoButton(onToggle: () => void) {
10+
const [expanded, setExpanded] = useState(false);
11+
12+
const [Icon, text] = expanded
13+
? [IconContract, t('Collapse Table')]
14+
: [IconExpand, t('Expand Table')];
15+
16+
const toggleExpanded = () => {
17+
setExpanded(!expanded);
18+
onToggle();
19+
};
20+
21+
return {
22+
expanded,
23+
expando: (
24+
<TableActionButton
25+
mobile={
26+
<Button onClick={toggleExpanded} icon={<Icon />} size="sm" aria-label={text} />
27+
}
28+
desktop={
29+
<Button onClick={toggleExpanded} icon={<Icon />} size="sm" aria-label={text}>
30+
{text}
31+
</Button>
32+
}
33+
/>
34+
),
35+
};
36+
}

static/app/views/performance/newTraceDetails/index.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ function TraceViewImpl({traceSlug}: {traceSlug: string}) {
135135
logs: logsData,
136136
traceId: traceSlug,
137137
});
138-
const traceInnerLayoutRef = useRef<HTMLDivElement>(null);
139138

140139
const {tabOptions, currentTab, onTabChange} = useTraceLayoutTabs({
141140
tree,
@@ -160,7 +159,7 @@ function TraceViewImpl({traceSlug}: {traceSlug: string}) {
160159
logs={logsData}
161160
metrics={metricsData}
162161
/>
163-
<TraceInnerLayout ref={traceInnerLayoutRef}>
162+
<TraceInnerLayout>
164163
<ErrorsOnlyWarnings
165164
tree={tree}
166165
traceSlug={traceSlug}
@@ -197,9 +196,7 @@ function TraceViewImpl({traceSlug}: {traceSlug: string}) {
197196
{currentTab === TraceLayoutTabKeys.PROFILES ? (
198197
<TraceProfiles tree={tree} />
199198
) : null}
200-
{currentTab === TraceLayoutTabKeys.LOGS ? (
201-
<TraceViewLogsSection scrollContainer={traceInnerLayoutRef} />
202-
) : null}
199+
{currentTab === TraceLayoutTabKeys.LOGS ? <TraceViewLogsSection /> : null}
203200
{currentTab === TraceLayoutTabKeys.METRICS ? (
204201
<TraceViewMetricsProviderWrapper traceSlug={traceSlug}>
205202
<TraceViewMetricsSection />
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import {useRef} from 'react';
2-
31
import {t} from 'sentry/locale';
42
import {useLogsPageDataQueryResult} from 'sentry/views/explore/contexts/logs/logsPageData';
53
import {LogsInfiniteTable} from 'sentry/views/explore/logs/tables/logsInfiniteTable';
@@ -9,18 +7,16 @@ import {FoldSection} from 'sentry/views/issueDetails/streamline/foldSection';
97
export function LogDetails() {
108
const logsQueryResult = useLogsPageDataQueryResult();
119

12-
const scrollContainer = useRef<HTMLDivElement>(null);
1310
if (!logsQueryResult?.data?.length) {
1411
return null;
1512
}
1613
return (
1714
<FoldSection
18-
ref={scrollContainer}
1915
sectionKey={SectionKey.LOGS}
2016
title={t('Logs')}
2117
disableCollapsePersistence
2218
>
23-
<LogsInfiniteTable embedded scrollContainer={scrollContainer} />
19+
<LogsInfiniteTable embedded />
2420
</FoldSection>
2521
);
2622
}

static/app/views/performance/newTraceDetails/traceOurlogs.spec.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import {useRef} from 'react';
21
import {OrganizationFixture} from 'sentry-fixture/organization';
32

43
import {render, screen} from 'sentry-test/reactTestingLibrary';
@@ -12,10 +11,9 @@ import {
1211
const TRACE_SLUG = '00000000000000000000000000000000';
1312

1413
function Component({traceSlug}: {traceSlug: string}) {
15-
const ref = useRef(null);
1614
return (
1715
<TraceViewLogsDataProvider traceSlug={traceSlug}>
18-
<TraceViewLogsSection scrollContainer={ref} />
16+
<TraceViewLogsSection />
1917
</TraceViewLogsDataProvider>
2018
);
2119
}

static/app/views/performance/newTraceDetails/traceOurlogs.tsx

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,15 @@ export function TraceViewLogsDataProvider({
3535
);
3636
}
3737

38-
export function TraceViewLogsSection({
39-
scrollContainer,
40-
}: {
41-
scrollContainer: React.RefObject<HTMLDivElement | null>;
42-
}) {
38+
export function TraceViewLogsSection() {
4339
return (
4440
<StyledPanel>
45-
<LogsSectionContent scrollContainer={scrollContainer} />
41+
<LogsSectionContent />
4642
</StyledPanel>
4743
);
4844
}
4945

50-
function LogsSectionContent({
51-
scrollContainer,
52-
}: {
53-
scrollContainer: React.RefObject<HTMLDivElement | null>;
54-
}) {
46+
function LogsSectionContent() {
5547
const setLogsQuery = useSetQueryParamsQuery();
5648
const logsSearch = useQueryParamsSearch();
5749

@@ -66,7 +58,7 @@ function LogsSectionContent({
6658
onSearch={query => setLogsQuery(query)}
6759
/>
6860
<TableContainer>
69-
<LogsInfiniteTable embedded scrollContainer={scrollContainer} />
61+
<LogsInfiniteTable embedded />
7062
</TableContainer>
7163
</Fragment>
7264
);

static/app/views/replays/detail/ourlogs/index.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {useCallback, useMemo, useRef} from 'react';
1+
import {useCallback, useMemo} from 'react';
22
import styled from '@emotion/styled';
33

44
import Placeholder from 'sentry/components/placeholder';
@@ -79,7 +79,6 @@ function OurLogsContent({replayId, startTimestampMs}: OurLogsContentProps) {
7979
const {attributes: stringAttributes} = useTraceItemAttributes('string');
8080
const {attributes: numberAttributes} = useTraceItemAttributes('number');
8181
const {attributes: booleanAttributes} = useTraceItemAttributes('boolean');
82-
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
8382

8483
const {currentTime, setCurrentTime} = useReplayContext();
8584
const [currentHoverTime] = useCurrentHoverTime();
@@ -127,15 +126,14 @@ function OurLogsContent({replayId, startTimestampMs}: OurLogsContentProps) {
127126
return (
128127
<OurLogsContentWrapper>
129128
<OurLogFilters logItems={logItems} replayId={replayId} {...filterProps} />
130-
<TableScrollContainer ref={scrollContainerRef}>
129+
<TableScrollContainer>
131130
{isPending ? (
132131
<Placeholder height="100%" />
133132
) : (
134133
<LogsInfiniteTable
135134
stringAttributes={stringAttributes}
136135
numberAttributes={numberAttributes}
137136
booleanAttributes={booleanAttributes}
138-
scrollContainer={scrollContainerRef}
139137
allowPagination
140138
embedded
141139
embeddedOptions={embeddedOptions}

0 commit comments

Comments
 (0)