mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-15 20:25:23 +02:00
* refactor: add sidebar * chore: add deps * refactor: update sidebar * refactor: another layout * refactor: update variant * refactor: change layout * refactor: change variant * refactor: enhance sidebar navigation with active state management * feat: add project button to dashboard * Merge branch 'canary' into feat/add-sidebar * refactor: add loader * refactor: update destinations and refactor * refactor: ui refactor certificates * refactor: delete unused files * refactor: remove unused files and duplicate registry * refactor: update style registry * refactor: add new design registry * refactor: enhance git providers * refactor: remove duplicate files * refactor: update * refactor: update users * refactor: delete unused files * refactor: update profile * refactor: apply changes * refactor: update UI * refactor: enhance Docker monitoring UI layout * refactor: add theme toggle and language selection to user navigation (#1083) * refactor: remove unused files * feat: add filter to services * refactor: add active items * refactor: remove tab prop * refactor: remove unused files * refactor: remove duplicated files * refactor: remove unused files * refactor: remove duplicate files * refactor: remove unused files * refactor: delete unused files * refactor: remove unsued files * refactor: delete unused files * refactor: lint * refactor: remove unused secuirty * refactor: delete unused files * refactor: delete unused files * remove imports * refactor: add update button * refactor: delete unused files * refactor: remove unused code * refactor: remove unused files * refactor: update login page * refactor: update login UI * refactor: update ui reset password * refactor: add justify end * feat: add suscriptions * feat: add sheet * feat: add logs for postgres * feat: add logs for all databases * feat: add server logs with drawer logs * refactor: remove unused files * refactor: add refetch when closing * refactor: fix linter * chore: bump node-20 * revert * refactor: fix conflicts * refactor: update * refactor: add missing deps * refactor: delete duplicate files * refactor: delete unsued files * chore: lint * refactor: remove unsued file * refactor: add refetch * refactor: remove duplicated files * refactor: delete unused files * refactor: update setup onboarding * refactor: add breadcrumb * refactor: apply updates * refactor: add faker * refactor: use 0 in validation * refactor: show correct state * refactor: update --------- Co-authored-by: vishalkadam47 <vishal@jeevops.com> Co-authored-by: Vishal kadam <107353260+vishalkadam47@users.noreply.github.com>
215 lines
7.2 KiB
TypeScript
215 lines
7.2 KiB
TypeScript
import { DialogAction } from "@/components/shared/dialog-action";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipProvider,
|
|
TooltipTrigger,
|
|
} from "@/components/ui/tooltip";
|
|
import { api } from "@/utils/api";
|
|
import { DatabaseBackup, Play, Trash2 } from "lucide-react";
|
|
import Link from "next/link";
|
|
import React from "react";
|
|
import { toast } from "sonner";
|
|
import type { ServiceType } from "../../application/advanced/show-resources";
|
|
import { AddBackup } from "./add-backup";
|
|
import { UpdateBackup } from "./update-backup";
|
|
|
|
interface Props {
|
|
id: string;
|
|
type: Exclude<ServiceType, "application" | "redis">;
|
|
}
|
|
export const ShowBackups = ({ id, type }: Props) => {
|
|
const queryMap = {
|
|
postgres: () =>
|
|
api.postgres.one.useQuery({ postgresId: id }, { enabled: !!id }),
|
|
mysql: () => api.mysql.one.useQuery({ mysqlId: id }, { enabled: !!id }),
|
|
mariadb: () =>
|
|
api.mariadb.one.useQuery({ mariadbId: id }, { enabled: !!id }),
|
|
mongo: () => api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id }),
|
|
};
|
|
const { data } = api.destination.all.useQuery();
|
|
const { data: postgres, refetch } = queryMap[type]
|
|
? queryMap[type]()
|
|
: api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id });
|
|
|
|
const mutationMap = {
|
|
postgres: () => api.backup.manualBackupPostgres.useMutation(),
|
|
mysql: () => api.backup.manualBackupMySql.useMutation(),
|
|
mariadb: () => api.backup.manualBackupMariadb.useMutation(),
|
|
mongo: () => api.backup.manualBackupMongo.useMutation(),
|
|
};
|
|
|
|
const { mutateAsync: manualBackup, isLoading: isManualBackup } = mutationMap[
|
|
type
|
|
]
|
|
? mutationMap[type]()
|
|
: api.backup.manualBackupMongo.useMutation();
|
|
|
|
const { mutateAsync: deleteBackup, isLoading: isRemoving } =
|
|
api.backup.remove.useMutation();
|
|
|
|
return (
|
|
<Card className="bg-background">
|
|
<CardHeader className="flex flex-row justify-between gap-4 flex-wrap">
|
|
<div className="flex flex-col gap-0.5">
|
|
<CardTitle className="text-xl">Backups</CardTitle>
|
|
<CardDescription>
|
|
Add backups to your database to save the data to a different
|
|
provider.
|
|
</CardDescription>
|
|
</div>
|
|
|
|
{postgres && postgres?.backups?.length > 0 && (
|
|
<AddBackup databaseId={id} databaseType={type} refetch={refetch} />
|
|
)}
|
|
</CardHeader>
|
|
<CardContent className="flex flex-col gap-4">
|
|
{data?.length === 0 ? (
|
|
<div className="flex flex-col items-center gap-3">
|
|
<DatabaseBackup className="size-8 text-muted-foreground" />
|
|
<span className="text-base text-muted-foreground">
|
|
To create a backup it is required to set at least 1 provider.
|
|
Please, go to{" "}
|
|
<Link
|
|
href="/dashboard/settings/server"
|
|
className="text-foreground"
|
|
>
|
|
Settings
|
|
</Link>{" "}
|
|
to do so.
|
|
</span>
|
|
</div>
|
|
) : (
|
|
<div>
|
|
{postgres?.backups.length === 0 ? (
|
|
<div className="flex w-full flex-col items-center justify-center gap-3 pt-10">
|
|
<DatabaseBackup className="size-8 text-muted-foreground" />
|
|
<span className="text-base text-muted-foreground">
|
|
No backups configured
|
|
</span>
|
|
<AddBackup
|
|
databaseId={id}
|
|
databaseType={type}
|
|
refetch={refetch}
|
|
/>
|
|
</div>
|
|
) : (
|
|
<div className="flex flex-col pt-2">
|
|
<div className="flex flex-col gap-6">
|
|
{postgres?.backups.map((backup) => (
|
|
<div key={backup.backupId}>
|
|
<div className="flex w-full flex-col md:flex-row md:items-center justify-between gap-4 md:gap-10 border rounded-lg p-4">
|
|
<div className="grid grid-cols-1 md:grid-cols-3 xl:grid-cols-5 flex-col gap-8">
|
|
<div className="flex flex-col gap-1">
|
|
<span className="font-medium">Destination</span>
|
|
<span className="text-sm text-muted-foreground">
|
|
{backup.destination.name}
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-col gap-1">
|
|
<span className="font-medium">Database</span>
|
|
<span className="text-sm text-muted-foreground">
|
|
{backup.database}
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-col gap-1">
|
|
<span className="font-medium">Scheduled</span>
|
|
<span className="text-sm text-muted-foreground">
|
|
{backup.schedule}
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-col gap-1">
|
|
<span className="font-medium">Prefix Storage</span>
|
|
<span className="text-sm text-muted-foreground">
|
|
{backup.prefix}
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-col gap-1">
|
|
<span className="font-medium">Enabled</span>
|
|
<span className="text-sm text-muted-foreground">
|
|
{backup.enabled ? "Yes" : "No"}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-row gap-4">
|
|
<TooltipProvider delayDuration={0}>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
isLoading={isManualBackup}
|
|
onClick={async () => {
|
|
await manualBackup({
|
|
backupId: backup.backupId as string,
|
|
})
|
|
.then(async () => {
|
|
toast.success(
|
|
"Manual Backup Successful",
|
|
);
|
|
})
|
|
.catch(() => {
|
|
toast.error(
|
|
"Error creating the manual backup",
|
|
);
|
|
});
|
|
}}
|
|
>
|
|
<Play className="size-5 text-muted-foreground" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>Run Manual Backup</TooltipContent>
|
|
</Tooltip>
|
|
</TooltipProvider>
|
|
<UpdateBackup
|
|
backupId={backup.backupId}
|
|
refetch={refetch}
|
|
/>
|
|
<DialogAction
|
|
title="Delete Backup"
|
|
description="Are you sure you want to delete this backup?"
|
|
type="destructive"
|
|
onClick={async () => {
|
|
await deleteBackup({
|
|
backupId: backup.backupId,
|
|
})
|
|
.then(() => {
|
|
refetch();
|
|
toast.success("Backup deleted successfully");
|
|
})
|
|
.catch(() => {
|
|
toast.error("Error deleting backup");
|
|
});
|
|
}}
|
|
>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="group hover:bg-red-500/10"
|
|
isLoading={isRemoving}
|
|
>
|
|
<Trash2 className="size-4 text-primary group-hover:text-red-500" />
|
|
</Button>
|
|
</DialogAction>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
};
|