F14: add per-activity delete (DELETE /api/activity/{id} + drawer button)

Server endpoint removes the activity JSON, GeoJSON, timeseries, sidecar
edit, and images directory. Also purges the dedup cache entry so the
file can be re-uploaded if needed. Runs merge_all + rebuild afterwards.

EditDrawer: two-click delete button (click once → "Confirm delete?",
click again → deletes). On success, dispatches 'deleted' event.
ActivityDetail navigates back to the feed on delete.
This commit is contained in:
Davide Scaini
2026-04-13 19:35:40 +02:00
parent e6bb6e61a2
commit a75dfa160b
3 changed files with 86 additions and 3 deletions
+1 -1
View File
@@ -112,7 +112,7 @@
<svelte:window on:keydown={onKeydown} />
{#if editOpen && editEnabled}
<EditDrawer activityId={activity.id} {editUrl} on:saved={onSaved} on:close={() => editOpen = false} />
<EditDrawer activityId={activity.id} {editUrl} on:saved={onSaved} on:close={() => editOpen = false} on:deleted={() => { window.location.href = base; }} />
{/if}
<!-- Lightbox -->
+35 -2
View File
@@ -5,7 +5,7 @@
export let activityId: string;
export let editUrl: string;
const dispatch = createEventDispatcher<{ saved: { title: string; description: string }; close: void }>();
const dispatch = createEventDispatcher<{ saved: { title: string; description: string }; close: void; deleted: void }>();
const SPORTS: Sport[] = ['cycling', 'running', 'hiking', 'walking', 'swimming', 'skiing', 'other'];
const STAT_PANELS = [
@@ -21,6 +21,8 @@
let saving = false;
let saveStatus = '';
let saveOk = false;
let confirmDelete = false;
let deleting = false;
// Form state
let title = '';
@@ -120,6 +122,22 @@
: [...hideStats, key];
}
async function deleteActivity() {
if (!confirmDelete) { confirmDelete = true; return; }
deleting = true;
try {
const res = await fetch(api, { method: 'DELETE' });
if (!res.ok) throw new Error(await res.text());
dispatch('deleted');
} catch (e: any) {
saveStatus = `Delete failed: ${e.message}`;
saveOk = false;
confirmDelete = false;
} finally {
deleting = false;
}
}
load();
</script>
@@ -284,11 +302,26 @@
<div class="px-5 py-4 border-t border-zinc-800 flex items-center gap-3 shrink-0">
<button
class="px-4 py-2 bg-blue-600 hover:bg-blue-500 disabled:opacity-40 text-white text-sm font-medium rounded-lg transition-colors"
disabled={saving}
disabled={saving || deleting}
on:click={save}
>
{saving ? 'Saving…' : 'Save'}
</button>
<button
class="px-3 py-2 text-sm font-medium rounded-lg border transition-colors disabled:opacity-40 ml-auto"
class:border-zinc-700={!confirmDelete}
class:text-zinc-500={!confirmDelete}
class:hover:border-red-600={!confirmDelete}
class:hover:text-red-400={!confirmDelete}
class:border-red-500={confirmDelete}
class:text-red-400={confirmDelete}
class:bg-red-950={confirmDelete}
disabled={deleting}
on:click={deleteActivity}
on:blur={() => confirmDelete = false}
>
{deleting ? 'Deleting…' : confirmDelete ? 'Confirm delete?' : 'Delete'}
</button>
{#if saveStatus}
<span class="text-xs" class:text-green-400={saveOk} class:text-red-400={!saveOk}>
{saveStatus}