From bf09a9568a94718e8497041dd45816b5b5b68fe7 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Tue, 10 Sep 2024 12:39:19 -0400 Subject: [PATCH 01/17] Revamped stat boxes and header --- Client/src/Pages/Monitors/Details/styled.jsx | 1 + Client/src/Pages/Monitors/utils.jsx | 8 +- Client/src/Pages/PageSpeed/Details/index.css | 7 - Client/src/Pages/PageSpeed/Details/index.jsx | 213 +++++++++--------- Client/src/Pages/PageSpeed/Details/styled.jsx | 29 +++ 5 files changed, 145 insertions(+), 113 deletions(-) create mode 100644 Client/src/Pages/PageSpeed/Details/styled.jsx diff --git a/Client/src/Pages/Monitors/Details/styled.jsx b/Client/src/Pages/Monitors/Details/styled.jsx index 99112802d..7f580d7c7 100644 --- a/Client/src/Pages/Monitors/Details/styled.jsx +++ b/Client/src/Pages/Monitors/Details/styled.jsx @@ -76,6 +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%)`, "& h2": { fontSize: 13, fontWeight: 500, diff --git a/Client/src/Pages/Monitors/utils.jsx b/Client/src/Pages/Monitors/utils.jsx index 0551a65aa..ede5baec1 100644 --- a/Client/src/Pages/Monitors/utils.jsx +++ b/Client/src/Pages/Monitors/utils.jsx @@ -23,22 +23,26 @@ const useUtils = () => { const statusStyles = { up: { backgroundColor: theme.palette.success.bg, + background: `linear-gradient(340deg, ${theme.palette.success.light} -60%, ${theme.palette.success.bg} 35%)`, borderColor: theme.palette.success.light, "& h2": { color: theme.palette.success.main }, }, down: { backgroundColor: theme.palette.error.bg, + background: `linear-gradient(340deg, ${theme.palette.error.light} -60%, ${theme.palette.error.bg} 35%)`, borderColor: theme.palette.error.light, "& h2": { color: theme.palette.error.main }, }, paused: { backgroundColor: theme.palette.warning.light, - borderColor: theme.palette.warning.border, + background: `linear-gradient(340deg, ${theme.palette.warning.dark} -60%, ${theme.palette.warning.light} 35%)`, + borderColor: theme.palette.warning.dark, "& h2": { color: theme.palette.warning.main }, }, pending: { backgroundColor: theme.palette.warning.light, - borderColor: theme.palette.warning.border, + background: `linear-gradient(340deg, ${theme.palette.warning.dark} -60%, ${theme.palette.warning.light} 35%)`, + borderColor: theme.palette.warning.dark, "& h2": { color: theme.palette.warning.main }, }, }; diff --git a/Client/src/Pages/PageSpeed/Details/index.css b/Client/src/Pages/PageSpeed/Details/index.css index 1da62a362..e3279bdf9 100644 --- a/Client/src/Pages/PageSpeed/Details/index.css +++ b/Client/src/Pages/PageSpeed/Details/index.css @@ -1,12 +1,7 @@ -.page-speed-details h1 { - font-size: var(--env-var-font-size-large-plus); -} -.page-speed-details h2, .page-speed-details h6 { font-size: var(--env-var-font-size-large); } .page-speed-details h4, -.page-speed-details p, .page-speed-details p > span { font-size: var(--env-var-font-size-medium); } @@ -17,8 +12,6 @@ .page-speed-details h6 { line-height: 22px; } -.page-speed-details h1, -.page-speed-details h2, .page-speed-details h6 { font-weight: 600; } diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 4004e1715..85af38952 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -1,5 +1,13 @@ import PropTypes from "prop-types"; -import { Box, Button, Skeleton, Stack, Typography } from "@mui/material"; +import { + Box, + Button, + Skeleton, + Stack, + Toolbar, + Tooltip, + Typography, +} from "@mui/material"; import { PieChart } from "@mui/x-charts/PieChart"; import { useDrawingArea } from "@mui/x-charts"; import { useEffect, useState } from "react"; @@ -9,7 +17,9 @@ import { useSelector } from "react-redux"; import { formatDuration, formatDurationRounded, + formatDurationSplit, } from "../../../Utils/timeUtils"; +import { StatBox } from "./styled"; import { logger } from "../../../Utils/Logger"; import { networkService } from "../../../main"; import SettingsIcon from "../../../assets/icons/settings-bold.svg?react"; @@ -21,46 +31,6 @@ import Breadcrumbs from "../../../Components/Breadcrumbs"; import PulseDot from "../../../Components/Animated/PulseDot"; import "./index.css"; -const StatBox = ({ icon, title, value }) => { - const theme = useTheme(); - - return ( - - {icon} - - - {title} - - - {value} - - - - ); -}; - -StatBox.propTypes = { - icon: PropTypes.element, - title: PropTypes.string, - value: PropTypes.node, -}; - /** * Renders a centered label within a pie chart. * @@ -356,8 +326,21 @@ const PageSpeedDetails = () => { borderRadius: theme.shape.borderRadius, backgroundColor: theme.palette.background.main, }; + + console.log(monitor); + + const splitDuration = (duration) => { + const { time, format } = formatDurationSplit(duration); + return ( + <> + {time} + {format} + + ); + }; + return ( - + {loading ? ( ) : ( @@ -369,32 +352,82 @@ const PageSpeedDetails = () => { ]} /> - - {monitor?.url} + {monitor.name} - - Your pagespeed monitor is live. - + + + + + + + {monitor?.url} + + + Checking every {formatDurationRounded(monitor?.interval)}. + + - - } - title="Last checked" - value={ - <> - {formatDuration(monitor?.lastChecked)}{" "} - - ago - - - } - /> - } - title="Checks since" - value={ - <> - {formatDuration(monitor?.uptimeDuration)}{" "} - - ago - - - } - > - } - title="Checks every" - value={formatDurationRounded(monitor?.interval)} - > + + + checks since + + {splitDuration(monitor?.uptimeDuration)} + ago + + + + last check + + {splitDuration(monitor?.lastChecked)} + ago + + Score history diff --git a/Client/src/Pages/PageSpeed/Details/styled.jsx b/Client/src/Pages/PageSpeed/Details/styled.jsx new file mode 100644 index 000000000..cae50839e --- /dev/null +++ b/Client/src/Pages/PageSpeed/Details/styled.jsx @@ -0,0 +1,29 @@ +import { Box, styled } from "@mui/material"; + +export const StatBox = styled(Box)(({ theme }) => ({ + padding: `${theme.spacing(4)} ${theme.spacing(8)}`, + minWidth: 200, + width: 225, + border: 1, + borderStyle: "solid", + 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%)`, + "& h2": { + fontSize: 13, + fontWeight: 500, + color: theme.palette.text.secondary, + textTransform: "uppercase", + }, + "& p": { + fontSize: 18, + color: theme.palette.text.primary, + marginTop: theme.spacing(2), + "& span": { + color: theme.palette.text.tertiary, + marginLeft: theme.spacing(2), + fontSize: 15, + }, + }, +})); From 4ec51ca886133911fcdb0550e28d1f18f784d511 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Tue, 10 Sep 2024 13:20:33 -0400 Subject: [PATCH 02/17] Revamped chart boxes --- Client/src/Pages/PageSpeed/Details/index.css | 16 ----- Client/src/Pages/PageSpeed/Details/index.jsx | 64 ++++++++----------- Client/src/Pages/PageSpeed/Details/styled.jsx | 46 ++++++++++++- .../src/assets/icons/monitor-graph-line.svg | 3 + .../src/assets/icons/performance-report.svg | 3 + 5 files changed, 76 insertions(+), 56 deletions(-) create mode 100644 Client/src/assets/icons/monitor-graph-line.svg create mode 100644 Client/src/assets/icons/performance-report.svg diff --git a/Client/src/Pages/PageSpeed/Details/index.css b/Client/src/Pages/PageSpeed/Details/index.css index e3279bdf9..18b2f1f3a 100644 --- a/Client/src/Pages/PageSpeed/Details/index.css +++ b/Client/src/Pages/PageSpeed/Details/index.css @@ -9,26 +9,10 @@ .page-speed-details h4 > span { font-size: var(--env-var-font-size-small-plus); } -.page-speed-details h6 { - line-height: 22px; -} -.page-speed-details h6 { - font-weight: 600; -} .page-speed-details button.MuiButtonBase-root { height: 34px; } -.page-speed-details .stat-box { - flex: 1; -} -.page-speed-details .stat-box:last-of-type { - flex-shrink: 1; -} -.page-speed-details .stat-box svg { - width: 22px; - height: 22px; -} .page-speed-details .MuiPieArcLabel-root { font-size: var(--env-var-font-size-small-plus); transition: fill 300ms ease; diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 85af38952..6de6d04d6 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -4,7 +4,6 @@ import { Button, Skeleton, Stack, - Toolbar, Tooltip, Typography, } from "@mui/material"; @@ -19,13 +18,12 @@ import { formatDurationRounded, formatDurationSplit, } from "../../../Utils/timeUtils"; -import { StatBox } from "./styled"; +import { ChartBox, IconBox, StatBox } from "./styled"; import { logger } from "../../../Utils/Logger"; import { networkService } from "../../../main"; import SettingsIcon from "../../../assets/icons/settings-bold.svg?react"; -import LastCheckedIcon from "../../../assets/icons/calendar-check.svg?react"; -import ClockIcon from "../../../assets/icons/maintenance.svg?react"; -import IntervalCheckIcon from "../../../assets/icons/interval-check.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"; @@ -302,7 +300,7 @@ const PageSpeedDetails = () => { cx: pieSize.width / 2, }); - performance += Math.round(value); + performance += Math.floor(value); startAngle = endAngle + padding; } }); @@ -320,13 +318,6 @@ const PageSpeedDetails = () => { let loading = Object.keys(monitor).length === 0; const data = monitor?.checks ? [...monitor.checks].reverse() : []; - let sharedStyles = { - border: 1, - borderColor: theme.palette.border.light, - borderRadius: theme.shape.borderRadius, - backgroundColor: theme.palette.background.main, - }; - console.log(monitor); const splitDuration = (duration) => { @@ -465,32 +456,27 @@ const PageSpeedDetails = () => { - - Score history - - - + + + Showing statistics for past 24 hours. + - - Performance report - - + + + + + + Score history + + + + + + + + + Performance report + { })} - + )} diff --git a/Client/src/Pages/PageSpeed/Details/styled.jsx b/Client/src/Pages/PageSpeed/Details/styled.jsx index cae50839e..b067efa22 100644 --- a/Client/src/Pages/PageSpeed/Details/styled.jsx +++ b/Client/src/Pages/PageSpeed/Details/styled.jsx @@ -1,4 +1,48 @@ -import { Box, styled } from "@mui/material"; +import { Box, Stack, styled } from "@mui/material"; + +export const ChartBox = styled(Stack)(({ theme }) => ({ + flex: "1 30%", + gap: theme.spacing(8), + height: 300, + minWidth: 250, + padding: theme.spacing(8), + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.light, + borderRadius: 4, + backgroundColor: theme.palette.background.main, + "& h2": { + color: theme.palette.text.secondary, + fontSize: 15, + fontWeight: 500, + }, + "& p": { + color: theme.palette.text.secondary, + }, +})); + +export const IconBox = styled(Box)(({ theme }) => ({ + height: 34, + minWidth: 34, + width: 34, + position: "relative", + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.dark, + borderRadius: 4, + backgroundColor: theme.palette.background.accent, + "& svg": { + position: "absolute", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + width: 20, + height: 20, + "& path": { + stroke: theme.palette.text.tertiary, + }, + }, +})); export const StatBox = styled(Box)(({ theme }) => ({ padding: `${theme.spacing(4)} ${theme.spacing(8)}`, diff --git a/Client/src/assets/icons/monitor-graph-line.svg b/Client/src/assets/icons/monitor-graph-line.svg new file mode 100644 index 000000000..86049eb9e --- /dev/null +++ b/Client/src/assets/icons/monitor-graph-line.svg @@ -0,0 +1,3 @@ + + + diff --git a/Client/src/assets/icons/performance-report.svg b/Client/src/assets/icons/performance-report.svg new file mode 100644 index 000000000..8b7073ac3 --- /dev/null +++ b/Client/src/assets/icons/performance-report.svg @@ -0,0 +1,3 @@ + + + From 0025141e9dc0d6cce477d1cf787b93f855d43b8f Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Tue, 10 Sep 2024 13:24:01 -0400 Subject: [PATCH 03/17] Moved skeleton to its own file for increased readability --- Client/src/Pages/PageSpeed/Details/index.jsx | 58 +------------------ .../src/Pages/PageSpeed/Details/skeleton.jsx | 43 ++++++++++++++ 2 files changed, 45 insertions(+), 56 deletions(-) create mode 100644 Client/src/Pages/PageSpeed/Details/skeleton.jsx diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 6de6d04d6..40d71dc5e 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -1,12 +1,5 @@ import PropTypes from "prop-types"; -import { - Box, - Button, - Skeleton, - Stack, - Tooltip, - Typography, -} from "@mui/material"; +import { Box, Button, Stack, Tooltip, Typography } from "@mui/material"; import { PieChart } from "@mui/x-charts/PieChart"; import { useDrawingArea } from "@mui/x-charts"; import { useEffect, useState } from "react"; @@ -14,13 +7,13 @@ import { useTheme } from "@emotion/react"; import { useNavigate, useParams } from "react-router-dom"; import { useSelector } from "react-redux"; import { - formatDuration, formatDurationRounded, formatDurationSplit, } from "../../../Utils/timeUtils"; import { ChartBox, IconBox, StatBox } from "./styled"; import { logger } from "../../../Utils/Logger"; import { networkService } from "../../../main"; +import SkeletonLayout from "./skeleton"; import SettingsIcon from "../../../assets/icons/settings-bold.svg?react"; import ScoreIcon from "../../../assets/icons/monitor-graph-line.svg?react"; import PerformanceIcon from "../../../assets/icons/performance-report.svg?react"; @@ -118,53 +111,6 @@ PieValueLabel.propTypes = { highlighted: PropTypes.bool, }; -/** - * Renders a skeleton layout. - * - * @returns {JSX.Element} - */ -const SkeletonLayout = () => { - const theme = useTheme(); - - return ( - <> - - - - - - - - - - - - - - - - - - - - ); -}; - const PageSpeedDetails = () => { const theme = useTheme(); const navigate = useNavigate(); diff --git a/Client/src/Pages/PageSpeed/Details/skeleton.jsx b/Client/src/Pages/PageSpeed/Details/skeleton.jsx new file mode 100644 index 000000000..5f64b1e0d --- /dev/null +++ b/Client/src/Pages/PageSpeed/Details/skeleton.jsx @@ -0,0 +1,43 @@ +import { Box, Skeleton, Stack } from "@mui/material"; + +/** + * Renders a skeleton layout. + * + * @returns {JSX.Element} + */ +const SkeletonLayout = () => { + return ( + <> + + + + + + + + + + + + + + + + + + + + ); +}; + +export default SkeletonLayout; From 34f0a1e067687d9c02967efbfe46c7fab9ec5bea Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Tue, 10 Sep 2024 14:17:59 -0400 Subject: [PATCH 04/17] Implemented basic pagespeed metrics chart --- .../PageSpeed/Details/Charts/AreaChart.jsx | 109 ++++++++++++++++++ Client/src/Pages/PageSpeed/Details/index.jsx | 9 +- Client/src/Pages/PageSpeed/Details/styled.jsx | 1 - 3 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx diff --git a/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx b/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx new file mode 100644 index 000000000..1c5c8df8a --- /dev/null +++ b/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx @@ -0,0 +1,109 @@ +import { + AreaChart, + Area, + XAxis, + Tooltip, + CartesianGrid, + ResponsiveContainer, +} from "recharts"; +import { useTheme } from "@emotion/react"; +import { useMemo } from "react"; + +const config = { + accessibility: { + id: "accessibility", + color: "primary", + }, + bestPractices: { + id: "bestPractices", + color: "warning", + }, + performance: { + id: "performance", + color: "success", + }, + seo: { + id: "seo", + color: "unresolved", + }, +}; + +const PagespeedDetailsAreaChart = ({ data }) => { + const formatDate = (timestamp) => { + const date = new Date(timestamp); + return date.toLocaleTimeString("en-US", { + hour: "numeric", + minute: "2-digit", + hour12: true, + }); + }; + + const memoizedData = useMemo(() => data, [data[0]]); + + const theme = useTheme(); + + return ( + + + + + + + {Object.values(config).map(({ id, color }) => { + const startColor = theme.palette[color].main; + const endColor = theme.palette[color].light; + + return ( + + + + + ); + })} + + {Object.keys(config).map((key) => { + const { color } = config[key]; + const strokeColor = theme.palette[color].main; + const activeDotColor = theme.palette[color].bg; + + return ( + + ); + })} + + + ); +}; + +export default PagespeedDetailsAreaChart; diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 40d71dc5e..5fdc186b2 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -20,6 +20,7 @@ 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"; import "./index.css"; /** @@ -264,7 +265,7 @@ const PageSpeedDetails = () => { let loading = Object.keys(monitor).length === 0; const data = monitor?.checks ? [...monitor.checks].reverse() : []; - console.log(monitor); + console.log(data); const splitDuration = (duration) => { const { time, format } = formatDurationSplit(duration); @@ -407,16 +408,16 @@ const PageSpeedDetails = () => { Showing statistics for past 24 hours. - + Score history - + - + diff --git a/Client/src/Pages/PageSpeed/Details/styled.jsx b/Client/src/Pages/PageSpeed/Details/styled.jsx index b067efa22..a6c829061 100644 --- a/Client/src/Pages/PageSpeed/Details/styled.jsx +++ b/Client/src/Pages/PageSpeed/Details/styled.jsx @@ -1,7 +1,6 @@ import { Box, Stack, styled } from "@mui/material"; export const ChartBox = styled(Stack)(({ theme }) => ({ - flex: "1 30%", gap: theme.spacing(8), height: 300, minWidth: 250, From db3c7e6b525e45b26efc41af04a27598e98e8e5c Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Tue, 10 Sep 2024 17:43:43 -0400 Subject: [PATCH 05/17] Added null entries --- .../PageSpeed/Details/Charts/AreaChart.jsx | 142 ++++++++++++++++-- Client/src/Pages/PageSpeed/Details/index.jsx | 7 +- 2 files changed, 132 insertions(+), 17 deletions(-) diff --git a/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx b/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx index 1c5c8df8a..6c26c43bd 100644 --- a/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx +++ b/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx @@ -8,42 +8,144 @@ import { } from "recharts"; import { useTheme } from "@emotion/react"; import { useMemo } from "react"; +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", }, performance: { id: "performance", + text: "performance", color: "success", }, seo: { id: "seo", + text: "SEO", color: "unresolved", }, }; -const PagespeedDetailsAreaChart = ({ data }) => { - const formatDate = (timestamp) => { - const date = new Date(timestamp); - return date.toLocaleTimeString("en-US", { - hour: "numeric", - minute: "2-digit", - hour12: true, +const CustomToolTip = ({ active, payload, label }) => { + const theme = useTheme(); + + if (active && payload && payload.length) { + return ( + + + {formatDate(new Date(label))} + + {Object.keys(config).map((key) => { + const { color } = config[key]; + const dotColor = theme.palette[color].main; + + return ( + + + + {config[key].text} + {" "} + + {payload[0].payload[key]} + + + ); + })} + + ); + } + return null; +}; + +const processDataWithGaps = (data, interval) => { + if (data.length === 0) return []; + let formattedData = []; + let last = new Date(data[0].createdAt).getTime(); + + // Helper function to add a null entry + const addNullEntry = (timestamp) => { + formattedData.push({ + accessibility: "N/A", + bestPractices: "N/A", + performance: "N/A", + seo: "N/A", + createdAt: timestamp, }); }; - const memoizedData = useMemo(() => data, [data[0]]); + data.forEach((entry) => { + const current = new Date(entry.createdAt).getTime(); + if (current - last > interval * 2) { + // Insert null entries for each interval + let temp = last + interval; + while (temp < current) { + addNullEntry(new Date(temp).toISOString()); + temp += interval; + } + } + + formattedData.push(entry); + last = current; + }); + + return formattedData; +}; + +const PagespeedDetailsAreaChart = ({ data, interval }) => { const theme = useTheme(); + const memoizedData = useMemo( + () => processDataWithGaps(data, interval), + [data] + ); return ( - + { + formatDate(new Date(timestamp), { + year: undefined, + month: undefined, + day: undefined, + }) + } tick={{ - fontSize: 12, + fontSize: 11, fontWeight: 100, opacity: 0.8, stroke: theme.palette.text.tertiary, }} tickLine={false} + minTickGap={20} height={18} + interval="preserveEnd" + /> + } /> - {Object.values(config).map(({ id, color }) => { const startColor = theme.palette[color].main; @@ -87,17 +200,18 @@ const PagespeedDetailsAreaChart = ({ data }) => { {Object.keys(config).map((key) => { const { color } = config[key]; const strokeColor = theme.palette[color].main; - const activeDotColor = theme.palette[color].bg; + const bgColor = theme.palette.background.main; return ( ); })} diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 5fdc186b2..657ecc36d 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -265,8 +265,6 @@ const PageSpeedDetails = () => { let loading = Object.keys(monitor).length === 0; const data = monitor?.checks ? [...monitor.checks].reverse() : []; - console.log(data); - const splitDuration = (duration) => { const { time, format } = formatDurationSplit(duration); return ( @@ -415,7 +413,10 @@ const PageSpeedDetails = () => { Score history - + From 23dc8fed36aeabf5a17be3be8203ec13b9260002 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Wed, 11 Sep 2024 12:46:41 -0400 Subject: [PATCH 06/17] Finalized area chart, added custom tick --- .../Charts/MonitorDetailsAreaChart/index.jsx | 48 ++-- .../Charts/PagespeedLineChart/index.css | 0 .../Charts/PagespeedLineChart/index.jsx | 71 ------ Client/src/Pages/Monitors/Details/index.jsx | 10 +- Client/src/Pages/Monitors/Details/styled.jsx | 2 +- .../PageSpeed/Details/Charts/AreaChart.jsx | 209 ++++++++++++------ Client/src/Pages/PageSpeed/Details/index.jsx | 62 +++--- Client/src/Pages/PageSpeed/Details/styled.jsx | 28 ++- Client/src/Utils/Theme/darkTheme.js | 2 +- Client/src/assets/icons/ruler-icon.svg | 3 + 10 files changed, 245 insertions(+), 190 deletions(-) delete mode 100644 Client/src/Components/Charts/PagespeedLineChart/index.css delete mode 100644 Client/src/Components/Charts/PagespeedLineChart/index.jsx create mode 100644 Client/src/assets/icons/ruler-icon.svg 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 @@ + + + From 16e9b64161d072833e834b96d0a3dd00a54475a7 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Wed, 11 Sep 2024 15:47:46 -0400 Subject: [PATCH 07/17] Implemented score chart filter --- .../PageSpeed/Details/Charts/AreaChart.jsx | 23 ++++--- Client/src/Pages/PageSpeed/Details/index.jsx | 63 ++++++++++++++++++- 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx b/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx index b040d87a5..9523a31d7 100644 --- a/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx +++ b/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx @@ -45,7 +45,7 @@ const config = { * @returns {JSX.Element|null} The tooltip element or null if not active. */ -const CustomToolTip = ({ active, payload, label }) => { +const CustomToolTip = ({ active, payload, label, config }) => { const theme = useTheme(); if (active && payload && payload.length) { @@ -213,13 +213,20 @@ CustomTick.propTypes = { * @returns {JSX.Element} The area chart component. */ -const PagespeedDetailsAreaChart = ({ data, interval }) => { +const PagespeedDetailsAreaChart = ({ data, interval, metrics }) => { const theme = useTheme(); const memoizedData = useMemo( () => processDataWithGaps(data, interval), - [data] + [data[0]] ); + const filteredConfig = Object.keys(config).reduce((result, key) => { + if (metrics[key]) { + result[key] = config[key]; + } + return result; + }, {}); + return ( { /> } + content={} /> - {Object.values(config).map(({ id, color }) => { + {Object.values(filteredConfig).map(({ id, color }) => { const startColor = theme.palette[color].main; const endColor = theme.palette[color].light; @@ -262,8 +269,8 @@ const PagespeedDetailsAreaChart = ({ data, interval }) => { ); })} - {Object.keys(config).map((key) => { - const { color } = config[key]; + {Object.keys(filteredConfig).map((key) => { + const { color } = filteredConfig[key]; const strokeColor = theme.palette[color].main; const bgColor = theme.palette.background.main; @@ -275,7 +282,7 @@ const PagespeedDetailsAreaChart = ({ data, interval }) => { stackId={1} stroke={strokeColor} strokeWidth={1.5} - fill={`url(#${config[key].id})`} + fill={`url(#${filteredConfig[key].id})`} activeDot={{ stroke: bgColor, fill: strokeColor, r: 4.5 }} /> ); diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 07953609a..f87b6dcf8 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -1,5 +1,12 @@ import PropTypes from "prop-types"; -import { Box, Button, Stack, Tooltip, Typography } from "@mui/material"; +import { + Box, + Button, + Divider, + Stack, + Tooltip, + Typography, +} from "@mui/material"; import { PieChart } from "@mui/x-charts/PieChart"; import { useDrawingArea } from "@mui/x-charts"; import { useEffect, useState } from "react"; @@ -22,6 +29,7 @@ import Breadcrumbs from "../../../Components/Breadcrumbs"; import PulseDot from "../../../Components/Animated/PulseDot"; import PagespeedDetailsAreaChart from "./Charts/AreaChart"; import "./index.css"; +import Checkbox from "../../../Components/Inputs/Checkbox"; /** * Renders a centered label within a pie chart. @@ -275,6 +283,16 @@ const PageSpeedDetails = () => { ); }; + const [metrics, setMetrics] = useState({ + accessibility: true, + bestPractices: true, + performance: true, + seo: true, + }); + const handleMetrics = (id) => { + setMetrics((prev) => ({ ...prev, [id]: !prev[id] })); + }; + return ( {loading ? ( @@ -420,6 +438,7 @@ const PageSpeedDetails = () => { @@ -433,6 +452,48 @@ const PageSpeedDetails = () => { Metrics + + + + Shown + + + + handleMetrics("accessibility")} + /> + + handleMetrics("bestPractices")} + /> + + handleMetrics("performance")} + /> + + handleMetrics("seo")} + /> + + From c0c1cf64acf4ac50b98a3fae912ddae76e69064e Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Wed, 11 Sep 2024 17:41:37 -0400 Subject: [PATCH 08/17] Refactored pie chart --- .../PageSpeed/Details/Charts/PieChart.jsx | 298 ++++++++++++++++++ Client/src/Pages/PageSpeed/Details/index.jsx | 250 +++------------ Client/src/Pages/PageSpeed/Details/styled.jsx | 2 +- Client/src/Utils/Theme/lightTheme.js | 2 +- 4 files changed, 338 insertions(+), 214 deletions(-) create mode 100644 Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx diff --git a/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx b/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx new file mode 100644 index 000000000..be3b0cbb8 --- /dev/null +++ b/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx @@ -0,0 +1,298 @@ +import PropTypes from "prop-types"; +import { PieChart as MuiPieChart } from "@mui/x-charts/PieChart"; +import { useDrawingArea } from "@mui/x-charts"; +import { useState } from "react"; +import { useTheme } from "@emotion/react"; +import { Box } from "@mui/material"; + +/** + * Renders a centered label within a pie chart. + * + * @param {Object} props + * @param {string | number} props.value - The value to display in the label. + * @param {string} props.color - The color of the text. + * @returns {JSX.Element} + */ +const PieCenterLabel = ({ value, color, setExpand }) => { + const { width, height } = useDrawingArea(); + return ( + setExpand(true)} + > + + + {value} + + + ); +}; + +PieCenterLabel.propTypes = { + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + color: PropTypes.string, + setExpand: PropTypes.func, +}; + +/** + * A component that renders a label on a pie chart slice. + * The label is positioned relative to the center of the pie chart and is optionally highlighted. + * + * @param {Object} props + * @param {number} props.value - The value to display inside the pie slice. + * @param {number} props.startAngle - The starting angle of the pie slice in degrees. + * @param {number} props.endAngle - The ending angle of the pie slice in degrees. + * @param {string} props.color - The color of the label text when highlighted. + * @param {boolean} props.highlighted - Determines if the label should be highlighted or not. + * @returns {JSX.Element} + */ +const PieValueLabel = ({ value, startAngle, endAngle, color, highlighted }) => { + const { width, height } = useDrawingArea(); + + // Compute the midpoint angle in radians + const angle = (((startAngle + endAngle) / 2) * Math.PI) / 180; + const radius = height / 3.5; // length from center of the circle to where the text is positioned + + // Calculate x and y positions + const x = Math.sin(angle) * radius; + const y = -Math.cos(angle) * radius; + + return ( + + + +{value} + + + ); +}; + +const PieChart = ({ audits }) => { + const theme = useTheme(); + + /** + * Weight constants for different performance metrics. + * @type {Object} + */ + const weights = { + fcp: 10, + si: 10, + lcp: 25, + tbt: 30, + cls: 25, + }; + + /** + * Retrieves color properties based on the performance value. + * + * @param {number} value - The performance score used to determine the color properties. + * @returns {{stroke: string, strokeBg: string, text: string, bg: string}} The color properties for the given performance value. + */ + const getColors = (value) => { + if (value >= 90 && value <= 100) + return { + stroke: theme.palette.success.main, + strokeBg: theme.palette.success.light, + text: theme.palette.success.text, + bg: theme.palette.success.bg, + }; + else if (value >= 50 && value < 90) + return { + stroke: theme.palette.warning.main, + strokeBg: theme.palette.warning.light, + text: theme.palette.warning.text, + bg: theme.palette.warning.bg, + }; + else if (value >= 0 && value < 50) + return { + stroke: theme.palette.error.text, + strokeBg: theme.palette.error.light, + text: theme.palette.error.text, + bg: theme.palette.error.bg, + }; + return { + stroke: theme.palette.unresolved.main, + strokeBg: theme.palette.unresolved.light, + text: theme.palette.unresolved.main, + bg: theme.palette.unresolved.bg, + }; + }; + + /** + * Calculates and formats the data needed for rendering a pie chart based on audit scores and weights. + * This function generates properties for each pie slice, including angles, radii, and colors. + * It also calculates performance based on the weighted values. + * + * @returns {Array} An array of objects, each representing the properties for a slice of the pie chart. + * @returns {number} performance - A variable updated with the rounded sum of weighted values. + */ + let performance = 0; + const getPieData = (audits) => { + let props = []; + let startAngle = 0; + const padding = 3; // padding between arcs + const max = 360 - padding * (Object.keys(audits).length - 1); // _id is a child of audits + + Object.keys(audits).forEach((key) => { + if (audits[key].score) { + let value = audits[key].score * weights[key]; + let endAngle = startAngle + (weights[key] * max) / 100; + + let theme = getColors(audits[key].score * 100); + props.push({ + id: key, + data: [ + { + value: value, + color: theme.stroke, + label: key.toUpperCase(), + }, + { + value: weights[key] - value, + color: theme.strokeBg, + label: "", + }, + ], + arcLabel: (item) => `${item.label}`, + arcLabelRadius: 95, + startAngle: startAngle, + endAngle: endAngle, + innerRadius: 73, + outerRadius: 80, + cornerRadius: 2, + highlightScope: { faded: "global", highlighted: "series" }, + faded: { + innerRadius: 63, + outerRadius: 70, + additionalRadius: -20, + arcLabelRadius: 5, + }, + cx: pieSize.width / 2, + }); + + performance += Math.floor(value); + startAngle = endAngle + padding; + } + }); + + return props; + }; + + const pieSize = { width: 210, height: 200 }; + const pieData = getPieData(audits); + const colorMap = getColors(performance); + + const [highlightedItem, setHighLightedItem] = useState(null); + const [expand, setExpand] = useState(false); + return ( + setExpand(false)}> + {expand ? ( + + + {pieData?.map((pie) => ( + + ))} + + ) : ( + + + + )} + + ); +}; + +export default PieChart; diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index f87b6dcf8..f5ab4c987 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -7,7 +7,6 @@ import { Tooltip, Typography, } from "@mui/material"; -import { PieChart } from "@mui/x-charts/PieChart"; import { useDrawingArea } from "@mui/x-charts"; import { useEffect, useState } from "react"; import { useTheme } from "@emotion/react"; @@ -30,6 +29,7 @@ import PulseDot from "../../../Components/Animated/PulseDot"; import PagespeedDetailsAreaChart from "./Charts/AreaChart"; import "./index.css"; import Checkbox from "../../../Components/Inputs/Checkbox"; +import PieChart from "./Charts/PieChart"; /** * Renders a centered label within a pie chart. @@ -151,125 +151,6 @@ const PageSpeedDetails = () => { fetchMonitor(); }, [monitorId, authToken, navigate]); - /** - * Weight constants for different performance metrics. - * @type {Object} - */ - const weights = { - fcp: 10, - si: 10, - lcp: 25, - tbt: 30, - cls: 25, - }; - - /** - * Retrieves color properties based on the performance value. - * - * @param {number} value - The performance score used to determine the color properties. - * @returns {{stroke: string, text: string, bg: string}} The color properties for the given performance value. - */ - const getColors = (value) => { - if (value >= 90 && value <= 100) - return { - stroke: theme.palette.success.main, - strokeBg: theme.palette.success.light, - text: theme.palette.success.text, - bg: theme.palette.success.bg, - shape: "circle", - }; - else if (value >= 50 && value < 90) - return { - stroke: theme.palette.warning.main, - strokeBg: theme.palette.warning.bg, - text: theme.palette.warning.text, - bg: theme.palette.warning.light, - shape: "square", - }; - else if (value >= 0 && value < 50) - return { - stroke: theme.palette.error.text, - strokeBg: theme.palette.error.light, - text: theme.palette.error.text, - bg: theme.palette.error.bg, - shape: "circle", - }; - return { - stroke: theme.palette.unresolved.main, - strokeBg: theme.palette.unresolved.light, - text: theme.palette.unresolved.main, - bg: theme.palette.unresolved.bg, - shape: "", - }; - }; - - /** - * Calculates and formats the data needed for rendering a pie chart based on audit scores and weights. - * This function generates properties for each pie slice, including angles, radii, and colors. - * It also calculates performance based on the weighted values. - * - * @returns {Array} An array of objects, each representing the properties for a slice of the pie chart. - * @returns {number} performance - A variable updated with the rounded sum of weighted values. - */ - let performance = 0; - const getPieData = (audits) => { - let props = []; - let startAngle = 0; - const padding = 3; // padding between arcs - const max = 360 - padding * (Object.keys(audits).length - 1); // _id is a child of audits - - Object.keys(audits).forEach((key) => { - if (audits[key].score) { - let value = audits[key].score * weights[key]; - let endAngle = startAngle + (weights[key] * max) / 100; - - let theme = getColors(audits[key].score * 100); - props.push({ - id: key, - data: [ - { - value: value, - color: theme.stroke, - label: key.toUpperCase(), - }, - { - value: weights[key] - value, - color: theme.strokeBg, - label: "", - }, - ], - arcLabel: (item) => `${item.label}`, - arcLabelRadius: 95, - startAngle: startAngle, - endAngle: endAngle, - innerRadius: 73, - outerRadius: 80, - cornerRadius: 2, - highlightScope: { faded: "global", highlighted: "series" }, - faded: { - innerRadius: 63, - outerRadius: 70, - additionalRadius: -20, - arcLabelRadius: 5, - }, - cx: pieSize.width / 2, - }); - - performance += Math.floor(value); - startAngle = endAngle + padding; - } - }); - - return props; - }; - - const pieSize = { width: 210, height: 200 }; - const pieData = getPieData(audits); - const colorMap = getColors(performance); - - const [highlightedItem, setHighLightedItem] = useState(null); - const [expand, setExpand] = useState(false); - let loading = Object.keys(monitor).length === 0; const data = monitor?.checks ? [...monitor.checks].reverse() : []; @@ -293,6 +174,38 @@ const PageSpeedDetails = () => { setMetrics((prev) => ({ ...prev, [id]: !prev[id] })); }; + /** + * Retrieves color properties based on the performance value. + * + * @param {number} value - The performance score used to determine the color properties. + * @returns {{stroke: string, text: string, shape: string}} The color properties for the given performance value. + */ + const getColors = (value) => { + if (value >= 90 && value <= 100) + return { + stroke: theme.palette.success.main, + text: theme.palette.success.text, + shape: "circle", + }; + else if (value >= 50 && value < 90) + return { + stroke: theme.palette.warning.main, + text: theme.palette.warning.text, + shape: "square", + }; + else if (value >= 0 && value < 50) + return { + stroke: theme.palette.error.text, + text: theme.palette.error.text, + shape: "circle", + }; + return { + stroke: theme.palette.unresolved.main, + text: theme.palette.unresolved.main, + shape: "", + }; + }; + return ( {loading ? ( @@ -499,7 +412,8 @@ const PageSpeedDetails = () => { @@ -512,98 +426,10 @@ const PageSpeedDetails = () => { textAlign="center" minWidth="300px" flex={1} - px={theme.spacing(20)} - py={theme.spacing(8)} + p={theme.spacing(12)} > - setExpand(false)}> - {expand ? ( - - - {pieData?.map((pie) => ( - - ))} - - ) : ( - - - - )} - - + + Values are estimated and may vary.{" "} ({ fontSize: 15, fontWeight: 500, }, - "& p": { color: theme.palette.text.secondary }, + "& p": { color: theme.palette.text.tertiary }, "& > :nth-of-type(1)": { gridColumn: 1, gridRow: 1, diff --git a/Client/src/Utils/Theme/lightTheme.js b/Client/src/Utils/Theme/lightTheme.js index f00ece091..92e7f7817 100644 --- a/Client/src/Utils/Theme/lightTheme.js +++ b/Client/src/Utils/Theme/lightTheme.js @@ -51,7 +51,7 @@ const lightTheme = createTheme({ text: "#DC6803", main: "#fdb022", light: "#ffecbc", - bg: "#fffcf5", + bg: "#fef8ea", border: "#fec84b", }, percentage: { From 06e1c35e770d4b79b5b14155fa067106f92ad133 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Thu, 12 Sep 2024 20:08:04 -0400 Subject: [PATCH 09/17] Revamped performance section and removed redundant code --- Client/src/Pages/PageSpeed/Details/index.css | 16 -- Client/src/Pages/PageSpeed/Details/index.jsx | 256 ++++--------------- Client/src/assets/icons/spedometer-icon.svg | 3 + 3 files changed, 49 insertions(+), 226 deletions(-) create mode 100644 Client/src/assets/icons/spedometer-icon.svg diff --git a/Client/src/Pages/PageSpeed/Details/index.css b/Client/src/Pages/PageSpeed/Details/index.css index 18b2f1f3a..2bd9bda44 100644 --- a/Client/src/Pages/PageSpeed/Details/index.css +++ b/Client/src/Pages/PageSpeed/Details/index.css @@ -1,14 +1,3 @@ -.page-speed-details h6 { - font-size: var(--env-var-font-size-large); -} -.page-speed-details h4, -.page-speed-details p > span { - font-size: var(--env-var-font-size-medium); -} -.page-speed-details h1 + span, -.page-speed-details h4 > span { - font-size: var(--env-var-font-size-small-plus); -} .page-speed-details button.MuiButtonBase-root { height: 34px; } @@ -27,8 +16,3 @@ .page-speed-details .MuiPieArc-root { stroke: inherit; } - -.page-speed-details .metric { - min-width: 200px; - flex: 1; -} diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index f5ab4c987..042347c67 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -21,104 +21,16 @@ import { logger } from "../../../Utils/Logger"; import { networkService } from "../../../main"; import SkeletonLayout from "./skeleton"; import SettingsIcon from "../../../assets/icons/settings-bold.svg?react"; +import SpedometerIcon from "../../../assets/icons/spedometer-icon.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 Breadcrumbs from "../../../Components/Breadcrumbs"; import PulseDot from "../../../Components/Animated/PulseDot"; import PagespeedDetailsAreaChart from "./Charts/AreaChart"; -import "./index.css"; import Checkbox from "../../../Components/Inputs/Checkbox"; import PieChart from "./Charts/PieChart"; - -/** - * Renders a centered label within a pie chart. - * - * @param {Object} props - * @param {string | number} props.value - The value to display in the label. - * @param {string} props.color - The color of the text. - * @returns {JSX.Element} - */ -const PieCenterLabel = ({ value, color, setExpand }) => { - const { width, height } = useDrawingArea(); - return ( - setExpand(true)} - > - - - {value} - - - ); -}; - -PieCenterLabel.propTypes = { - value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - color: PropTypes.string, - setExpand: PropTypes.func, -}; - -/** - * A component that renders a label on a pie chart slice. - * The label is positioned relative to the center of the pie chart and is optionally highlighted. - * - * @param {Object} props - * @param {number} props.value - The value to display inside the pie slice. - * @param {number} props.startAngle - The starting angle of the pie slice in degrees. - * @param {number} props.endAngle - The ending angle of the pie slice in degrees. - * @param {string} props.color - The color of the label text when highlighted. - * @param {boolean} props.highlighted - Determines if the label should be highlighted or not. - * @returns {JSX.Element} - */ -const PieValueLabel = ({ value, startAngle, endAngle, color, highlighted }) => { - const { width, height } = useDrawingArea(); - - // Compute the midpoint angle in radians - const angle = (((startAngle + endAngle) / 2) * Math.PI) / 180; - const radius = height / 3.5; // length from center of the circle to where the text is positioned - - // Calculate x and y positions - const x = Math.sin(angle) * radius; - const y = -Math.cos(angle) * radius; - - return ( - - - +{value} - - - ); -}; - -PieValueLabel.propTypes = { - value: PropTypes.number, - startAngle: PropTypes.number, - endAngle: PropTypes.number, - color: PropTypes.string, - highlighted: PropTypes.bool, -}; +import "./index.css"; const PageSpeedDetails = () => { const theme = useTheme(); @@ -174,38 +86,6 @@ const PageSpeedDetails = () => { setMetrics((prev) => ({ ...prev, [id]: !prev[id] })); }; - /** - * Retrieves color properties based on the performance value. - * - * @param {number} value - The performance score used to determine the color properties. - * @returns {{stroke: string, text: string, shape: string}} The color properties for the given performance value. - */ - const getColors = (value) => { - if (value >= 90 && value <= 100) - return { - stroke: theme.palette.success.main, - text: theme.palette.success.text, - shape: "circle", - }; - else if (value >= 50 && value < 90) - return { - stroke: theme.palette.warning.main, - text: theme.palette.warning.text, - shape: "square", - }; - else if (value >= 0 && value < 50) - return { - stroke: theme.palette.error.text, - text: theme.palette.error.text, - shape: "circle", - }; - return { - stroke: theme.palette.unresolved.main, - text: theme.palette.unresolved.main, - shape: "", - }; - }; - return ( {loading ? ( @@ -412,8 +292,7 @@ const PageSpeedDetails = () => { @@ -433,11 +312,17 @@ const PageSpeedDetails = () => { Values are estimated and may vary.{" "} See calculator @@ -445,84 +330,30 @@ const PageSpeedDetails = () => { - - The{" "} - - performance score is calculated - {" "} - directly from these{" "} - - metrics - - . - + + + + + Performance Metrics + {Object.keys(audits).map((key) => { if (key === "_id") return; let audit = audits[key]; - let metricParams = getColors(audit.score * 100); - - let shape = ( - - ); - if (metricParams.shape === "square") - shape = ( - - ); - else if (metricParams.shape === "triangle") - shape = ( - - ); + let score = audit.score * 100; + let bg = + score >= 90 + ? theme.palette.success.main + : score >= 50 + ? theme.palette.warning.main + : score >= 0 + ? theme.palette.error.text + : theme.palette.unresolved.main; // Find the position where the number ends and the unit begins const match = audit.displayValue.match( @@ -532,44 +363,49 @@ const PageSpeedDetails = () => { let unit; if (match) { value = match[1]; - unit = match[2]; + match[2] === "s" ? (unit = "seconds") : (unit = match[2]); } else { value = audit.displayValue; } return ( - {shape} - + {audit.title} {value} {unit} + ); })} diff --git a/Client/src/assets/icons/spedometer-icon.svg b/Client/src/assets/icons/spedometer-icon.svg new file mode 100644 index 000000000..19b13f44e --- /dev/null +++ b/Client/src/assets/icons/spedometer-icon.svg @@ -0,0 +1,3 @@ + + + From 146a6463651a487c676764a7c4cc6c9e298b190f Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Thu, 12 Sep 2024 20:38:59 -0400 Subject: [PATCH 10/17] Enlarged pie chart --- .../PageSpeed/Details/Charts/PieChart.jsx | 29 ++++++++++++------- Client/src/Pages/PageSpeed/Details/index.jsx | 3 +- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx b/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx index be3b0cbb8..ff9fa3df2 100644 --- a/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx +++ b/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx @@ -20,12 +20,18 @@ const PieCenterLabel = ({ value, color, setExpand }) => { transform={`translate(${width / 2}, ${height / 2})`} onMouseEnter={() => setExpand(true)} > - + { // Compute the midpoint angle in radians const angle = (((startAngle + endAngle) / 2) * Math.PI) / 180; - const radius = height / 3.5; // length from center of the circle to where the text is positioned + const radius = height / 4; // length from center of the circle to where the text is positioned // Calculate x and y positions const x = Math.sin(angle) * radius; @@ -74,10 +80,11 @@ const PieValueLabel = ({ value, startAngle, endAngle, color, highlighted }) => { y={y} style={{ fill: highlighted ? color : "rgba(0,0,0,0)", - fontSize: "12px", + fontSize: 12, textAnchor: "middle", dominantBaseline: "central", userSelect: "none", + pointerEvents: "none", }} > +{value} @@ -181,8 +188,8 @@ const PieChart = ({ audits }) => { cornerRadius: 2, highlightScope: { faded: "global", highlighted: "series" }, faded: { - innerRadius: 63, - outerRadius: 70, + innerRadius: 73, + outerRadius: 80, additionalRadius: -20, arcLabelRadius: 5, }, @@ -197,7 +204,7 @@ const PieChart = ({ audits }) => { return props; }; - const pieSize = { width: 210, height: 200 }; + const pieSize = { width: 230, height: 230 }; const pieData = getPieData(audits); const colorMap = getColors(performance); @@ -215,7 +222,7 @@ const PieChart = ({ audits }) => { color: colorMap.bg, }, ], - outerRadius: 67, + outerRadius: 77, cx: pieSize.width / 2, }, ...pieData, @@ -260,7 +267,7 @@ const PieChart = ({ audits }) => { color: colorMap.bg, }, ], - outerRadius: 67, + outerRadius: 77, cx: pieSize.width / 2, }, { @@ -270,8 +277,8 @@ const PieChart = ({ audits }) => { color: colorMap.stroke, }, ], - innerRadius: 63, - outerRadius: 70, + innerRadius: 73, + outerRadius: 80, paddingAngle: 5, cornerRadius: 2, startAngle: 0, diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 042347c67..372fbb720 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -305,7 +305,8 @@ const PageSpeedDetails = () => { textAlign="center" minWidth="300px" flex={1} - p={theme.spacing(12)} + pt={theme.spacing(6)} + pb={theme.spacing(12)} > From 5c3f7162430ee89c6f6777d8e39fcf8106057a5b Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Thu, 12 Sep 2024 20:51:00 -0400 Subject: [PATCH 11/17] Increased pointer event range --- Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx b/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx index ff9fa3df2..70aa441fd 100644 --- a/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx +++ b/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx @@ -20,13 +20,7 @@ const PieCenterLabel = ({ value, color, setExpand }) => { transform={`translate(${width / 2}, ${height / 2})`} onMouseEnter={() => setExpand(true)} > - + Date: Fri, 13 Sep 2024 11:26:37 -0400 Subject: [PATCH 12/17] Light UI style updates --- Client/src/Pages/Incidents/IncidentTable/index.jsx | 1 + Client/src/Pages/Incidents/index.jsx | 2 +- Client/src/Pages/Monitors/Details/index.jsx | 5 +++++ Client/src/Pages/Monitors/Home/MonitorTable/index.jsx | 2 -- Client/src/Pages/PageSpeed/Details/index.jsx | 6 +++--- Client/src/assets/icons/certificate.svg | 4 ++-- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Client/src/Pages/Incidents/IncidentTable/index.jsx b/Client/src/Pages/Incidents/IncidentTable/index.jsx index d10c79c68..61bd60f87 100644 --- a/Client/src/Pages/Incidents/IncidentTable/index.jsx +++ b/Client/src/Pages/Incidents/IncidentTable/index.jsx @@ -109,6 +109,7 @@ const IncidentTable = ({ monitors, selectedMonitor, filter }) => { {...item} /> )} + sx={{ mt: "auto" }} /> ); } diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index 1fd91c10a..c86cac543 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -54,7 +54,7 @@ const Incidents = () => { }; return ( - + {loading ? ( ) : ( diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx index 76e06b408..ebf72744a 100644 --- a/Client/src/Pages/Monitors/Details/index.jsx +++ b/Client/src/Pages/Monitors/Details/index.jsx @@ -217,6 +217,11 @@ const DetailsPage = ({ isAdmin }) => { onClick={openCertificate} sx={{ cursor: "pointer", + "& svg": { + width: 23, + height: 23, + top: "52%", + }, }} > diff --git a/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx b/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx index f055a57a1..47c080284 100644 --- a/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx +++ b/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx @@ -223,8 +223,6 @@ const MonitorTable = ({ isAdmin }) => { status: determineState(monitor), }; - console.log(params); - return ( { {Object.keys(audits).map((key) => { if (key === "_id") return; @@ -374,7 +374,7 @@ const PageSpeedDetails = () => { key={`${key}-box`} justifyContent="space-between" direction="row" - gap={theme.spacing(3)} + gap={theme.spacing(4)} p={theme.spacing(3)} border={1} borderColor={theme.palette.border.light} diff --git a/Client/src/assets/icons/certificate.svg b/Client/src/assets/icons/certificate.svg index a985bef9f..2bc6c7e74 100644 --- a/Client/src/assets/icons/certificate.svg +++ b/Client/src/assets/icons/certificate.svg @@ -1,3 +1,3 @@ - - + + \ No newline at end of file From b068776ce704f4a63cb827f2e19e006736bbf071 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Fri, 13 Sep 2024 11:40:03 -0400 Subject: [PATCH 13/17] Removed line causing an error --- Client/src/Pages/PageSpeed/Details/index.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 2118f4197..06f59698e 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -38,7 +38,6 @@ const PageSpeedDetails = () => { const [audits, setAudits] = useState({}); const { monitorId } = useParams(); const { authToken } = useSelector((state) => state.auth); - const { determineState, statusColor, pagespeedStatusMsg } = useUtils(); useEffect(() => { const fetchMonitor = async () => { From 1e480a10e090a8af3de1d39c52c2bea904b72c0b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Sep 2024 10:57:46 +0800 Subject: [PATCH 14/17] Update proptypes, use date function --- .../Components/Charts/MonitorDetailsAreaChart/index.jsx | 9 +++------ Client/src/Pages/Monitors/Details/Charts/index.jsx | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx index 595836f65..ed3d724e8 100644 --- a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx +++ b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx @@ -85,9 +85,10 @@ const CustomToolTip = ({ active, payload, label }) => { const CustomTick = ({ x, y, payload, index }) => { const theme = useTheme(); + const uiTimezone = useSelector((state) => state.ui.timezone); + // Render nothing for the first tick if (index === 0) return null; - return ( { fontSize={11} fontWeight={400} > - {formatDate(new Date(payload.value), { - year: undefined, - month: undefined, - day: undefined, - })} + {formatDateWithTz(payload?.value, "HH:mm:ss", uiTimezone)} ); }; diff --git a/Client/src/Pages/Monitors/Details/Charts/index.jsx b/Client/src/Pages/Monitors/Details/Charts/index.jsx index b70712340..d38335800 100644 --- a/Client/src/Pages/Monitors/Details/Charts/index.jsx +++ b/Client/src/Pages/Monitors/Details/Charts/index.jsx @@ -42,8 +42,8 @@ const CustomLabels = ({ CustomLabels.propTypes = { x: PropTypes.number.isRequired, - width: PropTypes.number.isRequired, - height: PropTypes.number.isRequired, + width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), firstDataPoint: PropTypes.object.isRequired, lastDataPoint: PropTypes.object.isRequired, type: PropTypes.string.isRequired, From d942e3144f3d492c04073d7e05af123531ea8717 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Sep 2024 11:20:28 +0800 Subject: [PATCH 15/17] Add proptypes --- Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx b/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx index 9523a31d7..fea80f5c4 100644 --- a/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx +++ b/Client/src/Pages/PageSpeed/Details/Charts/AreaChart.jsx @@ -47,7 +47,7 @@ const config = { const CustomToolTip = ({ active, payload, label, config }) => { const theme = useTheme(); - + console.log(payload); if (active && payload && payload.length) { return ( Date: Sat, 14 Sep 2024 11:23:38 +0800 Subject: [PATCH 16/17] Add proptypes to monitor details area chart" --- .../Components/Charts/MonitorDetailsAreaChart/index.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx index ed3d724e8..2ecb2f6a8 100644 --- a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx +++ b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx @@ -11,7 +11,6 @@ import { import { Box, Stack, Typography } from "@mui/material"; import { useTheme } from "@emotion/react"; import { useMemo } from "react"; -import { formatDate } from "../../../Utils/timeUtils"; import "./index.css"; import { useSelector } from "react-redux"; import { formatDateWithTz } from "../../../Utils/timeUtils"; @@ -103,6 +102,13 @@ const CustomTick = ({ x, y, payload, index }) => { ); }; +CustomTick.propTypes = { + x: PropTypes.number, + y: PropTypes.number, + payload: PropTypes.object, + index: PropTypes.number, +}; + const MonitorDetailsAreaChart = ({ checks }) => { const theme = useTheme(); const memoizedChecks = useMemo(() => checks, [checks[0]]); From 4b0ac5822a1bafc1230f24d1373abd721b48c20c Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 14 Sep 2024 11:29:14 +0800 Subject: [PATCH 17/17] Rename reserved keyword prop to data --- .../PageSpeed/Details/Charts/PieChart.jsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx b/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx index 70aa441fd..37556f178 100644 --- a/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx +++ b/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx @@ -87,6 +87,15 @@ const PieValueLabel = ({ value, startAngle, endAngle, color, highlighted }) => { ); }; +// Validate props using PropTypes +PieValueLabel.propTypes = { + value: PropTypes.number.isRequired, + startAngle: PropTypes.number.isRequired, + endAngle: PropTypes.number.isRequired, + color: PropTypes.string.isRequired, + highlighted: PropTypes.bool.isRequired, +}; + const PieChart = ({ audits }) => { const theme = useTheme(); @@ -148,7 +157,7 @@ const PieChart = ({ audits }) => { */ let performance = 0; const getPieData = (audits) => { - let props = []; + let data = []; let startAngle = 0; const padding = 3; // padding between arcs const max = 360 - padding * (Object.keys(audits).length - 1); // _id is a child of audits @@ -159,7 +168,7 @@ const PieChart = ({ audits }) => { let endAngle = startAngle + (weights[key] * max) / 100; let theme = getColors(audits[key].score * 100); - props.push({ + data.push({ id: key, data: [ { @@ -195,7 +204,7 @@ const PieChart = ({ audits }) => { } }); - return props; + return data; }; const pieSize = { width: 230, height: 230 }; @@ -296,4 +305,8 @@ const PieChart = ({ audits }) => { ); }; +PieChart.propTypes = { + audits: PropTypes.object, +}; + export default PieChart;