Skip to content

fix(FR-2819): use BAIConfirmModalWithInput for irreversible delete actions#7370

Merged
graphite-app[bot] merged 1 commit into
mainfrom
fix/FR-2819-use-bai-confirm-modal
May 18, 2026
Merged

fix(FR-2819): use BAIConfirmModalWithInput for irreversible delete actions#7370
graphite-app[bot] merged 1 commit into
mainfrom
fix/FR-2819-use-bai-confirm-modal

Conversation

@ironAiken2
Copy link
Copy Markdown
Contributor

@ironAiken2 ironAiken2 commented May 12, 2026

Resolves #7253(FR-2819)

Summary

Sweep all permanent-delete flows that still used modal.confirm / Popconfirm / ad-hoc dialogs and move them onto the project's typed-confirmation pattern (.claude/rules/destructive-confirmation.md). In the process, consolidate two overlapping componentsBAIConfirmModalWithInput and BAIDeleteConfirmModal — into a single API so every irreversible delete in the app looks and behaves the same.

What changed

Component consolidation

  • Remove BAIConfirmModalWithInput (component, stories, exports). All 16 call sites are migrated to BAIDeleteConfirmModal.
  • Extend BAIDeleteConfirmModal:
    • Add requireConfirmInput to force typed confirmation for single-item deletes.
    • Add target prop — when set (and no description is provided) the modal renders the localized "Are you sure you want to permanently delete {target}?" copy. Centralizes the most common irreversible-delete sentence so call sites don't redeclare it.
  • Reinstall-confirm flows (ManageImageResourceLimitModal, ManageAppsModal) — which are confirmations but not deletes — are moved to plain BAIModal instead of a delete-shaped modal. They were only on BAIConfirmModalWithInput for the typed-input UX, which they don't actually need.

