diff --git a/apps/dokploy/components/dashboard/compose/monitoring/show.tsx b/apps/dokploy/components/dashboard/compose/monitoring/show.tsx
index 4f7c3e024..217b9caa9 100644
--- a/apps/dokploy/components/dashboard/compose/monitoring/show.tsx
+++ b/apps/dokploy/components/dashboard/compose/monitoring/show.tsx
@@ -20,7 +20,7 @@ import { api } from "@/utils/api";
import { Loader2 } from "lucide-react";
import { useEffect, useState } from "react";
import { toast } from "sonner";
-import { ContainerMonitoring } from "../../monitoring/container/show";
+import { ContainerMonitoring } from "../../monitoring/paid/container/show-paid-container-monitoring";
interface Props {
appName: string;
diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/docker-block-chart.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/docker-block-chart.tsx
new file mode 100644
index 000000000..57a3cbe22
--- /dev/null
+++ b/apps/dokploy/components/dashboard/monitoring/free/container/docker-block-chart.tsx
@@ -0,0 +1,101 @@
+import { format } from "date-fns";
+import {
+ Area,
+ AreaChart,
+ CartesianGrid,
+ Legend,
+ ResponsiveContainer,
+ Tooltip,
+ YAxis,
+} from "recharts";
+import type { DockerStatsJSON } from "./show";
+
+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 (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* @ts-ignore */}
+ } />
+
+
+
+
+
+
+ );
+};
+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 (
+
+
{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}
+
{`Read ${payload[0].payload.readMb.toFixed(2)} MB`}
+
{`Write: ${payload[0].payload.writeMb.toFixed(3)} MB`}
+
+ );
+ }
+
+ return null;
+};
diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/docker-cpu-chart.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/docker-cpu-chart.tsx
new file mode 100644
index 000000000..41f20f8f1
--- /dev/null
+++ b/apps/dokploy/components/dashboard/monitoring/free/container/docker-cpu-chart.tsx
@@ -0,0 +1,85 @@
+import { format } from "date-fns";
+import {
+ Area,
+ AreaChart,
+ CartesianGrid,
+ Legend,
+ ResponsiveContainer,
+ Tooltip,
+ YAxis,
+} from "recharts";
+import type { DockerStatsJSON } from "./show";
+
+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 (
+
+
+
+
+
+
+
+
+
+
+
+ {/* @ts-ignore */}
+ } />
+
+
+
+
+
+ );
+};
+
+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 (
+
+
{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}
+
{`CPU Usage: ${payload[0].payload.usage}%`}
+
+ );
+ }
+
+ return null;
+};
diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/docker-disk-chart.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/docker-disk-chart.tsx
new file mode 100644
index 000000000..a97fcfedd
--- /dev/null
+++ b/apps/dokploy/components/dashboard/monitoring/free/container/docker-disk-chart.tsx
@@ -0,0 +1,105 @@
+import { format } from "date-fns";
+import {
+ Area,
+ AreaChart,
+ CartesianGrid,
+ Legend,
+ ResponsiveContainer,
+ Tooltip,
+ YAxis,
+} from "recharts";
+import type { DockerStatsJSON } from "./show";
+
+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 (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* @ts-ignore */}
+ } />
+
+
+
+
+
+
+ );
+};
+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 (
+
+
{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}
+
{`Disk usage: ${payload[0].payload.usedGb} GB`}
+
{`Disk free: ${payload[0].payload.freeGb} GB`}
+
{`Total disk: ${payload[0].payload.totalGb} GB`}
+
+ );
+ }
+
+ return null;
+};
diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/docker-memory-chart.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/docker-memory-chart.tsx
new file mode 100644
index 000000000..36f1edb81
--- /dev/null
+++ b/apps/dokploy/components/dashboard/monitoring/free/container/docker-memory-chart.tsx
@@ -0,0 +1,88 @@
+import { format } from "date-fns";
+import {
+ Area,
+ AreaChart,
+ CartesianGrid,
+ Legend,
+ ResponsiveContainer,
+ Tooltip,
+ YAxis,
+} from "recharts";
+import type { DockerStatsJSON } from "./show";
+
+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 ** 3).toFixed(2),
+ };
+ });
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {/* @ts-ignore */}
+ } />
+
+
+
+
+
+ );
+};
+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 (
+
+
{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}
+
{`Memory usage: ${payload[0].payload.usage} GB`}
+
+ );
+ }
+
+ return null;
+};
diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/docker-network-chart.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/docker-network-chart.tsx
new file mode 100644
index 000000000..b522603d8
--- /dev/null
+++ b/apps/dokploy/components/dashboard/monitoring/free/container/docker-network-chart.tsx
@@ -0,0 +1,97 @@
+import { format } from "date-fns";
+import {
+ Area,
+ AreaChart,
+ CartesianGrid,
+ Legend,
+ ResponsiveContainer,
+ Tooltip,
+ YAxis,
+} from "recharts";
+import type { DockerStatsJSON } from "./show";
+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 (
+
+
+
+
+
+
+
+
+
+
+
+ {/* @ts-ignore */}
+ } />
+
+
+
+
+
+
+ );
+};
+
+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 (
+
+
{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}
+
{`In MB Usage: ${payload[0].payload.inMB} MB`}
+
{`Out MB Usage: ${payload[0].payload.outMB} MB`}
+
+ );
+ }
+
+ return null;
+};
diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx
new file mode 100644
index 000000000..930e9ad95
--- /dev/null
+++ b/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx
@@ -0,0 +1,314 @@
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card";
+import { Progress } from "@/components/ui/progress";
+import { api } from "@/utils/api";
+import React, { useEffect, useState } from "react";
+import { DockerBlockChart } from "./docker-block-chart";
+import { DockerCpuChart } from "./docker-cpu-chart";
+import { DockerDiskChart } from "./docker-disk-chart";
+import { DockerMemoryChart } from "./docker-memory-chart";
+import { DockerNetworkChart } from "./docker-network-chart";
+
+const defaultData = {
+ 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: "",
+ },
+};
+
+interface Props {
+ appName: string;
+ appType?: "application" | "stack" | "docker-compose";
+}
+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 ContainerFreeMonitoring = ({
+ appName,
+ appType = "application",
+}: Props) => {
+ const { data } = api.application.readAppMonitoring.useQuery(
+ { appName },
+ {
+ refetchOnWindowFocus: false,
+ },
+ );
+ const [acummulativeData, setAcummulativeData] = useState({
+ cpu: [],
+ memory: [],
+ block: [],
+ network: [],
+ disk: [],
+ });
+ const [currentData, setCurrentData] = useState(defaultData);
+
+ useEffect(() => {
+ setCurrentData(defaultData);
+
+ setAcummulativeData({
+ cpu: [],
+ memory: [],
+ block: [],
+ network: [],
+ disk: [],
+ });
+ }, [appName]);
+
+ 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({
+ block: data?.block || [],
+ cpu: data?.cpu || [],
+ disk: data?.disk || [],
+ memory: data?.memory || [],
+ network: data?.network || [],
+ });
+ }, [data]);
+
+ useEffect(() => {
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
+ const wsUrl = `${protocol}//${window.location.host}/listen-docker-stats-monitoring?appName=${appName}&appType=${appType}`;
+ 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 (
+
+
+
+
+
+
+
+
+ CPU Usage
+
+
+
+
+ Used: {currentData.cpu.value.toFixed(2)}%
+
+
+
+
+
+
+
+
+
+
+ Memory Usage
+
+
+
+
+
+ {`Used: ${(currentData.memory.value.used / 1024 ** 3).toFixed(2)} GB / Limit: ${(currentData.memory.value.total / 1024 ** 3).toFixed(2)} GB`}
+
+
+
+
+
+
+
+ {appName === "dokploy" && (
+
+
+
+ Disk Space
+
+
+
+
+
+ {`Used: ${currentData.disk.value.diskUsage} GB / Limit: ${currentData.disk.value.diskTotal} GB`}
+
+
+
+
+
+
+ )}
+
+
+
+ Block I/O
+
+
+
+
+ {`Read: ${currentData.block.value.readMb.toFixed(
+ 2,
+ )} MB / Write: ${currentData.block.value.writeMb.toFixed(
+ 3,
+ )} MB`}
+
+
+
+
+
+
+
+
+
+ Network I/O
+
+
+
+
+
+ {`In MB: ${currentData.network.value.inputMb.toFixed(
+ 2,
+ )} MB / Out MB: ${currentData.network.value.outputMb.toFixed(
+ 2,
+ )} MB`}
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/dokploy/components/dashboard/monitoring/container/container-block-chart.tsx b/apps/dokploy/components/dashboard/monitoring/paid/container/container-block-chart.tsx
similarity index 100%
rename from apps/dokploy/components/dashboard/monitoring/container/container-block-chart.tsx
rename to apps/dokploy/components/dashboard/monitoring/paid/container/container-block-chart.tsx
diff --git a/apps/dokploy/components/dashboard/monitoring/container/container-cpu-chart.tsx b/apps/dokploy/components/dashboard/monitoring/paid/container/container-cpu-chart.tsx
similarity index 100%
rename from apps/dokploy/components/dashboard/monitoring/container/container-cpu-chart.tsx
rename to apps/dokploy/components/dashboard/monitoring/paid/container/container-cpu-chart.tsx
diff --git a/apps/dokploy/components/dashboard/monitoring/container/container-memory-chart.tsx b/apps/dokploy/components/dashboard/monitoring/paid/container/container-memory-chart.tsx
similarity index 100%
rename from apps/dokploy/components/dashboard/monitoring/container/container-memory-chart.tsx
rename to apps/dokploy/components/dashboard/monitoring/paid/container/container-memory-chart.tsx
diff --git a/apps/dokploy/components/dashboard/monitoring/container/container-network-chart.tsx b/apps/dokploy/components/dashboard/monitoring/paid/container/container-network-chart.tsx
similarity index 100%
rename from apps/dokploy/components/dashboard/monitoring/container/container-network-chart.tsx
rename to apps/dokploy/components/dashboard/monitoring/paid/container/container-network-chart.tsx
diff --git a/apps/dokploy/components/dashboard/monitoring/container/show.tsx b/apps/dokploy/components/dashboard/monitoring/paid/container/show-paid-container-monitoring.tsx
similarity index 98%
rename from apps/dokploy/components/dashboard/monitoring/container/show.tsx
rename to apps/dokploy/components/dashboard/monitoring/paid/container/show-paid-container-monitoring.tsx
index 08ad46bc2..80af6a43c 100644
--- a/apps/dokploy/components/dashboard/monitoring/container/show.tsx
+++ b/apps/dokploy/components/dashboard/monitoring/paid/container/show-paid-container-monitoring.tsx
@@ -60,7 +60,7 @@ interface Props {
token: string;
}
-export const ContainerMonitoring = ({ appName, baseUrl, token }: Props) => {
+export const ContainerPaidMonitoring = ({ appName, baseUrl, token }: Props) => {
const [historicalData, setHistoricalData] = useState([]);
const [metrics, setMetrics] = useState(
{} as ContainerMetric,
diff --git a/apps/dokploy/components/dashboard/monitoring/servers/cpu-chart.tsx b/apps/dokploy/components/dashboard/monitoring/paid/servers/cpu-chart.tsx
similarity index 100%
rename from apps/dokploy/components/dashboard/monitoring/servers/cpu-chart.tsx
rename to apps/dokploy/components/dashboard/monitoring/paid/servers/cpu-chart.tsx
diff --git a/apps/dokploy/components/dashboard/monitoring/servers/disk-chart.tsx b/apps/dokploy/components/dashboard/monitoring/paid/servers/disk-chart.tsx
similarity index 100%
rename from apps/dokploy/components/dashboard/monitoring/servers/disk-chart.tsx
rename to apps/dokploy/components/dashboard/monitoring/paid/servers/disk-chart.tsx
diff --git a/apps/dokploy/components/dashboard/monitoring/servers/memory-chart.tsx b/apps/dokploy/components/dashboard/monitoring/paid/servers/memory-chart.tsx
similarity index 100%
rename from apps/dokploy/components/dashboard/monitoring/servers/memory-chart.tsx
rename to apps/dokploy/components/dashboard/monitoring/paid/servers/memory-chart.tsx
diff --git a/apps/dokploy/components/dashboard/monitoring/servers/network-chart.tsx b/apps/dokploy/components/dashboard/monitoring/paid/servers/network-chart.tsx
similarity index 100%
rename from apps/dokploy/components/dashboard/monitoring/servers/network-chart.tsx
rename to apps/dokploy/components/dashboard/monitoring/paid/servers/network-chart.tsx
diff --git a/apps/dokploy/components/dashboard/monitoring/servers/show-monitoring.tsx b/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx
similarity index 96%
rename from apps/dokploy/components/dashboard/monitoring/servers/show-monitoring.tsx
rename to apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx
index 2eb58d8a0..fecab36e5 100644
--- a/apps/dokploy/components/dashboard/monitoring/servers/show-monitoring.tsx
+++ b/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx
@@ -1,4 +1,3 @@
-import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import {
Select,
SelectContent,
@@ -6,9 +5,7 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
-import { IS_CLOUD, validateRequest } from "@dokploy/server";
import { Clock, Cpu, HardDrive, Loader2, MemoryStick } from "lucide-react";
-import type { GetServerSidePropsContext } from "next";
import type React from "react";
import { useEffect, useState } from "react";
import { CPUChart } from "./cpu-chart";
@@ -17,8 +14,6 @@ import { MemoryChart } from "./memory-chart";
import { NetworkChart } from "./network-chart";
const REFRESH_INTERVAL = 4500;
-// const BASE_URL =
-// process.env.NEXT_PUBLIC_METRICS_URL || "http://localhost:3001/metrics";
const DATA_POINTS_OPTIONS = {
"50": "50 points",
@@ -57,7 +52,7 @@ interface Props {
token?: string;
}
-export const ShowMonitoring = ({
+export const ShowPaidMonitoring = ({
BASE_URL = process.env.NEXT_PUBLIC_METRICS_URL ||
"http://localhost:3001/metrics",
token = process.env.NEXT_PUBLIC_METRICS_TOKEN || "my-token",
diff --git a/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx b/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx
index c7b5c224a..5f09e382a 100644
--- a/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx
+++ b/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx
@@ -1,6 +1,13 @@
import { AlertBlock } from "@/components/shared/alert-block";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card";
import {
Command,
CommandEmpty,
@@ -24,13 +31,11 @@ import {
PopoverTrigger,
} from "@/components/ui/popover";
import { ScrollArea } from "@/components/ui/scroll-area";
-import { Separator } from "@/components/ui/separator";
import { extractServices } from "@/pages/dashboard/project/[projectId]";
import { api } from "@/utils/api";
import { useUrl } from "@/utils/hooks/use-url";
import { zodResolver } from "@hookform/resolvers/zod";
-import { Eye, EyeOff, RefreshCw } from "lucide-react";
-import { useRouter } from "next/router";
+import { Eye, EyeOff, LayoutDashboardIcon, RefreshCw } from "lucide-react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
@@ -198,363 +203,402 @@ export const SetupMonitoring = ({ serverId }: Props) => {
};
return (
-