From 6d3051a52f1b914a798d141b0ab07d1449eb0055 Mon Sep 17 00:00:00 2001 From: xxiaoxiong <2482929840@qq.com> Date: Thu, 21 May 2026 09:55:43 +0800 Subject: [PATCH 1/7] fix: add confirmation dialog for extraction history deletion Individual extraction history records were being deleted immediately without confirmation, creating a risk of accidental data loss. Changes: - Added confirmation dialog before deleting individual extraction records - Added new i18n key 'settings.memoryExtractionDeleteConfirm' - Updated onDeleteExtraction callback to include 't' dependency The confirmation follows the same pattern as the bulk clear operation, providing a consistent and safer UX for destructive actions. Fixes #2249 --- apps/web/src/components/MemorySection.tsx | 3 ++- apps/web/src/i18n/locales/en.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/MemorySection.tsx b/apps/web/src/components/MemorySection.tsx index 5284a439b3..fc19a6dc45 100644 --- a/apps/web/src/components/MemorySection.tsx +++ b/apps/web/src/components/MemorySection.tsx @@ -1364,6 +1364,7 @@ export function MemorySection({ }, [indexDraft, fireFlash]); const onDeleteExtraction = useCallback(async (id: string) => { + if (!window.confirm(t('settings.memoryExtractionDeleteConfirm'))) return; // Optimistic removal: drop the row immediately so the click feels // instant. The SSE 'deleted' event will arrive moments later and is // a no-op against an already-removed id; if the request fails we @@ -1373,7 +1374,7 @@ export function MemorySection({ if (!ok) { void reloadExtractions(); } - }, [reloadExtractions]); + }, [reloadExtractions, t]); const onClearExtractions = useCallback(async () => { if (!window.confirm(t('settings.memoryExtractionsClearConfirm'))) return; diff --git a/apps/web/src/i18n/locales/en.ts b/apps/web/src/i18n/locales/en.ts index e386d8a490..19f390120e 100644 --- a/apps/web/src/i18n/locales/en.ts +++ b/apps/web/src/i18n/locales/en.ts @@ -2148,6 +2148,8 @@ export const en: Dict = { 'settings.memoryExtractionWritten': 'written', 'settings.memoryExtractionDuration': 'in', 'settings.memoryExtractionDelete': 'Delete', + 'settings.memoryExtractionDeleteConfirm': + 'Delete this extraction record? This cannot be undone.', 'settings.memoryExtractionsClear': 'Clear', 'settings.memoryExtractionsClearTitle': 'Clear all extraction history', 'settings.memoryExtractionsClearConfirm': From 78ec9acb33c49dcca04a2f50d7e5eb9a5d66d4a4 Mon Sep 17 00:00:00 2001 From: xxiaoxiong <2482929840@qq.com> Date: Thu, 21 May 2026 20:49:08 +0800 Subject: [PATCH 2/7] fix: add Chinese translation for extraction delete confirmation Added missing zh-CN translation for 'settings.memoryExtractionDeleteConfirm' to fix the i18n wiring issue identified in review. --- apps/web/src/i18n/locales/zh-CN.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/i18n/locales/zh-CN.ts b/apps/web/src/i18n/locales/zh-CN.ts index 917825ef7e..0e171ed9fb 100644 --- a/apps/web/src/i18n/locales/zh-CN.ts +++ b/apps/web/src/i18n/locales/zh-CN.ts @@ -2114,6 +2114,7 @@ export const zhCN: Dict = { 'settings.memoryExtractionWritten': '写入', 'settings.memoryExtractionDuration': '耗时', 'settings.memoryExtractionDelete': '删除', + 'settings.memoryExtractionDeleteConfirm': '确定要删除此抽取记录吗?此操作无法撤销。', 'settings.memoryExtractionsClear': '清空', 'settings.memoryExtractionsClearTitle': '清空整个抽取历史', 'settings.memoryExtractionsClearConfirm': '确定要清空整个抽取历史吗?此操作无法撤销。', From 1672a691e454e46d012bf5691c4fc2234ccb76d6 Mon Sep 17 00:00:00 2001 From: xxiaoxiong <2482929840@qq.com> Date: Thu, 21 May 2026 21:32:41 +0800 Subject: [PATCH 3/7] fix: add memoryExtractionDeleteConfirm to Dict type definition Added the missing type definition for 'settings.memoryExtractionDeleteConfirm' to fix TypeScript errors in MemorySection.tsx and locale files. --- apps/web/src/i18n/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/i18n/types.ts b/apps/web/src/i18n/types.ts index a4e16005dc..a7e93f85b2 100644 --- a/apps/web/src/i18n/types.ts +++ b/apps/web/src/i18n/types.ts @@ -564,6 +564,7 @@ export interface Dict { 'settings.memoryExtractionWritten': string; 'settings.memoryExtractionDuration': string; 'settings.memoryExtractionDelete': string; + 'settings.memoryExtractionDeleteConfirm': string; 'settings.memoryExtractionsClear': string; 'settings.memoryExtractionsClearTitle': string; 'settings.memoryExtractionsClearConfirm': string; From b740e6929bbddf9f57878cc957d71bc993175a96 Mon Sep 17 00:00:00 2001 From: xxiaoxiong <2482929840@qq.com> Date: Thu, 21 May 2026 22:05:23 +0800 Subject: [PATCH 4/7] chore: trigger CI re-run From 6d6e2a42a1f8d3a09c334cffcae1c672c3a37255 Mon Sep 17 00:00:00 2001 From: xxiaoxiong <2482929840@qq.com> Date: Thu, 21 May 2026 22:26:40 +0800 Subject: [PATCH 5/7] chore: trigger CI status refresh From 7a42c81bc191704c26c980494eef60406882336d Mon Sep 17 00:00:00 2001 From: xxiaoxiong <2482929840@qq.com> Date: Thu, 21 May 2026 23:02:52 +0800 Subject: [PATCH 6/7] test: update MemorySection test to confirm deletion dialog --- apps/web/tests/components/MemorySection.test.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/web/tests/components/MemorySection.test.tsx b/apps/web/tests/components/MemorySection.test.tsx index f9acaec506..02e87fe06a 100644 --- a/apps/web/tests/components/MemorySection.test.tsx +++ b/apps/web/tests/components/MemorySection.test.tsx @@ -1475,6 +1475,10 @@ describe('MemorySection', () => { .closest('.library-card') as HTMLElement; fireEvent.click(within(row).getByRole('button', { name: 'Delete' })); + // Confirm the deletion in the dialog + const confirmButton = await screen.findByRole('button', { name: 'Delete' }); + fireEvent.click(confirmButton); + await waitFor(() => { expect(screen.queryByText('Remember I prefer dark mode')).toBeNull(); }); From 6360dec89a15d8109f556235bf3f0fd37203c2f9 Mon Sep 17 00:00:00 2001 From: xxiaoxiong <2482929840@qq.com> Date: Thu, 21 May 2026 23:49:16 +0800 Subject: [PATCH 7/7] test: use dialog scope to find confirmation Delete button --- apps/web/tests/components/MemorySection.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/tests/components/MemorySection.test.tsx b/apps/web/tests/components/MemorySection.test.tsx index 02e87fe06a..1b9a229bfc 100644 --- a/apps/web/tests/components/MemorySection.test.tsx +++ b/apps/web/tests/components/MemorySection.test.tsx @@ -1476,7 +1476,8 @@ describe('MemorySection', () => { fireEvent.click(within(row).getByRole('button', { name: 'Delete' })); // Confirm the deletion in the dialog - const confirmButton = await screen.findByRole('button', { name: 'Delete' }); + const dialog = await screen.findByRole('dialog'); + const confirmButton = within(dialog).getByRole('button', { name: 'Delete' }); fireEvent.click(confirmButton); await waitFor(() => {