feat(files): Sammel-Loeschen und Ziehen auf den Papierkorb

Zwei Wege, weil sie verschiedene Momente treffen: Der Knopf in der
Auswahlleiste raeumt eine geplante Auswahl weg, das Ziehen auf den
Papierkorb in der Seitenleiste die eine Datei, die einem gerade
auffaellt.

Zieht man eine markierte Datei, meint man die Markierung - deshalb
traegt der Ziehvorgang jetzt zusaetzlich aether-file-ids mit allen
markierten IDs. Eine unmarkierte Datei zieht nur sich selbst.

Der Knopf fragt nach, das Ziehen nicht: Ziehen ist eine bewusste
Bewegung mit gedrueckter Taste, und der Papierkorb ist umkehrbar. Eine
Rueckfrage nach jedem Zug klickt man nach dem dritten Mal blind weg.

filesApi.deleteMany schickt vier Anfragen gleichzeitig und meldet, was
nicht ging; fehlgeschlagene Dateien bleiben markiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-08-24 22:43:36 +02:00
1 parent 3b12d2e943
commit 1d933c5c73
6 files changed
+198 -13

No files matched your search

+32
View File
@@ -598,6 +598,38 @@ export const filesApi = {
delete: (id: string) => request<void>('DELETE', `/files/${id}`),
/**
* Mehrere Dateien in den Papierkorb legen.
*
* Vier gleichzeitig, nicht alle auf einmal: Bei achtzig markierten Dateien
* schickte der Browser sonst achtzig Anfragen in derselben Sekunde – die
* Verbindungsgrenze staut sie ohnehin, und der Server verschiebt für jede
* einen Blob. Nacheinander wäre umgekehrt spürbar zäh.
*
* Der Rückgabewert nennt, was **nicht** ging. Eine einzelne fehlgeschlagene
* Datei darf die übrigen nicht aufhalten – sie soll nur nicht verschwiegen
* werden.
*/
deleteMany: async (ids: string[]): Promise<{ ok: string[]; failed: string[] }> => {
const ok: string[] = []
const failed: string[] = []
const queue = [...ids]
const worker = async () => {
for (;;) {
const id = queue.shift()
if (!id) return
try {
await request<void>('DELETE', `/files/${id}`)
ok.push(id)
} catch {
failed.push(id)
}
}
}
await Promise.all(Array.from({ length: Math.min(4, ids.length) }, worker))
return { ok, failed }
},
rename: (id: string, name: string) =>
request<FileItem>('PATCH', `/files/${id}/rename`, { name }),