Skip to content

Commit 65f89d4

Browse files
authored
feat(LogViewer): refactor the component to get rid of the gaps between items (#6201)
1 parent f282077 commit 65f89d4

File tree

8 files changed

+700
-361
lines changed

8 files changed

+700
-361
lines changed

packages/react-log-viewer/src/LogViewer/LogViewer.tsx

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { css } from '@patternfly/react-styles';
44
import { LogViewerRow } from './LogViewerRow';
55
import { DEFAULT_FOCUS, DEFAULT_SEARCH_INDEX, DEFAULT_INDEX } from './utils/constants';
66
import { searchForKeyword, parseConsoleOutput, escapeString } from './utils/utils';
7-
import { VariableSizeList as List, areEqual } from '../react-window';
7+
import { DynamicSizeList as List, areEqual } from '../react-window';
88
import styles from '@patternfly/react-styles/css/components/LogViewer/log-viewer';
99

1010
interface LogViewerProps {
@@ -18,7 +18,7 @@ interface LogViewerProps {
1818
width?: number;
1919
/** Height in pixels of the log viewer. */
2020
height?: number;
21-
/** Rows being rendered outside of view. The more rows are rendered, the higher impact on performance */
21+
/** Rows rendered outside of view. The more rows are rendered, the higher impact on performance */
2222
overScanCount?: number;
2323
/** Toolbar rendered in the log viewer header */
2424
toolbar?: React.ReactNode;
@@ -30,18 +30,8 @@ interface LogViewerProps {
3030
scrollToRow?: number;
3131
/** Number of rows to display in the log viewer */
3232
itemCount?: number;
33-
}
34-
35-
let canvas: HTMLCanvasElement | undefined;
36-
37-
function getTextWidth(text: string, font: string) {
38-
// if given, use cached canvas for better performance
39-
// else, create new canvas
40-
canvas = canvas || document.createElement('canvas');
41-
const context = canvas.getContext('2d');
42-
context.font = font;
43-
const metrics = context.measureText(text);
44-
return metrics.width;
33+
/** Component rendered in the log viewer console window header */
34+
headerComponent?: React.ReactNode;
4535
}
4636

4737
export const LogViewer: React.FunctionComponent<LogViewerProps> = memo(
@@ -56,6 +46,7 @@ export const LogViewer: React.FunctionComponent<LogViewerProps> = memo(
5646
theme = 'light',
5747
scrollToRow = 0,
5848
itemCount = undefined,
49+
headerComponent,
5950
...props
6051
}: LogViewerProps) => {
6152
const [searchedInput, setSearchedInput] = useState<string | null>('');
@@ -121,12 +112,6 @@ export const LogViewer: React.FunctionComponent<LogViewerProps> = memo(
121112
setParsedData(parseConsoleOutput(data));
122113
}, [data]);
123114

124-
useEffect(() => {
125-
if (logViewerRef && logViewerRef.current) {
126-
logViewerRef.current.resetAfterIndex(0);
127-
}
128-
}, [parsedData]);
129-
130115
useEffect(() => {
131116
if (scrollToRow && parsedData.length) {
132117
setRowInFocus(parsedData.length - 1);
@@ -147,6 +132,7 @@ export const LogViewer: React.FunctionComponent<LogViewerProps> = memo(
147132
if (foundKeywordIndexes.length !== 0) {
148133
setSearchedWordIndexes(foundKeywordIndexes);
149134
scrollToRowInFocus(foundKeywordIndexes[DEFAULT_SEARCH_INDEX]);
135+
setCurrentSearchedItemCount(DEFAULT_INDEX);
150136
}
151137
}
152138

@@ -166,20 +152,11 @@ export const LogViewer: React.FunctionComponent<LogViewerProps> = memo(
166152
logViewerRef.current.scrollToItem(searchedRowIndex, 'center');
167153
};
168154

169-
const guessRowHeight = (rowIndex: number) => {
170-
const rowText = parsedData[rowIndex];
171-
const textWidth = getTextWidth(rowText, 'Liberation Mono');
172-
const numRows = Math.ceil(textWidth / (currentWidth || 600));
173-
174-
return 60 * (numRows || 1);
175-
};
176-
177155
const createList = (parsedData: string[]) => (
178156
<List
179157
className={css(styles.logViewerList)}
180158
height={height}
181-
width={`${currentWidth}px`}
182-
itemSize={guessRowHeight}
159+
width={currentWidth}
183160
itemCount={typeof itemCount === 'undefined' ? parsedData.length : itemCount}
184161
itemData={dataToRender}
185162
ref={logViewerRef}
@@ -221,6 +198,7 @@ export const LogViewer: React.FunctionComponent<LogViewerProps> = memo(
221198
<div className={css(styles.logViewerHeader)}>{toolbar}</div>
222199
</LogViewerToolbarContext.Provider>
223200
)}
201+
{headerComponent}
224202
<div className={css(styles.logViewerMain)} ref={containerRef}>
225203
{loading ? <div style={{ height }}>{loadingContent}</div> : createList(parsedData)}
226204
</div>

packages/react-log-viewer/src/LogViewer/LogViewerRow.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import React, { useState, useEffect, memo } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import { LOGGER_LINE_NUMBER_INDEX_DELTA } from './utils/constants';
33
import { css } from '@patternfly/react-styles';
44
import styles from '@patternfly/react-styles/css/components/LogViewer/log-viewer';
55
import { LogViewerContext } from './LogViewerContext';
6+
import { forwardRef } from 'react';
67

7-
interface LogViewerRowProps extends React.Props<HTMLElement> {
8-
index: number;
8+
interface LogViewerRowProps {
9+
index?: number;
910
style?: React.CSSProperties;
10-
data: {
11+
data?: {
1112
parsedData: string[] | null;
1213
rowInFocus: number;
1314
searchedWordIndexes: number[];
@@ -16,7 +17,7 @@ interface LogViewerRowProps extends React.Props<HTMLElement> {
1617
};
1718
}
1819

19-
export const LogViewerRow: React.FunctionComponent<LogViewerRowProps> = memo(({ index, style, data }) => {
20+
export const LogViewerRow: React.FunctionComponent<LogViewerRowProps> = forwardRef(({ index, style, data }, ref) => {
2021
const { parsedData, highlightedRowIndexes, searchedWordIndexes, setHighlightedRowIndexes, rowInFocus } = data;
2122
const [clickCounter, setClickCounter] = useState(0);
2223
const [isHiglighted, setIsHiglighted] = useState(false);
@@ -84,7 +85,13 @@ export const LogViewerRow: React.FunctionComponent<LogViewerRowProps> = memo(({
8485
};
8586

8687
return (
87-
<div style={style} className={css(styles.logViewerListItem)} onClick={() => handleHighlightRow()}>
88+
<div
89+
key={index}
90+
ref={ref as any}
91+
style={style}
92+
className={css(styles.logViewerListItem)}
93+
onClick={() => handleHighlightRow()}
94+
>
8895
<span className={css(styles.logViewerIndex)}>{getRowIndex(index)}</span>
8996
<span className={css(styles.logViewerText)} onClick={() => handleHighlightRow()}>
9097
{getFormattedData()}

packages/react-log-viewer/src/LogViewer/examples/LogViewer.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { Checkbox } from '@patternfly/react-core';
2121

2222
BasicLogViewer = () => {
2323
const [isDarkTheme, setIsDarkTheme] = React.useState(false);
24-
24+
2525
return (
2626
<React.Fragment>
2727
<Checkbox
@@ -35,7 +35,7 @@ BasicLogViewer = () => {
3535
<LogViewer hasLineNumbers={false} height={300} data={data.data} theme={isDarkTheme ? 'dark' : 'light'} />
3636
</React.Fragment>
3737
);
38-
}
38+
};
3939
```
4040

4141
### With search
@@ -107,3 +107,26 @@ CustomControlLogViewer = () => {
107107
);
108108
};
109109
```
110+
111+
### With header component
112+
113+
```js
114+
import React from 'react';
115+
import { data } from './realTestData.js';
116+
import { LogViewer } from '@patternfly/react-log-viewer';
117+
import { Banner } from '@patternfly/react-core';
118+
119+
HeaderComponentLogViewer = () => {
120+
return (
121+
<React.Fragment>
122+
<LogViewer
123+
hasLineNumbers={false}
124+
height={300}
125+
data={data.data}
126+
theme="dark"
127+
headerComponent={<Banner>{data.data.length} lines</Banner>}
128+
/>
129+
</React.Fragment>
130+
);
131+
};
132+
```

0 commit comments

Comments
 (0)