Fetch data from gist

This commit is contained in:
Alex Holliday
2024-11-19 16:01:08 +08:00
parent 9e7e13baea
commit 217ae50acc
2 changed files with 207 additions and 314 deletions

View File

@@ -1,133 +0,0 @@
function generateMonitorEntries(monitorId, count = 10, options = {}) {
const defaultOptions = {
timeRange: {
start: new Date(Date.now() - 24 * 60 * 60 * 1000 * 20),
end: new Date(),
},
statusVariation: [true, false],
responseTimeRange: [50, 500],
cpuUsageRange: [0, 1],
memoryUsageRange: [0, 1],
diskUsageRange: [0, 1],
};
const mergedOptions = { ...defaultOptions, ...options };
const startTime = mergedOptions.timeRange.start.getTime();
const endTime = mergedOptions.timeRange.end.getTime();
const totalTimeSpan = endTime - startTime;
// Generate sorted random time points
const timePoints = Array.from({ length: count }, (_, index) => {
// Use a non-linear distribution to create more varied spacing
const progress = Math.pow(Math.random(), 2); // Bias towards earlier times
return startTime + progress * totalTimeSpan;
}).sort((a, b) => a - b);
return timePoints.map((timestamp) => {
const createdAt = new Date(timestamp);
return {
_id: "123",
monitorId: monitorId,
status: randomFromArray(mergedOptions.statusVariation),
responseTime: randomInRange(mergedOptions.responseTimeRange),
statusCode: randomStatusCode(),
message: randomMessage(),
cpu: {
physical_core: randomInRange([4, 8]),
logical_core: randomInRange([4, 16]),
frequency: randomInRange([10, 4000]),
temperature: randomInRange([20, 90]),
free_percent: 1 - randomInRange(mergedOptions.cpuUsageRange),
usage_percent: randomInRange(mergedOptions.cpuUsageRange),
_id: "123",
},
memory: {
total_bytes: randomInRange([8, 32]) * 1024 * 1024 * 1024,
available_bytes: randomInRange([4, 16]) * 1024 * 1024 * 1024,
used_bytes: randomInRange([4, 16]) * 1024 * 1024 * 1024,
usage_percent: randomInRange(mergedOptions.memoryUsageRange),
_id: "123",
},
disk: [
{
read_speed_bytes: randomInRange([100, 1000]) * 1024 * 1024,
write_speed_bytes: randomInRange([100, 1000]) * 1024 * 1024,
total_bytes: randomInRange([100, 1000]) * 1024 * 1024 * 1024,
free_bytes: randomInRange([50, 500]) * 1024 * 1024 * 1024,
usage_percent: randomInRange(mergedOptions.diskUsageRange),
_id: "123",
},
],
host: {
os: randomOS(),
platform: randomPlatform(),
kernel_version: randomKernelVersion(),
_id: "123",
},
errors: randomErrors(),
expiry: new Date(createdAt.getTime() + 365 * 24 * 60 * 60 * 1000),
createdAt: createdAt,
updatedAt: createdAt,
__v: 0,
};
});
}
// Modify randomInRange to work with decimal ranges
function randomInRange([min, max]) {
return Number((Math.random() * (max - min) + min).toFixed(2));
}
// ... rest of the code remains the same
function randomFromArray(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}
function randomStatusCode() {
const statusCodes = [200, 201, 204, 400, 401, 403, 404, 500, 502, 503];
return randomFromArray(statusCodes);
}
function randomMessage() {
const messages = [
"OK",
"Created",
"No Content",
"Bad Request",
"Unauthorized",
"Forbidden",
"Not Found",
"Internal Server Error",
];
return randomFromArray(messages);
}
function randomOS() {
const oss = ["Windows", "Linux", "macOS", "Ubuntu", "CentOS"];
return randomFromArray(oss);
}
function randomPlatform() {
const platforms = ["x64", "x86", "ARM", "ARM64"];
return randomFromArray(platforms);
}
function randomKernelVersion() {
return `${randomInRange([4, 6])}.${randomInRange([0, 20])}.${randomInRange([0, 100])}`;
}
function randomErrors() {
const possibleErrors = [
"Network timeout",
"Connection refused",
"SSL certificate error",
"DNS resolution failed",
"",
];
return Math.random() < 0.2 ? [randomFromArray(possibleErrors)] : [];
}
// Usage
const monitorId = "123";
export const monitorData = generateMonitorEntries(monitorId, 20);

