Skip to content

Commit 305eab2

Browse files
committed
refactor(FR-2848): use DeleteFilled for permanent delete, DeleteOutlined for trash (#7314)
Resolves #7311(FR-2848) ## Summary Standardize trash-bin icon semantics across the entire WebUI: - **`DeleteFilled`** = permanent / irreversible delete - **`DeleteOutlined`** = move to trash / soft delete / reversible form-row removal This is an icon-only refactor. No behavior, mutation, confirmation modal, or i18n string is changed. ## Changes ### `BAITrashBinIcon` retirement The custom `BAITrashBinIcon` (a filled silhouette SVG) was previously used for both reversible "Move to Trash" actions (e.g. `data.folders.MoveToTrash`) and irreversible "Delete forever" actions, which made the two visually indistinguishable. It is now replaced everywhere by the standard antd `DeleteOutlined` / `DeleteFilled` pair so the semantic is unambiguous at a glance. The `BAITrashBinIcon` component file itself is **kept** in `backend.ai-ui` for potential future use as a "Trash location" indicator (page header, tab label, sidebar destination), but no longer has any active usage. ### Switched `DeleteOutlined` → `DeleteFilled` (permanent delete) | File | Justification | |---|---| | `react/src/components/AutoScalingRuleList.tsx` | `DeleteAutoScalingRuleInput` mutation | | `react/src/components/AutoScalingRuleListLegacy.tsx` | `delete_endpoint_auto_scaling_rule_node` | | `react/src/components/ContainerRegistryList.tsx` | `BAIConfirmModalWithInput` typed-confirmation flow | | `react/src/components/CustomizedImageList.tsx` | `untag_image_from_registry` | | `react/src/components/DeploymentAccessTokensTab.tsx` | `DeploymentAccessTokensTabDeleteMutation` | | `react/src/components/DeploymentList.tsx` | `DeleteDeploymentInput` | | `react/src/components/EndpointList.tsx` | terminate endpoint | | `react/src/components/ErrorLogList.tsx` | clear all error logs (irrecoverable from UI) | | `react/src/components/KeypairResourcePolicyList.tsx` | policy delete | | `react/src/components/ProjectResourcePolicyList.tsx` | policy delete | | `react/src/components/PrometheusQueryPresetNodes.tsx` | preset delete | | `react/src/components/ResourceGroupList.tsx` | resource group delete | | `react/src/components/ResourcePresetList.tsx` | preset delete | | `react/src/components/ShellScriptEditModal.tsx` | typed-confirmation delete | | `react/src/components/UserCredentialList.tsx` | credential delete | | `react/src/components/UserResourcePolicyList.tsx` | policy delete | | `react/src/pages/AIAgentPage.tsx` | agent delete | | `react/src/pages/EndpointDetailPage.tsx` | auto-scaling rule delete | | `react/src/pages/ProjectAdminDeploymentsPage.tsx` | deployment delete | ### Switched `BAITrashBinIcon` → `DeleteFilled` (permanent delete) | File | Justification | |---|---| | `packages/backend.ai-ui/src/components/fragments/BAIArtifactRevisionDeleteButton.tsx` | revision permanent delete (`reservoirPage.RemoveThisVersion`) | | `packages/backend.ai-ui/src/components/baiClient/FileExplorer/FileItemControls.tsx` | single-file delete in VFolder file explorer (no trash for files) | | `packages/backend.ai-ui/src/components/baiClient/FileExplorer/ExplorerActionControls.tsx` | bulk file delete in file explorer | | `react/src/components/UserManagement.tsx` | `credential.PermanentlyDelete` + bulk delete | | `react/src/components/AdminDeploymentPresetNodes.tsx` | preset delete (`button.Delete`) | | `react/src/components/RoleAssignmentTab.tsx` | `rbac.RevokeUser` + danger button | | `react/src/components/RolePermissionTab.tsx` | `rbac.RemovePermission` | | `react/src/pages/AdminModelCardListPage.tsx` | model card delete + bulk delete | | `react/src/pages/RBACManagementPage.tsx` | `rbac.PurgeRole` | | `react/src/components/VFolderNodes.tsx` (line 205) | `data.folders.Delete` (delete-from-trash, permanent) | | `react/src/components/VFolderNodesV2.tsx` (line 204) | `data.folders.Delete` (delete-from-trash, permanent) | ### Switched `BAITrashBinIcon` → `DeleteOutlined` (move to trash) | File | Justification | |---|---| | `packages/backend.ai-ui/src/components/fragments/BAIVFolderDeleteButton.tsx` | always rendered under `Tooltip title="data.folders.MoveToTrash"` | | `packages/backend.ai-ui/src/components/fragments/BAIVFolderDeleteButtonV2.tsx` | always rendered under `Tooltip title="data.folders.MoveToTrash"` | | `react/src/components/VFolderNodes.tsx` (line 169) | `data.folders.MoveToTrash` row action | | `react/src/components/VFolderNodesV2.tsx` (line 163) | `data.folders.MoveToTrash` row action | ### Files left unchanged (kept `DeleteOutlined`) | File | Justification | |---|---| | `react/src/components/RoleFormModal.tsx` | `Form.List` row removal — reversible while form is unsubmitted | | `react/src/components/ManageAppsModal.tsx` | `Form.List` row removal — reversible while form is unsubmitted | | `packages/backend.ai-ui/src/components/Table/BAINameActionCell.stories.tsx` | abstract demo story; intentionally generic | ### Storybook - `BAIConfirmModalWithInput.stories.tsx` and `BAIDeleteConfirmModal.stories.tsx` updated to use `DeleteFilled` so the trigger reflects the new convention (these modals exclusively front permanent-delete flows). ### Other - `packages/backend.ai-ui/src/components/fragments/BAIProjectTable.tsx` already uses `DeleteFilled` for the project Purge action (paired with a `BanIcon` for the reversible Inactivate). No icon change here, included for consistency reference. ## Out-of-scope follow-ups The following call sites still use `Popconfirm` or `modal.confirm` for permanent deletion instead of `BAIConfirmModalWithInput`. They are flagged here for a follow-up; the icon swap is correct, but the modal type should also migrate per `.claude/rules/destructive-confirmation.md`: - `AutoScalingRuleListLegacy.tsx` (Popconfirm L183-255) - `UserCredentialList.tsx` (modal.confirm L413) - `EndpointDetailPage.tsx` (Popconfirm L1115-1192) - `AutoScalingRuleList.tsx` (modal.confirm L513) - `ResourceGroupList.tsx` (modal.confirm L157) - `BAIProjectTable.tsx` purge (uses `modal.confirm`) ## Test Plan - [x] `bash scripts/verify.sh`: Relay PASS, Lint PASS, Format PASS. TypeScript fails only on pre-existing errors in `packages/backend.ai-client/src/client.ts` and `react/src/components/DeleteForeverVFolderModalV2.tsx` — both reproduce on a clean `main` checkout and are unrelated to this PR. - [ ] Visual spot-check on dev server: filled trash for permanent delete, outlined trash for move-to-trash.
1 parent f817651 commit 305eab2

35 files changed

Lines changed: 86 additions & 124 deletions

packages/backend.ai-ui/src/components/BAIConfirmModalWithInput.stories.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import BAIButton from './BAIButton';
44
import BAIConfirmModalWithInput from './BAIConfirmModalWithInput';
55
import BAIText from './BAIText';
6-
import { DeleteOutlined } from '@ant-design/icons';
6+
import { DeleteFilled } from '@ant-design/icons';
77
import type { Meta, StoryObj } from '@storybook/react-vite';
88
import { theme } from 'antd';
99
import { useState } from 'react';
@@ -117,9 +117,7 @@ export const CustomIcon: Story = {
117117
{...args}
118118
open={open}
119119
icon={
120-
<DeleteOutlined
121-
style={{ color: token.colorError, marginRight: 5 }}
122-
/>
120+
<DeleteFilled style={{ color: token.colorError, marginRight: 5 }} />
123121
}
124122
content={
125123
<BAIText>

packages/backend.ai-ui/src/components/BAIDeleteConfirmModal.stories.tsx

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import BAIButton from './BAIButton';
44
import BAIDeleteConfirmModal from './BAIDeleteConfirmModal';
55
import BAIFlex from './BAIFlex';
6-
import { DeleteOutlined, FolderOutlined } from '@ant-design/icons';
6+
import { DeleteFilled, FolderOutlined } from '@ant-design/icons';
77
import type { Meta, StoryObj } from '@storybook/react-vite';
88
import { Checkbox, Space, Tag } from 'antd';
99
import { useState } from 'react';
@@ -51,11 +51,7 @@ export const SingleItem: Story = {
5151
const [open, setOpen] = useState(false);
5252
return (
5353
<>
54-
<BAIButton
55-
danger
56-
icon={<DeleteOutlined />}
57-
onClick={() => setOpen(true)}
58-
>
54+
<BAIButton danger icon={<DeleteFilled />} onClick={() => setOpen(true)}>
5955
Delete Item
6056
</BAIButton>
6157
<BAIDeleteConfirmModal
@@ -82,11 +78,7 @@ export const SingleItemWithInput: Story = {
8278
const [open, setOpen] = useState(false);
8379
return (
8480
<>
85-
<BAIButton
86-
danger
87-
icon={<DeleteOutlined />}
88-
onClick={() => setOpen(true)}
89-
>
81+
<BAIButton danger icon={<DeleteFilled />} onClick={() => setOpen(true)}>
9082
Delete (Confirm Required)
9183
</BAIButton>
9284
<BAIDeleteConfirmModal
@@ -121,11 +113,7 @@ export const MultipleItems: Story = {
121113
];
122114
return (
123115
<>
124-
<BAIButton
125-
danger
126-
icon={<DeleteOutlined />}
127-
onClick={() => setOpen(true)}
128-
>
116+
<BAIButton danger icon={<DeleteFilled />} onClick={() => setOpen(true)}>
129117
Delete 5 Items
130118
</BAIButton>
131119
<BAIDeleteConfirmModal
@@ -156,11 +144,7 @@ export const ManyItems: Story = {
156144
}));
157145
return (
158146
<>
159-
<BAIButton
160-
danger
161-
icon={<DeleteOutlined />}
162-
onClick={() => setOpen(true)}
163-
>
147+
<BAIButton danger icon={<DeleteFilled />} onClick={() => setOpen(true)}>
164148
Delete 50 Items
165149
</BAIButton>
166150
<BAIDeleteConfirmModal
@@ -219,11 +203,7 @@ export const CustomRenderedItems: Story = {
219203
];
220204
return (
221205
<>
222-
<BAIButton
223-
danger
224-
icon={<DeleteOutlined />}
225-
onClick={() => setOpen(true)}
226-
>
206+
<BAIButton danger icon={<DeleteFilled />} onClick={() => setOpen(true)}>
227207
Delete Folders
228208
</BAIButton>
229209
<BAIDeleteConfirmModal
@@ -254,11 +234,7 @@ export const WithExtraContent: Story = {
254234
];
255235
return (
256236
<>
257-
<BAIButton
258-
danger
259-
icon={<DeleteOutlined />}
260-
onClick={() => setOpen(true)}
261-
>
237+
<BAIButton danger icon={<DeleteFilled />} onClick={() => setOpen(true)}>
262238
Purge Users
263239
</BAIButton>
264240
<BAIDeleteConfirmModal
@@ -290,11 +266,7 @@ export const EmptyItems: Story = {
290266
const [open, setOpen] = useState(false);
291267
return (
292268
<>
293-
<BAIButton
294-
danger
295-
icon={<DeleteOutlined />}
296-
onClick={() => setOpen(true)}
297-
>
269+
<BAIButton danger icon={<DeleteFilled />} onClick={() => setOpen(true)}>
298270
Delete (No Selection)
299271
</BAIButton>
300272
<BAIDeleteConfirmModal

packages/backend.ai-ui/src/components/baiClient/FileExplorer/ExplorerActionControls.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { initiateDownload } from '../../../helper';
22
import { useTanMutation } from '../../../helper/reactQueryAlias';
3-
import { BAITrashBinIcon } from '../../../icons';
43
import BAIButton from '../../BAIButton';
54
import BAIFlex from '../../BAIFlex';
65
import BAISelectionLabel from '../../BAISelectionLabel';
@@ -14,6 +13,7 @@ import DeleteSelectedItemsModal, {
1413
} from './DeleteSelectedItemsModal';
1514
import { useUploadVFolderFiles } from './hooks';
1615
import {
16+
DeleteFilled,
1717
FileAddOutlined,
1818
FolderAddOutlined,
1919
UploadOutlined,
@@ -128,7 +128,7 @@ const ExplorerActionControls: React.FC<ExplorerActionControlsProps> = ({
128128
<Tooltip title={t('general.button.Delete')} placement="topLeft">
129129
<Button
130130
disabled={!enableDelete}
131-
icon={<BAITrashBinIcon style={{ color: token.colorError }} />}
131+
icon={<DeleteFilled style={{ color: token.colorError }} />}
132132
onClick={() => {
133133
toggleDeleteModal();
134134
}}

packages/backend.ai-ui/src/components/baiClient/FileExplorer/FileItemControls.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { convertToBinaryUnit, initiateDownload } from '../../../helper';
22
import { useTanMutation } from '../../../helper/reactQueryAlias';
3-
import { BAITrashBinIcon } from '../../../icons';
43
import BAIButton, { BAIButtonProps } from '../../BAIButton';
54
import BAIFlex from '../../BAIFlex';
65
import useConnectedBAIClient from '../../provider/BAIClientProvider/hooks/useConnectedBAIClient';
76
import { VFolderFile } from '../../provider/BAIClientProvider/types';
87
import { FolderInfoContext } from './BAIFileExplorer';
9-
import { MoreOutlined } from '@ant-design/icons';
8+
import { DeleteFilled, MoreOutlined } from '@ant-design/icons';
109
import { App, theme, Dropdown, Tooltip } from 'antd';
1110
import { DownloadIcon, EditIcon } from 'lucide-react';
1211
import { use, useState } from 'react';
@@ -110,7 +109,7 @@ const FileItemControls: React.FC<FileItemControlsProps> = ({
110109
<BAIButton
111110
type="text"
112111
size="small"
113-
icon={<BAITrashBinIcon style={{ color: token.colorError }} />}
112+
icon={<DeleteFilled style={{ color: token.colorError }} />}
114113
disabled={!enableDelete}
115114
onClick={(e) => {
116115
e.stopPropagation();

packages/backend.ai-ui/src/components/fragments/BAIArtifactRevisionDeleteButton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { BAIArtifactRevisionDeleteButtonFragment$key } from '../../__generated__/BAIArtifactRevisionDeleteButtonFragment.graphql';
2-
import { BAITrashBinIcon } from '../../icons';
32
import BAIButton, { BAIButtonProps } from '../BAIButton';
3+
import { DeleteFilled } from '@ant-design/icons';
44
import { theme } from 'antd';
55
import * as _ from 'lodash-es';
66
import { graphql, useFragment } from 'react-relay';
@@ -39,7 +39,7 @@ const BAIArtifactRevisionDeleteButton = ({
3939

4040
return (
4141
<BAIButton
42-
icon={<BAITrashBinIcon />}
42+
icon={<DeleteFilled />}
4343
disabled={isDisabled}
4444
type="text"
4545
style={{

packages/backend.ai-ui/src/components/fragments/BAIProjectTable.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import BAITag from '../BAITag';
1313
import BAIText from '../BAIText';
1414
import { BAIColumnsType, BAITable, BAITableProps } from '../Table';
1515
import AllowedVfolderHostsWithPermission from './BAIAllowedVfolderHostsWithPermission';
16-
import { DeleteOutlined, SettingOutlined } from '@ant-design/icons';
16+
import { DeleteFilled, SettingOutlined } from '@ant-design/icons';
1717
import { App, Popconfirm, Tag, theme } from 'antd';
1818
import dayjs from 'dayjs';
1919
import * as _ from 'lodash-es';
@@ -209,7 +209,7 @@ const BAIProjectTable = ({
209209
<BAIButton
210210
type="text"
211211
icon={
212-
<DeleteOutlined
212+
<DeleteFilled
213213
style={{
214214
color:
215215
_.get(record, 'type') === 'MODEL_STORE'

packages/backend.ai-ui/src/components/fragments/BAIVFolderDeleteButton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { BAIVFolderDeleteButtonFragment$key } from '../../__generated__/BAIVFolderDeleteButtonFragment.graphql';
2-
import { BAITrashBinIcon } from '../../icons';
32
import BAIButton from '../BAIButton';
3+
import { DeleteOutlined } from '@ant-design/icons';
44
import { theme, type ButtonProps } from 'antd';
55
import * as _ from 'lodash-es';
66
import { graphql, useFragment } from 'react-relay';
@@ -30,7 +30,7 @@ const BAIVFolderDeleteButton = ({
3030

3131
return (
3232
<BAIButton
33-
icon={<BAITrashBinIcon />}
33+
icon={<DeleteOutlined />}
3434
disabled={buttonProps.disabled || !isDeletable}
3535
style={{
3636
color:

packages/backend.ai-ui/src/components/fragments/BAIVFolderDeleteButtonV2.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { BAIVFolderDeleteButtonV2Fragment$key } from '../../__generated__/BAIVFolderDeleteButtonV2Fragment.graphql';
2-
import { BAITrashBinIcon } from '../../icons';
32
import BAIButton from '../BAIButton';
3+
import { DeleteOutlined } from '@ant-design/icons';
44
import { theme, type ButtonProps } from 'antd';
55
import * as _ from 'lodash-es';
66
import { graphql, useFragment } from 'react-relay';
@@ -35,7 +35,7 @@ const BAIVFolderDeleteButtonV2 = ({
3535

3636
return (
3737
<BAIButton
38-
icon={<BAITrashBinIcon />}
38+
icon={<DeleteOutlined />}
3939
disabled={buttonProps.disabled}
4040
style={{
4141
color: isEnabled ? token.colorError : token.colorTextDisabled,

react/src/components/AdminDeploymentPresetNodes.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@ import type {
77
AdminDeploymentPresetNodesFragment$key,
88
} from '../__generated__/AdminDeploymentPresetNodesFragment.graphql';
99
import type { AdminDeploymentPresetNodesImagesQuery } from '../__generated__/AdminDeploymentPresetNodesImagesQuery.graphql';
10-
import { SettingOutlined } from '@ant-design/icons';
10+
import { DeleteFilled, SettingOutlined } from '@ant-design/icons';
1111
import {
1212
BAIColumnType,
1313
BAINameActionCell,
1414
BAITable,
1515
BAITableProps,
16-
BAITrashBinIcon,
1716
filterOutEmpty,
1817
filterOutNullAndUndefined,
1918
toLocalId,
@@ -159,7 +158,7 @@ const AdminDeploymentPresetNodes: React.FC<AdminDeploymentPresetNodesProps> = ({
159158
{
160159
key: 'delete',
161160
title: t('button.Delete'),
162-
icon: <BAITrashBinIcon />,
161+
icon: <DeleteFilled />,
163162
type: 'danger' as const,
164163
onClick: () => onDelete?.(preset),
165164
},

react/src/components/AutoScalingRuleList.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@ import { AutoScalingRuleListQuery } from '../__generated__/AutoScalingRuleListQu
1212
import { useBAIPaginationOptionStateOnSearchParam } from '../hooks/reactPaginationQueryOptions';
1313
import { useBAISettingUserState } from '../hooks/useBAISetting';
1414
import AutoScalingRuleEditorModal from './AutoScalingRuleEditorModal';
15-
import {
16-
DeleteOutlined,
17-
PlusOutlined,
18-
SettingOutlined,
19-
} from '@ant-design/icons';
15+
import { DeleteFilled, PlusOutlined, SettingOutlined } from '@ant-design/icons';
2016
import { App, Button, Tag, Tooltip, Typography } from 'antd';
2117
import {
2218
BAIFetchKeyButton,
@@ -218,7 +214,7 @@ const AutoScalingRuleListNodes: React.FC<AutoScalingRuleListNodesProps> = ({
218214
{
219215
key: 'delete',
220216
title: t('button.Delete'),
221-
icon: <DeleteOutlined />,
217+
icon: <DeleteFilled />,
222218
type: 'danger',
223219
disabled: isEndpointDestroying || !isOwnedByCurrentUser,
224220
onClick: () => onDeleteRule(row.id, row.metricName ?? ''),

0 commit comments

Comments
 (0)