remove unused
This commit is contained in:
1 parent
64de01437e
commit
174665e70a
15 files changed
+11
-918
No files matched your search
@@ -84,7 +84,6 @@ export const HistogramDetails = ({
|
||||
checks: GroupedCheck[];
|
||||
range: string;
|
||||
}) => {
|
||||
console.log(range);
|
||||
const theme = useTheme();
|
||||
const uiTimezone = useSelector((state: RootState) => state.ui.timezone);
|
||||
return (
|
||||
|
||||
@@ -75,7 +75,7 @@ export const HistogramStatus = ({
|
||||
if (!active || !payload?.length) return null;
|
||||
const d = payload[0]?.payload;
|
||||
const avg = d?.avgResponseTime ?? 0;
|
||||
const titleText = t("common.charts.labels.averageRepsonseTime");
|
||||
const titleText = t("common.charts.labels.averageResponseTime");
|
||||
const fmt = range === "30d" ? "MMM D, YYYY" : "ddd, MMM D, YYYY, h:mm A";
|
||||
let dateLabel = "";
|
||||
if (d?._id) {
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
// Components
|
||||
import { Stack, Typography, Box } from "@mui/material";
|
||||
import ChartBox from "@/Components/v1/Charts/ChartBox/index.jsx";
|
||||
import Icon from "@/Components/v1/Icon";
|
||||
import UpBarChart from "../Charts/UpBarChart.jsx";
|
||||
import DownBarChart from "../Charts/DownBarChart.jsx";
|
||||
import ResponseGaugeChart from "../Charts/ResponseGaugeChart.jsx";
|
||||
import SkeletonLayout from "./skeleton.jsx";
|
||||
// Utils
|
||||
import { formatDateWithTz } from "../../../../../Utils/timeUtilsLegacy.js";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useState } from "react";
|
||||
|
||||
const ChartBoxes = ({
|
||||
isLoading = false,
|
||||
monitorData,
|
||||
dateRange,
|
||||
uiTimezone,
|
||||
dateFormat,
|
||||
}) => {
|
||||
// Local state
|
||||
const [hoveredUptimeData, setHoveredUptimeData] = useState(null);
|
||||
const [hoveredIncidentsData, setHoveredIncidentsData] = useState(null);
|
||||
const theme = useTheme();
|
||||
if (isLoading) {
|
||||
return <SkeletonLayout />;
|
||||
}
|
||||
|
||||
const noIncidentsMessage = "Great. No Incidents, yet!";
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
flexWrap="wrap"
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<ChartBox
|
||||
icon={
|
||||
<Icon
|
||||
name="Activity"
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
header="Uptime"
|
||||
isEmpty={monitorData?.groupedUpChecks?.length === 0}
|
||||
>
|
||||
<Stack
|
||||
width={"100%"}
|
||||
justifyContent="space-between"
|
||||
direction="row"
|
||||
>
|
||||
<Box position="relative">
|
||||
<Typography>Total Checks</Typography>
|
||||
<Typography component="span">
|
||||
{hoveredUptimeData !== null
|
||||
? hoveredUptimeData.totalChecks
|
||||
: (monitorData?.groupedUpChecks?.reduce((count, checkGroup) => {
|
||||
return count + checkGroup.totalChecks;
|
||||
}, 0) ?? 0)}
|
||||
</Typography>
|
||||
{hoveredUptimeData !== null && hoveredUptimeData.time !== null && (
|
||||
<Typography
|
||||
component="h5"
|
||||
position="absolute"
|
||||
top="100%"
|
||||
fontSize={11}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
{formatDateWithTz(hoveredUptimeData._id, dateFormat, uiTimezone)}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography>
|
||||
{hoveredUptimeData !== null ? "Avg Response Time" : "Uptime Percentage"}
|
||||
</Typography>
|
||||
<Typography component="span">
|
||||
{hoveredUptimeData !== null
|
||||
? Math.floor(hoveredUptimeData?.originalAvgResponseTime ?? 0)
|
||||
: Math.floor((monitorData?.groupedUptimePercentage ?? 0) * 100)}
|
||||
<Typography component="span">
|
||||
{hoveredUptimeData !== null ? " ms" : " %"}
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
<UpBarChart
|
||||
groupedUpChecks={monitorData?.groupedUpChecks}
|
||||
type={dateRange}
|
||||
onBarHover={setHoveredUptimeData}
|
||||
/>
|
||||
</ChartBox>
|
||||
<ChartBox
|
||||
icon={
|
||||
<Icon
|
||||
name="AlertTriangle"
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
header="Incidents"
|
||||
noDataMessage={noIncidentsMessage}
|
||||
isEmpty={monitorData?.groupedDownChecks?.length === 0}
|
||||
>
|
||||
<Stack width={"100%"}>
|
||||
<Box position="relative">
|
||||
<Typography component="span">
|
||||
{hoveredIncidentsData !== null
|
||||
? hoveredIncidentsData.totalChecks
|
||||
: (monitorData?.groupedDownChecks?.reduce((count, checkGroup) => {
|
||||
return count + checkGroup.totalChecks;
|
||||
}, 0) ?? 0)}
|
||||
</Typography>
|
||||
{hoveredIncidentsData !== null && hoveredIncidentsData.time !== null && (
|
||||
<Typography
|
||||
component="h5"
|
||||
position="absolute"
|
||||
top="100%"
|
||||
fontSize={11}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
{formatDateWithTz(hoveredIncidentsData._id, dateFormat, uiTimezone)}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Stack>
|
||||
<DownBarChart
|
||||
groupedDownChecks={monitorData?.groupedDownChecks}
|
||||
type={dateRange}
|
||||
onBarHover={setHoveredIncidentsData}
|
||||
/>
|
||||
</ChartBox>
|
||||
<ChartBox
|
||||
icon={
|
||||
<Icon
|
||||
name="BarChart3"
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
header="Average Response Time"
|
||||
>
|
||||
<ResponseGaugeChart avgResponseTime={monitorData?.groupedAvgResponseTime ?? 0} />
|
||||
</ChartBox>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChartBoxes;
|
||||
|
||||
ChartBoxes.propTypes = {
|
||||
isLoading: PropTypes.bool,
|
||||
monitorData: PropTypes.object,
|
||||
dateRange: PropTypes.string.isRequired,
|
||||
uiTimezone: PropTypes.string.isRequired,
|
||||
dateFormat: PropTypes.string.isRequired,
|
||||
hoveredUptimeData: PropTypes.object,
|
||||
setHoveredUptimeData: PropTypes.func,
|
||||
hoveredIncidentsData: PropTypes.object,
|
||||
setHoveredIncidentsData: PropTypes.func,
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
import { Skeleton, Stack } from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
const SkeletonLayout = () => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<Skeleton
|
||||
variant="rounded"
|
||||
width="100%"
|
||||
height={300}
|
||||
/>
|
||||
<Skeleton
|
||||
variant="rounded"
|
||||
width="100%"
|
||||
height={300}
|
||||
/>
|
||||
<Skeleton
|
||||
variant="rounded"
|
||||
width="100%"
|
||||
height={300}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default SkeletonLayout;
|
||||
@@ -1,42 +0,0 @@
|
||||
import PropTypes from "prop-types";
|
||||
import { useSelector } from "react-redux";
|
||||
import { formatDateWithTz } from "../../../../../Utils/timeUtilsLegacy.js";
|
||||
|
||||
const CustomLabels = ({ x, width, height, firstDataPoint, lastDataPoint, type }) => {
|
||||
const uiTimezone = useSelector((state) => state.ui.timezone);
|
||||
const dateFormat = type === "day" ? "MMM D, h:mm A" : "MMM D";
|
||||
|
||||
return (
|
||||
<>
|
||||
<text
|
||||
x={x}
|
||||
y={height}
|
||||
dy={-3}
|
||||
textAnchor="start"
|
||||
fontSize={11}
|
||||
>
|
||||
{formatDateWithTz(firstDataPoint._id, dateFormat, uiTimezone)}
|
||||
</text>
|
||||
<text
|
||||
x={width}
|
||||
y={height}
|
||||
dy={-3}
|
||||
textAnchor="end"
|
||||
fontSize={11}
|
||||
>
|
||||
{formatDateWithTz(lastDataPoint._id, dateFormat, uiTimezone)}
|
||||
</text>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
CustomLabels.propTypes = {
|
||||
x: PropTypes.number.isRequired,
|
||||
width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
firstDataPoint: PropTypes.object,
|
||||
lastDataPoint: PropTypes.object,
|
||||
type: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default CustomLabels;
|
||||
@@ -1,90 +0,0 @@
|
||||
import { memo, useState } from "react";
|
||||
import { useTheme } from "@mui/material";
|
||||
import { ResponsiveContainer, BarChart, XAxis, Bar, Cell } from "recharts";
|
||||
import PropTypes from "prop-types";
|
||||
import CustomLabels from "./CustomLabels.jsx";
|
||||
|
||||
const DownBarChart = memo(({ groupedDownChecks = [], type, onBarHover }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const [chartHovered, setChartHovered] = useState(false);
|
||||
const [hoveredBarIndex, setHoveredBarIndex] = useState(null);
|
||||
|
||||
return (
|
||||
<ResponsiveContainer
|
||||
width="100%"
|
||||
minWidth={250}
|
||||
height={155}
|
||||
>
|
||||
<BarChart
|
||||
width="100%"
|
||||
height="100%"
|
||||
data={groupedDownChecks}
|
||||
onMouseEnter={() => {
|
||||
setChartHovered(true);
|
||||
onBarHover({ time: null, totalChecks: 0 });
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setChartHovered(false);
|
||||
setHoveredBarIndex(null);
|
||||
onBarHover(null);
|
||||
}}
|
||||
>
|
||||
<XAxis
|
||||
stroke={theme.palette.primary.lowContrast}
|
||||
height={15}
|
||||
tick={false}
|
||||
label={
|
||||
<CustomLabels
|
||||
x={0}
|
||||
y={0}
|
||||
width="100%"
|
||||
height="100%"
|
||||
firstDataPoint={groupedDownChecks?.[0] ?? {}}
|
||||
lastDataPoint={groupedDownChecks?.[groupedDownChecks?.length - 1] ?? {}}
|
||||
type={type}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="avgResponseTime"
|
||||
maxBarSize={7}
|
||||
background={{ fill: "transparent" }}
|
||||
>
|
||||
{groupedDownChecks?.map((entry, index) => {
|
||||
return (
|
||||
<Cell
|
||||
key={`cell-${entry.time}`}
|
||||
fill={
|
||||
hoveredBarIndex === index
|
||||
? theme.palette.error.main
|
||||
: chartHovered
|
||||
? theme.palette.error.light // CAIO_REVIEW
|
||||
: theme.palette.error.main
|
||||
}
|
||||
onMouseEnter={() => {
|
||||
setHoveredBarIndex(index);
|
||||
onBarHover(entry);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setHoveredBarIndex(null);
|
||||
onBarHover({ time: null, totalChecks: 0 });
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Bar>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
});
|
||||
|
||||
DownBarChart.displayName = "DownBarChart";
|
||||
DownBarChart.propTypes = {
|
||||
monitor: PropTypes.shape({
|
||||
groupedDownChecks: PropTypes.arrayOf(PropTypes.object),
|
||||
}),
|
||||
type: PropTypes.string,
|
||||
onBarHover: PropTypes.func,
|
||||
};
|
||||
export default DownBarChart;
|
||||
@@ -1,118 +0,0 @@
|
||||
import PropTypes from "prop-types";
|
||||
import { useTheme } from "@mui/material";
|
||||
import { ResponsiveContainer, RadialBarChart, RadialBar, Cell } from "recharts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const ResponseGaugeChart = ({ avgResponseTime }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
let max = 1000; // max ms
|
||||
|
||||
const data = [
|
||||
{ response: max, fill: "transparent", background: false },
|
||||
{ response: avgResponseTime, background: true },
|
||||
];
|
||||
let responseTime = Math.floor(avgResponseTime);
|
||||
let responseProps =
|
||||
responseTime <= 200
|
||||
? {
|
||||
category: "Excellent",
|
||||
main: theme.palette.success.main,
|
||||
bg: theme.palette.success.lowContrast,
|
||||
}
|
||||
: responseTime <= 500
|
||||
? {
|
||||
category: "Fair",
|
||||
main: theme.palette.success.main,
|
||||
bg: theme.palette.success.lowContrast,
|
||||
}
|
||||
: responseTime <= 600
|
||||
? {
|
||||
category: "Acceptable",
|
||||
main: theme.palette.warning.main,
|
||||
bg: theme.palette.warning.lowContrast,
|
||||
}
|
||||
: {
|
||||
category: "Poor",
|
||||
main: theme.palette.error.main,
|
||||
bg: theme.palette.error.lowContrast,
|
||||
};
|
||||
|
||||
return (
|
||||
<ResponsiveContainer
|
||||
width="100%"
|
||||
minWidth={210}
|
||||
height={155}
|
||||
>
|
||||
<RadialBarChart
|
||||
width="100%"
|
||||
height="100%"
|
||||
cy="89%"
|
||||
data={data}
|
||||
startAngle={180}
|
||||
endAngle={0}
|
||||
innerRadius={100}
|
||||
outerRadius={150}
|
||||
>
|
||||
<text
|
||||
x={0}
|
||||
y="100%"
|
||||
dx="5%"
|
||||
dy={-2}
|
||||
textAnchor="start"
|
||||
fontSize={11}
|
||||
>
|
||||
{t("low")}
|
||||
</text>
|
||||
<text
|
||||
x="100%"
|
||||
y="100%"
|
||||
dx="-3%"
|
||||
dy={-2}
|
||||
textAnchor="end"
|
||||
fontSize={11}
|
||||
>
|
||||
{t("high")}
|
||||
</text>
|
||||
<text
|
||||
x="50%"
|
||||
y="45%"
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
fontSize={18}
|
||||
fontWeight={400}
|
||||
>
|
||||
{responseProps.category}
|
||||
</text>
|
||||
<text
|
||||
x="50%"
|
||||
y="70%"
|
||||
textAnchor="middle"
|
||||
alignmentBaseline="hanging"
|
||||
fontSize={25}
|
||||
>
|
||||
<tspan fontWeight={600}>{responseTime}</tspan> <tspan opacity={0.8}>ms</tspan>
|
||||
</text>
|
||||
<RadialBar
|
||||
background={{ fill: responseProps.bg }}
|
||||
clockWise
|
||||
dataKey="response"
|
||||
stroke="none"
|
||||
>
|
||||
<Cell
|
||||
fill="transparent"
|
||||
background={false}
|
||||
barSize={0}
|
||||
/>
|
||||
<Cell fill={responseProps.main} />
|
||||
</RadialBar>
|
||||
</RadialBarChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
};
|
||||
|
||||
ResponseGaugeChart.propTypes = {
|
||||
avgResponseTime: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
export default ResponseGaugeChart;
|
||||
@@ -1,36 +0,0 @@
|
||||
import ChartBox from "@/Components/v1/Charts/ChartBox/index.jsx";
|
||||
import MonitorDetailsAreaChart from "@/Components/v1/Charts/MonitorDetailsAreaChart/index.jsx";
|
||||
import Icon from "@/Components/v1/Icon";
|
||||
import SkeletonLayout from "./ResponseTimeChartSkeleton.jsx";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const ResponseTImeChart = ({ isLoading = false, groupedChecks = [], dateRange }) => {
|
||||
if (isLoading) {
|
||||
return <SkeletonLayout />;
|
||||
}
|
||||
|
||||
return (
|
||||
<ChartBox
|
||||
icon={
|
||||
<Icon
|
||||
name="TrendingUp"
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
header="Response Times"
|
||||
>
|
||||
<MonitorDetailsAreaChart
|
||||
checks={groupedChecks}
|
||||
dateRange={dateRange}
|
||||
/>
|
||||
</ChartBox>
|
||||
);
|
||||
};
|
||||
|
||||
ResponseTImeChart.propTypes = {
|
||||
isLoading: PropTypes.bool,
|
||||
groupedChecks: PropTypes.array,
|
||||
dateRange: PropTypes.string,
|
||||
};
|
||||
|
||||
export default ResponseTImeChart;
|
||||
@@ -1,12 +0,0 @@
|
||||
import { Skeleton } from "@mui/material";
|
||||
const ResponseTimeChartSkeleton = () => {
|
||||
return (
|
||||
<Skeleton
|
||||
variant="rounded"
|
||||
width="100%"
|
||||
height={300}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResponseTimeChartSkeleton;
|
||||
@@ -1,107 +0,0 @@
|
||||
import { memo, useState } from "react";
|
||||
import { useTheme } from "@mui/material";
|
||||
import { ResponsiveContainer, BarChart, XAxis, Bar, Cell } from "recharts";
|
||||
import PropTypes from "prop-types";
|
||||
import CustomLabels from "./CustomLabels.jsx";
|
||||
|
||||
const getThemeColor = (responseTime) => {
|
||||
if (responseTime < 200) {
|
||||
return "success";
|
||||
} else if (responseTime < 300) {
|
||||
return "warning";
|
||||
} else {
|
||||
return "error";
|
||||
}
|
||||
};
|
||||
|
||||
const UpBarChart = memo(({ groupedUpChecks = [], type, onBarHover }) => {
|
||||
const theme = useTheme();
|
||||
const [chartHovered, setChartHovered] = useState(false);
|
||||
const [hoveredBarIndex, setHoveredBarIndex] = useState(null);
|
||||
|
||||
return (
|
||||
<ResponsiveContainer
|
||||
width="100%"
|
||||
minWidth={210}
|
||||
height={155}
|
||||
>
|
||||
<BarChart
|
||||
width="100%"
|
||||
height="100%"
|
||||
data={groupedUpChecks}
|
||||
onMouseEnter={() => {
|
||||
setChartHovered(true);
|
||||
onBarHover({ time: null, totalChecks: 0, originalAvgResponseTime: 0 });
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setChartHovered(false);
|
||||
setHoveredBarIndex(null);
|
||||
onBarHover(null);
|
||||
}}
|
||||
>
|
||||
<XAxis
|
||||
stroke={theme.palette.primary.lowContrast}
|
||||
height={15}
|
||||
tick={false}
|
||||
label={
|
||||
<CustomLabels
|
||||
x={0}
|
||||
y={0}
|
||||
width="100%"
|
||||
height="100%"
|
||||
firstDataPoint={groupedUpChecks?.[0]}
|
||||
lastDataPoint={groupedUpChecks?.[groupedUpChecks?.length - 1]}
|
||||
type={type}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="avgResponseTime"
|
||||
maxBarSize={7}
|
||||
background={{ fill: "transparent" }}
|
||||
>
|
||||
{groupedUpChecks?.map((entry, index) => {
|
||||
const themeColor = getThemeColor(entry.originalAvgResponseTime);
|
||||
return (
|
||||
<Cell
|
||||
key={`cell-${entry.time}`}
|
||||
fill={
|
||||
hoveredBarIndex === index
|
||||
? theme.palette[themeColor].main
|
||||
: chartHovered
|
||||
? theme.palette[themeColor].light
|
||||
: theme.palette[themeColor].main
|
||||
}
|
||||
onMouseEnter={() => {
|
||||
setHoveredBarIndex(index);
|
||||
onBarHover(entry);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setHoveredBarIndex(null);
|
||||
onBarHover({
|
||||
time: null,
|
||||
totalChecks: 0,
|
||||
groupUptimePercentage: 0,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Bar>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
});
|
||||
|
||||
// Add display name for the component
|
||||
UpBarChart.displayName = "UpBarChart";
|
||||
|
||||
// Validate props using PropTypes
|
||||
UpBarChart.propTypes = {
|
||||
monitor: PropTypes.shape({
|
||||
groupedUpChecks: PropTypes.array,
|
||||
}),
|
||||
type: PropTypes.string,
|
||||
onBarHover: PropTypes.func,
|
||||
};
|
||||
export default UpBarChart;
|
||||
@@ -20,7 +20,7 @@ const getHeaders = (t: Function, uiTimezone: string) => {
|
||||
},
|
||||
{
|
||||
id: "date",
|
||||
content: t("checks.table.headers.dateTime"),
|
||||
content: t("pages.checks.table.headers.dateTime"),
|
||||
render: (row) => {
|
||||
return formatDateWithTz(row.createdAt, "ddd, MMMM D, YYYY, HH:mm A", uiTimezone);
|
||||
},
|
||||
@@ -34,7 +34,7 @@ const getHeaders = (t: Function, uiTimezone: string) => {
|
||||
},
|
||||
{
|
||||
id: "statusCode",
|
||||
content: t("checks.table.headers.statusCode"),
|
||||
content: t("pages.checks.table.headers.statusCode"),
|
||||
render: (row) => {
|
||||
return row.statusCode || "N/A";
|
||||
},
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
import ChartBox from "@/Components/v1/Charts/ChartBox/index.jsx";
|
||||
import PropTypes from "prop-types";
|
||||
import Icon from "@/Components/v1/Icon";
|
||||
import Table from "@/Components/v1/Table/index.jsx";
|
||||
import TablePagination from "@/Components/v1/Table/TablePagination/index.jsx";
|
||||
import { StatusLabel } from "@/Components/v1/Label/index.jsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { formatDateWithTz } from "../../../../../Utils/timeUtilsLegacy.js";
|
||||
import SkeletonLayout from "./skeleton.jsx";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import { lighten, useTheme } from "@mui/material";
|
||||
|
||||
/**
|
||||
* Creates tooltip content with detailed timing breakdown
|
||||
* Following the pattern from IncidentTable's GetTooltip function
|
||||
* @param {Object} timings - Timing object (guaranteed to have phases by caller)
|
||||
* @param {Object} theme - MUI theme object
|
||||
* @param {Function} t - Translation function
|
||||
* @returns {JSX.Element} Tooltip content
|
||||
*/
|
||||
const GetTooltip = (timings, theme, t) => {
|
||||
const phases = timings.phases;
|
||||
const timingDetails = [
|
||||
{ label: t("dnsLookup"), value: phases.dns },
|
||||
{ label: t("tcpConnection"), value: phases.tcp },
|
||||
{ label: t("tlsHandshake"), value: phases.tls },
|
||||
{ label: t("waitTime"), value: phases.wait },
|
||||
{ label: t("timeToFirstByte"), value: phases.firstByte },
|
||||
{ label: t("download"), value: phases.download },
|
||||
{ label: t("total"), value: phases.total },
|
||||
].filter((item) => item.value > 0);
|
||||
|
||||
return (
|
||||
<Stack
|
||||
sx={{
|
||||
py: theme.spacing(2),
|
||||
px: theme.spacing(4),
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
marginBottom: theme.spacing(1),
|
||||
color: theme.palette.primary.contrastText,
|
||||
}}
|
||||
>
|
||||
{t("responseTimeBreakdown")}
|
||||
</Typography>
|
||||
{timingDetails.map((detail, index, array) => (
|
||||
<Box
|
||||
key={index}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
gap: theme.spacing(4),
|
||||
marginBottom: index < array.length - 1 ? theme.spacing(0.5) : 0,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ color: theme.palette.primary.contrastText }}
|
||||
>
|
||||
{detail.label}:
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{
|
||||
fontWeight: index === array.length - 1 ? 600 : 400,
|
||||
color: theme.palette.primary.contrastText,
|
||||
}}
|
||||
>
|
||||
{Math.round(detail.value)} ms
|
||||
</Typography>
|
||||
</Box>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
const ResponseTable = ({
|
||||
isLoading = false,
|
||||
checks = [],
|
||||
checksCount,
|
||||
uiTimezone,
|
||||
page,
|
||||
setPage,
|
||||
rowsPerPage,
|
||||
setRowsPerPage,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
|
||||
if (isLoading) {
|
||||
return <SkeletonLayout />;
|
||||
}
|
||||
|
||||
const headers = [
|
||||
{
|
||||
id: "status",
|
||||
content: t("status"),
|
||||
render: (row) => {
|
||||
const status = row.status === true ? "up" : "down";
|
||||
|
||||
return (
|
||||
<StatusLabel
|
||||
status={status}
|
||||
text={status}
|
||||
customStyles={{ textTransform: "capitalize" }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "date",
|
||||
content: t("date&Time"),
|
||||
render: (row) =>
|
||||
formatDateWithTz(row.createdAt, "ddd, MMMM D, YYYY, HH:mm A", uiTimezone),
|
||||
},
|
||||
{
|
||||
id: "statusCode",
|
||||
content: t("statusCode"),
|
||||
render: (row) => (row.statusCode ? row.statusCode : "N/A"),
|
||||
},
|
||||
{
|
||||
id: "message",
|
||||
content: t("message"),
|
||||
render: (row) => row.message,
|
||||
},
|
||||
{
|
||||
id: "responseTime",
|
||||
content: t("responseTime"),
|
||||
render: (row) => {
|
||||
const hasTimings = row.timings && row.timings.phases;
|
||||
const responseTime = row.responseTime;
|
||||
const responseTimeDisplay =
|
||||
responseTime !== null && responseTime !== undefined
|
||||
? `${Math.round(responseTime)} ms`
|
||||
: "N/A";
|
||||
|
||||
if (!hasTimings) {
|
||||
return responseTimeDisplay;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
title={GetTooltip(row.timings, theme, t)}
|
||||
placement="top"
|
||||
arrow
|
||||
enterDelay={300}
|
||||
enterNextDelay={300}
|
||||
slotProps={{
|
||||
tooltip: {
|
||||
sx: {
|
||||
backgroundColor: lighten(theme.palette.primary.main, 0.1),
|
||||
border: `1px solid ${theme.palette.primary.lowContrast}`,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
"& .MuiTooltip-arrow": {
|
||||
color: lighten(theme.palette.primary.main, 0.1),
|
||||
"&::before": {
|
||||
border: `1px solid ${theme.palette.primary.lowContrast}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
cursor: "help",
|
||||
display: "inline-block",
|
||||
}}
|
||||
>
|
||||
{responseTimeDisplay}
|
||||
</Box>
|
||||
</Tooltip>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<ChartBox
|
||||
icon={
|
||||
<Icon
|
||||
name="History"
|
||||
size={20}
|
||||
/>
|
||||
}
|
||||
header="Response Times"
|
||||
height="100%"
|
||||
>
|
||||
<Table
|
||||
headers={headers}
|
||||
data={checks}
|
||||
/>
|
||||
<TablePagination
|
||||
page={page}
|
||||
handleChangePage={setPage}
|
||||
rowsPerPage={rowsPerPage}
|
||||
handleChangeRowsPerPage={setRowsPerPage}
|
||||
itemCount={checksCount}
|
||||
/>
|
||||
</ChartBox>
|
||||
);
|
||||
};
|
||||
|
||||
ResponseTable.propTypes = {
|
||||
isLoading: PropTypes.bool,
|
||||
checks: PropTypes.array,
|
||||
checksCount: PropTypes.number,
|
||||
uiTimezone: PropTypes.string.isRequired,
|
||||
page: PropTypes.number.isRequired,
|
||||
setPage: PropTypes.func.isRequired,
|
||||
rowsPerPage: PropTypes.number.isRequired,
|
||||
setRowsPerPage: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ResponseTable;
|
||||
@@ -1,13 +0,0 @@
|
||||
import { Skeleton } from "@mui/material";
|
||||
|
||||
const SkeletonLayout = () => {
|
||||
return (
|
||||
<Skeleton
|
||||
variant="rounded"
|
||||
width="100%"
|
||||
height={300}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SkeletonLayout;
|
||||
@@ -1,84 +0,0 @@
|
||||
import StatusBoxes from "@/Components/v1/StatusBoxes/index.jsx";
|
||||
import StatBox from "@/Components/v1/StatBox/index.jsx";
|
||||
|
||||
import PropTypes from "prop-types";
|
||||
import { getHumanReadableDuration } from "../../../../../Utils/timeUtilsLegacy.js";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { Typography } from "@mui/material";
|
||||
import { useMonitorUtils } from "../../../../../Hooks/useMonitorUtils.js";
|
||||
|
||||
const UptimeStatusBoxes = ({
|
||||
isLoading = false,
|
||||
monitor,
|
||||
monitorStats,
|
||||
certificateExpiry,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const { determineState } = useMonitorUtils();
|
||||
|
||||
// Determine time since last failure
|
||||
const timeOfLastFailure = monitorStats?.timeOfLastFailure;
|
||||
const timeSinceLastFailure =
|
||||
timeOfLastFailure > 0
|
||||
? Date.now() - timeOfLastFailure
|
||||
: Date.now() - new Date(monitorStats?.createdAt);
|
||||
|
||||
// Determine time since last check
|
||||
const timeOfLastCheck = monitorStats?.lastCheckTimestamp;
|
||||
const timeSinceLastCheck = Date.now() - timeOfLastCheck;
|
||||
|
||||
const streakTime = getHumanReadableDuration(timeSinceLastFailure);
|
||||
|
||||
const lastCheckTime = getHumanReadableDuration(timeSinceLastCheck);
|
||||
return (
|
||||
<StatusBoxes shouldRender={!isLoading}>
|
||||
<StatBox
|
||||
gradient={true}
|
||||
status={determineState(monitor)}
|
||||
heading={"active for"}
|
||||
subHeading={streakTime}
|
||||
/>
|
||||
<StatBox
|
||||
heading="last check"
|
||||
subHeading={
|
||||
<>
|
||||
{lastCheckTime}
|
||||
<Typography component="span">{"ago"}</Typography>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<StatBox
|
||||
heading="last response time"
|
||||
subHeading={
|
||||
<>
|
||||
{monitorStats?.lastResponseTime}
|
||||
<Typography component="span">{"ms"}</Typography>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
{monitor?.type === "http" && (
|
||||
<StatBox
|
||||
heading="certificate expiry"
|
||||
subHeading={
|
||||
<Typography
|
||||
component="span"
|
||||
fontSize={13}
|
||||
color={theme.palette.primary.contrastText}
|
||||
>
|
||||
{certificateExpiry}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</StatusBoxes>
|
||||
);
|
||||
};
|
||||
|
||||
UptimeStatusBoxes.propTypes = {
|
||||
isLoading: PropTypes.bool,
|
||||
monitor: PropTypes.object,
|
||||
monitorStats: PropTypes.object,
|
||||
certificateExpiry: PropTypes.string,
|
||||
};
|
||||
|
||||
export default UptimeStatusBoxes;
|
||||
@@ -208,6 +208,14 @@
|
||||
"placeholder": "Search monitors..."
|
||||
}
|
||||
}
|
||||
},
|
||||
"checks": {
|
||||
"table": {
|
||||
"headers": {
|
||||
"dateTime": "Date & time",
|
||||
"statusCode": "Status code"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"distributedUptimeStatusCreateStatusPage": "status page",
|
||||
|
||||
Reference in new issue
Block a user