feat: Papierkorb + Bestaetigungsdialoge bei allen Loeschaktionen

Papierkorb:
- Dateien/Ordner werden beim Loeschen in den Papierkorb verschoben
  (Soft-Delete) statt sofort geloescht
- Papierkorb-Seite in der Sidebar mit Tabelle aller geloeschten Elemente
- Pro Element: Wiederherstellen (am Originalort) oder endgueltig loeschen
- "Papierkorb leeren" Button loescht alles unwiderruflich
- Backend: is_trashed, trashed_at, original_parent_id Felder im File-Model
- Getrashte Dateien erscheinen nicht in der normalen Dateiliste

Bestaetigungsdialoge (vorher fehlend):
- Kontakte: "Moechtest du XY wirklich loeschen?"
- Kalender Events: Bestaetigung vor dem Loeschen
- Kalender: Bestaetigung vor dem Loeschen (mit Hinweis auf Events)
- E-Mail Nachrichten: Bestaetigung mit Betreff-Vorschau
- Share-Link Dateien: Bestaetigung beim Loeschen aus geteiltem Ordner
- Admin SFTP-Backup-Ziele: Bestaetigung
- Admin Email-Konten: Bestaetigung

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker
2026-04-11 20:50:19 +02:00
parent 1ee80e650d
commit 82f3091f2e
10 changed files with 423 additions and 26 deletions
+22 -3
View File
@@ -31,7 +31,7 @@
<Column field="phone" header="Telefon" />
<Column header="" style="width: 80px">
<template #body="{ data }">
<Button icon="pi pi-trash" text size="small" severity="danger" @click.stop="deleteContact(data)" />
<Button icon="pi pi-trash" text size="small" severity="danger" @click.stop="confirmDeleteContact(data)" />
</template>
</Column>
</DataTable>
@@ -77,6 +77,15 @@
<Button :label="editingContact ? 'Speichern' : 'Erstellen'" @click="saveContact" />
</template>
</Dialog>
<!-- Delete Confirm -->
<Dialog v-model:visible="showDeleteConfirm" header="Kontakt loeschen" modal :style="{ width: '400px' }">
<p>Moechtest du <strong>{{ deleteTarget?.display_name }}</strong> wirklich loeschen?</p>
<template #footer>
<Button label="Abbrechen" text @click="showDeleteConfirm = false" />
<Button label="Loeschen" severity="danger" @click="doDeleteContact" />
</template>
</Dialog>
</div>
</template>
@@ -178,8 +187,18 @@ async function saveContact() {
}
}
async function deleteContact(contact) {
await apiClient.delete(`/contacts/${contact.id}`)
const showDeleteConfirm = ref(false)
const deleteTarget = ref(null)
function confirmDeleteContact(contact) {
deleteTarget.value = contact
showDeleteConfirm.value = true
}
async function doDeleteContact() {
if (!deleteTarget.value) return
await apiClient.delete(`/contacts/${deleteTarget.value.id}`)
showDeleteConfirm.value = false
await loadContacts()
await loadBooks()
}