mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat: initial commit
This commit is contained in:
101
components/dashboard/monitoring/docker/docker-block-chart.tsx
Normal file
101
components/dashboard/monitoring/docker/docker-block-chart.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import {
|
||||
AreaChart,
|
||||
Area,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
ResponsiveContainer,
|
||||
Legend,
|
||||
} from "recharts";
|
||||
import type { DockerStatsJSON } from "./show";
|
||||
import { format } from "date-fns";
|
||||
|
||||
interface Props {
|
||||
acummulativeData: DockerStatsJSON["block"];
|
||||
}
|
||||
|
||||
export const DockerBlockChart = ({ acummulativeData }: Props) => {
|
||||
const transformedData = acummulativeData.map((item, index) => {
|
||||
return {
|
||||
time: item.time,
|
||||
name: `Point ${index + 1}`,
|
||||
readMb: item.value.readMb,
|
||||
writeMb: item.value.writeMb,
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="mt-6 w-full h-[10rem]">
|
||||
<ResponsiveContainer>
|
||||
<AreaChart
|
||||
data={transformedData}
|
||||
margin={{
|
||||
top: 10,
|
||||
right: 30,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#27272A" stopOpacity={0.8} />
|
||||
<stop offset="95%" stopColor="#8884d8" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
<linearGradient id="colorWrite" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#82ca9d" stopOpacity={0.8} />
|
||||
<stop offset="95%" stopColor="#82ca9d" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<YAxis stroke="#A1A1AA" />
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#27272A" />
|
||||
{/* @ts-ignore */}
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Legend />
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="readMb"
|
||||
stroke="#27272A"
|
||||
fillOpacity={1}
|
||||
fill="url(#colorUv)"
|
||||
name="Read Mb"
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="writeMb"
|
||||
stroke="#82ca9d"
|
||||
fillOpacity={1}
|
||||
fill="url(#colorWrite)"
|
||||
name="Write Mb"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
interface CustomTooltipProps {
|
||||
active: boolean;
|
||||
payload?: {
|
||||
color?: string;
|
||||
dataKey?: string;
|
||||
value?: number;
|
||||
payload: {
|
||||
time: string;
|
||||
readMb: number;
|
||||
writeMb: number;
|
||||
};
|
||||
}[];
|
||||
}
|
||||
|
||||
const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
|
||||
if (active && payload && payload.length && payload[0]) {
|
||||
return (
|
||||
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
<p>{`Read ${payload[0].payload.readMb.toFixed(2)} MB`}</p>
|
||||
<p>{`Write: ${payload[0].payload.writeMb.toFixed(3)} MB`}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
85
components/dashboard/monitoring/docker/docker-cpu-chart.tsx
Normal file
85
components/dashboard/monitoring/docker/docker-cpu-chart.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import {
|
||||
AreaChart,
|
||||
Area,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
ResponsiveContainer,
|
||||
Legend,
|
||||
} from "recharts";
|
||||
import type { DockerStatsJSON } from "./show";
|
||||
import { format } from "date-fns";
|
||||
|
||||
interface Props {
|
||||
acummulativeData: DockerStatsJSON["cpu"];
|
||||
}
|
||||
|
||||
export const DockerCpuChart = ({ acummulativeData }: Props) => {
|
||||
const transformedData = acummulativeData.map((item, index) => {
|
||||
return {
|
||||
name: `Point ${index + 1}`,
|
||||
time: item.time,
|
||||
usage: item.value.toFixed(2),
|
||||
};
|
||||
});
|
||||
return (
|
||||
<div className="mt-6 w-full h-[10rem]">
|
||||
<ResponsiveContainer>
|
||||
<AreaChart
|
||||
data={transformedData}
|
||||
margin={{
|
||||
top: 10,
|
||||
right: 30,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#27272A" stopOpacity={0.8} />
|
||||
<stop offset="95%" stopColor="white" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<YAxis stroke="#A1A1AA" domain={[0, 100]} />
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#27272A" />
|
||||
{/* @ts-ignore */}
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Legend />
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="usage"
|
||||
stroke="#27272A"
|
||||
fillOpacity={1}
|
||||
fill="url(#colorUv)"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface CustomTooltipProps {
|
||||
active: boolean;
|
||||
payload?: {
|
||||
color?: string;
|
||||
dataKey?: string;
|
||||
value?: number;
|
||||
payload: {
|
||||
time: string;
|
||||
usage: number;
|
||||
};
|
||||
}[];
|
||||
}
|
||||
|
||||
const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
|
||||
if (active && payload && payload.length && payload[0]) {
|
||||
return (
|
||||
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
<p>{`CPU Usage: ${payload[0].payload.usage}%`}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
105
components/dashboard/monitoring/docker/docker-disk-chart.tsx
Normal file
105
components/dashboard/monitoring/docker/docker-disk-chart.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
import {
|
||||
AreaChart,
|
||||
Area,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
ResponsiveContainer,
|
||||
Legend,
|
||||
} from "recharts";
|
||||
import type { DockerStatsJSON } from "./show";
|
||||
import { format } from "date-fns";
|
||||
|
||||
interface Props {
|
||||
acummulativeData: DockerStatsJSON["disk"];
|
||||
diskTotal: number;
|
||||
}
|
||||
|
||||
export const DockerDiskChart = ({ acummulativeData, diskTotal }: Props) => {
|
||||
const transformedData = acummulativeData.map((item, index) => {
|
||||
return {
|
||||
time: item.time,
|
||||
name: `Point ${index + 1}`,
|
||||
usedGb: +item.value.diskUsage,
|
||||
totalGb: +item.value.diskTotal,
|
||||
freeGb: item.value.diskFree,
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="mt-6 w-full h-[10rem]">
|
||||
<ResponsiveContainer>
|
||||
<AreaChart
|
||||
data={transformedData}
|
||||
margin={{
|
||||
top: 10,
|
||||
right: 30,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="colorUsed" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#6C28D9" stopOpacity={0.8} />
|
||||
<stop offset="95%" stopColor="#6C28D9" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
<linearGradient id="colorFree" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#6C28D9" stopOpacity={0.2} />
|
||||
<stop offset="95%" stopColor="#6C28D9" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<YAxis stroke="#A1A1AA" domain={[0, diskTotal]} />
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#27272A" />
|
||||
{/* @ts-ignore */}
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Legend />
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="usedGb"
|
||||
stroke="#6C28D9"
|
||||
fillOpacity={1}
|
||||
fill="url(#colorUsed)"
|
||||
name="Used GB"
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="freeGb"
|
||||
stroke="#8884d8"
|
||||
fillOpacity={1}
|
||||
fill="url(#colorFree)"
|
||||
name="Free GB"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
interface CustomTooltipProps {
|
||||
active: boolean;
|
||||
payload?: {
|
||||
color?: string;
|
||||
dataKey?: string;
|
||||
value?: number;
|
||||
payload: {
|
||||
time: string;
|
||||
usedGb: number;
|
||||
freeGb: number;
|
||||
totalGb: number;
|
||||
};
|
||||
}[];
|
||||
}
|
||||
|
||||
const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
|
||||
if (active && payload && payload.length && payload[0]) {
|
||||
return (
|
||||
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
<p>{`Disk usage: ${payload[0].payload.usedGb} GB`}</p>
|
||||
<p>{`Disk free: ${payload[0].payload.freeGb} GB`}</p>
|
||||
<p>{`Total disk: ${payload[0].payload.totalGb} GB`}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
import {
|
||||
AreaChart,
|
||||
Area,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
ResponsiveContainer,
|
||||
Legend,
|
||||
} from "recharts";
|
||||
import type { DockerStatsJSON } from "./show";
|
||||
import { format } from "date-fns";
|
||||
|
||||
interface Props {
|
||||
acummulativeData: DockerStatsJSON["memory"];
|
||||
memoryLimitGB: number;
|
||||
}
|
||||
|
||||
export const DockerMemoryChart = ({
|
||||
acummulativeData,
|
||||
memoryLimitGB,
|
||||
}: Props) => {
|
||||
const transformedData = acummulativeData.map((item, index) => {
|
||||
return {
|
||||
time: item.time,
|
||||
name: `Point ${index + 1}`,
|
||||
usage: (item.value.used / 1024).toFixed(2),
|
||||
};
|
||||
});
|
||||
return (
|
||||
<div className="mt-6 w-full h-[10rem]">
|
||||
<ResponsiveContainer>
|
||||
<AreaChart
|
||||
data={transformedData}
|
||||
margin={{
|
||||
top: 10,
|
||||
right: 30,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#27272A" stopOpacity={0.8} />
|
||||
<stop offset="95%" stopColor="white" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<YAxis stroke="#A1A1AA" domain={[0, +memoryLimitGB.toFixed(2)]} />
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#27272A" />
|
||||
{/* @ts-ignore */}
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Legend />
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="usage"
|
||||
stroke="#27272A"
|
||||
fillOpacity={1}
|
||||
fill="url(#colorUv)"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
interface CustomTooltipProps {
|
||||
active: boolean;
|
||||
payload?: {
|
||||
color?: string;
|
||||
dataKey?: string;
|
||||
value?: number;
|
||||
payload: {
|
||||
time: string;
|
||||
usage: number;
|
||||
};
|
||||
}[];
|
||||
}
|
||||
|
||||
const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
|
||||
if (active && payload && payload.length && payload[0]) {
|
||||
return (
|
||||
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
<p>{`Memory usage: ${payload[0].payload.usage} GB`}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
import {
|
||||
AreaChart,
|
||||
Area,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
ResponsiveContainer,
|
||||
Legend,
|
||||
} from "recharts";
|
||||
import type { DockerStatsJSON } from "./show";
|
||||
import { format } from "date-fns";
|
||||
1;
|
||||
interface Props {
|
||||
acummulativeData: DockerStatsJSON["network"];
|
||||
}
|
||||
|
||||
export const DockerNetworkChart = ({ acummulativeData }: Props) => {
|
||||
const transformedData = acummulativeData.map((item, index) => {
|
||||
return {
|
||||
time: item.time,
|
||||
name: `Point ${index + 1}`,
|
||||
inMB: item.value.inputMb.toFixed(2),
|
||||
outMB: item.value.outputMb.toFixed(2),
|
||||
};
|
||||
});
|
||||
return (
|
||||
<div className="mt-6 w-full h-[10rem]">
|
||||
<ResponsiveContainer>
|
||||
<AreaChart
|
||||
data={transformedData}
|
||||
margin={{
|
||||
top: 10,
|
||||
right: 30,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="#27272A" stopOpacity={0.8} />
|
||||
<stop offset="95%" stopColor="white" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<YAxis stroke="#A1A1AA" />
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#27272A" />
|
||||
{/* @ts-ignore */}
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Legend />
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="inMB"
|
||||
stroke="#8884d8"
|
||||
fillOpacity={1}
|
||||
fill="url(#colorUv)"
|
||||
name="In MB"
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="outMB"
|
||||
stroke="#82ca9d"
|
||||
fillOpacity={1}
|
||||
fill="url(#colorUv)"
|
||||
name="Out MB"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface CustomTooltipProps {
|
||||
active: boolean;
|
||||
payload?: {
|
||||
color?: string;
|
||||
dataKey?: string;
|
||||
value?: number;
|
||||
payload: {
|
||||
time: string;
|
||||
inMB: number;
|
||||
outMB: number;
|
||||
};
|
||||
}[];
|
||||
}
|
||||
|
||||
const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
|
||||
if (active && payload && payload.length && payload[0]) {
|
||||
return (
|
||||
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
<p>{`In MB Usage: ${payload[0].payload.inMB} MB`}</p>
|
||||
<p>{`Out MB Usage: ${payload[0].payload.outMB} MB`}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
248
components/dashboard/monitoring/docker/show.tsx
Normal file
248
components/dashboard/monitoring/docker/show.tsx
Normal file
@@ -0,0 +1,248 @@
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { DockerCpuChart } from "./docker-cpu-chart";
|
||||
import { DockerMemoryChart } from "./docker-memory-chart";
|
||||
import { DockerBlockChart } from "./docker-block-chart";
|
||||
import { DockerNetworkChart } from "./docker-network-chart";
|
||||
import { DockerDiskChart } from "./docker-disk-chart";
|
||||
import { api } from "@/utils/api";
|
||||
|
||||
interface Props {
|
||||
appName: string;
|
||||
}
|
||||
export interface DockerStats {
|
||||
cpu: {
|
||||
value: number;
|
||||
time: string;
|
||||
};
|
||||
memory: {
|
||||
value: {
|
||||
used: number;
|
||||
free: number;
|
||||
usedPercentage: number;
|
||||
total: number;
|
||||
};
|
||||
time: string;
|
||||
};
|
||||
block: {
|
||||
value: {
|
||||
readMb: number;
|
||||
writeMb: number;
|
||||
};
|
||||
time: string;
|
||||
};
|
||||
network: {
|
||||
value: {
|
||||
inputMb: number;
|
||||
outputMb: number;
|
||||
};
|
||||
time: string;
|
||||
};
|
||||
disk: {
|
||||
value: {
|
||||
diskTotal: number;
|
||||
diskUsage: number;
|
||||
diskUsedPercentage: number;
|
||||
diskFree: number;
|
||||
};
|
||||
|
||||
time: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type DockerStatsJSON = {
|
||||
cpu: DockerStats["cpu"][];
|
||||
memory: DockerStats["memory"][];
|
||||
block: DockerStats["block"][];
|
||||
network: DockerStats["network"][];
|
||||
disk: DockerStats["disk"][];
|
||||
};
|
||||
|
||||
export const DockerMonitoring = ({ appName }: Props) => {
|
||||
const { data } = api.application.readAppMonitoring.useQuery(
|
||||
{ appName },
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
);
|
||||
const [acummulativeData, setAcummulativeData] = useState<DockerStatsJSON>({
|
||||
cpu: [],
|
||||
memory: [],
|
||||
block: [],
|
||||
network: [],
|
||||
disk: [],
|
||||
});
|
||||
const [currentData, setCurrentData] = useState<DockerStats>({
|
||||
cpu: {
|
||||
value: 0,
|
||||
time: "",
|
||||
},
|
||||
memory: {
|
||||
value: {
|
||||
used: 0,
|
||||
free: 0,
|
||||
usedPercentage: 0,
|
||||
total: 0,
|
||||
},
|
||||
time: "",
|
||||
},
|
||||
block: {
|
||||
value: {
|
||||
readMb: 0,
|
||||
writeMb: 0,
|
||||
},
|
||||
time: "",
|
||||
},
|
||||
network: {
|
||||
value: {
|
||||
inputMb: 0,
|
||||
outputMb: 0,
|
||||
},
|
||||
time: "",
|
||||
},
|
||||
disk: {
|
||||
value: { diskTotal: 0, diskUsage: 0, diskUsedPercentage: 0, diskFree: 0 },
|
||||
time: "",
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return;
|
||||
|
||||
setCurrentData({
|
||||
cpu: data.cpu[data.cpu.length - 1] ?? currentData.cpu,
|
||||
memory: data.memory[data.memory.length - 1] ?? currentData.memory,
|
||||
block: data.block[data.block.length - 1] ?? currentData.block,
|
||||
network: data.network[data.network.length - 1] ?? currentData.network,
|
||||
disk: data.disk[data.disk.length - 1] ?? currentData.disk,
|
||||
});
|
||||
setAcummulativeData(data);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||
const wsUrl = `${protocol}//${window.location.host}/listen-docker-stats-monitoring?appName=${appName}`;
|
||||
const ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onmessage = (e) => {
|
||||
const value = JSON.parse(e.data);
|
||||
if (!value) return;
|
||||
|
||||
const data = {
|
||||
cpu: value.data.cpu ?? currentData.cpu,
|
||||
memory: value.data.memory ?? currentData.memory,
|
||||
block: value.data.block ?? currentData.block,
|
||||
disk: value.data.disk ?? currentData.disk,
|
||||
network: value.data.network ?? currentData.network,
|
||||
};
|
||||
|
||||
setCurrentData(data);
|
||||
|
||||
setAcummulativeData((prevData) => ({
|
||||
cpu: [...prevData.cpu, data.cpu],
|
||||
memory: [...prevData.memory, data.memory],
|
||||
block: [...prevData.block, data.block],
|
||||
network: [...prevData.network, data.network],
|
||||
disk: [...prevData.disk, data.disk],
|
||||
}));
|
||||
};
|
||||
|
||||
ws.onclose = (e) => {
|
||||
console.log(e.reason);
|
||||
};
|
||||
|
||||
return () => ws.close();
|
||||
}, [appName]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card className="bg-background">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-xl">Monitoring</CardTitle>
|
||||
<CardDescription>
|
||||
Watch the usage of your server in the current app
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="flex w-full gap-8 ">
|
||||
<div className=" flex-row gap-8 grid md:grid-cols-2 w-full">
|
||||
<div className="flex flex-col gap-2 w-full ">
|
||||
<span className="text-base font-medium">CPU</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Used: {currentData.cpu.value.toFixed(2)}%
|
||||
</span>
|
||||
<Progress value={currentData.cpu.value} className="w-[100%]" />
|
||||
<DockerCpuChart acummulativeData={acummulativeData.cpu} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 w-full ">
|
||||
<span className="text-base font-medium">Memory</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{`Used: ${(currentData.memory.value.used / 1024).toFixed(
|
||||
2,
|
||||
)} GB / Limit: ${(
|
||||
currentData.memory.value.total / 1024
|
||||
).toFixed(2)} GB`}
|
||||
</span>
|
||||
<Progress
|
||||
value={currentData.memory.value.usedPercentage}
|
||||
className="w-[100%]"
|
||||
/>
|
||||
<DockerMemoryChart
|
||||
acummulativeData={acummulativeData.memory}
|
||||
memoryLimitGB={currentData.memory.value.total / 1024}
|
||||
/>
|
||||
</div>
|
||||
{appName === "dokploy" && (
|
||||
<div className="flex flex-col gap-2 w-full ">
|
||||
<span className="text-base font-medium">Space</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{`Used: ${currentData.disk.value.diskUsage} GB / Limit: ${currentData.disk.value.diskTotal} GB`}
|
||||
</span>
|
||||
<Progress
|
||||
value={currentData.disk.value.diskUsedPercentage}
|
||||
className="w-[100%]"
|
||||
/>
|
||||
<DockerDiskChart
|
||||
acummulativeData={acummulativeData.disk}
|
||||
diskTotal={currentData.disk.value.diskTotal}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col gap-2 w-full ">
|
||||
<span className="text-base font-medium">Block I/O</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{`Used: ${currentData.block.value.readMb.toFixed(
|
||||
2,
|
||||
)} MB / Limit: ${currentData.block.value.writeMb.toFixed(
|
||||
3,
|
||||
)} MB`}
|
||||
</span>
|
||||
<DockerBlockChart acummulativeData={acummulativeData.block} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 w-full ">
|
||||
<span className="text-base font-medium">Network</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{`In MB: ${currentData.network.value.inputMb.toFixed(
|
||||
2,
|
||||
)} MB / Out MB: ${currentData.network.value.outputMb.toFixed(
|
||||
2,
|
||||
)} MB`}
|
||||
</span>
|
||||
<DockerNetworkChart
|
||||
acummulativeData={acummulativeData.network}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user