mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat(cluster-nodes): enhance node management by adding serverId prop to components and implementing ShowNodesModal
This commit is contained in:
parent
60c03e1ca7
commit
35ff8dcfe6
@ -13,7 +13,11 @@ import Link from "next/link";
|
||||
import { AddManager } from "./manager/add-manager";
|
||||
import { AddWorker } from "./workers/add-worker";
|
||||
|
||||
export const AddNode = () => {
|
||||
interface Props {
|
||||
serverId?: string;
|
||||
}
|
||||
|
||||
export const AddNode = ({ serverId }: Props) => {
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
@ -53,10 +57,10 @@ export const AddNode = () => {
|
||||
<TabsTrigger value="manager">Manager</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="worker" className="pt-4">
|
||||
<AddWorker />
|
||||
<AddWorker serverId={serverId} />
|
||||
</TabsContent>
|
||||
<TabsContent value="manager" className="pt-4">
|
||||
<AddManager />
|
||||
<AddManager serverId={serverId} />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
@ -9,8 +9,12 @@ import copy from "copy-to-clipboard";
|
||||
import { CopyIcon } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export const AddManager = () => {
|
||||
const { data } = api.cluster.addManager.useQuery();
|
||||
interface Props {
|
||||
serverId?: string;
|
||||
}
|
||||
|
||||
export const AddManager = ({ serverId }: Props) => {
|
||||
const { data } = api.cluster.addManager.useQuery({ serverId });
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -0,0 +1,30 @@
|
||||
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
|
||||
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
|
||||
import { useState } from "react";
|
||||
import { ShowNodes } from "./show-nodes";
|
||||
|
||||
interface Props {
|
||||
serverId: string;
|
||||
}
|
||||
|
||||
export const ShowNodesModal = ({ serverId }: Props) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<DropdownMenuItem
|
||||
className="w-full cursor-pointer "
|
||||
onSelect={(e) => e.preventDefault()}
|
||||
>
|
||||
Show Nodes
|
||||
</DropdownMenuItem>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-5xl overflow-y-auto max-h-screen ">
|
||||
<div className="grid w-full gap-1">
|
||||
<ShowNodes serverId={serverId} />
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
@ -32,13 +32,25 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { api } from "@/utils/api";
|
||||
import { Boxes, HelpCircle, LockIcon, MoreHorizontal } from "lucide-react";
|
||||
import {
|
||||
Boxes,
|
||||
HelpCircle,
|
||||
LockIcon,
|
||||
MoreHorizontal,
|
||||
Loader2,
|
||||
} from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { AddNode } from "./add-node";
|
||||
import { ShowNodeData } from "./show-node-data";
|
||||
|
||||
export const ShowNodes = () => {
|
||||
const { data, isLoading, refetch } = api.cluster.getNodes.useQuery();
|
||||
interface Props {
|
||||
serverId?: string;
|
||||
}
|
||||
|
||||
export const ShowNodes = ({ serverId }: Props) => {
|
||||
const { data, isLoading, refetch } = api.cluster.getNodes.useQuery({
|
||||
serverId,
|
||||
});
|
||||
const { data: registry } = api.registry.all.useQuery();
|
||||
|
||||
const { mutateAsync: deleteNode } = api.cluster.removeWorker.useMutation();
|
||||
@ -58,14 +70,17 @@ export const ShowNodes = () => {
|
||||
</div>
|
||||
{haveAtLeastOneRegistry && (
|
||||
<div className="flex flex-row gap-2">
|
||||
<AddNode />
|
||||
<AddNode serverId={serverId} />
|
||||
</div>
|
||||
)}
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2 py-8 border-t min-h-[35vh]">
|
||||
{haveAtLeastOneRegistry ? (
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center w-full h-[40vh]">
|
||||
<Loader2 className="size-8 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
) : haveAtLeastOneRegistry ? (
|
||||
<div className="grid md:grid-cols-1 gap-4">
|
||||
{isLoading && <div>Loading...</div>}
|
||||
<Table>
|
||||
<TableCaption>
|
||||
A list of your managers / workers.
|
||||
@ -137,6 +152,7 @@ export const ShowNodes = () => {
|
||||
onClick={async () => {
|
||||
await deleteNode({
|
||||
nodeId: node.ID,
|
||||
serverId,
|
||||
})
|
||||
.then(() => {
|
||||
refetch();
|
||||
|
@ -9,8 +9,12 @@ import copy from "copy-to-clipboard";
|
||||
import { CopyIcon } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export const AddWorker = () => {
|
||||
const { data } = api.cluster.addWorker.useQuery();
|
||||
interface Props {
|
||||
serverId?: string;
|
||||
}
|
||||
|
||||
export const AddWorker = ({ serverId }: Props) => {
|
||||
const { data } = api.cluster.addWorker.useQuery({ serverId });
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -42,6 +42,7 @@ import { ShowMonitoringModal } from "./show-monitoring-modal";
|
||||
import { ShowSwarmOverviewModal } from "./show-swarm-overview-modal";
|
||||
import { ShowTraefikFileSystemModal } from "./show-traefik-file-system-modal";
|
||||
import { WelcomeSuscription } from "./welcome-stripe/welcome-suscription";
|
||||
import { ShowNodesModal } from "../cluster/nodes/show-nodes-modal";
|
||||
|
||||
export const ShowServers = () => {
|
||||
const { t } = useTranslation("settings");
|
||||
@ -328,6 +329,9 @@ export const ShowServers = () => {
|
||||
<ShowSwarmOverviewModal
|
||||
serverId={server.serverId}
|
||||
/>
|
||||
<ShowNodesModal
|
||||
serverId={server.serverId}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
|
@ -1,22 +1,35 @@
|
||||
import { getPublicIpWithFallback } from "@/server/wss/terminal";
|
||||
import { type DockerNode, IS_CLOUD, docker, execAsync } from "@dokploy/server";
|
||||
import {
|
||||
type DockerNode,
|
||||
IS_CLOUD,
|
||||
execAsync,
|
||||
getRemoteDocker,
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
|
||||
export const clusterRouter = createTRPCRouter({
|
||||
getNodes: protectedProcedure.query(async () => {
|
||||
if (IS_CLOUD) {
|
||||
return [];
|
||||
}
|
||||
const workers: DockerNode[] = await docker.listNodes();
|
||||
getNodes: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
serverId: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
if (IS_CLOUD) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return workers;
|
||||
}),
|
||||
const docker = await getRemoteDocker(input.serverId);
|
||||
const workers: DockerNode[] = await docker.listNodes();
|
||||
|
||||
return workers;
|
||||
}),
|
||||
removeWorker: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
nodeId: z.string(),
|
||||
serverId: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
@ -40,37 +53,51 @@ export const clusterRouter = createTRPCRouter({
|
||||
});
|
||||
}
|
||||
}),
|
||||
addWorker: protectedProcedure.query(async () => {
|
||||
if (IS_CLOUD) {
|
||||
return {
|
||||
command: "",
|
||||
version: "",
|
||||
};
|
||||
}
|
||||
const result = await docker.swarmInspect();
|
||||
const docker_version = await docker.version();
|
||||
addWorker: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
serverId: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
if (IS_CLOUD) {
|
||||
return {
|
||||
command: "",
|
||||
version: "",
|
||||
};
|
||||
}
|
||||
const docker = await getRemoteDocker(input.serverId);
|
||||
const result = await docker.swarmInspect();
|
||||
const docker_version = await docker.version();
|
||||
|
||||
return {
|
||||
command: `docker swarm join --token ${
|
||||
result.JoinTokens.Worker
|
||||
} ${await getPublicIpWithFallback()}:2377`,
|
||||
version: docker_version.Version,
|
||||
};
|
||||
}),
|
||||
addManager: protectedProcedure.query(async () => {
|
||||
if (IS_CLOUD) {
|
||||
return {
|
||||
command: "",
|
||||
version: "",
|
||||
command: `docker swarm join --token ${
|
||||
result.JoinTokens.Worker
|
||||
} ${await getPublicIpWithFallback()}:2377`,
|
||||
version: docker_version.Version,
|
||||
};
|
||||
}
|
||||
const result = await docker.swarmInspect();
|
||||
const docker_version = await docker.version();
|
||||
return {
|
||||
command: `docker swarm join --token ${
|
||||
result.JoinTokens.Manager
|
||||
} ${await getPublicIpWithFallback()}:2377`,
|
||||
version: docker_version.Version,
|
||||
};
|
||||
}),
|
||||
}),
|
||||
addManager: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
serverId: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
if (IS_CLOUD) {
|
||||
return {
|
||||
command: "",
|
||||
version: "",
|
||||
};
|
||||
}
|
||||
const docker = await getRemoteDocker(input.serverId);
|
||||
const result = await docker.swarmInspect();
|
||||
const docker_version = await docker.version();
|
||||
return {
|
||||
command: `docker swarm join --token ${
|
||||
result.JoinTokens.Manager
|
||||
} ${await getPublicIpWithFallback()}:2377`,
|
||||
version: docker_version.Version,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user