diff --git a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
index fd28b6e7e..023962cb0 100644
--- a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
+++ b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx
@@ -6,10 +6,12 @@ import {
Tooltip,
CartesianGrid,
ResponsiveContainer,
+ Text,
} from "recharts";
import { Box, Stack, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import { useMemo } from "react";
+import { formatDate } from "../../../Utils/timeUtils";
import "./index.css";
const CustomToolTip = ({ active, payload, label }) => {
@@ -87,20 +89,34 @@ const CustomToolTip = ({ active, payload, label }) => {
return null;
};
-const MonitorDetailsAreaChart = ({ checks }) => {
- const formatDate = (timestamp) => {
- const date = new Date(timestamp);
- return date.toLocaleTimeString("en-US", {
- hour: "numeric",
- minute: "2-digit",
- hour12: true,
- });
- };
-
- const memoizedChecks = useMemo(() => checks, [checks[0]]);
-
+const CustomTick = ({ x, y, payload, index }) => {
const theme = useTheme();
+ // Render nothing for the first tick
+ if (index === 0) return null;
+
+ return (
+
+ {formatDate(new Date(payload.value), {
+ year: undefined,
+ month: undefined,
+ day: undefined,
+ })}
+
+ );
+};
+
+const MonitorDetailsAreaChart = ({ checks }) => {
+ const theme = useTheme();
+ const memoizedChecks = useMemo(() => checks, [checks[0]]);
+
return (
{
}
+ minTickGap={0}
+ axisLine={false}
tickLine={false}
- height={18}
+ height={20}
+ interval="equidistantPreserveStart"
/>
{
- const keyToLabel = {
- performance: "Performance",
- seo: "SEO",
- bestPractices: "Best practices",
- accessibility: "Accessibility",
- };
-
- const colors = {
- performance: "#2aa02b",
- seo: "#9467bd",
- bestPractices: "#ff7f0e",
- accessibility: "#1f76b3",
- };
-
- const customize = {
- legend: { position: { vertical: "bottom", horizontal: "middle" } },
- margin: { bottom: 75 },
- };
-
- const xLabels = pageSpeedChecks.map((check) => {
- return check.createdAt;
- });
-
- return (
- ({
- dataKey: key,
- label: keyToLabel[key],
- color: colors[key],
- showMark: false,
- }))}
- yAxis={[{ min: 0, max: 100 }]}
- xAxis={[
- {
- scaleType: "point",
- data: xLabels,
- valueFormatter: (val) => new Date(val).toLocaleDateString(),
- },
- ]}
- dataset={pageSpeedChecks}
- {...customize}
- grid={{ vertical: true, horizontal: true }}
- tooltip={{ trigger: "none" }}
- slotProps={{
- legend: {
- direction: "row",
- position: { vertical: "bottom", horizontal: "middle" },
- padding: 2,
- itemMarkWidth: 8,
- itemMarkHeight: 8,
- markGap: 5,
- itemGap: 15,
- labelStyle: {
- fontSize: 13,
- color: "#344054"
- }
- },
- }}
- />
- );
-};
-
-PageSpeedLineChart.propTypes = {
- pageSpeedChecks: PropTypes.array,
-};
-
-export default PageSpeedLineChart;
diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx
index 41e529eb9..76e06b408 100644
--- a/Client/src/Pages/Monitors/Details/index.jsx
+++ b/Client/src/Pages/Monitors/Details/index.jsx
@@ -445,14 +445,8 @@ const DetailsPage = ({ isAdmin }) => {
data={[{ response: monitor?.periodAvgResponseTime }]}
/>
-
-
+
+
diff --git a/Client/src/Pages/Monitors/Details/styled.jsx b/Client/src/Pages/Monitors/Details/styled.jsx
index 7f580d7c7..728df4922 100644
--- a/Client/src/Pages/Monitors/Details/styled.jsx
+++ b/Client/src/Pages/Monitors/Details/styled.jsx
@@ -76,7 +76,7 @@ export const StatBox = styled(Box)(({ theme }) => ({
borderColor: theme.palette.border.light,
borderRadius: 4,
backgroundColor: theme.palette.background.main,
- background: `linear-gradient(340deg, ${theme.palette.background.accent} 20%, ${theme.palette.background.main} 35%)`,
+ background: `linear-gradient(340deg, ${theme.palette.background.accent} 20%, ${theme.palette.background.main} 45%)`,
"& h2": {
fontSize: 13,
fontWeight: 500,
diff --git a/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx b/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx
index 6c26c43bd..b040d87a5 100644
--- a/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx
+++ b/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx
@@ -1,3 +1,4 @@
+import PropTypes from "prop-types";
import {
AreaChart,
Area,
@@ -5,6 +6,7 @@ import {
Tooltip,
CartesianGrid,
ResponsiveContainer,
+ Text,
} from "recharts";
import { useTheme } from "@emotion/react";
import { useMemo } from "react";
@@ -12,28 +14,37 @@ import { Box, Stack, Typography } from "@mui/material";
import { formatDate } from "../../../../Utils/timeUtils";
const config = {
- accessibility: {
- id: "accessibility",
- text: "accessibility",
- color: "primary",
- },
- bestPractices: {
- id: "bestPractices",
- text: "best practices",
- color: "warning",
+ seo: {
+ id: "seo",
+ text: "SEO",
+ color: "unresolved",
},
performance: {
id: "performance",
text: "performance",
color: "success",
},
- seo: {
- id: "seo",
- text: "SEO",
- color: "unresolved",
+ bestPractices: {
+ id: "bestPractices",
+ text: "best practices",
+ color: "warning",
+ },
+ accessibility: {
+ id: "accessibility",
+ text: "accessibility",
+ color: "primary",
},
};
+/**
+ * Custom tooltip for the area chart.
+ * @param {Object} props
+ * @param {boolean} props.active - Whether the tooltip is active.
+ * @param {Array} props.payload - The payload data for the tooltip.
+ * @param {string} props.label - The label for the tooltip.
+ * @returns {JSX.Element|null} The tooltip element or null if not active.
+ */
+
const CustomToolTip = ({ active, payload, label }) => {
const theme = useTheme();
@@ -58,50 +69,64 @@ const CustomToolTip = ({ active, payload, label }) => {
>
{formatDate(new Date(label))}
- {Object.keys(config).map((key) => {
- const { color } = config[key];
- const dotColor = theme.palette[color].main;
+ {Object.keys(config)
+ .reverse()
+ .map((key) => {
+ const { color } = config[key];
+ const dotColor = theme.palette[color].main;
- return (
-
-
-
- {config[key].text}
- {" "}
-
- {payload[0].payload[key]}
-
-
- );
- })}
+
+
+ {config[key].text}
+ {" "}
+
+ {payload[0].payload[key]}
+
+
+ );
+ })}
);
}
return null;
};
+CustomToolTip.propTypes = {
+ active: PropTypes.bool,
+ payload: PropTypes.array,
+ label: PropTypes.string,
+};
+
+/**
+ * Processes data to insert gaps with null values based on the interval.
+ * @param {Array} data
+ * @param {number} interval - The interval in milliseconds for gaps.
+ * @returns {Array} The formatted data with gaps.
+ */
const processDataWithGaps = (data, interval) => {
if (data.length === 0) return [];
let formattedData = [];
@@ -137,6 +162,57 @@ const processDataWithGaps = (data, interval) => {
return formattedData;
};
+/**
+ * Custom tick component to render ticks on the XAxis.
+ *
+ * @param {Object} props
+ * @param {number} props.x - The x coordinate for the tick.
+ * @param {number} props.y - The y coordinate for the tick.
+ * @param {Object} props.payload - The data object containing the tick value.
+ * @param {number} props.index - The index of the tick in the array of ticks.
+ *
+ * @returns {JSX.Element|null} The tick element or null if the tick should be hidden.
+ */
+const CustomTick = ({ x, y, payload, index }) => {
+ const theme = useTheme();
+
+ // Render nothing for the first tick
+ if (index === 0) return null;
+
+ return (
+
+ {formatDate(new Date(payload.value), {
+ year: undefined,
+ month: undefined,
+ day: undefined,
+ })}
+
+ );
+};
+CustomTick.propTypes = {
+ x: PropTypes.number,
+ y: PropTypes.number,
+ payload: PropTypes.shape({
+ value: PropTypes.string.isRequired,
+ }),
+ index: PropTypes.number,
+};
+
+/**
+ * A chart displaying pagespeed details over time.
+ * @param {Object} props
+ * @param {Array} props.data - The data to display in the chart.
+ * @param {number} props.interval - The interval in milliseconds for processing gaps.
+ * @returns {JSX.Element} The area chart component.
+ */
+
const PagespeedDetailsAreaChart = ({ data, interval }) => {
const theme = useTheme();
const memoizedData = useMemo(
@@ -162,23 +238,12 @@ const PagespeedDetailsAreaChart = ({ data, interval }) => {
- formatDate(new Date(timestamp), {
- year: undefined,
- month: undefined,
- day: undefined,
- })
- }
- tick={{
- fontSize: 11,
- fontWeight: 100,
- opacity: 0.8,
- stroke: theme.palette.text.tertiary,
- }}
+ tick={}
+ axisLine={false}
tickLine={false}
- minTickGap={20}
height={18}
- interval="preserveEnd"
+ minTickGap={0}
+ interval="equidistantPreserveStart"
/>
{
);
};
+PagespeedDetailsAreaChart.propTypes = {
+ data: PropTypes.arrayOf(
+ PropTypes.shape({
+ createdAt: PropTypes.string.isRequired,
+ accessibility: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
+ .isRequired,
+ bestPractices: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
+ .isRequired,
+ performance: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
+ .isRequired,
+ seo: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+ })
+ ).isRequired,
+ interval: PropTypes.number.isRequired,
+};
+
export default PagespeedDetailsAreaChart;
diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx
index 657ecc36d..07953609a 100644
--- a/Client/src/Pages/PageSpeed/Details/index.jsx
+++ b/Client/src/Pages/PageSpeed/Details/index.jsx
@@ -15,9 +15,9 @@ import { logger } from "../../../Utils/Logger";
import { networkService } from "../../../main";
import SkeletonLayout from "./skeleton";
import SettingsIcon from "../../../assets/icons/settings-bold.svg?react";
+import MetricsIcon from "../../../assets/icons/ruler-icon.svg?react";
import ScoreIcon from "../../../assets/icons/monitor-graph-line.svg?react";
import PerformanceIcon from "../../../assets/icons/performance-report.svg?react";
-import PageSpeedLineChart from "../../../Components/Charts/PagespeedLineChart";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import PulseDot from "../../../Components/Animated/PulseDot";
import PagespeedDetailsAreaChart from "./Charts/AreaChart";
@@ -402,23 +402,44 @@ const PageSpeedDetails = () => {
-
+
Showing statistics for past 24 hours.
+
+
+
+
+
+ Score history
+
+
+
+
+
+
+
+
+
+ Metrics
+
+
+
-
-
-
-
-
- Score history
-
-
-
-
+
@@ -536,16 +557,7 @@ const PageSpeedDetails = () => {
-
+
({
- gap: theme.spacing(8),
+ display: "grid",
height: 300,
minWidth: 250,
- padding: theme.spacing(8),
border: 1,
borderStyle: "solid",
borderColor: theme.palette.border.light,
borderRadius: 4,
+ borderTopRightRadius: 16,
+ borderBottomRightRadius: 16,
backgroundColor: theme.palette.background.main,
"& h2": {
color: theme.palette.text.secondary,
fontSize: 15,
fontWeight: 500,
},
- "& p": {
- color: theme.palette.text.secondary,
+ "& p": { color: theme.palette.text.secondary },
+ "& > :nth-of-type(1)": {
+ gridColumn: 1,
+ gridRow: 1,
+ height: "fit-content",
+ paddingTop: theme.spacing(8),
+ paddingLeft: theme.spacing(8),
+ },
+ "& > :nth-of-type(2)": { gridColumn: 1, gridRow: 2 },
+ "& > :nth-of-type(3)": {
+ gridColumn: 2,
+ gridRow: "span 2",
+ padding: theme.spacing(8),
+ borderLeft: 1,
+ borderLeftStyle: "solid",
+ borderLeftColor: theme.palette.border.light,
+ borderRadius: 16,
+ backgroundColor: theme.palette.background.main,
+ background: `linear-gradient(325deg, ${theme.palette.background.accent} 20%, ${theme.palette.background.main} 45%)`,
},
}));
@@ -52,7 +70,7 @@ export const StatBox = styled(Box)(({ theme }) => ({
borderColor: theme.palette.border.light,
borderRadius: 4,
backgroundColor: theme.palette.background.main,
- background: `linear-gradient(340deg, ${theme.palette.background.accent} 20%, ${theme.palette.background.main} 35%)`,
+ background: `linear-gradient(340deg, ${theme.palette.background.accent} 20%, ${theme.palette.background.main} 45%)`,
"& h2": {
fontSize: 13,
fontWeight: 500,
diff --git a/Client/src/Utils/Theme/darkTheme.js b/Client/src/Utils/Theme/darkTheme.js
index 261f8135f..2d1f80635 100644
--- a/Client/src/Utils/Theme/darkTheme.js
+++ b/Client/src/Utils/Theme/darkTheme.js
@@ -63,7 +63,7 @@ const darkTheme = createTheme({
uptimeGood: "#ffd600",
uptimeExcellent: "#079455",
},
- unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" },
+ unresolved: { main: "#664eff", light: "#3a1bff", bg: "#f2f4f7" },
divider: border.light,
other: {
icon: "#e6e6e6",
diff --git a/Client/src/assets/icons/ruler-icon.svg b/Client/src/assets/icons/ruler-icon.svg
new file mode 100644
index 000000000..7266d2876
--- /dev/null
+++ b/Client/src/assets/icons/ruler-icon.svg
@@ -0,0 +1,3 @@
+