mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-14 01:50:39 +09:00
feat(backups): gzip compress backups and add retention config to Instance Settings
Compress database backups with gzip (.sql.gz), reducing file size ~83%. Add backup retention configuration to Instance Settings UI with preset options (7 days, 2 weeks, 1 month). The backup scheduler now reads retention from the database on each tick so changes take effect without restart. Default retention changed from 30 to 7 days.
This commit is contained in:
parent
316790ea0a
commit
cc44d309c0
11 changed files with 107 additions and 17 deletions
|
|
@ -1,7 +1,8 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import type { PatchInstanceGeneralSettings } from "@paperclipai/shared";
|
||||
import { LogOut, SlidersHorizontal } from "lucide-react";
|
||||
import type { PatchInstanceGeneralSettings, BackupRetentionDays } from "@paperclipai/shared";
|
||||
import { BACKUP_RETENTION_PRESETS, DEFAULT_BACKUP_RETENTION_DAYS } from "@paperclipai/shared";
|
||||
import { Database, LogOut, SlidersHorizontal } from "lucide-react";
|
||||
import { authApi } from "@/api/auth";
|
||||
import { instanceSettingsApi } from "@/api/instanceSettings";
|
||||
import { Button } from "../components/ui/button";
|
||||
|
|
@ -67,6 +68,7 @@ export function InstanceGeneralSettings() {
|
|||
const censorUsernameInLogs = generalQuery.data?.censorUsernameInLogs === true;
|
||||
const keyboardShortcuts = generalQuery.data?.keyboardShortcuts === true;
|
||||
const feedbackDataSharingPreference = generalQuery.data?.feedbackDataSharingPreference ?? "prompt";
|
||||
const backupRetentionDays: BackupRetentionDays = generalQuery.data?.backupRetentionDays ?? DEFAULT_BACKUP_RETENTION_DAYS;
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl space-y-6">
|
||||
|
|
@ -123,6 +125,49 @@ export function InstanceGeneralSettings() {
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<section className="rounded-xl border border-border bg-card p-5">
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Database className="h-4 w-4 text-muted-foreground" />
|
||||
<div className="space-y-1.5">
|
||||
<h2 className="text-sm font-semibold">Backup retention</h2>
|
||||
<p className="max-w-2xl text-sm text-muted-foreground">
|
||||
How long to keep automatic database backups before pruning. Backups are compressed
|
||||
with gzip to minimize disk usage.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{BACKUP_RETENTION_PRESETS.map((days) => {
|
||||
const active = backupRetentionDays === days;
|
||||
const label =
|
||||
days === 7 ? "7 days" : days === 14 ? "2 weeks" : "1 month";
|
||||
return (
|
||||
<button
|
||||
key={days}
|
||||
type="button"
|
||||
disabled={updateGeneralMutation.isPending}
|
||||
className={cn(
|
||||
"rounded-lg border px-3 py-2 text-left transition-colors disabled:cursor-not-allowed disabled:opacity-60",
|
||||
active
|
||||
? "border-foreground bg-accent text-foreground"
|
||||
: "border-border bg-background hover:bg-accent/50",
|
||||
)}
|
||||
onClick={() =>
|
||||
updateGeneralMutation.mutate({ backupRetentionDays: days })
|
||||
}
|
||||
>
|
||||
<div className="text-sm font-medium">{label}</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
Keep backups for {days} days
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="rounded-xl border border-border bg-card p-5">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-1.5">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue