diff --git a/Client/src/Pages/Incidents/IncidentTable/index.jsx b/Client/src/Pages/Incidents/IncidentTable/index.jsx
index aa80b35ce..d10c79c68 100644
--- a/Client/src/Pages/Incidents/IncidentTable/index.jsx
+++ b/Client/src/Pages/Incidents/IncidentTable/index.jsx
@@ -15,14 +15,12 @@ import {
import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded";
import ArrowForwardRoundedIcon from "@mui/icons-material/ArrowForwardRounded";
-
import { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { networkService } from "../../../main";
import { StatusLabel } from "../../../Components/Label";
import { logger } from "../../../Utils/Logger";
import { useTheme } from "@emotion/react";
-
const IncidentTable = ({ monitors, selectedMonitor, filter }) => {
const theme = useTheme();
const { authToken, user } = useSelector((state) => state.auth);
diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx
index 3152cf506..d5d8d001e 100644
--- a/Client/src/Pages/Incidents/index.jsx
+++ b/Client/src/Pages/Incidents/index.jsx
@@ -1,43 +1,12 @@
import { useState, useEffect } from "react";
import { useSelector } from "react-redux";
-import {
- ButtonGroup,
- Stack,
- Skeleton,
- Typography,
- Button,
-} from "@mui/material";
+import { ButtonGroup, Stack, Typography, Button } from "@mui/material";
import { networkService } from "../../main";
import { useTheme } from "@emotion/react";
import Select from "../../Components/Inputs/Select";
import IncidentTable from "./IncidentTable";
import "./index.css";
-
-/**
- * Renders a skeleton layout.
- *
- * @returns {JSX.Element}
- */
-const SkeletonLayout = () => {
- const theme = useTheme();
-
- return (
- <>
-
-
-
-
-
-
-
- >
- );
-};
+import SkeletonLayout from "./skeleton";
const Incidents = () => {
const theme = useTheme();
diff --git a/Client/src/Pages/Incidents/skeleton.jsx b/Client/src/Pages/Incidents/skeleton.jsx
new file mode 100644
index 000000000..d1571ad3a
--- /dev/null
+++ b/Client/src/Pages/Incidents/skeleton.jsx
@@ -0,0 +1,30 @@
+import { Stack, Skeleton } from "@mui/material";
+import { useTheme } from "@emotion/react";
+
+/**
+ * Renders a skeleton layout.
+ *
+ * @returns {JSX.Element}
+ */
+const SkeletonLayout = () => {
+ const theme = useTheme();
+
+ return (
+ <>
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default SkeletonLayout;
diff --git a/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx b/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx
new file mode 100644
index 000000000..dae082379
--- /dev/null
+++ b/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx
@@ -0,0 +1,201 @@
+import PropTypes from "prop-types";
+import {
+ TableContainer,
+ Table,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableBody,
+ Pagination,
+ PaginationItem,
+ Paper,
+ Box,
+} from "@mui/material";
+import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded";
+import ArrowForwardRoundedIcon from "@mui/icons-material/ArrowForwardRounded";
+import ArrowDownwardRoundedIcon from "@mui/icons-material/ArrowDownwardRounded";
+
+import { useState, useEffect } from "react";
+import { logger } from "../../../../Utils/Logger";
+import Host from "../host";
+import { StatusLabel } from "../../../../Components/Label";
+import { jwtDecode } from "jwt-decode";
+import { useSelector } from "react-redux";
+import { networkService } from "../../../../main";
+import { useTheme } from "@emotion/react";
+import BarChart from "../../../../Components/Charts/BarChart";
+import ActionsMenu from "../actionsMenu";
+
+const MonitorTable = ({ isAdmin }) => {
+ const theme = useTheme();
+
+ const [paginationController, setPaginationController] = useState({
+ page: 0,
+ rowsPerPage: 14,
+ });
+ const [monitors, setMonitors] = useState([]);
+ const [monitorCount, setMonitorCount] = useState(0);
+ const authState = useSelector((state) => state.auth);
+ const [updateTrigger, setUpdateTrigger] = useState(false);
+
+ const handleActionMenuDelete = () => {
+ setUpdateTrigger((prev) => !prev);
+ };
+
+ const handlePageChange = (_, newPage) => {
+ setPaginationController({
+ ...paginationController,
+ page: newPage - 1, // 0-indexed
+ });
+ };
+
+ useEffect(() => {
+ const fetchPage = async () => {
+ try {
+ const { authToken } = authState;
+ const user = jwtDecode(authToken);
+ const res = await networkService.getMonitorsByTeamId(
+ authToken,
+ user.teamId,
+ 25,
+ ["http", "ping"],
+ null,
+ "desc",
+ true,
+ paginationController.page,
+ paginationController.rowsPerPage
+ );
+ setMonitors(res?.data?.data?.monitors ?? []);
+ setMonitorCount(res?.data?.data?.monitorCount ?? 0);
+ } catch (error) {
+ logger.error(error);
+ }
+ };
+ fetchPage();
+ }, [
+ updateTrigger,
+ authState,
+ paginationController.page,
+ paginationController.rowsPerPage,
+ ]);
+
+ let paginationComponent = <>>;
+ if (monitorCount > paginationController.rowsPerPage) {
+ paginationComponent = (
+ (
+
+ )}
+ />
+ );
+ }
+
+ return (
+ <>
+
+
+
+
+ Host
+
+ {" "}
+
+ Status
+
+
+
+
+
+ Response Time
+ Type
+ Actions
+
+
+
+ {monitors.map((monitor) => {
+ let uptimePercentage = "";
+ let percentageColor = theme.palette.percentage.uptimeExcellent;
+
+ // Determine uptime percentage and color based on the monitor's uptimePercentage value
+ if (monitor.uptimePercentage !== undefined) {
+ uptimePercentage =
+ monitor.uptimePercentage === 0
+ ? "0"
+ : (monitor.uptimePercentage * 100).toFixed(2);
+
+ percentageColor =
+ monitor.uptimePercentage < 0.25
+ ? theme.palette.percentage.uptimePoor
+ : monitor.uptimePercentage < 0.5
+ ? theme.palette.percentage.uptimeFair
+ : monitor.uptimePercentage < 0.75
+ ? theme.palette.percentage.uptimeGood
+ : theme.palette.percentage.uptimeExcellent;
+ }
+
+ const params = {
+ url: monitor.url,
+ title: monitor.name,
+ percentage: uptimePercentage,
+ percentageColor,
+ status:
+ monitor.status === undefined
+ ? "pending"
+ : monitor.status === true
+ ? "up"
+ : "down",
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ {monitor.type}
+
+
+
+
+
+
+ );
+ })}
+
+
+
+ {paginationComponent}
+ >
+ );
+};
+
+MonitorTable.propTypes = {
+ isAdmin: PropTypes.bool,
+};
+
+export default MonitorTable;
diff --git a/Client/src/Pages/Monitors/Home/actionsMenu.jsx b/Client/src/Pages/Monitors/Home/actionsMenu.jsx
index 7d342f5d7..efb29402d 100644
--- a/Client/src/Pages/Monitors/Home/actionsMenu.jsx
+++ b/Client/src/Pages/Monitors/Home/actionsMenu.jsx
@@ -19,7 +19,7 @@ import {
import Settings from "../../../assets/icons/settings-bold.svg?react";
import PropTypes from "prop-types";
-const ActionsMenu = ({ monitor, isAdmin }) => {
+const ActionsMenu = ({ monitor, isAdmin, updateCallback }) => {
const [anchorEl, setAnchorEl] = useState(null);
const [actions, setActions] = useState({});
const [isOpen, setIsOpen] = useState(false);
@@ -37,6 +37,7 @@ const ActionsMenu = ({ monitor, isAdmin }) => {
if (action.meta.requestStatus === "fulfilled") {
setIsOpen(false); // close modal
dispatch(getUptimeMonitorsByTeamId(authState.authToken));
+ updateCallback();
createToast({ body: "Monitor deleted successfully." });
} else {
createToast({ body: "Failed to delete monitor." });
@@ -222,6 +223,7 @@ ActionsMenu.propTypes = {
type: PropTypes.string,
}).isRequired,
isAdmin: PropTypes.bool,
+ updateCallback: PropTypes.func,
};
export default ActionsMenu;
diff --git a/Client/src/Pages/Monitors/Home/index.jsx b/Client/src/Pages/Monitors/Home/index.jsx
index 64c01b7ac..9de50df83 100644
--- a/Client/src/Pages/Monitors/Home/index.jsx
+++ b/Client/src/Pages/Monitors/Home/index.jsx
@@ -4,15 +4,14 @@ import { useSelector, useDispatch } from "react-redux";
import { getUptimeMonitorsByTeamId } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice";
import { useNavigate } from "react-router-dom";
import { useTheme } from "@emotion/react";
-import BasicTable from "../../../Components/BasicTable";
import { Box, Button, Stack, Typography } from "@mui/material";
import PropTypes from "prop-types";
import SkeletonLayout from "./skeleton";
import Fallback from "./fallback";
import StatusBox from "./StatusBox";
-import { buildData } from "./monitorData";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import Greeting from "../../../Utils/greeting";
+import MonitorTable from "./MonitorTable";
const Monitors = ({ isAdmin }) => {
const theme = useTheme();
@@ -25,7 +24,7 @@ const Monitors = ({ isAdmin }) => {
dispatch(getUptimeMonitorsByTeamId(authState.authToken));
}, [authState.authToken, dispatch]);
- const monitorStats = monitorState.monitors.reduce(
+ const monitorStats = monitorState.monitors.monitors.reduce(
(acc, monitor) => {
if (monitor.isActive === false) {
acc["paused"] += 1;
@@ -39,8 +38,6 @@ const Monitors = ({ isAdmin }) => {
{ paused: 0, up: 0, down: 0 }
);
- const data = buildData(monitorState.monitors, isAdmin, navigate);
-
let loading = monitorState.isLoading && monitorState.monitors.length === 0;
return (
@@ -118,7 +115,7 @@ const Monitors = ({ isAdmin }) => {
{/* TODO - add search bar */}
-
+
>
)}
diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js
index acb1134e4..4c8dd57e8 100644
--- a/Client/src/Utils/NetworkService.js
+++ b/Client/src/Utils/NetworkService.js
@@ -80,7 +80,9 @@ class NetworkService {
types,
status,
sortOrder,
- normalize
+ normalize,
+ page,
+ rowsPerPage
) {
const params = new URLSearchParams();
@@ -93,6 +95,8 @@ class NetworkService {
if (status) params.append("status", status);
if (sortOrder) params.append("sortOrder", sortOrder);
if (normalize) params.append("normalize", normalize);
+ if (page) params.append("page", page);
+ if (rowsPerPage) params.append("rowsPerPage", rowsPerPage);
return this.axiosInstance.get(
`/monitors/team/${teamId}?${params.toString()}`,
diff --git a/Client/src/assets/data/hostnames.json b/Client/src/assets/data/hostnames.json
new file mode 100644
index 000000000..b66818c3a
--- /dev/null
+++ b/Client/src/assets/data/hostnames.json
@@ -0,0 +1,1290 @@
+[
+ {
+ "Company Name": "0to255",
+ "Company Link ": "https://0to255.com"
+ },
+ {
+ "Company Name": "10015.io",
+ "Company Link ": "https://10015.io"
+ },
+ {
+ "Company Name": "3DIcons",
+ "Company Link ": "https://3dicons.co"
+ },
+ {
+ "Company Name": "About.me",
+ "Company Link ": "https://about.me"
+ },
+ {
+ "Company Name": "Alias",
+ "Company Link ": "https://alias.co"
+ },
+ {
+ "Company Name": "All About Berlin",
+ "Company Link ": "https://allaboutberlin.com"
+ },
+ {
+ "Company Name": "All Acronyms",
+ "Company Link ": "https://allacronyms.com"
+ },
+ {
+ "Company Name": "All You Can Read ",
+ "Company Link ": "https://allyoucanread.com"
+ },
+ {
+ "Company Name": "AllTrails",
+ "Company Link ": "https://alltrails.com"
+ },
+ {
+ "Company Name": "Anotepad",
+ "Company Link ": "https://anotepad.com"
+ },
+ {
+ "Company Name": "AnswerSocrates",
+ "Company Link ": "https://answersocrates.com"
+ },
+ {
+ "Company Name": "AnswerThePublic ",
+ "Company Link ": "https://answerthepublic.com"
+ },
+ {
+ "Company Name": "Apollo ",
+ "Company Link ": "https://apollo.io"
+ },
+ {
+ "Company Name": "ArrayList",
+ "Company Link ": "https://arraylist.org"
+ },
+ {
+ "Company Name": "Ask Difference",
+ "Company Link ": "https://askdifference.com"
+ },
+ {
+ "Company Name": "Audd.io",
+ "Company Link ": "https://audd.io"
+ },
+ {
+ "Company Name": "Audiocheck",
+ "Company Link ": "https://audiocheck.net"
+ },
+ {
+ "Company Name": "Audionautix",
+ "Company Link ": "https://audionautix.com"
+ },
+ {
+ "Company Name": "Authentic Jobs",
+ "Company Link ": "https://authenticjobs.com"
+ },
+ {
+ "Company Name": "Behind the Name",
+ "Company Link ": "https://behindthename.com"
+ },
+ {
+ "Company Name": "Bilim Terimleri",
+ "Company Link ": "https://terimler.org"
+ },
+ {
+ "Company Name": "BitBof",
+ "Company Link ": "https://bitbof.com"
+ },
+ {
+ "Company Name": "Blank Page",
+ "Company Link ": "https://blank.page"
+ },
+ {
+ "Company Name": "Bonanza",
+ "Company Link ": "https://bonanza.com"
+ },
+ {
+ "Company Name": "BookCrossing",
+ "Company Link ": "https://bookcrossing.com"
+ },
+ {
+ "Company Name": "Browse AI",
+ "Company Link ": "https://browse.ai"
+ },
+ {
+ "Company Name": "Bubbl.us",
+ "Company Link ": "https://bubbl.us"
+ },
+ {
+ "Company Name": "Business Model Toolbox",
+ "Company Link ": "https://bmtoolbox.net"
+ },
+ {
+ "Company Name": "ByClickDownloader",
+ "Company Link ": "https://byclickdownloader.com"
+ },
+ {
+ "Company Name": "Calligraphr",
+ "Company Link ": "https://calligraphr.com"
+ },
+ {
+ "Company Name": "CertificateClaim",
+ "Company Link ": "https://certificateclaim.com"
+ },
+ {
+ "Company Name": "Chosic",
+ "Company Link ": "https://chosic.com"
+ },
+ {
+ "Company Name": "ClipDrop",
+ "Company Link ": "https://clipdrop.co"
+ },
+ {
+ "Company Name": "CloudConvert",
+ "Company Link ": "https://cloudconvert.com"
+ },
+ {
+ "Company Name": "CodingFont",
+ "Company Link ": "https://codingfont.com"
+ },
+ {
+ "Company Name": "Color Hunt",
+ "Company Link ": "https://colorhunt.co"
+ },
+ {
+ "Company Name": "ColorHexa",
+ "Company Link ": "https://colorhexa.com"
+ },
+ {
+ "Company Name": "Conversion-Tool",
+ "Company Link ": "https://conversion-tool.com"
+ },
+ {
+ "Company Name": "Cool Startup Jobs",
+ "Company Link ": "https://coolstartupjobs.com"
+ },
+ {
+ "Company Name": "Coroflot",
+ "Company Link ": "https://coroflot.com"
+ },
+ {
+ "Company Name": "Corrupt-a-File",
+ "Company Link ": "https://corrupt-a-file.net"
+ },
+ {
+ "Company Name": "Couchsurfing",
+ "Company Link ": "https://couchsurfing.com"
+ },
+ {
+ "Company Name": "Countries Been",
+ "Company Link ": "https://countriesbeen.com"
+ },
+ {
+ "Company Name": "Country Code",
+ "Company Link ": "https://countrycode.org"
+ },
+ {
+ "Company Name": "Creately",
+ "Company Link ": "https://creately.com"
+ },
+ {
+ "Company Name": "Creately ",
+ "Company Link ": "https://creately.com"
+ },
+ {
+ "Company Name": "Crossfade.io",
+ "Company Link ": "https://crossfade.io"
+ },
+ {
+ "Company Name": "Crunchbase",
+ "Company Link ": "https://crunchbase.com"
+ },
+ {
+ "Company Name": "CVmkr",
+ "Company Link ": "https://cvwizard.com"
+ },
+ {
+ "Company Name": "Daily Remote",
+ "Company Link ": "https://dailyremote.com"
+ },
+ {
+ "Company Name": "David Li",
+ "Company Link ": "https://david.li"
+ },
+ {
+ "Company Name": "DemandHunt",
+ "Company Link ": "https://demandhunt.com"
+ },
+ {
+ "Company Name": "Designify",
+ "Company Link ": "https://designify.com"
+ },
+ {
+ "Company Name": "Diff Checker",
+ "Company Link ": "https://diffchecker.com"
+ },
+ {
+ "Company Name": "DifferenceBetween.info",
+ "Company Link ": "https://differencebetween.info"
+ },
+ {
+ "Company Name": "Digital Glossary",
+ "Company Link ": "https://digital-glossary.com"
+ },
+ {
+ "Company Name": "Dimensions",
+ "Company Link ": "https://dimensions.com"
+ },
+ {
+ "Company Name": "Discoverify Music",
+ "Company Link ": "https://discoverifymusic.com"
+ },
+ {
+ "Company Name": "discu.eu",
+ "Company Link ": "https://discu.eu"
+ },
+ {
+ "Company Name": "Do It Yourself",
+ "Company Link ": "https://doityourself.com"
+ },
+ {
+ "Company Name": "Donkey Car",
+ "Company Link ": "https://donkeycar.com"
+ },
+ {
+ "Company Name": "draw.io",
+ "Company Link ": "https://drawio.com"
+ },
+ {
+ "Company Name": "Drumeo",
+ "Company Link ": "https://drumeo.com"
+ },
+ {
+ "Company Name": "Dummies",
+ "Company Link ": "https://dummies.com"
+ },
+ {
+ "Company Name": "Easel.ly",
+ "Company Link ": "https://easel.ly"
+ },
+ {
+ "Company Name": "Educalingo",
+ "Company Link ": "https://educalingo.com"
+ },
+ {
+ "Company Name": "Emoji Combos",
+ "Company Link ": "https://emojicombos.com"
+ },
+ {
+ "Company Name": "EquityBee",
+ "Company Link ": "https://equitybee.com"
+ },
+ {
+ "Company Name": "EquityZen",
+ "Company Link ": "https://equityzen.com"
+ },
+ {
+ "Company Name": "Escape Room Tips",
+ "Company Link ": "https://escaperoomtips.com"
+ },
+ {
+ "Company Name": "Every Noise",
+ "Company Link ": "https://everynoise.com"
+ },
+ {
+ "Company Name": "Every Time Zone",
+ "Company Link ": "https://everytimezone.com"
+ },
+ {
+ "Company Name": "Excalideck",
+ "Company Link ": "https://excalideck.com"
+ },
+ {
+ "Company Name": "Excalidraw",
+ "Company Link ": "https://excalidraw.com"
+ },
+ {
+ "Company Name": "Extract pics",
+ "Company Link ": "https://extract.pics"
+ },
+ {
+ "Company Name": "EZGIF",
+ "Company Link ": "https://ezgif.com"
+ },
+ {
+ "Company Name": "FactSlides",
+ "Company Link ": "https://factslides.com"
+ },
+ {
+ "Company Name": "FIGR ",
+ "Company Link ": "https://figr.app"
+ },
+ {
+ "Company Name": "Fine Dictionary",
+ "Company Link ": "https://finedictionary.com"
+ },
+ {
+ "Company Name": "Fiverr",
+ "Company Link ": "https://fiverr.com"
+ },
+ {
+ "Company Name": "Fix It Club",
+ "Company Link ": "https://fixitclub.com"
+ },
+ {
+ "Company Name": "FlexJobs",
+ "Company Link ": "https://flexjobs.com"
+ },
+ {
+ "Company Name": "Flightradar24",
+ "Company Link ": "https://flightradar24.com"
+ },
+ {
+ "Company Name": "FlowCV ",
+ "Company Link ": "https://flowcv.com"
+ },
+ {
+ "Company Name": "Foco Clipping",
+ "Company Link ": "https://fococlipping.com"
+ },
+ {
+ "Company Name": "Font Squirrel",
+ "Company Link ": "https://fontsquirrel.com"
+ },
+ {
+ "Company Name": "FontAwesome",
+ "Company Link ": "https://fontawesome.com"
+ },
+ {
+ "Company Name": "Fontello ",
+ "Company Link ": "https://fontello.com"
+ },
+ {
+ "Company Name": "Form to Chatbot",
+ "Company Link ": "https://formtochatbot.com"
+ },
+ {
+ "Company Name": "Founder Resources",
+ "Company Link ": "https://founderresources.io"
+ },
+ {
+ "Company Name": "Franz",
+ "Company Link ": "https://meetfranz.com"
+ },
+ {
+ "Company Name": "Fraze It",
+ "Company Link ": "https://fraze.it"
+ },
+ {
+ "Company Name": "Freecycle",
+ "Company Link ": "https://freecycle.org"
+ },
+ {
+ "Company Name": "FreeType",
+ "Company Link ": "https://freetype.org"
+ },
+ {
+ "Company Name": "FutureM",
+ "Company Link ": "https://futureme.org"
+ },
+ {
+ "Company Name": "Generated.Photos",
+ "Company Link ": "https://generated.photos"
+ },
+ {
+ "Company Name": "Get Human",
+ "Company Link ": "https://gethuman.com"
+ },
+ {
+ "Company Name": "Go Bento",
+ "Company Link ": "https://gobento.com"
+ },
+ {
+ "Company Name": "Good CV",
+ "Company Link ": "https://goodcv.com"
+ },
+ {
+ "Company Name": "Grammar Monster",
+ "Company Link ": "https://grammar-monster.com"
+ },
+ {
+ "Company Name": "Grammar Book",
+ "Company Link ": "https://grammarbook.com"
+ },
+ {
+ "Company Name": "Gummy Search",
+ "Company Link ": "https://gummysearch.com"
+ },
+ {
+ "Company Name": "Gumroad",
+ "Company Link ": "https://gumroad.com"
+ },
+ {
+ "Company Name": "HealthIcons",
+ "Company Link ": "https://healthicons.org"
+ },
+ {
+ "Company Name": "HexColor",
+ "Company Link ": "https://hexcolor.co"
+ },
+ {
+ "Company Name": "Hidden Life Radio",
+ "Company Link ": "https://hiddenliferadio.com"
+ },
+ {
+ "Company Name": "Hired",
+ "Company Link ": "https://lhh.com"
+ },
+ {
+ "Company Name": "Honey",
+ "Company Link ": "https://joinhoney.com"
+ },
+ {
+ "Company Name": "HowStuffWorks",
+ "Company Link ": "https://howstuffworks.com"
+ },
+ {
+ "Company Name": "HugeIcons Pro",
+ "Company Link ": "https://hugeicons.com"
+ },
+ {
+ "Company Name": "Humble Bundle",
+ "Company Link ": "https://humblebundle.com"
+ },
+ {
+ "Company Name": "I Have No TV",
+ "Company Link ": "https://ihavenotv.com"
+ },
+ {
+ "Company Name": "I Miss the Office",
+ "Company Link ": "https://imisstheoffice.eu"
+ },
+ {
+ "Company Name": "IcoMoon",
+ "Company Link ": "https://icomoon.io"
+ },
+ {
+ "Company Name": "Iconfinder",
+ "Company Link ": "https://iconfinder.com"
+ },
+ {
+ "Company Name": "Icon Packs",
+ "Company Link ": "https://iconpacks.net"
+ },
+ {
+ "Company Name": "Iconshock",
+ "Company Link ": "https://iconshock.com"
+ },
+ {
+ "Company Name": "Iconz Design",
+ "Company Link ": "https://iconz.design"
+ },
+ {
+ "Company Name": "iFixit",
+ "Company Link ": "https://ifixit.com"
+ },
+ {
+ "Company Name": "IFTTT",
+ "Company Link ": "https://ifttt.com"
+ },
+ {
+ "Company Name": "Illlustrations",
+ "Company Link ": "https://illlustrations.co"
+ },
+ {
+ "Company Name": "Illustration Kit",
+ "Company Link ": "https://illustrationkit.com"
+ },
+ {
+ "Company Name": "IMSDB",
+ "Company Link ": "https://imsdb.com"
+ },
+ {
+ "Company Name": "Incompetech",
+ "Company Link ": "https://incompetech.com"
+ },
+ {
+ "Company Name": "Incredibox",
+ "Company Link ": "https://incredibox.com"
+ },
+ {
+ "Company Name": "InnerBod",
+ "Company Link ": "https://innerbody.com"
+ },
+ {
+ "Company Name": "Instructables",
+ "Company Link ": "https://instructables.com"
+ },
+ {
+ "Company Name": "Integromat",
+ "Company Link ": "https://make.com"
+ },
+ {
+ "Company Name": "Investopedia",
+ "Company Link ": "https://investopedia.com"
+ },
+ {
+ "Company Name": "Japanese Wiki Corpus",
+ "Company Link ": "https://japanesewiki.com"
+ },
+ {
+ "Company Name": "Jitter.Video",
+ "Company Link ": "https://jitter.video"
+ },
+ {
+ "Company Name": "Jobspresso",
+ "Company Link ": "https://jobspresso.co"
+ },
+ {
+ "Company Name": "JPEG-Optimizer",
+ "Company Link ": "https://jpeg-optimizer.com"
+ },
+ {
+ "Company Name": "JS Remotely",
+ "Company Link ": "https://jsremotely.com"
+ },
+ {
+ "Company Name": "JScreenFix",
+ "Company Link ": "https://jscreenfix.com"
+ },
+ {
+ "Company Name": "JSON Resume",
+ "Company Link ": "https://jsonresume.io"
+ },
+ {
+ "Company Name": "Just Join",
+ "Company Link ": "https://justjoin.it"
+ },
+ {
+ "Company Name": "Just the Recipe",
+ "Company Link ": "https://justtherecipe.com"
+ },
+ {
+ "Company Name": "JustRemote",
+ "Company Link ": "https://justremote.co"
+ },
+ {
+ "Company Name": "JustWatch",
+ "Company Link ": "https://justwatch.com"
+ },
+ {
+ "Company Name": "Kanopy",
+ "Company Link ": "https://kanopy.com"
+ },
+ {
+ "Company Name": "Kassellabs",
+ "Company Link ": "https://kassellabs.io"
+ },
+ {
+ "Company Name": "Key Differences",
+ "Company Link ": "https://keydifferences.com"
+ },
+ {
+ "Company Name": "Keybase",
+ "Company Link ": "https://keybase.io"
+ },
+ {
+ "Company Name": "KeyValues",
+ "Company Link ": "https://keyvalues.com"
+ },
+ {
+ "Company Name": "KHInsider",
+ "Company Link ": "https://khinsider.com"
+ },
+ {
+ "Company Name": "Killed by Google",
+ "Company Link ": "https://killedbygoogle.com"
+ },
+ {
+ "Company Name": "Kimovil",
+ "Company Link ": "https://kimovil.com"
+ },
+ {
+ "Company Name": "Lalal.ai",
+ "Company Link ": "https://www.lalal.ai"
+ },
+ {
+ "Company Name": "Learn Anything",
+ "Company Link ": "https://learn-anything.xyz"
+ },
+ {
+ "Company Name": "LendingTree",
+ "Company Link ": "https://lendingtree.com"
+ },
+ {
+ "Company Name": "Lightyear.fm",
+ "Company Link ": "https://lightyear.fm"
+ },
+ {
+ "Company Name": "LittleSis",
+ "Company Link ": "https://littlesis.org"
+ },
+ {
+ "Company Name": "Looria",
+ "Company Link ": "https://looria.com"
+ },
+ {
+ "Company Name": "Lucidchart",
+ "Company Link ": "https://lucidchart.com"
+ },
+ {
+ "Company Name": "Lunar",
+ "Company Link ": "https://lunar.fyi"
+ },
+ {
+ "Company Name": "Manuals Lib",
+ "Company Link ": "https://manualslib.com"
+ },
+ {
+ "Company Name": "Map Crunch",
+ "Company Link ": "https://mapcrunch.com"
+ },
+ {
+ "Company Name": "Masterworks",
+ "Company Link ": "https://masterworks.com"
+ },
+ {
+ "Company Name": "MediaFire",
+ "Company Link ": "https://mediafire.com"
+ },
+ {
+ "Company Name": "Mind Mup",
+ "Company Link ": "https://mindmup.com"
+ },
+ {
+ "Company Name": "Mixlr",
+ "Company Link ": "https://mixlr.com"
+ },
+ {
+ "Company Name": "Moises AI",
+ "Company Link ": "https://moises.ai"
+ },
+ {
+ "Company Name": "Money",
+ "Company Link ": "https://money.com"
+ },
+ {
+ "Company Name": "Mountain Project",
+ "Company Link ": "https://mountainproject.com"
+ },
+ {
+ "Company Name": "Movie Map",
+ "Company Link ": "https://movie-map.com"
+ },
+ {
+ "Company Name": "Movie Sounds",
+ "Company Link ": "https://movie-sounds.org"
+ },
+ {
+ "Company Name": "MP3Cut",
+ "Company Link ": "https://mp3cut.net"
+ },
+ {
+ "Company Name": "Murmel",
+ "Company Link ": "https://murmel.social"
+ },
+ {
+ "Company Name": "Muscle Wiki",
+ "Company Link ": "https://musclewiki.com"
+ },
+ {
+ "Company Name": "Music-Map",
+ "Company Link ": "https://music-map.com"
+ },
+ {
+ "Company Name": "MusicTheory.net",
+ "Company Link ": "https://musictheory.net"
+ },
+ {
+ "Company Name": "MyFonts",
+ "Company Link ": "https://myfonts.com"
+ },
+ {
+ "Company Name": "MyFridgeFood",
+ "Company Link ": "https://myfridgefood.com"
+ },
+ {
+ "Company Name": "Nameberry",
+ "Company Link ": "https://nameberry.com"
+ },
+ {
+ "Company Name": "Namechk",
+ "Company Link ": "https://namechk.com"
+ },
+ {
+ "Company Name": "Ncase",
+ "Company Link ": "https://ncase.me"
+ },
+ {
+ "Company Name": "News in Levels",
+ "Company Link ": "https://newsinlevels.com"
+ },
+ {
+ "Company Name": "Noisli",
+ "Company Link ": "https://noisli.com"
+ },
+ {
+ "Company Name": "Notes.io",
+ "Company Link ": "https://notes.io"
+ },
+ {
+ "Company Name": "Novoresume",
+ "Company Link ": "https://novoresume.com"
+ },
+ {
+ "Company Name": "Ocoya",
+ "Company Link ": "https://ocoya.com"
+ },
+ {
+ "Company Name": "Old Computers Museum",
+ "Company Link ": "https://oldcomputers.net"
+ },
+ {
+ "Company Name": "Online Tone Generator",
+ "Company Link ": "https://onlinetonegenerator.com"
+ },
+ {
+ "Company Name": "Online-Convert",
+ "Company Link ": "https://online-convert.com"
+ },
+ {
+ "Company Name": "OnlineConversion",
+ "Company Link ": "https://onlineconversion.com"
+ },
+ {
+ "Company Name": "Online OCR",
+ "Company Link ": "https://onlineocr.net"
+ },
+ {
+ "Company Name": "OpenWeatherMap",
+ "Company Link ": "https://openweathermap.org"
+ },
+ {
+ "Company Name": "OrgPad",
+ "Company Link ": "https://orgpad.com"
+ },
+ {
+ "Company Name": "Passport Index",
+ "Company Link ": "https://passportindex.org"
+ },
+ {
+ "Company Name": "PDF Candy",
+ "Company Link ": "https://pdfcandy.com"
+ },
+ {
+ "Company Name": "PDF2DOC",
+ "Company Link ": "https://pdf2doc.com"
+ },
+ {
+ "Company Name": "PDFescape",
+ "Company Link ": "https://pdfescape.com"
+ },
+ {
+ "Company Name": "PfpMaker",
+ "Company Link ": "https://pfpmaker.com"
+ },
+ {
+ "Company Name": "PIDGI Wiki ",
+ "Company Link ": "https://pidgi.net"
+ },
+ {
+ "Company Name": "PimEyes",
+ "Company Link ": "https://pimeyes.com"
+ },
+ {
+ "Company Name": "Pipl ",
+ "Company Link ": "https://pipl.com"
+ },
+ {
+ "Company Name": "PixelBazaar",
+ "Company Link ": "https://pixelbazaar.com"
+ },
+ {
+ "Company Name": "PixelPaper",
+ "Company Link ": "https://pixelpaper.io"
+ },
+ {
+ "Company Name": "Ponly",
+ "Company Link ": "https://ponly.com"
+ },
+ {
+ "Company Name": "PowerToFly",
+ "Company Link ": "https://powertofly.com"
+ },
+ {
+ "Company Name": "Pretzel Rocks",
+ "Company Link ": "https://pretzel.rocks"
+ },
+ {
+ "Company Name": "PrintIt",
+ "Company Link ": "https://printit.work"
+ },
+ {
+ "Company Name": "Prismatext",
+ "Company Link ": "https://prismatext.com"
+ },
+ {
+ "Company Name": "Puffin Maps",
+ "Company Link ": "https://puffinmaps.com"
+ },
+ {
+ "Company Name": "Puzzle Loop ",
+ "Company Link ": "https://puzzle-loop.com"
+ },
+ {
+ "Company Name": "QuoteMaster",
+ "Company Link ": "https://quotemaster.org"
+ },
+ {
+ "Company Name": "Radio Garden",
+ "Company Link ": "https://radio.garden"
+ },
+ {
+ "Company Name": "Radiooooo",
+ "Company Link ": "https://radiooooo.com"
+ },
+ {
+ "Company Name": "Radiosondy",
+ "Company Link ": "https://radiosondy.info"
+ },
+ {
+ "Company Name": "Rainy Mood",
+ "Company Link ": "https://rainymood.com"
+ },
+ {
+ "Company Name": "Random Street View",
+ "Company Link ": "https://randomstreetview.com"
+ },
+ {
+ "Company Name": "Rap4Ever",
+ "Company Link ": "https://rap4all.com"
+ },
+ {
+ "Company Name": "RareFilm",
+ "Company Link ": "https://rarefilm.net"
+ },
+ {
+ "Company Name": "Rattibha",
+ "Company Link ": "https://rattibha.com"
+ },
+ {
+ "Company Name": "Reddit List ",
+ "Company Link ": "https://redditlist.com"
+ },
+ {
+ "Company Name": "RedditSearch.io",
+ "Company Link ": "https://redditsearch.io"
+ },
+ {
+ "Company Name": "Reelgood",
+ "Company Link ": "https://reelgood.com"
+ },
+ {
+ "Company Name": "Reface",
+ "Company Link ": "https://reface.ai"
+ },
+ {
+ "Company Name": "Rejected.us",
+ "Company Link ": "https://rejected.us"
+ },
+ {
+ "Company Name": "Relanote",
+ "Company Link ": "https://relanote.com"
+ },
+ {
+ "Company Name": "Remote Leaf",
+ "Company Link ": "https://remoteleaf.com"
+ },
+ {
+ "Company Name": "Remote OK",
+ "Company Link ": "https://remoteok.com"
+ },
+ {
+ "Company Name": "Remote Starter Kit ",
+ "Company Link ": "https://remotestarterkit.com"
+ },
+ {
+ "Company Name": "Remote.co",
+ "Company Link ": "https://remote.co"
+ },
+ {
+ "Company Name": "Remote Base ",
+ "Company Link ": "https://remotebase.com"
+ },
+ {
+ "Company Name": "Remote Bear",
+ "Company Link ": "https://remotebear.io"
+ },
+ {
+ "Company Name": "Remove.bg",
+ "Company Link ": "https://remove.bg"
+ },
+ {
+ "Company Name": "Respresso",
+ "Company Link ": "https://respresso.io"
+ },
+ {
+ "Company Name": "Reveddit",
+ "Company Link ": "https://reveddit.com"
+ },
+ {
+ "Company Name": "Rhymer",
+ "Company Link ": "https://rhymer.com"
+ },
+ {
+ "Company Name": "RhymeZone",
+ "Company Link ": "https://rhymezone.com"
+ },
+ {
+ "Company Name": "Ribbet",
+ "Company Link ": "https://ribbet.com"
+ },
+ {
+ "Company Name": "Roadmap.sh",
+ "Company Link ": "https://roadmap.sh"
+ },
+ {
+ "Company Name": "Roadtrippers",
+ "Company Link ": "https://roadtrippers.com"
+ },
+ {
+ "Company Name": "RxResu.me",
+ "Company Link ": "https://rxresu.me"
+ },
+ {
+ "Company Name": "SchemeColor",
+ "Company Link ": "https://schemecolor.com"
+ },
+ {
+ "Company Name": "Screenshot.Guru",
+ "Company Link ": "https://screenshot.guru"
+ },
+ {
+ "Company Name": "SeatGuru",
+ "Company Link ": "https://seatguru.com"
+ },
+ {
+ "Company Name": "Sessions",
+ "Company Link ": "https://sessions.us"
+ },
+ {
+ "Company Name": "Shottr",
+ "Company Link ": "https://shottr.cc"
+ },
+ {
+ "Company Name": "Signature Maker",
+ "Company Link ": "https://signature-maker.net"
+ },
+ {
+ "Company Name": "Skip The Drive",
+ "Company Link ": "https://skipthedrive.com"
+ },
+ {
+ "Company Name": "Slowby",
+ "Company Link ": "https://slowby.travel"
+ },
+ {
+ "Company Name": "Small World",
+ "Company Link ": "https://smallworld.kiwi"
+ },
+ {
+ "Company Name": "SmallPDF",
+ "Company Link ": "https://smallpdf.com"
+ },
+ {
+ "Company Name": "Social Image Maker",
+ "Company Link ": "https://socialimagemaker.io"
+ },
+ {
+ "Company Name": "Social Sizes",
+ "Company Link ": "https://socialsizes.io"
+ },
+ {
+ "Company Name": "SoundLove",
+ "Company Link ": "https://soundlove.se"
+ },
+ {
+ "Company Name": "Spline",
+ "Company Link ": "https://spline.design"
+ },
+ {
+ "Company Name": "Starkey Comics",
+ "Company Link ": "https://starkeycomics.com"
+ },
+ {
+ "Company Name": "Startups List",
+ "Company Link ": "https://startups-list.com"
+ },
+ {
+ "Company Name": "Statista",
+ "Company Link ": "https://statista.com"
+ },
+ {
+ "Company Name": "Stolen Camera Finder",
+ "Company Link ": "https://stolencamerafinder.com"
+ },
+ {
+ "Company Name": "Strobe.Cool",
+ "Company Link ": "https://strobe.cool"
+ },
+ {
+ "Company Name": "Sumo",
+ "Company Link ": "https://sumo.app"
+ },
+ {
+ "Company Name": "SuperMeme AI",
+ "Company Link ": "https://supermeme.ai"
+ },
+ {
+ "Company Name": "Synthesia",
+ "Company Link ": "https://synthesia.io"
+ },
+ {
+ "Company Name": "TablerIcons",
+ "Company Link ": "https://tablericons.com"
+ },
+ {
+ "Company Name": "Tango",
+ "Company Link ": "https://tango.us"
+ },
+ {
+ "Company Name": "TasteDive",
+ "Company Link ": "https://tastedive.com"
+ },
+ {
+ "Company Name": "TechSpecs",
+ "Company Link ": "https://techspecs.io"
+ },
+ {
+ "Company Name": "Teoria",
+ "Company Link ": "https://teoria.com"
+ },
+ {
+ "Company Name": "Text Faces",
+ "Company Link ": "https://textfac.es"
+ },
+ {
+ "Company Name": "The Balance Money",
+ "Company Link ": "https://thebalancemoney.com"
+ },
+ {
+ "Company Name": "The Punctuation Guide",
+ "Company Link ": "https://thepunctuationguide.com"
+ },
+ {
+ "Company Name": "This to That",
+ "Company Link ": "https://thistothat.com"
+ },
+ {
+ "Company Name": "This vs That",
+ "Company Link ": "https://thisvsthat.io"
+ },
+ {
+ "Company Name": "ThreadReaderApp ",
+ "Company Link ": "https://threadreaderapp.com"
+ },
+ {
+ "Company Name": "Thumbly",
+ "Company Link ": "https://tokee.ai"
+ },
+ {
+ "Company Name": "Tiii.me",
+ "Company Link ": "https://tiii.me"
+ },
+ {
+ "Company Name": "TikTok Video Downloader",
+ "Company Link ": "https://ttvdl.com"
+ },
+ {
+ "Company Name": "Time and Date",
+ "Company Link ": "https://timeanddate.com"
+ },
+ {
+ "Company Name": "Time.is",
+ "Company Link ": "https://time.is"
+ },
+ {
+ "Company Name": "Title Case",
+ "Company Link ": "https://titlecase.com"
+ },
+ {
+ "Company Name": "Toaster Central",
+ "Company Link ": "https://toastercentral.com"
+ },
+ {
+ "Company Name": "Tongue-Twister ",
+ "Company Link ": "https://tongue-twister.net"
+ },
+ {
+ "Company Name": "TradingView",
+ "Company Link ": "https://tradingview.com"
+ },
+ {
+ "Company Name": "Transparent Textures",
+ "Company Link ": "https://transparenttextures.com"
+ },
+ {
+ "Company Name": "Tubi TV",
+ "Company Link ": "https://tubitv.com"
+ },
+ {
+ "Company Name": "Tunefind",
+ "Company Link ": "https://tunefind.com"
+ },
+ {
+ "Company Name": "TuneMyMusic",
+ "Company Link ": "https://tunemymusic.com"
+ },
+ {
+ "Company Name": "Tweepsmap",
+ "Company Link ": "https://fedica.com"
+ },
+ {
+ "Company Name": "Two Peas and Their Pod",
+ "Company Link ": "https://twopeasandtheirpod.com"
+ },
+ {
+ "Company Name": "Typatone",
+ "Company Link ": "https://typatone.com"
+ },
+ {
+ "Company Name": "Under Glass",
+ "Company Link ": "https://underglass.io"
+ },
+ {
+ "Company Name": "UniCorner",
+ "Company Link ": "https://unicorner.news"
+ },
+ {
+ "Company Name": "Unita",
+ "Company Link ": "https://unita.co"
+ },
+ {
+ "Company Name": "UnitConverters",
+ "Company Link ": "https://unitconverters.net"
+ },
+ {
+ "Company Name": "Unreadit",
+ "Company Link ": "https://unreadit.com"
+ },
+ {
+ "Company Name": "Unscreen",
+ "Company Link ": "https://unscreen.com"
+ },
+ {
+ "Company Name": "UnTools ",
+ "Company Link ": "https://untools.co"
+ },
+ {
+ "Company Name": "Upwork",
+ "Company Link ": "https://upwork.com"
+ },
+ {
+ "Company Name": "UTF8 Icons",
+ "Company Link ": "https://utf8icons.com"
+ },
+ {
+ "Company Name": "Vector Magic",
+ "Company Link ": "https://vectormagic.com"
+ },
+ {
+ "Company Name": "Virtual Vacation",
+ "Company Link ": "https://virtualvacation.us"
+ },
+ {
+ "Company Name": "Virtual Vocations",
+ "Company Link ": "https://virtualvocations.com"
+ },
+ {
+ "Company Name": "Visiwig",
+ "Company Link ": "https://visiwig.com"
+ },
+ {
+ "Company Name": "Visual CV",
+ "Company Link ": "https://visualcv.com"
+ },
+ {
+ "Company Name": "Vocus.io",
+ "Company Link ": "https://vocus.io"
+ },
+ {
+ "Company Name": "Voscreen",
+ "Company Link ": "https://voscreen.com"
+ },
+ {
+ "Company Name": "Wanderprep",
+ "Company Link ": "https://wanderprep.com"
+ },
+ {
+ "Company Name": "Warmshowers",
+ "Company Link ": "https:/warmshowers.org"
+ },
+ {
+ "Company Name": "Watch Documentaries",
+ "Company Link ": "https://watchdocumentaries.com"
+ },
+ {
+ "Company Name": "We Work Remotely",
+ "Company Link ": "https://weworkremotely.com"
+ },
+ {
+ "Company Name": "Web2PDFConvert",
+ "Company Link ": "https://web2pdfconvert.com"
+ },
+ {
+ "Company Name": "Welcome to My Garden",
+ "Company Link ": "https://welcometomygarden.org"
+ },
+ {
+ "Company Name": "When2meet ",
+ "Company Link ": "https://when2meet.com"
+ },
+ {
+ "Company Name": "Where's George",
+ "Company Link ": "https://wheresgeorge.com"
+ },
+ {
+ "Company Name": "Where's Willy",
+ "Company Link ": "https://whereswilly.com"
+ },
+ {
+ "Company Name": "WikiHow",
+ "Company Link ": "https://wikihow.com"
+ },
+ {
+ "Company Name": "Windy",
+ "Company Link ": "https://www.windy.com"
+ },
+ {
+ "Company Name": "WonderHowTo",
+ "Company Link ": "https://wonderhowto.com"
+ },
+ {
+ "Company Name": "Working Nomads",
+ "Company Link ": "https://workingnomads.com"
+ },
+ {
+ "Company Name": "Wormhole",
+ "Company Link ": "https://wormhole.app"
+ },
+ {
+ "Company Name": "Y Combinator Jobs",
+ "Company Link ": "https://ycombinator.com"
+ },
+ {
+ "Company Name": "Yes Promo",
+ "Company Link ": "https://yespromo.me"
+ },
+ {
+ "Company Name": "YouGlish",
+ "Company Link ": "https://youglish.com"
+ },
+ {
+ "Company Name": "Zamzar",
+ "Company Link ": "https://zamzar.com"
+ },
+ {
+ "Company Name": "Zippyshare",
+ "Company Link ": "https://zippyshare.com"
+ },
+ {
+ "Company Name": "Zoom Earth",
+ "Company Link ": "https://zoom.earth"
+ },
+ {
+ "Company Name": "Zoom.it",
+ "Company Link ": "https://zoom.it"
+ }
+]
\ No newline at end of file
diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js
index bfa4bd73a..276c0cf6f 100644
--- a/Server/db/mongo/modules/monitorModule.js
+++ b/Server/db/mongo/modules/monitorModule.js
@@ -302,8 +302,16 @@ const getMonitorById = async (monitorId) => {
*/
const getMonitorsByTeamId = async (req, res) => {
try {
- let { limit, type, status, sortOrder, normalize } = req.query || {};
+ let { limit, type, status, sortOrder, normalize, page, rowsPerPage } =
+ req.query || {};
const monitorQuery = { teamId: req.params.teamId };
+ const monitorsCount = await Monitor.countDocuments(monitorQuery);
+
+ // Pagination
+ let skip = 0;
+ if (page && rowsPerPage) {
+ skip = page * rowsPerPage;
+ }
if (type !== undefined) {
const types = Array.isArray(type) ? type : [type];
@@ -320,7 +328,9 @@ const getMonitorsByTeamId = async (req, res) => {
// This effectively removes limit, returning all checks
if (limit === undefined) limit = 0;
- const monitors = await Monitor.find(monitorQuery);
+ const monitors = await Monitor.find(monitorQuery)
+ .skip(skip)
+ .limit(rowsPerPage);
// Map each monitor to include its associated checks
const monitorsWithChecks = await Promise.all(
monitors.map(async (monitor) => {
@@ -349,7 +359,7 @@ const getMonitorsByTeamId = async (req, res) => {
return { ...monitor.toObject(), checks };
})
);
- return monitorsWithChecks;
+ return { monitors: monitorsWithChecks, monitorCount: monitorsCount };
} catch (error) {
throw error;
}
diff --git a/Server/validation/joi.js b/Server/validation/joi.js
index d0ef24751..090a49a7a 100644
--- a/Server/validation/joi.js
+++ b/Server/validation/joi.js
@@ -176,6 +176,8 @@ const getMonitorsByTeamIdQueryValidation = joi.object({
joi.string().valid("http", "ping", "pagespeed"),
joi.array().items(joi.string().valid("http", "ping", "pagespeed"))
),
+ page: joi.number(),
+ rowsPerPage: joi.number(),
});
const getMonitorStatsByIdParamValidation = joi.object({