pocketbase/ui/src/components/settings/BackupRestorePanel.svelte

133 lines
3.8 KiB
Svelte

<script>
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import { setErrors } from "@/stores/errors";
import { addErrorToast } from "@/stores/toasts";
import OverlayPanel from "@/components/base/OverlayPanel.svelte";
import Field from "@/components/base/Field.svelte";
import CopyIcon from "@/components/base/CopyIcon.svelte";
import { onDestroy } from "svelte";
const formId = "backup_restore_" + CommonHelper.randomString(5);
let panel;
let name = "";
let nameConfirm = "";
let isSubmitting = false;
let reloadTimeoutId = null;
$: canSubmit = nameConfirm != "" && name == nameConfirm;
export function show(backupName) {
setErrors({});
nameConfirm = "";
name = backupName;
isSubmitting = false;
panel?.show();
}
export function hide() {
return panel?.hide();
}
async function submit() {
if (!canSubmit || isSubmitting) {
return;
}
clearTimeout(reloadTimeoutId);
isSubmitting = true;
try {
await ApiClient.backups.restore(name);
// optimistic restore page reload
reloadTimeoutId = setTimeout(() => {
window.location.reload();
}, 2000);
} catch (err) {
clearTimeout(reloadTimeoutId);
if (!err?.isAbort) {
isSubmitting = false;
addErrorToast(err.response?.message || err.message);
}
}
}
onDestroy(() => {
clearTimeout(reloadTimeoutId);
});
</script>
<OverlayPanel
bind:this={panel}
class="backup-restore-panel"
overlayClose={!isSubmitting}
escClose={!isSubmitting}
beforeHide={() => !isSubmitting}
popup
on:show
on:hide
>
<svelte:fragment slot="header">
<h4 class="popup-title txt-ellipsis">Restore <strong>{name}</strong></h4>
</svelte:fragment>
<div class="alert alert-danger">
<div class="icon">
<i class="ri-alert-line" />
</div>
<div class="content">
<p class="txt-bold">Please proceed with caution and use it only with trusted backup sources.</p>
<p>Backup restore is still experimental and currently works only on UNIX based systems.</p>
<p>
The restore operation will attempt to replace your existing <code>pb_data</code> with the one from
the backup and will restart the application process.
</p>
<p>
Nothing will happen if the backup file is invalid or incompatible (ex. missing
<code>data.db</code> file).
</p>
</div>
</div>
<div class="content m-b-sm">
Type the backup name
<div class="label">
<span class="txt">{name}</span>
<CopyIcon value={name} />
</div>
to confirm:
</div>
<form id={formId} autocomplete="off" on:submit|preventDefault={submit}>
<Field class="form-field required m-0" name="name" let:uniqueId>
<label for={uniqueId}>Backup name</label>
<input type="text" id={uniqueId} required bind:value={nameConfirm} />
</Field>
</form>
<svelte:fragment slot="footer">
<button type="button" class="btn btn-transparent" on:click={hide} disabled={isSubmitting}>
Cancel
</button>
<button
type="submit"
form={formId}
class="btn btn-expanded"
class:btn-loading={isSubmitting}
disabled={!canSubmit || isSubmitting}
>
<span class="txt">Restore backup</span>
</button>
</svelte:fragment>
</OverlayPanel>
<style>
.popup-title {
max-width: 80%;
}
</style>