-
Notifications
You must be signed in to change notification settings - Fork 209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat/fe/infrastructure details, resolves #1068 #1167
Merged
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
93d96b9
Add infrastrucutre/details route
ajhollid 0832320
Create stat boxes
ajhollid fbdd3c1
Add custom gauge component
ajhollid d2f42f4
Add styles for custom gauage
ajhollid ca9ca4f
Add gauges
ajhollid 55e13d7
Add area chart file
ajhollid 49d81cf
Add area chart
ajhollid 92ba0d8
Add data for area chart
ajhollid 924c799
add and update chartUtils
ajhollid 6a0d61b
Update Area Chart docs and proptype
ajhollid a0c7346
Add area charts, fix dummy data
ajhollid e3c13d9
Fix label proptype to allow for dates and numbers, add comments
ajhollid 9cf2be7
Add a randomly generated gradientID to so each chart has a unique gra…
ajhollid 0c194a0
Change AreaChart responsive container height to 80%
ajhollid 7f380ce
Add headers to charts, add multpilier for percentages, increase chart…
ajhollid 5a2c6a9
Add jsdocs and proptypes to Infrastructure Details Page
ajhollid 9e7e13b
truncate Gauge percentage to 2 decimal places
ajhollid 217ae50
Fetch data from gist
ajhollid 7223ca3
Add temporary dummy data route
ajhollid dbe174d
remove dummy from Area Chart
ajhollid 8b73955
truncate decimals in tool top
ajhollid b1449d3
refactor details page to use reduce code duplication, caluclate area …
ajhollid 9bbcaaf
memoize calculations in SVG gauge
ajhollid 1f5b5dd
details -> Details
ajhollid 8bbb001
Add monitor information at top of page
ajhollid 11cc283
extract tooltip percentage formatting
ajhollid File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import { | ||
AreaChart, | ||
Area, | ||
XAxis, | ||
YAxis, | ||
CartesianGrid, | ||
Tooltip, | ||
ResponsiveContainer, | ||
} from "recharts"; | ||
import { createGradient } from "../Utils/gradientUtils"; | ||
import PropTypes from "prop-types"; | ||
import { useTheme } from "@mui/material"; | ||
import { useId } from "react"; | ||
/** | ||
* CustomAreaChart component for rendering an area chart with optional gradient and custom ticks. | ||
* | ||
* @param {Object} props - The properties object. | ||
* @param {Array} props.data - The data array for the chart. | ||
* @param {string} props.xKey - The key for the x-axis data. | ||
* @param {string} props.yKey - The key for the y-axis data. | ||
* @param {Object} [props.xTick] - Custom tick component for the x-axis. | ||
* @param {Object} [props.yTick] - Custom tick component for the y-axis. | ||
* @param {string} [props.strokeColor] - The stroke color for the area. | ||
* @param {string} [props.fillColor] - The fill color for the area. | ||
* @param {boolean} [props.gradient=false] - Whether to apply a gradient fill. | ||
* @param {string} [props.gradientDirection="vertical"] - The direction of the gradient. | ||
* @param {string} [props.gradientStartColor] - The start color of the gradient. | ||
* @param {string} [props.gradientEndColor] - The end color of the gradient. | ||
* @param {Object} [props.customTooltip] - Custom tooltip component. | ||
* @returns {JSX.Element} The rendered area chart component. | ||
* | ||
* @example | ||
* // Example usage of CustomAreaChart | ||
* import React from 'react'; | ||
* import CustomAreaChart from './CustomAreaChart'; | ||
* import { TzTick, PercentTick, InfrastructureTooltip } from './chartUtils'; | ||
* | ||
* const data = [ | ||
* { createdAt: '2023-01-01T00:00:00Z', cpu: { usage_percent: 0.5 } }, | ||
* { createdAt: '2023-01-01T01:00:00Z', cpu: { usage_percent: 0.6 } }, | ||
* // more data points... | ||
* ]; | ||
* | ||
* const MyChartComponent = () => { | ||
* return ( | ||
* <CustomAreaChart | ||
* data={data} | ||
* xKey="createdAt" | ||
* yKey="cpu.usage_percent" | ||
* xTick={<TzTick />} | ||
* yTick={<PercentTick />} | ||
* strokeColor="#8884d8" | ||
* fillColor="#8884d8" | ||
* gradient={true} | ||
* gradientStartColor="#8884d8" | ||
* gradientEndColor="#82ca9d" | ||
* customTooltip={({ active, payload, label }) => ( | ||
* <InfrastructureTooltip | ||
* label={label?.toString() ?? ""} | ||
* yKey="cpu.usage_percent" | ||
* yLabel="CPU Usage" | ||
* active={active} | ||
* payload={payload} | ||
* /> | ||
* )} | ||
* /> | ||
* ); | ||
* }; | ||
* | ||
* export default MyChartComponent; | ||
*/ | ||
const CustomAreaChart = ({ | ||
data, | ||
dataKey, | ||
xKey, | ||
yKey, | ||
xTick, | ||
yTick, | ||
strokeColor, | ||
fillColor, | ||
gradient = false, | ||
gradientDirection = "vertical", | ||
gradientStartColor, | ||
gradientEndColor, | ||
customTooltip, | ||
height = "100%", | ||
}) => { | ||
const theme = useTheme(); | ||
const uniqueId = useId(); | ||
const gradientId = `gradient-${uniqueId}`; | ||
return ( | ||
<ResponsiveContainer | ||
width="100%" | ||
height={height} | ||
// FE team HELP! Why does this overflow if set to 100%? | ||
> | ||
<AreaChart data={data}> | ||
<XAxis | ||
dataKey={xKey} | ||
{...(xTick && { tick: xTick })} | ||
/> | ||
<YAxis | ||
dataKey={yKey} | ||
{...(yTick && { tick: yTick })} | ||
/> | ||
{gradient === true && | ||
createGradient({ | ||
id: gradientId, | ||
startColor: gradientStartColor, | ||
endColor: gradientEndColor, | ||
direction: gradientDirection, | ||
})} | ||
<CartesianGrid | ||
stroke={theme.palette.border.light} | ||
strokeWidth={1} | ||
strokeOpacity={1} | ||
fill="transparent" | ||
vertical={false} | ||
/> | ||
<Area | ||
type="monotone" | ||
dataKey={dataKey} | ||
stroke={strokeColor} | ||
fill={gradient === true ? `url(#${gradientId})` : fillColor} | ||
/> | ||
{customTooltip ? ( | ||
<Tooltip | ||
cursor={{ stroke: theme.palette.border.light }} | ||
content={customTooltip} | ||
wrapperStyle={{ pointerEvents: "none" }} | ||
/> | ||
) : ( | ||
<Tooltip /> | ||
)} | ||
</AreaChart> | ||
</ResponsiveContainer> | ||
); | ||
}; | ||
|
||
CustomAreaChart.propTypes = { | ||
data: PropTypes.array.isRequired, | ||
dataKey: PropTypes.string.isRequired, | ||
xTick: PropTypes.object, // Recharts takes an instance of component, so we can't pass the component itself | ||
yTick: PropTypes.object, // Recharts takes an instance of component, so we can't pass the component itself | ||
xKey: PropTypes.string.isRequired, | ||
yKey: PropTypes.string.isRequired, | ||
fillColor: PropTypes.string, | ||
strokeColor: PropTypes.string, | ||
gradient: PropTypes.bool, | ||
gradientDirection: PropTypes.string, | ||
gradientStartColor: PropTypes.string, | ||
gradientEndColor: PropTypes.string, | ||
customTooltip: PropTypes.func, | ||
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | ||
}; | ||
|
||
export default CustomAreaChart; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
.radial-chart { | ||
position: relative; | ||
display: inline-block; | ||
} | ||
|
||
.radial-chart-base { | ||
opacity: 0.3; | ||
} | ||
|
||
.radial-chart-progress { | ||
transform: rotate(-90deg); | ||
transform-origin: center; | ||
transition: stroke-dashoffset 1.5s ease-in-out; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { useTheme } from "@emotion/react"; | ||
import { useEffect, useState, useMemo } from "react"; | ||
import { Box, Typography } from "@mui/material"; | ||
import PropTypes from "prop-types"; | ||
import "./index.css"; | ||
|
||
/** | ||
* A Performant SVG based circular gauge | ||
* | ||
* @component | ||
* @param {Object} props - Component properties | ||
* @param {number} [props.progress=0] - Progress percentage (0-100) | ||
* @param {number} [props.radius=60] - Radius of the gauge circle | ||
* @param {string} [props.color="#000000"] - Color of the progress stroke | ||
* @param {number} [props.strokeWidth=15] - Width of the gauge stroke | ||
* | ||
* @example | ||
* <CustomGauge | ||
* progress={75} | ||
* radius={50} | ||
* color="#00ff00" | ||
* strokeWidth={10} | ||
* /> | ||
* | ||
* @returns {React.ReactElement} Rendered CustomGauge component | ||
*/ | ||
const CustomGauge = ({ | ||
progress = 0, | ||
radius = 60, | ||
color = "#000000", | ||
strokeWidth = 15, | ||
}) => { | ||
// Calculate the length of the stroke for the circle | ||
const { circumference, totalSize, strokeLength } = useMemo( | ||
() => ({ | ||
circumference: 2 * Math.PI * radius, | ||
totalSize: radius * 2 + strokeWidth * 2, | ||
strokeLength: (progress / 100) * (2 * Math.PI * radius), | ||
}), | ||
[radius, strokeWidth, progress] | ||
); | ||
const [offset, setOffset] = useState(circumference); | ||
const theme = useTheme(); | ||
|
||
// Handle initial animation | ||
useEffect(() => { | ||
setOffset(circumference); | ||
const timer = setTimeout(() => { | ||
setOffset(circumference - strokeLength); | ||
}, 100); | ||
|
||
return () => clearTimeout(timer); | ||
}, [progress, circumference, strokeLength]); | ||
|
||
return ( | ||
<Box | ||
className="radial-chart" | ||
width={radius} | ||
height={radius} | ||
> | ||
<svg | ||
viewBox={`0 0 ${totalSize} ${totalSize}`} | ||
width={radius} | ||
height={radius} | ||
> | ||
<circle | ||
className="radial-chart-base" | ||
stroke={theme.palette.background.fill} | ||
strokeWidth={strokeWidth} | ||
fill="none" | ||
cx={totalSize / 2} // Center the circle | ||
cy={totalSize / 2} // Center the circle | ||
r={radius} | ||
/> | ||
<circle | ||
className="radial-chart-progress" | ||
stroke={color} | ||
strokeWidth={strokeWidth} | ||
strokeDasharray={`${circumference} ${circumference}`} | ||
strokeDashoffset={offset} | ||
strokeLinecap="round" | ||
fill="none" | ||
cx={totalSize / 2} | ||
cy={totalSize / 2} | ||
r={radius} | ||
/> | ||
</svg> | ||
|
||
<Typography | ||
className="radial-chart-text" | ||
style={{ | ||
position: "absolute", | ||
top: "50%", | ||
left: "50%", | ||
transform: "translate(-50%, -50%)", | ||
...theme.typography.body2, | ||
fill: theme.typography.body2.color, | ||
}} | ||
> | ||
{`${progress.toFixed(2)}%`} | ||
</Typography> | ||
</Box> | ||
); | ||
}; | ||
|
||
export default CustomGauge; | ||
|
||
CustomGauge.propTypes = { | ||
progress: PropTypes.number, | ||
radius: PropTypes.number, | ||
color: PropTypes.string, | ||
strokeWidth: PropTypes.number, | ||
}; | ||
Comment on lines
+108
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Yo, let's lock down these PropTypes! Make these PropTypes more strict to catch bugs early in development. CustomGauge.propTypes = {
- progress: PropTypes.number,
- radius: PropTypes.number,
- color: PropTypes.string,
- strokeWidth: PropTypes.number,
+ progress: PropTypes.number.isRequired,
+ radius: PropTypes.number,
+ color: PropTypes.string,
+ strokeWidth: PropTypes.oneOf([PropTypes.number, PropTypes.string]),
};
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Let's make this accessible, fam!
The SVG needs ARIA attributes and a title for screen readers.
📝 Committable suggestion