Verschieben hatte denselben Fehler -- und Ordner entfernen gab es nur im Dienst

VERSCHIEBEN: derselbe Griff wie beim Loeschen, dieselbe Wirkung.

    onClick={() => setVerschieben(items.filter((i) => gewaehlt.has(i.id)))}

`items` ist die offene Seite; von 3565 gewaehlten Bildern wanderten 60. Ich
hatte gestern nur das Loeschen repariert und diese Stelle nicht gesucht --
zwei Knoepfe mit demselben Muster, und ich habe einen davon uebersehen.

Jetzt haelt der Auftrag auch hier `ids` (alle) und `namen` (die benennbaren)
getrennt, und verschoben wird in Haeppchen zu 200 mit Fortschritt im Knopf.
Was nicht ging, wird benannt statt verschwiegen.

ORDNER ENTFERNEN: die Route gab es (`DELETE /folders/:pfad`), die
Schnittstelle auch (`ordnerEntfernen` in api.ts) -- nur wurde sie NIRGENDS
aufgerufen. Eine Funktion ohne Knopf ist fuer den, der sie sucht, nicht
vorhanden; dieselbe Lehre steht schon ueber "Neuer Ordner" in derselben Datei.

Der Knopf sitzt jetzt neben dem Umbenennen, erst beim Darueberfahren sichtbar.
Die REGEL bleibt beim Dienst: er lehnt einen Ordner mit Inhalt ab und sagt,
wieviele Dateien darin liegen. Sie in der Oberflaeche zu wiederholen hiesse,
sie zweimal zu pflegen -- und die zweite Fassung ist irgendwann die falsche.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-26 13:44:38 +02:00
co-authored by Claude Opus 5
parent 8a17b8b974
commit c9e5bb3c31
3 changed files with 116 additions and 25 deletions
+42 -1
View File
@@ -1,5 +1,5 @@
import { useState } from 'react'
import { Check, Folder, FolderOpen, FolderPlus, Layers, PenLine, X } from 'lucide-react'
import { Check, Folder, FolderOpen, FolderPlus, Layers, PenLine, Trash2, X } from 'lucide-react'
import { api, type Folders } from '../api'
import { bytes } from '../format'
import { run } from '../store'
@@ -22,6 +22,7 @@ export function Ordner({
onWahl,
onAngelegt,
onUmbenennen,
onEntfernt,
}: {
daten: Folders | null
gewaehlt: string
@@ -29,12 +30,28 @@ export function Ordner({
/** Damit die Liste den neuen Ordner auch zeigt. */
onAngelegt: () => void
onUmbenennen: (pfad: string) => void
/** Nach dem Entfernen muss die Liste neu geladen werden -- sonst steht
* dort ein Ordner, den es nicht mehr gibt. */
onEntfernt: () => void
}) {
const [neu, setNeu] = useState<string | null>(null)
const [legtAn, setLegtAn] = useState(false)
if (!daten) return null
async function entfernen(pfad: string) {
// Nachfragen, und dabei sagen, was NICHT passiert: der Ordner geht,
// die Dateien darin gehen nicht -- der Dienst laesst ihn ohnehin nur
// leer entfernen.
if (!confirm(`Ordner "${pfad}" entfernen?
Er muss leer sein; Dateien darin werden nicht angetastet.`)) {
return
}
const r = await run(() => api.ordnerEntfernen(pfad), `Ordner ${pfad} entfernt.`)
if (r) onEntfernt()
}
async function anlegen() {
const name = (neu ?? '').trim()
if (!name) return
@@ -96,6 +113,30 @@ export function Ordner({
</button>
)}
{/* ORDNER ENTFERNEN. Den Weg gab es im Dienst und in `api.ts`
laengst -- es fehlte allein der Knopf, und damit war die
Funktion fuer den, der sie sucht, nicht vorhanden. Dieselbe
Lehre wie beim "Neuer Ordner" ein paar Zeilen weiter oben.
DIE PRUEFUNG BLEIBT BEIM DIENST: er lehnt einen Ordner mit
Inhalt ab und sagt, wieviele Dateien darin liegen. Diese Regel
hier zu wiederholen hiesse, sie zweimal zu pflegen -- und die
zweite Fassung ist irgendwann die falsche. */}
{pfad !== undefined && (
<button
onClick={(e) => {
e.stopPropagation()
void entfernen(pfad)
}}
className="shrink-0 text-schrift-leise opacity-0 transition-opacity
group-hover:opacity-100 hover:text-schlecht focus-visible:opacity-100"
aria-label={`${pfad} entfernen`}
title="Ordner entfernen (muss leer sein)"
>
<Trash2 size={12} />
</button>
)}
<span className="shrink-0 text-[11px] tabular-nums text-schrift-leise">
{anzahl}
</span>