Bug fixes (the issue's scope)

  • UserCredentialList.tsx — permanent keypair deletion was a single-click modal.confirm. Now opens BAIDeleteConfirmModal with requireConfirmInput and the keypair's access_key as the confirm string.
  • AutoScalingRuleListLegacy.tsx — permanent rule deletion was a Popconfirm. Now opens BAIDeleteConfirmModal requiring the rule's identifier to be typed. Card is migrated to BAICard in the same change per project convention.

Sweep — other irreversible flows migrated

Single-click confirms / ad-hoc patterns replaced with BAIDeleteConfirmModal (+ requireConfirmInput where the item is sensitive):

  • AutoScalingRuleList.tsx (V2)
  • ContainerRegistryList.tsx
  • CustomizedImageList.tsx
  • DeleteForeverVFolderModalV2.tsx
  • DeploymentAccessTokensTab.tsx, DeploymentConfigurationSection.tsx, DeploymentList.tsx, EndpointList.tsx
  • KeypairResourcePolicyList.tsx, ProjectResourcePolicyList.tsx, UserResourcePolicyList.tsx
  • MyKeypairManagementModal.tsx
  • PrometheusPresetTab.tsx
  • PurgeUsersModal.tsx
  • ResourceGroupList.tsx, ResourcePresetList.tsx
  • RoleAssignmentTab.tsx, RolePermissionTab.tsx, RBACManagementPage.tsx
  • ShellScriptEditModal.tsx
  • UserCredentialList.tsx
  • VFolderNodes.tsx
  • AIAgentPage.tsx
  • FileExplorer/DeleteSelectedItemsModal.tsx
  • fragments/BAIProjectTable.tsx

confirmText policy

Standardized so each call site picks the safer of two options:

  • User-readable IDs (project name, vfolder name, keypair access_key, role name, …) → use the resource's name as the confirm string. The user has it on screen and can copy-type it unambiguously.
  • Cryptic / long IDs (image full path, autoscaling metric name, bulk purge across N users) → use the literal "Permanently Delete" string. Asking the user to type a 90-char Docker reference is worse UX, not better.

Activate / deactivate (reversible) flows are intentionally left as-is — those belong to FR-2825.

i18n

  • New keys across all 22 locales:
    • general.* resource-type labels (9 new entries) for the target prop.
    • dialog.title.DeleteSomething
    • comp:BAIDeleteConfirmModal.AreYouSureToPermanentlyDeleteTarget
  • Filled in previously missing keys across non-English locales (translations were already drifting; this PR brings them back in sync).
  • Fix one Korean typo: environment.ModifyImageResourceLimitReinstallRequired.

Storybook

  • Remove BAIConfirmModalWithInput.stories.tsx.
  • Add a Storybook case for the new target prop on BAIDeleteConfirmModal.

Why one API, not two

Before: BAIConfirmModalWithInput (typed-input shape) and BAIDeleteConfirmModal (item-list shape) covered overlapping use cases — the typed-input modal was being used for deletes, and call sites were duplicating copy and layout that already existed in BAIDeleteConfirmModal. After: a single component covers both the single-item and N-item delete cases, with requireConfirmInput and target handling the variants. Less surface area, less drift, fewer translation keys to keep aligned.

Checklist

  • Documentation — N/A (no user-facing manual change; convention rule unchanged)
  • Minimum required manager version — N/A
  • Specific setting for review — none
  • Minimum requirements to check during review — bash scripts/verify.sh passes; manually exercise a few migrated flows (keypair delete, autoscaling rule delete, vfolder permanent delete, bulk user purge) to confirm the OK button stays disabled until the right string is typed
  • Test case(s) — see Storybook stories and the migrated call sites; behavior across all 16 sites is now driven by one component

Copilot AI review requested due to automatic review settings May 12, 2026 07:17
@github-actions github-actions Bot added the size:L 100~500 LoC label May 12, 2026
Copy link
Copy Markdown
Contributor Author

ironAiken2 commented May 12, 2026


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • flow:merge-queue - adds this PR to the back of the merge queue
  • flow:hotfix - for urgent changes, fast-track this PR to the front of the merge queue

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has required the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@cla-assistant
Copy link
Copy Markdown

cla-assistant Bot commented May 12, 2026

CLA assistant check
All committers have signed the CLA.

@cla-assistant
Copy link
Copy Markdown

cla-assistant Bot commented May 12, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 12, 2026

Coverage Report for react-coverage (./react)

Status Category Percentage Covered / Total
🔵 Lines 6.45% 1783 / 27622
🔵 Statements 5.31% 1978 / 37233
🔵 Functions 5.17% 296 / 5716
🔵 Branches 3.71% 1293 / 34819
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
react/src/components/AutoScalingRuleList.tsx 0% 0% 0% 0% 59-395
react/src/components/AutoScalingRuleListLegacy.tsx 0% 0% 0% 0% 38-264
react/src/components/ContainerRegistryList.tsx 0% 0% 0% 0% 56-592
react/src/components/CustomizedImageList.tsx 0% 0% 0% 0% 49-538
react/src/components/DeleteForeverVFolderModalV2.tsx 0% 0% 0% 0% 29-91
react/src/components/DeploymentAccessTokensTab.tsx 0% 0% 0% 0% 57-359
react/src/components/DeploymentConfigurationSection.tsx 0% 0% 0% 0% 72-302
react/src/components/DeploymentList.tsx 0% 0% 0% 0% 50-386
react/src/components/EndpointList.tsx 0% 0% 0% 0% 52-308
react/src/components/KeypairResourcePolicyList.tsx 0% 0% 0% 0% 53-461
react/src/components/ManageAppsModal.tsx 0% 0% 0% 0% 31-333
react/src/components/ManageImageResourceLimitModal.tsx 0% 0% 0% 0% 23-246
react/src/components/MyKeypairManagementModal.tsx 0% 0% 0% 0% 77-604
react/src/components/ProjectResourcePolicyList.tsx 0% 0% 0% 0% 56-362
react/src/components/PrometheusPresetTab.tsx 0% 0% 0% 0% 37-127
react/src/components/PurgeUsersModal.tsx 0% 0% 0% 0% 37-213
react/src/components/ResourceGroupList.tsx 0% 0% 0% 0% 57-380
react/src/components/ResourcePresetList.tsx 0% 0% 0% 0% 43-252
react/src/components/RoleAssignmentTab.tsx 0% 0% 0% 0% 46-456
react/src/components/RolePermissionTab.tsx 0% 0% 0% 0% 45-174
react/src/components/ShellScriptEditModal.tsx 0% 0% 0% 0% 43-345
react/src/components/UserCredentialList.tsx 0% 0% 0% 0% 54-604
react/src/components/UserResourcePolicyList.tsx 0% 0% 0% 0% 53-366
react/src/components/VFolderNodes.tsx 0% 0% 0% 0% 48-671
react/src/pages/AIAgentPage.tsx 0% 0% 0% 0% 37-199
react/src/pages/AdminDeploymentPresetListPage.tsx 0% 0% 0% 0% 39-67
react/src/pages/ProjectAdminDeploymentsPage.tsx 0% 0% 0% 0% 37-162
react/src/pages/RBACManagementPage.tsx 0% 0% 0% 0% 50-214
Generated in workflow #716 for commit f942af5 by the Vitest Coverage Report Action

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR standardizes irreversible delete confirmations by replacing simple confirm dialogs with BAIConfirmModalWithInput, requiring users to type an identifier before destructive actions proceed (aligning with the project’s destructive-action UX pattern).

Changes:

  • Updated keypair deletion in UserCredentialList to use BAIConfirmModalWithInput instead of modal.confirm.
  • Updated auto-scaling rule deletion in AutoScalingRuleListLegacy to use BAIConfirmModalWithInput and replaced Card with BAICard.
  • Refactored delete triggers to set “currently deleting” state and render the typed-confirm modal at the component level.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
react/src/components/UserCredentialList.tsx Switches keypair deletion confirmation from modal.confirm to BAIConfirmModalWithInput using a selected-row state.
react/src/components/AutoScalingRuleListLegacy.tsx Switches rule deletion from Popconfirm to BAIConfirmModalWithInput, introduces delete-target state, and uses BAICard.

Comment thread react/src/components/UserCredentialList.tsx
Comment thread react/src/components/AutoScalingRuleListLegacy.tsx
Comment thread react/src/components/AutoScalingRuleListLegacy.tsx
Comment thread react/src/components/AutoScalingRuleListLegacy.tsx
@ironAiken2 ironAiken2 force-pushed the fix/FR-2819-use-bai-confirm-modal branch from 58235a5 to f1a3556 Compare May 12, 2026 07:46
@github-actions github-actions Bot added area:ux UI / UX issue. area:i18n Localization size:XL 500~ LoC and removed size:L 100~500 LoC labels May 12, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 14, 2026

Coverage Report for backend-ai-ui-coverage (./packages/backend.ai-ui)

Status Category Percentage Covered / Total
🔵 Lines 8.03% 362 / 4506
🔵 Statements 7.17% 411 / 5728
🔵 Functions 8.93% 94 / 1052
🔵 Branches 6.36% 362 / 5688
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/backend.ai-ui/src/components/BAIDeleteConfirmModal.tsx 0% 0% 0% 0% 9-145
packages/backend.ai-ui/src/components/index.ts 0% 100% 100% 0% 113-117
packages/backend.ai-ui/src/components/baiClient/FileExplorer/DeleteSelectedItemsModal.tsx 0% 0% 0% 0% 21-91
packages/backend.ai-ui/src/components/fragments/BAIProjectTable.tsx 0% 0% 0% 0% 26-410
Generated in workflow #815 for commit 0ca1f8b by the Vitest Coverage Report Action

Copy link
Copy Markdown
Contributor

@nowgnuesLee nowgnuesLee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also update the Storybook case for when target is included.

@ironAiken2
Copy link
Copy Markdown
Contributor Author

Addressed feedback from @nowgnuesLee: added a WithTarget Storybook case (packages/backend.ai-ui/src/components/BAIDeleteConfirmModal.stories.tsx) that demonstrates the target prop producing the "Are you sure you want to permanently delete {target}?" description, paired with requireConfirmInput for the typical irreversible-delete pattern. Also added a Key Features bullet in the meta description so the prop is discoverable from autodocs.

@ironAiken2 ironAiken2 requested a review from nowgnuesLee May 14, 2026 08:04
@ironAiken2 ironAiken2 force-pushed the fix/FR-2819-use-bai-confirm-modal branch from 72c5872 to f942af5 Compare May 14, 2026 08:53
Copy link
Copy Markdown
Contributor

@nowgnuesLee nowgnuesLee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please fill the pr description.

@github-actions github-actions Bot added the UX label May 18, 2026
Copy link
Copy Markdown
Contributor

@nowgnuesLee nowgnuesLee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@graphite-app
Copy link
Copy Markdown

graphite-app Bot commented May 18, 2026

Merge activity

…tions (#7370)

Resolves #7253(FR-2819)

## Summary

Sweep all permanent-delete flows that still used `modal.confirm` / `Popconfirm` / ad-hoc dialogs and move them onto the project's typed-confirmation pattern (`.claude/rules/destructive-confirmation.md`). In the process, **consolidate two overlapping components** — `BAIConfirmModalWithInput` and `BAIDeleteConfirmModal` — into a single API so every irreversible delete in the app looks and behaves the same.

## What changed

### Component consolidation
- **Remove `BAIConfirmModalWithInput`** (component, stories, exports). All 16 call sites are migrated to `BAIDeleteConfirmModal`.
- **Extend `BAIDeleteConfirmModal`**:
  - Add `requireConfirmInput` to force typed confirmation for single-item deletes.
  - Add `target` prop — when set (and no `description` is provided) the modal renders the localized "Are you sure you want to permanently delete {target}?" copy. Centralizes the most common irreversible-delete sentence so call sites don't redeclare it.
- Reinstall-confirm flows (`ManageImageResourceLimitModal`, `ManageAppsModal`) — which are confirmations but **not deletes** — are moved to plain `BAIModal` instead of a delete-shaped modal. They were only on `BAIConfirmModalWithInput` for the typed-input UX, which they don't actually need.

### Bug fixes (the issue's scope)
- `UserCredentialList.tsx` — permanent keypair deletion was a single-click `modal.confirm`. Now opens `BAIDeleteConfirmModal` with `requireConfirmInput` and the keypair's `access_key` as the confirm string.
- `AutoScalingRuleListLegacy.tsx` — permanent rule deletion was a `Popconfirm`. Now opens `BAIDeleteConfirmModal` requiring the rule's identifier to be typed. Card is migrated to `BAICard` in the same change per project convention.

### Sweep — other irreversible flows migrated
Single-click confirms / ad-hoc patterns replaced with `BAIDeleteConfirmModal` (+ `requireConfirmInput` where the item is sensitive):

- `AutoScalingRuleList.tsx` (V2)
- `ContainerRegistryList.tsx`
- `CustomizedImageList.tsx`
- `DeleteForeverVFolderModalV2.tsx`
- `DeploymentAccessTokensTab.tsx`, `DeploymentConfigurationSection.tsx`, `DeploymentList.tsx`, `EndpointList.tsx`
- `KeypairResourcePolicyList.tsx`, `ProjectResourcePolicyList.tsx`, `UserResourcePolicyList.tsx`
- `MyKeypairManagementModal.tsx`
- `PrometheusPresetTab.tsx`
- `PurgeUsersModal.tsx`
- `ResourceGroupList.tsx`, `ResourcePresetList.tsx`
- `RoleAssignmentTab.tsx`, `RolePermissionTab.tsx`, `RBACManagementPage.tsx`
- `ShellScriptEditModal.tsx`
- `UserCredentialList.tsx`
- `VFolderNodes.tsx`
- `AIAgentPage.tsx`
- `FileExplorer/DeleteSelectedItemsModal.tsx`
- `fragments/BAIProjectTable.tsx`

### `confirmText` policy
Standardized so each call site picks the **safer** of two options:
- **User-readable IDs** (project name, vfolder name, keypair `access_key`, role name, …) → use the resource's name as the confirm string. The user has it on screen and can copy-type it unambiguously.
- **Cryptic / long IDs** (image full path, autoscaling metric name, bulk purge across N users) → use the literal `"Permanently Delete"` string. Asking the user to type a 90-char Docker reference is worse UX, not better.

Activate / deactivate (reversible) flows are intentionally **left as-is** — those belong to FR-2825.

### i18n
- New keys across all 22 locales:
  - `general.*` resource-type labels (9 new entries) for the `target` prop.
  - `dialog.title.DeleteSomething`
  - `comp:BAIDeleteConfirmModal.AreYouSureToPermanentlyDeleteTarget`
- Filled in previously missing keys across non-English locales (translations were already drifting; this PR brings them back in sync).
- Fix one Korean typo: `environment.ModifyImageResourceLimitReinstallRequired`.

### Storybook
- Remove `BAIConfirmModalWithInput.stories.tsx`.
- Add a Storybook case for the new `target` prop on `BAIDeleteConfirmModal`.

## Why one API, not two

Before: `BAIConfirmModalWithInput` (typed-input shape) and `BAIDeleteConfirmModal` (item-list shape) covered overlapping use cases — the typed-input modal was being used for deletes, and call sites were duplicating copy and layout that already existed in `BAIDeleteConfirmModal`. After: a single component covers both the single-item and N-item delete cases, with `requireConfirmInput` and `target` handling the variants. Less surface area, less drift, fewer translation keys to keep aligned.

## Checklist

- [x] Documentation — N/A (no user-facing manual change; convention rule unchanged)
- [x] Minimum required manager version — N/A
- [x] Specific setting for review — none
- [x] Minimum requirements to check during review — `bash scripts/verify.sh` passes; manually exercise a few migrated flows (keypair delete, autoscaling rule delete, vfolder permanent delete, bulk user purge) to confirm the OK button stays disabled until the right string is typed
- [x] Test case(s) — see Storybook stories and the migrated call sites; behavior across all 16 sites is now driven by one component
@graphite-app graphite-app Bot force-pushed the fix/FR-2819-use-bai-confirm-modal branch from 1839b25 to 0ca1f8b Compare May 18, 2026 04:06
@graphite-app graphite-app Bot merged commit 0ca1f8b into main May 18, 2026
11 of 12 checks passed
@graphite-app graphite-app Bot deleted the fix/FR-2819-use-bai-confirm-modal branch May 18, 2026 04:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Permanent keypair deletion on /credential uses single-click confirm modal — must use BAIConfirmModalWithInput; sweep other components too

3 participants