mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-01 22:20:03 -05:00
Merge branch 'develop' into fix/email-case
This commit is contained in:
@@ -23,8 +23,8 @@ const PulseDot = ({ color }) => {
|
||||
justifyContent="center"
|
||||
>
|
||||
<Box
|
||||
minWidth="16px"
|
||||
minHeight="16px"
|
||||
minWidth="18px"
|
||||
minHeight="18px"
|
||||
sx={{
|
||||
position: "relative",
|
||||
backgroundColor: color,
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
.MuiTable-root .host a {
|
||||
width: var(--env-var-img-width-2);
|
||||
height: var(--env-var-img-width-2);
|
||||
color: var(--env-var-color-5);
|
||||
margin-right: 10px;
|
||||
}
|
||||
.MuiTable-root .host a svg {
|
||||
width: var(--env-var-font-size-large);
|
||||
height: var(--env-var-font-size-large);
|
||||
}
|
||||
.MuiTable-root .host div:nth-child(2) {
|
||||
.MuiTable-root .host {
|
||||
width: fit-content;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.MuiTable-root .host div:nth-child(2) span {
|
||||
.MuiTable-root .host span {
|
||||
font-size: var(--env-var-font-size-small);
|
||||
margin-left: 10px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.MuiTable-root .label {
|
||||
@@ -128,6 +118,7 @@
|
||||
.MuiTablePagination-root p {
|
||||
color: var(--env-var-color-2);
|
||||
font-weight: 500;
|
||||
font-size: var(--env-var-font-size-small-plus);
|
||||
}
|
||||
.MuiTablePagination-root button,
|
||||
.MuiTablePagination-root .MuiSelect-select {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
.bar-tooltip .MuiTooltip-tooltip {
|
||||
background-color: white;
|
||||
border: solid 1px black;
|
||||
box-shadow: var(--env-var-shadow-1);
|
||||
border: solid 1px var(--env-var-color-6);
|
||||
border-radius: var(--env-var-radius-1);
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.bar-tooltip .MuiTooltip-tooltip p {
|
||||
font-size: var(--env-var-font-size-small-plus);
|
||||
color: var(--env-var-color-2);
|
||||
font-weight: 500;
|
||||
}
|
||||
.bar-tooltip .MuiTooltip-tooltip span {
|
||||
font-size: var(--env-var-font-size-small);
|
||||
color: var(--env-var-color-2);
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { Box, Stack, Tooltip, Typography } from "@mui/material";
|
||||
import { formatDate } from "../../../Utils/timeUtils";
|
||||
import { useEffect, useState } from "react";
|
||||
import "./index.css";
|
||||
|
||||
const BarChart = ({ checks = [] }) => {
|
||||
const theme = useTheme();
|
||||
const [animate, setAnimate] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setAnimate(true);
|
||||
});
|
||||
|
||||
// set responseTime to average if there's only one check
|
||||
if (checks.length === 1) {
|
||||
checks[0] = { ...checks[0], responseTime: 50 };
|
||||
}
|
||||
|
||||
if (checks.length !== 25) {
|
||||
const placeholders = Array(25 - checks.length).fill("placeholder");
|
||||
checks = [...checks, ...placeholders];
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
flexWrap="nowrap"
|
||||
gap="3px"
|
||||
height="50px"
|
||||
width="fit-content"
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
sx={{
|
||||
cursor: "default",
|
||||
}}
|
||||
>
|
||||
{checks.map((check, index) =>
|
||||
check === "placeholder" ? (
|
||||
<Box
|
||||
key={`${check}-${index}`}
|
||||
position="relative"
|
||||
width="9px"
|
||||
height="100%"
|
||||
backgroundColor={theme.palette.otherColors.fillGray}
|
||||
sx={{
|
||||
borderRadius: "3px",
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
<Typography>
|
||||
{formatDate(new Date(check.createdAt), { year: undefined })}
|
||||
</Typography>
|
||||
<Box mt={theme.gap.xs}>
|
||||
<Box
|
||||
display="inline-block"
|
||||
width={theme.gap.small}
|
||||
height={theme.gap.small}
|
||||
backgroundColor={
|
||||
check.status
|
||||
? theme.label.up.dotColor
|
||||
: theme.label.down.dotColor
|
||||
}
|
||||
sx={{ borderRadius: "50%" }}
|
||||
/>
|
||||
<Stack
|
||||
display="inline-flex"
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
ml={theme.gap.xs}
|
||||
gap={theme.gap.large}
|
||||
>
|
||||
<Typography component="span" sx={{ opacity: 0.8 }}>
|
||||
Response Time
|
||||
</Typography>
|
||||
<Typography component="span">
|
||||
{check.originalResponseTime}
|
||||
<Typography component="span" sx={{ opacity: 0.8 }}>
|
||||
{" "}
|
||||
ms
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
</>
|
||||
}
|
||||
placement="top"
|
||||
key={`check-${check?._id}`}
|
||||
slotProps={{
|
||||
popper: {
|
||||
className: "bar-tooltip",
|
||||
modifiers: [
|
||||
{
|
||||
name: "offset",
|
||||
options: {
|
||||
offset: [0, -10],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
position="relative"
|
||||
width="9px"
|
||||
height="100%"
|
||||
backgroundColor={
|
||||
check.status ? theme.label.up.bgColor : theme.label.down.bgColor
|
||||
}
|
||||
sx={{
|
||||
borderRadius: "3px",
|
||||
"&:hover > .MuiBox-root": {
|
||||
filter: "brightness(0.8)",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
position="absolute"
|
||||
bottom={0}
|
||||
width="100%"
|
||||
height={`${animate ? check.responseTime : 0}%`}
|
||||
backgroundColor={
|
||||
check.status
|
||||
? theme.label.up.dotColor
|
||||
: theme.label.down.dotColor
|
||||
}
|
||||
sx={{
|
||||
borderRadius: "3px",
|
||||
transition: "height 600ms cubic-bezier(0.4, 0, 0.2, 1)",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
)
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default BarChart;
|
||||
@@ -53,9 +53,9 @@ const menu = [
|
||||
],
|
||||
},
|
||||
{ name: "Incidents", path: "incidents", icon: <Incidents /> },
|
||||
{ name: "Status pages", path: "status", icon: <StatusPages /> },
|
||||
// { name: "Status pages", path: "status", icon: <StatusPages /> },
|
||||
{ name: "Maintenance", path: "maintenance", icon: <Maintenance /> },
|
||||
{ name: "Integrations", path: "integrations", icon: <Integrations /> },
|
||||
// { name: "Integrations", path: "integrations", icon: <Integrations /> },
|
||||
{
|
||||
name: "Account",
|
||||
icon: <Account />,
|
||||
@@ -310,7 +310,7 @@ function Sidebar() {
|
||||
gap: theme.gap.small,
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
pl: theme.gap.small,
|
||||
mb:"1px"
|
||||
mb: "1px",
|
||||
}}
|
||||
>
|
||||
{child.icon}
|
||||
@@ -427,7 +427,7 @@ function Sidebar() {
|
||||
onClick={() =>
|
||||
item.path === "support"
|
||||
? window.open(
|
||||
"https://github.com/bluewave-labs/bluewave-uptime",
|
||||
"https://github.com/bluewave-labs/bluewave-uptime/issues",
|
||||
"_blank",
|
||||
"noreferrer"
|
||||
)
|
||||
|
||||
@@ -74,7 +74,8 @@ const TeamPanel = () => {
|
||||
{ id: 1, name: "NAME" },
|
||||
{ id: 2, name: "EMAIL" },
|
||||
{ id: 3, name: "ROLE" },
|
||||
{ id: 4, name: "ACTION" },
|
||||
// FEATURE STILL TO BE IMPLEMENTED
|
||||
// { id: 4, name: "ACTION" },
|
||||
],
|
||||
rows: team?.map((member, idx) => {
|
||||
return {
|
||||
@@ -101,22 +102,23 @@ const TeamPanel = () => {
|
||||
id: idx + 2,
|
||||
data: member.role.includes("admin") ? "Administrator" : "Member",
|
||||
},
|
||||
{
|
||||
// TODO - Add delete onClick
|
||||
id: idx + 3,
|
||||
data: (
|
||||
<IconButton
|
||||
aria-label="remove member"
|
||||
sx={{
|
||||
"&:focus": {
|
||||
outline: "none",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Remove />
|
||||
</IconButton>
|
||||
),
|
||||
},
|
||||
// FEATURE STILL TO BE IMPLEMENTED
|
||||
// {
|
||||
// // TODO - Add delete onClick
|
||||
// id: idx + 3,
|
||||
// data: (
|
||||
// <IconButton
|
||||
// aria-label="remove member"
|
||||
// sx={{
|
||||
// "&:focus": {
|
||||
// outline: "none",
|
||||
// },
|
||||
// }}
|
||||
// >
|
||||
// <Remove />
|
||||
// </IconButton>
|
||||
// ),
|
||||
// },
|
||||
],
|
||||
};
|
||||
}),
|
||||
@@ -197,7 +199,8 @@ const TeamPanel = () => {
|
||||
|
||||
return (
|
||||
<TabPanel value="team">
|
||||
<Stack component="form">
|
||||
{/* FEATURE STILL TO BE IMPLEMENTED */}
|
||||
{/* <Stack component="form">
|
||||
<Box sx={{ alignSelf: "flex-start" }}>
|
||||
<Typography component="h1">Organization name</Typography>
|
||||
</Box>
|
||||
@@ -242,7 +245,7 @@ const TeamPanel = () => {
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Divider aria-hidden="true" sx={{ marginY: theme.spacing(4) }} />
|
||||
<Divider aria-hidden="true" sx={{ marginY: theme.spacing(4) }} /> */}
|
||||
<Stack
|
||||
component="form"
|
||||
noValidate
|
||||
|
||||
@@ -10,11 +10,9 @@ 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 OpenInNewPage from "../../assets/icons/open-in-new-page.svg?react";
|
||||
import BasicTable from "../../Components/BasicTable";
|
||||
import { StatusLabel } from "../../Components/Label";
|
||||
import { createToast } from "../../Utils/toastUtils";
|
||||
import ResponseTimeChart from "../../Components/Charts/ResponseTimeChart";
|
||||
import {
|
||||
Box,
|
||||
IconButton,
|
||||
@@ -28,6 +26,7 @@ import {
|
||||
|
||||
import Settings from "../../assets/icons/settings-bold.svg?react";
|
||||
import PropTypes from "prop-types";
|
||||
import BarChart from "../../Components/Charts/BarChart";
|
||||
|
||||
const ActionsMenu = ({ monitor }) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
@@ -206,7 +205,6 @@ ActionsMenu.propTypes = {
|
||||
*
|
||||
* @component
|
||||
* @param {Object} params - An object containing the following properties:
|
||||
* @param {string} params.url - The URL of the host.
|
||||
* @param {string} params.title - The name of the host.
|
||||
* @param {string} params.percentageColor - The color of the percentage text.
|
||||
* @param {number} params.percentage - The percentage to display.
|
||||
@@ -214,40 +212,17 @@ ActionsMenu.propTypes = {
|
||||
*/
|
||||
const Host = ({ params }) => {
|
||||
return (
|
||||
<Stack direction="row" alignItems="center" className="host">
|
||||
<IconButton
|
||||
aria-label="monitor link"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
window.open(params.url, "_blank", "noreferrer");
|
||||
}}
|
||||
sx={{
|
||||
"&:focus": {
|
||||
outline: "none",
|
||||
},
|
||||
mr: "5px",
|
||||
}}
|
||||
>
|
||||
<OpenInNewPage
|
||||
style={{
|
||||
marginTop: "-1px",
|
||||
marginRight: "-1px",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
<Box>
|
||||
{params.title}
|
||||
<Typography component="span" sx={{ color: params.percentageColor }}>
|
||||
{params.percentage}%
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack direction="row" alignItems="baseline" className="host">
|
||||
{params.title}
|
||||
<Typography component="span" sx={{ color: params.percentageColor }}>
|
||||
{params.percentage}%
|
||||
</Typography>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
Host.propTypes = {
|
||||
params: PropTypes.shape({
|
||||
url: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
percentageColor: PropTypes.string,
|
||||
percentage: PropTypes.number,
|
||||
@@ -326,7 +301,6 @@ const Monitors = () => {
|
||||
|
||||
data.rows = monitorState.monitors.map((monitor, idx) => {
|
||||
const params = {
|
||||
url: monitor.url,
|
||||
title: monitor.name,
|
||||
percentage: 100,
|
||||
percentageColor:
|
||||
@@ -357,7 +331,7 @@ const Monitors = () => {
|
||||
/>
|
||||
),
|
||||
},
|
||||
{ id: idx + 2, data: <ResponseTimeChart checks={reversedChecks} /> },
|
||||
{ id: idx + 2, data: <BarChart checks={reversedChecks} /> },
|
||||
{
|
||||
id: idx + 3,
|
||||
data: (
|
||||
|
||||
@@ -43,7 +43,7 @@ export const formatDurationRounded = (ms) => {
|
||||
return time;
|
||||
};
|
||||
|
||||
export const formatDate = (date) => {
|
||||
export const formatDate = (date, customOptions) => {
|
||||
const options = {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
@@ -51,6 +51,7 @@ export const formatDate = (date) => {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: true,
|
||||
...customOptions
|
||||
};
|
||||
|
||||
// Return the date using the specified options
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
--env-var-width-2: 360px;
|
||||
|
||||
--env-var-height-1: 100vh;
|
||||
--env-var-height-2: 36px;
|
||||
--env-var-height-2: 34px;
|
||||
|
||||
--env-var-nav-bar-height: 70px;
|
||||
--env-var-side-bar-width: 250px;
|
||||
|
||||
@@ -16,7 +16,7 @@ RUN npm run build
|
||||
|
||||
FROM nginx:1.27.1-alpine
|
||||
|
||||
COPY ./Docker/nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||
# COPY ./Docker/nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -1,11 +1,21 @@
|
||||
version: "3"
|
||||
services:
|
||||
client:
|
||||
image: uptime_client:latest
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
depends_on:
|
||||
- server
|
||||
volumes:
|
||||
- ./nginx/conf.d:/etc/nginx/conf.d/:ro
|
||||
- ./certbot/www:/var/www/certbot/:ro
|
||||
- ./certbot/conf/:/etc/nginx/ssl/:ro
|
||||
|
||||
certbot:
|
||||
image: certbot/certbot:latest
|
||||
volumes:
|
||||
- ./certbot/www/:/var/www/certbot/:rw
|
||||
- ./certbot/conf/:/etc/letsencrypt/:rw
|
||||
server:
|
||||
image: uptime_server:latest
|
||||
ports:
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_name uptime-demo.bluewavelabs.ca;
|
||||
server_tokens off;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://server:5000/api/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 default_server ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
server_name uptime-demo.bluewavelabs.ca;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/live/uptime-demo.bluewavelabs.ca/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/ssl/live/uptime-demo.bluewavelabs.ca/privkey.pem;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://server:5000/api/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name localhost;
|
||||
|
||||
#access_log /var/log/nginx/host.access.log main;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
#error_page 404 /404.html;
|
||||
|
||||
# redirect server error pages to the static page /50x.html
|
||||
#
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
|
||||
#
|
||||
#location ~ \.php$ {
|
||||
# proxy_pass http://127.0.0.1;
|
||||
#}
|
||||
|
||||
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
|
||||
#
|
||||
#location ~ \.php$ {
|
||||
# root html;
|
||||
# fastcgi_pass 127.0.0.1:9000;
|
||||
# fastcgi_index index.php;
|
||||
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
|
||||
# include fastcgi_params;
|
||||
#}
|
||||
|
||||
# deny access to .htaccess files, if Apache's document root
|
||||
# concurs with nginx's one
|
||||
#
|
||||
#location ~ /\.ht {
|
||||
# deny all;
|
||||
#}
|
||||
}
|
||||
Reference in New Issue
Block a user