import { useState } from "react"; import { LuDownload, LuUpload } from "react-icons/lu"; import { errorMessage } from "../api/client.js"; import { useDownloadWorkflowBackup, useRestoreWorkflowBackup, } from "../api/hooks.js"; import { ConfirmDialog } from "../components/ConfirmDialog.jsx"; import { useNotifications } from "../notifications.jsx"; export function BackupPage() { const backup = useDownloadWorkflowBackup(); const restoreBackup = useRestoreWorkflowBackup(); const { notify } = useNotifications(); const [restoreMode, setRestoreMode] = useState("merge"); const [pendingFile, setPendingFile] = useState(null); function download() { backup.mutate(undefined, { onSuccess: () => notify.success("Backup downloaded"), onError: (err) => notify.error(errorMessage(err)), }); } function restore(file, mode) { restoreBackup.mutate( { file, mode }, { onSuccess: (data) => { notify.success("Backup restored"); if (data.warnings?.length) { notify.warning(data.warnings.join("; ")); } }, onError: (err) => notify.error(errorMessage(err)), onSettled: () => setPendingFile(null), }, ); } function onPickFile(e) { const file = e.target.files?.[0]; e.target.value = ""; if (!file) return; if (restoreMode === "replace") { setPendingFile(file); return; } restore(file, restoreMode); } return (

Backup

Download or restore workflows and installed plugins as a zip archive.

Download

Includes workflow YAML and installed plugins. Use this to copy the setup to another machine or keep a snapshot before a restore.

Restore

Merge keeps existing files and overwrites matches from the zip. Replace deletes current workflows and plugins first.

Current workflows and plugins will be deleted, then{" "} {pendingFile.name} will be restored. This cannot be undone from this page. ) : null } confirmLabel="Replace" loading={restoreBackup.isPending} onCancel={() => setPendingFile(null)} onConfirm={() => restore(pendingFile, "replace")} />
); }