Skip to content

Commit 40c5891

Browse files
committed
[Bug]: Can't see the entire log of a run via UI #2832
1 parent 026ba42 commit 40c5891

File tree

5 files changed

+100
-70
lines changed

5 files changed

+100
-70
lines changed

frontend/src/hooks/useInfiniteScroll.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const useInfiniteScroll = <DataItem, Args extends InfinityListArgs>({
2626
const [data, setData] = useState<ListResponse<DataItem>>([]);
2727
const scrollElement = useRef<HTMLElement>(document.documentElement);
2828
const isLoadingRef = useRef<boolean>(false);
29-
const lastRequestParams = useRef<TRunsRequestParams | undefined>(undefined);
29+
const lastRequestParams = useRef<Args | undefined>(undefined);
3030
const [disabledMore, setDisabledMore] = useState(false);
3131
const { limit, ...argsProp } = args;
3232
const lastArgsProps = useRef<Partial<Args>>(null);

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

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Terminal } from '@xterm/xterm';
88
import { Container, Header, ListEmptyMessage, Loader, TextContent } from 'components';
99

1010
import { useAppSelector } from 'hooks';
11-
import { useGetProjectLogsQuery } from 'services/project';
11+
import { useLazyGetProjectLogsQuery } from 'services/project';
1212

1313
import { selectSystemMode } from 'App/slice';
1414

@@ -23,9 +23,49 @@ export const Logs: React.FC<IProps> = ({ className, projectName, runName, jobSub
2323
const appliedTheme = useAppSelector(selectSystemMode);
2424

2525
const terminalInstance = useRef<Terminal>(new Terminal());
26-
2726
const fitAddonInstance = useRef<FitAddon>(new FitAddon());
2827
const [logsData, setLogsData] = useState<ILogItem[]>([]);
28+
const [isLoading, setIsLoading] = useState(false);
29+
30+
const [getProjectLogs] = useLazyGetProjectLogsQuery();
31+
32+
const writeDataToTerminal = (logs: ILogItem[]) => {
33+
logs.forEach((logItem) => {
34+
terminalInstance.current.write(logItem.message);
35+
});
36+
37+
fitAddonInstance.current.fit();
38+
};
39+
40+
const getNextLogItems = (nextToken?: string) => {
41+
setIsLoading(true);
42+
43+
if (!jobSubmissionId) {
44+
return;
45+
}
46+
47+
getProjectLogs({
48+
project_name: projectName,
49+
run_name: runName,
50+
descending: false,
51+
job_submission_id: jobSubmissionId ?? '',
52+
next_token: nextToken,
53+
limit: LIMIT_LOG_ROWS,
54+
})
55+
.unwrap()
56+
.then((response) => {
57+
setLogsData((old) => [...old, ...response.logs]);
58+
59+
writeDataToTerminal(response.logs);
60+
61+
if (response.next_token) {
62+
getNextLogItems(response.next_token);
63+
} else {
64+
setIsLoading(false);
65+
}
66+
})
67+
.catch(() => setIsLoading(false));
68+
};
2969

3070
useEffect(() => {
3171
if (appliedTheme === Mode.Light) {
@@ -45,6 +85,8 @@ export const Logs: React.FC<IProps> = ({ className, projectName, runName, jobSub
4585
useEffect(() => {
4686
terminalInstance.current.loadAddon(fitAddonInstance.current);
4787

88+
getNextLogItems();
89+
4890
const onResize = () => {
4991
fitAddonInstance.current.fit();
5092
};
@@ -56,50 +98,27 @@ export const Logs: React.FC<IProps> = ({ className, projectName, runName, jobSub
5698
};
5799
}, []);
58100

59-
const {
60-
data: fetchData,
61-
isLoading,
62-
isFetching: isFetchingLogs,
63-
} = useGetProjectLogsQuery(
64-
{
65-
project_name: projectName,
66-
run_name: runName,
67-
descending: true,
68-
job_submission_id: jobSubmissionId ?? '',
69-
limit: LIMIT_LOG_ROWS,
70-
},
71-
{
72-
skip: !jobSubmissionId,
73-
},
74-
);
75-
76-
useEffect(() => {
77-
if (fetchData) {
78-
const reversed = [...fetchData].reverse();
79-
setLogsData((old) => [...reversed, ...old]);
80-
}
81-
}, [fetchData]);
82-
83101
useEffect(() => {
84102
const element = document.getElementById('terminal');
85103

86-
if (logsData.length && terminalInstance.current && element) {
104+
if (terminalInstance.current && element) {
87105
terminalInstance.current.open(element);
88-
89-
logsData.forEach((logItem) => {
90-
terminalInstance.current.write(logItem.message);
91-
});
92-
93-
fitAddonInstance.current.fit();
94106
}
95-
}, [logsData]);
107+
}, []);
96108

97109
return (
98110
<div className={classNames(styles.logs, className)}>
99-
<Container header={<Header variant="h2">{t('projects.run.log')}</Header>}>
111+
<Container
112+
header={
113+
<Header variant="h2">
114+
<div className={styles.headerContainer}>
115+
{t('projects.run.log')}
116+
<Loader show={isLoading} padding={'n'} className={classNames(styles.loader)} loadingText={''} />
117+
</div>
118+
</Header>
119+
}
120+
>
100121
<TextContent>
101-
<Loader padding={'n'} className={classNames(styles.loader, { show: isLoading || isFetchingLogs })} />
102-
103122
{!isLoading && !logsData.length && (
104123
<ListEmptyMessage
105124
title={t('projects.run.log_empty_message_title')}

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

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
@use '@cloudscape-design/design-tokens/index' as awsui;
22

3+
.headerContainer {
4+
display: flex;
5+
gap: 10px;
6+
align-items: center;
7+
}
8+
9+
.loader {
10+
position: relative;
11+
top: -2px;
12+
height: 20px;
13+
background-color: rgba(awsui.$color-background-container-content, .8);
14+
color: #6e6e6e;
15+
}
16+
317
.logs {
418
display: flex;
519
flex-direction: column;
@@ -39,22 +53,6 @@
3953
}
4054
}
4155

42-
.loader {
43-
pointer-events: none;
44-
position: absolute;
45-
left: 0;
46-
right: 0;
47-
top: -20px;
48-
height: 20px;
49-
background-color: rgba(awsui.$color-background-container-content, .8);
50-
transition: transform .3s ease;
51-
color: #6e6e6e;
52-
53-
&:global(.show) {
54-
transform: translateY(100%);
55-
}
56-
}
57-
5856
.terminal {
5957
flex-grow: 1;
6058
min-height: 0;

frontend/src/services/project.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export const projectApi = createApi({
7373
invalidatesTags: () => ['Projects'],
7474
}),
7575

76-
getProjectLogs: builder.query<ILogItem[], TRequestLogsParams>({
76+
getProjectLogs: builder.query<TResponseLogsParams, TRequestLogsParams>({
7777
query: ({ project_name, ...body }) => {
7878
return {
7979
url: API.PROJECTS.LOGS(project_name),
@@ -84,11 +84,17 @@ export const projectApi = createApi({
8484

8585
keepUnusedDataFor: 0,
8686
providesTags: () => ['ProjectLogs'],
87-
transformResponse: (response: { logs: ILogItem[] }) =>
88-
response.logs.map((logItem) => ({
87+
transformResponse: (response: { logs: ILogItem[]; next_token: string }) => {
88+
const logs = response.logs.map((logItem) => ({
8989
...logItem,
9090
message: base64ToArrayBuffer(logItem.message as string),
91-
})),
91+
}));
92+
93+
return {
94+
...response,
95+
logs,
96+
};
97+
},
9298
}),
9399

94100
getProjectRepos: builder.query<IRepo[], { project_name: string }>({
@@ -111,5 +117,6 @@ export const {
111117
useUpdateProjectMembersMutation,
112118
useDeleteProjectsMutation,
113119
useGetProjectLogsQuery,
120+
useLazyGetProjectLogsQuery,
114121
useGetProjectReposQuery,
115122
} = projectApi;

frontend/src/types/log.d.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
declare interface ILogItem {
2-
log_source: 'stdout' | 'stderr'
3-
timestamp: string,
4-
message: string | Uint8Array,
2+
log_source: 'stdout' | 'stderr';
3+
timestamp: string;
4+
message: string | Uint8Array;
55
}
66

77
declare type TRequestLogsParams = {
8-
project_name: IProject['project_name'],
9-
run_name: IRun['run_name'],
10-
job_submission_id: string
11-
start_time?: DateTime,
12-
end_time?: DateTime,
13-
descending?: boolean,
14-
limit?: number
15-
diagnose?: boolean
16-
}
8+
project_name: IProject['project_name'];
9+
run_name: IRun['run_name'];
10+
job_submission_id: string;
11+
start_time?: DateTime;
12+
end_time?: DateTime;
13+
descending?: boolean;
14+
limit?: number;
15+
diagnose?: boolean;
16+
next_token?: string;
17+
};
18+
19+
declare type TResponseLogsParams = {
20+
logs: ILogItem[];
21+
next_token?: string;
22+
};

0 commit comments

Comments
 (0)