import { useEffect, useState } from 'react' import { AlertTriangle, CheckCircle2, CloudUpload, Loader2, ShieldCheck, ShieldX } from 'lucide-react' import { api, type Einstellungen as EinstellungenDaten } from '../api' import { run, useStore } from '../store' import { bytes, zeit } from '../format' import { Feld, Karte, Knopf } from '../components/Bausteine' import { DiscordKarte } from '../components/DiscordKarte' import { VorlagenKarte } from '../components/VorlagenKarte' import { FreigabenKarte } from '../components/FreigabenKarte' import { MeldungenKarte } from '../components/MeldungenKarte' /** Alles, was sich einstellen lässt, an einer Stelle. * * Bisher lag die Discord-Karte beim Konto und die Zugangsdaten der Sicherung * in einer Textdatei auf der Platte. Beides ist jetzt hier — und das ist mehr * als Aufräumen: eine Textdatei sagt niemandem, ob die Sicherung heute Nacht * gelaufen ist. Diese Seite tut es. */ export function Einstellungen() { const [urls, setUrls] = useState({ publicUrl: '', filePrefix: '' }) // Die Vorlagenkarte zeigt die FERTIGE Adresse und nicht nur das Muster — // dafuer braucht sie den Ursprung, und der steht in der Uebersicht. useEffect(() => { api.uebersicht() .then((u) => setUrls({ publicUrl: u.publicUrl, filePrefix: u.filePrefix })) .catch(() => {}) }, []) return (
) } function SicherungKarte() { const note = useStore((s) => s.note) const [daten, setDaten] = useState(null) const [laedt, setLaedt] = useState(true) const [speichert, setSpeichert] = useState(false) const [basis, setBasis] = useState('') const [benutzer, setBenutzer] = useState('') const [passwort, setPasswort] = useState('') const [ordner, setOrdner] = useState('') const [behalten, setBehalten] = useState('14') async function laden() { setLaedt(true) try { const e = await api.einstellungen() setDaten(e) setBasis(e.sicherung.basis) setBenutzer(e.sicherung.benutzer) setOrdner(e.sicherung.ordner) setBehalten(String(e.sicherung.behalten)) } catch (err) { note('fehler', err instanceof Error ? err.message : 'Unbekannt') } finally { setLaedt(false) } } useEffect(() => { void laden() // eslint-disable-next-line react-hooks/exhaustive-deps }, []) async function speichern() { setSpeichert(true) const ergebnis = await run( () => api.sicherungSpeichern({ basis, benutzer, ...(passwort ? { passwort } : {}), ordner, behalten: Number(behalten), }), (r) => r.bereit ? 'Gespeichert. Die nächste Sicherung geht in die Nextcloud.' : `Gespeichert. Es fehlt noch: ${r.fehlt.join(', ')}.`, ) setSpeichert(false) if (ergebnis) { setPasswort('') void laden() } } if (laedt) { return (
) } if (!daten) return null const s = daten.sicherung const l = s.letzte return ( eingerichtet ) : ( nur lokal ) } >
{/* Das Wichtigste zuerst: LIEF sie? Eine Sicherung, die still aufhoert zu laufen, ist der eigentliche Schaden. */}
{!l ? ( ) : l.ok ? ( ) : ( )} {!l ? ( 'Noch keine Sicherung gemeldet. Sie läuft täglich um 04:30 als geplante Aufgabe.' ) : ( <> Zuletzt {zeit(l.at)} — {l.ok ? 'erfolgreich' : 'FEHLGESCHLAGEN'} {l.dateien != null && `, ${l.dateien} Dateien`} {l.groesse != null && `, ${bytes(l.groesse)}`} {l.hoch === true && ', in der Nextcloud'} {l.hoch === false && ', nur lokal'} {l.fehler && ( {l.fehler} )} )}
setBasis(e.target.value)} /> setBenutzer(e.target.value)} /> setPasswort(e.target.value)} /> setOrdner(e.target.value)} /> setBehalten(e.target.value)} />

Nimm ein App-Passwort, nicht dein echtes: Nextcloud → Einstellungen → Sicherheit → „Neues App-Passwort erstellen". Es lässt sich einzeln zurückziehen. Das Skript liest die Werte direkt aus der Datenbank des Dienstes — über HTTP geht das Passwort nur hier beim Eintragen, und das über TLS.

) }