Skip to content

Commit bcf58d0

Browse files
committed
feat(FR-2846): move deployment delete into a more menu next to edit
1 parent 802c916 commit bcf58d0

22 files changed

Lines changed: 131 additions & 9 deletions

react/src/components/DeploymentConfigurationSection.tsx

Lines changed: 110 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,58 @@
22
@license
33
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
44
*/
5+
import { DeploymentConfigurationSectionDeleteMutation } from '../__generated__/DeploymentConfigurationSectionDeleteMutation.graphql';
56
import type {
67
DeploymentConfigurationSection_deployment$data,
78
DeploymentConfigurationSection_deployment$key,
89
} from '../__generated__/DeploymentConfigurationSection_deployment.graphql';
910
import type { DeploymentRevisionDetail_revision$key } from '../__generated__/DeploymentRevisionDetail_revision.graphql';
11+
import { useWebUINavigate } from '../hooks';
1012
import DeploymentRevisionDetail from './DeploymentRevisionDetail';
1113
import DeploymentRevisionDetailDrawer from './DeploymentRevisionDetailDrawer';
1214
import DeploymentRevisionHistoryTab from './DeploymentRevisionHistoryTab';
1315
import DeploymentSettingModal from './DeploymentSettingModal';
1416
import DeploymentTagChips from './DeploymentTagChips';
1517
import ErrorBoundaryWithNullFallback from './ErrorBoundaryWithNullFallback';
16-
import { EditOutlined, LoadingOutlined, PlusOutlined } from '@ant-design/icons';
18+
import {
19+
DeleteFilled,
20+
EditOutlined,
21+
LoadingOutlined,
22+
MoreOutlined,
23+
PlusOutlined,
24+
} from '@ant-design/icons';
1725
import { useToggle } from 'ahooks';
1826
import {
1927
Alert,
28+
App,
2029
Button,
2130
Descriptions,
31+
Dropdown,
2232
Empty,
2333
Skeleton,
34+
Space,
2435
Typography,
2536
theme,
2637
} from 'antd';
2738
import {
2839
BAICard,
40+
BAIConfirmModalWithInput,
2941
BAIFetchKeyButton,
3042
BAIFlex,
3143
BAIId,
3244
BAIText,
3345
BAIUnmountAfterClose,
3446
BooleanTag,
3547
filterOutEmpty,
48+
toLocalId,
49+
useBAILogger,
3650
useInterval,
3751
} from 'backend.ai-ui';
3852
import { parseAsStringLiteral, useQueryState } from 'nuqs';
3953
import React, { Suspense, useState } from 'react';
4054
import { useTranslation } from 'react-i18next';
41-
import { graphql, useFragment } from 'react-relay';
55+
import { graphql, useFragment, useMutation } from 'react-relay';
56+
import { useLocation } from 'react-router-dom';
4257

