Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: swarm style improvement #1038

Merged
merged 2 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export function NodeCard({ node, serverId }: Props) {
</CardHeader>
<CardContent>
<div className="space-y-6">
<div className="flex flex-wrap items-center justify-between">
<div className="flex flex-wrap gap-y-2 items-center justify-between">
<div className="flex items-center space-x-4 p-2 rounded-xl border">
<div className={`h-2.5 w-2.5 rounded-full ${node.Status === "Ready" ? "bg-green-500" : "bg-red-500"}`} />
<div className="font-medium">{node.Hostname}</div>
Expand Down
256 changes: 133 additions & 123 deletions apps/dokploy/components/dashboard/swarm/monitoring-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,23 @@ import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { api } from "@/utils/api";
import {
Activity,
Loader2,
Monitor,
Settings,
Server,
} from "lucide-react";
import { Activity, Loader2, Monitor, Settings, Server } from "lucide-react";
import { NodeCard } from "./details/details-card";

interface Props {
serverId?: string;
serverId?: string;
}

export default function SwarmMonitorCard({ serverId }: Props) {
const { data: nodes, isLoading } = api.swarm.getNodes.useQuery({
serverId,
});
const { data: nodes, isLoading } = api.swarm.getNodes.useQuery({
serverId,
});

if (isLoading) {
return (
Expand All @@ -50,116 +44,132 @@ export default function SwarmMonitorCard({ serverId }: Props) {
);
}

const totalNodes = nodes.length;
const activeNodesCount = nodes.filter((node) => node.Status === "Ready").length;
const managerNodesCount = nodes.filter((node) =>node.ManagerStatus === "Leader" || node.ManagerStatus === "Reachable").length;
const activeNodes = nodes.filter((node) => node.Status === "Ready");
const managerNodes = nodes.filter((node) => node.ManagerStatus === "Leader" || node.ManagerStatus === "Reachable");
const totalNodes = nodes.length;
const activeNodesCount = nodes.filter(
(node) => node.Status === "Ready",
).length;
const managerNodesCount = nodes.filter(
(node) =>
node.ManagerStatus === "Leader" || node.ManagerStatus === "Reachable",
).length;
const activeNodes = nodes.filter((node) => node.Status === "Ready");
const managerNodes = nodes.filter(
(node) =>
node.ManagerStatus === "Leader" || node.ManagerStatus === "Reachable",
);

return (
<div className="min-h-screen">
<div className="w-full max-w-7xl mx-auto space-y-6 py-4">
<header className="flex items-center justify-between">
<div className="space-y-1">
<h1 className="text-2xl font-semibold tracking-tight">Docker Swarm Overview</h1>
<p className="text-sm text-muted-foreground">Monitor and manage your Docker Swarm cluster</p>
</div>
{!serverId && (
<Button onClick={() => window.location.replace("/dashboard/settings/cluster")}>
<Settings className="mr-2 h-4 w-4" />
Manage Cluster
</Button>
)}
</header>
return (
<div>
<div className="w-full max-w-7xl mx-auto space-y-6 py-4">
<header className="flex items-center justify-between">
<div className="space-y-1">
<h1 className="text-2xl font-semibold tracking-tight">
Docker Swarm Overview
</h1>
<p className="text-sm text-muted-foreground">
Monitor and manage your Docker Swarm cluster
</p>
</div>
{!serverId && (
<Button
onClick={() =>
window.location.replace("/dashboard/settings/cluster")
}
>
<Settings className="mr-2 h-4 w-4" />
Manage Cluster
</Button>
)}
</header>

<div className="grid gap-6 md:grid-cols-3">
<Card className="bg-background">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Nodes</CardTitle>
<div className="p-2 bg-emerald-600/20 text-emerald-600 rounded-md">
<Server className="h-4 w-4 text-muted-foreground dark:text-emerald-600" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{totalNodes}</div>
</CardContent>
</Card>
<div className="grid gap-6 md:grid-cols-3">
<Card className="bg-background">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Nodes</CardTitle>
<div className="p-2 bg-emerald-600/20 text-emerald-600 rounded-md">
<Server className="h-4 w-4 text-muted-foreground dark:text-emerald-600" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{totalNodes}</div>
</CardContent>
</Card>

<Card className="bg-background">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">
Active Nodes
<Badge variant="green">
Online
</Badge>
</CardTitle>
<div className="p-2 bg-emerald-600/20 text-emerald-600 rounded-md">
<Activity className="h-4 w-4 text-muted-foreground dark:text-emerald-600" />
</div>
</CardHeader>
<CardContent>
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<div className="text-2xl font-bold">
{activeNodesCount} / {totalNodes}
</div>
</TooltipTrigger>
<TooltipContent>
<div className="max-h-48 overflow-y-auto">
{activeNodes.map((node) => (
<div key={node.ID} className="flex items-center gap-2">
{node.Hostname}
</div>
))}
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</CardContent>
</Card>
<Card className="bg-background">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<div className="flex items-center gap-2">
<CardTitle className="text-sm font-medium">
Active Nodes
</CardTitle>
<Badge variant="green">Online</Badge>
</div>
<div className="p-2 bg-emerald-600/20 text-emerald-600 rounded-md">
<Activity className="h-4 w-4 text-muted-foreground dark:text-emerald-600" />
</div>
</CardHeader>
<CardContent>
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<div className="text-2xl font-bold">
{activeNodesCount} / {totalNodes}
</div>
</TooltipTrigger>
<TooltipContent>
<div className="max-h-48 overflow-y-auto">
{activeNodes.map((node) => (
<div key={node.ID} className="flex items-center gap-2">
{node.Hostname}
</div>
))}
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</CardContent>
</Card>

<Card className="bg-background">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">
Manager Nodes
<Badge variant="green">
Online
</Badge>
</CardTitle>
<div className="p-2 bg-emerald-600/20 text-emerald-600 rounded-md">
<Monitor className="h-4 w-4 text-muted-foreground dark:text-emerald-600" />
</div>
</CardHeader>
<CardContent>
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<div className="text-2xl font-bold">
{managerNodesCount} / {totalNodes}
</div>
</TooltipTrigger>
<TooltipContent>
<div className="max-h-48 overflow-y-auto">
{managerNodes.map((node) => (
<div key={node.ID} className="flex items-center gap-2">
{node.Hostname}
</div>
))}
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</CardContent>
</Card>
</div>
<Card className="bg-background">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<div className="flex items-center gap-2">
<CardTitle className="text-sm font-medium">
Manager Nodes
</CardTitle>
<Badge variant="green">Online</Badge>
</div>
<div className="p-2 bg-emerald-600/20 text-emerald-600 rounded-md">
<Monitor className="h-4 w-4 text-muted-foreground dark:text-emerald-600" />
</div>
</CardHeader>
<CardContent>
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<div className="text-2xl font-bold">
{managerNodesCount} / {totalNodes}
</div>
</TooltipTrigger>
<TooltipContent>
<div className="max-h-48 overflow-y-auto">
{managerNodes.map((node) => (
<div key={node.ID} className="flex items-center gap-2">
{node.Hostname}
</div>
))}
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</CardContent>
</Card>
</div>

<div className="flex flex-row gap-4">
{nodes.map((node) => (
<NodeCard key={node.ID} node={node} serverId={serverId} />
))}
</div>
</div>
</div>
);
}
<div className="flex flex-row gap-4">
{nodes.map((node) => (
<NodeCard key={node.ID} node={node} serverId={serverId} />
))}
</div>
</div>
</div>
);
}
Loading