feat: turned disk uage into graph and fixed issue with termina console
This commit is contained in:
@@ -64,11 +64,11 @@ export function ConsoleTerminal({
|
|||||||
"http://127.0.0.1:30001";
|
"http://127.0.0.1:30001";
|
||||||
const wsProtocol = baseUrl.startsWith("https://") ? "wss://" : "ws://";
|
const wsProtocol = baseUrl.startsWith("https://") ? "wss://" : "ws://";
|
||||||
const wsHost = baseUrl.replace(/^https?:\/\//, "");
|
const wsHost = baseUrl.replace(/^https?:\/\//, "");
|
||||||
return `${wsProtocol}${wsHost}/docker/console`;
|
return `${wsProtocol}${wsHost}/docker/console/`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||||
return `${protocol}//${window.location.host}/docker/console`;
|
return `${protocol}//${window.location.host}/docker/console/`;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|||||||
@@ -388,18 +388,18 @@ export function ServerStats({
|
|||||||
let retryCount = 0;
|
let retryCount = 0;
|
||||||
let data = null;
|
let data = null;
|
||||||
const maxRetries = 15;
|
const maxRetries = 15;
|
||||||
const initialDelay = totpVerified ? 3000 : 5000;
|
|
||||||
const retryDelay = 2000;
|
const retryDelay = 2000;
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, initialDelay));
|
|
||||||
|
|
||||||
while (retryCount < maxRetries && !cancelled) {
|
while (retryCount < maxRetries && !cancelled) {
|
||||||
try {
|
try {
|
||||||
data = await getServerMetricsById(currentHostConfig.id);
|
data = await getServerMetricsById(currentHostConfig.id);
|
||||||
break;
|
break;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
retryCount++;
|
retryCount++;
|
||||||
if (retryCount < maxRetries && !cancelled) {
|
if (retryCount === 1) {
|
||||||
|
const initialDelay = totpVerified ? 3000 : 5000;
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, initialDelay));
|
||||||
|
} else if (retryCount < maxRetries && !cancelled) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
||||||
} else {
|
} else {
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@@ -62,7 +62,10 @@ export function CpuWidget({ metrics, metricsHistory }: CpuWidgetProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-h-0">
|
<div className="flex-1 min-h-0">
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
<LineChart data={chartData}>
|
<LineChart
|
||||||
|
data={chartData}
|
||||||
|
margin={{ top: 5, right: 5, left: -25, bottom: 5 }}
|
||||||
|
>
|
||||||
<CartesianGrid strokeDasharray="3 3" stroke="#374151" />
|
<CartesianGrid strokeDasharray="3 3" stroke="#374151" />
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="index"
|
dataKey="index"
|
||||||
|
|||||||
@@ -4,27 +4,30 @@ import { useTranslation } from "react-i18next";
|
|||||||
import type { ServerMetrics } from "@/ui/main-axios.ts";
|
import type { ServerMetrics } from "@/ui/main-axios.ts";
|
||||||
import { RechartsPrimitive } from "@/components/ui/chart.tsx";
|
import { RechartsPrimitive } from "@/components/ui/chart.tsx";
|
||||||
|
|
||||||
const { RadialBarChart, RadialBar, PolarAngleAxis, ResponsiveContainer } =
|
const {
|
||||||
RechartsPrimitive;
|
AreaChart,
|
||||||
|
Area,
|
||||||
|
XAxis,
|
||||||
|
YAxis,
|
||||||
|
CartesianGrid,
|
||||||
|
Tooltip,
|
||||||
|
ResponsiveContainer,
|
||||||
|
} = RechartsPrimitive;
|
||||||
|
|
||||||
interface DiskWidgetProps {
|
interface DiskWidgetProps {
|
||||||
metrics: ServerMetrics | null;
|
metrics: ServerMetrics | null;
|
||||||
metricsHistory: ServerMetrics[];
|
metricsHistory: ServerMetrics[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DiskWidget({ metrics }: DiskWidgetProps) {
|
export function DiskWidget({ metrics, metricsHistory }: DiskWidgetProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const radialData = React.useMemo(() => {
|
const chartData = React.useMemo(() => {
|
||||||
const percent = metrics?.disk?.percent || 0;
|
return metricsHistory.map((m, index) => ({
|
||||||
return [
|
index,
|
||||||
{
|
disk: m.disk?.percent || 0,
|
||||||
name: "Disk",
|
}));
|
||||||
value: percent,
|
}, [metricsHistory]);
|
||||||
fill: "#fb923c",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}, [metrics]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-full p-4 rounded-lg bg-elevated border border-edge/50 hover:bg-elevated/70 flex flex-col overflow-hidden">
|
<div className="h-full w-full p-4 rounded-lg bg-elevated border border-edge/50 hover:bg-elevated/70 flex flex-col overflow-hidden">
|
||||||
@@ -35,45 +38,13 @@ export function DiskWidget({ metrics }: DiskWidgetProps) {
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col flex-1 min-h-0">
|
<div className="flex flex-col flex-1 min-h-0 gap-2">
|
||||||
<div className="flex-1 min-h-0 flex items-center justify-center">
|
<div className="flex items-baseline gap-3 flex-shrink-0">
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<div className="text-2xl font-bold text-orange-400">
|
||||||
<RadialBarChart
|
|
||||||
cx="50%"
|
|
||||||
cy="50%"
|
|
||||||
innerRadius="60%"
|
|
||||||
outerRadius="90%"
|
|
||||||
data={radialData}
|
|
||||||
startAngle={90}
|
|
||||||
endAngle={-270}
|
|
||||||
>
|
|
||||||
<PolarAngleAxis
|
|
||||||
type="number"
|
|
||||||
domain={[0, 100]}
|
|
||||||
angleAxisId={0}
|
|
||||||
tick={false}
|
|
||||||
/>
|
|
||||||
<RadialBar
|
|
||||||
background
|
|
||||||
dataKey="value"
|
|
||||||
cornerRadius={10}
|
|
||||||
fill="#fb923c"
|
|
||||||
/>
|
|
||||||
<text
|
|
||||||
x="50%"
|
|
||||||
y="50%"
|
|
||||||
textAnchor="middle"
|
|
||||||
dominantBaseline="middle"
|
|
||||||
className="text-2xl font-bold fill-orange-400"
|
|
||||||
>
|
|
||||||
{typeof metrics?.disk?.percent === "number"
|
{typeof metrics?.disk?.percent === "number"
|
||||||
? `${metrics.disk.percent}%`
|
? `${metrics.disk.percent}%`
|
||||||
: "N/A"}
|
: "N/A"}
|
||||||
</text>
|
|
||||||
</RadialBarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-shrink-0 space-y-1 text-center pb-2">
|
|
||||||
<div className="text-xs text-muted-foreground">
|
<div className="text-xs text-muted-foreground">
|
||||||
{(() => {
|
{(() => {
|
||||||
const used = metrics?.disk?.usedHuman;
|
const used = metrics?.disk?.usedHuman;
|
||||||
@@ -84,7 +55,8 @@ export function DiskWidget({ metrics }: DiskWidgetProps) {
|
|||||||
return "N/A";
|
return "N/A";
|
||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-foreground-subtle">
|
</div>
|
||||||
|
<div className="text-xs text-foreground-subtle flex-shrink-0">
|
||||||
{(() => {
|
{(() => {
|
||||||
const available = metrics?.disk?.availableHuman;
|
const available = metrics?.disk?.availableHuman;
|
||||||
return available
|
return available
|
||||||
@@ -92,6 +64,49 @@ export function DiskWidget({ metrics }: DiskWidgetProps) {
|
|||||||
: `${t("serverStats.available")}: N/A`;
|
: `${t("serverStats.available")}: N/A`;
|
||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex-1 min-h-0">
|
||||||
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<AreaChart
|
||||||
|
data={chartData}
|
||||||
|
margin={{ top: 5, right: 5, left: -25, bottom: 5 }}
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="diskGradient" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="5%" stopColor="#fb923c" stopOpacity={0.8} />
|
||||||
|
<stop offset="95%" stopColor="#fb923c" stopOpacity={0.1} />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" stroke="#374151" />
|
||||||
|
<XAxis
|
||||||
|
dataKey="index"
|
||||||
|
stroke="#9ca3af"
|
||||||
|
tick={{ fill: "#9ca3af" }}
|
||||||
|
hide
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
domain={[0, 100]}
|
||||||
|
stroke="#9ca3af"
|
||||||
|
tick={{ fill: "#9ca3af" }}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
contentStyle={{
|
||||||
|
backgroundColor: "#1f2937",
|
||||||
|
border: "1px solid #374151",
|
||||||
|
borderRadius: "6px",
|
||||||
|
color: "#fff",
|
||||||
|
}}
|
||||||
|
formatter={(value: number) => [`${value.toFixed(1)}%`, "Disk"]}
|
||||||
|
/>
|
||||||
|
<Area
|
||||||
|
type="monotone"
|
||||||
|
dataKey="disk"
|
||||||
|
stroke="#fb923c"
|
||||||
|
strokeWidth={2}
|
||||||
|
fill="url(#diskGradient)"
|
||||||
|
animationDuration={300}
|
||||||
|
/>
|
||||||
|
</AreaChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -69,7 +69,10 @@ export function MemoryWidget({ metrics, metricsHistory }: MemoryWidgetProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-h-0">
|
<div className="flex-1 min-h-0">
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
<AreaChart data={chartData}>
|
<AreaChart
|
||||||
|
data={chartData}
|
||||||
|
margin={{ top: 5, right: 5, left: -25, bottom: 5 }}
|
||||||
|
>
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="memoryGradient" x1="0" y1="0" x2="0" y2="1">
|
<linearGradient id="memoryGradient" x1="0" y1="0" x2="0" y2="1">
|
||||||
<stop offset="5%" stopColor="#34d399" stopOpacity={0.8} />
|
<stop offset="5%" stopColor="#34d399" stopOpacity={0.8} />
|
||||||
|
|||||||
Reference in New Issue
Block a user