From b5b1ff88e57469e27e55ab0d4b70a19de0763b2a Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Tue, 11 Aug 2026 16:18:38 +0200 Subject: [PATCH] feat(history): expose complete history deletion Add a permanent danger action to the History toolbar so users can clear all saved entries without selecting rows or expanding the sidebar. Reuse the existing confirmation and storage path, disable the action while history is empty or loading, localize the label in English, and cover the interaction with focused regression tests. --- CHANGELOG.md | 13 +++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- src/renderer/i18n.ts | 2 +- src/renderer/views/history/HistoryView.tsx | 1 + tests/history-view.test.tsx | 21 ++++++++++++++++++++- tests/i18n.test.ts | 1 + 7 files changed, 39 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d97430e..7ef5128 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to Multi-Debrid Downloader are documented in this file. +## [2.0.22] - 2026-08-11 + +### History management + +- Added a permanently visible destructive toolbar action for clearing the complete download history without selecting individual entries. +- Kept full-history deletion behind the existing confirmation dialog and disabled the action while history is empty or loading. +- Added complete English localization for the new history action. + +### Reliability and testing + +- Added regression coverage for full-history action visibility, danger styling, loading state, empty state, and dispatch behavior. +- Verified the updated History toolbar at 1920 and 1120 pixel window widths without horizontal overflow. + ## [2.0.21] - 2026-08-11 ### Responsive interface diff --git a/package-lock.json b/package-lock.json index 675ab4f..c47ce4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "real-debrid-downloader", - "version": "2.0.21", + "version": "2.0.22", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "real-debrid-downloader", - "version": "2.0.21", + "version": "2.0.22", "license": "MIT", "dependencies": { "adm-zip": "0.6.0", diff --git a/package.json b/package.json index b2d130f..6eec620 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "real-debrid-downloader", - "version": "2.0.21", + "version": "2.0.22", "description": "Desktop downloader", "main": "build/main/main/main.js", "author": "Sucukdeluxe", diff --git a/src/renderer/i18n.ts b/src/renderer/i18n.ts index 2db91ab..6c4859e 100644 --- a/src/renderer/i18n.ts +++ b/src/renderer/i18n.ts @@ -52,7 +52,7 @@ const pairs = [ ["Rotations-Verlauf", "Rotation history"], ["Sammlung", "Collection"], ["URL oder Rohzeile", "URL or raw line"], ["Zeile", "Line"], ["Paket / Datei", "Package / file"], ["Größe", "Size"], ["Gestartet", "Started"], ["Beendet", "Finished"], ["Alle Einträge", "All entries"], ["Heute", "Today"], ["Letzte 7 Tage", "Last 7 days"], ["Älter", "Older"], ["Gelöscht", "Deleted"], ["Fehlgeschlagen", "Failed"], ["Dauer", "Duration"], ["Durchschnitt", "Average"], ["Zielordner", "Destination folder"], ["Verlaufsfilter", "History filters"], ["Verlauf leeren", "Clear history"], ["Verlaufsaktionen", "History actions"], - ["Einträge", "Entries"], ["Erneut hinzufügen", "Add again"], ["Im Ordner zeigen", "Show in folder"], ["Auswahl löschen", "Clear selection"], ["Verlauf durchsuchen", "Search history"], ["Name, Pfad, Hoster oder Provider", "Name, path, hoster or provider"], + ["Einträge", "Entries"], ["Erneut hinzufügen", "Add again"], ["Im Ordner zeigen", "Show in folder"], ["Auswahl löschen", "Clear selection"], ["Gesamtverlauf löschen", "Delete all history"], ["Verlauf durchsuchen", "Search history"], ["Name, Pfad, Hoster oder Provider", "Name, path, hoster or provider"], ["Verlaufstabelle", "History table"], ["Verlaufsseiten", "History pages"], ["Vorherige Verlaufsseite", "Previous history page"], ["Nächste Verlaufsseite", "Next history page"], ["Zurück", "Back"], ["Vor", "Next"], ["Verlauf wird geladen", "Loading history"], ["Die gespeicherten Einträge werden geladen.", "Saved entries are being loaded."], ["Verlauf wird geladen. Die gespeicherten Einträge werden geladen.", "History is loading. Saved entries are being loaded."], ["Noch kein Verlauf", "No history yet"], ["Keine passenden Einträge", "No matching entries"], ["Abgeschlossene und gelöschte Pakete erscheinen hier.", "Completed and deleted packages appear here."], ["Passe Filter oder Suche an.", "Adjust the filter or search."], ["Öffne die Ansicht erneut, um es noch einmal zu versuchen.", "Open the view again to retry."], ["Alle sichtbaren Einträge auswählen", "Select all visible entries"], ["Details anzeigen", "Show details"], ["Details ausblenden", "Hide details"], diff --git a/src/renderer/views/history/HistoryView.tsx b/src/renderer/views/history/HistoryView.tsx index 2be4f4b..1e2796b 100644 --- a/src/renderer/views/history/HistoryView.tsx +++ b/src/renderer/views/history/HistoryView.tsx @@ -97,6 +97,7 @@ export function HistoryToolbar({ model, actions }: HistoryViewProps): ReactEleme + { ]); }); - it("renders expanded paths and URLs as copyable details without changing the 48px main-row contract", () => { + it("keeps the full-history delete action visible without a selection and disables it only for unavailable history", () => { + const calls: string[] = []; + const populated = buildHistoryViewModel(entries, "all", "", [], [], false, "", now); + const empty = buildHistoryViewModel([], "all", "", [], [], false, "", now); + const loading = buildHistoryViewModel(entries, "all", "", [], [], true, "", now); + const actions = createActions({ onClearHistory: () => calls.push("clear-history") }); + + const populatedButton = findButton(HistoryToolbar({ actions, model: populated }), "Gesamtverlauf löschen"); + const emptyButton = findButton(HistoryToolbar({ actions, model: empty }), "Gesamtverlauf löschen"); + const loadingButton = findButton(HistoryToolbar({ actions, model: loading }), "Gesamtverlauf löschen"); + + expect(populatedButton.props.className).toContain("history-action-danger"); + expect(populatedButton.props.disabled).toBe(false); + expect(emptyButton.props.disabled).toBe(true); + expect(loadingButton.props.disabled).toBe(true); + populatedButton.props.onClick(); + expect(calls).toEqual(["clear-history"]); + }); + + it("renders expanded paths and URLs as copyable details without changing the 48px main-row contract", () => { const html = renderToStaticMarkup( { ["Gelöscht", "Deleted"], ["Fehlgeschlagen", "Failed"], ["Verlauf leeren", "Clear history"], + ["Gesamtverlauf löschen", "Delete all history"], ["Erneut hinzufügen", "Add again"], ["Im Ordner zeigen", "Show in folder"], ["Auswahl löschen", "Clear selection"],