| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  | import { debounce } from 'lodash'; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   createContext, | 
					
						
							|  |  |  |   Dispatch, | 
					
						
							|  |  |  |   ReactNode, | 
					
						
							|  |  |  |   SetStateAction, | 
					
						
							|  |  |  |   useCallback, | 
					
						
							|  |  |  |   useContext, | 
					
						
							|  |  |  |   useEffect, | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  |   useMemo, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   useState, | 
					
						
							|  |  |  | } from 'react'; | 
					
						
							| 
									
										
										
										
											2025-02-28 00:34:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-21 18:07:47 +08:00
										 |  |  | import { createAssistantContextItem, OpenAssistantProps, useAssistant } from '@grafana/assistant'; | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   CoreApp, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   DataFrame, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   LogLevel, | 
					
						
							|  |  |  |   LogRowModel, | 
					
						
							|  |  |  |   LogsDedupStrategy, | 
					
						
							|  |  |  |   LogsMetaItem, | 
					
						
							|  |  |  |   LogsSortOrder, | 
					
						
							|  |  |  |   shallowCompare, | 
					
						
							|  |  |  |   store, | 
					
						
							|  |  |  | } from '@grafana/data'; | 
					
						
							| 
									
										
										
										
											2025-07-23 18:12:47 +08:00
										 |  |  | import { t } from '@grafana/i18n'; | 
					
						
							| 
									
										
										
										
											2025-08-27 01:46:01 +08:00
										 |  |  | import { config, getDataSourceSrv } from '@grafana/runtime'; | 
					
						
							| 
									
										
										
										
											2025-02-28 00:34:02 +08:00
										 |  |  | import { PopoverContent } from '@grafana/ui'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-23 18:12:47 +08:00
										 |  |  | import { checkLogsError, checkLogsSampled, downloadLogs as download, DownloadFormat } from '../../utils'; | 
					
						
							| 
									
										
										
										
											2025-07-16 23:42:14 +08:00
										 |  |  | import { getDisplayedFieldsForLogs } from '../otel/formats'; | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  | import { LogLineTimestampResolution } from './LogLine'; | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  | import { LogLineDetailsMode } from './LogLineDetails'; | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  | import { GetRowContextQueryFn, LogLineMenuCustomItem } from './LogLineMenu'; | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  | import { LogListControlOptions, LogListFontSize } from './LogList'; | 
					
						
							| 
									
										
										
										
											2025-08-27 01:46:01 +08:00
										 |  |  | import { reportInteractionOnce } from './analytics'; | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  | import { LogListModel } from './processing'; | 
					
						
							| 
									
										
										
										
											2025-08-19 03:06:31 +08:00
										 |  |  | import { getScrollbarWidth, LOG_LIST_CONTROLS_WIDTH, LOG_LIST_MIN_WIDTH } from './virtualization'; | 
					
						
							| 
									
										
										
										
											2025-02-28 00:34:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  | export interface LogListContextData extends Omit<Props, 'containerElement' | 'logs' | 'logsMeta' | 'showControls'> { | 
					
						
							|  |  |  |   closeDetails: () => void; | 
					
						
							|  |  |  |   detailsDisplayed: (log: LogListModel) => boolean; | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  |   detailsMode: LogLineDetailsMode; | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   detailsWidth: number; | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   downloadLogs: (format: DownloadFormat) => void; | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   enableLogDetails: boolean; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   filterLevels: LogLevel[]; | 
					
						
							| 
									
										
										
										
											2025-07-17 16:59:03 +08:00
										 |  |  |   forceEscape: boolean; | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  |   hasLogsWithErrors?: boolean; | 
					
						
							|  |  |  |   hasSampledLogs?: boolean; | 
					
						
							| 
									
										
										
										
											2025-07-17 16:59:03 +08:00
										 |  |  |   hasUnescapedContent: boolean; | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  |   logLineMenuCustomItems?: LogLineMenuCustomItem[]; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setDedupStrategy: (dedupStrategy: LogsDedupStrategy) => void; | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  |   setDetailsMode: (mode: LogLineDetailsMode) => void; | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   setDetailsWidth: (width: number) => void; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setFilterLevels: (filterLevels: LogLevel[]) => void; | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   setFontSize: (size: LogListFontSize) => void; | 
					
						
							| 
									
										
										
										
											2025-04-11 02:47:17 +08:00
										 |  |  |   setForceEscape: (forceEscape: boolean) => void; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setLogListState: Dispatch<SetStateAction<LogListState>>; | 
					
						
							|  |  |  |   setPinnedLogs: (pinnedlogs: string[]) => void; | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   setPrettifyJSON: (prettifyJSON: boolean) => void; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setSyntaxHighlighting: (syntaxHighlighting: boolean) => void; | 
					
						
							|  |  |  |   setShowTime: (showTime: boolean) => void; | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   setShowUniqueLabels: (showUniqueLabels: boolean) => void; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setSortOrder: (sortOrder: LogsSortOrder) => void; | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   setTimestampResolution: (format: LogLineTimestampResolution) => void; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setWrapLogMessage: (showTime: boolean) => void; | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   showDetails: LogListModel[]; | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   timestampResolution: LogLineTimestampResolution; | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   toggleDetails: (log: LogListModel) => void; | 
					
						
							| 
									
										
										
										
											2025-07-23 18:12:47 +08:00
										 |  |  |   isAssistantAvailable: boolean; | 
					
						
							|  |  |  |   openAssistantByLog: ((log: LogListModel) => void) | undefined; | 
					
						
							| 
									
										
										
										
											2025-02-28 00:34:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  | export const LogListContext = createContext<LogListContextData>({ | 
					
						
							|  |  |  |   app: CoreApp.Unknown, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   closeDetails: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   dedupStrategy: LogsDedupStrategy.none, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   detailsDisplayed: () => false, | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  |   detailsMode: 'sidebar', | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   detailsWidth: 0, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   displayedFields: [], | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   downloadLogs: () => {}, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   enableLogDetails: false, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   filterLevels: [], | 
					
						
							| 
									
										
										
										
											2025-07-17 16:59:03 +08:00
										 |  |  |   forceEscape: false, | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   fontSize: 'default', | 
					
						
							| 
									
										
										
										
											2025-04-11 02:47:17 +08:00
										 |  |  |   hasUnescapedContent: false, | 
					
						
							| 
									
										
										
										
											2025-07-18 19:13:51 +08:00
										 |  |  |   noInteractions: false, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setDedupStrategy: () => {}, | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  |   setDetailsMode: () => {}, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   setDetailsWidth: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setFilterLevels: () => {}, | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   setFontSize: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-11 02:47:17 +08:00
										 |  |  |   setForceEscape: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setLogListState: () => {}, | 
					
						
							|  |  |  |   setPinnedLogs: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   setPrettifyJSON: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setShowTime: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   setShowUniqueLabels: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setSortOrder: () => {}, | 
					
						
							|  |  |  |   setSyntaxHighlighting: () => {}, | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   setTimestampResolution: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   setWrapLogMessage: () => {}, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   showDetails: [], | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   showTime: true, | 
					
						
							|  |  |  |   sortOrder: LogsSortOrder.Ascending, | 
					
						
							|  |  |  |   syntaxHighlighting: true, | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   timestampResolution: 'ns', | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   toggleDetails: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   wrapLogMessage: false, | 
					
						
							| 
									
										
										
										
											2025-07-23 18:12:47 +08:00
										 |  |  |   isAssistantAvailable: false, | 
					
						
							|  |  |  |   openAssistantByLog: () => {}, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2025-02-28 00:34:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export const useLogListContextData = (key: keyof LogListContextData) => { | 
					
						
							|  |  |  |   const data: LogListContextData = useContext(LogListContext); | 
					
						
							|  |  |  |   return data[key]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const useLogListContext = (): LogListContextData => { | 
					
						
							|  |  |  |   return useContext(LogListContext); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-23 02:12:06 +08:00
										 |  |  | export const useLogIsPinned = (log: LogListModel) => { | 
					
						
							| 
									
										
										
										
											2025-02-28 00:34:02 +08:00
										 |  |  |   const { pinnedLogs } = useContext(LogListContext); | 
					
						
							|  |  |  |   return pinnedLogs?.some((logId) => logId === log.rowId); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-23 02:12:06 +08:00
										 |  |  | export const useLogIsPermalinked = (log: LogListModel) => { | 
					
						
							|  |  |  |   const { permalinkedLogId } = useContext(LogListContext); | 
					
						
							|  |  |  |   return permalinkedLogId && permalinkedLogId === log.uid; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  | export type LogListState = Pick< | 
					
						
							|  |  |  |   LogListContextData, | 
					
						
							|  |  |  |   | 'dedupStrategy' | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   | 'fontSize' | 
					
						
							| 
									
										
										
										
											2025-04-11 02:47:17 +08:00
										 |  |  |   | 'forceEscape' | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   | 'filterLevels' | 
					
						
							|  |  |  |   | 'pinnedLogs' | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   | 'showUniqueLabels' | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   | 'showTime' | 
					
						
							|  |  |  |   | 'sortOrder' | 
					
						
							|  |  |  |   | 'syntaxHighlighting' | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   | 'timestampResolution' | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  | >; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  | export type LogListOption = keyof LogListState | 'wrapLogMessage' | 'prettifyJSON'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  | export interface Props { | 
					
						
							|  |  |  |   app: CoreApp; | 
					
						
							|  |  |  |   children?: ReactNode; | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   // Only ControlledLogRows can send an undefined containerElement. See LogList.tsx
 | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   containerElement?: HTMLDivElement; | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  |   detailsMode?: LogLineDetailsMode; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   dedupStrategy: LogsDedupStrategy; | 
					
						
							|  |  |  |   displayedFields: string[]; | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   enableLogDetails: boolean; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   filterLevels?: LogLevel[]; | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   fontSize: LogListFontSize; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   getRowContextQuery?: GetRowContextQueryFn; | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   isLabelFilterActive?: (key: string, value: string, refId?: string) => Promise<boolean>; | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   logs: LogRowModel[]; | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  |   logLineMenuCustomItems?: LogLineMenuCustomItem[]; | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   logsMeta?: LogsMetaItem[]; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   logOptionsStorageKey?: string; | 
					
						
							|  |  |  |   logSupportsContext?: (row: LogRowModel) => boolean; | 
					
						
							| 
									
										
										
										
											2025-07-18 19:13:51 +08:00
										 |  |  |   noInteractions?: 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-08-28 01:34:14 +08:00
										 |  |  |   onLogOptionsChange?: (option: LogListControlOptions, value: string | boolean | string[]) => void; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   onLogLineHover?: (row?: LogRowModel) => void; | 
					
						
							|  |  |  |   onPermalinkClick?: (row: LogRowModel) => Promise<void>; | 
					
						
							|  |  |  |   onPinLine?: (row: LogRowModel) => void; | 
					
						
							|  |  |  |   onOpenContext?: (row: LogRowModel, onClose: () => void) => void; | 
					
						
							|  |  |  |   onUnpinLine?: (row: LogRowModel) => void; | 
					
						
							| 
									
										
										
										
											2025-05-23 02:12:06 +08:00
										 |  |  |   permalinkedLogId?: string; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   pinLineButtonTooltipTitle?: PopoverContent; | 
					
						
							|  |  |  |   pinnedLogs?: string[]; | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   prettifyJSON?: boolean; | 
					
						
							| 
									
										
										
										
											2025-07-08 17:57:28 +08:00
										 |  |  |   setDisplayedFields?: (displayedFields: string[]) => void; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   showControls: boolean; | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   showUniqueLabels?: boolean; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   showTime: boolean; | 
					
						
							|  |  |  |   sortOrder: LogsSortOrder; | 
					
						
							|  |  |  |   syntaxHighlighting?: boolean; | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   timestampResolution?: LogLineTimestampResolution; | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   wrapLogMessage: boolean; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const LogListContextProvider = ({ | 
					
						
							|  |  |  |   app, | 
					
						
							|  |  |  |   children, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   containerElement, | 
					
						
							|  |  |  |   enableLogDetails, | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  |   detailsMode: detailsModeProp, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   dedupStrategy, | 
					
						
							|  |  |  |   displayedFields, | 
					
						
							| 
									
										
										
										
											2025-04-11 02:47:17 +08:00
										 |  |  |   filterLevels, | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   fontSize, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   isLabelFilterActive, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   getRowContextQuery, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   logs, | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  |   logLineMenuCustomItems, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   logsMeta, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   logOptionsStorageKey, | 
					
						
							|  |  |  |   logSupportsContext, | 
					
						
							| 
									
										
										
										
											2025-07-18 19:13:51 +08:00
										 |  |  |   noInteractions, | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							| 
									
										
										
										
											2025-05-23 02:12:06 +08:00
										 |  |  |   permalinkedLogId, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   pinLineButtonTooltipTitle, | 
					
						
							|  |  |  |   pinnedLogs, | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |   prettifyJSON: prettifyJSONProp = logOptionsStorageKey | 
					
						
							|  |  |  |     ? store.getBool(`${logOptionsStorageKey}.prettifyLogMessage`, true) | 
					
						
							|  |  |  |     : true, | 
					
						
							| 
									
										
										
										
											2025-07-08 17:57:28 +08:00
										 |  |  |   setDisplayedFields, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   showControls, | 
					
						
							|  |  |  |   showTime, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   showUniqueLabels, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   sortOrder, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   syntaxHighlighting, | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   timestampResolution = logOptionsStorageKey | 
					
						
							|  |  |  |     ? (store.get(`${logOptionsStorageKey}.timestampResolution`) ?? 'ms') | 
					
						
							|  |  |  |     : 'ms', | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |   wrapLogMessage: wrapLogMessageProp, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  | }: Props) => { | 
					
						
							|  |  |  |   const [logListState, setLogListState] = useState<LogListState>({ | 
					
						
							|  |  |  |     dedupStrategy, | 
					
						
							|  |  |  |     filterLevels: | 
					
						
							|  |  |  |       filterLevels ?? (logOptionsStorageKey ? store.getObject(`${logOptionsStorageKey}.filterLevels`, []) : []), | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |     fontSize, | 
					
						
							| 
									
										
										
										
											2025-07-17 16:59:03 +08:00
										 |  |  |     forceEscape: logOptionsStorageKey ? store.getBool(`${logOptionsStorageKey}.forceEscape`, false) : false, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |     pinnedLogs, | 
					
						
							|  |  |  |     showTime, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |     showUniqueLabels, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |     sortOrder, | 
					
						
							|  |  |  |     syntaxHighlighting, | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |     timestampResolution, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   const [showDetails, setShowDetails] = useState<LogListModel[]>([]); | 
					
						
							| 
									
										
										
										
											2025-08-19 03:06:31 +08:00
										 |  |  |   const [detailsWidth, setDetailsWidthState] = useState( | 
					
						
							|  |  |  |     getDetailsWidth(containerElement, logOptionsStorageKey, undefined, detailsModeProp, showControls) | 
					
						
							|  |  |  |   ); | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  |   const [detailsMode, setDetailsMode] = useState<LogLineDetailsMode>(detailsModeProp ?? 'sidebar'); | 
					
						
							| 
									
										
										
										
											2025-07-23 18:12:47 +08:00
										 |  |  |   const [isAssistantAvailable, openAssistant] = useAssistant(); | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |   const [prettifyJSON, setPrettifyJSONState] = useState(prettifyJSONProp); | 
					
						
							|  |  |  |   const [wrapLogMessage, setWrapLogMessageState] = useState(wrapLogMessageProp); | 
					
						
							| 
									
										
										
										
											2025-07-23 18:12:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-18 19:13:51 +08:00
										 |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     if (noInteractions) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     reportInteractionOnce(`logs_log_list_${app}_logs_displayed`, { | 
					
						
							|  |  |  |       dedupStrategy, | 
					
						
							|  |  |  |       fontSize, | 
					
						
							|  |  |  |       forceEscape: logListState.forceEscape, | 
					
						
							|  |  |  |       showTime, | 
					
						
							|  |  |  |       syntaxHighlighting, | 
					
						
							|  |  |  |       wrapLogMessage, | 
					
						
							|  |  |  |       detailsWidth, | 
					
						
							|  |  |  |       detailsMode, | 
					
						
							|  |  |  |       withDisplayedFields: displayedFields.length > 0, | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |       timestampResolution: logListState.timestampResolution, | 
					
						
							| 
									
										
										
										
											2025-07-18 19:13:51 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  |     // Just once
 | 
					
						
							|  |  |  |     // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
					
						
							|  |  |  |   }, []); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   // OTel displayed fields
 | 
					
						
							| 
									
										
										
										
											2025-07-16 23:42:14 +08:00
										 |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     if (displayedFields.length > 0 || !config.featureToggles.otelLogsFormatting || !setDisplayedFields) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const otelDisplayedFields = getDisplayedFieldsForLogs(logs); | 
					
						
							|  |  |  |     if (otelDisplayedFields.length) { | 
					
						
							|  |  |  |       setDisplayedFields(otelDisplayedFields); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }, [displayedFields.length, logs, setDisplayedFields]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   // Sync state
 | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     // Props are updated in the context only of the panel is being externally controlled.
 | 
					
						
							|  |  |  |     if (showControls && app !== CoreApp.PanelEditor) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const newState = { | 
					
						
							|  |  |  |       ...logListState, | 
					
						
							|  |  |  |       dedupStrategy, | 
					
						
							|  |  |  |       showTime, | 
					
						
							|  |  |  |       sortOrder, | 
					
						
							|  |  |  |       syntaxHighlighting, | 
					
						
							|  |  |  |       wrapLogMessage, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     if (!shallowCompare(logListState, newState)) { | 
					
						
							|  |  |  |       setLogListState(newState); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }, [ | 
					
						
							|  |  |  |     app, | 
					
						
							|  |  |  |     dedupStrategy, | 
					
						
							|  |  |  |     logListState, | 
					
						
							|  |  |  |     pinnedLogs, | 
					
						
							|  |  |  |     showControls, | 
					
						
							|  |  |  |     showTime, | 
					
						
							|  |  |  |     sortOrder, | 
					
						
							|  |  |  |     syntaxHighlighting, | 
					
						
							|  |  |  |     wrapLogMessage, | 
					
						
							|  |  |  |   ]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   // Sync filter levels
 | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     if (filterLevels === undefined) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-06-23 17:29:30 +08:00
										 |  |  |     setLogListState((logListState) => { | 
					
						
							|  |  |  |       if (!shallowCompare(logListState.filterLevels, filterLevels)) { | 
					
						
							|  |  |  |         return { ...logListState, filterLevels }; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return logListState; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }, [filterLevels]); | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   // Sync font size
 | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     setLogListState((logListState) => ({ ...logListState, fontSize })); | 
					
						
							|  |  |  |   }, [fontSize]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   // Sync pinned logs
 | 
					
						
							| 
									
										
										
										
											2025-05-23 02:12:06 +08:00
										 |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     if (!shallowCompare(logListState.pinnedLogs ?? [], pinnedLogs ?? [])) { | 
					
						
							|  |  |  |       setLogListState({ ...logListState, pinnedLogs }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }, [logListState, pinnedLogs]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   // Sync show details
 | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     if (!showDetails.length) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const newShowDetails = showDetails.filter( | 
					
						
							|  |  |  |       (expandedLog) => logs.findIndex((log) => log.uid === expandedLog.uid) >= 0 | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     if (newShowDetails.length !== showDetails.length) { | 
					
						
							|  |  |  |       setShowDetails(newShowDetails); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }, [logs, showDetails]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-19 03:06:31 +08:00
										 |  |  |   // Sync log details inline and sidebar width
 | 
					
						
							|  |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     setDetailsWidthState(getDetailsWidth(containerElement, logOptionsStorageKey, undefined, detailsMode, showControls)); | 
					
						
							|  |  |  |   }, [containerElement, detailsMode, logOptionsStorageKey, showControls]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   // Sync log details width
 | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   useEffect(() => { | 
					
						
							| 
									
										
										
										
											2025-08-19 03:06:31 +08:00
										 |  |  |     if (!containerElement) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |     const handleResize = debounce(() => { | 
					
						
							| 
									
										
										
										
											2025-08-19 03:06:31 +08:00
										 |  |  |       setDetailsWidthState((detailsWidth) => | 
					
						
							|  |  |  |         getDetailsWidth(containerElement, logOptionsStorageKey, detailsWidth, detailsMode, showControls) | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |     }, 50); | 
					
						
							| 
									
										
										
										
											2025-08-19 03:06:31 +08:00
										 |  |  |     const observer = new ResizeObserver(() => handleResize()); | 
					
						
							|  |  |  |     observer.observe(containerElement); | 
					
						
							|  |  |  |     return () => observer.disconnect(); | 
					
						
							|  |  |  |   }, [containerElement, detailsMode, logOptionsStorageKey, showControls]); | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   // Sync timestamp resolution
 | 
					
						
							|  |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     setLogListState((state) => ({ | 
					
						
							|  |  |  |       ...state, | 
					
						
							|  |  |  |       timestampResolution, | 
					
						
							|  |  |  |     })); | 
					
						
							|  |  |  |   }, [timestampResolution]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   const detailsDisplayed = useCallback( | 
					
						
							|  |  |  |     (log: LogListModel) => !!showDetails.find((shownLog) => shownLog.uid === log.uid), | 
					
						
							|  |  |  |     [showDetails] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   const setDedupStrategy = useCallback( | 
					
						
							|  |  |  |     (dedupStrategy: LogsDedupStrategy) => { | 
					
						
							|  |  |  |       setLogListState({ ...logListState, dedupStrategy }); | 
					
						
							|  |  |  |       onLogOptionsChange?.('dedupStrategy', dedupStrategy); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [logListState, onLogOptionsChange] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   const setFontSize = useCallback( | 
					
						
							|  |  |  |     (fontSize: LogListFontSize) => { | 
					
						
							|  |  |  |       if (logOptionsStorageKey) { | 
					
						
							|  |  |  |         store.set(`${logOptionsStorageKey}.fontSize`, fontSize); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       setLogListState((logListState) => ({ ...logListState, fontSize })); | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |       onLogOptionsChange?.('fontSize', fontSize); | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |     [logOptionsStorageKey, onLogOptionsChange] | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-11 02:47:17 +08:00
										 |  |  |   const setForceEscape = useCallback( | 
					
						
							|  |  |  |     (forceEscape: boolean) => { | 
					
						
							|  |  |  |       setLogListState({ ...logListState, forceEscape }); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [logListState] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   const setFilterLevels = useCallback( | 
					
						
							|  |  |  |     (filterLevels: LogLevel[]) => { | 
					
						
							|  |  |  |       setLogListState({ ...logListState, filterLevels }); | 
					
						
							|  |  |  |       onLogOptionsChange?.('filterLevels', filterLevels); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [logListState, onLogOptionsChange] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const setPinnedLogs = useCallback( | 
					
						
							|  |  |  |     (pinnedLogs: string[]) => { | 
					
						
							|  |  |  |       setLogListState({ ...logListState, pinnedLogs }); | 
					
						
							|  |  |  |       onLogOptionsChange?.('pinnedLogs', pinnedLogs); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [logListState, onLogOptionsChange] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const setShowTime = useCallback( | 
					
						
							|  |  |  |     (showTime: boolean) => { | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |       const newTimestampFormat = showTime === false ? 'ms' : logListState.timestampResolution; | 
					
						
							|  |  |  |       setLogListState({ | 
					
						
							|  |  |  |         ...logListState, | 
					
						
							|  |  |  |         showTime, | 
					
						
							|  |  |  |         timestampResolution: newTimestampFormat, | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |       onLogOptionsChange?.('showTime', showTime); | 
					
						
							|  |  |  |       if (logOptionsStorageKey) { | 
					
						
							|  |  |  |         store.set(`${logOptionsStorageKey}.showTime`, showTime); | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |         store.set(`${logOptionsStorageKey}.timestampResolution`, newTimestampFormat); | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [logListState, logOptionsStorageKey, onLogOptionsChange] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   const setShowUniqueLabels = useCallback( | 
					
						
							|  |  |  |     (showUniqueLabels: boolean) => { | 
					
						
							|  |  |  |       setLogListState({ ...logListState, showUniqueLabels }); | 
					
						
							|  |  |  |       onLogOptionsChange?.('showUniqueLabels', showUniqueLabels); | 
					
						
							|  |  |  |       if (logOptionsStorageKey) { | 
					
						
							|  |  |  |         store.set(`${logOptionsStorageKey}.showLabels`, showUniqueLabels); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [logListState, logOptionsStorageKey, onLogOptionsChange] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const setPrettifyJSON = useCallback( | 
					
						
							|  |  |  |     (prettifyJSON: boolean) => { | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |       setPrettifyJSONState(prettifyJSON); | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |       if (logOptionsStorageKey) { | 
					
						
							|  |  |  |         store.set(`${logOptionsStorageKey}.prettifyLogMessage`, prettifyJSON); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |       onLogOptionsChange?.('prettifyJSON', prettifyJSON); | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |     [logOptionsStorageKey, onLogOptionsChange] | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   const setSyntaxHighlighting = useCallback( | 
					
						
							|  |  |  |     (syntaxHighlighting: boolean) => { | 
					
						
							|  |  |  |       setLogListState({ ...logListState, syntaxHighlighting }); | 
					
						
							|  |  |  |       onLogOptionsChange?.('syntaxHighlighting', syntaxHighlighting); | 
					
						
							|  |  |  |       if (logOptionsStorageKey) { | 
					
						
							|  |  |  |         store.set(`${logOptionsStorageKey}.syntaxHighlighting`, syntaxHighlighting); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [logListState, logOptionsStorageKey, onLogOptionsChange] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const setSortOrder = useCallback( | 
					
						
							|  |  |  |     (sortOrder: LogsSortOrder) => { | 
					
						
							|  |  |  |       setLogListState({ ...logListState, sortOrder }); | 
					
						
							|  |  |  |       onLogOptionsChange?.('sortOrder', sortOrder); | 
					
						
							|  |  |  |       if (logOptionsStorageKey) { | 
					
						
							|  |  |  |         store.set(`${logOptionsStorageKey}.sortOrder`, sortOrder); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [logListState, logOptionsStorageKey, onLogOptionsChange] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const setWrapLogMessage = useCallback( | 
					
						
							|  |  |  |     (wrapLogMessage: boolean) => { | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |       setWrapLogMessageState(wrapLogMessage); | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |       if (logOptionsStorageKey) { | 
					
						
							|  |  |  |         store.set(`${logOptionsStorageKey}.wrapLogMessage`, wrapLogMessage); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |       onLogOptionsChange?.('wrapLogMessage', wrapLogMessage); | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |     [logOptionsStorageKey, onLogOptionsChange] | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |   const downloadLogs = useCallback( | 
					
						
							|  |  |  |     (format: DownloadFormat) => { | 
					
						
							|  |  |  |       const filteredLogs = | 
					
						
							|  |  |  |         logListState.filterLevels.length === 0 | 
					
						
							|  |  |  |           ? logs | 
					
						
							|  |  |  |           : logs.filter((log) => logListState.filterLevels.includes(log.logLevel)); | 
					
						
							|  |  |  |       download(format, filteredLogs, logsMeta); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [logListState.filterLevels, logs, logsMeta] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   const closeDetails = useCallback(() => { | 
					
						
							| 
									
										
										
										
											2025-07-21 19:02:20 +08:00
										 |  |  |     showDetails.forEach((log) => removeDetailsScrollPosition(log)); | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |     setShowDetails([]); | 
					
						
							| 
									
										
										
										
											2025-07-16 00:17:20 +08:00
										 |  |  |   }, [showDetails]); | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const toggleDetails = useCallback( | 
					
						
							|  |  |  |     (log: LogListModel) => { | 
					
						
							|  |  |  |       if (!enableLogDetails) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-07-21 19:02:20 +08:00
										 |  |  |       const found = showDetails.find((stateLog) => stateLog === log || stateLog.uid === log.uid); | 
					
						
							|  |  |  |       if (found) { | 
					
						
							|  |  |  |         removeDetailsScrollPosition(found); | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |         setShowDetails(showDetails.filter((stateLog) => stateLog !== log && stateLog.uid !== log.uid)); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         // Supporting one displayed details for now
 | 
					
						
							| 
									
										
										
										
											2025-07-21 19:02:20 +08:00
										 |  |  |         setShowDetails([...showDetails, log]); | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [enableLogDetails, showDetails] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const setDetailsWidth = useCallback( | 
					
						
							|  |  |  |     (width: number) => { | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |       if (!logOptionsStorageKey || !containerElement) { | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const maxWidth = containerElement.clientWidth - LOG_LIST_MIN_WIDTH; | 
					
						
							|  |  |  |       if (width > maxWidth) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |       store.set(`${logOptionsStorageKey}.detailsWidth`, width); | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |       setDetailsWidthState(width); | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |     [containerElement, logOptionsStorageKey] | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   const setTimestampResolution = useCallback( | 
					
						
							|  |  |  |     (timestampResolution: LogLineTimestampResolution) => { | 
					
						
							|  |  |  |       if (logOptionsStorageKey) { | 
					
						
							|  |  |  |         store.set(`${logOptionsStorageKey}.timestampResolution`, timestampResolution); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       setLogListState((state) => ({ | 
					
						
							|  |  |  |         ...state, | 
					
						
							|  |  |  |         timestampResolution, | 
					
						
							|  |  |  |       })); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [logOptionsStorageKey] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const openAssistantByLog = useCallback( | 
					
						
							|  |  |  |     (log: LogListModel) => { | 
					
						
							|  |  |  |       if (!openAssistant) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       handleOpenAssistant(openAssistant, log); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [openAssistant] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  |   const hasLogsWithErrors = useMemo(() => logs.some((log) => !!checkLogsError(log)), [logs]); | 
					
						
							|  |  |  |   const hasSampledLogs = useMemo(() => logs.some((log) => !!checkLogsSampled(log)), [logs]); | 
					
						
							| 
									
										
										
										
											2025-07-17 16:59:03 +08:00
										 |  |  |   const hasUnescapedContent = useMemo(() => logs.some((r) => r.hasUnescapedContent), [logs]); | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |   return ( | 
					
						
							|  |  |  |     <LogListContext.Provider | 
					
						
							|  |  |  |       value={{ | 
					
						
							|  |  |  |         app, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |         closeDetails, | 
					
						
							|  |  |  |         detailsDisplayed, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         dedupStrategy: logListState.dedupStrategy, | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  |         detailsMode, | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |         detailsWidth, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |         displayedFields, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |         downloadLogs, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |         enableLogDetails, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         filterLevels: logListState.filterLevels, | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |         fontSize: logListState.fontSize, | 
					
						
							| 
									
										
										
										
											2025-04-11 02:47:17 +08:00
										 |  |  |         forceEscape: logListState.forceEscape, | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  |         hasLogsWithErrors, | 
					
						
							|  |  |  |         hasSampledLogs, | 
					
						
							| 
									
										
										
										
											2025-07-17 16:59:03 +08:00
										 |  |  |         hasUnescapedContent, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |         isLabelFilterActive, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         getRowContextQuery, | 
					
						
							|  |  |  |         logSupportsContext, | 
					
						
							| 
									
										
										
										
											2025-06-01 20:29:49 +08:00
										 |  |  |         logLineMenuCustomItems, | 
					
						
							| 
									
										
										
										
											2025-07-08 17:57:28 +08:00
										 |  |  |         logOptionsStorageKey, | 
					
						
							| 
									
										
										
										
											2025-07-18 19:13:51 +08:00
										 |  |  |         noInteractions: noInteractions ?? false, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |         onClickFilterLabel, | 
					
						
							|  |  |  |         onClickFilterOutLabel, | 
					
						
							|  |  |  |         onClickFilterString, | 
					
						
							|  |  |  |         onClickFilterOutString, | 
					
						
							|  |  |  |         onClickShowField, | 
					
						
							|  |  |  |         onClickHideField, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         onLogLineHover, | 
					
						
							|  |  |  |         onPermalinkClick, | 
					
						
							|  |  |  |         onPinLine, | 
					
						
							|  |  |  |         onOpenContext, | 
					
						
							|  |  |  |         onUnpinLine, | 
					
						
							| 
									
										
										
										
											2025-05-23 02:12:06 +08:00
										 |  |  |         permalinkedLogId, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         pinLineButtonTooltipTitle, | 
					
						
							|  |  |  |         pinnedLogs: logListState.pinnedLogs, | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |         prettifyJSON, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         setDedupStrategy, | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  |         setDetailsMode, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |         setDetailsWidth, | 
					
						
							| 
									
										
										
										
											2025-07-08 17:57:28 +08:00
										 |  |  |         setDisplayedFields, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         setFilterLevels, | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |         setFontSize, | 
					
						
							| 
									
										
										
										
											2025-04-11 02:47:17 +08:00
										 |  |  |         setForceEscape, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         setLogListState, | 
					
						
							|  |  |  |         setPinnedLogs, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |         setPrettifyJSON, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         setShowTime, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |         setShowUniqueLabels, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         setSortOrder, | 
					
						
							|  |  |  |         setSyntaxHighlighting, | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |         setTimestampResolution, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         setWrapLogMessage, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |         showDetails, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         showTime: logListState.showTime, | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  |         showUniqueLabels: logListState.showUniqueLabels, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |         sortOrder: logListState.sortOrder, | 
					
						
							|  |  |  |         syntaxHighlighting: logListState.syntaxHighlighting, | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |         timestampResolution: logListState.timestampResolution, | 
					
						
							| 
									
										
										
										
											2025-05-21 01:28:35 +08:00
										 |  |  |         toggleDetails, | 
					
						
							| 
									
										
										
										
											2025-08-28 01:34:14 +08:00
										 |  |  |         wrapLogMessage, | 
					
						
							| 
									
										
										
										
											2025-07-23 18:12:47 +08:00
										 |  |  |         isAssistantAvailable, | 
					
						
							|  |  |  |         openAssistantByLog, | 
					
						
							| 
									
										
										
										
											2025-04-04 20:53:12 +08:00
										 |  |  |       }} | 
					
						
							|  |  |  |     > | 
					
						
							|  |  |  |       {children} | 
					
						
							|  |  |  |     </LogListContext.Provider> | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2025-04-07 22:38:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export function isLogsSortOrder(value: unknown): value is LogsSortOrder { | 
					
						
							|  |  |  |   return value === LogsSortOrder.Ascending || value === LogsSortOrder.Descending; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function isDedupStrategy(value: unknown): value is LogsDedupStrategy { | 
					
						
							|  |  |  |   return ( | 
					
						
							|  |  |  |     value === LogsDedupStrategy.exact || | 
					
						
							|  |  |  |     value === LogsDedupStrategy.none || | 
					
						
							|  |  |  |     value === LogsDedupStrategy.numbers || | 
					
						
							|  |  |  |     value === LogsDedupStrategy.signature | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Only ControlledLogRows can send an undefined containerElement. See LogList.tsx
 | 
					
						
							|  |  |  | function getDetailsWidth( | 
					
						
							|  |  |  |   containerElement: HTMLDivElement | undefined, | 
					
						
							|  |  |  |   logOptionsStorageKey?: string, | 
					
						
							| 
									
										
										
										
											2025-08-19 03:06:31 +08:00
										 |  |  |   currentWidth?: number, | 
					
						
							|  |  |  |   detailsMode: LogLineDetailsMode = 'sidebar', | 
					
						
							|  |  |  |   showControls?: boolean | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  | ) { | 
					
						
							|  |  |  |   if (!containerElement) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-08-19 03:06:31 +08:00
										 |  |  |   if (detailsMode === 'inline') { | 
					
						
							|  |  |  |     return containerElement.clientWidth - getScrollbarWidth() - (showControls ? LOG_LIST_CONTROLS_WIDTH : 0); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  |   const defaultWidth = containerElement.clientWidth * 0.4; | 
					
						
							|  |  |  |   const detailsWidth = | 
					
						
							|  |  |  |     currentWidth || | 
					
						
							| 
									
										
										
										
											2025-07-09 22:07:19 +08:00
										 |  |  |     (logOptionsStorageKey | 
					
						
							|  |  |  |       ? parseInt(store.get(`${logOptionsStorageKey}.detailsWidth`) ?? defaultWidth, 10) | 
					
						
							|  |  |  |       : defaultWidth); | 
					
						
							| 
									
										
										
										
											2025-06-10 17:59:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const maxWidth = containerElement.clientWidth - LOG_LIST_MIN_WIDTH; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // The user might have resized the screen.
 | 
					
						
							|  |  |  |   if (detailsWidth >= containerElement.clientWidth || detailsWidth > maxWidth) { | 
					
						
							|  |  |  |     return currentWidth ?? defaultWidth; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return detailsWidth; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-07-16 00:17:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const detailsScrollMap = new Map<string, number>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function saveDetailsScrollPosition(log: LogListModel, position: number) { | 
					
						
							|  |  |  |   detailsScrollMap.set(log.uid, position); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function getDetailsScrollPosition(log: LogListModel) { | 
					
						
							|  |  |  |   return detailsScrollMap.get(log.uid) ?? 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function removeDetailsScrollPosition(log: LogListModel) { | 
					
						
							|  |  |  |   detailsScrollMap.delete(log.uid); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-07-18 19:13:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  | async function handleOpenAssistant(openAssistant: (props: OpenAssistantProps) => void, log: LogListModel) { | 
					
						
							|  |  |  |   const datasource = await getDataSourceSrv().get(log.datasourceUid); | 
					
						
							|  |  |  |   const context = []; | 
					
						
							|  |  |  |   if (datasource) { | 
					
						
							| 
									
										
										
										
											2025-09-03 21:30:02 +08:00
										 |  |  |     context.push( | 
					
						
							|  |  |  |       createAssistantContextItem('datasource', { | 
					
						
							|  |  |  |         datasourceUid: datasource.uid, | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |   } | 
					
						
							|  |  |  |   openAssistant({ | 
					
						
							| 
									
										
										
										
											2025-09-03 21:30:02 +08:00
										 |  |  |     origin: 'grafana/explain-log-line', | 
					
						
							| 
									
										
										
										
											2025-08-28 17:10:02 +08:00
										 |  |  |     prompt: `${t('logs.log-line-menu.log-line-explainer', 'Explain log line in a concise way')}:
 | 
					
						
							| 
									
										
										
										
											2025-09-03 21:30:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       \`\`\`
 | 
					
						
							|  |  |  | ${log.entry.replaceAll('`', '\\`')} | 
					
						
							|  |  |  |       \`\`\`
 | 
					
						
							|  |  |  |       `,
 | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |     context: [ | 
					
						
							|  |  |  |       ...context, | 
					
						
							| 
									
										
										
										
											2025-08-21 18:07:47 +08:00
										 |  |  |       createAssistantContextItem('structured', { | 
					
						
							| 
									
										
										
										
											2025-08-09 01:13:01 +08:00
										 |  |  |         title: t('logs.log-line-menu.log-line', 'Log line'), | 
					
						
							|  |  |  |         data: { | 
					
						
							|  |  |  |           labels: log.labels, | 
					
						
							|  |  |  |           value: log.entry, | 
					
						
							|  |  |  |           timestamp: log.timestamp, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       }), | 
					
						
							|  |  |  |     ], | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } |