zerobyte/app/client/modules/backups/components/create-schedule-form/summary-section.tsx
2026-03-26 19:35:18 +01:00

121 lines
4.3 KiB
TypeScript

import { useQuery } from "@tanstack/react-query";
import { listRepositoriesOptions } from "~/client/api-client/@tanstack/react-query.gen";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card";
import { cn } from "~/client/lib/utils";
import type { Volume } from "~/client/lib/types";
import type { InternalFormValues } from "./types";
type SummarySectionProps = {
volume: Volume;
frequency: string | undefined;
formValues: InternalFormValues;
};
export const SummarySection = ({ volume, frequency, formValues }: SummarySectionProps) => {
const { data: repositoriesData } = useQuery({
...listRepositoriesOptions(),
});
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between gap-4">
<div>
<CardTitle>Schedule summary</CardTitle>
<CardDescription>Review the backup configuration.</CardDescription>
</div>
</CardHeader>
<CardContent className="flex flex-col gap-4 text-sm">
<div>
<p className="text-xs uppercase text-muted-foreground">Volume</p>
<p className="font-medium">{volume.name}</p>
</div>
<div>
<p className="text-xs uppercase text-muted-foreground">Schedule</p>
<p className="font-medium">
<span className={cn({ hidden: frequency !== "manual" })}>Manual only</span>
<span className={cn({ hidden: !frequency || frequency === "manual" })}>
{frequency ? frequency.charAt(0).toUpperCase() + frequency.slice(1) : null}
</span>
<span className={cn({ hidden: Boolean(frequency) })}>-</span>
</p>
</div>
<div>
<p className="text-xs uppercase text-muted-foreground">Repository</p>
<p className="font-medium">
{repositoriesData?.find((r) => r.shortId === formValues.repositoryId)?.name || "—"}
</p>
</div>
{(formValues.includePaths && formValues.includePaths.length > 0) || formValues.includePatterns ? (
<div>
<p className="text-xs uppercase text-muted-foreground">Include paths/patterns</p>
<div className="flex flex-col gap-1">
{formValues.includePaths?.slice(0, 20).map((path) => (
<span key={path} className="text-xs font-mono bg-accent px-1.5 py-0.5 rounded">
{path}
</span>
))}
{formValues.includePaths && formValues.includePaths.length > 20 && (
<span className="text-xs text-muted-foreground">+ {formValues.includePaths.length - 20} more</span>
)}
{formValues.includePatterns
?.split("\n")
.filter(Boolean)
.slice(0, 20 - (formValues.includePaths?.length || 0))
.map((pattern) => (
<span key={pattern} className="text-xs font-mono bg-accent px-1.5 py-0.5 rounded">
{pattern.trim()}
</span>
))}
</div>
</div>
) : null}
{formValues.excludePatternsText && (
<div>
<p className="text-xs uppercase text-muted-foreground">Exclude patterns</p>
<div className="flex flex-col gap-1">
{formValues.excludePatternsText
.split("\n")
.filter(Boolean)
.map((pattern) => (
<span key={pattern} className="text-xs font-mono bg-accent px-1.5 py-0.5 rounded">
{pattern.trim()}
</span>
))}
</div>
</div>
)}
{formValues.excludeIfPresentText && (
<div>
<p className="text-xs uppercase text-muted-foreground">Exclude if present</p>
<div className="flex flex-col gap-1">
{formValues.excludeIfPresentText
.split("\n")
.filter(Boolean)
.map((filename) => (
<span key={filename} className="text-xs font-mono bg-accent px-1.5 py-0.5 rounded">
{filename.trim()}
</span>
))}
</div>
</div>
)}
<div>
<p className="text-xs uppercase text-muted-foreground">One file system</p>
<p className="font-medium">{formValues.oneFileSystem ? "Enabled" : "Disabled"}</p>
</div>
<div>
<p className="text-xs uppercase text-muted-foreground">Retention</p>
<p className="font-medium">
{Object.entries(formValues)
.filter(([key, value]) => key.startsWith("keep") && Boolean(value))
.map(([key, value]) => {
const label = key.replace("keep", "").toLowerCase();
return `${value.toString()} ${label}`;
})
.join(", ") || "-"}
</p>
</div>
</CardContent>
</Card>
);
};