fix(trash): Daten-Review-Befunde — Import-Cap nach deletedAt sortiert (Verlust-Schutz), Restore-Doppelklick-Guard, Delete-Rollback bei Save-Fehler, NaN/Null-Haertung

This commit is contained in:
2026-06-14 10:18:10 +02:00
parent 9800e6c949
commit 83df926979
5 changed files with 41 additions and 14 deletions
+8 -2
View File
@@ -82,7 +82,7 @@ function initDataButtons() {
// Papierkorb importieren (falls vorhanden) — defensiv validiert.
if (Array.isArray(data.trash) && data.trash.length > 0) {
const validTrash = data.trash
.filter(e => e && e.item && ['bookmark', 'board'].includes(e.type) && typeof e.deletedAt === 'number')
.filter(e => e && e.item && ['bookmark', 'board'].includes(e.type) && typeof e.deletedAt === 'number' && Number.isFinite(e.deletedAt))
.map(e => ({
type: e.type,
originBoardId: typeof e.originBoardId === 'string' ? e.originBoardId : null,
@@ -96,6 +96,7 @@ function initDataButtons() {
? e.item.bookmarks
.filter(bm => bm && typeof bm.title === 'string' && isSafeUrl(bm.url))
.map(bm => ({ id: bm.id || uid(), title: String(bm.title).slice(0, 200), url: bm.url, desc: String(bm.desc || '').slice(0, 500) }))
.slice(0, 500)
: []
}
: (isSafeUrl(e.item.url)
@@ -104,7 +105,12 @@ function initDataButtons() {
}))
.filter(e => e.item !== null);
if (validTrash.length > 0) {
trash = [...trash, ...validTrash].slice(-TRASH_MAX_ENTRIES);
// Nach deletedAt aufsteigend sortieren, DANN die neuesten TRASH_MAX_ENTRIES behalten.
// Positionsbasiertes slice(-N) wuerde sonst frische lokale Eintraege verdraengen
// statt der aeltesten — Datenverlust, da ein Trash-Eintrag die einzige Kopie ist.
const combined = [...trash, ...validTrash];
combined.sort((a, b) => a.deletedAt - b.deletedAt);
trash = combined.slice(-TRASH_MAX_ENTRIES);
await saveTrash();
}
}