View File

@@ -1,10 +1,11 @@
import { monitorData } from "./data";
import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import { Stack, Box, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import CustomGauge from "../../../Components/Charts/CustomGauge";
import AreaChart from "../../../Components/Charts/AreaChart";
import axios from "axios";
import {
TzTick,
PercentTick,
@@ -17,11 +18,18 @@ import PropTypes from "prop-types";
* @param {number} bytes - Number of bytes to convert
* @returns {number} Converted value in gigabytes
*/
const bytesToGB = (bytes) => {
if (typeof bytes !== "number") return 0;
if (bytes === 0) return 0;
const formatBytes = (bytes) => {
if (typeof bytes !== "number") return "0 GB";
if (bytes === 0) return "0 GB";
const GB = bytes / (1024 * 1024 * 1024);
return Number(GB.toFixed(0));
const MB = bytes / (1024 * 1024);
if (GB >= 1) {
return `${Number(GB.toFixed(0))} GB`;
} else {
return `${Number(MB.toFixed(0))} MB`;
}
};
/**
@@ -130,12 +138,12 @@ const GaugeBox = ({ value, heading, metricOne, valueOne, metricTwo, valueTwo })
};
GaugeBox.propTypes = {
value: PropTypes.number.isRequired,
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
heading: PropTypes.string.isRequired,
metricOne: PropTypes.string.isRequired,
valueOne: PropTypes.string.isRequired,
valueOne: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
metricTwo: PropTypes.string.isRequired,
valueTwo: PropTypes.string.isRequired,
valueTwo: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
};
/**
@@ -145,189 +153,207 @@ GaugeBox.propTypes = {
const InfrastructureDetails = () => {
const theme = useTheme();
const { monitorId } = useParams();
const testData = monitorData;
const latestCheck = testData[testData.length - 1];
const navList = [
{ name: "infrastructure monitors", path: "/infrastructure" },
{ name: "details", path: `/infrastructure/${monitorId}` },
];
const [monitor, setMonitor] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get("http://localhost:5000/api/v1/dummy-data", {
headers: {
"Content-Type": "application/json",
"Cache-Control": "no-cache",
},
});
setMonitor(response.data.data);
} catch (error) {
console.error(error);
}
};
fetchData();
}, []);
return (
<Box>
<Breadcrumbs list={navList} />
<Stack
direction="column"
gap={theme.spacing(10)}
mt={theme.spacing(10)}
>
monitor && (
<Box>
<Breadcrumbs list={navList} />
<Stack
direction="row"
gap={theme.spacing(8)}
direction="column"
gap={theme.spacing(10)}
mt={theme.spacing(10)}
>
<StatBox
heading={"CPU"}
subHeading={`${latestCheck.cpu.physical_core} cores`}
/>
<StatBox
heading={"Memory"}
subHeading={`${bytesToGB(latestCheck.memory.total_bytes)}GB`}
/>
<StatBox
heading={"Disk"}
subHeading={`${bytesToGB(latestCheck.disk[0].total_bytes)}GB`}
/>
<StatBox
heading={"Uptime"}
subHeading={"100%"}
/>
<StatBox
heading={"Status"}
subHeading={latestCheck.status === true ? "Active" : "Inactive"}
/>
</Stack>
<Stack
direction="row"
gap={theme.spacing(8)}
>
<GaugeBox
value={latestCheck.cpu.usage_percent * 100}
heading={"Memory Usage"}
metricOne={"Used"}
valueOne={`${bytesToGB(latestCheck.memory.used_bytes)}GB`}
metricTwo={"Total"}
valueTwo={`${bytesToGB(latestCheck.memory.total_bytes)}GB`}
/>
<GaugeBox
value={latestCheck.cpu.usage_percent * 100}
heading={"CPU Usage"}
metricOne={"Cores"}
valueOne={latestCheck.cpu.physical_core}
metricTwo={"Frequency"}
valueTwo={`${latestCheck.cpu.frequency} Ghz`}
/>
{latestCheck.disk.map((disk, idx) => {
return (
<GaugeBox
key={disk._id}
value={disk.usage_percent * 100}
heading={`Disk${idx} usage`}
metricOne={"Used"}
valueOne={`${bytesToGB(disk.total_bytes - disk.free_bytes)}GB`}
metricTwo={"Total"}
valueTwo={`${bytesToGB(disk.total_bytes)}GB`}
<Stack
direction="row"
gap={theme.spacing(8)}
>
<StatBox
heading={"CPU"}
subHeading={`${monitor.checks[0].cpu.physical_core} cores`}
/>
<StatBox
heading={"Memory"}
subHeading={formatBytes(monitor.checks[0].memory.total_bytes)}
/>
<StatBox
heading={"Disk"}
subHeading={formatBytes(monitor.checks[0].disk[0].total_bytes)}
/>
<StatBox
heading={"Uptime"}
subHeading={"100%"}
/>
<StatBox
heading={"Status"}
subHeading={monitor.status === true ? "Active" : "Inactive"}
/>
</Stack>
<Stack
direction="row"
gap={theme.spacing(8)}
>
<GaugeBox
value={monitor.checks[0].memory.usage_percent * 100}
heading={"Memory Usage"}
metricOne={"Used"}
valueOne={formatBytes(monitor.checks[0].memory.used_bytes)}
metricTwo={"Total"}
valueTwo={formatBytes(monitor.checks[0].memory.total_bytes)}
/>
<GaugeBox
value={monitor.checks[0].cpu.usage_percent * 100}
heading={"CPU Usage"}
metricOne={"Cores"}
valueOne={monitor.checks[0].cpu.physical_core}
metricTwo={"Frequency"}
valueTwo={`${(monitor.checks[0].cpu.frequency / 1000).toFixed(2)} Ghz`}
/>
{monitor.checks[0].disk.map((disk, idx) => {
return (
<GaugeBox
key={disk._id}
value={disk.usage_percent * 100}
heading={`Disk${idx} usage`}
metricOne={"Used"}
valueOne={formatBytes(disk.total_bytes - disk.free_bytes)}
metricTwo={"Total"}
valueTwo={formatBytes(disk.total_bytes)}
/>
);
})}
</Stack>
<Stack
direction={"row"}
height={300} // FE team HELP!
gap={theme.spacing(8)} // FE team HELP!
flexWrap="wrap" // //FE team HELP! Better way to do this?
sx={{
"& > *": {
flexBasis: `calc(50% - ${theme.spacing(8)})`,
maxWidth: `calc(50% - ${theme.spacing(8)})`,
},
}}
>
<BaseBox>
<Typography
component="h2"
padding={theme.spacing(8)}
>
Memory usage
</Typography>
<AreaChart
data={monitor?.checks ?? []}
dataKey="memory.usage_percent"
xKey="createdAt"
yKey="memory.usage_percent"
customTooltip={({ active, payload, label }) => (
<InfrastructureTooltip
label={label}
yKey="memory.usage_percent"
yLabel="Memory Usage"
active={active}
payload={payload}
/>
)}
xTick={<TzTick />}
yTick={<PercentTick />}
strokeColor={theme.palette.primary.main}
gradient={true}
gradientStartColor={theme.palette.primary.main} //FE team HELP! Not sure what colors to use
gradientEndColor="#ffffff" // FE team HELP!
/>
);
})}
</BaseBox>
<BaseBox>
<Typography
component="h2"
padding={theme.spacing(8)}
>
CPU usage
</Typography>
<AreaChart
data={monitor?.checks ?? []}
dataKey="cpu.usage_percent"
xKey="createdAt"
yKey="cpu.usage_percent"
customTooltip={({ active, payload, label }) => (
<InfrastructureTooltip
label={label}
yKey="cpu.usage_percent"
yLabel="CPU Usage"
active={active}
payload={payload}
/>
)}
xTick={<TzTick />}
yTick={<PercentTick />}
strokeColor={theme.palette.success.main} // FE team HELP!
gradient={true}
fill={theme.palette.success.main} // FE team HELP!
gradientStartColor={theme.palette.success.main}
gradientEndColor="#ffffff"
/>
</BaseBox>
{monitor?.checks?.[0]?.disk?.map((disk, idx) => {
// disk is an array of disks, so we need to map over it
return (
<BaseBox key={disk._id}>
<Typography
component="h2"
padding={theme.spacing(8)}
>
{`Disk${idx} usage`}
</Typography>
<AreaChart
data={monitor?.checks ?? []}
dataKey={`disk[${idx}].usage_percent`}
xKey="createdAt"
yKey={`disk[${idx}].usage_percent`} // We are looking for the usage_percent of the current disk in the array
customTooltip={({ active, payload, label }) => (
<InfrastructureTooltip
label={label} // label must be a string
yKey={`disk.usage_percent`}
yLabel="Disk Usage"
yIdx={idx}
active={active}
payload={payload}
/>
)}
xTick={<TzTick />}
yTick={<PercentTick />}
strokeColor={theme.palette.warning.main}
gradient={true}
gradientStartColor={theme.palette.warning.main}
gradientEndColor="#ffffff"
/>
</BaseBox>
);
})}
</Stack>
</Stack>
<Stack
direction={"row"}
height={300} // FE team HELP!
gap={theme.spacing(8)} // FE team HELP!
flexWrap="wrap" // //FE team HELP! Better way to do this?
sx={{
"& > *": {
flexBasis: `calc(50% - ${theme.spacing(8)})`,
maxWidth: `calc(50% - ${theme.spacing(8)})`,
},
}}
>
<BaseBox>
<Typography
component="h2"
padding={theme.spacing(8)}
>
Memory usage
</Typography>
<AreaChart
data={testData}
dataKey="memory.usage_percent"
xKey="createdAt"
yKey="memory.usage_percent"
customTooltip={({ active, payload, label }) => (
<InfrastructureTooltip
label={label}
yKey="memory.usage_percent"
yLabel="Memory Usage"
active={active}
payload={payload}
/>
)}
xTick={<TzTick />}
yTick={<PercentTick />}
strokeColor={theme.palette.primary.main}
gradient={true}
gradientStartColor={theme.palette.primary.main} //FE team HELP! Not sure what colors to use
gradientEndColor="#ffffff" // FE team HELP!
/>
</BaseBox>
<BaseBox>
<Typography
component="h2"
padding={theme.spacing(8)}
>
CPU usage
</Typography>
<AreaChart
data={testData}
dataKey="cpu.usage_percent"
xKey="createdAt"
yKey="cpu.usage_percent"
customTooltip={({ active, payload, label }) => (
<InfrastructureTooltip
label={label}
yKey="cpu.usage_percent"
yLabel="CPU Usage"
active={active}
payload={payload}
/>
)}
xTick={<TzTick />}
yTick={<PercentTick />}
strokeColor={theme.palette.success.main} // FE team HELP!
gradient={true}
fill={theme.palette.success.main} // FE team HELP!
gradientStartColor={theme.palette.success.main}
gradientEndColor="#ffffff"
/>
</BaseBox>
{latestCheck.disk.map((disk, idx) => {
// disk is an array of disks, so we need to map over it
return (
<BaseBox key={disk._id}>
<Typography
component="h2"
padding={theme.spacing(8)}
>
{`Disk${idx} usage`}
</Typography>
<AreaChart
data={testData}
dataKey={`disk[${idx}].usage_percent`}
xKey="createdAt"
yKey={`disk[${idx}].usage_percent`} // We are looking for the usage_percent of the current disk in the array
customTooltip={({ active, payload, label }) => (
<InfrastructureTooltip
label={label} // label must be a string
yKey={`disk.usage_percent`}
yLabel="Disk Usage"
yIdx={idx}
active={active}
payload={payload}
/>
)}
xTick={<TzTick />}
yTick={<PercentTick />}
strokeColor={theme.palette.warning.main}
gradient={true}
gradientStartColor={theme.palette.warning.main}
gradientEndColor="#ffffff"
/>
</BaseBox>
);
})}
</Stack>
</Stack>
</Box>
</Box>
)
);
};