- Update Falback component to accept ovelStart and enlarge the maxWidth to fit into one line

- Add empty page when there is no infrastructure monitors
This commit is contained in:
Shemy Gan
2024-12-02 10:08:41 -05:00
parent 8e831bdb65
commit 0e8bccfea1
3 changed files with 261 additions and 150 deletions

View File

@@ -20,7 +20,7 @@ import "./index.css";
* @returns {JSX.Element} The rendered fallback UI.
*/
const Fallback = ({ title, checks, link = "/", isAdmin }) => {
const Fallback = ({ title, checks, link = "/", isAdmin, ovalStart }) => {
const theme = useTheme();
const navigate = useNavigate();
const mode = useSelector((state) => state.ui.mode);
@@ -48,7 +48,7 @@ const Fallback = ({ title, checks, link = "/", isAdmin }) => {
</Box>
<Stack
gap={theme.spacing(4)}
maxWidth={"275px"}
maxWidth={"300px"}
zIndex={1}
>
<Typography
@@ -56,7 +56,7 @@ const Fallback = ({ title, checks, link = "/", isAdmin }) => {
marginY={theme.spacing(4)}
color={theme.palette.text.tertiary}
>
A {title} is used to:
{ovalStart ? "An" : "A"} {title} is used to:
</Typography>
{checks.map((check, index) => (
<Check

View File

@@ -4,6 +4,8 @@ import { /* useDispatch, */ useSelector } from "react-redux";
import { useTheme } from "@emotion/react";
import useUtils from "../Monitors/utils";
import { jwtDecode } from "jwt-decode";
import SkeletonLayout from "./skeleton";
import Fallback from "../../Components/Fallback";
// import GearIcon from "../../Assets/icons/settings-bold.svg?react";
import CPUChipIcon from "../../assets/icons/cpu-chip.svg?react";
import {
@@ -77,6 +79,7 @@ function Infrastructure() {
/* Adding this custom hook so we can avoid using the HOC approach that can lower performance (we are calling the admin logic N times on initializing the project. using a custom hook will cal it ass needed ) */
const isAdmin = useIsAdmin();
const theme = useTheme();
const [isLoading, setIsLoading] = useState(true);
const navigate = useNavigate();
const navigateToCreate = () => navigate("/infrastructure/create");
@@ -99,6 +102,7 @@ function Infrastructure() {
const fetchMonitors = async () => {
try {
setIsLoading(true);
const response = await networkService.getMonitorsByTeamId({
authToken,
teamId: user.teamId,
@@ -116,6 +120,8 @@ function Infrastructure() {
});
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
};
@@ -165,168 +171,200 @@ function Infrastructure() {
};
});
let isActuallyLoading = isLoading && monitorState.monitors?.length === 0;
return (
<Stack
component="main"
style={{ width: "100%", gap: "1rem" }}
<Box
className="infrastructure-monitor"
sx={{
':has(> [class*="fallback__"])': {
position: "relative",
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
borderStyle: "dashed",
backgroundColor: theme.palette.background.main,
overflow: "hidden",
},
}}
>
<Breadcrumbs list={BREADCRUMBS} />
<Stack
direction="row"
sx={{
justifyContent: "end",
alignItems: "center",
gap: "1rem",
flexWrap: "wrap",
marginBottom: "2rem",
}}
>
{/*
{isActuallyLoading ? (
<SkeletonLayout />
) : monitorState.monitors?.length !== 0 ? (
<Stack
component="main"
style={{ width: "100%", gap: "1rem" }}
>
<Breadcrumbs list={BREADCRUMBS} />
<Stack
direction="row"
sx={{
justifyContent: "end",
alignItems: "center",
gap: "1rem",
flexWrap: "wrap",
marginBottom: "2rem",
}}
>
{/*
This will be removed from here, but keeping the commented code to remind me to add a max width to the greeting component
<Box style={{ maxWidth: "65ch" }}>
<Greeting type="uptime" />
</Box> */}
<Button
variant="contained"
color="primary"
onClick={navigateToCreate}
sx={{ fontWeight: 500 }}
>
Create infrastructure monitor
</Button>
</Stack>
<Stack
sx={{
gap: "1rem",
}}
>
<Stack
direction="row"
sx={{
alignItems: "center",
gap: ".25rem",
flexWrap: "wrap",
}}
>
<Heading component="h2">Infrastructure monitors</Heading>
{/* TODO Correct the class current-monitors-counter, there are some unnecessary things there */}
<Box
component="span"
className="current-monitors-counter"
color={theme.palette.text.primary}
border={1}
borderColor={theme.palette.border.light}
backgroundColor={theme.palette.background.accent}
<Button
variant="contained"
color="primary"
onClick={navigateToCreate}
sx={{ fontWeight: 500 }}
>
Create infrastructure monitor
</Button>
</Stack>
<Stack
sx={{
gap: "1rem",
}}
>
{totalMonitors}
</Box>
</Stack>
<TableContainer component={Paper}>
<Table stickyHeader>
<TableHead sx={{ backgroundColor: theme.palette.background.accent }}>
<TableRow>
{columns.map((column, index) => (
<TableCell
key={index}
align={index === 0 ? "left" : "center"}
sx={{
backgroundColor: theme.palette.background.accent,
}}
>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{monitorsAsRows.map((row) => {
return (
<TableRow
key={row.id}
onClick={() => openDetails(row.id)}
sx={{
cursor: "pointer",
"&:hover": {
backgroundColor: theme.palette.background.accent,
},
}}
>
{/* TODO iterate over column and get column id, applying row[column.id] */}
<TableCell>
<Host
title={row.name}
url={row.url}
percentage={row.uptimePercentage}
percentageColor={row.percentageColor}
/>
</TableCell>
<TableCell align="center">
<StatusLabel
status={row.status}
text={row.status}
/* Use capitalize inside of Status Label */
/* Update component so we don't need to pass text and status separately*/
customStyles={{ textTransform: "capitalize" }}
/>
</TableCell>
<TableCell align="center">
<Stack
direction={"row"}
justifyContent={"center"}
alignItems={"center"}
gap=".25rem"
>
<CPUChipIcon
width={20}
height={20}
/>
{row.processor}
</Stack>
</TableCell>
<TableCell align="center">
<CustomGauge progress={row.cpu} />
</TableCell>
<TableCell align="center">
<CustomGauge progress={row.mem} />
</TableCell>
<TableCell align="center">
<CustomGauge progress={row.disk} />
</TableCell>
<TableCell align="center">
{/* Get ActionsMenu from Monitor Table and create a component */}
<IconButton
<Stack
direction="row"
sx={{
alignItems: "center",
gap: ".25rem",
flexWrap: "wrap",
}}
>
<Heading component="h2">Infrastructure monitors</Heading>
{/* TODO Correct the class current-monitors-counter, there are some unnecessary things there */}
<Box
component="span"
className="current-monitors-counter"
color={theme.palette.text.primary}
border={1}
borderColor={theme.palette.border.light}
backgroundColor={theme.palette.background.accent}
>
{totalMonitors}
</Box>
</Stack>
<TableContainer component={Paper}>
<Table stickyHeader>
<TableHead sx={{ backgroundColor: theme.palette.background.accent }}>
<TableRow>
{columns.map((column, index) => (
<TableCell
key={index}
align={index === 0 ? "left" : "center"}
sx={{
"& svg path": {
stroke: theme.palette.other.icon,
backgroundColor: theme.palette.background.accent,
}}
>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{monitorsAsRows.map((row) => {
return (
<TableRow
key={row.id}
onClick={() => openDetails(row.id)}
sx={{
cursor: "pointer",
"&:hover": {
backgroundColor: theme.palette.background.accent,
},
}}
>
<InfrastructureMenu
monitor={row}
isAdmin={isAdmin}
updateCallback={handleActionMenuDelete}
/>
{/* <GearIcon
{/* TODO iterate over column and get column id, applying row[column.id] */}
<TableCell>
<Host
title={row.name}
url={row.url}
percentage={row.uptimePercentage}
percentageColor={row.percentageColor}
/>
</TableCell>
<TableCell align="center">
<StatusLabel
status={row.status}
text={row.status}
/* Use capitalize inside of Status Label */
/* Update component so we don't need to pass text and status separately*/
customStyles={{ textTransform: "capitalize" }}
/>
</TableCell>
<TableCell align="center">
<Stack
direction={"row"}
justifyContent={"center"}
alignItems={"center"}
gap=".25rem"
>
<CPUChipIcon
width={20}
height={20}
/>
{row.processor}
</Stack>
</TableCell>
<TableCell align="center">
<CustomGauge progress={row.cpu} />
</TableCell>
<TableCell align="center">
<CustomGauge progress={row.mem} />
</TableCell>
<TableCell align="center">
<CustomGauge progress={row.disk} />
</TableCell>
<TableCell align="center">
{/* Get ActionsMenu from Monitor Table and create a component */}
<IconButton
sx={{
"& svg path": {
stroke: theme.palette.other.icon,
},
}}
>
<InfrastructureMenu
monitor={row}
isAdmin={isAdmin}
updateCallback={handleActionMenuDelete}
/>
{/* <GearIcon
width={20}
height={20}
/> */}
</IconButton>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
<Pagination
monitorCount={totalMonitors}
page={page}
rowsPerPage={rowsPerPage}
handleChangePage={handleChangePage}
handleChangeRowsPerPage={handleChangeRowsPerPage}
</IconButton>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
<Pagination
monitorCount={totalMonitors}
page={page}
rowsPerPage={rowsPerPage}
handleChangePage={handleChangePage}
handleChangeRowsPerPage={handleChangeRowsPerPage}
/>
</Stack>
</Stack>
) : (
<Fallback
ovalStart={true}
title="infrastructure monitor"
checks={[
"Track the performance of your servers",
"Identify bottlenecks and optimize usage",
"Ensure reliability with real-time monitoring",
]}
link="/infrastructure/create"
isAdmin={isAdmin}
/>
</Stack>
</Stack>
)}
</Box>
);
}

View File

@@ -0,0 +1,73 @@
import { Box, Skeleton, Stack } from "@mui/material";
import { useTheme } from "@emotion/react";
/**
* Renders a skeleton layout.
*
* @returns {JSX.Element}
*/
const SkeletonLayout = () => {
const theme = useTheme();
return (
<Stack gap={theme.spacing(2)}>
<Stack
direction="row"
justifyContent="space-between"
mb={theme.spacing(12)}
>
<Box width="80%">
<Skeleton
variant="rounded"
width="25%"
height={24}
/>
<Skeleton
variant="rounded"
width="50%"
height={19.5}
sx={{ mt: theme.spacing(2) }}
/>
</Box>
<Skeleton
variant="rounded"
width="20%"
height={34}
sx={{ alignSelf: "flex-end" }}
/>
</Stack>
<Stack
direction="row"
flexWrap="wrap"
gap={theme.spacing(12)}
>
<Skeleton
variant="rounded"
width="100%"
height={120}
sx={{ flex: "35%" }}
/>
<Skeleton
variant="rounded"
width="100%"
height={120}
sx={{ flex: "35%" }}
/>
<Skeleton
variant="rounded"
width="100%"
height={120}
sx={{ flex: "35%" }}
/>
<Skeleton
variant="rounded"
width="100%"
height={120}
sx={{ flex: "35%" }}
/>
</Stack>
</Stack>
);
};
export default SkeletonLayout;