Skip to content

Commit f44b23f

Browse files
authored
Merge pull request #2121 from RedisInsight/feature/RI-4367_autoscroll-profiler
Feature/ri 4367 autoscroll profiler
2 parents 9e3d3e5 + 24424f7 commit f44b23f

File tree

6 files changed

+115
-77
lines changed

6 files changed

+115
-77
lines changed

redisinsight/ui/src/components/monitor/Monitor/Monitor.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ export interface Props {
2828
isShowHelper: boolean
2929
isSaveToFile: boolean
3030
isShowCli: boolean
31-
scrollViewOnAppear: boolean
3231
handleRunMonitor: (isSaveToLog?: boolean) => void
3332
}
3433

@@ -143,8 +142,8 @@ const Monitor = (props: Props) => {
143142
<AutoSizer>
144143
{({ width, height }) => (
145144
<MonitorOutputList
146-
width={width}
147-
height={height}
145+
width={width || 0}
146+
height={height || 0}
148147
items={items}
149148
compressed={isShowCli || isShowHelper}
150149
/>

redisinsight/ui/src/components/monitor/Monitor/styles.module.scss

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,28 +37,34 @@
3737
height: 100%;
3838
position: relative;
3939
overflow: auto;
40-
padding-left: 12px;
4140
}
4241

4342
.content {
44-
@include euiScrollBar;
45-
46-
width: 100%;
4743
height: 100%;
48-
position: relative;
49-
overflow: auto;
50-
44+
width: 100%;
5145
display: flex;
5246
flex-direction: column;
53-
margin-bottom: 6px;
54-
55-
&:first-child {
56-
padding-top: 10px;
57-
}
58-
59-
&:last-child {
60-
padding-bottom: 10px;
61-
}
47+
overflow: hidden;
48+
padding: 12px 4px 12px 12px;
49+
50+
//@include euiScrollBar;
51+
//
52+
//width: 100%;
53+
//height: 100%;
54+
//position: relative;
55+
//overflow: auto;
56+
//
57+
//display: flex;
58+
//flex-direction: column;
59+
//margin-bottom: 6px;
60+
//
61+
//&:first-child {
62+
// padding-top: 10px;
63+
//}
64+
//
65+
//&:last-child {
66+
// padding-bottom: 10px;
67+
//}
6268
}
6369

6470
.startContainer {
@@ -180,10 +186,10 @@
180186

181187
.item {
182188
display: block;
183-
overflow: hidden;
184189

185190
& > span {
186191
padding-right: 5px;
192+
word-break: break-word;
187193
}
188194
}
189195

redisinsight/ui/src/components/monitor/MonitorOutputList/MonitorOutputList.tsx

Lines changed: 81 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import React, { useEffect, useRef } from 'react'
1+
import React, { useCallback, useEffect, useRef } from 'react'
22
import cx from 'classnames'
33
import { EuiTextColor } from '@elastic/eui'
4-
import { CellMeasurer, List, CellMeasurerCache, ListRowProps } from 'react-virtualized'
4+
import { ListChildComponentProps, ListOnScrollProps, VariableSizeList as List } from 'react-window'
55

66
import { DEFAULT_ERROR_MESSAGE, getFormatTime } from 'uiSrc/utils'
77

88
import styles from 'uiSrc/components/monitor/Monitor/styles.module.scss'
9-
import 'react-virtualized/styles.css'
109

1110
export interface Props {
1211
compressed: boolean
@@ -18,28 +17,67 @@ export interface Props {
1817
const PROTRUDING_OFFSET = 2
1918
const MIDDLE_SCREEN_RESOLUTION = 460
2019
const SMALL_SCREEN_RESOLUTION = 360
20+
const MIN_ROW_HEIGHT = 17
2121

2222
const MonitorOutputList = (props: Props) => {
2323
const { compressed, items = [], width = 0, height = 0 } = props
2424

25-
const cache = new CellMeasurerCache({
26-
defaultHeight: 17,
27-
fixedWidth: true,
28-
fixedHeight: false
29-
})
30-
25+
const autoScrollRef = useRef<boolean>(true)
26+
const rowHeights = useRef<{ [key: number]: number }>({})
27+
const outerRef = useRef<HTMLDivElement>(null)
3128
const listRef = useRef<List>(null)
29+
const hasMountedRef = useRef<boolean>(false)
30+
31+
useEffect(() => {
32+
if (autoScrollRef.current) {
33+
setTimeout(() => {
34+
scrollToBottom()
35+
}, 0)
36+
}
37+
}, [items])
38+
39+
const getRowHeight = (index: number) => (
40+
rowHeights.current[index] > MIN_ROW_HEIGHT ? (rowHeights.current[index] + 2) : MIN_ROW_HEIGHT
41+
)
42+
43+
const setRowHeight = (index: number, size: number) => {
44+
listRef.current?.resetAfterIndex(0)
45+
if (size > MIN_ROW_HEIGHT) {
46+
rowHeights.current[index] = size
47+
return
48+
}
49+
50+
if (rowHeights.current[index]) {
51+
delete rowHeights.current[index]
52+
}
53+
}
3254

33-
const clearCacheAndUpdate = () => {
34-
listRef?.current?.scrollToRow(items.length - 1)
55+
const scrollToBottom = () => {
56+
listRef.current?.scrollToItem(items.length - 1, 'end')
3557
requestAnimationFrame(() => {
36-
listRef?.current?.scrollToRow(items.length - 1)
58+
listRef.current?.scrollToItem(items.length - 1, 'end')
3759
})
3860
}
3961

40-
useEffect(() => {
41-
clearCacheAndUpdate()
42-
}, [items])
62+
const handleScroll = useCallback((e: ListOnScrollProps) => {
63+
if (!hasMountedRef.current) {
64+
hasMountedRef.current = true
65+
return
66+
}
67+
68+
if (!outerRef.current) {
69+
return
70+
}
71+
72+
if (e.scrollOffset + outerRef.current.offsetHeight === outerRef.current.scrollHeight) {
73+
autoScrollRef.current = true
74+
return
75+
}
76+
77+
if (!e.scrollUpdateWasRequested) {
78+
autoScrollRef.current = false
79+
}
80+
}, [])
4381

4482
const getArgs = (args: string[]): JSX.Element => (
4583
<span className={cx(styles.itemArgs, { [styles.itemArgs__compressed]: compressed })}>
@@ -54,51 +92,47 @@ const MonitorOutputList = (props: Props) => {
5492
</span>
5593
)
5694

57-
const rowRenderer = ({ parent, index, key, style }: ListRowProps) => {
95+
const Row = ({ index, style }: ListChildComponentProps) => {
5896
const { time = '', args = [], database = '', source = '', isError, message = '' } = items[index]
97+
const rowRef = useRef<HTMLDivElement>(null)
98+
99+
useEffect(() => {
100+
if (!rowRef.current) return
101+
setRowHeight(index, rowRef.current?.clientHeight)
102+
}, [rowRef])
103+
59104
return (
60-
<CellMeasurer
61-
cache={cache}
62-
columnIndex={0}
63-
key={key}
64-
parent={parent}
65-
rowIndex={index}
66-
>
67-
{({ registerChild, measure }) => (
68-
<div onLoad={measure} className={styles.item} ref={registerChild} style={style}>
69-
{!isError && (
70-
<>
71-
{width > MIDDLE_SCREEN_RESOLUTION && (
72-
<span className={cx(styles.time)}>
73-
{getFormatTime(time)}
74-
&nbsp;
75-
</span>
76-
)}
77-
{width > SMALL_SCREEN_RESOLUTION && (<span>{`[${database} ${source}] `}</span>)}
78-
<span>{getArgs(args)}</span>
79-
</>
80-
)}
81-
{isError && (
82-
<EuiTextColor color="danger">{message ?? DEFAULT_ERROR_MESSAGE}</EuiTextColor>
105+
<div style={style} className={styles.item} data-testid={`row-${index}`}>
106+
{!isError && (
107+
<div ref={rowRef}>
108+
{width > MIDDLE_SCREEN_RESOLUTION && (
109+
<span className={cx(styles.time)}>{getFormatTime(time)}&nbsp;</span>
83110
)}
111+
{width > SMALL_SCREEN_RESOLUTION && (<span>{`[${database} ${source}] `}</span>)}
112+
<span>{getArgs(args)}</span>
84113
</div>
85114
)}
86-
</CellMeasurer>
115+
{isError && (
116+
<EuiTextColor color="danger">{message ?? DEFAULT_ERROR_MESSAGE}</EuiTextColor>
117+
)}
118+
</div>
87119
)
88120
}
89121

90122
return (
91123
<List
124+
height={height}
125+
itemCount={items.length}
126+
itemSize={getRowHeight}
92127
ref={listRef}
93128
width={width - PROTRUDING_OFFSET}
94-
height={height - PROTRUDING_OFFSET}
95-
rowCount={items.length}
96-
rowHeight={cache.rowHeight}
97-
rowRenderer={rowRenderer}
98-
overscanRowCount={30}
99129
className={styles.listWrapper}
100-
deferredMeasurementCache={cache}
101-
/>
130+
outerRef={outerRef}
131+
onScroll={handleScroll}
132+
overscanCount={30}
133+
>
134+
{Row}
135+
</List>
102136
)
103137
}
104138

redisinsight/ui/src/components/monitor/MonitorWrapper.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ const MonitorWrapper = () => {
4040
<section className={styles.monitorWrapper} data-testid="monitor-container">
4141
<MonitorHeader handleRunMonitor={handleRunMonitor} />
4242
<Monitor
43-
scrollViewOnAppear
4443
items={items}
4544
error={error}
4645
isStarted={isStarted}

redisinsight/ui/src/pages/pubSub/components/messages-list/MessagesList/MessagesList.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ const MessagesList = (props: Props) => {
7676
return
7777
}
7878

79-
if (e.scrollUpdateWasRequested === false) {
80-
if (followRef.current && outerRef.current.scrollHeight !== outerRef.current.offsetHeight) {
79+
if (!e.scrollUpdateWasRequested) {
80+
if (followRef.current && outerRef.current?.scrollHeight !== outerRef.current?.offsetHeight) {
8181
sendEventTelemetry({
8282
event: TelemetryEvent.PUBSUB_AUTOSCROLL_PAUSED,
8383
eventData: {

redisinsight/ui/src/slices/cli/monitor.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const initialState: StateMonitor = {
2626
}
2727
}
2828

29-
export const MONITOR_ITEMS_MAX_COUNT = 5_000
29+
export const MONITOR_ITEMS_MAX_COUNT = 10_000
3030

3131
// A slice for recipes
3232
const monitorSlice = createSlice({
@@ -114,17 +114,17 @@ const monitorSlice = createSlice({
114114
concatMonitorItems: (state, { payload }: { payload: IMonitorDataPayload[] }) => {
115115
// small optimization to not unnecessary concat big arrays since we know max logs to show limitations
116116
if (payload.length >= MONITOR_ITEMS_MAX_COUNT) {
117-
state.items = [...payload.slice(-MONITOR_ITEMS_MAX_COUNT)]
117+
state.items = payload.slice(-MONITOR_ITEMS_MAX_COUNT)
118118
return
119119
}
120120

121-
let newItems = [...state.items, ...payload]
122-
123-
if (newItems.length > MONITOR_ITEMS_MAX_COUNT) {
124-
newItems = newItems.slice(newItems.length - MONITOR_ITEMS_MAX_COUNT)
121+
if (state.items.length + payload.length >= MONITOR_ITEMS_MAX_COUNT) {
122+
// concat is faster for arrays
123+
state.items = state.items.slice(payload.length - MONITOR_ITEMS_MAX_COUNT).concat(payload)
124+
return
125125
}
126126

127-
state.items = newItems
127+
state.items = state.items.concat(payload)
128128
},
129129

130130
resetMonitorItems: (state) => {

0 commit comments

Comments
 (0)