Skip to content

Commit 3d35731

Browse files
committed
feat(FR-2676): add DeploymentConfigurationSection for detail page overview
1 parent d374d59 commit 3d35731

2 files changed

Lines changed: 280 additions & 0 deletions

File tree

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
/**
2+
@license
3+
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
4+
*/
5+
import { DeploymentConfigurationSection_deployment$key } from '../__generated__/DeploymentConfigurationSection_deployment.graphql';
6+
import { useWebUINavigate } from '../hooks';
7+
import { CheckOutlined, CloseOutlined, EditOutlined } from '@ant-design/icons';
8+
import { Descriptions, Tag, Typography, theme } from 'antd';
9+
import { DescriptionsItemType } from 'antd/es/descriptions';
10+
import {
11+
filterOutEmpty,
12+
BAIButton,
13+
BAICard,
14+
BAIFlex,
15+
toLocalId,
16+
} from 'backend.ai-ui';
17+
import { useTranslation } from 'react-i18next';
18+
import { graphql, useFragment } from 'react-relay';
19+
20+
interface DeploymentConfigurationSectionProps {
21+
deploymentFrgmt: DeploymentConfigurationSection_deployment$key;
22+
}
23+
24+
const DeploymentConfigurationSection: React.FC<
25+
DeploymentConfigurationSectionProps
26+
> = ({ deploymentFrgmt }) => {
27+
'use memo';
28+
29+
const { t } = useTranslation();
30+
const { token } = theme.useToken();
31+
const webuiNavigate = useWebUINavigate();
32+
33+
const deployment = useFragment(
34+
graphql`
35+
fragment DeploymentConfigurationSection_deployment on ModelDeployment {
36+
id
37+
metadata {
38+
name
39+
tags
40+
projectId
41+
domainName
42+
projectV2 @since(version: "26.4.3") {
43+
basicInfo {
44+
name
45+
}
46+
}
47+
}
48+
networkAccess {
49+
openToPublic
50+
}
51+
defaultDeploymentStrategy {
52+
type
53+
}
54+
replicaState {
55+
desiredReplicaCount
56+
}
57+
currentRevision @since(version: "26.4.3") {
58+
id
59+
name
60+
clusterConfig {
61+
mode
62+
size
63+
}
64+
resourceConfig {
65+
resourceGroupName
66+
}
67+
modelRuntimeConfig {
68+
runtimeVariant
69+
environ {
70+
entries {
71+
name
72+
value
73+
}
74+
}
75+
}
76+
modelMountConfig {
77+
vfolderId
78+
mountDestination
79+
definitionPath
80+
vfolder {
81+
id
82+
name
83+
}
84+
}
85+
imageV2 @since(version: "26.4.3") {
86+
id
87+
identity {
88+
canonicalName
89+
}
90+
}
91+
}
92+
}
93+
`,
94+
deploymentFrgmt,
95+
);
96+
97+
const deploymentId = toLocalId(deployment.id);
98+
const currentRevision = deployment.currentRevision;
99+
const clusterConfig = currentRevision?.clusterConfig;
100+
const resourceConfig = currentRevision?.resourceConfig;
101+
const runtimeConfig = currentRevision?.modelRuntimeConfig;
102+
const mountConfig = currentRevision?.modelMountConfig;
103+
const projectName =
104+
deployment.metadata.projectV2?.basicInfo?.name ??
105+
deployment.metadata.projectId;
106+
107+
const renderFallback = () => (
108+
<Typography.Text type="secondary">-</Typography.Text>
109+
);
110+
111+
const environEntries = runtimeConfig?.environ?.entries ?? [];
112+
const tags = deployment.metadata.tags ?? [];
113+
114+
const items: DescriptionsItemType[] = filterOutEmpty([
115+
{
116+
key: 'name',
117+
label: t('deployment.Name'),
118+
children: deployment.metadata.name ? (
119+
<Typography.Text copyable>{deployment.metadata.name}</Typography.Text>
120+
) : (
121+
renderFallback()
122+
),
123+
},
124+
{
125+
key: 'project',
126+
label: t('deployment.Project'),
127+
children: projectName || renderFallback(),
128+
},
129+
{
130+
key: 'domain',
131+
label: t('deployment.Domain'),
132+
children: deployment.metadata.domainName || renderFallback(),
133+
},
134+
{
135+
key: 'resource-group',
136+
label: t('deployment.ResourceGroup'),
137+
children: resourceConfig?.resourceGroupName || renderFallback(),
138+
},
139+
{
140+
key: 'model-folder',
141+
label: t('deployment.ModelFolder'),
142+
children: mountConfig?.vfolder?.name ? (
143+
<BAIFlex direction="column" align="start">
144+
<Typography.Text>{mountConfig.vfolder.name}</Typography.Text>
145+
{mountConfig.mountDestination && (
146+
<Typography.Text type="secondary">
147+
{mountConfig.mountDestination}
148+
</Typography.Text>
149+
)}
150+
</BAIFlex>
151+
) : (
152+
renderFallback()
153+
),
154+
},
155+
{
156+
key: 'model-version',
157+
label: t('deployment.ModelVersion'),
158+
children: currentRevision?.name || renderFallback(),
159+
},
160+
{
161+
key: 'model-definition-path',
162+
label: t('deployment.ModelDefinitionPath'),
163+
children: mountConfig?.definitionPath || renderFallback(),
164+
},
165+
{
166+
key: 'runtime-variant',
167+
label: t('deployment.RuntimeVariant'),
168+
children: runtimeConfig?.runtimeVariant || renderFallback(),
169+
},
170+
{
171+
key: 'image',
172+
label: t('deployment.Image'),
173+
children:
174+
currentRevision?.imageV2?.identity?.canonicalName || renderFallback(),
175+
},
176+
{
177+
key: 'cluster-mode',
178+
label: t('deployment.ClusterMode'),
179+
children: clusterConfig ? (
180+
<Typography.Text>
181+
{clusterConfig.mode} / {clusterConfig.size}
182+
</Typography.Text>
183+
) : (
184+
renderFallback()
185+
),
186+
},
187+
{
188+
key: 'desired-replicas',
189+
label: t('deployment.DesiredReplicas'),
190+
children:
191+
deployment.replicaState?.desiredReplicaCount ?? renderFallback(),
192+
},
193+
{
194+
key: 'open-to-public',
195+
label: t('deployment.OpenToPublic'),
196+
children: deployment.networkAccess.openToPublic ? (
197+
<CheckOutlined />
198+
) : (
199+
<CloseOutlined />
200+
),
201+
},
202+
{
203+
key: 'tags',
204+
label: t('deployment.Tags'),
205+
children:
206+
tags.length > 0 ? (
207+
<BAIFlex direction="row" wrap="wrap" gap="xxs">
208+
{tags.map((tag) => (
209+
<Tag key={tag}>{tag}</Tag>
210+
))}
211+
</BAIFlex>
212+
) : (
213+
renderFallback()
214+
),
215+
},
216+
{
217+
key: 'environ',
218+
label: t('deployment.EnvironmentVariables'),
219+
children:
220+
environEntries.length > 0 ? (
221+
<BAIFlex direction="column" align="start">
222+
{environEntries.map((entry) => (
223+
<Typography.Text key={entry.name} code>
224+
{entry.name}={entry.value}
225+
</Typography.Text>
226+
))}
227+
</BAIFlex>
228+
) : (
229+
renderFallback()
230+
),
231+
span: { xl: 2 },
232+
},
233+
]);
234+
235+
return (
236+
<BAICard
237+
title={t('deployment.Configuration')}
238+
extra={
239+
<BAIButton
240+
type="primary"
241+
icon={<EditOutlined />}
242+
onClick={() => {
243+
webuiNavigate(`/deployments/${deploymentId}/edit`);
244+
}}
245+
>
246+
{t('deployment.EditConfiguration')}
247+
</BAIButton>
248+
}
249+
>
250+
<Descriptions
251+
bordered
252+
column={{ xxl: 3, xl: 2, lg: 2, md: 1, sm: 1, xs: 1 }}
253+
style={{
254+
backgroundColor: token.colorBgBase,
255+
}}
256+
items={items}
257+
/>
258+
</BAICard>
259+
);
260+
};
261+
262+
export default DeploymentConfigurationSection;

resources/i18n/en.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,24 @@
752752
"Used": "used"
753753
}
754754
},
755+
"deployment": {
756+
"ClusterMode": "Cluster Mode / Size",
757+
"Configuration": "Configuration",
758+
"DesiredReplicas": "Desired Replicas",
759+
"Domain": "Domain",
760+
"EditConfiguration": "Edit Configuration",
761+
"EnvironmentVariables": "Environment Variables",
762+
"Image": "Image",
763+
"ModelDefinitionPath": "Model Definition Path",
764+
"ModelFolder": "Model Folder",
765+
"ModelVersion": "Model Version",
766+
"Name": "Name",
767+
"OpenToPublic": "Open to Public",
768+
"Project": "Project",
769+
"ResourceGroup": "Resource Group",
770+
"RuntimeVariant": "Runtime Variant",
771+
"Tags": "Tags"
772+
},
755773
"desktopNotification": {
756774
"NotSupported": "This browser does not support notifications.",
757775
"PermissionDenied": "You've denied notification access. To use alerts, please allow it in your browser settings."

0 commit comments

Comments
 (0)