Add delete with confirmation for trips and dashcam

- Confirmation modal in server base.html (window.confirmDelete promise helper)
- Trip delete: trash button in Replay column (server-only via data-deletable on
  trip-list div), DELETE /api/v1/portal/trip/<id>, removes computed trip only
  (raw tracking_points kept)
- Dashcam delete: trash button next to download, DELETE /api/v1/portal/dashcam/<id>,
  removes from DB + disk (best-effort file removal)
- history.js: delete button gated on data-deletable='1' attribute; click handler
  intercepts before replay logic
- db.py: delete_trip(), delete_dashcam_file() helpers

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Mathieu Moran
2026-08-10 04:40:22 -04:00
co-authored by Copilot
parent a13d74e18e
commit 7aa9ffda16
7 changed files with 151 additions and 6 deletions
+29 -2
View File
@@ -133,13 +133,17 @@ async function loadFiles() {
<td class="text-truncate" style="max-width:200px;" title="${f.relative_path}">${name}</td>
<td class="text-nowrap">${fmtSize(f.size_bytes)}</td>
<td class="text-nowrap d-none d-sm-table-cell">${fmtDate(f.uploaded_at)}</td>
<td class="text-end">
<td class="text-end text-nowrap">
<a href="/api/v1/portal/dashcam/stream/${f.id}" download="${name}"
class="btn btn-outline-secondary btn-sm py-0 px-1" title="Download"
onclick="event.stopPropagation()">
<i class="fas fa-download fa-fw"></i>
</a>
</td>
<button class="btn btn-outline-danger btn-sm py-0 px-1 ms-1" title="Delete"
onclick="event.stopPropagation(); deleteFile(${f.id}, '${name.replace(/'/g,"\\'")}')">
<i class="fas fa-trash fa-fw"></i>
</button>
</td>
</tr>
`;
}).join('');
@@ -152,5 +156,28 @@ async function loadFiles() {
}
loadFiles();
async function deleteFile(id, name) {
const confirmed = await window.confirmDelete(`Delete "${name}"? This removes the file from disk permanently.`);
if (!confirmed) return;
const res = await fetch(`/api/v1/portal/dashcam/${id}`, { method: 'DELETE' });
if (!res.ok) { alert('Delete failed.'); return; }
// Clear player if this file was playing
const player = document.getElementById('video-player');
if (currentFileId === id) {
player.pause();
player.src = '';
player.hidden = true;
document.getElementById('player-placeholder').hidden = false;
document.getElementById('player-meta').hidden = true;
document.getElementById('btn-download').hidden = true;
currentFileId = null;
}
// Remove row
const row = document.querySelector(`#files-body tr[data-file-id="${id}"]`);
if (row) row.remove();
const countEl = document.getElementById('file-count');
countEl.textContent = parseInt(countEl.textContent) - 1;
}
</script>
{% endblock %}