stat boxes
This commit is contained in:
1 parent
ec03addba6
commit
dcf5a77923
9 files changed
+240
-1
No files matched your search
@@ -0,0 +1,64 @@
|
||||
import MuiTabs from "@mui/material/Tabs";
|
||||
import type { TabsProps } from "@mui/material/Tabs";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
interface CustomTabsProps extends TabsProps {}
|
||||
|
||||
export const Tabs = (props: CustomTabsProps) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<MuiTabs
|
||||
sx={{
|
||||
minHeight: 34,
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
"& .MuiTabs-indicator": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
height: 2,
|
||||
bottom: 0,
|
||||
},
|
||||
"& .MuiTabs-flexContainer": {
|
||||
gap: theme.spacing(16),
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{props.children}
|
||||
</MuiTabs>
|
||||
);
|
||||
};
|
||||
|
||||
import MuiTab from "@mui/material/Tab";
|
||||
import type { TabProps } from "@mui/material/Tab";
|
||||
interface CustomTabProps extends TabProps {}
|
||||
|
||||
export const Tab = (props: CustomTabProps) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<MuiTab
|
||||
disableRipple
|
||||
iconPosition="start"
|
||||
sx={{
|
||||
textTransform: "none",
|
||||
fontSize: 14,
|
||||
fontWeight: 500,
|
||||
minHeight: 34,
|
||||
padding: theme.spacing(1, 0),
|
||||
paddingBottom: 0,
|
||||
minWidth: "auto",
|
||||
alignItems: "flex-start",
|
||||
color: theme.palette.text.secondary,
|
||||
"&.Mui-selected": {
|
||||
color: theme.palette.primary.main,
|
||||
fontWeight: 600,
|
||||
},
|
||||
"&:hover": {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
"& .MuiTab-iconWrapper": {
|
||||
marginRight: theme.spacing(2),
|
||||
marginBottom: 0,
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -16,3 +16,4 @@ export * from "./Tooltip";
|
||||
export * from "./StatBox";
|
||||
export * from "./BaseChart";
|
||||
export * from "./Gauge";
|
||||
export * from "./Tabs";
|
||||
@@ -0,0 +1,74 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import { StatBox } from "@/Components/v2/design-elements";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import prettyMilliseconds from "pretty-ms";
|
||||
import type { Monitor } from "@/Types/Monitor";
|
||||
import {
|
||||
getAvgTemp,
|
||||
getCores,
|
||||
getFrequency,
|
||||
getGbs,
|
||||
getDiskTotalGbs,
|
||||
getOsAndPlatform,
|
||||
} from "@/Utils/InfraUtils";
|
||||
|
||||
export const StatusBoxes = ({ monitor }: { monitor: Monitor }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
|
||||
const latestCheck = monitor?.recentChecks?.[0];
|
||||
// Get data from latest check
|
||||
const physicalCores = getCores(latestCheck?.cpu?.physical_core);
|
||||
const logicalCores = getCores(latestCheck?.cpu?.logical_core);
|
||||
const cpuFrequency = getFrequency(latestCheck?.cpu?.frequency);
|
||||
const cpuTemps = latestCheck?.cpu?.temperature ?? [];
|
||||
const cpuTemperature = getAvgTemp(cpuTemps);
|
||||
const memoryTotalBytes = getGbs(latestCheck?.memory?.total_bytes);
|
||||
const diskTotalBytes = getDiskTotalGbs(latestCheck?.disk);
|
||||
const os = getOsAndPlatform(latestCheck?.host);
|
||||
|
||||
const platform = latestCheck?.host?.platform ?? undefined;
|
||||
const osPlatform =
|
||||
typeof os === "undefined" && typeof platform === "undefined"
|
||||
? undefined
|
||||
: `${os} ${platform}`;
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(8)}
|
||||
flexWrap={"wrap"}
|
||||
>
|
||||
<StatBox
|
||||
title={t("pages.infrastructure.statBoxes.cpuPhysical")}
|
||||
subtitle={physicalCores.toString()}
|
||||
/>
|
||||
<StatBox
|
||||
title={t("pages.infrastructure.statBoxes.cpuLogical")}
|
||||
subtitle={logicalCores.toString()}
|
||||
/>
|
||||
<StatBox
|
||||
title={t("pages.infrastructure.statBoxes.cpuFrequency")}
|
||||
subtitle={cpuFrequency}
|
||||
/>
|
||||
<StatBox
|
||||
title={t("pages.infrastructure.statBoxes.avgCpuTemperature")}
|
||||
subtitle={cpuTemperature}
|
||||
/>
|
||||
<StatBox
|
||||
title={t("pages.infrastructure.statBoxes.memory")}
|
||||
subtitle={memoryTotalBytes.toString()}
|
||||
/>
|
||||
<StatBox
|
||||
title={t("pages.infrastructure.statBoxes.disk")}
|
||||
subtitle={diskTotalBytes.toString()}
|
||||
/>
|
||||
<StatBox
|
||||
title={t("pages.infrastructure.statBoxes.os")}
|
||||
subtitle={osPlatform || "N/A"}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export const TabNetwork = () => {
|
||||
return <div>Network Content</div>;
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import { StatusBoxes } from "@/Pages/Infrastructure/Details/Components/StatusBoxes";
|
||||
|
||||
import type { Monitor } from "@/Types/Monitor";
|
||||
|
||||
export const TabOverview = ({ monitor }: { monitor: Monitor | undefined }) => {
|
||||
if (!monitor) {
|
||||
return null;
|
||||
}
|
||||
return <StatusBoxes monitor={monitor} />;
|
||||
};
|
||||
@@ -1,7 +1,9 @@
|
||||
import { BasePage } from "@/Components/v2/design-elements";
|
||||
import { BasePage, Tab, Tabs } from "@/Components/v2/design-elements";
|
||||
import { HeaderMonitorControls, HeaderTimeRange } from "@/Components/v2/common";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import { MonitorStatBoxes } from "@/Components/v2/monitors";
|
||||
import { TabNetwork } from "@/Pages/Infrastructure/Details/Components/TabNetwork";
|
||||
import { TabOverview } from "@/Pages/Infrastructure/Details/Components/TabOverview";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
import { useMemo, useState } from "react";
|
||||
@@ -9,14 +11,17 @@ import { useParams } from "react-router-dom";
|
||||
import { useGet } from "@/Hooks/UseApi";
|
||||
import type { HardwareDetailsResponse } from "@/Types/Monitor";
|
||||
import { useIsAdmin } from "@/Hooks/useIsAdmin";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const InfrastructureDetails = () => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const isAdmin = useIsAdmin();
|
||||
|
||||
const { monitorId } = useParams<{ monitorId: string }>();
|
||||
|
||||
const [dateRange, setDateRange] = useState<string>("recent");
|
||||
const [selectedTab, setSelectedTab] = useState<number>(0);
|
||||
|
||||
const monitorDetailsUrl = useMemo(() => {
|
||||
if (!monitorId) {
|
||||
@@ -54,6 +59,17 @@ const InfrastructureDetails = () => {
|
||||
monitor={monitor}
|
||||
monitorStats={monitorStats}
|
||||
/>
|
||||
<Tabs
|
||||
value={selectedTab}
|
||||
onChange={(_e, value) => {
|
||||
setSelectedTab(value);
|
||||
}}
|
||||
>
|
||||
<Tab label={t("pages.infrastructure.tabs.labels.overview")} />
|
||||
<Tab label={t("pages.infrastructure.tabs.labels.network")} />
|
||||
</Tabs>
|
||||
{selectedTab === 0 && <TabOverview monitor={monitor} />}
|
||||
{selectedTab === 1 && <TabNetwork />}
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@ export interface CheckHostInfo {
|
||||
os?: string;
|
||||
platform?: string;
|
||||
kernel_version?: string;
|
||||
pretty_name?: string;
|
||||
}
|
||||
|
||||
export interface CheckCaptureInfo {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import type { CheckDiskInfo, CheckHostInfo } from "@/Types/Check";
|
||||
|
||||
export const getFrequency = (frequency: number | undefined): string => {
|
||||
if (!frequency) return "N/A";
|
||||
const ghz = (frequency / 1000).toFixed(2);
|
||||
return `${ghz} GHz`;
|
||||
};
|
||||
|
||||
export const getCores = (cores: number | undefined) => {
|
||||
if (!cores) return "N/A";
|
||||
if (cores === 1) return `${cores} core`;
|
||||
return `${cores} cores`;
|
||||
};
|
||||
|
||||
export const getAvgTemp = (temps: number[]): string => {
|
||||
console.log(temps);
|
||||
if (!temps || temps.length === 0) return "N/A";
|
||||
const avgTemp = temps.reduce((a, b) => a + b, 0) / temps.length;
|
||||
return `${avgTemp?.toFixed(2)} °C`;
|
||||
};
|
||||
|
||||
export const getGbs = (bytes: number | undefined): string => {
|
||||
if (!bytes) {
|
||||
return "N/A";
|
||||
}
|
||||
if (bytes === 0) {
|
||||
return "0 GB";
|
||||
}
|
||||
|
||||
const GB = bytes / (1024 * 1024 * 1024);
|
||||
const MB = bytes / (1024 * 1024);
|
||||
|
||||
if (GB >= 1) {
|
||||
return GB.toFixed(2) + " GB";
|
||||
} else {
|
||||
return MB.toFixed(2) + " MB";
|
||||
}
|
||||
};
|
||||
|
||||
export const getDiskTotalGbs = (disk?: Partial<CheckDiskInfo>[]): string => {
|
||||
if (!disk) {
|
||||
return getGbs(0);
|
||||
}
|
||||
const totalBytes = disk?.reduce((acc, disk) => acc + (disk.total_bytes || 0), 0) || 0;
|
||||
return getGbs(totalBytes);
|
||||
};
|
||||
|
||||
export const getOsAndPlatform = (hostInfo: CheckHostInfo | undefined): string => {
|
||||
if (!hostInfo) {
|
||||
return "N/A";
|
||||
}
|
||||
const os = hostInfo?.pretty_name || hostInfo?.os || "N/A";
|
||||
const platform = hostInfo?.platform || "N/A";
|
||||
return `${os} (${platform})`;
|
||||
};
|
||||
@@ -284,6 +284,21 @@
|
||||
"disk": "Disk",
|
||||
"memory": "Memory"
|
||||
}
|
||||
},
|
||||
"tabs": {
|
||||
"labels": {
|
||||
"overview": "Overview",
|
||||
"network": "Network"
|
||||
}
|
||||
},
|
||||
"statBoxes": {
|
||||
"cpuPhysical": "CPU (Physical)",
|
||||
"cpuLogical": "CPU (Logical)",
|
||||
"cpuFrequency": "CPU Frequency",
|
||||
"avgCpuTemperature": "Average CPU Temperature",
|
||||
"memory": "Memory",
|
||||
"disk": "Disk",
|
||||
"os": "OS"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user