Files
pocketbase/ui/src/settings/backups/backupsList.js

230 lines
8.2 KiB
JavaScript

import { openBackupCreateModal } from "./backupCreateModal";
import { openBackupRestoreModal } from "./backupRestoreModal";
export function backupsList(propsArg = {}) {
const props = store({
reset: null,
});
const watchers = app.utils.extendStore(props, propsArg);
const data = store({
canBackup: true,
isLoading: false,
isDownloading: {},
isDeleting: {},
backups: [],
});
async function loadBackups() {
data.isLoading = true;
try {
data.backups = await app.pb.backups.getFullList();
// sort backups DESC by their modified date
data.backups.sort((a, b) => {
if (a.modified < b.modified) {
return 1;
}
if (a.modified > b.modified) {
return -1;
}
return 0;
});
data.isLoading = false;
} catch (err) {
if (!err.isAbort) {
app.checkApiError(err);
data.isLoading = false;
}
}
}
async function confirmBackupDelete(key) {
app.modals.confirm(`Do you really want to delete ${key}?`, () => deleteBackup(key));
}
async function deleteBackup(key) {
if (data.isDeleting[key]) {
return;
}
data.isDeleting[key] = true;
try {
await app.pb.backups.delete(key);
loadBackups();
app.toasts.success(`Successfully deleted ${key}.`);
} catch (err) {
app.checkApiError(err);
}
delete data.isDeleting[key];
}
async function loadCanBackup() {
try {
const health = await app.pb.health.check({ requestKey: null });
const oldCanBackup = data.canBackup;
data.canBackup = health?.data?.canBackup || false;
// reload backups list
if (data.canBackup && oldCanBackup != data.canBackup) {
loadBackups();
}
} catch (err) {
console.warn("failed to load canBackup checks", err);
}
}
async function downloadBackup(key) {
if (data.isDownloading[key]) {
return;
}
data.isDownloading[key] = true;
try {
const token = await app.pb.files.getToken({ requestKey: null });
app.utils.download(app.pb.backups.getDownloadURL(token, key));
} catch (err) {
app.checkApiError(err);
}
delete data.isDownloading[key];
}
return t.div(
{
pbEvent: "backupsList",
className: "list backups-list",
onmount: (el) => {
watchers.push(watch(() => props.reset, () => {
loadBackups();
}));
el._canBackupIntervalId = setInterval(() => {
loadCanBackup();
}, 3500);
},
onunmount: (el) => {
clearInterval(el._canBackupIntervalId);
watchers.forEach((w) => w?.unwatch());
},
},
t.div(
{ className: "list-content" },
t.div(
{
hidden: () => !data.isLoading || data.backups.length,
className: "list-item",
},
t.div({ className: "skeleton-loader" }),
),
t.div(
{
hidden: () => data.isLoading || data.backups.length,
className: () => "list-item",
},
t.div({ className: "content block txt-hint" }, "No backups found."),
),
() => {
return data.backups.map((backup) => {
return t.div(
{ className: () => `list-item ${data.isLoading ? "faded" : ""}` },
t.i({ className: "ri-folder-zip-line", ariaHidden: true }),
t.div(
{ className: "content" },
t.span({
className: "backup-name txt-ellipsis",
title: () => backup.key,
textContent: () => backup.key,
}),
t.small(
{ className: "backup-size txt-hint txt-nowrap" },
"(",
() => app.utils.formattedFileSize(backup.size),
")",
),
),
t.nav(
{
hidden: () => data.isLoading,
className: "actions autohide",
},
t.button(
{
type: "button",
ariaLabel: app.attrs.tooltip("Download"),
className: () =>
`btn sm circle secondary transparent ${
data.isDownloading[backup.key] ? "loading" : ""
}`,
disabled: () => data.isDeleting[backup.key] || data.isDownloading[backup.key],
onclick: () => downloadBackup(backup.key),
},
t.i({ className: "ri-download-line", ariaHidden: true }),
),
t.button(
{
type: "button",
ariaLabel: app.attrs.tooltip("Restore"),
className: () => `btn sm circle secondary transparent`,
disabled: () => data.isDeleting[backup.key] || data.isDownloading[backup.key],
onclick: () => openBackupRestoreModal(backup.key),
},
t.i({ className: "ri-restart-line", ariaHidden: true }),
),
t.button(
{
type: "button",
ariaLabel: app.attrs.tooltip("Delete"),
className: () =>
`btn sm circle secondary transparent ${
data.isDeleting[backup.key] ? "loading" : ""
}`,
disabled: () => data.isDeleting[backup.key] || data.isDownloading[backup.key],
onclick: () => confirmBackupDelete(backup.key),
},
t.i({ className: "ri-delete-bin-7-line", ariaHidden: true }),
),
),
);
});
},
),
t.div(
{ className: "list-item" },
t.button(
{
type: "button",
className: () => `btn secondary block ${data.isLoading ? "loading" : ""}`,
disabled: () => !data.canBackup || data.isLoading,
onclick: () => {
openBackupCreateModal({
oncreated: () => loadBackups(),
});
},
},
() => {
if (data.canBackup) {
return [
t.i({ className: "ri-play-circle-line", ariaHidden: true }),
t.span({ className: "txt" }, "Initialize new backup"),
];
}
return [
t.span({ className: "loader sm" }),
t.span({ className: "txt" }, "Backup/restore operation is in process"),
];
},
),
),
);
}