Skip to content

Commit 205c3bd

Browse files
committed
LogLineDetails: add scroll to log line option and improve toggling behavior
1 parent 6f2ac8f commit 205c3bd

File tree

4 files changed

+52
-29
lines changed

4 files changed

+52
-29
lines changed

public/app/features/logs/components/panel/LogLineDetails.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { css } from '@emotion/css';
22
import { Resizable } from 're-resizable';
33
import { memo, useCallback, useEffect, useRef, useState } from 'react';
4+
import { usePrevious } from 'react-use';
45

56
import { GrafanaTheme2 } from '@grafana/data';
67
import { t } from '@grafana/i18n';
@@ -28,25 +29,32 @@ export const LogLineDetails = ({ containerElement, focusLogLine, logs, onResize
2829
const dragStyles = useStyles2(getDragStyles);
2930
const containerRef = useRef<HTMLDivElement | null>(null);
3031
const [currentLog, setCurrentLog] = useState(showDetails[0]);
32+
const previousShowDetails = usePrevious(showDetails);
3133

3234
useEffect(() => {
33-
focusLogLine(showDetails[0]);
35+
focusLogLine(currentLog);
3436
if (!noInteractions) {
3537
reportInteraction('logs_log_line_details_displayed', {
3638
mode: 'sidebar',
3739
});
3840
}
39-
// Just once
40-
// eslint-disable-next-line react-hooks/exhaustive-deps
41+
// Once
42+
// eslint-disable-next-line react-hooks/exhaustive-deps
4143
}, []);
4244

4345
useEffect(() => {
4446
if (!showDetails.length) {
4547
closeDetails();
4648
return;
4749
}
48-
setCurrentLog(showDetails[showDetails.length - 1]);
49-
}, [closeDetails, showDetails]);
50+
// Focus on the recently open
51+
if (!previousShowDetails || showDetails.length > previousShowDetails.length) {
52+
setCurrentLog(showDetails[showDetails.length - 1]);
53+
return;
54+
} else if (!showDetails.find((log) => log.uid === currentLog.uid)) {
55+
setCurrentLog(showDetails[showDetails.length - 1]);
56+
}
57+
}, [closeDetails, currentLog.uid, previousShowDetails, showDetails]);
5058

