import { useState } from 'react' import { AlertTriangle, FolderInput, Plus } from 'lucide-react' import { api, type Folders, type MediaItem } from '../api' import { run, useStore } from '../store' import { Feld, Knopf } from './Bausteine' /** Dateien in einen anderen Ordner legen. * * DIE WARNUNG STEHT OBEN UND NICHT IM KLEINGEDRUCKTEN. Der Pfad IST die * öffentliche Adresse: wer ein Bild verschiebt, macht jede Stelle ungültig, * die die alte URL benutzt — im Handy, in einer Vorlage, in einem * Zwischenspeicher. Das ist kein Fehler, sondern der Preis vorhersagbarer * Adressen; nur muss man es vorher wissen und nicht hinterher suchen. */ export function Verschieben({ ids, namen, ordner, onFertig, onAbbruch, }: { /** ALLE Gewaehlten. */ ids: number[] /** Nur die, deren Pfad bekannt ist -- die der offenen Seite. Fuer die * Anzeige, nicht fuer die Handlung. */ namen: MediaItem[] ordner: Folders | null onFertig: () => void onAbbruch: () => void }) { const [ziel, setZiel] = useState('') const [neuerOrdner, setNeuerOrdner] = useState('') const [laeuft, setLaeuft] = useState(false) const [fortschritt, setFortschritt] = useState(0) const beispiel = namen[0] const name = beispiel?.path.split('/').pop() ?? '' const neuerPfad = ziel ? `${ziel}/${name}` : name async function verschieben() { setLaeuft(true) const { note } = useStore.getState() // IN HAEPPCHEN, wie beim Loeschen: der Dienst verschiebt jede Datei // einzeln, und tausende in einer Anfrage laufen in die Zeitgrenze des // Proxys. 200 je Runde, und der Knopf sagt, wie weit es ist. const PORTION = 200 let bewegt = 0 let daneben: string[] = [] let abbruch: string | null = null for (let i = 0; i < ids.length; i += PORTION) { try { const x = await api.verschieben(ids.slice(i, i + PORTION), ziel) bewegt += x.verschoben daneben.push( ...x.ergebnisse.filter((e) => !e.ok).map((e) => `${e.path} (${e.error})`), ) } catch (e) { abbruch = e instanceof Error ? e.message : 'Unbekannt' break } setFortschritt(bewegt) } setLaeuft(false) if (abbruch) { note('fehler', `${bewegt} von ${ids.length} verschoben, dann brach es ab: ${abbruch}`) return } if (daneben.length === 0) { note('ok', `${bewegt} verschoben.`) } else { // Was NICHT ging, wird benannt -- ein "verschoben" ueber einer // halben Bewegung waere die Sorte Rueckmeldung, die hier nicht // vorkommt. note( 'hinweis', `${bewegt} verschoben, ${daneben.length} nicht: ${daneben.slice(0, 3).join('; ')}` + (daneben.length > 3 ? ` … und ${daneben.length - 3} weitere` : ''), ) } onFertig() } async function ordnerAnlegen() { const pfad = neuerOrdner.trim() if (!pfad) return const r = await run(() => api.ordnerAnlegen(pfad), (x) => `Ordner ${x.pfad} angelegt.`) if (r) { setZiel(r.pfad) setNeuerOrdner('') } } return (
e.stopPropagation()} >

{ids.length === 1 ? 'Datei verschieben' : `${ids.length} Dateien verschieben`}

Der Pfad ist die öffentliche Adresse. Nach dem Verschieben führt die alte URL ins Leere — überall, wo sie steht.

setNeuerOrdner(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() void ordnerAnlegen() } }} /> void ordnerAnlegen()} kind={} />
{/* Zeigen, WAS daraus wird — nicht nur, wohin es geht. */} {beispiel && (
{beispiel.path}
{neuerPfad}
{ids.length > 1 && (
… und {ids.length - 1} weitere
)}
)}
void verschieben()} kind={ // Bei tausenden Dateien dauert es; Stillstand ist // sonst von Haengen nicht zu unterscheiden. laeuft && fortschritt > 0 ? `${fortschritt} von ${ids.length} …` : 'Verschieben' } />
) }