2025-02-27 18:31:55 +08:00
|
|
|
import { css } from '@emotion/css';
|
2025-02-05 01:40:17 +08:00
|
|
|
import { debounce } from 'lodash';
|
2025-04-04 20:53:12 +08:00
|
|
|
import { Grammar } from 'prismjs';
|
2025-02-27 18:31:55 +08:00
|
|
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
2025-02-14 19:52:34 +08:00
|
|
|
import { VariableSizeList } from 'react-window';
|
2025-02-05 01:40:17 +08:00
|
|
|
|
2025-02-27 18:31:55 +08:00
|
|
|
import {
|
|
|
|
AbsoluteTimeRange,
|
|
|
|
CoreApp,
|
2025-05-21 01:28:35 +08:00
|
|
|
DataFrame,
|
2025-02-27 18:31:55 +08:00
|
|
|
EventBus,
|
2025-04-04 20:53:12 +08:00
|
|
|
EventBusSrv,
|
|
|
|
LogLevel,
|
2025-02-27 18:31:55 +08:00
|
|
|
LogRowModel,
|
2025-04-04 20:53:12 +08:00
|
|
|
LogsDedupStrategy,
|
2025-04-07 22:38:55 +08:00
|
|
|
LogsMetaItem,
|
2025-02-27 18:31:55 +08:00
|
|
|
LogsSortOrder,
|
2025-04-07 22:38:55 +08:00
|
|
|
store,
|
2025-02-27 18:31:55 +08:00
|
|
|
TimeRange,
|
|
|
|
} from '@grafana/data';
|
2025-02-28 00:34:02 +08:00
|
|
|
import { PopoverContent, useTheme2 } from '@grafana/ui';
|
2025-04-15 22:08:29 +08:00
|
|
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
2025-02-05 01:40:17 +08:00
|
|
|
|
2025-02-14 19:52:34 +08:00
|
|
|
import { InfiniteScroll } from './InfiniteScroll';
|
2025-02-27 18:31:55 +08:00
|
|
|
import { getGridTemplateColumns } from './LogLine';
|
2025-05-21 01:28:35 +08:00
|
|
|
import { LogLineDetails } from './LogLineDetails';
|
2025-02-28 00:34:02 +08:00
|
|
|
import { GetRowContextQueryFn } from './LogLineMenu';
|
2025-04-04 20:53:12 +08:00
|
|
|
import { LogListContextProvider, LogListState, useLogListContext } from './LogListContext';
|
|
|
|
import { LogListControls } from './LogListControls';
|
2025-03-26 19:48:26 +08:00
|
|
|
import { preProcessLogs, LogListModel } from './processing';
|
2025-02-05 01:40:17 +08:00
|
|
|
import {
|
2025-03-26 19:48:26 +08:00
|
|
|
calculateFieldDimensions,
|
2025-02-05 01:40:17 +08:00
|
|
|
getLogLineSize,
|
|
|
|
init as initVirtualization,
|
2025-03-26 19:48:26 +08:00
|
|
|
LogFieldDimension,
|
2025-02-05 01:40:17 +08:00
|
|
|
resetLogLineSizes,
|
|
|
|
ScrollToLogsEvent,
|
|
|
|
storeLogLineSize,
|
|
|
|
} from './virtualization';
|
|
|
|
|
2025-05-21 01:28:35 +08:00
|
|
|
export interface Props {
|
2025-02-05 01:40:17 +08:00
|
|
|
app: CoreApp;
|
|
|
|
containerElement: HTMLDivElement;
|
2025-04-04 20:53:12 +08:00
|
|
|
dedupStrategy: LogsDedupStrategy;
|
2025-02-27 18:31:55 +08:00
|
|
|
displayedFields: string[];
|
2025-05-21 01:28:35 +08:00
|
|
|
enableLogDetails: boolean;
|
2025-04-04 20:53:12 +08:00
|
|
|
eventBus?: EventBus;
|
|
|
|
filterLevels?: LogLevel[];
|
2025-02-27 18:31:55 +08:00
|
|
|
getFieldLinks?: GetFieldLinksFn;
|
2025-02-28 00:34:02 +08:00
|
|
|
getRowContextQuery?: GetRowContextQueryFn;
|
2025-04-04 20:53:12 +08:00
|
|
|
grammar?: Grammar;
|
2025-02-14 19:52:34 +08:00
|
|
|
initialScrollPosition?: 'top' | 'bottom';
|
2025-05-21 01:28:35 +08:00
|
|
|
isLabelFilterActive?: (key: string, value: string, refId?: string) => Promise<boolean>;
|
2025-05-07 06:26:54 +08:00
|
|
|
loading?: boolean;
|
2025-02-14 19:52:34 +08:00
|
|
|
loadMore?: (range: AbsoluteTimeRange) => void;
|
2025-04-04 20:53:12 +08:00
|
|
|
logOptionsStorageKey?: string;
|
2025-02-27 18:31:55 +08:00
|
|
|
logs: LogRowModel[];
|
2025-04-07 22:38:55 +08:00
|
|
|
logsMeta?: LogsMetaItem[];
|
2025-02-28 00:34:02 +08:00
|
|
|
logSupportsContext?: (row: LogRowModel) => boolean;
|
2025-05-21 01:28:35 +08:00
|
|
|
onClickFilterLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
|
|
|
onClickFilterOutLabel?: (key: string, value: string, frame?: DataFrame) => void;
|
|
|
|
onClickFilterString?: (value: string, refId?: string) => void;
|
|
|
|
onClickFilterOutString?: (value: string, refId?: string) => void;
|
|
|
|
onClickShowField?: (key: string) => void;
|
|
|
|
onClickHideField?: (key: string) => void;
|
2025-04-04 20:53:12 +08:00
|
|
|
onLogOptionsChange?: (option: keyof LogListControlOptions, value: string | boolean | string[]) => void;
|
|
|
|
onLogLineHover?: (row?: LogRowModel) => void;
|
2025-02-28 00:34:02 +08:00
|
|
|
onPermalinkClick?: (row: LogRowModel) => Promise<void>;
|
|
|
|
onPinLine?: (row: LogRowModel) => void;
|
|
|
|
onOpenContext?: (row: LogRowModel, onClose: () => void) => void;
|
|
|
|
onUnpinLine?: (row: LogRowModel) => void;
|
|
|
|
pinLineButtonTooltipTitle?: PopoverContent;
|
|
|
|
pinnedLogs?: string[];
|
2025-04-04 20:53:12 +08:00
|
|
|
showControls: boolean;
|
2025-02-05 01:40:17 +08:00
|
|
|
showTime: boolean;
|
|
|
|
sortOrder: LogsSortOrder;
|
2025-02-14 19:52:34 +08:00
|
|
|
timeRange: TimeRange;
|
2025-02-05 01:40:17 +08:00
|
|
|
timeZone: string;
|
2025-04-04 20:53:12 +08:00
|
|
|
syntaxHighlighting?: boolean;
|
2025-02-05 01:40:17 +08:00
|
|
|
wrapLogMessage: boolean;
|
|
|
|
}
|
|
|
|
|
2025-04-04 20:53:12 +08:00
|
|
|
export type LogListControlOptions = LogListState;
|
|
|
|
|
|
|
|
type LogListComponentProps = Omit<
|
|
|
|
Props,
|
2025-05-21 01:28:35 +08:00
|
|
|
| 'app'
|
|
|
|
| 'dedupStrategy'
|
|
|
|
| 'displayedFields'
|
|
|
|
| 'enableLogDetails'
|
|
|
|
| 'showTime'
|
|
|
|
| 'sortOrder'
|
|
|
|
| 'syntaxHighlighting'
|
|
|
|
| 'wrapLogMessage'
|
2025-04-04 20:53:12 +08:00
|
|
|
>;
|
|
|
|
|
2025-02-05 01:40:17 +08:00
|
|
|
export const LogList = ({
|
|
|
|
app,
|
2025-04-04 20:53:12 +08:00
|
|
|
displayedFields,
|
2025-02-05 01:40:17 +08:00
|
|
|
containerElement,
|
2025-04-04 20:53:12 +08:00
|
|
|
dedupStrategy,
|
2025-05-21 01:28:35 +08:00
|
|
|
enableLogDetails,
|
2025-02-05 01:40:17 +08:00
|
|
|
eventBus,
|
2025-04-04 20:53:12 +08:00
|
|
|
filterLevels,
|
2025-02-27 18:31:55 +08:00
|
|
|
getFieldLinks,
|
2025-04-04 20:53:12 +08:00
|
|
|
getRowContextQuery,
|
|
|
|
grammar,
|
2025-02-14 19:52:34 +08:00
|
|
|
initialScrollPosition = 'top',
|
2025-05-21 01:28:35 +08:00
|
|
|
isLabelFilterActive,
|
2025-05-07 06:26:54 +08:00
|
|
|
loading,
|
2025-02-14 19:52:34 +08:00
|
|
|
loadMore,
|
2025-04-04 20:53:12 +08:00
|
|
|
logOptionsStorageKey,
|
2025-02-14 19:52:34 +08:00
|
|
|
logs,
|
2025-04-07 22:38:55 +08:00
|
|
|
logsMeta,
|
2025-04-04 20:53:12 +08:00
|
|
|
logSupportsContext,
|
2025-05-21 01:28:35 +08:00
|
|
|
onClickFilterLabel,
|
|
|
|
onClickFilterOutLabel,
|
|
|
|
onClickFilterString,
|
|
|
|
onClickFilterOutString,
|
|
|
|
onClickShowField,
|
|
|
|
onClickHideField,
|
2025-04-04 20:53:12 +08:00
|
|
|
onLogOptionsChange,
|
|
|
|
onLogLineHover,
|
|
|
|
onPermalinkClick,
|
|
|
|
onPinLine,
|
|
|
|
onOpenContext,
|
|
|
|
onUnpinLine,
|
|
|
|
pinLineButtonTooltipTitle,
|
|
|
|
pinnedLogs,
|
|
|
|
showControls,
|
2025-02-05 01:40:17 +08:00
|
|
|
showTime,
|
|
|
|
sortOrder,
|
2025-04-07 22:38:55 +08:00
|
|
|
syntaxHighlighting = logOptionsStorageKey ? store.getBool(`${logOptionsStorageKey}.syntaxHighlighting`, true) : true,
|
2025-02-14 19:52:34 +08:00
|
|
|
timeRange,
|
2025-02-05 01:40:17 +08:00
|
|
|
timeZone,
|
|
|
|
wrapLogMessage,
|
|
|
|
}: Props) => {
|
2025-04-04 20:53:12 +08:00
|
|
|
return (
|
|
|
|
<LogListContextProvider
|
|
|
|
app={app}
|
2025-05-21 01:28:35 +08:00
|
|
|
containerElement={containerElement}
|
2025-04-04 20:53:12 +08:00
|
|
|
dedupStrategy={dedupStrategy}
|
|
|
|
displayedFields={displayedFields}
|
2025-05-21 01:28:35 +08:00
|
|
|
enableLogDetails={enableLogDetails}
|
2025-04-04 20:53:12 +08:00
|
|
|
filterLevels={filterLevels}
|
|
|
|
getRowContextQuery={getRowContextQuery}
|
2025-05-21 01:28:35 +08:00
|
|
|
isLabelFilterActive={isLabelFilterActive}
|
2025-04-07 22:38:55 +08:00
|
|
|
logs={logs}
|
|
|
|
logsMeta={logsMeta}
|
2025-04-04 20:53:12 +08:00
|
|
|
logOptionsStorageKey={logOptionsStorageKey}
|
|
|
|
logSupportsContext={logSupportsContext}
|
2025-05-21 01:28:35 +08:00
|
|
|
onClickFilterLabel={onClickFilterLabel}
|
|
|
|
onClickFilterOutLabel={onClickFilterOutLabel}
|
|
|
|
onClickFilterString={onClickFilterString}
|
|
|
|
onClickFilterOutString={onClickFilterOutString}
|
|
|
|
onClickShowField={onClickShowField}
|
|
|
|
onClickHideField={onClickHideField}
|
2025-04-04 20:53:12 +08:00
|
|
|
onLogOptionsChange={onLogOptionsChange}
|
|
|
|
onLogLineHover={onLogLineHover}
|
|
|
|
onPermalinkClick={onPermalinkClick}
|
|
|
|
onPinLine={onPinLine}
|
|
|
|
onOpenContext={onOpenContext}
|
|
|
|
onUnpinLine={onUnpinLine}
|
|
|
|
pinLineButtonTooltipTitle={pinLineButtonTooltipTitle}
|
|
|
|
pinnedLogs={pinnedLogs}
|
|
|
|
showControls={showControls}
|
|
|
|
showTime={showTime}
|
|
|
|
sortOrder={sortOrder}
|
|
|
|
syntaxHighlighting={syntaxHighlighting}
|
|
|
|
wrapLogMessage={wrapLogMessage}
|
|
|
|
>
|
|
|
|
<LogListComponent
|
|
|
|
containerElement={containerElement}
|
|
|
|
eventBus={eventBus}
|
|
|
|
getFieldLinks={getFieldLinks}
|
|
|
|
grammar={grammar}
|
|
|
|
initialScrollPosition={initialScrollPosition}
|
2025-05-07 06:26:54 +08:00
|
|
|
loading={loading}
|
2025-04-04 20:53:12 +08:00
|
|
|
loadMore={loadMore}
|
|
|
|
logs={logs}
|
|
|
|
showControls={showControls}
|
|
|
|
timeRange={timeRange}
|
|
|
|
timeZone={timeZone}
|
|
|
|
/>
|
|
|
|
</LogListContextProvider>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const LogListComponent = ({
|
|
|
|
containerElement,
|
|
|
|
eventBus = new EventBusSrv(),
|
|
|
|
getFieldLinks,
|
|
|
|
grammar,
|
|
|
|
initialScrollPosition = 'top',
|
2025-05-07 06:26:54 +08:00
|
|
|
loading,
|
2025-04-04 20:53:12 +08:00
|
|
|
loadMore,
|
|
|
|
logs,
|
|
|
|
showControls,
|
|
|
|
timeRange,
|
|
|
|
timeZone,
|
|
|
|
}: LogListComponentProps) => {
|
2025-05-21 01:28:35 +08:00
|
|
|
const {
|
|
|
|
app,
|
|
|
|
displayedFields,
|
|
|
|
dedupStrategy,
|
|
|
|
filterLevels,
|
|
|
|
forceEscape,
|
|
|
|
showDetails,
|
|
|
|
showTime,
|
|
|
|
sortOrder,
|
|
|
|
toggleDetails,
|
|
|
|
wrapLogMessage,
|
|
|
|
} = useLogListContext();
|
2025-02-14 19:52:34 +08:00
|
|
|
const [processedLogs, setProcessedLogs] = useState<LogListModel[]>([]);
|
2025-02-05 01:40:17 +08:00
|
|
|
const [listHeight, setListHeight] = useState(
|
|
|
|
app === CoreApp.Explore ? window.innerHeight * 0.75 : containerElement.clientHeight
|
|
|
|
);
|
|
|
|
const theme = useTheme2();
|
|
|
|
const listRef = useRef<VariableSizeList | null>(null);
|
|
|
|
const widthRef = useRef(containerElement.clientWidth);
|
2025-05-21 01:28:35 +08:00
|
|
|
const wrapperRef = useRef<HTMLDivElement | null>(null);
|
2025-02-14 19:52:34 +08:00
|
|
|
const scrollRef = useRef<HTMLDivElement | null>(null);
|
2025-02-27 18:31:55 +08:00
|
|
|
const dimensions = useMemo(
|
|
|
|
() => (wrapLogMessage ? [] : calculateFieldDimensions(processedLogs, displayedFields)),
|
|
|
|
[displayedFields, processedLogs, wrapLogMessage]
|
|
|
|
);
|
|
|
|
const styles = getStyles(dimensions, { showTime });
|
2025-05-21 01:28:35 +08:00
|
|
|
const widthContainer = wrapperRef.current ?? containerElement;
|
|
|
|
|
|
|
|
const debouncedResetAfterIndex = useMemo(() => {
|
|
|
|
return debounce((index: number) => {
|
|
|
|
listRef.current?.resetAfterIndex(index);
|
|
|
|
overflowIndexRef.current = Infinity;
|
|
|
|
}, 25);
|
|
|
|
}, []);
|
2025-02-05 01:40:17 +08:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
initVirtualization(theme);
|
|
|
|
}, [theme]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
2025-02-14 19:52:34 +08:00
|
|
|
const subscription = eventBus.subscribe(ScrollToLogsEvent, (e: ScrollToLogsEvent) =>
|
|
|
|
handleScrollToEvent(e, logs.length, listRef.current)
|
|
|
|
);
|
2025-02-05 01:40:17 +08:00
|
|
|
return () => subscription.unsubscribe();
|
2025-02-14 19:52:34 +08:00
|
|
|
}, [eventBus, logs.length]);
|
2025-02-05 01:40:17 +08:00
|
|
|
|
|
|
|
useEffect(() => {
|
2025-05-07 06:26:54 +08:00
|
|
|
if (loading) {
|
|
|
|
return;
|
|
|
|
}
|
2025-04-11 02:47:17 +08:00
|
|
|
setProcessedLogs(
|
|
|
|
preProcessLogs(logs, { getFieldLinks, escape: forceEscape ?? false, order: sortOrder, timeZone }, grammar)
|
|
|
|
);
|
2025-05-07 06:26:54 +08:00
|
|
|
resetLogLineSizes();
|
|
|
|
listRef.current?.resetAfterIndex(0);
|
|
|
|
}, [forceEscape, getFieldLinks, grammar, loading, logs, sortOrder, timeZone]);
|
2025-03-26 19:48:26 +08:00
|
|
|
|
|
|
|
useEffect(() => {
|
2025-02-05 01:40:17 +08:00
|
|
|
listRef.current?.resetAfterIndex(0);
|
2025-05-21 01:28:35 +08:00
|
|
|
}, [wrapLogMessage, showDetails, displayedFields]);
|
2025-02-05 01:40:17 +08:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const handleResize = debounce(() => {
|
|
|
|
setListHeight(app === CoreApp.Explore ? window.innerHeight * 0.75 : containerElement.clientHeight);
|
|
|
|
}, 50);
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
handleResize();
|
|
|
|
return () => {
|
|
|
|
window.removeEventListener('resize', handleResize);
|
|
|
|
};
|
|
|
|
}, [app, containerElement.clientHeight]);
|
|
|
|
|
|
|
|
useLayoutEffect(() => {
|
2025-05-21 01:28:35 +08:00
|
|
|
if (widthRef.current === widthContainer.clientWidth) {
|
2025-02-05 01:40:17 +08:00
|
|
|
return;
|
|
|
|
}
|
2025-05-21 01:28:35 +08:00
|
|
|
widthRef.current = widthContainer.clientWidth;
|
|
|
|
debouncedResetAfterIndex(0);
|
2025-02-05 01:40:17 +08:00
|
|
|
});
|
|
|
|
|
2025-05-21 01:28:35 +08:00
|
|
|
const overflowIndexRef = useRef(Infinity);
|
2025-02-05 01:40:17 +08:00
|
|
|
const handleOverflow = useCallback(
|
2025-05-07 06:26:54 +08:00
|
|
|
(index: number, id: string, height?: number) => {
|
2025-05-21 01:28:35 +08:00
|
|
|
if (height !== undefined) {
|
|
|
|
storeLogLineSize(id, widthContainer, height);
|
2025-02-05 01:40:17 +08:00
|
|
|
}
|
2025-05-21 01:28:35 +08:00
|
|
|
overflowIndexRef.current = index < overflowIndexRef.current ? index : overflowIndexRef.current;
|
|
|
|
debouncedResetAfterIndex(overflowIndexRef.current);
|
2025-02-05 01:40:17 +08:00
|
|
|
},
|
2025-05-21 01:28:35 +08:00
|
|
|
[debouncedResetAfterIndex, widthContainer]
|
2025-02-05 01:40:17 +08:00
|
|
|
);
|
|
|
|
|
2025-02-14 19:52:34 +08:00
|
|
|
const handleScrollPosition = useCallback(() => {
|
|
|
|
listRef.current?.scrollToItem(initialScrollPosition === 'top' ? 0 : logs.length - 1);
|
|
|
|
}, [initialScrollPosition, logs.length]);
|
2025-02-05 01:40:17 +08:00
|
|
|
|
|
|
|
if (!containerElement || listHeight == null) {
|
|
|
|
// Wait for container to be rendered
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2025-05-21 01:28:35 +08:00
|
|
|
const handleLogLineClick = useCallback(
|
|
|
|
(log: LogListModel) => {
|
|
|
|
toggleDetails(log);
|
|
|
|
},
|
|
|
|
[toggleDetails]
|
|
|
|
);
|
|
|
|
|
|
|
|
const handleLogDetailsResize = useCallback(() => {
|
|
|
|
debouncedResetAfterIndex(0);
|
|
|
|
}, [debouncedResetAfterIndex]);
|
|
|
|
|
2025-04-04 20:53:12 +08:00
|
|
|
const filteredLogs = useMemo(
|
|
|
|
() =>
|
|
|
|
filterLevels.length === 0 ? processedLogs : processedLogs.filter((log) => filterLevels.includes(log.logLevel)),
|
|
|
|
[filterLevels, processedLogs]
|
|
|
|
);
|
|
|
|
|
2025-02-05 01:40:17 +08:00
|
|
|
return (
|
2025-04-04 20:53:12 +08:00
|
|
|
<div className={styles.logListContainer}>
|
2025-05-21 01:28:35 +08:00
|
|
|
<div className={styles.logListWrapper} ref={wrapperRef}>
|
|
|
|
<InfiniteScroll
|
|
|
|
displayedFields={displayedFields}
|
|
|
|
handleOverflow={handleOverflow}
|
|
|
|
logs={filteredLogs}
|
|
|
|
loadMore={loadMore}
|
|
|
|
onClick={handleLogLineClick}
|
|
|
|
scrollElement={scrollRef.current}
|
|
|
|
showTime={showTime}
|
|
|
|
sortOrder={sortOrder}
|
|
|
|
timeRange={timeRange}
|
|
|
|
timeZone={timeZone}
|
|
|
|
setInitialScrollPosition={handleScrollPosition}
|
|
|
|
wrapLogMessage={wrapLogMessage}
|
|
|
|
>
|
|
|
|
{({ getItemKey, itemCount, onItemsRendered, Renderer }) => (
|
|
|
|
<VariableSizeList
|
|
|
|
className={styles.logList}
|
|
|
|
height={listHeight}
|
|
|
|
itemCount={itemCount}
|
|
|
|
itemSize={getLogLineSize.bind(null, filteredLogs, widthContainer, displayedFields, {
|
|
|
|
showDuplicates: dedupStrategy !== LogsDedupStrategy.none,
|
|
|
|
showTime,
|
|
|
|
wrap: wrapLogMessage,
|
|
|
|
})}
|
|
|
|
itemKey={getItemKey}
|
|
|
|
layout="vertical"
|
|
|
|
onItemsRendered={onItemsRendered}
|
|
|
|
outerRef={scrollRef}
|
|
|
|
ref={listRef}
|
|
|
|
style={{ overflowY: 'scroll' }}
|
|
|
|
width="100%"
|
|
|
|
>
|
|
|
|
{Renderer}
|
|
|
|
</VariableSizeList>
|
|
|
|
)}
|
|
|
|
</InfiniteScroll>
|
|
|
|
</div>
|
|
|
|
{showDetails.length > 0 && (
|
|
|
|
<LogLineDetails
|
|
|
|
containerElement={containerElement}
|
|
|
|
getFieldLinks={getFieldLinks}
|
|
|
|
logs={filteredLogs}
|
|
|
|
onResize={handleLogDetailsResize}
|
|
|
|
/>
|
|
|
|
)}
|
2025-04-04 20:53:12 +08:00
|
|
|
{showControls && <LogListControls eventBus={eventBus} />}
|
|
|
|
</div>
|
2025-02-05 01:40:17 +08:00
|
|
|
);
|
|
|
|
};
|
2025-02-14 19:52:34 +08:00
|
|
|
|
2025-02-27 18:31:55 +08:00
|
|
|
function getStyles(dimensions: LogFieldDimension[], { showTime }: { showTime: boolean }) {
|
|
|
|
const columns = showTime ? dimensions : dimensions.filter((_, index) => index > 0);
|
|
|
|
return {
|
|
|
|
logList: css({
|
|
|
|
'& .unwrapped-log-line': {
|
|
|
|
display: 'grid',
|
|
|
|
gridTemplateColumns: getGridTemplateColumns(columns),
|
|
|
|
},
|
|
|
|
}),
|
2025-04-04 20:53:12 +08:00
|
|
|
logListContainer: css({
|
|
|
|
display: 'flex',
|
|
|
|
}),
|
2025-05-21 01:28:35 +08:00
|
|
|
logListWrapper: css({
|
|
|
|
width: '100%',
|
|
|
|
}),
|
2025-02-27 18:31:55 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2025-02-14 19:52:34 +08:00
|
|
|
function handleScrollToEvent(event: ScrollToLogsEvent, logsCount: number, list: VariableSizeList | null) {
|
|
|
|
if (event.payload.scrollTo === 'top') {
|
|
|
|
list?.scrollTo(0);
|
|
|
|
} else {
|
|
|
|
list?.scrollToItem(logsCount - 1);
|
|
|
|
}
|
|
|
|
}
|