feat: soft-delete and undo/restore for local-workspace items
Backend:
- DELETE /api/local-workspace/items/{id} now soft-deletes (sets deleted_at
instead of hard DELETE) — items go to trash, not permanently gone
- New POST /api/local-workspace/items/{id}/restore to undo a delete
- _load_workspace_pages() and _load_children() now filter deleted_at IS NULL
so soft-deleted items disappear from sidebar and tree queries
Frontend:
- undoDelete() now calls the restore API per item (single or bulk)
- bulkDelete() now shows the same undo banner as context menu delete
- All delete paths (ctxMenu, bulk, modal) use the same soft-delete + undo flow
This commit is contained in:
@@ -567,11 +567,20 @@ window._wsInitData = (function() {
|
||||
if (ids.length === 0) return;
|
||||
if (!confirm('Delete ' + ids.length + ' selected items?')) return;
|
||||
var self = this;
|
||||
// Soft-delete all selected items
|
||||
for (var i=0; i<ids.length; i++) {
|
||||
await fetch('/api/local-workspace/items/' + ids[i], { method: 'DELETE' });
|
||||
}
|
||||
this.clearSelection();
|
||||
this._reloadAfterAction();
|
||||
// Show undo banner for bulk delete
|
||||
this.undoItemId = ids.join(',');
|
||||
this.undoMessage = 'Deleted ' + ids.length + ' item(s)';
|
||||
this.undoVisible = true;
|
||||
this.undoTimeout = setTimeout(function() {
|
||||
self.undoVisible = false;
|
||||
self.undoItemId = null;
|
||||
}, 5000);
|
||||
},
|
||||
clearSelection() {
|
||||
for (var k in this.selectedIds) delete this.selectedIds[k];
|
||||
@@ -1223,11 +1232,23 @@ window._wsInitData = (function() {
|
||||
undoDelete() {
|
||||
if (this.undoTimeout) clearTimeout(this.undoTimeout);
|
||||
this.undoVisible = false;
|
||||
var id = this.undoItemId;
|
||||
if (!id) return;
|
||||
// Recreate the item (we can't really undo a DELETE, so reload)
|
||||
this._reloadAfterAction();
|
||||
var ids = (this.undoItemId || '').toString().split(',');
|
||||
this.undoItemId = null;
|
||||
if (!ids.length || !ids[0]) return;
|
||||
// Restore via API (soft-delete undo) — single or bulk
|
||||
var self = this;
|
||||
var restored = 0;
|
||||
var total = ids.length;
|
||||
function restoreOne(i) {
|
||||
if (i >= total) {
|
||||
self._reloadAfterAction();
|
||||
return;
|
||||
}
|
||||
fetch('/api/local-workspace/items/' + ids[i] + '/restore', { method: 'POST' })
|
||||
.then(function(r) { if (r.ok) restored++; })
|
||||
.finally(function() { restoreOne(i + 1); });
|
||||
}
|
||||
restoreOne(0);
|
||||
},
|
||||
_removeFromTree(nodes, id) {
|
||||
for (var i=0; i<nodes.length; i++) {
|
||||
|
||||
Reference in New Issue
Block a user