Files
dokploy/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx
T
Mauricio Siu 8ab6d6b282 chore: clean up unused variables and improve error handling across codebase
This commit focuses on removing unused variables, adding placeholder error handling, and generally tidying up various files across the Dokploy application. Changes include:

- Removing unused imports and variables
- Adding placeholder error handling in catch blocks
- Cleaning up commented-out code
- Removing deprecated utility files
- Improving type safety and code consistency
2025-02-22 20:35:21 -06:00

282 lines
7.8 KiB
TypeScript

import { AlertBlock } from "@/components/shared/alert-block";
import { DialogAction } from "@/components/shared/dialog-action";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { api } from "@/utils/api";
import { CheckCircle2, Cpu, Loader2, RefreshCw, XCircle } from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "sonner";
interface GPUSupportProps {
serverId?: string;
}
export function GPUSupport({ serverId }: GPUSupportProps) {
const [isLoading, setIsLoading] = useState(false);
const [isRefreshing, setIsRefreshing] = useState(false);
const utils = api.useContext();
const {
data: gpuStatus,
isLoading: isChecking,
refetch,
} = api.settings.checkGPUStatus.useQuery(
{ serverId },
{
enabled: serverId !== undefined,
},
);
const setupGPU = api.settings.setupGPU.useMutation({
onMutate: () => {
setIsLoading(true);
},
onSuccess: async () => {
toast.success("GPU support enabled successfully");
setIsLoading(false);
await utils.settings.checkGPUStatus.invalidate({ serverId });
},
onError: (error) => {
toast.error(
error.message ||
"Failed to enable GPU support. Please check server logs.",
);
setIsLoading(false);
},
});
const handleRefresh = async () => {
setIsRefreshing(true);
try {
await utils.settings.checkGPUStatus.invalidate({ serverId });
await refetch();
} catch (_error) {
toast.error("Failed to refresh GPU status");
} finally {
setIsRefreshing(false);
}
};
useEffect(() => {
handleRefresh();
}, []);
const handleEnableGPU = async () => {
if (serverId === undefined) {
toast.error("No server selected");
return;
}
try {
await setupGPU.mutateAsync({ serverId });
} catch (_error) {
// Error handling is done in mutation's onError
}
};
return (
<CardContent className="p-0">
<div className="flex flex-col gap-4">
<Card className="bg-background">
<CardHeader className="flex flex-row items-center justify-between flex-wrap gap-2">
<div className="flex flex-row gap-2 justify-between w-full items-end max-sm:flex-col">
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<Cpu className="size-5" />
<CardTitle className="text-xl">GPU Configuration</CardTitle>
</div>
<CardDescription>
Configure and monitor GPU support
</CardDescription>
</div>
<div className="flex items-center gap-2">
<DialogAction
title="Enable GPU Support?"
description="This will enable GPU support for Docker Swarm on this server. Make sure you have the required hardware and drivers installed."
onClick={handleEnableGPU}
>
<Button
isLoading={isLoading}
disabled={isLoading || serverId === undefined || isChecking}
>
{isLoading
? "Enabling GPU..."
: gpuStatus?.swarmEnabled
? "Reconfigure GPU"
: "Enable GPU"}
</Button>
</DialogAction>
<Button
size="icon"
onClick={handleRefresh}
disabled={isChecking || isRefreshing}
>
<RefreshCw
className={`h-5 w-5 ${isChecking || isRefreshing ? "animate-spin" : ""}`}
/>
</Button>
</div>
</div>
</CardHeader>
<CardContent className="flex flex-col gap-4">
<AlertBlock type="info">
<div className="font-medium mb-2">System Requirements:</div>
<ul className="list-disc list-inside text-sm space-y-1">
<li>NVIDIA GPU hardware must be physically installed</li>
<li>
NVIDIA drivers must be installed and running (check with
nvidia-smi)
</li>
<li>
NVIDIA Container Runtime must be installed
(nvidia-container-runtime)
</li>
<li>User must have sudo/administrative privileges</li>
<li>System must support CUDA for GPU acceleration</li>
</ul>
</AlertBlock>
{isChecking ? (
<div className="flex items-center justify-center text-muted-foreground py-4">
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
<span>Checking GPU status...</span>
</div>
) : (
<div className="grid gap-4">
{/* Prerequisites Section */}
<div className="border rounded-lg p-4">
<h3 className="text-lg font-semibold mb-1">Prerequisites</h3>
<p className="text-sm text-muted-foreground mb-4">
Shows all software checks and available hardware
</p>
<div className="grid gap-2.5">
<StatusRow
label="NVIDIA Driver"
isEnabled={gpuStatus?.driverInstalled}
description={
gpuStatus?.driverVersion
? `Installed (v${gpuStatus.driverVersion})`
: "Not Installed"
}
/>
<StatusRow
label="GPU Model"
value={gpuStatus?.gpuModel || "Not Detected"}
showIcon={false}
/>
<StatusRow
label="GPU Memory"
value={gpuStatus?.memoryInfo || "Not Available"}
showIcon={false}
/>
<StatusRow
label="Available GPUs"
value={gpuStatus?.availableGPUs || 0}
showIcon={false}
/>
<StatusRow
label="CUDA Support"
isEnabled={gpuStatus?.cudaSupport}
description={
gpuStatus?.cudaVersion
? `Available (v${gpuStatus.cudaVersion})`
: "Not Available"
}
/>
<StatusRow
label="NVIDIA Container Runtime"
isEnabled={gpuStatus?.runtimeInstalled}
description={
gpuStatus?.runtimeInstalled
? "Installed"
: "Not Installed"
}
/>
</div>
</div>
{/* Configuration Status */}
<div className="border rounded-lg p-4">
<h3 className="text-lg font-semibold mb-1">
Docker Swarm GPU Status
</h3>
<p className="text-sm text-muted-foreground mb-4">
Shows the configuration state that changes with the Enable
GPU
</p>
<div className="grid gap-2.5">
<StatusRow
label="Runtime Configuration"
isEnabled={gpuStatus?.runtimeConfigured}
description={
gpuStatus?.runtimeConfigured
? "Default Runtime"
: "Not Default Runtime"
}
/>
<StatusRow
label="Swarm GPU Support"
isEnabled={gpuStatus?.swarmEnabled}
description={
gpuStatus?.swarmEnabled
? `Enabled (${gpuStatus.gpuResources} GPU${gpuStatus.gpuResources !== 1 ? "s" : ""})`
: "Not Enabled"
}
/>
</div>
</div>
</div>
)}
</CardContent>
</Card>
</div>
</CardContent>
);
}
interface StatusRowProps {
label: string;
isEnabled?: boolean;
description?: string;
value?: string | number;
showIcon?: boolean;
}
export function StatusRow({
label,
isEnabled,
description,
value,
showIcon = true,
}: StatusRowProps) {
return (
<div className="flex items-center justify-between">
<span className="text-sm">{label}</span>
<div className="flex items-center gap-2">
{showIcon ? (
<>
<span
className={`text-sm ${isEnabled ? "text-green-500" : "text-red-500"}`}
>
{description || (isEnabled ? "Installed" : "Not Installed")}
</span>
{isEnabled ? (
<CheckCircle2 className="size-4 text-green-500" />
) : (
<XCircle className="size-4 text-red-500" />
)}
</>
) : (
<span className="text-sm text-muted-foreground">{value}</span>
)}
</div>
</div>
);
}