Skip to content

Commit a0a1084

Browse files
yomybabyagatha197
authored andcommitted
feat: Mockup UI for Deployment and Revisions
1 parent c09fef4 commit a0a1084

18 files changed

+2961
-1
lines changed

react/src/App.tsx

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,20 @@ const ChatPage = React.lazy(() => import('./pages/ChatPage'));
8282

8383
const AIAgentPage = React.lazy(() => import('./pages/AIAgentPage'));
8484

85+
// Deployment pages
86+
const DeploymentListPage = React.lazy(
87+
() => import('./pages/Deployments/DeploymentListPage'),
88+
);
89+
const DeploymentDetailPage = React.lazy(
90+
() => import('./pages/Deployments/DeploymentDetailPage'),
91+
);
92+
const RevisionCreatePage = React.lazy(
93+
() => import('./pages/Deployments/RevisionCreatePage'),
94+
);
95+
const RevisionDetailPage = React.lazy(
96+
() => import('./pages/Deployments/RevisionDetailPage'),
97+
);
98+
8599
interface CustomHandle {
86100
title?: string;
87101
labelKey?: string;
@@ -298,6 +312,69 @@ const router = createBrowserRouter([
298312
},
299313
],
300314
},
315+
{
316+
path: '/deployment',
317+
handle: { labelKey: 'webui.menu.Deployment' },
318+
children: [
319+
{
320+
path: '',
321+
Component: () => {
322+
const { t } = useTranslation();
323+
useSuspendedBackendaiClient();
324+
return (
325+
<BAIErrorBoundary>
326+
<Suspense
327+
fallback={
328+
<BAICard title={t('webui.menu.Deployment')} loading />
329+
}
330+
>
331+
<DeploymentListPage />
332+
</Suspense>
333+
</BAIErrorBoundary>
334+
);
335+
},
336+
},
337+
{
338+
path: '/deployment/:deploymentId',
339+
handle: { labelKey: 'deployment.DeploymentDetail' },
340+
element: (
341+
<BAIErrorBoundary>
342+
<Suspense fallback={<Skeleton active />}>
343+
<DeploymentDetailPage />
344+
</Suspense>
345+
</BAIErrorBoundary>
346+
),
347+
},
348+
{
349+
path: '/deployment/:deploymentId/revision/create',
350+
handle: { labelKey: 'revision.CreateRevision' },
351+
element: (
352+
<BAIErrorBoundary>
353+
<Suspense
354+
fallback={
355+
<BAIFlex direction="column" style={{ maxWidth: 700 }}>
356+
<Skeleton active />
357+
</BAIFlex>
358+
}
359+
>
360+
<RevisionCreatePage />
361+
</Suspense>
362+
</BAIErrorBoundary>
363+
),
364+
},
365+
{
366+
path: '/deployment/:deploymentId/revision/:revisionId',
367+
handle: { labelKey: 'revision.RevisionDetail' },
368+
element: (
369+
<BAIErrorBoundary>
370+
<Suspense fallback={<Skeleton active />}>
371+
<RevisionDetailPage />
372+
</Suspense>
373+
</BAIErrorBoundary>
374+
),
375+
},
376+
],
377+
},
301378
{
302379
path: '/service',
303380
handle: { labelKey: 'webui.menu.Serving' },
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import ResourceNumber from './ResourceNumber';
2+
import WebUILink from './WebUILink';
3+
import { Typography, TablePaginationConfig, Tooltip } from 'antd';
4+
import { ColumnType } from 'antd/lib/table';
5+
import { BAIFlex, BAITable, BAITableProps } from 'backend.ai-ui';
6+
import dayjs from 'dayjs';
7+
import { ExternalLinkIcon } from 'lucide-react';
8+
import React from 'react';
9+
import { useTranslation } from 'react-i18next';
10+
import { filterOutNullAndUndefined } from 'src/helper';
11+
12+
interface Deployment {
13+
id: string;
14+
name: string;
15+
endpoint_url: string;
16+
total_gpu: number;
17+
total_cpu: number;
18+
total_mem?: string; // Optional, if memory is included
19+
active_replicas: number;
20+
active_revisions: number;
21+
tokens_last_hour: number;
22+
created_at: string;
23+
}
24+
25+
interface DeploymentListProps
26+
extends Omit<BAITableProps<Deployment>, 'dataSource' | 'columns'> {
27+
deployments: Deployment[];
28+
loading?: boolean;
29+
pagination: TablePaginationConfig;
30+
}
31+
32+
const DeploymentList: React.FC<DeploymentListProps> = ({
33+
deployments,
34+
loading,
35+
pagination,
36+
...tableProps
37+
}) => {
38+
const { t } = useTranslation();
39+
40+
const columns: ColumnType<Deployment>[] = [
41+
{
42+
title: t('deployment.DeploymentName'),
43+
key: 'name',
44+
dataIndex: 'name',
45+
fixed: 'left',
46+
render: (name, row) => (
47+
<WebUILink to={`/deployment/${row.id}`}>{name}</WebUILink>
48+
),
49+
sorter: true,
50+
},
51+
{
52+
title: t('deployment.EndpointURL'),
53+
dataIndex: 'endpoint_url',
54+
key: 'endpoint_url',
55+
render: (url) => (
56+
<BAIFlex gap={'xxs'}>
57+
<Typography.Text copyable>{url}</Typography.Text>
58+
<a href={url} title="" target="_blank" rel="noopener noreferrer">
59+
<Tooltip title={t('common.OpenInNewTab')}>
60+
<ExternalLinkIcon />
61+
</Tooltip>
62+
</a>
63+
</BAIFlex>
64+
),
65+
},
66+
{
67+
title: t('deployment.TotalResources'),
68+
key: 'total_resources',
69+
render: (_, row) => (
70+
<BAIFlex direction="row" gap="xs">
71+
<ResourceNumber type="cpu" value={row.total_cpu.toString()} />
72+
<ResourceNumber type="mem" value={'12g'} />
73+
<ResourceNumber type="cuda.device" value={row.total_gpu.toString()} />
74+
</BAIFlex>
75+
),
76+
},
77+
{
78+
title: t('deployment.ActiveReplicas'),
79+
dataIndex: 'active_replicas',
80+
key: 'active_replicas',
81+
render: (count) => count,
82+
sorter: (a, b) => a.active_replicas - b.active_replicas,
83+
},
84+
{
85+
title: t('deployment.ActiveRevisions'),
86+
dataIndex: 'active_revisions',
87+
key: 'active_revisions',
88+
render: (count) => count,
89+
sorter: (a, b) => a.active_revisions - b.active_revisions,
90+
},
91+
{
92+
title: t('deployment.TokensLastHour'),
93+
dataIndex: 'tokens_last_hour',
94+
key: 'tokens_last_hour',
95+
render: (count) => (
96+
<Typography.Text>{count.toLocaleString()}</Typography.Text>
97+
),
98+
sorter: (a, b) => a.tokens_last_hour - b.tokens_last_hour,
99+
},
100+
{
101+
title: t('deployment.CreatedAt'),
102+
dataIndex: 'created_at',
103+
key: 'created_at',
104+
render: (created_at) => {
105+
return dayjs(created_at).format('ll LT');
106+
},
107+
sorter: (a, b) => {
108+
const date1 = dayjs(a.created_at);
109+
const date2 = dayjs(b.created_at);
110+
return date1.diff(date2);
111+
},
112+
},
113+
];
114+
115+
return (
116+
<BAITable
117+
size="small"
118+
loading={loading}
119+
scroll={{ x: 'max-content' }}
120+
rowKey="id"
121+
dataSource={filterOutNullAndUndefined(deployments)}
122+
columns={columns}
123+
pagination={pagination}
124+
{...tableProps}
125+
/>
126+
);
127+
};
128+
129+
export default DeploymentList;

0 commit comments

Comments
 (0)