feat(admin): purge-archived endpoint with an archived-items banner

Bulk escape hatch for archived rows (files missing from disk for 2+
scans) so a mass external deletion never has to wait out the retention
window or be clicked away row by row:

- POST /api/media-items/purge-archived (admin only) hard-deletes all
  archived items and returns the purged count; reading history goes with
  the rows, so the call is confirmed in the UI first.
- The library admin page shows an 'Archived items: N' card (only when
  non-zero) with a Purge Archived Now button that calls the endpoint,
  toasts the result, and reloads.
- Frontend admin JS exposes window.purgeArchivedItems following the
  existing localStorage-bearer-token pattern.
This commit is contained in:
John O'Keefe
2026-09-12 17:50:24 -04:00
parent 14445a7c3f
commit cd119a74da
6 changed files with 388 additions and 277 deletions
+18 -1
View File
@@ -1,6 +1,6 @@
package templates
templ AdminLibrary(user User, libraries []LibraryData, users []User) {
templ AdminLibrary(user User, libraries []LibraryData, users []User, archivedCount int64) {
<!DOCTYPE html>
<html lang="en">
<head>
@@ -34,6 +34,23 @@ templ AdminLibrary(user User, libraries []LibraryData, users []User) {
</button>
</div>
</div>
if archivedCount > 0 {
<div class="card p-4 mb-6 flex items-center justify-between gap-4 flex-wrap">
<div>
<p class="font-semibold" style="color: var(--text-primary)">
Archived items: { archivedCount }
</p>
<p class="text-sm" style="color: var(--text-secondary)">
Files missing from disk for two consecutive scans. Reading history is kept
unless purged; items return automatically if their files come back.
</p>
</div>
<button type="button" onclick="purgeArchivedItems()" class="btn btn-secondary">
@Icon("trash", "h-4 w-4")
Purge Archived Now
</button>
</div>
}
<div id="libraries-container">
@LibraryList(user, libraries, users)
</div>
File diff suppressed because it is too large Load Diff