1
Fork 0
mirror of https://github.com/thegeneralist01/archivr synced 2026-07-21 18:55:36 +02:00

feat: add orphan blob cleanup to Settings > Storage tab (#18)

- database.rs: add has_active_capture_jobs(), list_orphaned_blob_rows(),
  all_referenced_file_relpaths(), delete_orphaned_blob_rows()
- routes.rs: GET/DELETE /api/archives/:id/blob-cleanup (ROLE_ADMIN)
  - GET returns {orphaned_blob_rows, deletable_files, total_bytes}
  - DELETE has two active-capture guards (before and after disk walk)
    to prevent deleting files mid-capture; walks raw/ and raw_tweets/
  - Referenced set = entry_artifacts.relpath ∪ live blobs' raw_relpath,
    so a file is never deleted if any artifact still points at its path
- api.js: scanOrphanBlobs(), deleteOrphanBlobs()
- App.jsx: pass archiveId to SettingsView; add 'storage' to SETTINGS_TABS
  so /settings/storage survives refresh/back navigation
- SettingsView.jsx: new Storage tab (admin-only) with idle→scanning→
  scanned→deleting→done/error state machine; shows file/record counts
  and human-readable byte sizes before a btn-danger confirm

Tests (14 new, 248 total passing):
- database.rs: has_active_capture_jobs for pending/running/completed,
  list_orphaned_blob_rows, all_referenced_file_relpaths edge cases,
  delete_orphaned_blob_rows preserves referenced rows
- routes.rs: auth (401), active-capture 409 on GET and DELETE,
  end-to-end delete preserving referenced file and removing orphan
  blob file + extra disk-only file
This commit is contained in:
TheGeneralist 2026-07-06 14:01:38 +02:00 committed by GitHub
parent b8e496457f
commit 339076e6a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 739 additions and 48 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Archivr</title>
<script type="module" crossorigin src="/assets/index-BHg5-TAr.js"></script>
<script type="module" crossorigin src="/assets/index-bXPw5mQ7.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BW0QKHXE.css">
</head>
<body>