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; 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 ( <> { 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; 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), 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..746d10f42 --- /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/Hooks/useStatusPagesFetch.jsx b/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx index 7565f129a..26eec8104 100644 --- a/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx +++ b/Client/src/Pages/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx @@ -20,7 +20,9 @@ const useStatusPagesFetch = () => { setStatusPages(res?.data?.data); } catch (error) { setNetworkError(true); - createToast(error.message, "error"); + createToast({ + body: error.message, + }); } finally { setIsLoading(false); } diff --git a/Client/src/Pages/StatusPage/StatusPages/index.jsx b/Client/src/Pages/StatusPage/StatusPages/index.jsx index cf5b83289..9027467a4 100644 --- a/Client/src/Pages/StatusPage/StatusPages/index.jsx +++ b/Client/src/Pages/StatusPage/StatusPages/index.jsx @@ -4,11 +4,12 @@ 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"; +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 = () => { @@ -16,29 +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) { @@ -55,6 +36,21 @@ const StatusPages = () => { ); } + + if (!isLoading && typeof statusPages !== "undefined" && statusPages.length === 0) { + return ( + + ); + } return ( @@ -63,19 +59,7 @@ 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} - - ); - })} + ); }; 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); 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, 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" +}