Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Logs UI] Speed up stream rendering using memoization #59163

Merged
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

// import { darken, transparentize } from 'polished';
import React, { useState, useCallback, useMemo } from 'react';
import React, { memo, useState, useCallback, useMemo } from 'react';

import { euiStyled } from '../../../../../observability/public';
import {
Expand Down Expand Up @@ -41,155 +41,157 @@ interface LogEntryRowProps {
wrap: boolean;
}

export const LogEntryRow = ({
boundingBoxRef,
columnConfigurations,
columnWidths,
highlights,
isActiveHighlight,
isHighlighted,
logEntry,
openFlyoutWithItem,
scale,
wrap,
}: LogEntryRowProps) => {
const [isHovered, setIsHovered] = useState(false);

const setItemIsHovered = useCallback(() => {
setIsHovered(true);
}, []);

const setItemIsNotHovered = useCallback(() => {
setIsHovered(false);
}, []);

const openFlyout = useCallback(() => openFlyoutWithItem(logEntry.gid), [
export const LogEntryRow = memo(
({
boundingBoxRef,
columnConfigurations,
columnWidths,
highlights,
isActiveHighlight,
isHighlighted,
logEntry,
openFlyoutWithItem,
logEntry.gid,
]);

const logEntryColumnsById = useMemo(
() =>
logEntry.columns.reduce<{
[columnId: string]: LogEntry['columns'][0];
}>(
(columnsById, column) => ({
...columnsById,
[column.columnId]: column,
}),
{}
),
[logEntry.columns]
);

const highlightsByColumnId = useMemo(
() =>
highlights.reduce<{
[columnId: string]: LogEntryHighlightColumn[];
}>(
(columnsById, highlight) =>
highlight.columns.reduce(
(innerColumnsById, column) => ({
...innerColumnsById,
[column.columnId]: [...(innerColumnsById[column.columnId] || []), column],
}),
columnsById
),
{}
),
[highlights]
);

return (
<LogEntryRowWrapper
data-test-subj="streamEntry logTextStreamEntry"
ref={
/* Workaround for missing RefObject support in styled-components */
boundingBoxRef as any
}
onMouseEnter={setItemIsHovered}
onMouseLeave={setItemIsNotHovered}
scale={scale}
>
{columnConfigurations.map(columnConfiguration => {
if (isTimestampLogColumnConfiguration(columnConfiguration)) {
const column = logEntryColumnsById[columnConfiguration.timestampColumn.id];
const columnWidth = columnWidths[columnConfiguration.timestampColumn.id];

return (
<LogEntryColumn
data-test-subj="logColumn timestampLogColumn"
key={columnConfiguration.timestampColumn.id}
{...columnWidth}
>
{isTimestampColumn(column) ? (
<LogEntryTimestampColumn
isHighlighted={isHighlighted}
isHovered={isHovered}
time={column.timestamp}
/>
) : null}
</LogEntryColumn>
);
} else if (isMessageLogColumnConfiguration(columnConfiguration)) {
const column = logEntryColumnsById[columnConfiguration.messageColumn.id];
const columnWidth = columnWidths[columnConfiguration.messageColumn.id];

return (
<LogEntryColumn
data-test-subj="logColumn messageLogColumn"
key={columnConfiguration.messageColumn.id}
{...columnWidth}
>
{column ? (
<LogEntryMessageColumn
columnValue={column}
highlights={highlightsByColumnId[column.columnId] || []}
isHighlighted={isHighlighted}
isActiveHighlight={isActiveHighlight}
isHovered={isHovered}
isWrapped={wrap}
/>
) : null}
</LogEntryColumn>
);
} else if (isFieldLogColumnConfiguration(columnConfiguration)) {
const column = logEntryColumnsById[columnConfiguration.fieldColumn.id];
const columnWidth = columnWidths[columnConfiguration.fieldColumn.id];

return (
<LogEntryColumn
data-test-subj={`logColumn fieldLogColumn fieldLogColumn:${columnConfiguration.fieldColumn.field}`}
key={columnConfiguration.fieldColumn.id}
{...columnWidth}
>
{column ? (
<LogEntryFieldColumn
columnValue={column}
highlights={highlightsByColumnId[column.columnId] || []}
isActiveHighlight={isActiveHighlight}
isHighlighted={isHighlighted}
isHovered={isHovered}
isWrapped={wrap}
/>
) : null}
</LogEntryColumn>
);
scale,
wrap,
}: LogEntryRowProps) => {
const [isHovered, setIsHovered] = useState(false);

const setItemIsHovered = useCallback(() => {
setIsHovered(true);
}, []);

const setItemIsNotHovered = useCallback(() => {
setIsHovered(false);
}, []);

const openFlyout = useCallback(() => openFlyoutWithItem(logEntry.gid), [
openFlyoutWithItem,
logEntry.gid,
]);

const logEntryColumnsById = useMemo(
() =>
logEntry.columns.reduce<{
[columnId: string]: LogEntry['columns'][0];
}>(
(columnsById, column) => ({
...columnsById,
[column.columnId]: column,
}),
{}
),
[logEntry.columns]
);

const highlightsByColumnId = useMemo(
() =>
highlights.reduce<{
[columnId: string]: LogEntryHighlightColumn[];
}>(
(columnsById, highlight) =>
highlight.columns.reduce(
(innerColumnsById, column) => ({
...innerColumnsById,
[column.columnId]: [...(innerColumnsById[column.columnId] || []), column],
}),
columnsById
),
{}
),
[highlights]
);

return (
<LogEntryRowWrapper
data-test-subj="streamEntry logTextStreamEntry"
ref={
/* Workaround for missing RefObject support in styled-components */
boundingBoxRef as any
}
})}
<LogEntryColumn
key="logColumn iconLogColumn iconLogColumn:details"
{...columnWidths[iconColumnId]}
onMouseEnter={setItemIsHovered}
onMouseLeave={setItemIsNotHovered}
scale={scale}
>
<LogEntryDetailsIconColumn
isHighlighted={isHighlighted}
isHovered={isHovered}
openFlyout={openFlyout}
/>
</LogEntryColumn>
</LogEntryRowWrapper>
);
};
{columnConfigurations.map(columnConfiguration => {
if (isTimestampLogColumnConfiguration(columnConfiguration)) {
const column = logEntryColumnsById[columnConfiguration.timestampColumn.id];
const columnWidth = columnWidths[columnConfiguration.timestampColumn.id];

return (
<LogEntryColumn
data-test-subj="logColumn timestampLogColumn"
key={columnConfiguration.timestampColumn.id}
{...columnWidth}
>
{isTimestampColumn(column) ? (
<LogEntryTimestampColumn
isHighlighted={isHighlighted}
isHovered={isHovered}
time={column.timestamp}
/>
) : null}
</LogEntryColumn>
);
} else if (isMessageLogColumnConfiguration(columnConfiguration)) {
const column = logEntryColumnsById[columnConfiguration.messageColumn.id];
const columnWidth = columnWidths[columnConfiguration.messageColumn.id];

return (
<LogEntryColumn
data-test-subj="logColumn messageLogColumn"
key={columnConfiguration.messageColumn.id}
{...columnWidth}
>
{column ? (
<LogEntryMessageColumn
columnValue={column}
highlights={highlightsByColumnId[column.columnId] || []}
isHighlighted={isHighlighted}
isActiveHighlight={isActiveHighlight}
isHovered={isHovered}
isWrapped={wrap}
/>
) : null}
</LogEntryColumn>
);
} else if (isFieldLogColumnConfiguration(columnConfiguration)) {
const column = logEntryColumnsById[columnConfiguration.fieldColumn.id];
const columnWidth = columnWidths[columnConfiguration.fieldColumn.id];

return (
<LogEntryColumn
data-test-subj={`logColumn fieldLogColumn fieldLogColumn:${columnConfiguration.fieldColumn.field}`}
key={columnConfiguration.fieldColumn.id}
{...columnWidth}
>
{column ? (
<LogEntryFieldColumn
columnValue={column}
highlights={highlightsByColumnId[column.columnId] || []}
isActiveHighlight={isActiveHighlight}
isHighlighted={isHighlighted}
isHovered={isHovered}
isWrapped={wrap}
/>
) : null}
</LogEntryColumn>
);
}
})}
<LogEntryColumn
key="logColumn iconLogColumn iconLogColumn:details"
{...columnWidths[iconColumnId]}
>
<LogEntryDetailsIconColumn
isHighlighted={isHighlighted}
isHovered={isHovered}
openFlyout={openFlyout}
/>
</LogEntryColumn>
</LogEntryRowWrapper>
);
}
);

interface LogEntryRowWrapperProps {
scale: TextScale;
Expand Down