Skip to content

Commit

Permalink
feat: use NEO session log modal in session list (#2804)
Browse files Browse the repository at this point in the history
**Changes:**
With this PR, user can open a NEO session log modal in session list
The new implementation uses a lazy-loaded query to fetch session logs and displays them in a modern container log modal.

**Key Updates:**
- Introduces `ContainerLogModalWithLazyQueryLoader` component for handling session logs
- Adds event listener for `bai-open-session-log` to bridge legacy and React components
- Implements suspense boundary with skeleton loading state
- Replaces direct API calls with GraphQL queries for log fetching

**Review Requirements:**
- Open the log modal by clicking session's log button in session list.
  • Loading branch information
yomybaby committed Nov 5, 2024
1 parent aa52f73 commit 3a72c18
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 39 deletions.
63 changes: 55 additions & 8 deletions react/src/components/ComputeSessionList.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,64 @@
import BAIModal from './BAIModal';
import ContainerLogModalWithLazyQueryLoader from './ComputeSessionNodeItems/ContainerLogModalWithLazyQueryLoader';
import SessionDetailDrawer from './SessionDetailDrawer';
import React from 'react';
import { Skeleton } from 'antd';
import { Suspense, useEffect, useState } from 'react';
import { StringParam, useQueryParam } from 'use-query-params';

const ComputeSessionList = () => {
const [sessionId, setSessionId] = useQueryParam('sessionDetail', StringParam);

const [containerLogModalSessionId, setContainerLogModalSessionId] =
useState<string>();
useEffect(() => {
const handler = (e: any) => {
setContainerLogModalSessionId(e.detail);
};
document.addEventListener('bai-open-session-log', handler);
return () => {
document.removeEventListener('bai-open-session-log', handler);
};
}, []);
return (
<SessionDetailDrawer
open={!sessionId}
sessionId={sessionId || undefined}
onClose={() => {
setSessionId(null, 'replaceIn');
}}
/>
<>
<SessionDetailDrawer
open={!sessionId}
sessionId={sessionId || undefined}
onClose={() => {
setSessionId(null, 'replaceIn');
}}
/>
{containerLogModalSessionId && (
<Suspense
fallback={
<BAIModal
open
// loading
width={'100%'}
styles={{
header: {
width: '100%',
},
body: {
height: 'calc(100vh - 100px)',
maxHeight: 'calc(100vh - 100px)',
},
}}
footer={null}
>
<Skeleton active />
</BAIModal>
}
>
<ContainerLogModalWithLazyQueryLoader
sessionId={containerLogModalSessionId}
afterClose={() => {
setContainerLogModalSessionId(undefined);
}}
/>
</Suspense>
)}
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useCurrentProjectValue } from '../../hooks/useCurrentProject';
import ContainerLogModal from './ContainerLogModal';
import { ContainerLogModalWithLazyQueryLoaderQuery } from './__generated__/ContainerLogModalWithLazyQueryLoaderQuery.graphql';
import graphql from 'babel-plugin-relay/macro';
import { useState } from 'react';
import { useLazyLoadQuery } from 'react-relay';

const ContainerLogModalWithLazyQueryLoader: React.FC<{
sessionId: string;
afterClose?: () => void;
}> = ({ sessionId, afterClose }) => {
const currentProject = useCurrentProjectValue();
const [open, setOpen] = useState(true);
const { compute_session_node } =
useLazyLoadQuery<ContainerLogModalWithLazyQueryLoaderQuery>(
graphql`
query ContainerLogModalWithLazyQueryLoaderQuery(
$sessionId: GlobalIDField!
$project_id: UUID!
) {
compute_session_node(id: $sessionId, project_id: $project_id) {
...ContainerLogModalFragment
}
}
`,
{
sessionId,
project_id: currentProject.id,
},
);

return (
compute_session_node && (
<ContainerLogModal
maskTransitionName={open ? '' : undefined}
transitionName={open ? '' : undefined}
sessionFrgmt={compute_session_node}
open={open}
onCancel={() => {
setOpen(false);
}}
afterClose={() => {
afterClose?.();
}}
/>
)
);
};

export default ContainerLogModalWithLazyQueryLoader;
70 changes: 39 additions & 31 deletions src/components/backend-ai-session-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1647,37 +1647,45 @@ export default class BackendAISessionList extends BackendAIPage {
* Show logs - work title, session logs, session name, and access key.
*/
_showLogs() {
globalThis.backendaiclient
.get_logs(
this.workDialog.sessionUuid,
this.workDialog.accessKey,
this.selectedKernelId !== '' ? this.selectedKernelId : null,
15000,
)
.then((req) => {
const ansi_up = new AnsiUp();
const logs = ansi_up.ansi_to_html(req.result.logs);
(
this.shadowRoot?.querySelector('#work-title') as HTMLSpanElement
).innerHTML =
`${this.workDialog.sessionName} (${this.workDialog.sessionUuid})`;
(
this.shadowRoot?.querySelector('#work-area') as HTMLDivElement
).innerHTML = `<pre>${logs}</pre>` || _text('session.NoLogs');
// TODO define extended type for custom properties
this.workDialog.show();
})
.catch((err) => {
if (err && err.message) {
this.notification.text = PainKiller.relieve(err.title);
this.notification.detail = err.message;
this.notification.show(true, err);
} else if (err && err.title) {
this.notification.text = PainKiller.relieve(err.title);
this.notification.detail = '';
this.notification.show(true, err);
}
});
if (globalThis.backendaiclient.supports('session-node')) {
document.dispatchEvent(
new CustomEvent('bai-open-session-log', {
detail: this.workDialog.sessionUuid,
}),
);
} else {
globalThis.backendaiclient
.get_logs(
this.workDialog.sessionUuid,
this.workDialog.accessKey,
this.selectedKernelId !== '' ? this.selectedKernelId : null,
15000,
)
.then((req) => {
const ansi_up = new AnsiUp();
const logs = ansi_up.ansi_to_html(req.result.logs);
(
this.shadowRoot?.querySelector('#work-title') as HTMLSpanElement
).innerHTML =
`${this.workDialog.sessionName} (${this.workDialog.sessionUuid})`;
(
this.shadowRoot?.querySelector('#work-area') as HTMLDivElement
).innerHTML = `<pre>${logs}</pre>` || _text('session.NoLogs');
// TODO define extended type for custom properties
this.workDialog.show();
})
.catch((err) => {
if (err && err.message) {
this.notification.text = PainKiller.relieve(err.title);
this.notification.detail = err.message;
this.notification.show(true, err);
} else if (err && err.title) {
this.notification.text = PainKiller.relieve(err.title);
this.notification.detail = '';
this.notification.show(true, err);
}
});
}
}

_downloadLogs() {
Expand Down
1 change: 1 addition & 0 deletions src/lib/backend.ai-client-esm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ class Client {
}
if (this.isManagerVersionCompatibleWith('24.09')) {
this._features['extend-login-session'] = true;
this._features['session-node'] = true;
}
}

Expand Down

0 comments on commit 3a72c18

Please sign in to comment.