From 40393f3fef31b6fe5843cd8a011ed41000541b90 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 10 Feb 2025 16:15:31 -0800 Subject: [PATCH 01/12] remove console.log --- Client/src/Pages/Maintenance/MaintenanceTable/index.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/Client/src/Pages/Maintenance/MaintenanceTable/index.jsx b/Client/src/Pages/Maintenance/MaintenanceTable/index.jsx index 9bdce5887..ea8a1d7a3 100644 --- a/Client/src/Pages/Maintenance/MaintenanceTable/index.jsx +++ b/Client/src/Pages/Maintenance/MaintenanceTable/index.jsx @@ -34,7 +34,6 @@ const MaintenanceTable = ({ updateCallback, }) => { const { rowsPerPage } = useSelector((state) => state.ui.maintenance); - console.log(rowsPerPage); const dispatch = useDispatch(); const handleChangePage = (event, newPage) => { @@ -175,8 +174,6 @@ const MaintenanceTable = ({ setSort({ field, order }); }; - console.log(handleChangePage); - return ( <> Date: Mon, 10 Feb 2025 16:15:48 -0800 Subject: [PATCH 02/12] fix success message --- Client/src/Pages/StatusPage/Create/index.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Client/src/Pages/StatusPage/Create/index.jsx b/Client/src/Pages/StatusPage/Create/index.jsx index 158aca2e9..f54189fe8 100644 --- a/Client/src/Pages/StatusPage/Create/index.jsx +++ b/Client/src/Pages/StatusPage/Create/index.jsx @@ -134,7 +134,11 @@ const CreateStatusPage = () => { if (typeof error === "undefined") { const success = await createStatusPage({ form }); if (success) { - createToast({ body: "Status page created successfully" }); + createToast({ + body: isCreate + ? "Status page created successfully" + : "Status page updated successfully", + }); navigate(`/status/uptime/${form.url}`); } return; From 6e58b6a630dfffe2e6f490e143b08f4af3d2aafe Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 10 Feb 2025 16:16:25 -0800 Subject: [PATCH 03/12] nav to /status/ --- .../StatusPage/Status/Components/ControlsHeader/index.jsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Client/src/Pages/StatusPage/Status/Components/ControlsHeader/index.jsx b/Client/src/Pages/StatusPage/Status/Components/ControlsHeader/index.jsx index 2c96db054..e8ea104b8 100644 --- a/Client/src/Pages/StatusPage/Status/Components/ControlsHeader/index.jsx +++ b/Client/src/Pages/StatusPage/Status/Components/ControlsHeader/index.jsx @@ -43,11 +43,7 @@ const Controls = ({ isDeleteOpen, setIsDeleteOpen, isDeleting, url, type }) => { variant="contained" color="secondary" onClick={() => { - if (type === "uptime") { - navigate(`/status/uptime/configure/${url}`); - } else { - navigate(`/status/distributed/configure/${url}`); - } + navigate(`/status/`); }} sx={{ px: theme.spacing(5), From 52172921255d5fafa4f56eed2d15c1e83310617d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 10 Feb 2025 16:17:07 -0800 Subject: [PATCH 04/12] don't show toast on 404 --- .../StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx b/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx index 7565f129a..29e7f2b89 100644 --- a/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx +++ b/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx @@ -20,7 +20,12 @@ const useStatusPagesFetch = () => { setStatusPages(res?.data?.data); } catch (error) { setNetworkError(true); - createToast(error.message, "error"); + if (error.response.status === 404) { + return; + } + createToast({ + body: error.message, + }); } finally { setIsLoading(false); } From 771a9c6c99d92397e71f1a79cc5473facf037a57 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 10 Feb 2025 16:17:35 -0800 Subject: [PATCH 05/12] update empty view, use table --- .../Components/StatusPagesTable/index.jsx | 85 +++++++++++++++++++ .../Pages/StatusPage/StatusPages/index.jsx | 20 ++--- 2 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 Client/src/Pages/StatusPage/StatusPages/Components/StatusPagesTable/index.jsx diff --git a/Client/src/Pages/StatusPage/StatusPages/Components/StatusPagesTable/index.jsx b/Client/src/Pages/StatusPage/StatusPages/Components/StatusPagesTable/index.jsx new file mode 100644 index 000000000..6e7988153 --- /dev/null +++ b/Client/src/Pages/StatusPage/StatusPages/Components/StatusPagesTable/index.jsx @@ -0,0 +1,85 @@ +import DataTable from "../../../../../Components/Table"; +import { useTheme } from "@emotion/react"; +import { useNavigate } from "react-router-dom"; +import { ColoredLabel } from "../../../../../Components/Label"; +import ArrowOutwardIcon from "@mui/icons-material/ArrowOutward"; +import { Stack, Typography } from "@mui/material"; +const StatusPagesTable = ({ data }) => { + const theme = useTheme(); + const navigate = useNavigate(); + const headers = [ + { + id: "name", + content: "Status page name", + render: (row) => { + return row.companyName; + }, + }, + { + id: "url", + content: "URL", + render: (row) => { + return ( + + {row.url} + + + ); + }, + }, + { + id: "type", + content: "Type", + render: (row) => { + return row.type; + }, + }, + { + id: "status", + content: "Status", + render: (row) => { + return ( + + ); + }, + }, + ]; + + const handleRowClick = (statusPage) => { + if (statusPage.type === "distributed") { + navigate(`/status/distributed/${statusPage.url}`); + } else if (statusPage.type === "uptime") { + navigate(`/status/uptime/${statusPage.url}`); + } + }; + + return ( + { + handleRowClick(row); + }, + }} + headers={headers} + data={data} + /> + ); +}; + +export default StatusPagesTable; diff --git a/Client/src/Pages/StatusPage/StatusPages/index.jsx b/Client/src/Pages/StatusPage/StatusPages/index.jsx index cf5b83289..8ec741729 100644 --- a/Client/src/Pages/StatusPage/StatusPages/index.jsx +++ b/Client/src/Pages/StatusPage/StatusPages/index.jsx @@ -4,6 +4,7 @@ import Breadcrumbs from "../../../Components/Breadcrumbs"; import Fallback from "../../../Components/Fallback"; import MonitorCreateHeader from "../../../Components/MonitorCreateHeader"; import GenericFallback from "../../../Components/GenericFallback"; +import StatusPagesTable from "./Components/StatusPagesTable"; // Utils import { useTheme } from "@emotion/react"; import { useStatusPagesFetch } from "./Hooks/useStatusPagesFetch"; @@ -32,8 +33,9 @@ const StatusPages = () => { { isAdmin={isAdmin} path="/status/uptime/create" /> - {statusPages?.map((statusPage) => { - return ( - handleStatusPageClick(statusPage)} - sx={{ cursor: "pointer" }} - > - Company Name: {statusPage.companyName} - Status page URL: {statusPage.url} - Type: {statusPage.type} - - ); - })} + ); }; From eb8901f5ac2ee5cb9bd50124eeda8514c605372b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 10 Feb 2025 16:18:36 -0800 Subject: [PATCH 06/12] fix form.isPublished conditional --- Client/src/Utils/NetworkService.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index ebb726a2c..515ae5930 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -1015,11 +1015,12 @@ class NetworkService { async createStatusPage(config) { const { authToken, user, form, isCreate } = config; + const fd = new FormData(); fd.append("teamId", user.teamId); fd.append("userId", user._id); fd.append("type", form.type); - form.isPublished && fd.append("isPublished", form.isPublished); + form.isPublished !== undefined && fd.append("isPublished", form.isPublished); form.companyName && fd.append("companyName", form.companyName); form.url && fd.append("url", form.url); form.timezone && fd.append("timezone", form.timezone); From 1b5c01eeebf322acfd702f611973b0fcb62396da Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 11 Feb 2025 07:16:43 -0800 Subject: [PATCH 07/12] remove error throw --- Server/controllers/statusPageController.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Server/controllers/statusPageController.js b/Server/controllers/statusPageController.js index 1a69c92ec..7d75fc7d3 100644 --- a/Server/controllers/statusPageController.js +++ b/Server/controllers/statusPageController.js @@ -95,6 +95,7 @@ class StatusPageController { try { const teamId = req.params.teamId; const statusPages = await this.db.getStatusPagesByTeamId(teamId); + return res.success({ msg: successMessages.STATUS_PAGE_BY_TEAM_ID, data: statusPages, From 34c8e3ce55a4452589e2ffe1507bdd22d37dc94e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 11 Feb 2025 07:17:03 -0800 Subject: [PATCH 08/12] add leading / --- .../StatusPages/Components/StatusPagesTable/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Pages/StatusPage/StatusPages/Components/StatusPagesTable/index.jsx b/Client/src/Pages/StatusPage/StatusPages/Components/StatusPagesTable/index.jsx index 6e7988153..746d10f42 100644 --- a/Client/src/Pages/StatusPage/StatusPages/Components/StatusPagesTable/index.jsx +++ b/Client/src/Pages/StatusPage/StatusPages/Components/StatusPagesTable/index.jsx @@ -25,7 +25,7 @@ const StatusPagesTable = ({ data }) => { alignItems="center" gap={theme.spacing(2)} > - {row.url} + {`/${row.url}`} ); From f6f2ae5b3a24d26df3a209debc97c88fe6bc931b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 11 Feb 2025 07:17:45 -0800 Subject: [PATCH 09/12] remove 404 check --- .../Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx b/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx index 29e7f2b89..26eec8104 100644 --- a/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx +++ b/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx @@ -20,9 +20,6 @@ const useStatusPagesFetch = () => { setStatusPages(res?.data?.data); } catch (error) { setNetworkError(true); - if (error.response.status === 404) { - return; - } createToast({ body: error.message, }); From af0f940c22495ab91e5152babff9200a289a5a79 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 11 Feb 2025 07:18:09 -0800 Subject: [PATCH 10/12] Add skeleton --- .../Pages/StatusPage/StatusPages/index.jsx | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/Client/src/Pages/StatusPage/StatusPages/index.jsx b/Client/src/Pages/StatusPage/StatusPages/index.jsx index 8ec741729..9027467a4 100644 --- a/Client/src/Pages/StatusPage/StatusPages/index.jsx +++ b/Client/src/Pages/StatusPage/StatusPages/index.jsx @@ -5,11 +5,11 @@ import Fallback from "../../../Components/Fallback"; import MonitorCreateHeader from "../../../Components/MonitorCreateHeader"; import GenericFallback from "../../../Components/GenericFallback"; import StatusPagesTable from "./Components/StatusPagesTable"; +import SkeletonLayout from "../../../Components/Skeletons/FullPage"; // Utils import { useTheme } from "@emotion/react"; import { useStatusPagesFetch } from "./Hooks/useStatusPagesFetch"; import { useIsAdmin } from "../../../Hooks/useIsAdmin"; -import { useNavigate } from "react-router"; const BREADCRUMBS = [{ name: `Status Pages`, path: "" }]; const StatusPages = () => { @@ -17,30 +17,9 @@ const StatusPages = () => { const theme = useTheme(); const isAdmin = useIsAdmin(); const [isLoading, networkError, statusPages] = useStatusPagesFetch(); - const navigate = useNavigate(); - // Handlers - const handleStatusPageClick = (statusPage) => { - if (statusPage.type === "distributed") { - navigate(`/status/distributed/${statusPage.url}`); - } else if (statusPage.type === "uptime") { - navigate(`/status/uptime/${statusPage.url}`); - } - }; - - if (!isLoading && typeof statusPages === "undefined") { - return ( - - ); + if (isLoading) { + return ; } if (networkError === true) { @@ -57,6 +36,21 @@ const StatusPages = () => { ); } + + if (!isLoading && typeof statusPages !== "undefined" && statusPages.length === 0) { + return ( + + ); + } return ( From c7614ad89eab7e03bfabd32f25028222299e8815 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 11 Feb 2025 07:18:24 -0800 Subject: [PATCH 11/12] add reusable skeleton --- Client/src/Components/Skeletons/FullPage/index.jsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Client/src/Components/Skeletons/FullPage/index.jsx diff --git a/Client/src/Components/Skeletons/FullPage/index.jsx b/Client/src/Components/Skeletons/FullPage/index.jsx new file mode 100644 index 000000000..233fc3c06 --- /dev/null +++ b/Client/src/Components/Skeletons/FullPage/index.jsx @@ -0,0 +1,14 @@ +import { Stack, Skeleton } from "@mui/material"; + +export const SkeletonLayout = () => { + return ( + + + + ); +}; + +export default SkeletonLayout; From 7846c759d94268d12bbd239008b2f68313c47cde Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 11 Feb 2025 07:18:37 -0800 Subject: [PATCH 12/12] remove 404 --- Server/db/mongo/modules/statusPageModule.js | 5 - Server/locales/en.json.bak | 147 ++++++++++++++++++++ 2 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 Server/locales/en.json.bak diff --git a/Server/db/mongo/modules/statusPageModule.js b/Server/db/mongo/modules/statusPageModule.js index 8687f06ed..a0a1b5af6 100644 --- a/Server/db/mongo/modules/statusPageModule.js +++ b/Server/db/mongo/modules/statusPageModule.js @@ -69,11 +69,6 @@ const getStatusPageByUrl = async (url, type) => { const getStatusPagesByTeamId = async (teamId) => { try { const statusPages = await StatusPage.find({ teamId }); - if (statusPages.length === 0) { - const error = new Error(errorMessages.STATUS_PAGE_NOT_FOUND); - error.status = 404; - throw error; - } return statusPages; } catch (error) { error.service = SERVICE_NAME; diff --git a/Server/locales/en.json.bak b/Server/locales/en.json.bak new file mode 100644 index 000000000..eaef58eef --- /dev/null +++ b/Server/locales/en.json.bak @@ -0,0 +1,147 @@ +{ + "dontHaveAccount": "Don't have account", + "email": "E-mail", + "forgotPassword": "Forgot Password", + "password": "password", + "signUp": "Sign up", + "submit": "Submit", + "title": "Title", + "continue": "Continue", + "enterEmail": "Enter your email", + "authLoginTitle": "Log In", + "authLoginEnterPassword": "Enter your password", + "commonPassword": "Password", + "commonBack": "Back", + "authForgotPasswordTitle": "Forgot password?", + "authForgotPasswordResetPassword": "Reset password", + "createPassword": "Create your password", + "createAPassword": "Create a password", + "authRegisterAlreadyHaveAccount": "Already have an account?", + "commonAppName": "BlueWave Uptime", + "authLoginEnterEmail": "Enter your email", + "authRegisterTitle": "Create an account", + "authRegisterStepOneTitle": "Create your account", + "authRegisterStepOneDescription": "Enter your details to get started", + "authRegisterStepTwoTitle": "Set up your profile", + "authRegisterStepTwoDescription": "Tell us more about yourself", + "authRegisterStepThreeTitle": "Almost done!", + "authRegisterStepThreeDescription": "Review your information", + "authForgotPasswordDescription": "No worries, we'll send you reset instructions.", + "authForgotPasswordSendInstructions": "Send instructions", + "authForgotPasswordBackTo": "Back to", + "authCheckEmailTitle": "Check your email", + "authCheckEmailDescription": "We sent a password reset link to {{email}}", + "authCheckEmailResendEmail": "Resend email", + "authCheckEmailBackTo": "Back to", + "goBackTo": "Go back to", + "authCheckEmailDidntReceiveEmail": "Didn't receive the email?", + "authCheckEmailClickToResend": "Click to resend", + "authSetNewPasswordTitle": "Set new password", + "authSetNewPasswordDescription": "Your new password must be different from previously used passwords.", + "authSetNewPasswordNewPassword": "New password", + "authSetNewPasswordConfirmPassword": "Confirm password", + "confirmPassword": "Confirm your password", + "authSetNewPasswordResetPassword": "Reset password", + "authSetNewPasswordBackTo": "Back to", + "authPasswordMustBeAtLeast": "Must be at least", + "authPasswordCharactersLong": "8 characters long", + "authPasswordMustContainAtLeast": "Must contain at least", + "authPasswordSpecialCharacter": "one special character", + "authPasswordOneNumber": "one number", + "authPasswordUpperCharacter": "one upper character", + "authPasswordLowerCharacter": "one lower character", + "authPasswordConfirmAndPassword": "Confirm password and password", + "authPasswordMustMatch": "must match", + "friendlyError": "Something went wrong...", + "unknownError": "An unknown error occurred", + "unauthorized": "Unauthorized access", + "authAdminExists": "Admin already exists", + "authInviteNotFound": "Invite not found", + "unknownService": "Unknown service", + "noAuthToken": "No auth token provided", + "invalidAuthToken": "Invalid auth token", + "expiredAuthToken": "Token expired", + "noRefreshToken": "No refresh token provided", + "invalidRefreshToken": "Invalid refresh token", + "expiredRefreshToken": "Refresh token expired", + "requestNewAccessToken": "Request new access token", + "invalidPayload": "Invalid payload", + "verifyOwnerNotFound": "Document not found", + "verifyOwnerUnauthorized": "Unauthorized access", + "insufficientPermissions": "Insufficient permissions", + "dbUserExists": "User already exists", + "dbUserNotFound": "User not found", + "dbTokenNotFound": "Token not found", + "dbResetPasswordBadMatch": "New password must be different from old password", + "dbFindMonitorById": "Monitor with id ${monitorId} not found", + "dbDeleteChecks": "No checks found for monitor with id ${monitorId}", + "authIncorrectPassword": "Incorrect password", + "authUnauthorized": "Unauthorized access", + "monitorGetById": "Monitor not found", + "monitorGetByUserId": "No monitors found for user", + "jobQueueWorkerClose": "Error closing worker", + "jobQueueDeleteJob": "Job not found in queue", + "jobQueueObliterate": "Error obliterating queue", + "pingCannotResolve": "No response", + "statusPageNotFound": "Status page not found", + "statusPageUrlNotUnique": "Status page url must be unique", + "dockerFail": "Failed to fetch Docker container information", + "dockerNotFound": "Docker container not found", + "portFail": "Failed to connect to port", + "alertCreate": "Alert created successfully", + "alertGetByUser": "Got alerts successfully", + "alertGetByMonitor": "Got alerts by Monitor successfully", + "alertGetById": "Got alert by Id successfully", + "alertEdit": "Alert edited successfully", + "alertDelete": "Alert deleted successfully", + "authCreateUser": "User created successfully", + "authLoginUser": "User logged in successfully", + "authLogoutUser": "User logged out successfully", + "authUpdateUser": "User updated successfully", + "authCreateRecoveryToken": "Recovery token created successfully", + "authVerifyRecoveryToken": "Recovery token verified successfully", + "authResetPassword": "Password reset successfully", + "authAdminCheck": "Admin check completed successfully", + "authDeleteUser": "User deleted successfully", + "authTokenRefreshed": "Auth token is refreshed", + "authGetAllUsers": "Got all users successfully", + "inviteIssued": "Invite sent successfully", + "inviteVerified": "Invite verified successfully", + "checkCreate": "Check created successfully", + "checkGet": "Got checks successfully", + "checkDelete": "Checks deleted successfully", + "checkUpdateTtl": "Checks TTL updated successfully", + "monitorGetAll": "Got all monitors successfully", + "monitorStatsById": "Got monitor stats by Id successfully", + "monitorGetByIdSuccess": "Got monitor by Id successfully", + "monitorGetByTeamId": "Got monitors by Team Id successfully", + "monitorGetByUserIdSuccess": "Got monitor for ${userId} successfully", + "monitorCreate": "Monitor created successfully", + "monitorDelete": "Monitor deleted successfully", + "monitorEdit": "Monitor edited successfully", + "monitorCertificate": "Got monitor certificate successfully", + "monitorDemoAdded": "Successfully added demo monitors", + "queueGetMetrics": "Got metrics successfully", + "queueAddJob": "Job added successfully", + "queueObliterate": "Queue obliterated", + "jobQueueDeleteJobSuccess": "Job removed successfully", + "jobQueuePauseJob": "Job paused successfully", + "jobQueueResumeJob": "Job resumed successfully", + "maintenanceWindowGetById": "Got Maintenance Window by Id successfully", + "maintenanceWindowCreate": "Maintenance Window created successfully", + "maintenanceWindowGetByTeam": "Got Maintenance Windows by Team successfully", + "maintenanceWindowDelete": "Maintenance Window deleted successfully", + "maintenanceWindowEdit": "Maintenance Window edited successfully", + "pingSuccess": "Success", + "getAppSettings": "Got app settings successfully", + "updateAppSettings": "Updated app settings successfully", + "statusPageByUrl": "Got status page by url successfully", + "statusPageCreate": "Status page created successfully", + "newTermsAdded": "New terms added to POEditor", + "dockerSuccess": "Docker container status fetched successfully", + "portSuccess": "Port connected successfully", + "monitorPause": "Monitor paused successfully", + "monitorResume": "Monitor resumed successfully", + "statusPageDelete": "Status page deleted successfully", + "statusPageUpdate": "Status page updated successfully" +}