Skip to content

Commit 0b90d41

Browse files
committed
feat(FR-2846): move deployment delete into a more menu next to edit
1 parent d5f78df commit 0b90d41

2 files changed

Lines changed: 101 additions & 2 deletions

File tree

react/src/components/DeploymentConfigurationSection.tsx

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,38 @@
22
@license
33
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
44
*/
5+
import { DeploymentConfigurationSectionDeleteMutation } from '../__generated__/DeploymentConfigurationSectionDeleteMutation.graphql';
56
import { DeploymentConfigurationSectionQuery } from '../__generated__/DeploymentConfigurationSectionQuery.graphql';
67
import type { DeploymentRevisionDetail_revision$key } from '../__generated__/DeploymentRevisionDetail_revision.graphql';
8+
import { useWebUINavigate } from '../hooks';
79
import DeploymentRevisionDetail from './DeploymentRevisionDetail';
810
import DeploymentRevisionDetailDrawer from './DeploymentRevisionDetailDrawer';
911
import DeploymentRevisionHistoryTab from './DeploymentRevisionHistoryTab';
1012
import DeploymentSettingModal from './DeploymentSettingModal';
1113
import DeploymentTagChips from './DeploymentTagChips';
1214
import ErrorBoundaryWithNullFallback from './ErrorBoundaryWithNullFallback';
13-
import { EditOutlined, LoadingOutlined, PlusOutlined } from '@ant-design/icons';
15+
import {
16+
DeleteFilled,
17+
EditOutlined,
18+
LoadingOutlined,
19+
MoreOutlined,
20+
PlusOutlined,
21+
} from '@ant-design/icons';
1422
import { useToggle } from 'ahooks';
1523
import {
1624
Alert,
25+
App,
1726
Button,
1827
Descriptions,
28+
Dropdown,
1929
Empty,
2030
Skeleton,
2131
Typography,
2232
theme,
2333
} from 'antd';
2434
import {
2535
BAICard,
36+
BAIConfirmModalWithInput,
2637
BAIFetchKeyButton,
2738
BAIFlex,
2839
BAIId,
@@ -31,12 +42,15 @@ import {
3142
BooleanTag,
3243
INITIAL_FETCH_KEY,
3344
filterOutEmpty,
45+
toLocalId,
46+
useBAILogger,
3447
useInterval,
3548
} from 'backend.ai-ui';
3649
import { parseAsStringLiteral, useQueryState } from 'nuqs';
3750
import React, { Suspense, useState } from 'react';
3851
import { useTranslation } from 'react-i18next';
39-
import { graphql, useLazyLoadQuery } from 'react-relay';
52+
import { graphql, useLazyLoadQuery, useMutation } from 'react-relay';
53+
import { useLocation } from 'react-router-dom';
4054

4155
interface DeploymentConfigurationSectionProps {
4256
deploymentId: string;
@@ -262,6 +276,10 @@ const DeploymentConfigurationCards: React.FC<{
262276
'use memo';
263277
const { t } = useTranslation();
264278
const { token } = theme.useToken();
279+
const { message } = App.useApp();
280+
const { logger } = useBAILogger();
281+
const webuiNavigate = useWebUINavigate();
282+
const location = useLocation();
265283

266284
const [activeRevisionTab, setActiveRevisionTab] = useQueryState(
267285
'revisionTab',
@@ -278,6 +296,18 @@ const DeploymentConfigurationCards: React.FC<{
278296
settingModalOpen,
279297
{ setLeft: closeSettingModal, setRight: openSettingModal },
280298
] = useToggle(false);
299+
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
300+
301+
const [commitDeleteMutation, isInFlightDeleteMutation] =
302+
useMutation<DeploymentConfigurationSectionDeleteMutation>(graphql`
303+
mutation DeploymentConfigurationSectionDeleteMutation(
304+
$input: DeleteDeploymentInput!
305+
) {
306+
deleteModelDeployment(input: $input) {
307+
id
308+
}
309+
}
310+
`);
281311

282312
const { deployment } = useLazyLoadQuery<DeploymentConfigurationSectionQuery>(
283313
graphql`
@@ -337,6 +367,35 @@ const DeploymentConfigurationCards: React.FC<{
337367
// the deploying revision matches the current revision.
338368
useInterval(onRefetch, isDeployingDifferentRevision ? 5000 : null);
339369

370+
const deploymentName = deployment?.metadata.name ?? '';
371+
const isAdminContext = location.pathname.startsWith('/admin-deployments');
372+
const listPath = isAdminContext ? '/admin-deployments' : '/deployments';
373+
374+
const handleDelete = () => {
375+
if (!deployment?.id) return;
376+
commitDeleteMutation({
377+
variables: {
378+
input: {
379+
id: toLocalId(deployment.id) ?? deployment.id,
380+
},
381+
},
382+
onCompleted: (_response, errors) => {
383+
if (errors && errors.length > 0) {
384+
logger.error('Failed to delete deployment', errors);
385+
message.error(t('deployment.FailedToDeleteDeployment'));
386+
return;
387+
}
388+
message.success(t('deployment.DeploymentDeleted'));
389+
setIsDeleteModalOpen(false);
390+
webuiNavigate(listPath);
391+
},
392+
onError: (error) => {
393+
logger.error('Failed to delete deployment', error);
394+
message.error(t('deployment.FailedToDeleteDeployment'));
395+
},
396+
});
397+
};
398+
340399
return (
341400
<>
342401
<BAICard
@@ -351,6 +410,24 @@ const DeploymentConfigurationCards: React.FC<{
351410
>
352411
{t('button.Edit')}
353412
</Button>
413+
<Dropdown
414+
trigger={['click']}
415+
menu={{
416+
items: [
417+
{
418+
key: 'delete',
419+
label: t('deployment.DeleteDeployment'),
420+
icon: <DeleteFilled />,
421+
danger: true,
422+
disabled:
423+
isDeploymentDestroying || isInFlightDeleteMutation,
424+
onClick: () => setIsDeleteModalOpen(true),
425+
},
426+
],
427+
}}
428+
>
429+
<Button icon={<MoreOutlined />} aria-label={t('button.More')} />
430+
</Dropdown>
354431
</BAIFlex>
355432
}
356433
styles={{ body: { paddingTop: 0 } }}
@@ -445,6 +522,27 @@ const DeploymentConfigurationCards: React.FC<{
445522
if (success) onRefetch();
446523
}}
447524
/>
525+
<BAIConfirmModalWithInput
526+
open={isDeleteModalOpen}
527+
title={t('deployment.DeleteDeployment')}
528+
content={
529+
<BAIFlex direction="column" gap="md" align="stretch">
530+
<Alert type="warning" title={t('dialog.warning.CannotBeUndone')} />
531+
<BAIFlex>
532+
<Typography.Text style={{ marginRight: token.marginXXS }}>
533+
{t('dialog.TypeNameToConfirmDeletion')}
534+
</Typography.Text>
535+
(<Typography.Text code>{deploymentName}</Typography.Text>)
536+
</BAIFlex>
537+
</BAIFlex>
538+
}
539+
confirmText={deploymentName}
540+
inputProps={{ placeholder: deploymentName }}
541+
okText={t('button.Delete')}
542+
okButtonProps={{ loading: isInFlightDeleteMutation }}
543+
onOk={handleDelete}
544+
onCancel={() => setIsDeleteModalOpen(false)}
545+
/>
448546
</>
449547
);
450548
};

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",

0 commit comments

Comments
 (0)