Skip to content

Commit

Permalink
feat: Session detail panel
Browse files Browse the repository at this point in the history
  • Loading branch information
yomybaby committed Oct 31, 2024
1 parent 80bd516 commit 655e66a
Show file tree
Hide file tree
Showing 45 changed files with 1,227 additions and 66 deletions.
10 changes: 4 additions & 6 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"FGPU",
"filebrowser",
"Frgmt",
"Frgmts",
"Gaudi",
"keypair",
"Lablup",
Expand All @@ -19,17 +20,14 @@
"RNGD",
"shmem",
"superadmin",
"textbox",
"vaadin",
"vfolder",
"vfolders",
"Warboy",
"webcomponent",
"webui",
"wsproxy",
"vfolders",
"vfolder",
"filebrowser",
"vaadin",
"textbox"
"wsproxy"
],
"flagWords": [
"데이터레이크",
Expand Down
17 changes: 13 additions & 4 deletions react/data/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,18 @@ type Queries {
group_node(id: String!): GroupNode

"""Added in 24.03.0."""
group_nodes(filter: String, order: String, offset: Int, before: String, after: String, first: Int, last: Int): GroupConnection
group_nodes(
"""Added in 24.09.0."""
filter: String

"""Added in 24.09.0."""
order: String
offset: Int
before: String
after: String
first: Int
last: Int
): GroupConnection
group(
id: UUID!
domain_name: String
Expand Down Expand Up @@ -1258,9 +1269,7 @@ type ContainerRegistryNode implements Node {
"""The ID of the object"""
id: ID!

"""
Added in 24.09.0. The undecoded UUID type id of DB container_registries row.
"""
"""Added in 24.09.0. The UUID type id of DB container_registries row."""
row_id: UUID
name: String

Expand Down
1 change: 1 addition & 0 deletions react/relay.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ module.exports = {
// https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#number-string-boolean-symbol-and-object
DateTime: 'string',
UUID: 'string',
JSONString: 'string',
},
};
9 changes: 9 additions & 0 deletions react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ const InteractiveLoginPage = React.lazy(
);
const ImportAndRunPage = React.lazy(() => import('./pages/ImportAndRunPage'));

const ComputeSessionList = React.lazy(
() => import('./components/ComputeSessionList'),
);

const RedirectToSummary = () => {
useSuspendedBackendaiClient();
const pathName = '/summary';
Expand Down Expand Up @@ -139,6 +143,11 @@ const router = createBrowserRouter([
{
path: '/job',
handle: { labelKey: 'webui.menu.Sessions' },
element: (
<BAIErrorBoundary>
<ComputeSessionList />
</BAIErrorBoundary>
),
},
{
path: '/serving',
Expand Down
2 changes: 0 additions & 2 deletions react/src/components/BAIModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import Draggable from 'react-draggable';

export const DEFAULT_BAI_MODAL_Z_INDEX = 1001;
export interface BAIModalProps extends ModalProps {
okText?: string; // customize text of ok button with adequate content
draggable?: boolean; // modal can be draggle
className?: string;
}
const BAIModal: React.FC<BAIModalProps> = ({
className,
Expand Down
18 changes: 18 additions & 0 deletions react/src/components/ComputeSessionList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import SessionDetailDrawer from './SessionDetailDrawer';
import React from 'react';
import { StringParam, useQueryParam } from 'use-query-params';

const ComputeSessionList = () => {
const [sessionId, setSessionId] = useQueryParam('sessionDetail', StringParam);
return (
<SessionDetailDrawer
open={!sessionId}
sessionId={sessionId || undefined}
onClose={() => {
setSessionId(null, 'replaceIn');
}}
/>
);
};

export default ComputeSessionList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { EditableSessionNameFragment$key } from './__generated__/EditableSessionNameFragment.graphql';
import { EditableSessionNameMutation } from './__generated__/EditableSessionNameMutation.graphql';
import { theme } from 'antd';
import Text, { TextProps } from 'antd/es/typography/Text';
import Title, { TitleProps } from 'antd/es/typography/Title';
import graphql from 'babel-plugin-relay/macro';
import React, { useState } from 'react';
import { useFragment, useMutation } from 'react-relay';

type EditableSessionNameProps = {
sessionFrgmt: EditableSessionNameFragment$key;
} & (
| ({ component?: typeof Text } & Omit<TextProps, 'children'>)
| ({ component: typeof Title } & Omit<TitleProps, 'children'>)
);

const EditableSessionName: React.FC<EditableSessionNameProps> = ({
component: Component = Text,
sessionFrgmt,
style,
...otherProps
}) => {
const session = useFragment(
graphql`
fragment EditableSessionNameFragment on ComputeSessionNode {
id
name
priority
}
`,
sessionFrgmt,
);
const [optimisticName, setOptimisticName] = useState(session.name);
const { token } = theme.useToken();
const [commitEditMutation, isPendingEditMutation] =
useMutation<EditableSessionNameMutation>(graphql`
mutation EditableSessionNameMutation($input: ModifyComputeSessionInput!) {
modify_compute_session(input: $input) {
item {
id
name
}
}
}
`);
return (
session && (
<Component
editable={
isPendingEditMutation
? undefined
: {
onChange: (newName) => {
setOptimisticName(newName);
commitEditMutation({
variables: {
input: {
id: session.id,
name: newName,
// TODO: priority는 옵션이어야한다. 하지만 API 버그 때문에 유지
priority: session.priority,
},
},
onCompleted(response, errors) {},
onError(error) {},
});
},
triggerType: ['icon', 'text'],
}
}
copyable
style={{
...style,
color: isPendingEditMutation ? token.colorTextTertiary : style?.color,
}}
{...otherProps}
>
{isPendingEditMutation ? optimisticName : session.name}
</Component>
)
);
};

export default EditableSessionName;
122 changes: 122 additions & 0 deletions react/src/components/ComputeSessionNodeItems/SessionActionButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { useBackendAIAppLauncher } from '../../hooks/useBackendAIAppLauncher';
import TerminateSessionModal from './TerminateSessionModal';
import {
SessionActionButtonsFragment$data,
SessionActionButtonsFragment$key,
} from './__generated__/SessionActionButtonsFragment.graphql';
import { Tooltip, Button, theme } from 'antd';
import graphql from 'babel-plugin-relay/macro';
import { TerminalIcon, PowerOffIcon } from 'lucide-react';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useFragment } from 'react-relay';

interface SessionActionButtonsProps {
sessionFrgmt: SessionActionButtonsFragment$key | null;
}
// const isRunning = (session:SessionActionButtonsFragment$data) => {
// return [
// 'batch',
// 'interactive',
// 'inference',
// 'system',
// 'running',
// 'others',
// ].includes(session);
// }

const isActive = (session: SessionActionButtonsFragment$data) => {
return !['TERMINATED', 'CANCELLED'].includes(session?.status || '');
};
// const isTransitional = (session: SessionActionButtonsFragment$data) => {
// return [
// 'RESTARTING',
// 'TERMINATING',
// 'PENDING',
// 'PREPARING',
// 'PULLING',
// ].includes(session?.status || '');
// };

const SessionActionButtons: React.FC<SessionActionButtonsProps> = ({
sessionFrgmt,
}) => {
const { token } = theme.useToken();
const appLauncher = useBackendAIAppLauncher();

const { t } = useTranslation();

const session = useFragment(
graphql`
fragment SessionActionButtonsFragment on ComputeSessionNode {
id
row_id @required(action: NONE)
status
access_key
service_ports
commit_status
...TerminateSessionModalFragment
}
`,
sessionFrgmt,
);
const [openTerminateModal, setOpenTerminateModal] = useState(false);

// const isDisabledTermination = !['PENDING'].includes(session?.status || '') && session?.commit_status === 'ongoing'
// ${(this._isRunning && !this._isPreparing(rowData.item.status)) ||
// this._isError(rowData.item.status)
return (
session && (
<>
{/* <Tooltip title={t('session.SeeAppDialog')}>
<Button icon={<LayoutGridIcon />} onClick={()=>{
appLauncher.showLauncher({
"access-key": session?.access_key || '',
"service-ports": session?.service_ports || '',
})
}} />
</Tooltip> */}
<Tooltip title={t('session.ExecuteTerminalApp')}>
<Button
disabled={!isActive(session)}
icon={<TerminalIcon />}
onClick={() => {
appLauncher.runTerminal(session?.row_id);
}}
/>
</Tooltip>
{/* Don't put this modal to end of the return array(<></>). */}
<TerminateSessionModal
sessionFrgmts={[session]}
open={openTerminateModal}
onRequestClose={() => {
setOpenTerminateModal(false);
}}
/>
{/*
<Tooltip title={t('session.SeeContainerLogs')}>
<Button icon={<ScrollTextIcon />} />
</Tooltip>
<Tooltip title={t('session.RequestContainerCommit')}>
<Button icon={<ContainerIcon />} />
</Tooltip> */}
<Tooltip title={t('session.TerminateSession')}>
<Button
disabled={!isActive(session)}
icon={
<PowerOffIcon
color={isActive(session) ? token.colorError : undefined}
/>
}
onClick={() => {
setOpenTerminateModal(true);
}}
/>
</Tooltip>
</>
)
);
};

export default SessionActionButtons;
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useSuspendedBackendaiClient } from '../../hooks';
import BAIIntervalText from '../BAIIntervalText';
import DoubleTag from '../DoubleTag';
import { SessionReservationFragment$key } from './__generated__/SessionReservationFragment.graphql';
import graphql from 'babel-plugin-relay/macro';
import dayjs from 'dayjs';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useFragment } from 'react-relay';

const SessionReservation: React.FC<{
sessionFrgmt: SessionReservationFragment$key;
}> = ({ sessionFrgmt }) => {
const baiClient = useSuspendedBackendaiClient();
const { t } = useTranslation();
const session = useFragment(
graphql`
fragment SessionReservationFragment on ComputeSessionNode {
id
created_at
terminated_at
}
`,
sessionFrgmt,
);
return (
<>
{dayjs(session.created_at).format('lll')}
<DoubleTag
values={[
t('session.ElapsedTime'),
<BAIIntervalText
callback={() => {
return session?.created_at
? baiClient.utils.elapsedTime(
session.created_at,
session?.terminated_at,
)
: '-';
}}
delay={1000}
/>,
]}
/>
</>
);
};

export default SessionReservation;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

const SessionResourceNumbers = () => {
return <div>SessionResourceNumbers</div>;
};

export default SessionResourceNumbers;
Loading

0 comments on commit 655e66a

Please sign in to comment.