Merge pull request #1738 from bluewave-labs/feat/fe/status-page-table
feat: fe/status page table
This commit is contained in:
11 files changed
+278
-52
No files matched your search
@@ -0,0 +1,14 @@
|
||||
import { Stack, Skeleton } from "@mui/material";
|
||||
|
||||
export const SkeletonLayout = () => {
|
||||
return (
|
||||
<Stack>
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
height={"90vh"}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default SkeletonLayout;
|
||||
@@ -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 (
|
||||
<>
|
||||
<DataTable
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 (
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
gap={theme.spacing(2)}
|
||||
>
|
||||
<Typography>{`/${row.url}`}</Typography>
|
||||
<ArrowOutwardIcon />
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "type",
|
||||
content: "Type",
|
||||
render: (row) => {
|
||||
return row.type;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "status",
|
||||
content: "Status",
|
||||
render: (row) => {
|
||||
return (
|
||||
<ColoredLabel
|
||||
label={row.isPublished ? "Published" : "Unpublished"}
|
||||
color={
|
||||
row.isPublished ? theme.palette.success.main : theme.palette.warning.main
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const handleRowClick = (statusPage) => {
|
||||
if (statusPage.type === "distributed") {
|
||||
navigate(`/status/distributed/${statusPage.url}`);
|
||||
} else if (statusPage.type === "uptime") {
|
||||
navigate(`/status/uptime/${statusPage.url}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
config={{
|
||||
rowSX: {
|
||||
cursor: "pointer",
|
||||
"&:hover td": {
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
transition: "background-color .3s ease",
|
||||
},
|
||||
},
|
||||
onRowClick: (row) => {
|
||||
handleRowClick(row);
|
||||
},
|
||||
}}
|
||||
headers={headers}
|
||||
data={data}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatusPagesTable;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<Fallback
|
||||
title="status page"
|
||||
checks={[
|
||||
"Display a list of monitors to track",
|
||||
"Share your monitors with the public",
|
||||
]}
|
||||
link="/status/uptime/create"
|
||||
isAdmin={isAdmin}
|
||||
/>
|
||||
);
|
||||
if (isLoading) {
|
||||
return <SkeletonLayout />;
|
||||
}
|
||||
|
||||
if (networkError === true) {
|
||||
@@ -55,6 +36,21 @@ const StatusPages = () => {
|
||||
</GenericFallback>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isLoading && typeof statusPages !== "undefined" && statusPages.length === 0) {
|
||||
return (
|
||||
<Fallback
|
||||
title="status page"
|
||||
checks={[
|
||||
"Monitor and display the health of your services in real time",
|
||||
"Track multiple services and share their status",
|
||||
"Keep users informed about outages and performance",
|
||||
]}
|
||||
link="/status/uptime/create"
|
||||
isAdmin={isAdmin}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Stack gap={theme.spacing(10)}>
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
@@ -63,19 +59,7 @@ const StatusPages = () => {
|
||||
isAdmin={isAdmin}
|
||||
path="/status/uptime/create"
|
||||
/>
|
||||
{statusPages?.map((statusPage) => {
|
||||
return (
|
||||
<Stack
|
||||
key={statusPage._id}
|
||||
onClick={() => handleStatusPageClick(statusPage)}
|
||||
sx={{ cursor: "pointer" }}
|
||||
>
|
||||
<Typography variant="h2">Company Name: {statusPage.companyName}</Typography>
|
||||
<Typography variant="h2">Status page URL: {statusPage.url}</Typography>
|
||||
<Typography variant="h2">Type: {statusPage.type}</Typography>
|
||||
</Stack>
|
||||
);
|
||||
})}
|
||||
<StatusPagesTable data={statusPages} />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
Reference in new issue
Block a user