chore: stylistic changes
This commit is contained in:
parent
1b780ed127
commit
19e0a950fd
4 changed files with 61 additions and 72 deletions
|
|
@ -64,7 +64,7 @@ export function CompressionStatsChart({ repositoryShortId, initialStats }: Props
|
||||||
|
|
||||||
const hasStats = !!stats && (storedSize > 0 || uncompressedSize > 0 || snapshotsCount > 0);
|
const hasStats = !!stats && (storedSize > 0 || uncompressedSize > 0 || snapshotsCount > 0);
|
||||||
|
|
||||||
const storedPercent = uncompressedSize > 0 ? (storedSize / uncompressedSize) * 100 : 0;
|
const storedPercent = Math.min(100, Math.max(0, uncompressedSize > 0 ? (storedSize / uncompressedSize) * 100 : 0));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="flex flex-col px-6 py-6">
|
<Card className="flex flex-col px-6 py-6">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { useMutation, useSuspenseQuery } from "@tanstack/react-query";
|
import { useMutation, useSuspenseQuery } from "@tanstack/react-query";
|
||||||
import { Suspense, useState } from "react";
|
import { useState } from "react";
|
||||||
import { useNavigate, useSearch } from "@tanstack/react-router";
|
import { useNavigate, useSearch } from "@tanstack/react-router";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { ChevronDown, Database, Pencil, Square, Stethoscope, Trash2, Unlock } from "lucide-react";
|
import { ChevronDown, Database, Pencil, Square, Stethoscope, Trash2, Unlock } from "lucide-react";
|
||||||
|
|
@ -134,7 +134,7 @@ export default function RepositoryDetailsPage({
|
||||||
{repository.provisioningId && <Badge variant="secondary">Managed</Badge>}
|
{repository.provisioningId && <Badge variant="secondary">Managed</Badge>}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-muted-foreground mt-0.5">
|
<p className="text-sm text-muted-foreground mt-0.5">
|
||||||
Created {formatDateTime(repository.createdAt)} · Last checked{" "}
|
Created {formatDateTime(repository.createdAt)} · Last checked
|
||||||
{formatTimeAgo(repository.lastChecked)}
|
{formatTimeAgo(repository.lastChecked)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -222,13 +222,11 @@ export default function RepositoryDetailsPage({
|
||||||
<RepositoryInfoTabContent repository={repository} initialStats={initialStats} />
|
<RepositoryInfoTabContent repository={repository} initialStats={initialStats} />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="snapshots">
|
<TabsContent value="snapshots">
|
||||||
<Suspense>
|
<RepositorySnapshotsTabContent
|
||||||
<RepositorySnapshotsTabContent
|
repository={repository}
|
||||||
repository={repository}
|
initialSnapshots={initialSnapshots}
|
||||||
initialSnapshots={initialSnapshots}
|
initialBackupSchedules={initialBackupSchedules}
|
||||||
initialBackupSchedules={initialBackupSchedules}
|
/>
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -140,36 +140,35 @@ export function VolumeDetails({ volumeId }: { volumeId: string }) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{isMounted ? (
|
<Button
|
||||||
<Button
|
className={cn({ hidden: !isMounted })}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
toast.promise(unmountVol.mutateAsync({ path: { shortId: volume.shortId } }), {
|
toast.promise(unmountVol.mutateAsync({ path: { shortId: volume.shortId } }), {
|
||||||
loading: "Unmounting volume...",
|
loading: "Unmounting volume...",
|
||||||
success: "Volume unmounted successfully",
|
success: "Volume unmounted successfully",
|
||||||
error: (error) => parseError(error)?.message || "Failed to unmount volume",
|
error: (error) => parseError(error)?.message || "Failed to unmount volume",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
loading={unmountVol.isPending}
|
loading={unmountVol.isPending}
|
||||||
>
|
>
|
||||||
<Unplug className="h-4 w-4 mr-2" />
|
<Unplug className="h-4 w-4 mr-2" />
|
||||||
Unmount
|
Unmount
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
<Button
|
||||||
<Button
|
className={cn({ hidden: isMounted })}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
toast.promise(mountVol.mutateAsync({ path: { shortId: volume.shortId } }), {
|
toast.promise(mountVol.mutateAsync({ path: { shortId: volume.shortId } }), {
|
||||||
loading: "Mounting volume...",
|
loading: "Mounting volume...",
|
||||||
success: "Volume mounted successfully",
|
success: "Volume mounted successfully",
|
||||||
error: (error) => parseError(error)?.message || "Failed to mount volume",
|
error: (error) => parseError(error)?.message || "Failed to mount volume",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
loading={mountVol.isPending}
|
loading={mountVol.isPending}
|
||||||
>
|
>
|
||||||
<Plug className="h-4 w-4 mr-2" />
|
<Plug className="h-4 w-4 mr-2" />
|
||||||
Mount
|
Mount
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button variant="outline">
|
<Button variant="outline">
|
||||||
|
|
@ -203,19 +202,18 @@ export function VolumeDetails({ volumeId }: { volumeId: string }) {
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<HeartIcon className="h-4 w-4 text-muted-foreground" />
|
<HeartIcon className="h-4 w-4 text-muted-foreground" />
|
||||||
<span className="text-sm font-medium">Health</span>
|
<span className="text-sm font-medium">Health</span>
|
||||||
{isError ? (
|
<Badge variant="destructive" className={cn("ml-1", { hidden: !isError })}>
|
||||||
<Badge variant="destructive" className="ml-1">
|
Error
|
||||||
Error
|
</Badge>
|
||||||
</Badge>
|
<Badge
|
||||||
) : isMounted ? (
|
variant="outline"
|
||||||
<Badge variant="outline" className="text-success border-success/30 bg-success/10 ml-1">
|
className={cn("text-success border-success/30 bg-success/10 ml-1", { hidden: !isMounted })}
|
||||||
Healthy
|
>
|
||||||
</Badge>
|
Healthy
|
||||||
) : (
|
</Badge>
|
||||||
<Badge variant="secondary" className="ml-1">
|
<Badge variant="secondary" className={cn("ml-1", { hidden: isMounted || isError })}>
|
||||||
Unmounted
|
Unmounted
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<Separator orientation="vertical" className="h-4 hidden @lg:block" />
|
<Separator orientation="vertical" className="h-4 hidden @lg:block" />
|
||||||
<span className="text-sm text-muted-foreground">Checked {formatTimeAgo(volume.lastHealthCheck)}</span>
|
<span className="text-sm text-muted-foreground">Checked {formatTimeAgo(volume.lastHealthCheck)}</span>
|
||||||
|
|
@ -248,14 +246,12 @@ export function VolumeDetails({ volumeId }: { volumeId: string }) {
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{volume.lastError && (
|
<Card className={cn("px-6 py-6", { hidden: !volume.lastError })}>
|
||||||
<Card className="px-6 py-6">
|
<div className="space-y-2">
|
||||||
<div className="space-y-2">
|
<p className="text-sm font-medium text-destructive">Last Error</p>
|
||||||
<p className="text-sm font-medium text-destructive">Last Error</p>
|
<p className="text-sm text-muted-foreground wrap-break-word">{volume.lastError}</p>
|
||||||
<p className="text-sm text-muted-foreground wrap-break-word">{volume.lastError}</p>
|
</div>
|
||||||
</div>
|
</Card>
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Tabs value={activeTab} onValueChange={(value) => navigate({ to: ".", search: () => ({ tab: value }) })}>
|
<Tabs value={activeTab} onValueChange={(value) => navigate({ to: ".", search: () => ({ tab: value }) })}>
|
||||||
<TabsList className="mb-2">
|
<TabsList className="mb-2">
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { FolderOpen, HardDrive, Settings, Unplug } from "lucide-react";
|
||||||
import { Label, Pie, PieChart } from "recharts";
|
import { Label, Pie, PieChart } from "recharts";
|
||||||
import { ByteSize } from "~/client/components/bytes-size";
|
import { ByteSize } from "~/client/components/bytes-size";
|
||||||
import { Card, CardTitle } from "~/client/components/ui/card";
|
import { Card, CardTitle } from "~/client/components/ui/card";
|
||||||
import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from "~/client/components/ui/chart";
|
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "~/client/components/ui/chart";
|
||||||
import type { StatFs, Volume } from "~/client/lib/types";
|
import type { StatFs, Volume } from "~/client/lib/types";
|
||||||
import { cn } from "~/client/lib/utils";
|
import { cn } from "~/client/lib/utils";
|
||||||
|
|
||||||
|
|
@ -21,17 +21,14 @@ const backendLabels: Record<Volume["type"], string> = {
|
||||||
sftp: "SFTP",
|
sftp: "SFTP",
|
||||||
};
|
};
|
||||||
|
|
||||||
function ConfigRow({
|
type ConfigRowProps = {
|
||||||
icon,
|
|
||||||
label,
|
|
||||||
value,
|
|
||||||
mono,
|
|
||||||
}: {
|
|
||||||
icon: React.ReactNode;
|
icon: React.ReactNode;
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
mono?: boolean;
|
mono?: boolean;
|
||||||
}) {
|
};
|
||||||
|
|
||||||
|
function ConfigRow({ icon, label, value, mono }: ConfigRowProps) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-3 py-3 first:pt-0 last:pb-0">
|
<div className="flex items-center gap-3 py-3 first:pt-0 last:pb-0">
|
||||||
<span className="text-muted-foreground shrink-0">{icon}</span>
|
<span className="text-muted-foreground shrink-0">{icon}</span>
|
||||||
|
|
@ -95,14 +92,12 @@ function DonutChart({ statfs }: { statfs: StatFs }) {
|
||||||
[statfs],
|
[statfs],
|
||||||
);
|
);
|
||||||
|
|
||||||
const chartConfig = {} satisfies ChartConfig;
|
|
||||||
|
|
||||||
const usagePercentage = useMemo(() => {
|
const usagePercentage = useMemo(() => {
|
||||||
return Math.round((statfs.used / statfs.total) * 100);
|
return Math.round((statfs.used / statfs.total) * 100);
|
||||||
}, [statfs]);
|
}, [statfs]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[200px]">
|
<ChartContainer config={{}} className="mx-auto aspect-square max-h-[200px]">
|
||||||
<PieChart>
|
<PieChart>
|
||||||
<ChartTooltip
|
<ChartTooltip
|
||||||
cursor={false}
|
cursor={false}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue