diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js index 601dc016a..d472a673a 100644 --- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js +++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js @@ -40,7 +40,7 @@ export const checkEndpointResolution = createAsyncThunk( const res = await networkService.checkEndpointResolution({ authToken: authToken, monitorURL: monitorURL, - }) + }); return res.data; } catch (error) { if (error.response && error.response.data) { @@ -53,7 +53,7 @@ export const checkEndpointResolution = createAsyncThunk( return thunkApi.rejectWithValue(payload); } } -) +); export const getUptimeMonitorById = createAsyncThunk( "monitors/getMonitorById", @@ -86,7 +86,7 @@ export const getUptimeMonitorsByTeamId = createAsyncThunk( const res = await networkService.getMonitorsAndSummaryByTeamId({ authToken: token, teamId: user.teamId, - types: ["http", "ping"], + types: ["http", "ping", "docker"], }); return res.data; } catch (error) { diff --git a/Client/src/Pages/Monitors/CreateMonitor/index.jsx b/Client/src/Pages/Monitors/CreateMonitor/index.jsx index bfa62c7fa..18c1df0b4 100644 --- a/Client/src/Pages/Monitors/CreateMonitor/index.jsx +++ b/Client/src/Pages/Monitors/CreateMonitor/index.jsx @@ -1,10 +1,10 @@ import { useState, useEffect } from "react"; import { Box, Button, ButtonGroup, Stack, Typography } from "@mui/material"; -import LoadingButton from '@mui/lab/LoadingButton'; +import LoadingButton from "@mui/lab/LoadingButton"; import { useSelector, useDispatch } from "react-redux"; import { monitorValidation } from "../../../Validation/validation"; import { createUptimeMonitor } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice"; -import { checkEndpointResolution } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice" +import { checkEndpointResolution } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice"; import { useNavigate, useParams } from "react-router-dom"; import { useTheme } from "@emotion/react"; import { createToast } from "../../../Utils/toastUtils"; @@ -19,21 +19,40 @@ import { getUptimeMonitorById } from "../../../Features/UptimeMonitors/uptimeMon import "./index.css"; const CreateMonitor = () => { - const MS_PER_MINUTE = 60000; - const { user, authToken } = useSelector((state) => state.auth); - const { monitors, isLoading } = useSelector((state) => state.uptimeMonitors); - const dispatch = useDispatch(); - const navigate = useNavigate(); - const theme = useTheme(); + const MS_PER_MINUTE = 60000; + const { user, authToken } = useSelector((state) => state.auth); + const { monitors, isLoading } = useSelector((state) => state.uptimeMonitors); + const dispatch = useDispatch(); + const navigate = useNavigate(); + const theme = useTheme(); const idMap = { "monitor-url": "url", "monitor-name": "name", "monitor-checks-http": "type", "monitor-checks-ping": "type", + "monitor-checks-docker": "type", "notify-email-default": "notification-email", }; + const monitorTypeMaps = { + http: { + label: "URL to monitor", + placeholder: "google.com", + namePlaceholder: "Google", + }, + ping: { + label: "IP address to monitor", + placeholder: "1.1.1.1", + namePlaceholder: "Google", + }, + docker: { + label: "Container ID", + placeholder: "abc123", + namePlaceholder: "My Container", + }, + }; + const { monitorId } = useParams(); const [monitor, setMonitor] = useState({ url: "", @@ -112,7 +131,6 @@ const CreateMonitor = () => { { [name]: value }, { abortEarly: false } ); - console.log(error); setErrors((prev) => { const updatedErrors = { ...prev }; if (error) updatedErrors[name] = error.details[0].message; @@ -148,16 +166,18 @@ const CreateMonitor = () => { setErrors(newErrors); createToast({ body: "Error validation data." }); } else { - if (monitor.type === "http") { - const checkEndpointAction = await dispatch( - checkEndpointResolution({ authToken, monitorURL: form.url }) - ) - if (checkEndpointAction.meta.requestStatus === "rejected") { - createToast({ body: "The endpoint you entered doesn't resolve. Check the URL again." }); - setErrors({ url: "The entered URL is not reachable." }); - return; - } - } + if (monitor.type === "http") { + const checkEndpointAction = await dispatch( + checkEndpointResolution({ authToken, monitorURL: form.url }) + ); + if (checkEndpointAction.meta.requestStatus === "rejected") { + createToast({ + body: "The endpoint you entered doesn't resolve. Check the URL again.", + }); + setErrors({ url: "The entered URL is not reachable." }); + return; + } + } form = { ...form, @@ -232,9 +252,9 @@ const CreateMonitor = () => { { id="monitor-name" label="Display name" isOptional={true} - placeholder="Google" + placeholder={monitorTypeMaps[monitor.type].namePlaceholder || ""} value={monitor.name} onChange={handleChange} error={errors["name"]} @@ -299,6 +319,15 @@ const CreateMonitor = () => { checked={monitor.type === "ping"} onChange={(event) => handleChange(event)} /> + handleChange(event)} + /> {errors["type"] ? ( { direction="row" justifyContent="flex-end" > - - Create monitor - + + Create monitor + ); }; -export default CreateMonitor; \ No newline at end of file +export default CreateMonitor; diff --git a/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx b/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx index d9fbc34b2..5970a5c54 100644 --- a/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx +++ b/Client/src/Pages/Monitors/Home/MonitorTable/index.jsx @@ -150,7 +150,7 @@ const MonitorTable = ({ isAdmin, filter, setIsSearching, isSearching }) => { authToken, teamId: user.teamId, limit: 25, - types: ["http", "ping"], + types: ["http", "ping", "docker"], status: null, checkOrder: "desc", normalize: true, diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js index 28bf89d82..4d355141d 100644 --- a/Server/db/mongo/modules/monitorModule.js +++ b/Server/db/mongo/modules/monitorModule.js @@ -20,6 +20,7 @@ const SERVICE_NAME = "monitorModule"; const CHECK_MODEL_LOOKUP = { http: Check, ping: Check, + docker: Check, pagespeed: PageSpeedCheck, hardware: HardwareCheck, }; @@ -349,7 +350,7 @@ const getMonitorStatsById = async (req) => { ), }; - if (monitor.type === "http" || monitor.type === "ping") { + if (monitor.type === "http" || monitor.type === "ping" || monitor.type === "docker") { // HTTP/PING Specific stats monitorStats.periodAvgResponseTime = getAverageResponseTime(checksForDateRange); monitorStats.periodUptime = getUptimePercentage(checksForDateRange); diff --git a/Server/service/networkService.js b/Server/service/networkService.js index 23b3a62b1..60405df90 100644 --- a/Server/service/networkService.js +++ b/Server/service/networkService.js @@ -229,7 +229,7 @@ class NetworkService { }); const containers = await docker.listContainers({ all: true }); - const containerExists = containers.some((c) => c.Id === job.data.url); + const containerExists = containers.some((c) => c.Id.startsWith(job.data.url)); if (!containerExists) { throw new Error(errorMessages.DOCKER_NOT_FOUND); } diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 07521c7e0..82a732686 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -144,8 +144,8 @@ const getMonitorsAndSummaryByTeamIdQueryValidation = joi.object({ type: joi .alternatives() .try( - joi.string().valid("http", "ping", "pagespeed"), - joi.array().items(joi.string().valid("http", "ping", "pagespeed")) + joi.string().valid("http", "ping", "pagespeed", "docker"), + joi.array().items(joi.string().valid("http", "ping", "pagespeed", "docker")) ), }); @@ -161,8 +161,8 @@ const getMonitorsByTeamIdQueryValidation = joi.object({ type: joi .alternatives() .try( - joi.string().valid("http", "ping", "pagespeed"), - joi.array().items(joi.string().valid("http", "ping", "pagespeed")) + joi.string().valid("http", "ping", "pagespeed", "docker"), + joi.array().items(joi.string().valid("http", "ping", "pagespeed", "docker")) ), page: joi.number(), rowsPerPage: joi.number(),