Skip to content

Commit b098448

Browse files
authored
Implemented showing timestamp for logs (#2937)
* Implemented showing timestamp for logs * Implemented showing timestamp for logs * Implemented showing timestamp for logs. Fixes after review
1 parent a59a1a3 commit b098448

File tree

3 files changed

+111
-16
lines changed

3 files changed

+111
-16
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React, { useEffect, useRef, useState } from 'react';
2+
import cn from 'classnames';
3+
4+
import { Icon } from 'components';
5+
6+
import styles from '../../styles.module.scss';
7+
8+
export const LogRow: React.FC<{
9+
logItem: ILogItem;
10+
isShowTimestamp?: boolean;
11+
}> = ({ logItem, isShowTimestamp }) => {
12+
const [collapsed, setCollapsed] = useState(true);
13+
const [showChevron, setShowChevron] = useState(true);
14+
const messageInnerRef = useRef(null);
15+
16+
const toggleCollapsed = () => setCollapsed((val) => !val);
17+
18+
useEffect(() => {
19+
const observeTarget = messageInnerRef.current;
20+
if (!observeTarget) return;
21+
22+
const resizeObserver = new ResizeObserver((entries) => {
23+
const entry = entries[0];
24+
if (entry) {
25+
const { height } = entry.contentRect;
26+
27+
setShowChevron(height > 32);
28+
}
29+
});
30+
31+
resizeObserver.observe(observeTarget);
32+
33+
return () => {
34+
resizeObserver.unobserve(observeTarget);
35+
};
36+
}, []);
37+
38+
return (
39+
<tr className={styles.logItem}>
40+
{isShowTimestamp && (
41+
<td className={styles.timestamp}>
42+
<span className={cn(styles.toggleCollapse, { [styles.hidden]: !showChevron })} onClick={toggleCollapsed}>
43+
<Icon name={collapsed ? 'caret-right-filled' : 'caret-down-filled'} />
44+
</span>{' '}
45+
{new Date(logItem.timestamp).toISOString()}
46+
</td>
47+
)}
48+
<td className={styles.messageCol}>
49+
<div className={cn(styles.message, { [styles.collapsed]: collapsed && isShowTimestamp })}>
50+
<div ref={messageInnerRef} className={styles.messageInner}>
51+
{logItem.message}
52+
</div>
53+
</div>
54+
</td>
55+
</tr>
56+
);
57+
};

frontend/src/pages/Runs/Details/Logs/index.tsx

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Box, Button, Code, Container, Header, ListEmptyMessage, Loader, TextCon
77
import { useLocalStorageState } from 'hooks/useLocalStorageState';
88
import { useLazyGetProjectLogsQuery } from 'services/project';
99

10+
import { LogRow } from './components/LogRow';
1011
import { decodeLogs } from './helpers';
1112

1213
import { IProps } from './types';
@@ -27,7 +28,7 @@ export const Logs: React.FC<IProps> = ({ className, projectName, runName, jobSub
2728
const [isLoading, setIsLoading] = useState(false);
2829
const [getProjectLogs] = useLazyGetProjectLogsQuery();
2930
const [isEnabledDecoding, setIsEnabledDecoding] = useLocalStorageState('enable-encode-logs', false);
30-
// const [isShowTimestamp, setIsShowTimestamp] = useLocalStorageState('enable-showing-timestamp-logs', false);
31+
const [isShowTimestamp, setIsShowTimestamp] = useLocalStorageState('enable-showing-timestamp-logs', false);
3132

3233
const logsForView = useMemo(() => {
3334
if (isEnabledDecoding) {
@@ -105,6 +106,10 @@ export const Logs: React.FC<IProps> = ({ className, projectName, runName, jobSub
105106
setIsEnabledDecoding(!isEnabledDecoding);
106107
};
107108

109+
const toggleShowingTimestamp = () => {
110+
setIsShowTimestamp(!isShowTimestamp);
111+
};
112+
108113
useEffect(() => {
109114
getLogItems();
110115
}, []);
@@ -178,11 +183,15 @@ export const Logs: React.FC<IProps> = ({ className, projectName, runName, jobSub
178183
/>
179184
</Box>
180185

181-
{/*<Box>*/}
182-
{/* <Toggle onChange={({ detail }) => setIsShowTimestamp(detail.checked)} checked={isShowTimestamp}>*/}
183-
{/* Show timestamp*/}
184-
{/* </Toggle>*/}
185-
{/*</Box>*/}
186+
<Box>
187+
<Button
188+
ariaLabel="Show timestamp"
189+
formAction="none"
190+
iconName="status-pending"
191+
variant={isShowTimestamp ? 'primary' : 'icon'}
192+
onClick={toggleShowingTimestamp}
193+
/>
194+
</Box>
186195
</div>
187196
</div>
188197
}
@@ -199,12 +208,13 @@ export const Logs: React.FC<IProps> = ({ className, projectName, runName, jobSub
199208

200209
{Boolean(logsForView.length) && (
201210
<Code className={styles.terminal} ref={codeRef}>
202-
{logsForView.map((log, i) => (
203-
<p key={i}>
204-
{/*{isShowTimestamp && <span className={styles.timestamp}>{log.timestamp}</span>}*/}
205-
{log.message}
206-
</p>
207-
))}
211+
<table>
212+
<tbody>
213+
{logsForView.map((log, i) => (
214+
<LogRow logItem={log} key={i} isShowTimestamp={isShowTimestamp} />
215+
))}
216+
</tbody>
217+
</table>
208218
</Code>
209219
)}
210220
</TextContent>

frontend/src/pages/Runs/Details/Logs/styles.module.scss

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
.switchers {
1515
margin-left: auto;
1616
display: flex;
17-
gap: 24px;
17+
gap: 10px;
18+
19+
button {
20+
width: 32px !important;
21+
}
1822
}
1923
}
2024

@@ -81,13 +85,37 @@
8185
color: awsui.$color-text-body-default !important;
8286
}
8387

84-
p {
85-
padding: 0 !important;
88+
.logItem {
8689
font-size: awsui.$font-size-body-s !important;
8790
line-height: awsui.$line-height-body-s !important;
8891

92+
.toggleCollapse {
93+
position: relative;
94+
top: -3px;
95+
vertical-align: middle;
96+
cursor: pointer;
97+
98+
&.hidden {
99+
opacity: 0;
100+
pointer-events: none;
101+
}
102+
}
103+
89104
.timestamp {
90-
padding-right: 8px;
105+
vertical-align: top;
106+
padding-right: 16px;
107+
white-space: nowrap;
108+
}
109+
110+
.messageCol {
111+
vertical-align: top;
112+
}
113+
114+
.message {
115+
overflow-y: hidden;
116+
&.collapsed {
117+
max-height: calc(awsui.$line-height-body-s * 2);
118+
}
91119
}
92120
}
93121
}

0 commit comments

Comments
 (0)