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:
1 parent
3b12d2e943
commit
1d933c5c73
6 files changed
+198
-13
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { useState } from 'react'
|
||||
import { filesApi } from '../api/client'
|
||||
import type { FolderItem, User } from '../api/client'
|
||||
import { useNavHistory, type View } from '../hooks/useNavHistory'
|
||||
import Sidebar from './Sidebar'
|
||||
@@ -24,6 +25,23 @@ export default function Shell({ user, onLogout, onUserChanged }: Props) {
|
||||
const nav = useNavHistory()
|
||||
const { view, folderPath } = nav
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false)
|
||||
// Hochgezählt, wenn etwas auf den Papierkorb gezogen wurde – die Dateiliste
|
||||
// hängt daran und holt sich daraufhin neu.
|
||||
const [trashBump, setTrashBump] = useState(0)
|
||||
|
||||
/**
|
||||
* Auf den Papierkorb gezogene Dateien.
|
||||
*
|
||||
* Bewusst **ohne** Rückfrage: Der Weg dorthin ist eine bewusste Bewegung mit
|
||||
* gedrückter Maustaste, kein Klick, der danebengehen kann – und der
|
||||
* Papierkorb ist umkehrbar. Ein Dialog nach jedem Zug wäre die Art
|
||||
* Sicherheitsabfrage, die man nach dem dritten Mal blind wegklickt.
|
||||
*/
|
||||
async function trashDrop(fileIds: string[]) {
|
||||
await filesApi.deleteMany(fileIds)
|
||||
setTrashBump(n => n + 1)
|
||||
await onUserChanged()
|
||||
}
|
||||
|
||||
// Aus der Seitenleiste kennen wir nur Kennung und Name – die Kette darueber
|
||||
// holt die Liste nicht mit, also faengt der Pfad hier beim Ordner selbst an.
|
||||
@@ -61,6 +79,7 @@ export default function Shell({ user, onLogout, onUserChanged }: Props) {
|
||||
onOpenCorrespondent={nav.setCorrespondent}
|
||||
onNavigate={(v) => { nav.setView(v); setSidebarOpen(false) }}
|
||||
onNavigateToFolder={navigateToFolder}
|
||||
onTrashDrop={trashDrop}
|
||||
open={sidebarOpen}
|
||||
/>
|
||||
|
||||
@@ -72,6 +91,7 @@ export default function Shell({ user, onLogout, onUserChanged }: Props) {
|
||||
folderPath={folderPath}
|
||||
onNavigate={nav.setFolderPath}
|
||||
onUserChanged={onUserChanged}
|
||||
reloadSignal={trashBump}
|
||||
/>
|
||||
)}
|
||||
{view === 'trash' && <TrashPage onUserChanged={onUserChanged} />}
|
||||
|
||||
Reference in new issue
Block a user