5159
const handleResize = useCallback(() => {
5260
if (containerRef.current) {
@@ -106,7 +114,7 @@ export const LogLineDetails = ({ containerElement, focusLogLine, logs, onResize
106114
</TabsBar>
107115
)}
108116
<div className={styles.scrollContainer}>
109-
<LogLineDetailsComponent log={currentLog} logs={logs} />
117+
<LogLineDetailsComponent focusLogLine={focusLogLine} log={currentLog} logs={logs} />
110118
</div>
111119
</div>
112120
</Resizable>

public/app/features/logs/components/panel/LogLineDetailsComponent.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ import { useLogListContext } from './LogListContext';
1919
import { LogListModel } from './processing';
2020

2121
interface LogLineDetailsComponentProps {
22+
focusLogLine?: (log: LogListModel) => void;
2223
log: LogListModel;
2324
logs: LogListModel[];
2425
}
2526

26-
export const LogLineDetailsComponent = memo(({ log, logs }: LogLineDetailsComponentProps) => {
27+
export const LogLineDetailsComponent = memo(({ focusLogLine, log, logs }: LogLineDetailsComponentProps) => {
2728
const { displayedFields, noInteractions, logOptionsStorageKey, setDisplayedFields } = useLogListContext();
2829
const [search, setSearch] = useState('');
2930
const inputRef = useRef('');
@@ -101,7 +102,7 @@ export const LogLineDetailsComponent = memo(({ log, logs }: LogLineDetailsCompon
101102

102103
return (
103104
<>
104-
<LogLineDetailsHeader log={log} search={search} onSearch={handleSearch} />
105+
<LogLineDetailsHeader focusLogLine={focusLogLine} log={log} search={search} onSearch={handleSearch} />
105106
<div className={styles.componentWrapper}>
106107
<ControlledCollapse
107108
className={styles.collapsable}

public/app/features/logs/components/panel/LogLineDetailsHeader.tsx

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ import { useLogIsPinned, useLogListContext } from './LogListContext';
1414
import { LogListModel } from './processing';
1515

1616
interface Props {
17+
focusLogLine?: (log: LogListModel) => void;
1718
log: LogListModel;
1819
search: string;
1920
onSearch(newSearch: string): void;
2021
}
2122

22-
export const LogLineDetailsHeader = ({ log, search, onSearch }: Props) => {
23+
export const LogLineDetailsHeader = ({ focusLogLine, log, search, onSearch }: Props) => {
2324
const {
2425
closeDetails,
2526
detailsMode,
@@ -53,6 +54,10 @@ export const LogLineDetailsHeader = ({ log, search, onSearch }: Props) => {
5354
[noInteractions]
5455
);
5556

57+
const scrollToLogLine = useCallback(() => {
58+
focusLogLine?.(log);
59+
}, [focusLogLine, log]);
60+
5661
const copyLogLine = useCallback(() => {
5762
copyText(log.entry, containerRef);
5863
reportInteractionWrapper('logs_log_line_details_header_copy_clicked');
@@ -143,22 +148,32 @@ export const LogLineDetailsHeader = ({ log, search, onSearch }: Props) => {
143148
ref={inputRef}
144149
suffix={search !== '' ? clearSearch : undefined}
145150
/>
146-
{showLogLineToggle && (
147-
<IconButton
148-
tooltip={
149-
logLineDisplayed
150-
? t('logs.log-line-details.hide-log-line', 'Hide log line')
151-
: t('logs.log-line-details.show-log-line', 'Show log line')
152-
}
153-
tooltipPlacement="top"
154-
size="md"
155-
name="eye"
156-
onClick={toggleLogLine}
157-
tabIndex={0}
158-
variant={logLineDisplayed ? 'primary' : undefined}
159-
/>
160-
)}
161151
<div className={styles.icons}>
152+
{focusLogLine && (
153+
<IconButton
154+
tooltip={t('logs.log-line-details.scroll-to-logline', 'Scroll to log line')}
155+
tooltipPlacement="top"
156+
size="md"
157+
name="arrows-v"
158+
onClick={scrollToLogLine}
159+
tabIndex={0}
160+
/>
161+
)}
162+
{showLogLineToggle && (
163+
<IconButton
164+
tooltip={
165+
logLineDisplayed
166+
? t('logs.log-line-details.hide-log-line', 'Hide log line')
167+
: t('logs.log-line-details.show-log-line', 'Show log line')
168+
}
169+
tooltipPlacement="top"
170+
size="md"
171+
name="eye"
172+
onClick={toggleLogLine}
173+
tabIndex={0}
174+
variant={logLineDisplayed ? 'primary' : undefined}
175+
/>
176+
)}
162177
<IconButton
163178
tooltip={t('logs.log-line-details.copy-to-clipboard', 'Copy to clipboard')}
164179
tooltipPlacement="top"

public/app/features/logs/components/panel/LogListContext.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,7 @@ export const LogListContextProvider = ({
466466
);
467467

468468
const closeDetails = useCallback(() => {
469-
if (showDetails.length) {
470-
removeDetailsScrollPosition(showDetails[0]);
471-
}
469+
showDetails.forEach((log) => removeDetailsScrollPosition(log));
472470
setShowDetails([]);
473471
}, [showDetails]);
474472

@@ -477,8 +475,9 @@ export const LogListContextProvider = ({
477475
if (!enableLogDetails) {
478476
return;
479477
}
480-
const found = showDetails.findIndex((stateLog) => stateLog === log || stateLog.uid === log.uid);
481-
if (found >= 0) {
478+
const found = showDetails.find((stateLog) => stateLog === log || stateLog.uid === log.uid);
479+
if (found) {
480+
removeDetailsScrollPosition(found);
482481
setShowDetails(showDetails.filter((stateLog) => stateLog !== log && stateLog.uid !== log.uid));
483482
} else {
484483
// Supporting one displayed details for now

0 commit comments

Comments
 (0)