mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-20 06:35:22 +02:00
- Updated the SetupServer component to use a Button instead of DropdownMenuItem for better accessibility and user experience. - Enhanced the ShowServers component by adding tooltips for the Setup Server action, providing users with additional context on server configuration.
379 lines
12 KiB
TypeScript
379 lines
12 KiB
TypeScript
import copy from "copy-to-clipboard";
|
|
import { CopyIcon, ExternalLinkIcon, ServerIcon, Settings } from "lucide-react";
|
|
import Link from "next/link";
|
|
import { useState } from "react";
|
|
import { toast } from "sonner";
|
|
import { AlertBlock } from "@/components/shared/alert-block";
|
|
import { CodeEditor } from "@/components/shared/code-editor";
|
|
import { DialogAction } from "@/components/shared/dialog-action";
|
|
import { DrawerLogs } from "@/components/shared/drawer-logs";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from "@/components/ui/dialog";
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
import { cn } from "@/lib/utils";
|
|
import { api } from "@/utils/api";
|
|
import { ShowDeployment } from "../../application/deployments/show-deployment";
|
|
import { type LogLine, parseLogs } from "../../docker/logs/utils";
|
|
import { EditScript } from "./edit-script";
|
|
import { GPUSupport } from "./gpu-support";
|
|
import { SecurityAudit } from "./security-audit";
|
|
import { SetupMonitoring } from "./setup-monitoring";
|
|
import { ValidateServer } from "./validate-server";
|
|
|
|
interface Props {
|
|
serverId: string;
|
|
asButton?: boolean;
|
|
}
|
|
|
|
export const SetupServer = ({ serverId, asButton = false }: Props) => {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const { data: server } = api.server.one.useQuery(
|
|
{
|
|
serverId,
|
|
},
|
|
{
|
|
enabled: !!serverId,
|
|
},
|
|
);
|
|
|
|
const [activeLog, setActiveLog] = useState<string | null>(null);
|
|
const { data: isCloud } = api.settings.isCloud.useQuery();
|
|
const isBuildServer = server?.serverType === "build";
|
|
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
|
const [filteredLogs, setFilteredLogs] = useState<LogLine[]>([]);
|
|
const [isDeploying, setIsDeploying] = useState(false);
|
|
api.server.setupWithLogs.useSubscription(
|
|
{
|
|
serverId: serverId,
|
|
},
|
|
{
|
|
enabled: isDeploying,
|
|
onData(log) {
|
|
if (!isDrawerOpen) {
|
|
setIsDrawerOpen(true);
|
|
}
|
|
|
|
if (log === "Deployment completed successfully!") {
|
|
setIsDeploying(false);
|
|
}
|
|
const parsedLogs = parseLogs(log);
|
|
setFilteredLogs((prev) => [...prev, ...parsedLogs]);
|
|
},
|
|
onError(error) {
|
|
console.error("Deployment logs error:", error);
|
|
setIsDeploying(false);
|
|
},
|
|
},
|
|
);
|
|
|
|
return (
|
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
|
{asButton ? (
|
|
<DialogTrigger asChild>
|
|
<Button variant="outline" size="icon" className="h-9 w-9">
|
|
<Settings className="h-4 w-4" />
|
|
</Button>
|
|
</DialogTrigger>
|
|
) : (
|
|
<Button
|
|
className="w-full cursor-pointer "
|
|
size="sm"
|
|
onClick={() => {
|
|
setIsOpen(true);
|
|
}}
|
|
>
|
|
Setup Server <Settings className="size-4" />
|
|
</Button>
|
|
)}
|
|
<DialogContent className="sm:max-w-4xl ">
|
|
<DialogHeader>
|
|
<div className="flex flex-col gap-1.5">
|
|
<DialogTitle className="flex items-center gap-2">
|
|
<ServerIcon className="size-5" /> Setup Server
|
|
</DialogTitle>
|
|
<p className="text-muted-foreground text-sm">
|
|
To setup a server, please click on the button below.
|
|
</p>
|
|
</div>
|
|
</DialogHeader>
|
|
{!server?.sshKeyId ? (
|
|
<div className="flex flex-col gap-2 text-sm text-muted-foreground pt-3">
|
|
<AlertBlock type="warning">
|
|
Please add a SSH Key to your server before setting up the server.
|
|
you can assign a SSH Key to your server in Edit Server.
|
|
</AlertBlock>
|
|
</div>
|
|
) : (
|
|
<div id="hook-form-add-gitlab" className="grid w-full gap-4">
|
|
<AlertBlock type="warning">
|
|
Using a root user is required to ensure everything works as
|
|
expected.
|
|
</AlertBlock>
|
|
|
|
<Tabs defaultValue="ssh-keys">
|
|
<TabsList
|
|
className={cn(
|
|
"grid w-[700px]",
|
|
isBuildServer
|
|
? "grid-cols-3"
|
|
: isCloud
|
|
? "grid-cols-6"
|
|
: "grid-cols-5",
|
|
)}
|
|
>
|
|
<TabsTrigger value="ssh-keys">SSH Keys</TabsTrigger>
|
|
<TabsTrigger value="deployments">Deployments</TabsTrigger>
|
|
<TabsTrigger value="validate">Validate</TabsTrigger>
|
|
|
|
{!isBuildServer && (
|
|
<>
|
|
<TabsTrigger value="audit">Security</TabsTrigger>
|
|
{isCloud && (
|
|
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
|
|
)}
|
|
<TabsTrigger value="gpu-setup">GPU Setup</TabsTrigger>
|
|
</>
|
|
)}
|
|
</TabsList>
|
|
<TabsContent
|
|
value="ssh-keys"
|
|
className="outline-none ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
|
|
>
|
|
<div className="flex flex-col gap-2 text-sm text-muted-foreground pt-3">
|
|
<p className="text-primary text-base font-semibold">
|
|
You have two options to add SSH Keys to your server:
|
|
</p>
|
|
|
|
<ul>
|
|
<li>
|
|
1. Add the public SSH Key when you create a server in your
|
|
preffered provider (Hostinger, Digital Ocean, Hetzner,
|
|
etc){" "}
|
|
</li>
|
|
<li>2. Add The SSH Key to Server Manually</li>
|
|
</ul>
|
|
<div className="flex flex-col gap-4 w-full overflow-auto">
|
|
<div className="flex relative flex-col gap-2 overflow-y-auto">
|
|
<div className="text-sm text-primary flex flex-row gap-2 items-center">
|
|
Copy Public Key ({server?.sshKey?.name})
|
|
<button
|
|
type="button"
|
|
className="right-2 top-8"
|
|
onClick={() => {
|
|
copy(
|
|
server?.sshKey?.publicKey || "Generate a SSH Key",
|
|
);
|
|
toast.success("SSH Copied to clipboard");
|
|
}}
|
|
>
|
|
<CopyIcon className="size-4 text-muted-foreground" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-2 w-full mt-2 border rounded-lg p-4">
|
|
<span className="text-base font-semibold text-primary">
|
|
Automatic process
|
|
</span>
|
|
<Link
|
|
href="https://docs.dokploy.com/docs/core/multi-server/instructions#requirements"
|
|
target="_blank"
|
|
className="text-primary flex flex-row gap-2"
|
|
>
|
|
View Tutorial <ExternalLinkIcon className="size-4" />
|
|
</Link>
|
|
</div>
|
|
<div className="flex flex-col gap-2 w-full border rounded-lg p-4">
|
|
<span className="text-base font-semibold text-primary">
|
|
Manual process
|
|
</span>
|
|
<ul>
|
|
<li className="items-center flex gap-1">
|
|
1. Login to your server{" "}
|
|
<span className="text-primary bg-secondary p-1 rounded-lg">
|
|
ssh {server?.username}@{server?.ipAddress}
|
|
</span>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
copy(
|
|
`ssh ${server?.username}@${server?.ipAddress}`,
|
|
);
|
|
toast.success("Copied to clipboard");
|
|
}}
|
|
>
|
|
<CopyIcon className="size-4" />
|
|
</button>
|
|
</li>
|
|
<li>
|
|
2. When you are logged in run the following command
|
|
<div className="flex relative flex-col gap-4 w-full mt-2">
|
|
<CodeEditor
|
|
lineWrapping
|
|
language="properties"
|
|
value={`echo "${server?.sshKey?.publicKey}" >> ~/.ssh/authorized_keys`}
|
|
readOnly
|
|
className="font-mono opacity-60"
|
|
/>
|
|
<button
|
|
type="button"
|
|
className="absolute right-2 top-2"
|
|
onClick={() => {
|
|
copy(
|
|
`echo "${server?.sshKey?.publicKey}" >> ~/.ssh/authorized_keys`,
|
|
);
|
|
toast.success("Copied to clipboard");
|
|
}}
|
|
>
|
|
<CopyIcon className="size-4" />
|
|
</button>
|
|
</div>
|
|
</li>
|
|
<li className="mt-1">
|
|
3. You're done, you can test the connection by entering
|
|
to the terminal or by setting up the server tab.
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div className="flex flex-col gap-2 w-full border rounded-lg p-4">
|
|
<span className="text-base font-semibold text-primary">
|
|
Supported Distros:
|
|
</span>
|
|
<p>
|
|
We strongly recommend to use the following distros to
|
|
ensure the best experience:
|
|
</p>
|
|
<ul>
|
|
<li>1. Ubuntu 24.04 LTS</li>
|
|
<li>2. Ubuntu 23.10 LTS </li>
|
|
<li>3. Ubuntu 22.04 LTS</li>
|
|
<li>4. Ubuntu 20.04 LTS</li>
|
|
<li>5. Ubuntu 18.04 LTS</li>
|
|
<li>6. Debian 12</li>
|
|
<li>7. Debian 11</li>
|
|
<li>8. Debian 10</li>
|
|
<li>9. Fedora 40</li>
|
|
<li>10. Centos 9</li>
|
|
<li>11. Centos 8</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</TabsContent>
|
|
<TabsContent value="deployments">
|
|
<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 max-sm:flex-col">
|
|
<div className="flex flex-col gap-1">
|
|
<CardTitle className="text-xl">
|
|
Setup Server
|
|
</CardTitle>
|
|
<CardDescription>
|
|
To setup a server, please click on the button
|
|
below.
|
|
</CardDescription>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent className="flex flex-col gap-4 min-h-[25vh] items-center">
|
|
<div className="flex flex-col gap-4 items-center h-full max-w-xl mx-auto min-h-[25vh] justify-center">
|
|
<span className="text-sm text-muted-foreground text-center">
|
|
When your server is ready, you can click on the
|
|
button below, to directly run the script we use for
|
|
setup the server or directly modify the script
|
|
</span>
|
|
<div className="flex flex-row gap-2">
|
|
<EditScript serverId={server?.serverId || ""} />
|
|
<DialogAction
|
|
title={"Setup Server?"}
|
|
type="default"
|
|
description="This will setup the server and all associated data"
|
|
onClick={async () => {
|
|
setIsDeploying(true);
|
|
}}
|
|
>
|
|
<Button>Setup Server</Button>
|
|
</DialogAction>
|
|
</div>
|
|
</div>
|
|
|
|
<ShowDeployment
|
|
open={activeLog !== null}
|
|
onClose={() => setActiveLog(null)}
|
|
logPath={activeLog}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</CardContent>
|
|
</TabsContent>
|
|
<TabsContent
|
|
value="validate"
|
|
className="outline-none ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
|
|
>
|
|
<div className="flex flex-col gap-2 text-sm text-muted-foreground pt-3">
|
|
<ValidateServer serverId={serverId} />
|
|
</div>
|
|
</TabsContent>
|
|
{!isBuildServer && (
|
|
<>
|
|
<TabsContent
|
|
value="audit"
|
|
className="outline-none ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
|
|
>
|
|
<div className="flex flex-col gap-2 text-sm text-muted-foreground pt-3">
|
|
<SecurityAudit serverId={serverId} />
|
|
</div>
|
|
</TabsContent>
|
|
<TabsContent
|
|
value="monitoring"
|
|
className="outline-none ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
|
|
>
|
|
<div className="flex flex-col gap-2 text-sm pt-3">
|
|
<div className="rounded-xl bg-background shadow-md border">
|
|
<SetupMonitoring serverId={serverId} />
|
|
</div>
|
|
</div>
|
|
</TabsContent>
|
|
<TabsContent
|
|
value="gpu-setup"
|
|
className="outline-none ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
|
|
>
|
|
<div className="flex flex-col gap-2 text-sm text-muted-foreground pt-3">
|
|
<GPUSupport serverId={serverId} />
|
|
</div>
|
|
</TabsContent>
|
|
</>
|
|
)}
|
|
</Tabs>
|
|
</div>
|
|
)}
|
|
</DialogContent>
|
|
<DrawerLogs
|
|
isOpen={isDrawerOpen}
|
|
onClose={() => {
|
|
setIsDrawerOpen(false);
|
|
setFilteredLogs([]);
|
|
setIsDeploying(false);
|
|
}}
|
|
filteredLogs={filteredLogs}
|
|
/>
|
|
</Dialog>
|
|
);
|
|
};
|