Merge branch 'master' into feat/speedcheck-controller
This commit is contained in:
9 files changed
+98
-222
No files matched your search
@@ -17,40 +17,52 @@ import PropTypes from "prop-types";
|
||||
*
|
||||
* @component
|
||||
* @param {Object} props - Component props.
|
||||
* @param {Array} props.headers - Array of header titles for the table.
|
||||
* @param {Array} props.rowItems - Array of row data objects for the table.
|
||||
* @param {boolean} props.paginated - Flag to enable pagination.
|
||||
* @param {Object} props.data - Data for the table including columns and rows.
|
||||
* @param {Array} props.data.cols - Array of objects for column headers.
|
||||
* @param {number} props.data.cols[].id - Unique identifier for the column.
|
||||
* @param {string} props.data.cols[].name - Name of the column to display as header.
|
||||
* @param {Array} props.data.rows - Array of row objects.
|
||||
* @param {number} props.data.rows[].id - Unique identifier for the row.
|
||||
* @param {Array} props.data.rows[].data - Array of cell data objects for the row.
|
||||
* @param {number} props.data.rows[].data[].id - Unique identifier for the cell.
|
||||
* @param {JSX.Element} props.data.rows[].data[].data - The content to display in the cell.
|
||||
* @param {function} props.data.rows.data.handleClick - Function to call when the row is clicked.
|
||||
* @param {boolean} [props.paginated=false] - Flag to enable pagination.
|
||||
*
|
||||
* @example
|
||||
* const data = {
|
||||
* cols: [
|
||||
* { id: 1, name: "First Col" },
|
||||
* { id: 2, name: "Second Col" },
|
||||
* { id: 3, name: "Third Col" },
|
||||
* { id: 4, name: "Fourth Col" },
|
||||
* ],
|
||||
* rows: [
|
||||
* {
|
||||
* id: 1,
|
||||
* data: [
|
||||
* { id: 1, data: <div>Data for Row 1 Col 1</div> },
|
||||
* { id: 2, data: <div>Data for Row 1 Col 2</div> },
|
||||
* { id: 3, data: <div>Data for Row 1 Col 3</div> },
|
||||
* { id: 4, data: <div>Data for Row 1 Col 4</div> },
|
||||
* ],
|
||||
* },
|
||||
* {
|
||||
* id: 2,
|
||||
* data: [
|
||||
* { id: 5, data: <div>Data for Row 2 Col 1</div> },
|
||||
* { id: 6, data: <div>Data for Row 2 Col 2</div> },
|
||||
* { id: 7, data: <div>Data for Row 2 Col 3</div> },
|
||||
* { id: 8, data: <div>Data for Row 2 Col 4</div> },
|
||||
* ],
|
||||
* },
|
||||
* ],
|
||||
* };
|
||||
*
|
||||
* Headers is an array of objets that have a unique ID and a name
|
||||
* Rows is an array of objects that have a unique ID and some data to display
|
||||
* Row data can be any valid React node
|
||||
* Rows are split into groups according to the number of headers, so if you have 3 headers then
|
||||
* Rows will go under the index % 3 column.
|
||||
* ie: Row 0 -> col 0 % 3 = 0
|
||||
* ie: Row 1 -> col 1 % 3 = 1
|
||||
* ie: Row 2 -> col 2 % 3 = 2
|
||||
* ie: Row 3 -> col 3 % 3 = 0
|
||||
*
|
||||
* Thus items are put in their correct columns
|
||||
*
|
||||
*
|
||||
* const headers = [
|
||||
* { id: 1, name: "ID" },
|
||||
* { id: 2, name: "Name" },
|
||||
* { id: 3, name: "Age" },
|
||||
* ];
|
||||
* const rows = [
|
||||
* { id: 1, data: <span>999</span> },
|
||||
* { id: 2, data: <div>Alex Holliday</div> },
|
||||
* { id: 3, data: <div>5</div> },
|
||||
* // More rows...
|
||||
* ];
|
||||
* <BasicTable headers={headers} rows={rows} paginated={true} />
|
||||
* <BasicTable data={data} rows={rows} paginated={true} />
|
||||
*/
|
||||
|
||||
const BasicTable = ({ headers, rowItems, paginated }) => {
|
||||
const BasicTable = ({ data, paginated }) => {
|
||||
// Add headers to props validation
|
||||
|
||||
const [page, setPage] = useState(0);
|
||||
@@ -65,19 +77,9 @@ const BasicTable = ({ headers, rowItems, paginated }) => {
|
||||
setPage(0); // Reset to first page after changing rows per page
|
||||
};
|
||||
|
||||
const numOfCols = headers.length;
|
||||
|
||||
const groupedRowItems = rowItems.reduce((acc, item, idx) => {
|
||||
const rowIndex = Math.floor((item.id - 1) / numOfCols);
|
||||
if (!acc[rowIndex]) acc[rowIndex] = { items: [], idx };
|
||||
acc[rowIndex].items.push({ item });
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const paginatedRowsKeys = Object.keys(groupedRowItems).slice(
|
||||
page * rowsPerPage,
|
||||
page * rowsPerPage + rowsPerPage
|
||||
);
|
||||
let displayData = paginated
|
||||
? data.rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||
: data.rows;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -85,42 +87,37 @@ const BasicTable = ({ headers, rowItems, paginated }) => {
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{headers.map((header) => {
|
||||
return <TableCell key={header.id}>{header.name}</TableCell>;
|
||||
})}
|
||||
{data.cols.map((col) => (
|
||||
<TableCell key={col.id}>{col.name}</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{paginated === false &&
|
||||
Object.keys(groupedRowItems).map((key) => {
|
||||
return (
|
||||
<TableRow key={groupedRowItems[key].idx}>
|
||||
{groupedRowItems[key].items.map(({ item }) => {
|
||||
return <TableCell key={item.id}>{item.data}</TableCell>;
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
{paginated === true &&
|
||||
paginatedRowsKeys.map((key) => (
|
||||
<TableRow key={groupedRowItems[key].idx}>
|
||||
{groupedRowItems[key].items.map(({ item }) => (
|
||||
<TableCell key={item.id}>{item.data}</TableCell>
|
||||
))}
|
||||
{displayData.map((row) => {
|
||||
return (
|
||||
<TableRow
|
||||
sx={{ cursor: row.handleClick ? "pointer" : "default" }}
|
||||
key={row.id}
|
||||
onClick={row.handleClick ? row.handleClick : null}
|
||||
>
|
||||
{row.data.map((cell) => {
|
||||
return <TableCell key={cell.id}>{cell.data}</TableCell>;
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
{paginated === true && (
|
||||
<TablePagination
|
||||
rowsPerPageOptions={[1, 5, 10, 25]}
|
||||
component="div"
|
||||
count={Object.keys(groupedRowItems).length}
|
||||
count={data.rows.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
rowsPerPageOptions={[1, 5, 10]}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
@@ -128,18 +125,7 @@ const BasicTable = ({ headers, rowItems, paginated }) => {
|
||||
};
|
||||
|
||||
BasicTable.propTypes = {
|
||||
headers: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
rowItems: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||
data: PropTypes.node,
|
||||
})
|
||||
).isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
paginated: PropTypes.bool,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import React from "react";
|
||||
import OpenIt from "../../assets/Images/Icon-open-in-tab-gray.png";
|
||||
|
||||
function Host(title, precentage, statusColor, link) {
|
||||
return (
|
||||
<div className="host-list-item">
|
||||
<a href={link} target="_blank">
|
||||
<img className="host-list-item-open" src={OpenIt} alt="OpenIt" />
|
||||
</a>
|
||||
<div className="host-list-item-name">{title}</div>
|
||||
<div className="host-list-item-precentage" style={{ color: statusColor }}>
|
||||
{precentage}%
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Host;
|
||||
@@ -1,8 +0,0 @@
|
||||
import React from "react";
|
||||
import DashboardSettings from "../DashboardSettingsIcon";
|
||||
|
||||
function HostActions() {
|
||||
return <DashboardSettings />;
|
||||
}
|
||||
|
||||
export default HostActions;
|
||||
@@ -1,18 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
function HostStatus(backgroundColor, status, dotColor) {
|
||||
return (
|
||||
<div
|
||||
className="host-status-box"
|
||||
style={{ backgroundColor: backgroundColor }}
|
||||
>
|
||||
<div
|
||||
className="host-status-box-circle"
|
||||
style={{ backgroundColor: dotColor }}
|
||||
></div>
|
||||
<div className="host-status-box-text">{status}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default HostStatus;
|
||||
@@ -1,80 +0,0 @@
|
||||
import PropTypes from "prop-types";
|
||||
import Host from "../Host/";
|
||||
import HostStatus from "../HostStatus";
|
||||
import ResponseTimeChart from "../Charts/ResponseTimeChart";
|
||||
/**
|
||||
* HostsTable displays the current status of monitor
|
||||
*
|
||||
* @component
|
||||
* @param {Array<Monitor>} monitors - An array of monitor objects to be displayed.
|
||||
*/
|
||||
|
||||
const getLastCheckStatus = (monitor) => {
|
||||
if (monitor.checks.length === 0) {
|
||||
// Default values for when there are no checks
|
||||
return {
|
||||
color: "var(--env-var-color-21)",
|
||||
statusText: "No Data",
|
||||
dotColor: "var(--env-var-color-19)",
|
||||
};
|
||||
}
|
||||
|
||||
const lastCheck = monitor.checks[monitor.checks.length - 1];
|
||||
const isUp = lastCheck.status === true;
|
||||
return {
|
||||
color: isUp ? "var(--env-var-color-20)" : "var(--env-var-color-21)",
|
||||
statusText: isUp ? "Up" : "Down",
|
||||
dotColor: isUp ? "var(--env-var-color-17)" : "var(--env-var-color-19)",
|
||||
};
|
||||
};
|
||||
|
||||
const HostsTable = ({ monitors }) => {
|
||||
return (
|
||||
<div className="current-monitors-table-holder">
|
||||
<table className="current-monitors-table">
|
||||
<thead>
|
||||
<tr className="theader-row">
|
||||
<td className="theader-row-cell">Host</td>
|
||||
<td className="theader-row-cell">Status</td>
|
||||
<td className="theader-row-cell">Response</td>
|
||||
<td className="theader-row-cell">Actions</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{monitors.map((monitor) => {
|
||||
const host = Host(
|
||||
monitor.name,
|
||||
100,
|
||||
"var(--env-var-color-17)",
|
||||
monitor.url
|
||||
);
|
||||
|
||||
const { color, currentStatus, dotColor } =
|
||||
getLastCheckStatus(monitor);
|
||||
|
||||
const status = HostStatus(color, currentStatus, dotColor);
|
||||
|
||||
return (
|
||||
<tr className="tbody-row" key={monitor._id}>
|
||||
<td className="tbody-row-cell">{host}</td>
|
||||
<td className="tbody-row-cell">{status}</td>
|
||||
<td className="tbody-row-cell">
|
||||
<ResponseTimeChart checks={monitor.checks} />
|
||||
</td>
|
||||
<td className="tbody-row-cell actions-cell">
|
||||
{monitor.actions}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
HostsTable.propTypes = {
|
||||
monitors: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
};
|
||||
|
||||
export default HostsTable;
|
||||
@@ -3,6 +3,7 @@ import PropTypes from "prop-types";
|
||||
import ResponseTimeChart from "../Charts/ResponseTimeChart";
|
||||
import BasicTable from "../BasicTable";
|
||||
import OpenInNewPage from "../../assets/icons/open-in-new-page.svg?react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
/**
|
||||
* Host component.
|
||||
@@ -80,14 +81,19 @@ const Status = ({ params }) => {
|
||||
* @returns {React.Component} Returns a table with the monitor data.
|
||||
*/
|
||||
const MonitorTable = ({ monitors = [] }) => {
|
||||
const headers = [
|
||||
{ id: 1, name: "Host" },
|
||||
{ id: 2, name: "Status" },
|
||||
{ id: 3, name: "Response Time" },
|
||||
{ id: 4, name: "Actions" },
|
||||
];
|
||||
const data = [];
|
||||
monitors.forEach((monitor) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const data = {
|
||||
cols: [
|
||||
{ id: 1, name: "Host" },
|
||||
{ id: 2, name: "Status" },
|
||||
{ id: 3, name: "Response Time" },
|
||||
{ id: 4, name: "Actions" },
|
||||
],
|
||||
rows: [],
|
||||
};
|
||||
|
||||
data.rows = monitors.map((monitor, idx) => {
|
||||
const params = {
|
||||
url: monitor.url,
|
||||
title: monitor.name,
|
||||
@@ -106,16 +112,20 @@ const MonitorTable = ({ monitors = [] }) => {
|
||||
? "var(--env-var-color-17)"
|
||||
: "var(--env-var-color-19)",
|
||||
};
|
||||
data.push({ id: data.length + 1, data: <Host params={params} /> });
|
||||
data.push({ id: data.length + 1, data: <Status params={params} /> });
|
||||
data.push({
|
||||
id: data.length + 1,
|
||||
data: <ResponseTimeChart checks={monitor.checks} />,
|
||||
});
|
||||
data.push({ id: data.length + 1, data: "TODO" });
|
||||
|
||||
return {
|
||||
id: monitor._id,
|
||||
handleClick: () => navigate(`/monitors/${monitor._id}`),
|
||||
data: [
|
||||
{ id: idx, data: <Host params={params} /> },
|
||||
{ id: idx + 1, data: <Status params={params} /> },
|
||||
{ id: idx + 2, data: <ResponseTimeChart checks={monitor.checks} /> },
|
||||
{ id: idx + 3, data: "TODO" },
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
return <BasicTable headers={headers} rowItems={data} paginated={true} />;
|
||||
return <BasicTable data={data} paginated={true} />;
|
||||
};
|
||||
|
||||
MonitorTable.propTypes = {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import CustomizedTables from "../../Components/CustomizedTables";
|
||||
import { Box, Typography, useTheme } from "@mui/material";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -27,7 +26,6 @@ const DetailsPage = () => {
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
// Example monitor data (replace with actual data or fetch from API)
|
||||
/**
|
||||
* Function to calculate uptime duration based on the most recent check.
|
||||
* @param {Array} checks Array of check objects.
|
||||
|
||||
@@ -309,11 +309,12 @@ const validateRecoveryTokenController = async (req, res, next) => {
|
||||
const resetPasswordController = async (req, res, next) => {
|
||||
try {
|
||||
await newPasswordValidation.validateAsync(req.body);
|
||||
user = await req.db.resetPassword(req, res);
|
||||
const user = await req.db.resetPassword(req, res);
|
||||
const token = issueToken(user);
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.AUTH_RESET_PASSWORD,
|
||||
data: user,
|
||||
data: { user, token },
|
||||
});
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
|
||||
@@ -14,12 +14,14 @@ const {
|
||||
* @param {string} monitorId - The ID of the monitor
|
||||
* @middleware verifyOwnership - Ensures the user owns the monitor
|
||||
*/
|
||||
|
||||
router.post(
|
||||
"/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
createPageSpeedCheck
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @route GET /:monitorId
|
||||
* @description Get all PageSpeedChecks for a monitor
|
||||
@@ -27,6 +29,7 @@ router.post(
|
||||
* @param {string} monitorId - The ID of the monitor
|
||||
* @middleware verifyOwnership - Ensures the user owns the monitor
|
||||
*/
|
||||
|
||||
router.get(
|
||||
"/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
@@ -40,10 +43,12 @@ router.get(
|
||||
* @param {string} monitorId - The ID of the monitor
|
||||
* @middleware verifyOwnership - Ensures the user owns the monitor
|
||||
*/
|
||||
router.post(
|
||||
"/delete/:monitorId",
|
||||
|
||||
router.delete(
|
||||
"/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
deletePageSpeedCheck
|
||||
);
|
||||
|
||||
|
||||
module.exports = router;
|
||||
Reference in new issue
Block a user