From dfa6457f1ff101c307eb684c0b063d40f62730d3 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 25 Apr 2026 06:54:01 +0000 Subject: [PATCH] fix(history): bulk delete + clear-all now persist to SQLite The Phase 9 bulk-delete path passed UUID strings to deleteFromHistory(index), which expected an integer; JS coerced the string to NaN and splice(NaN, 1) collapsed to splice(0, 1), so bulk-delete silently removed the first N visible rows instead of the selected ones, then fired delete_transcript against the wrong IDs. Clear-all called saveHistory(), which was a no-op stub left over from the same incomplete-refactor pattern that produced the manualTags persistence bug fixed in 7eb52d9. The in-memory array was emptied, but SQLite still held every transcript, so they reappeared on next loadHistory(). - Add deleteFromHistoryById(id) next to the index-keyed deleteFromHistory. - bulkDelete now calls deleteFromHistoryById. - clearAll now awaits an explicit per-id delete loop and surfaces a toast on partial failure. - Remove the saveHistory() stub and its sole caller's import. https://claude.ai/code/session_0189xUb6ie6t9qHkzatGZ9Rb --- src/lib/pages/HistoryPage.svelte | 23 +++++++++++++++++++---- src/lib/stores/page.svelte.ts | 8 ++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/lib/pages/HistoryPage.svelte b/src/lib/pages/HistoryPage.svelte index da790f8..c0c2199 100644 --- a/src/lib/pages/HistoryPage.svelte +++ b/src/lib/pages/HistoryPage.svelte @@ -4,9 +4,9 @@ import { invoke } from "@tauri-apps/api/core"; import { history, - saveHistory, saveTranscriptMeta, deleteFromHistory, + deleteFromHistoryById, renameHistoryEntry, } from "$lib/stores/page.svelte.js"; import { toasts } from "$lib/stores/toasts.svelte.js"; @@ -228,12 +228,27 @@ return items; }); - function clearAll() { + async function clearAll() { if (!confirm("Delete all history? This can't be undone.")) return; + const ids = history.map((entry) => entry.id); history.splice(0); - saveHistory(); expandedId = null; stopPlayback(); + let failed = 0; + for (const id of ids) { + try { + await invoke("delete_transcript", { id: String(id) }); + } catch (err) { + failed++; + console.warn("clearAll: SQLite delete failed", id, err); + } + } + if (failed > 0) { + toasts.error( + "Some history entries could not be deleted", + `${failed} of ${ids.length} failed to delete from disk and may reappear after restart.`, + ); + } } function toggleExpand(id) { @@ -453,7 +468,7 @@ `Delete ${selected.size} transcript${selected.size === 1 ? "" : "s"}?`, ); if (!yes) return; - for (const id of selected) deleteFromHistory(id); + for (const id of selected) deleteFromHistoryById(id); clearSelection(); } diff --git a/src/lib/stores/page.svelte.ts b/src/lib/stores/page.svelte.ts index 08bb3d0..80845f2 100644 --- a/src/lib/stores/page.svelte.ts +++ b/src/lib/stores/page.svelte.ts @@ -223,8 +223,6 @@ if (typeof window !== "undefined" && hasTauriRuntime()) { loadHistory().catch(() => {}); } -export function saveHistory() {} - export async function addToHistory(entry: TranscriptWriteEntry) { const normalised = normaliseTranscriptEntry(entry); history.unshift(normalised); @@ -323,6 +321,12 @@ export function deleteFromHistory(index: number) { .catch((err) => console.warn("deleteFromHistory: SQLite delete failed", err)); } +export function deleteFromHistoryById(id: string) { + const idx = history.findIndex((entry) => String(entry.id) === String(id)); + if (idx === -1) return; + deleteFromHistory(idx); +} + export const tasks = $state([]); function mapTaskRow(row: TaskDto): TaskEntry {