feat(react/settings): port backup DB list

This commit is contained in:
Elian Doran
2025-08-15 13:11:44 +03:00
parent 6f19fde76e
commit 25dce64c3b
3 changed files with 65 additions and 5 deletions

View File

@@ -1,4 +1,4 @@
import { BackupDatabaseNowResponse } from "@triliumnext/commons"; import { BackupDatabaseNowResponse, DatabaseBackup } from "@triliumnext/commons";
import { t } from "../../../services/i18n"; import { t } from "../../../services/i18n";
import server from "../../../services/server"; import server from "../../../services/server";
import toast from "../../../services/toast"; import toast from "../../../services/toast";
@@ -8,12 +8,32 @@ import FormGroup from "../../react/FormGroup";
import FormText from "../../react/FormText"; import FormText from "../../react/FormText";
import { useTriliumOptionBool } from "../../react/hooks"; import { useTriliumOptionBool } from "../../react/hooks";
import OptionsSection from "./components/OptionsSection"; import OptionsSection from "./components/OptionsSection";
import { useCallback, useEffect, useState } from "preact/hooks";
import { formatDateTime } from "../../../utils/formatters";
export default function BackupSettings() { export default function BackupSettings() {
const [ backups, setBackups ] = useState<DatabaseBackup[]>([]);
const refreshBackups = useCallback(() => {
server.get<DatabaseBackup[]>("database/backups").then((backupFiles) => {
// Sort the backup files by modification date & time in a desceding order
backupFiles.sort((a, b) => {
if (a.mtime < b.mtime) return 1;
if (a.mtime > b.mtime) return -1;
return 0;
});
setBackups(backupFiles);
});
}, [ setBackups ]);
useEffect(refreshBackups, []);
return ( return (
<> <>
<AutomaticBackup /> <AutomaticBackup />
<BackupNow /> <BackupNow refreshCallback={refreshBackups} />
<BackupList backups={backups} />
</> </>
) )
} }
@@ -50,7 +70,7 @@ export function AutomaticBackup() {
) )
} }
export function BackupNow() { export function BackupNow({ refreshCallback }: { refreshCallback: () => void }) {
return ( return (
<OptionsSection title={t("backup.backup_now")}> <OptionsSection title={t("backup.backup_now")}>
<Button <Button
@@ -58,8 +78,42 @@ export function BackupNow() {
onClick={async () => { onClick={async () => {
const { backupFile } = await server.post<BackupDatabaseNowResponse>("database/backup-database"); const { backupFile } = await server.post<BackupDatabaseNowResponse>("database/backup-database");
toast.showMessage(t("backup.database_backed_up_to", { backupFilePath: backupFile }), 10000); toast.showMessage(t("backup.database_backed_up_to", { backupFilePath: backupFile }), 10000);
refreshCallback();
}} }}
/> />
</OptionsSection> </OptionsSection>
) )
}
export function BackupList({ backups }: { backups: DatabaseBackup[] }) {
return (
<OptionsSection title={t("backup.existing_backups")}>
<table class="table table-stripped">
<colgroup>
<col width="33%" />
<col />
</colgroup>
<thead>
<tr>
<th>{t("backup.date-and-time")}</th>
<th>{t("backup.path")}</th>
</tr>
</thead>
<tbody>
{ backups.length > 0 ? (
backups.map(({ mtime, filePath }) => (
<tr>
<td>{mtime ? formatDateTime(mtime) : "-"}</td>
<td>{filePath}</td>
</tr>
))
) : (
<tr>
<td className="empty-table-placeholder" colspan={2}>{t("backup.no_backup_yet")}</td>
</tr>
)}
</tbody>
</table>
</OptionsSection>
);
} }

View File

@@ -9,11 +9,11 @@ import syncMutexService from "./sync_mutex.js";
import cls from "./cls.js"; import cls from "./cls.js";
import sql from "./sql.js"; import sql from "./sql.js";
import path from "path"; import path from "path";
import type { OptionNames } from "@triliumnext/commons"; import type { DatabaseBackup, OptionNames } from "@triliumnext/commons";
type BackupType = "daily" | "weekly" | "monthly"; type BackupType = "daily" | "weekly" | "monthly";
function getExistingBackups() { function getExistingBackups(): DatabaseBackup[] {
if (!fs.existsSync(dataDir.BACKUP_DIR)) { if (!fs.existsSync(dataDir.BACKUP_DIR)) {
return []; return [];
} }

View File

@@ -101,3 +101,9 @@ export interface PostTokensResponse {
export interface BackupDatabaseNowResponse { export interface BackupDatabaseNowResponse {
backupFile: string; backupFile: string;
} }
export interface DatabaseBackup {
fileName: string;
filePath: string;
mtime: Date;
}