From 0ad08f431ee84b6ed2d5baf549a9247fa714c66f Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Tue, 20 Aug 2024 20:33:28 +0330 Subject: [PATCH 01/19] Marshali data, logging it, creating post req, send to BE --- Client/package-lock.json | 2 +- Client/package.json | 2 +- .../CreateMaintenanceWindow/index.jsx | 25 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Client/package-lock.json b/Client/package-lock.json index 44e276f63..2f1543bba 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -18,7 +18,7 @@ "@mui/x-data-grid": "7.3.2", "@mui/x-date-pickers": "7.3.2", "@reduxjs/toolkit": "2.2.5", - "axios": "1.7.4", + "axios": "^1.7.4", "chart.js": "^4.4.3", "dayjs": "1.11.11", "joi": "17.13.1", diff --git a/Client/package.json b/Client/package.json index 769e1f4a6..22f15f7f9 100644 --- a/Client/package.json +++ b/Client/package.json @@ -20,7 +20,7 @@ "@mui/x-data-grid": "7.3.2", "@mui/x-date-pickers": "7.3.2", "@reduxjs/toolkit": "2.2.5", - "axios": "1.7.4", + "axios": "^1.7.4", "chart.js": "^4.4.3", "dayjs": "1.11.11", "joi": "17.13.1", diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx index 8fff6e4a1..a5cbfaf56 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx @@ -10,6 +10,7 @@ import dayjs from "dayjs"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { MobileTimePicker } from "@mui/x-date-pickers/MobileTimePicker"; import Field from "../../../Components/Inputs/Field"; +import axios from "axios"; const directory = { title: "Create a maintenance window", @@ -71,6 +72,29 @@ const CreateNewMaintenanceWindow = () => { })); }; + const handleSubmit = async () => { + const data = { + repeat: values.repeat, + date: values.date.format("YYYY-MM-DD"), + startTime: values.startTime.format("HH:mm"), + duration: values.duration, + unit: values.unit, + friendlyName: values.friendlyName, + addMonitors: values.AddMonitors, + }; + + console.log("Submitting data: ", data); + + await axios + .post("/address-of-the-route", data) + .then((res) => { + console.log("Response: ", res.data); + }) + .catch((err) => { + console.log("Error: ", err); + }); + }; + const configOptions = [ { title: "Repeat", @@ -246,6 +270,7 @@ const CreateNewMaintenanceWindow = () => { }} level="primary" label="Create" + onClick={handleSubmit} /> From b247fabde0168a8cf639a24f9a1f1d3161edd796 Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Wed, 21 Aug 2024 09:40:09 +0330 Subject: [PATCH 02/19] adding validations and toasts as validation error --- .../CreateMaintenanceWindow/index.jsx | 33 ++++++++---- Client/src/Validation/validation.js | 52 +++++++++++++++---- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx index a5cbfaf56..c4789f883 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx @@ -10,7 +10,9 @@ import dayjs from "dayjs"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { MobileTimePicker } from "@mui/x-date-pickers/MobileTimePicker"; import Field from "../../../Components/Inputs/Field"; -import axios from "axios"; +import { maintenanceWindowValidation } from "../../../Validation/validation"; +import { logger } from "../../../Utils/Logger"; +import { createToast } from "../../../Utils/toastUtils"; const directory = { title: "Create a maintenance window", @@ -63,6 +65,7 @@ const CreateNewMaintenanceWindow = () => { friendlyName: "", AddMonitors: "", }); + const [errors, setErrors] = useState({}); const handleChange = (event, name) => { const { value } = event.target; @@ -83,16 +86,26 @@ const CreateNewMaintenanceWindow = () => { addMonitors: values.AddMonitors, }; - console.log("Submitting data: ", data); - - await axios - .post("/address-of-the-route", data) - .then((res) => { - console.log("Response: ", res.data); - }) - .catch((err) => { - console.log("Error: ", err); + const { error } = maintenanceWindowValidation.validate(data, { + abortEarly: false, + }); + logger.log("error: ", error); + if (error) { + const newErrors = {}; + error.details.forEach((err) => { + newErrors[err.path[0]] = err.message; }); + setErrors(newErrors); + createToast({ + body: + error.details && error.details.length > 0 + ? error.details[0].message + : "Error validating data", + }); + logger.error("Validation errors:", error.details); + } + + logger.log("Submitting data: ", data); }; const configOptions = [ diff --git a/Client/src/Validation/validation.js b/Client/src/Validation/validation.js index ab2501199..6719c2c1c 100644 --- a/Client/src/Validation/validation.js +++ b/Client/src/Validation/validation.js @@ -72,14 +72,10 @@ const credentials = joi.object({ }); const monitorValidation = joi.object({ - url: joi - .string() - .uri({ allowRelative: true }) - .trim() - .messages({ - "string.empty": "This field is required.", - "string.uri": "The URL you provided is not valid.", - }), + url: joi.string().uri({ allowRelative: true }).trim().messages({ + "string.empty": "This field is required.", + "string.uri": "The URL you provided is not valid.", + }), name: joi.string().trim().max(50).allow("").messages({ "string.max": "This field should not exceed the 50 characters limit.", }), @@ -108,4 +104,42 @@ const imageValidation = joi.object({ }), }); -export { credentials, imageValidation, monitorValidation }; +const maintenanceWindowValidation = joi.object({ + repeat: joi.number().valid(1, 2, 3).required().messages({ + "number.base": "Repeat must be a number.", + "any.only": "Repeat must be one of [1, 2, 3].", + "any.required": "Repeat is required.", + }), + date: joi.date().required().messages({ + "date.base": "Date must be a valid date.", + "any.required": "Date is required.", + }), + startTime: joi.string().required().messages({ + "string.base": "Start time must be a valid time.", + "any.required": "Start time is required.", + }), + duration: joi.number().required().messages({ + "number.base": "Duration must be a number.", + "any.required": "Duration is required.", + }), + unit: joi.string().valid("minutes", "hours", "days").required().messages({ + "string.base": "Unit must be a string.", + "any.only": "Unit must be one of ['minutes', 'hours', 'days'].", + "any.required": "Unit is required.", + }), + friendlyName: joi.string().required().max(100).messages({ + "string.max": "Friendly name must be less than 100 characters.", + "any.required": "Friendly name is required.", + }), + addMonitors: joi.string().required().messages({ + "string.base": "Add monitors must be a string.", + "any.required": "Add monitors is required.", + }), +}); + +export { + credentials, + imageValidation, + monitorValidation, + maintenanceWindowValidation, +}; From aecddb22bbf34907bcf8e7b996a347f62b73829f Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Wed, 21 Aug 2024 22:50:42 +0330 Subject: [PATCH 03/19] validation helper texts and input type --- .../Maintenance/CreateMaintenanceWindow/index.jsx | 3 +++ Client/src/Validation/validation.js | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx index c4789f883..eb19ba3d2 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx @@ -163,6 +163,7 @@ const CreateNewMaintenanceWindow = () => { placeholder="60" onChange={(e) => handleChange(e, "duration")} value={values.duration} + error={errors.duration} /> handleChange(e, "unit")} From d81bb8fe89c4bf10adef00ee0bb2ed9c8e7ddbe0 Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Thu, 22 Aug 2024 20:23:17 +0330 Subject: [PATCH 05/19] fixes --- Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css index e0311d4e7..4ee17db72 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css @@ -23,7 +23,7 @@ } .duration-config .field-text .MuiTextField-root, -.duration-config .field { +.maintenance-options .duration-config .field { width: 70px; min-width: 70px; max-width: 70px; From 81072cf767d7806c8da9184d2d07d193f0ba7cae Mon Sep 17 00:00:00 2001 From: "Gorkem Cetin (BWL)" <167266851+gorkem-bwl@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:15:19 -0400 Subject: [PATCH 06/19] Add video instead --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index adb9bc68f..9cbd37355 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,11 @@

An open source server monitoring application

-![Dashboard](https://github.com/user-attachments/assets/0f92d7a3-19cf-430c-8b0f-fe13ff46c51b) + +https://github.com/user-attachments/assets/c8234cce-edf8-4d7e-8f6b-f18b06669fcc + + + BlueWave Uptime is an open source server monitoring application used to track the operational status and performance of servers and websites. It regularly checks whether a server/website is accessible and performs optimally, providing real-time alerts and reports on the monitored services' availability, downtime, and response time. From f5e589886b1284a3d61870e424a6bb7001f0c01f Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Sat, 24 Aug 2024 10:11:13 +0330 Subject: [PATCH 07/19] adding the type number --- Client/src/Components/Inputs/Field/index.jsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Client/src/Components/Inputs/Field/index.jsx b/Client/src/Components/Inputs/Field/index.jsx index 0b2fe56fe..f44201e3f 100644 --- a/Client/src/Components/Inputs/Field/index.jsx +++ b/Client/src/Components/Inputs/Field/index.jsx @@ -177,7 +177,14 @@ const Field = forwardRef( ); Field.propTypes = { - type: PropTypes.oneOf(["text", "password", "url", "email", "description"]), + type: PropTypes.oneOf([ + "text", + "password", + "url", + "email", + "description", + "number", + ]), id: PropTypes.string.isRequired, label: PropTypes.string, https: PropTypes.bool, From 63ae25c16b79cb7aacd8573136977bfa87c23be9 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Sat, 24 Aug 2024 11:49:28 -0400 Subject: [PATCH 08/19] Removed url button link, tweaked typography and paddings --- Client/src/Components/BasicTable/index.css | 16 +- Client/src/Components/BasicTable/index.jsx | 6 +- Client/src/Components/Sidebar/index.css | 3 + .../Pages/Monitors/CreateMonitor/index.jsx | 2 +- Client/src/Pages/Monitors/index.css | 14 +- Client/src/Pages/Monitors/index.jsx | 143 +++++++++++++----- 6 files changed, 141 insertions(+), 43 deletions(-) diff --git a/Client/src/Components/BasicTable/index.css b/Client/src/Components/BasicTable/index.css index 47a47439d..208604021 100644 --- a/Client/src/Components/BasicTable/index.css +++ b/Client/src/Components/BasicTable/index.css @@ -5,8 +5,7 @@ white-space: nowrap; } .MuiTable-root .host span { - font-size: var(--env-var-font-size-small); - margin-left: 8px; + font-size: 11px; } .MuiTable-root .label { @@ -180,3 +179,16 @@ body:has(.pagination-dropdown) p:has(+ .MuiTablePagination-root) { body:has(.pagination-dropdown) p:has(+ .MuiTablePagination-root) { font-size: var(--env-var-font-size-small-plus); } + +.monitors .MuiTable-root .MuiTableHead-root .MuiTableCell-root { + text-transform: uppercase; + color: var(--env-var-color-5); + opacity: 0.8; + font-size: var(--env-var-font-size-small-plus); + font-weight: 400; +} +.monitors .MuiTableCell-root:not(:first-of-type):not(:last-of-type), +.monitors .MuiTableCell-root:not(:first-of-type):not(:last-of-type) { + padding-left: var(--env-var-spacing-1); + padding-right: var(--env-var-spacing-1); +} diff --git a/Client/src/Components/BasicTable/index.jsx b/Client/src/Components/BasicTable/index.jsx index bef5bd651..c723d2bec 100644 --- a/Client/src/Components/BasicTable/index.jsx +++ b/Client/src/Components/BasicTable/index.jsx @@ -233,6 +233,7 @@ const BasicTable = ({ data, paginated, reversed, table }) => { direction="row" alignItems="center" justifyContent="space-between" + px={theme.gap.small} > Showing {getRange()} of {data.rows.length} monitor(s) @@ -277,7 +278,10 @@ const BasicTable = ({ data, paginated, reversed, table }) => { }, }, }} - sx={{ mt: theme.gap.medium }} + sx={{ + mt: theme.gap.medium, + color: theme.palette.otherColors.bluishGray, + }} /> )} diff --git a/Client/src/Components/Sidebar/index.css b/Client/src/Components/Sidebar/index.css index 8ce0089bc..4c253c781 100644 --- a/Client/src/Components/Sidebar/index.css +++ b/Client/src/Components/Sidebar/index.css @@ -15,6 +15,9 @@ aside span.MuiTypography-root { font-size: var(--env-var-font-size-medium); line-height: 1; } +aside .MuiStack-root + span.MuiTypography-root { + font-size: var(--env-var-font-size-medium-plus); +} aside .MuiListSubheader-root { font-size: var(--env-var-font-size-small); font-weight: 500; diff --git a/Client/src/Pages/Monitors/CreateMonitor/index.jsx b/Client/src/Pages/Monitors/CreateMonitor/index.jsx index 28493080a..a637525ad 100644 --- a/Client/src/Pages/Monitors/CreateMonitor/index.jsx +++ b/Client/src/Pages/Monitors/CreateMonitor/index.jsx @@ -98,7 +98,7 @@ const CreateMonitor = () => { monitor.type === "http" ? `http${https ? "s" : ""}://` + monitor.url : monitor.url, - name: monitor.name === "" ? monitor.url : monitor.name, + name: monitor.name, type: monitor.type, interval: monitor.interval * MS_PER_MINUTE, }; diff --git a/Client/src/Pages/Monitors/index.css b/Client/src/Pages/Monitors/index.css index 1f46b3517..43c43f3c8 100644 --- a/Client/src/Pages/Monitors/index.css +++ b/Client/src/Pages/Monitors/index.css @@ -1,7 +1,10 @@ -.monitors h1.MuiTypography-root, -.monitors h2.MuiTypography-root { +.monitors h1.MuiTypography-root { color: var(--env-var-color-1); - font-weight: 600; + font-weight: 500; +} +.monitors h2.MuiTypography-root { + color: var(--env-var-color-5); + font-weight: 500; } .monitors h1.MuiTypography-root { font-size: var(--env-var-font-size-large-plus); @@ -13,6 +16,9 @@ font-size: var(--env-var-font-size-medium); color: var(--env-var-color-5); } +.monitors h1.MuiTypography-root + p.MuiTypography-root { + font-size: var(--env-var-font-size-medium-plus); +} .monitors .MuiStack-root > button:not(.MuiIconButton-root) { font-size: var(--env-var-font-size-medium); height: var(--env-var-height-2); @@ -31,7 +37,7 @@ border-radius: 50%; font-size: var(--env-var-font-size-medium); font-weight: 500; - color: var(--env-var-color-5); + color: var(--env-var-color-1); margin-left: 10px; line-height: 0.8; } diff --git a/Client/src/Pages/Monitors/index.jsx b/Client/src/Pages/Monitors/index.jsx index 9eef7ec3a..a91939e85 100644 --- a/Client/src/Pages/Monitors/index.jsx +++ b/Client/src/Pages/Monitors/index.jsx @@ -1,4 +1,3 @@ -import "./index.css"; import { useEffect, useState } from "react"; import { useSelector, useDispatch } from "react-redux"; import { @@ -6,11 +5,7 @@ import { getUptimeMonitorsByUserId, } from "../../Features/UptimeMonitors/uptimeMonitorsSlice"; import { useNavigate } from "react-router-dom"; -import Button from "../../Components/Button"; -import ServerStatus from "../../Components/Charts/Servers/ServerStatus"; import { useTheme } from "@emotion/react"; -import ArrowDownwardRoundedIcon from "@mui/icons-material/ArrowDownwardRounded"; -import BasicTable from "../../Components/BasicTable"; import { StatusLabel } from "../../Components/Label"; import { createToast } from "../../Utils/toastUtils"; import { @@ -23,10 +18,15 @@ import { Stack, Typography, } from "@mui/material"; - +import BasicTable from "../../Components/BasicTable"; +import Button from "../../Components/Button"; +import ServerStatus from "../../Components/Charts/Servers/ServerStatus"; import Settings from "../../assets/icons/settings-bold.svg?react"; import PropTypes from "prop-types"; import BarChart from "../../Components/Charts/BarChart"; +import Breadcrumbs from "../../Components/Breadcrumbs"; +import ArrowDownwardRoundedIcon from "@mui/icons-material/ArrowDownwardRounded"; +import "./index.css"; const ActionsMenu = ({ monitor }) => { const [anchorEl, setAnchorEl] = useState(null); @@ -177,7 +177,10 @@ const ActionsMenu = ({ monitor }) => {