4358
interface DeploymentConfigurationSectionProps {
4459
deploymentFrgmt: DeploymentConfigurationSection_deployment$key | null;
@@ -156,6 +171,10 @@ const DeploymentConfigurationSection: React.FC<
156171

157172
const { t } = useTranslation();
158173
const { token } = theme.useToken();
174+
const { message } = App.useApp();
175+
const { logger } = useBAILogger();
176+
const webuiNavigate = useWebUINavigate();
177+
const location = useLocation();
159178

160179
const deployment = useFragment(
161180
graphql`
@@ -218,6 +237,47 @@ const DeploymentConfigurationSection: React.FC<
218237
settingModalOpen,
219238
{ setLeft: closeSettingModal, setRight: openSettingModal },
220239
] = useToggle(false);
240+
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
241+
242+
const [commitDeleteMutation, isInFlightDeleteMutation] =
243+
useMutation<DeploymentConfigurationSectionDeleteMutation>(graphql`
244+
mutation DeploymentConfigurationSectionDeleteMutation(
245+
$input: DeleteDeploymentInput!
246+
) {
247+
deleteModelDeployment(input: $input) {
248+
id
249+
}
250+
}
251+
`);
252+
253+
const deploymentName = deployment?.metadata.name ?? '';
254+
const isAdminContext = location.pathname.startsWith('/admin-deployments');
255+
const listPath = isAdminContext ? '/admin-deployments' : '/deployments';
256+
257+
const handleDelete = () => {
258+
if (!deployment?.id) return;
259+
commitDeleteMutation({
260+
variables: {
261+
input: {
262+
id: toLocalId(deployment.id) ?? deployment.id,
263+
},
264+
},
265+
onCompleted: (_response, errors) => {
266+
if (errors && errors.length > 0) {
267+
logger.error('Failed to delete deployment', errors);
268+
message.error(t('deployment.FailedToDeleteDeployment'));
269+
return;
270+
}
271+
message.success(t('deployment.DeploymentDeleted'));
272+
setIsDeleteModalOpen(false);
273+
webuiNavigate(listPath);
274+
},
275+
onError: (error) => {
276+
logger.error('Failed to delete deployment', error);
277+
message.error(t('deployment.FailedToDeleteDeployment'));
278+
},
279+
});
280+
};
221281

222282
const handleShowRevisionDrawer = (
223283
frgmt: DeploymentRevisionDetail_revision$key,
@@ -249,13 +309,33 @@ const DeploymentConfigurationSection: React.FC<
249309
value=""
250310
onChange={onRefetch}
251311
/>
252-
<Button
253-
icon={<EditOutlined />}
254-
disabled={isDeploymentDestroying}
255-
onClick={openSettingModal}
256-
>
257-
{t('button.Edit')}
258-
</Button>
312+
<Space.Compact>
313+
<Button
314+
icon={<EditOutlined />}
315+
disabled={isDeploymentDestroying}
316+
onClick={openSettingModal}
317+
>
318+
{t('button.Edit')}
319+
</Button>
320+
<Dropdown
321+
trigger={['click']}
322+
menu={{
323+
items: [
324+
{
325+
key: 'delete',
326+
label: t('deployment.DeleteDeployment'),
327+
icon: <DeleteFilled />,
328+
danger: true,
329+
disabled:
330+
isDeploymentDestroying || isInFlightDeleteMutation,
331+
onClick: () => setIsDeleteModalOpen(true),
332+
},
333+
],
334+
}}
335+
>
336+
<Button icon={<MoreOutlined />} aria-label={t('button.More')} />
337+
</Dropdown>
338+
</Space.Compact>
259339
</BAIFlex>
260340
}
261341
styles={{ body: { paddingTop: 0 } }}
@@ -359,6 +439,27 @@ const DeploymentConfigurationSection: React.FC<
359439
onClose={() => setDrawerState(null)}
360440
/>
361441
</BAIUnmountAfterClose>
442+
<BAIConfirmModalWithInput
443+
open={isDeleteModalOpen}
444+
title={t('deployment.DeleteDeployment')}
445+
content={
446+
<BAIFlex direction="column" gap="md" align="stretch">
447+
<Alert type="warning" title={t('dialog.warning.CannotBeUndone')} />
448+
<BAIFlex>
449+
<Typography.Text style={{ marginRight: token.marginXXS }}>
450+
{t('dialog.TypeNameToConfirmDeletion')}
451+
</Typography.Text>
452+
(<Typography.Text code>{deploymentName}</Typography.Text>)
453+
</BAIFlex>
454+
</BAIFlex>
455+
}
456+
confirmText={deploymentName}
457+
inputProps={{ placeholder: deploymentName }}
458+
okText={t('button.Delete')}
459+
okButtonProps={{ loading: isInFlightDeleteMutation }}
460+
onOk={handleDelete}
461+
onCancel={() => setIsDeleteModalOpen(false)}
462+
/>
362463
</>
363464
);
364465
};

resources/i18n/de.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
"Generate": "Generieren",
363363
"GoBackToStartPage": "Zurück zur Seite {{title}}",
364364
"Info": "Info",
365+
"More": "Mehr",
365366
"Move": "Verschieben",
366367
"Next": "Weiter",
367368
"No": "Nein",

resources/i18n/el.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
"Generate": "Παράγω",
363363
"GoBackToStartPage": "Επιστροφή στη σελίδα {{title}}",
364364
"Info": "Πληροφορίες",
365+
"More": "Περισσότερα",
365366
"Move": "Μετακίνηση",
366367
"Next": "Επόμενο",
367368
"No": "Οχι",

resources/i18n/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
"Generate": "Generate",
363363
"GoBackToStartPage": "Go back to the {{title}} page",
364364
"Info": "Info",
365+
"More": "More",
365366
"Move": "Move",
366367
"Next": "Next",
367368
"No": "No",

resources/i18n/es.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
"Generate": "Genere",
363363
"GoBackToStartPage": "Volver a la página {{title}}",
364364
"Info": "Info",
365+
"More": "Más",
365366
"Move": "Mover",
366367
"Next": "Siguiente",
367368
"No": "No",

resources/i18n/fi.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
"Generate": "Luo",
363363
"GoBackToStartPage": "Palaa sivulle {{title}}",
364364
"Info": "Tiedot",
365+
"More": "Lisää",
365366
"Move": "Siirrä",
366367
"Next": "Seuraava",
367368
"No": "Ei",

resources/i18n/fr.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
"Generate": "produire",
363363
"GoBackToStartPage": "Retour à la page {{title}}",
364364
"Info": "Info",
365+
"More": "Plus",
365366
"Move": "Déplacer",
366367
"Next": "Suivant",
367368
"No": "Non",

resources/i18n/id.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
"Generate": "Hasilkan",
363363
"GoBackToStartPage": "Kembali ke halaman {{title}}",
364364
"Info": "Info",
365+
"More": "Selengkapnya",
365366
"Move": "Pindahkan",
366367
"Next": "Berikutnya",
367368
"No": "Tidak",

resources/i18n/it.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
"Generate": "creare",
363363
"GoBackToStartPage": "Torna alla pagina {{title}}",
364364
"Info": "Info",
365+
"More": "Altro",
365366
"Move": "Sposta",
366367
"Next": "Avanti",
367368
"No": "No",

resources/i18n/ja.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
"Generate": "生む",
363363
"GoBackToStartPage": "{{title}}ページに戻る",
364364
"Info": "情報",
365+
"More": "その他",
365366
"Move": "移動",
366367
"Next": "次のページ",
367368
"No": "番号",

0 commit comments

Comments
 (0)