Merge pull request #1152 from bluewave-labs/refactor/theme
Refactor - Theme
This commit is contained in:
36 files changed
+1128
-905
No files matched your search
Generated
+13
-13
@@ -8,12 +8,12 @@
|
||||
"name": "client",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
"@fontsource/roboto": "^5.0.13",
|
||||
"@mui/icons-material": "^5.15.17",
|
||||
"@mui/lab": "^5.0.0-alpha.170",
|
||||
"@mui/material": "^5.15.16",
|
||||
"@mui/material": "^5.16.7",
|
||||
"@mui/x-charts": "^7.5.1",
|
||||
"@mui/x-data-grid": "7.22.2",
|
||||
"@mui/x-date-pickers": "7.22.2",
|
||||
@@ -304,9 +304,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz",
|
||||
"integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==",
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
|
||||
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
@@ -1356,12 +1356,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/types": {
|
||||
"version": "7.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz",
|
||||
"integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==",
|
||||
"version": "7.2.19",
|
||||
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz",
|
||||
"integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.0 || ^18.0.0"
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
@@ -2350,9 +2350,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
||||
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==",
|
||||
"version": "15.7.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
|
||||
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
|
||||
+3
-3
@@ -11,12 +11,12 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
"@fontsource/roboto": "^5.0.13",
|
||||
"@mui/icons-material": "^5.15.17",
|
||||
"@mui/lab": "^5.0.0-alpha.170",
|
||||
"@mui/material": "^5.15.16",
|
||||
"@mui/material": "^5.16.7",
|
||||
"@mui/x-charts": "^7.5.1",
|
||||
"@mui/x-data-grid": "7.22.2",
|
||||
"@mui/x-date-pickers": "7.22.2",
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
+39
-23
@@ -1,14 +1,12 @@
|
||||
import { useEffect } from "react";
|
||||
import { Routes, Route } from "react-router-dom";
|
||||
import { Routes, Route, Navigate } from "react-router-dom";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useDispatch } from "react-redux";
|
||||
// import "./App.css";
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
import NotFound from "./Pages/NotFound";
|
||||
import Login from "./Pages/Auth/Login";
|
||||
import Register from "./Pages/Auth/Register/Register";
|
||||
import HomeLayout from "./Layouts/HomeLayout";
|
||||
import Account from "./Pages/Account";
|
||||
import Monitors from "./Pages/Monitors/Home";
|
||||
import CreateMonitor from "./Pages/Monitors/CreateMonitor";
|
||||
@@ -30,15 +28,17 @@ import CreatePageSpeed from "./Pages/PageSpeed/CreatePageSpeed";
|
||||
import CreateNewMaintenanceWindow from "./Pages/Maintenance/CreateMaintenance";
|
||||
import PageSpeedDetails from "./Pages/PageSpeed/Details";
|
||||
import PageSpeedConfigure from "./Pages/PageSpeed/Configure";
|
||||
import withAdminCheck from "./HOC/withAdminCheck";
|
||||
import withAdminProp from "./HOC/withAdminProp";
|
||||
import HomeLayout from "./Components/Layouts/HomeLayout";
|
||||
import withAdminCheck from "./Components/HOC/withAdminCheck";
|
||||
import withAdminProp from "./Components/HOC/withAdminProp";
|
||||
import { ThemeProvider } from "@emotion/react";
|
||||
import lightTheme from "./Utils/Theme/lightTheme";
|
||||
import darkTheme from "./Utils/Theme/darkTheme";
|
||||
import { CssBaseline } from "@mui/material";
|
||||
import { CssBaseline, GlobalStyles } from "@mui/material";
|
||||
import { getAppSettings } from "./Features/Settings/settingsSlice";
|
||||
import { logger } from "./Utils/Logger"; // Import the logger
|
||||
import { networkService } from "./main";
|
||||
import { Infrastructure } from "./Pages/Infrastructure";
|
||||
function App() {
|
||||
const AdminCheckedRegister = withAdminCheck(Register);
|
||||
const MonitorsWithAdminProp = withAdminProp(Monitors);
|
||||
@@ -67,8 +67,19 @@ function App() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
/* Extract Themeprovider, baseline and global styles to Styles */
|
||||
<ThemeProvider theme={mode === "light" ? lightTheme : darkTheme}>
|
||||
<CssBaseline />
|
||||
<GlobalStyles
|
||||
styles={({ palette }) => {
|
||||
return {
|
||||
body: {
|
||||
backgroundImage: `radial-gradient(circle, ${palette.gradient.color1}, ${palette.gradient.color2}, ${palette.gradient.color3}, ${palette.gradient.color4}, ${palette.gradient.color5})`,
|
||||
},
|
||||
};
|
||||
}}
|
||||
/>
|
||||
{/* Extract Routes to Routes */}
|
||||
<Routes>
|
||||
<Route
|
||||
exact
|
||||
@@ -78,7 +89,7 @@ function App() {
|
||||
<Route
|
||||
exact
|
||||
path="/"
|
||||
element={<ProtectedRoute Component={MonitorsWithAdminProp} />}
|
||||
element={<Navigate to="/monitors" />}
|
||||
/>
|
||||
<Route
|
||||
path="/monitors"
|
||||
@@ -96,6 +107,27 @@ function App() {
|
||||
path="/monitors/configure/:monitorId/"
|
||||
element={<ProtectedRoute Component={Configure} />}
|
||||
/>
|
||||
<Route
|
||||
path="pagespeed"
|
||||
element={<ProtectedRoute Component={PageSpeedWithAdminProp} />}
|
||||
/>
|
||||
<Route
|
||||
path="pagespeed/create"
|
||||
element={<ProtectedRoute Component={CreatePageSpeed} />}
|
||||
/>
|
||||
<Route
|
||||
path="pagespeed/:monitorId"
|
||||
element={<ProtectedRoute Component={PageSpeedDetailsWithAdminProp} />}
|
||||
/>
|
||||
<Route
|
||||
path="pagespeed/configure/:monitorId"
|
||||
element={<ProtectedRoute Component={PageSpeedConfigure} />}
|
||||
/>
|
||||
<Route
|
||||
path="infrastructure"
|
||||
element={<ProtectedRoute Component={Infrastructure} />}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="incidents/:monitorId?"
|
||||
element={<ProtectedRoute Component={Incidents} />}
|
||||
@@ -152,22 +184,6 @@ function App() {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="pagespeed"
|
||||
element={<ProtectedRoute Component={PageSpeedWithAdminProp} />}
|
||||
/>
|
||||
<Route
|
||||
path="pagespeed/create"
|
||||
element={<ProtectedRoute Component={CreatePageSpeed} />}
|
||||
/>
|
||||
<Route
|
||||
path="pagespeed/:monitorId"
|
||||
element={<ProtectedRoute Component={PageSpeedDetailsWithAdminProp} />}
|
||||
/>
|
||||
<Route
|
||||
path="pagespeed/configure/:monitorId"
|
||||
element={<ProtectedRoute Component={PageSpeedConfigure} />}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
|
||||
@@ -31,6 +31,9 @@ const icons = {
|
||||
|
||||
const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => {
|
||||
const theme = useTheme();
|
||||
/* TODO
|
||||
This needs fixing. text bg and border not necessarilly exist. Probably text becomes contrastText. border becomes contrastText. bg becomes dark.
|
||||
Check possible variants, see implementation in light and dark theme, and adjust */
|
||||
const { text, bg, border } = theme.palette[variant];
|
||||
const icon = icons[variant];
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useEffect, useState } from "react";
|
||||
import "./index.css";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
/* TODO add prop validation and jsdocs */
|
||||
const BarChart = ({ checks = [] }) => {
|
||||
const theme = useTheme();
|
||||
const [animate, setAnimate] = useState(false);
|
||||
@@ -65,7 +66,9 @@ const BarChart = ({ checks = [] }) => {
|
||||
width={theme.spacing(4)}
|
||||
height={theme.spacing(4)}
|
||||
backgroundColor={
|
||||
check.status ? theme.palette.success.main : theme.palette.error.text
|
||||
check.status
|
||||
? theme.palette.success.main
|
||||
: theme.palette.error.contrastText
|
||||
}
|
||||
sx={{ borderRadius: "50%" }}
|
||||
/>
|
||||
@@ -111,7 +114,7 @@ const BarChart = ({ checks = [] }) => {
|
||||
],
|
||||
sx: {
|
||||
"& .MuiTooltip-tooltip": {
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
@@ -138,7 +141,9 @@ const BarChart = ({ checks = [] }) => {
|
||||
width="9px"
|
||||
height="100%"
|
||||
backgroundColor={
|
||||
check.status ? theme.palette.success.bg : theme.palette.error.bg
|
||||
check.status
|
||||
? theme.palette.success.contrastText
|
||||
: theme.palette.error.dark
|
||||
}
|
||||
sx={{
|
||||
borderRadius: theme.spacing(1.5),
|
||||
@@ -153,7 +158,9 @@ const BarChart = ({ checks = [] }) => {
|
||||
width="100%"
|
||||
height={`${animate ? check.responseTime : 0}%`}
|
||||
backgroundColor={
|
||||
check.status ? theme.palette.success.main : theme.palette.error.text
|
||||
check.status
|
||||
? theme.palette.success.main
|
||||
: theme.palette.error.contrastText
|
||||
}
|
||||
sx={{
|
||||
borderRadius: theme.spacing(1.5),
|
||||
|
||||
@@ -24,7 +24,7 @@ const Check = ({ text, noHighlightText, variant = "info", outlined = false }) =>
|
||||
const theme = useTheme();
|
||||
const colors = {
|
||||
success: theme.palette.success.main,
|
||||
error: theme.palette.error.text,
|
||||
error: theme.palette.error.contrastText,
|
||||
info: theme.palette.info.border,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { logger } from "../Utils/Logger";
|
||||
import { networkService } from "../main";
|
||||
import { logger } from "../../Utils/Logger";
|
||||
import { networkService } from "../../main";
|
||||
|
||||
const withAdminCheck = (WrappedComponent) => {
|
||||
const WithAdminCheck = (props) => {
|
||||
File renamed without changes.
@@ -0,0 +1,29 @@
|
||||
import { Typography } from "@mui/material";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
/**
|
||||
* A heading component that renders text with a specific heading level.
|
||||
*
|
||||
* @param {Object} props - The properties passed to the Heading component.
|
||||
* @param {('h1'|'h2'|'h3')} props.component - The heading level for the component.
|
||||
* @param {string} props.children - The content to display inside the heading.
|
||||
* @returns {JSX.Element} The Typography component with specified heading properties.
|
||||
*/
|
||||
|
||||
function Heading({ component, children }) {
|
||||
return (
|
||||
<Typography
|
||||
component={component}
|
||||
variant="h2"
|
||||
fontWeight={600}
|
||||
>
|
||||
{children}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
Heading.propTypes = {
|
||||
component: PropTypes.oneOf(["h1", "h2", "h3"]).isRequired,
|
||||
children: PropTypes.string.isRequired,
|
||||
};
|
||||
export { Heading };
|
||||
@@ -67,7 +67,7 @@ const Field = forwardRef(
|
||||
borderColor: theme.palette.border.dark,
|
||||
},
|
||||
"&:has(.input-error) .MuiOutlinedInput-root fieldset": {
|
||||
borderColor: theme.palette.error.text,
|
||||
borderColor: theme.palette.error.contrastText,
|
||||
},
|
||||
display: hidden ? "none" : "",
|
||||
}}
|
||||
@@ -83,7 +83,7 @@ const Field = forwardRef(
|
||||
<Typography
|
||||
component="span"
|
||||
ml={theme.spacing(1)}
|
||||
color={theme.palette.error.text}
|
||||
color={theme.palette.error.contrastText}
|
||||
>
|
||||
*
|
||||
</Typography>
|
||||
@@ -189,7 +189,7 @@ const Field = forwardRef(
|
||||
<Typography
|
||||
component="span"
|
||||
className="input-error"
|
||||
color={theme.palette.error.text}
|
||||
color={theme.palette.error.contrastText}
|
||||
mt={theme.spacing(2)}
|
||||
sx={{
|
||||
opacity: 0.8,
|
||||
|
||||
@@ -41,7 +41,7 @@ const Radio = (props) => {
|
||||
color: "transparent",
|
||||
width: 16,
|
||||
height: 16,
|
||||
boxShadow: "inset 0 0 0 1px #656a74",
|
||||
boxShadow: `inset 0 0 0 1px ${theme.palette.secondary.main}`,
|
||||
mt: theme.spacing(0.5),
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -99,7 +99,7 @@ const Search = ({
|
||||
<Typography
|
||||
component="span"
|
||||
className="input-error"
|
||||
color={theme.palette.error.text}
|
||||
color={theme.palette.error.contrastText}
|
||||
mt={theme.spacing(2)}
|
||||
sx={{
|
||||
opacity: 0.8,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
.label {
|
||||
border: 1px solid #000;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
@@ -31,7 +31,7 @@ const BaseLabel = ({ label, styles, children }) => {
|
||||
className="label"
|
||||
sx={{
|
||||
borderRadius: borderRadius,
|
||||
borderColor: theme.palette.text.tertiary,
|
||||
border: `1px solid ${theme.palette.text.tertiary}`,
|
||||
color: theme.palette.text.tertiary,
|
||||
padding: padding,
|
||||
...styles,
|
||||
@@ -127,22 +127,22 @@ const StatusLabel = ({ status, text, customStyles }) => {
|
||||
const colors = {
|
||||
up: {
|
||||
dotColor: theme.palette.success.main,
|
||||
bgColor: theme.palette.success.bg,
|
||||
borderColor: theme.palette.success.light,
|
||||
bgColor: theme.palette.success./* dark */ contrastText,
|
||||
borderColor: theme.palette.success.main /* light */,
|
||||
},
|
||||
down: {
|
||||
dotColor: theme.palette.error.text,
|
||||
bgColor: theme.palette.error.bg,
|
||||
dotColor: theme.palette.error.contrastText,
|
||||
bgColor: theme.palette.error.dark,
|
||||
borderColor: theme.palette.error.light,
|
||||
},
|
||||
paused: {
|
||||
dotColor: theme.palette.warning.main,
|
||||
bgColor: theme.palette.warning.bg,
|
||||
bgColor: theme.palette.warning.dark,
|
||||
borderColor: theme.palette.warning.light,
|
||||
},
|
||||
pending: {
|
||||
dotColor: theme.palette.warning.main,
|
||||
bgColor: theme.palette.warning.bg,
|
||||
bgColor: theme.palette.warning.dark,
|
||||
borderColor: theme.palette.warning.light,
|
||||
},
|
||||
"cannot resolve": {
|
||||
|
||||
File renamed without changes.
+1
-1
@@ -1,4 +1,4 @@
|
||||
import Sidebar from "../../Components/Sidebar";
|
||||
import Sidebar from "../../Sidebar";
|
||||
import { Outlet } from "react-router";
|
||||
import { Stack } from "@mui/material";
|
||||
|
||||
@@ -34,11 +34,11 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick, error }) =>
|
||||
backgroundColor: theme.palette.background.fill,
|
||||
"&:has(.input-error)": {
|
||||
borderColor: theme.palette.error.main,
|
||||
backgroundColor: theme.palette.error.bg,
|
||||
backgroundColor: theme.palette.error.dark,
|
||||
py: theme.spacing(4),
|
||||
px: theme.spacing(8),
|
||||
"& > .MuiStack-root > svg": {
|
||||
fill: theme.palette.error.text,
|
||||
fill: theme.palette.error.contrastText,
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
},
|
||||
@@ -85,7 +85,7 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick, error }) =>
|
||||
<Typography
|
||||
component="p"
|
||||
className="input-error"
|
||||
color={theme.palette.error.text}
|
||||
color={theme.palette.error.contrastText}
|
||||
>
|
||||
{error}
|
||||
</Typography>
|
||||
|
||||
@@ -19,7 +19,7 @@ import { useLocation, useNavigate } from "react-router";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { clearAuthState } from "../../Features/Auth/authSlice";
|
||||
import { setMode, toggleSidebar } from "../../Features/UI/uiSlice";
|
||||
import { toggleSidebar } from "../../Features/UI/uiSlice";
|
||||
import { clearUptimeMonitorState } from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
|
||||
import Avatar from "../Avatar";
|
||||
import LockSvg from "../../assets/icons/lock.svg?react";
|
||||
@@ -29,7 +29,6 @@ import LogoutSvg from "../../assets/icons/logout.svg?react";
|
||||
import Support from "../../assets/icons/support.svg?react";
|
||||
import Dashboard from "../../assets/icons/dashboard.svg?react";
|
||||
import Account from "../../assets/icons/user-edit.svg?react";
|
||||
import StatusPages from "../../assets/icons/status-pages.svg?react";
|
||||
import Maintenance from "../../assets/icons/maintenance.svg?react";
|
||||
import Monitors from "../../assets/icons/monitors.svg?react";
|
||||
import Incidents from "../../assets/icons/incidents.svg?react";
|
||||
@@ -54,6 +53,7 @@ const menu = [
|
||||
nested: [
|
||||
{ name: "Monitors", path: "monitors", icon: <Monitors /> },
|
||||
{ name: "Pagespeed", path: "pagespeed", icon: <PageSpeed /> },
|
||||
{ name: "Infrastructure", path: "infrastructure", icon: <Integrations /> },
|
||||
],
|
||||
},
|
||||
{ name: "Incidents", path: "incidents", icon: <Incidents /> },
|
||||
@@ -113,7 +113,6 @@ function Sidebar() {
|
||||
const [popup, setPopup] = useState();
|
||||
const { user } = useSelector((state) => state.auth);
|
||||
|
||||
// Remove demo password if demo
|
||||
const accountMenuItem = menu.find((item) => item.name === "Account");
|
||||
if (user.role?.includes("demo") && accountMenuItem) {
|
||||
accountMenuItem.nested = accountMenuItem.nested.filter((item) => {
|
||||
@@ -148,7 +147,9 @@ function Sidebar() {
|
||||
if (matchedKey) {
|
||||
setOpen((prev) => ({ ...prev, [PATH_MAP[matchedKey]]: true }));
|
||||
}
|
||||
}, []);
|
||||
}, [location]);
|
||||
|
||||
/* TODO refactor this, there are a some ternaries and comments in the return */
|
||||
|
||||
return (
|
||||
<Stack
|
||||
@@ -181,7 +182,13 @@ function Sidebar() {
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
gap={theme.spacing(4)}
|
||||
onClick={() => window.open("https://github.com/bluewave-labs/bluewave-uptime", "_blank", "noreferrer")}
|
||||
onClick={() =>
|
||||
window.open(
|
||||
"https://github.com/bluewave-labs/bluewave-uptime",
|
||||
"_blank",
|
||||
"noreferrer"
|
||||
)
|
||||
}
|
||||
sx={{ cursor: "pointer" }}
|
||||
>
|
||||
<Stack
|
||||
@@ -297,6 +304,7 @@ function Sidebar() {
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
) : collapsed ? (
|
||||
/* TODO Do we ever get here? */
|
||||
<React.Fragment key={item.name}>
|
||||
<Tooltip
|
||||
placement="right"
|
||||
@@ -616,22 +624,6 @@ function Sidebar() {
|
||||
</MenuItem>
|
||||
)}
|
||||
{collapsed && <Divider />}
|
||||
{/* <MenuItem
|
||||
onClick={() => {
|
||||
dispatch(setMode("light"));
|
||||
closePopup();
|
||||
}}
|
||||
>
|
||||
Light
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
dispatch(setMode("dark"));
|
||||
closePopup();
|
||||
}}
|
||||
>
|
||||
Dark
|
||||
</MenuItem> */}
|
||||
<Divider />
|
||||
<MenuItem
|
||||
onClick={logout}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Box, Button } from "@mui/material";
|
||||
import { Heading } from "../../Components/Heading";
|
||||
|
||||
/**
|
||||
* This is the Infrastructure monitoring page. This is a work in progress
|
||||
*
|
||||
* @param - Define params.
|
||||
* @returns {JSX.Element} The infrastructure monitoring page.
|
||||
*/
|
||||
|
||||
function Infrastructure() {
|
||||
return (
|
||||
<Box component="main">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
// navigate("/monitors/create");
|
||||
}}
|
||||
sx={{ fontWeight: 500 }}
|
||||
>
|
||||
Create monitor
|
||||
</Button>
|
||||
<Heading component="h2">Infrastructure monitors</Heading>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export { Infrastructure };
|
||||
@@ -114,7 +114,7 @@ const ActionsMenu = ({ /* isAdmin, */ maintenanceWindow, updateCallback }) => {
|
||||
"& ul": { p: theme.spacing(2.5) },
|
||||
"& li": { m: 0 },
|
||||
"& li:last-of-type": {
|
||||
color: theme.palette.error.text,
|
||||
color: theme.palette.error.contrastText,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -333,7 +333,7 @@ const CreateMonitor = () => {
|
||||
<Typography
|
||||
component="p"
|
||||
className="input-error"
|
||||
color={theme.palette.error.text}
|
||||
color={theme.palette.error.contrastText}
|
||||
>
|
||||
{errors["type"]}
|
||||
</Typography>
|
||||
|
||||
@@ -61,7 +61,7 @@ const UpBarChart = memo(({ data, type, onBarHover }) => {
|
||||
? { main: theme.palette.success.main, light: theme.palette.success.light }
|
||||
: uptime > 50
|
||||
? { main: theme.palette.warning.main, light: theme.palette.warning.light }
|
||||
: { main: theme.palette.error.text, light: theme.palette.error.light };
|
||||
: { main: theme.palette.error.contrastText, light: theme.palette.error.light };
|
||||
};
|
||||
|
||||
// TODO - REMOVE THIS LATER
|
||||
@@ -201,10 +201,10 @@ const DownBarChart = memo(({ data, type, onBarHover }) => {
|
||||
key={`cell-${entry.time}`}
|
||||
fill={
|
||||
hoveredBarIndex === index
|
||||
? theme.palette.error.text
|
||||
? theme.palette.error.contrastText
|
||||
: chartHovered
|
||||
? theme.palette.error.light
|
||||
: theme.palette.error.text
|
||||
: theme.palette.error.contrastText
|
||||
}
|
||||
onMouseEnter={() => {
|
||||
setHoveredBarIndex(index);
|
||||
@@ -246,24 +246,24 @@ const ResponseGaugeChart = ({ data }) => {
|
||||
? {
|
||||
category: "Excellent",
|
||||
main: theme.palette.success.main,
|
||||
bg: theme.palette.success.bg,
|
||||
bg: theme.palette.success.dark,
|
||||
}
|
||||
: responseTime <= 500
|
||||
? {
|
||||
category: "Fair",
|
||||
main: theme.palette.success.main,
|
||||
bg: theme.palette.success.bg,
|
||||
bg: theme.palette.success.dark,
|
||||
}
|
||||
: responseTime <= 600
|
||||
? {
|
||||
category: "Acceptable",
|
||||
main: theme.palette.warning.main,
|
||||
bg: theme.palette.warning.bg,
|
||||
bg: theme.palette.warning.dark,
|
||||
}
|
||||
: {
|
||||
category: "Poor",
|
||||
main: theme.palette.error.text,
|
||||
bg: theme.palette.error.bg,
|
||||
main: theme.palette.error.contrastText,
|
||||
bg: theme.palette.error.dark,
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { Box, Stack, Typography } from "@mui/material";
|
||||
import { Box, Stack } from "@mui/material";
|
||||
import Search from "../../../../Components/Inputs/Search";
|
||||
import MemoizedMonitorTable from "../MonitorTable";
|
||||
import { useState } from "react";
|
||||
import useDebounce from "../../../../Utils/debounce";
|
||||
import PropTypes from "prop-types";
|
||||
import { Heading } from "../../../../Components/Heading";
|
||||
|
||||
const CurrentMonitoring = ({ totalMonitors, monitors, isAdmin }) => {
|
||||
const theme = useTheme();
|
||||
@@ -18,26 +19,15 @@ const CurrentMonitoring = ({ totalMonitors, monitors, isAdmin }) => {
|
||||
return (
|
||||
<Box
|
||||
flex={1}
|
||||
px={theme.spacing(10)}
|
||||
py={theme.spacing(8)}
|
||||
border={1}
|
||||
borderColor={theme.palette.border.light}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
backgroundColor={theme.palette.background.main}
|
||||
>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
mb={theme.spacing(8)}
|
||||
>
|
||||
<Typography
|
||||
component="h2"
|
||||
variant="h2"
|
||||
fontWeight={500}
|
||||
letterSpacing={-0.2}
|
||||
>
|
||||
Actively monitoring
|
||||
</Typography>
|
||||
<Heading component="h2">Actively monitoring</Heading>
|
||||
|
||||
<Box
|
||||
className="current-monitors-counter"
|
||||
color={theme.palette.text.primary}
|
||||
|
||||
@@ -25,7 +25,7 @@ const StatusBox = ({ title, value }) => {
|
||||
</Box>
|
||||
);
|
||||
} else if (title === "down") {
|
||||
color = theme.palette.error.text;
|
||||
color = theme.palette.error.main;
|
||||
icon = (
|
||||
<Box sx={{ ...sharedStyles, transform: "rotate(180deg)", top: 5 }}>
|
||||
<Arrow />
|
||||
|
||||
@@ -109,7 +109,7 @@ const ActionsMenu = ({ monitor, isAdmin, updateCallback }) => {
|
||||
"& ul": { p: theme.spacing(2.5) },
|
||||
"& li": { m: 0 },
|
||||
"& li:last-of-type": {
|
||||
color: theme.palette.error.text,
|
||||
color: theme.palette.error.contrastText,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* TODO take these from here and declare using emotion. Plus, the values should live in the theme */
|
||||
.monitors .MuiStack-root > button:not(.MuiIconButton-root) {
|
||||
font-size: var(--env-var-font-size-medium);
|
||||
height: var(--env-var-height-2);
|
||||
|
||||
@@ -28,20 +28,20 @@ const useUtils = () => {
|
||||
};
|
||||
const statusStyles = {
|
||||
up: {
|
||||
backgroundColor: theme.palette.success.bg,
|
||||
background: `linear-gradient(340deg, ${theme.palette.success.light} -60%, ${theme.palette.success.bg} 35%)`,
|
||||
backgroundColor: theme.palette.success.dark,
|
||||
background: `linear-gradient(340deg, ${theme.palette.success.light} -60%, ${theme.palette.success.dark} 35%)`,
|
||||
borderColor: theme.palette.success.light,
|
||||
"& h2": { color: theme.palette.success.main },
|
||||
},
|
||||
down: {
|
||||
backgroundColor: theme.palette.error.bg,
|
||||
background: `linear-gradient(340deg, ${theme.palette.error.light} -60%, ${theme.palette.error.bg} 35%)`,
|
||||
backgroundColor: theme.palette.error.dark,
|
||||
background: `linear-gradient(340deg, ${theme.palette.error.light} -60%, ${theme.palette.error.dark} 35%)`,
|
||||
borderColor: theme.palette.error.light,
|
||||
"& h2": { color: theme.palette.error.main },
|
||||
},
|
||||
paused: {
|
||||
backgroundColor: theme.palette.warning.bg,
|
||||
background: `linear-gradient(340deg, ${theme.palette.warning.light} -60%, ${theme.palette.warning.bg} 35%)`,
|
||||
backgroundColor: theme.palette.warning.dark,
|
||||
background: `linear-gradient(340deg, ${theme.palette.warning.light} -60%, ${theme.palette.warning.dark} 35%)`,
|
||||
borderColor: theme.palette.warning.light,
|
||||
"& h2": { color: theme.palette.warning.main },
|
||||
},
|
||||
@@ -54,22 +54,22 @@ const useUtils = () => {
|
||||
};
|
||||
const pagespeedStyles = {
|
||||
up: {
|
||||
bg: theme.palette.success.bg,
|
||||
bg: theme.palette.success.dark,
|
||||
light: theme.palette.success.light,
|
||||
stroke: theme.palette.success.main,
|
||||
},
|
||||
down: {
|
||||
bg: theme.palette.error.bg,
|
||||
bg: theme.palette.error.dark,
|
||||
light: theme.palette.error.light,
|
||||
stroke: theme.palette.error.main,
|
||||
},
|
||||
paused: {
|
||||
bg: theme.palette.warning.bg,
|
||||
bg: theme.palette.warning.dark,
|
||||
light: theme.palette.warning.light,
|
||||
stroke: theme.palette.warning.main,
|
||||
},
|
||||
pending: {
|
||||
bg: theme.palette.warning.bg,
|
||||
bg: theme.palette.warning.dark,
|
||||
light: theme.palette.warning.light,
|
||||
stroke: theme.palette.warning.main,
|
||||
},
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { useState } from "react";
|
||||
import { Box, Button, ButtonGroup, Stack, Typography } from "@mui/material";
|
||||
import LoadingButton from '@mui/lab/LoadingButton';
|
||||
import LoadingButton from "@mui/lab/LoadingButton";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { monitorValidation } from "../../../Validation/validation";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { createPageSpeed, checkEndpointResolution } from "../../../Features/PageSpeedMonitor/pageSpeedMonitorSlice";
|
||||
import {
|
||||
createPageSpeed,
|
||||
checkEndpointResolution,
|
||||
} from "../../../Features/PageSpeedMonitor/pageSpeedMonitorSlice";
|
||||
import { createToast } from "../../../Utils/toastUtils";
|
||||
import { logger } from "../../../Utils/Logger";
|
||||
import { ConfigBox } from "../../Monitors/styled";
|
||||
@@ -17,12 +20,12 @@ import Breadcrumbs from "../../../Components/Breadcrumbs";
|
||||
import "./index.css";
|
||||
|
||||
const CreatePageSpeed = () => {
|
||||
const MS_PER_MINUTE = 60000;
|
||||
const { user, authToken } = useSelector((state) => state.auth);
|
||||
const { isLoading } = useSelector((state) => state.pageSpeedMonitors);
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
const MS_PER_MINUTE = 60000;
|
||||
const { user, authToken } = useSelector((state) => state.auth);
|
||||
const { isLoading } = useSelector((state) => state.pageSpeedMonitors);
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
|
||||
const idMap = {
|
||||
"monitor-url": "url",
|
||||
@@ -105,252 +108,260 @@ const CreatePageSpeed = () => {
|
||||
abortEarly: false,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
const newErrors = {};
|
||||
error.details.forEach((err) => {
|
||||
newErrors[err.path[0]] = err.message;
|
||||
});
|
||||
setErrors(newErrors);
|
||||
createToast({ body: "Error validation data." });
|
||||
} else {
|
||||
const checkEndpointAction = await dispatch(
|
||||
checkEndpointResolution({ authToken, monitorURL: form.url })
|
||||
)
|
||||
if (checkEndpointAction.meta.requestStatus === "rejected") {
|
||||
createToast({ body: "The endpoint you entered doesn't resolve. Check the URL again." });
|
||||
setErrors({ url: "The entered URL is not reachable." });
|
||||
return;
|
||||
}
|
||||
if (error) {
|
||||
const newErrors = {};
|
||||
error.details.forEach((err) => {
|
||||
newErrors[err.path[0]] = err.message;
|
||||
});
|
||||
setErrors(newErrors);
|
||||
createToast({ body: "Error validation data." });
|
||||
} else {
|
||||
const checkEndpointAction = await dispatch(
|
||||
checkEndpointResolution({ authToken, monitorURL: form.url })
|
||||
);
|
||||
if (checkEndpointAction.meta.requestStatus === "rejected") {
|
||||
createToast({
|
||||
body: "The endpoint you entered doesn't resolve. Check the URL again.",
|
||||
});
|
||||
setErrors({ url: "The entered URL is not reachable." });
|
||||
return;
|
||||
}
|
||||
|
||||
form = {
|
||||
...form,
|
||||
description: form.name,
|
||||
teamId: user.teamId,
|
||||
userId: user._id,
|
||||
notifications: monitor.notifications,
|
||||
};
|
||||
const action = await dispatch(
|
||||
createPageSpeed({ authToken, monitor: form })
|
||||
);
|
||||
if (action.meta.requestStatus === "fulfilled") {
|
||||
createToast({ body: "Monitor created successfully!" });
|
||||
navigate("/pagespeed");
|
||||
} else {
|
||||
createToast({ body: "Failed to create monitor." });
|
||||
}
|
||||
}
|
||||
};
|
||||
form = {
|
||||
...form,
|
||||
description: form.name,
|
||||
teamId: user.teamId,
|
||||
userId: user._id,
|
||||
notifications: monitor.notifications,
|
||||
};
|
||||
const action = await dispatch(createPageSpeed({ authToken, monitor: form }));
|
||||
if (action.meta.requestStatus === "fulfilled") {
|
||||
createToast({ body: "Monitor created successfully!" });
|
||||
navigate("/pagespeed");
|
||||
} else {
|
||||
createToast({ body: "Failed to create monitor." });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//select values
|
||||
const frequencies = [
|
||||
{ _id: 3, name: "3 minutes" },
|
||||
{ _id: 5, name: "5 minutes" },
|
||||
{ _id: 10, name: "10 minutes" },
|
||||
{ _id: 20, name: "20 minutes" },
|
||||
{ _id: 60, name: "1 hour" },
|
||||
{ _id: 1440, name: "1 day" },
|
||||
{ _id: 10080, name: "1 week" },
|
||||
];
|
||||
return (
|
||||
<Box
|
||||
className="create-monitor"
|
||||
sx={{
|
||||
"& h1": {
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Breadcrumbs
|
||||
list={[
|
||||
{ name: "pagespeed", path: "/pagespeed" },
|
||||
{ name: "create", path: `/pagespeed/create` },
|
||||
]}
|
||||
/>
|
||||
<Stack
|
||||
component="form"
|
||||
className="create-monitor-form"
|
||||
onSubmit={handleCreateMonitor}
|
||||
noValidate
|
||||
spellCheck="false"
|
||||
gap={theme.spacing(12)}
|
||||
mt={theme.spacing(6)}
|
||||
>
|
||||
<Typography component="h1" variant="h1">
|
||||
<Typography component="span" fontSize="inherit">
|
||||
Create your{" "}
|
||||
</Typography>
|
||||
<Typography
|
||||
component="span"
|
||||
fontSize="inherit"
|
||||
fontWeight="inherit"
|
||||
color={theme.palette.text.secondary}
|
||||
>
|
||||
pagespeed monitor
|
||||
</Typography>
|
||||
</Typography>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">General settings</Typography>
|
||||
<Typography component="p">
|
||||
Here you can select the URL of the host, together with the type of
|
||||
monitor.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(15)}>
|
||||
<Field
|
||||
type={"url"}
|
||||
id="monitor-url"
|
||||
label="URL to monitor"
|
||||
https={https}
|
||||
placeholder="google.com"
|
||||
value={monitor.url}
|
||||
onChange={handleChange}
|
||||
error={errors["url"]}
|
||||
/>
|
||||
<Field
|
||||
type="text"
|
||||
id="monitor-name"
|
||||
label="Display name"
|
||||
isOptional={true}
|
||||
placeholder="Google"
|
||||
value={monitor.name}
|
||||
onChange={handleChange}
|
||||
error={errors["name"]}
|
||||
/>
|
||||
</Stack>
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">Checks to perform</Typography>
|
||||
<Typography component="p">
|
||||
You can always add or remove checks after adding your site.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(12)}>
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
<Radio
|
||||
id="monitor-checks-http"
|
||||
title="Website monitoring"
|
||||
desc="Use HTTP(s) to monitor your website or API endpoint."
|
||||
size="small"
|
||||
value="http"
|
||||
checked={monitor.type === "pagespeed"}
|
||||
onChange={(event) => handleChange(event)}
|
||||
/>
|
||||
<ButtonGroup sx={{ ml: "32px" }}>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={https.toString()}
|
||||
onClick={() => setHttps(true)}
|
||||
>
|
||||
HTTPS
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(!https).toString()}
|
||||
onClick={() => setHttps(false)}
|
||||
>
|
||||
HTTP
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Stack>
|
||||
{errors["type"] ? (
|
||||
<Box className="error-container">
|
||||
<Typography
|
||||
component="p"
|
||||
className="input-error"
|
||||
color={theme.palette.error.text}
|
||||
>
|
||||
{errors["type"]}
|
||||
</Typography>
|
||||
</Box>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</Stack>
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">Incident notifications</Typography>
|
||||
<Typography component="p">
|
||||
When there is an incident, notify users.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
<Typography component="p">When there is a new incident,</Typography>
|
||||
<Checkbox
|
||||
id="notify-sms"
|
||||
label="Notify via SMS (coming soon)"
|
||||
isChecked={false}
|
||||
value=""
|
||||
onChange={() => logger.warn("disabled")}
|
||||
isDisabled={true}
|
||||
/>
|
||||
<Checkbox
|
||||
id="notify-email-default"
|
||||
label={`Notify via email (to ${user.email})`}
|
||||
isChecked={monitor.notifications.some(
|
||||
(notification) => notification.type === "email"
|
||||
)}
|
||||
value={user?.email}
|
||||
onChange={(event) => handleChange(event)}
|
||||
/>
|
||||
<Checkbox
|
||||
id="notify-email"
|
||||
label="Also notify via email to multiple addresses (coming soon)"
|
||||
isChecked={false}
|
||||
value=""
|
||||
onChange={() => logger.warn("disabled")}
|
||||
isDisabled={true}
|
||||
/>
|
||||
{monitor.notifications.some(
|
||||
(notification) => notification.type === "emails"
|
||||
) ? (
|
||||
<Box mx={theme.spacing(16)}>
|
||||
<Field
|
||||
id="notify-email-list"
|
||||
type="text"
|
||||
placeholder="name@gmail.com"
|
||||
value=""
|
||||
onChange={() => logger.warn("disabled")}
|
||||
/>
|
||||
<Typography mt={theme.spacing(4)}>
|
||||
You can separate multiple emails with a comma
|
||||
</Typography>
|
||||
</Box>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</Stack>
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">Advanced settings</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(12)}>
|
||||
<Select
|
||||
id="monitor-interval"
|
||||
label="Check frequency"
|
||||
value={monitor.interval || 3}
|
||||
onChange={(event) => handleChange(event, "interval")}
|
||||
items={frequencies}
|
||||
/>
|
||||
</Stack>
|
||||
</ConfigBox>
|
||||
<Stack direction="row" justifyContent="flex-end">
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleCreateMonitor}
|
||||
disabled={Object.keys(errors).length !== 0 && true}
|
||||
loading={isLoading}
|
||||
>
|
||||
Create monitor
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
//select values
|
||||
const frequencies = [
|
||||
{ _id: 3, name: "3 minutes" },
|
||||
{ _id: 5, name: "5 minutes" },
|
||||
{ _id: 10, name: "10 minutes" },
|
||||
{ _id: 20, name: "20 minutes" },
|
||||
{ _id: 60, name: "1 hour" },
|
||||
{ _id: 1440, name: "1 day" },
|
||||
{ _id: 10080, name: "1 week" },
|
||||
];
|
||||
return (
|
||||
<Box
|
||||
className="create-monitor"
|
||||
sx={{
|
||||
"& h1": {
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Breadcrumbs
|
||||
list={[
|
||||
{ name: "pagespeed", path: "/pagespeed" },
|
||||
{ name: "create", path: `/pagespeed/create` },
|
||||
]}
|
||||
/>
|
||||
<Stack
|
||||
component="form"
|
||||
className="create-monitor-form"
|
||||
onSubmit={handleCreateMonitor}
|
||||
noValidate
|
||||
spellCheck="false"
|
||||
gap={theme.spacing(12)}
|
||||
mt={theme.spacing(6)}
|
||||
>
|
||||
<Typography
|
||||
component="h1"
|
||||
variant="h1"
|
||||
>
|
||||
<Typography
|
||||
component="span"
|
||||
fontSize="inherit"
|
||||
>
|
||||
Create your{" "}
|
||||
</Typography>
|
||||
<Typography
|
||||
component="span"
|
||||
fontSize="inherit"
|
||||
fontWeight="inherit"
|
||||
color={theme.palette.text.secondary}
|
||||
>
|
||||
pagespeed monitor
|
||||
</Typography>
|
||||
</Typography>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">General settings</Typography>
|
||||
<Typography component="p">
|
||||
Here you can select the URL of the host, together with the type of monitor.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(15)}>
|
||||
<Field
|
||||
type={"url"}
|
||||
id="monitor-url"
|
||||
label="URL to monitor"
|
||||
https={https}
|
||||
placeholder="google.com"
|
||||
value={monitor.url}
|
||||
onChange={handleChange}
|
||||
error={errors["url"]}
|
||||
/>
|
||||
<Field
|
||||
type="text"
|
||||
id="monitor-name"
|
||||
label="Display name"
|
||||
isOptional={true}
|
||||
placeholder="Google"
|
||||
value={monitor.name}
|
||||
onChange={handleChange}
|
||||
error={errors["name"]}
|
||||
/>
|
||||
</Stack>
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">Checks to perform</Typography>
|
||||
<Typography component="p">
|
||||
You can always add or remove checks after adding your site.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(12)}>
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
<Radio
|
||||
id="monitor-checks-http"
|
||||
title="Website monitoring"
|
||||
desc="Use HTTP(s) to monitor your website or API endpoint."
|
||||
size="small"
|
||||
value="http"
|
||||
checked={monitor.type === "pagespeed"}
|
||||
onChange={(event) => handleChange(event)}
|
||||
/>
|
||||
<ButtonGroup sx={{ ml: "32px" }}>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={https.toString()}
|
||||
onClick={() => setHttps(true)}
|
||||
>
|
||||
HTTPS
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(!https).toString()}
|
||||
onClick={() => setHttps(false)}
|
||||
>
|
||||
HTTP
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Stack>
|
||||
{errors["type"] ? (
|
||||
<Box className="error-container">
|
||||
<Typography
|
||||
component="p"
|
||||
className="input-error"
|
||||
color={theme.palette.error.contrastText}
|
||||
>
|
||||
{errors["type"]}
|
||||
</Typography>
|
||||
</Box>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</Stack>
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">Incident notifications</Typography>
|
||||
<Typography component="p">
|
||||
When there is an incident, notify users.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
<Typography component="p">When there is a new incident,</Typography>
|
||||
<Checkbox
|
||||
id="notify-sms"
|
||||
label="Notify via SMS (coming soon)"
|
||||
isChecked={false}
|
||||
value=""
|
||||
onChange={() => logger.warn("disabled")}
|
||||
isDisabled={true}
|
||||
/>
|
||||
<Checkbox
|
||||
id="notify-email-default"
|
||||
label={`Notify via email (to ${user.email})`}
|
||||
isChecked={monitor.notifications.some(
|
||||
(notification) => notification.type === "email"
|
||||
)}
|
||||
value={user?.email}
|
||||
onChange={(event) => handleChange(event)}
|
||||
/>
|
||||
<Checkbox
|
||||
id="notify-email"
|
||||
label="Also notify via email to multiple addresses (coming soon)"
|
||||
isChecked={false}
|
||||
value=""
|
||||
onChange={() => logger.warn("disabled")}
|
||||
isDisabled={true}
|
||||
/>
|
||||
{monitor.notifications.some(
|
||||
(notification) => notification.type === "emails"
|
||||
) ? (
|
||||
<Box mx={theme.spacing(16)}>
|
||||
<Field
|
||||
id="notify-email-list"
|
||||
type="text"
|
||||
placeholder="name@gmail.com"
|
||||
value=""
|
||||
onChange={() => logger.warn("disabled")}
|
||||
/>
|
||||
<Typography mt={theme.spacing(4)}>
|
||||
You can separate multiple emails with a comma
|
||||
</Typography>
|
||||
</Box>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</Stack>
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">Advanced settings</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(12)}>
|
||||
<Select
|
||||
id="monitor-interval"
|
||||
label="Check frequency"
|
||||
value={monitor.interval || 3}
|
||||
onChange={(event) => handleChange(event, "interval")}
|
||||
items={frequencies}
|
||||
/>
|
||||
</Stack>
|
||||
</ConfigBox>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="flex-end"
|
||||
>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleCreateMonitor}
|
||||
disabled={Object.keys(errors).length !== 0 && true}
|
||||
loading={isLoading}
|
||||
>
|
||||
Create monitor
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreatePageSpeed;
|
||||
@@ -127,22 +127,22 @@ const PieChart = ({ audits }) => {
|
||||
return {
|
||||
stroke: theme.palette.success.main,
|
||||
strokeBg: theme.palette.success.light,
|
||||
text: theme.palette.success.text,
|
||||
bg: theme.palette.success.bg,
|
||||
text: theme.palette.success.contrastText,
|
||||
bg: theme.palette.success.dark,
|
||||
};
|
||||
else if (value >= 50 && value < 90)
|
||||
return {
|
||||
stroke: theme.palette.warning.main,
|
||||
strokeBg: theme.palette.warning.light,
|
||||
text: theme.palette.warning.text,
|
||||
bg: theme.palette.warning.bg,
|
||||
text: theme.palette.warning.contrastText,
|
||||
bg: theme.palette.warning.dark,
|
||||
};
|
||||
else if (value >= 0 && value < 50)
|
||||
return {
|
||||
stroke: theme.palette.error.text,
|
||||
stroke: theme.palette.error.contrastText,
|
||||
strokeBg: theme.palette.error.light,
|
||||
text: theme.palette.error.text,
|
||||
bg: theme.palette.error.bg,
|
||||
text: theme.palette.error.contrastText,
|
||||
bg: theme.palette.error.dark,
|
||||
};
|
||||
return {
|
||||
stroke: theme.palette.unresolved.main,
|
||||
|
||||
@@ -362,7 +362,7 @@ const PageSpeedDetails = ({ isAdmin }) => {
|
||||
: score >= 50
|
||||
? theme.palette.warning.main
|
||||
: score >= 0
|
||||
? theme.palette.error.text
|
||||
? theme.palette.error.contrastText
|
||||
: theme.palette.unresolved.main;
|
||||
|
||||
// Find the position where the number ends and the unit begins
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
#Pages Folder
|
||||
@@ -0,0 +1,244 @@
|
||||
const typographyBase = 14;
|
||||
|
||||
/* TODO
|
||||
Check for px in codebase. All font sizes should be in REM and should live here.
|
||||
Rest should be checked on each case
|
||||
*/
|
||||
const typographyLevels = {
|
||||
base: typographyBase,
|
||||
xs: `${(typographyBase - 4) / 16}rem`,
|
||||
s: `${(typographyBase - 2) / 16}rem`,
|
||||
m: `${typographyBase / 16}rem`,
|
||||
l: `${(typographyBase + 2) / 16}rem`,
|
||||
xl: `${(typographyBase + 10) / 16}rem`,
|
||||
};
|
||||
|
||||
/* TODO Review color palette and semantic colors */
|
||||
const paletteColors = {
|
||||
white: "#FFFFFF",
|
||||
gray50: "#FEFEFE",
|
||||
gray60: "#FEFDFE",
|
||||
gray70: "#FDFDFD",
|
||||
gray80: "#FDFCFD",
|
||||
gray90: "#FCFCFD",
|
||||
gray100: "#F4F4F4",
|
||||
gray200: "#E3E3E3",
|
||||
gray300: "#A2A3A3",
|
||||
gray500: "#838C99",
|
||||
gray600: "#454546",
|
||||
gray750: "#36363E",
|
||||
gray800: "#2D2D33",
|
||||
gray850: "#131315",
|
||||
gray860: "#111113",
|
||||
gray870: "#0F0F11",
|
||||
gray880: "#0C0C0E",
|
||||
gray890: "#09090B",
|
||||
blueGray20: "#E8F0FE",
|
||||
blueGray150: "#667085",
|
||||
blueGray200: "#475467",
|
||||
blueGray400: "#344054",
|
||||
blueGray900: "#1c2130",
|
||||
blueBlueWave: "#1570EF",
|
||||
blue700: "#4E5BA6",
|
||||
purple300: "#664EFF",
|
||||
purple400: "#3A1BFF",
|
||||
green50: "#D4F4E1",
|
||||
green150: "#45BB7A",
|
||||
green400: "#079455",
|
||||
green800: "#1C4428",
|
||||
green900: "#12261E",
|
||||
red50: "#F9ECED",
|
||||
red100: "#FBD1D1",
|
||||
red200: "#F04438",
|
||||
red300: "#D32F2F",
|
||||
red700: "#542426",
|
||||
red800: "#301A1F",
|
||||
orange50: "#FEF8EA",
|
||||
orange100: "#FFECBC",
|
||||
orange300: "#FDB022",
|
||||
orange400: "#FF9F00",
|
||||
orange500: "#E88C30",
|
||||
orange600: "#DC6803",
|
||||
orange800: "#624711",
|
||||
};
|
||||
|
||||
const semanticColors = {
|
||||
primary: {
|
||||
main: {
|
||||
light: paletteColors.blueBlueWave,
|
||||
dark: paletteColors.blueBlueWave,
|
||||
},
|
||||
// TODO we dont have primary light, dark or contrast text
|
||||
},
|
||||
secondary: {
|
||||
main: {
|
||||
light: paletteColors.gray100,
|
||||
dark: paletteColors.gray800,
|
||||
},
|
||||
contrastText: {
|
||||
light: paletteColors.blueGray200,
|
||||
dark: paletteColors.blueGray200,
|
||||
},
|
||||
light: {
|
||||
light: paletteColors.gray200,
|
||||
dark: paletteColors.gray200,
|
||||
},
|
||||
dark: {
|
||||
light: paletteColors.gray200,
|
||||
dark: paletteColors.gray200,
|
||||
},
|
||||
},
|
||||
success: {
|
||||
main: {
|
||||
light: paletteColors.green400,
|
||||
dark: paletteColors.green400,
|
||||
},
|
||||
contrastText: {
|
||||
light: paletteColors.green50,
|
||||
dark: paletteColors.green900,
|
||||
},
|
||||
light: {
|
||||
light: paletteColors.green50,
|
||||
dark: paletteColors.green150,
|
||||
},
|
||||
dark: {
|
||||
light: paletteColors.green800,
|
||||
dark: paletteColors.green900,
|
||||
},
|
||||
},
|
||||
error: {
|
||||
main: {
|
||||
light: paletteColors.red300,
|
||||
dark: paletteColors.red300,
|
||||
},
|
||||
contrastText: {
|
||||
light: paletteColors.gray50,
|
||||
dark: paletteColors.gray50,
|
||||
},
|
||||
light: {
|
||||
light: paletteColors.red100,
|
||||
dark: paletteColors.red700,
|
||||
},
|
||||
dark: {
|
||||
light: paletteColors.red50,
|
||||
dark: paletteColors.red800,
|
||||
},
|
||||
},
|
||||
warning: {
|
||||
main: {
|
||||
light: paletteColors.orange300,
|
||||
dark: paletteColors.orange400,
|
||||
},
|
||||
contrastText: {
|
||||
light: paletteColors.orange600,
|
||||
dark: paletteColors.orange500,
|
||||
},
|
||||
light: {
|
||||
light: paletteColors.orange100,
|
||||
dark: paletteColors.orange800,
|
||||
},
|
||||
dark: {
|
||||
light: paletteColors.orange50,
|
||||
dark: paletteColors.gray800,
|
||||
},
|
||||
},
|
||||
/* From this part on, try to create semantic structure, not feature based structure */
|
||||
gradient: {
|
||||
color1: {
|
||||
light: paletteColors.gray90,
|
||||
dark: paletteColors.gray890,
|
||||
},
|
||||
color2: {
|
||||
light: paletteColors.gray80,
|
||||
dark: paletteColors.gray880,
|
||||
},
|
||||
color3: {
|
||||
light: paletteColors.gray70,
|
||||
dark: paletteColors.gray870,
|
||||
},
|
||||
color4: {
|
||||
light: paletteColors.gray60,
|
||||
dark: paletteColors.gray860,
|
||||
},
|
||||
color5: {
|
||||
light: paletteColors.gray50,
|
||||
dark: paletteColors.gray850,
|
||||
},
|
||||
},
|
||||
background: {
|
||||
main: {
|
||||
light: paletteColors.white,
|
||||
dark: paletteColors.gray850,
|
||||
},
|
||||
alt: {
|
||||
light: paletteColors.gray90,
|
||||
dark: paletteColors.gray890,
|
||||
},
|
||||
fill: {
|
||||
light: paletteColors.gray100,
|
||||
dark: paletteColors.gray800,
|
||||
},
|
||||
accent: {
|
||||
light: paletteColors.gray100,
|
||||
dark: paletteColors.gray850,
|
||||
},
|
||||
},
|
||||
text: {
|
||||
primary: {
|
||||
light: paletteColors.blueGray900,
|
||||
dark: paletteColors.gray100,
|
||||
},
|
||||
secondary: {
|
||||
light: paletteColors.blueGray400,
|
||||
dark: paletteColors.gray200,
|
||||
},
|
||||
tertiary: {
|
||||
light: paletteColors.blueGray200,
|
||||
dark: paletteColors.gray300,
|
||||
},
|
||||
accent: {
|
||||
light: paletteColors.gray500,
|
||||
dark: paletteColors.gray500,
|
||||
},
|
||||
},
|
||||
border: {
|
||||
light: {
|
||||
light: paletteColors.gray200,
|
||||
dark: paletteColors.gray800,
|
||||
},
|
||||
dark: {
|
||||
light: paletteColors.gray200,
|
||||
dark: paletteColors.gray750,
|
||||
},
|
||||
},
|
||||
unresolved: {
|
||||
main: {
|
||||
light: paletteColors.blue700,
|
||||
dark: paletteColors.purple300,
|
||||
},
|
||||
light: {
|
||||
light: paletteColors.blueGray20,
|
||||
dark: paletteColors.purple400,
|
||||
},
|
||||
bg: {
|
||||
light: paletteColors.gray100,
|
||||
dark: paletteColors.gray100,
|
||||
},
|
||||
},
|
||||
other: {
|
||||
icon: {
|
||||
light: paletteColors.blueGray150,
|
||||
},
|
||||
line: {
|
||||
light: paletteColors.gray200,
|
||||
},
|
||||
grid: {
|
||||
light: paletteColors.gray300,
|
||||
dark: paletteColors.gray600,
|
||||
},
|
||||
autofill: {
|
||||
light: paletteColors.blueGray20,
|
||||
},
|
||||
},
|
||||
};
|
||||
export { typographyLevels, semanticColors as colors };
|
||||
+100
-259
@@ -1,267 +1,108 @@
|
||||
import { createTheme } from "@mui/material";
|
||||
import { baseTheme } from "./globalTheme";
|
||||
import { colors } from "./constants";
|
||||
|
||||
const text = {
|
||||
primary: "#fafafa",
|
||||
secondary: "#e6e6e6",
|
||||
tertiary: "#a1a1aa",
|
||||
accent: "#8e8e8f",
|
||||
disabled: "rgba(172, 172, 172, 0.3)",
|
||||
};
|
||||
const background = {
|
||||
main: "#151518",
|
||||
alt: "#09090b",
|
||||
fill: "#2D2D33",
|
||||
accent: "#18181a",
|
||||
};
|
||||
const border = { light: "#27272a", dark: "#36363e" };
|
||||
const {
|
||||
primary,
|
||||
secondary,
|
||||
success,
|
||||
error,
|
||||
warning,
|
||||
gradient: {
|
||||
color1: { dark: color1 },
|
||||
color2: { dark: color2 },
|
||||
color3: { dark: color3 },
|
||||
color4: { dark: color4 },
|
||||
color5: { dark: color5 },
|
||||
},
|
||||
background,
|
||||
text,
|
||||
border,
|
||||
unresolved,
|
||||
other,
|
||||
} = colors;
|
||||
|
||||
const fontFamilyDefault =
|
||||
'"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif';
|
||||
const shadow =
|
||||
"0px 4px 24px -4px rgba(255, 255, 255, 0.03), 0px 3px 3px -3px rgba(255, 255, 255, 0.01)";
|
||||
const palette = {
|
||||
primary: { main: primary.main.dark },
|
||||
secondary: {
|
||||
main: secondary.main.dark,
|
||||
contrastText: secondary.contrastText.dark,
|
||||
light: secondary.dark.dark,
|
||||
dark: secondary.dark.dark,
|
||||
},
|
||||
success: {
|
||||
main: success.main.dark,
|
||||
contrastText: success.contrastText.dark,
|
||||
light: success.light.dark,
|
||||
dark: success.dark.dark,
|
||||
},
|
||||
error: {
|
||||
main: error.main.dark,
|
||||
contrastText: error.contrastText.dark,
|
||||
light: error.light.dark,
|
||||
dark: error.dark.dark,
|
||||
},
|
||||
warning: {
|
||||
main: warning.main.dark,
|
||||
light: warning.light.dark,
|
||||
contrastText: warning.contrastText.dark,
|
||||
dark: warning.dark.dark,
|
||||
},
|
||||
/* From this part on, try to create semantic structure, not feature based structure */
|
||||
percentage: {
|
||||
uptimePoor: error.main.dark,
|
||||
uptimeFair: warning.contrastText.dark,
|
||||
uptimeGood: warning.main.dark /* Change for a success color? ?*/,
|
||||
uptimeExcellent: success.main.dark,
|
||||
},
|
||||
unresolved: {
|
||||
main: unresolved.main.dark,
|
||||
light: unresolved.light.dark,
|
||||
bg: unresolved.bg.dark,
|
||||
},
|
||||
divider: border.light.dark,
|
||||
other: {
|
||||
icon: text.secondary.dark,
|
||||
line: border.light.dark,
|
||||
fill: background.accent.dark,
|
||||
grid: other.grid.dark,
|
||||
autofill: secondary.main.dark,
|
||||
},
|
||||
gradient: {
|
||||
color1,
|
||||
color2,
|
||||
color3,
|
||||
color4,
|
||||
color5,
|
||||
},
|
||||
text: {
|
||||
primary: text.primary.dark,
|
||||
secondary: text.secondary.dark,
|
||||
tertiary: text.tertiary.dark,
|
||||
accent: text.accent.dark,
|
||||
},
|
||||
background: {
|
||||
main: background.main.dark,
|
||||
alt: background.alt.dark,
|
||||
fill: background.fill.dark,
|
||||
accent: background.accent.dark,
|
||||
},
|
||||
border: {
|
||||
light: border.light.dark,
|
||||
dark: border.dark.dark,
|
||||
},
|
||||
info: {
|
||||
text: text.primary.dark,
|
||||
main: text.secondary.dark,
|
||||
bg: background.main.dark,
|
||||
light: background.main.dark,
|
||||
border: border.light.dark,
|
||||
},
|
||||
};
|
||||
|
||||
const darkTheme = createTheme({
|
||||
typography: {
|
||||
fontFamily: fontFamilyDefault,
|
||||
fontSize: 13,
|
||||
h1: { fontSize: 22, color: text.primary, fontWeight: 500 },
|
||||
h2: { fontSize: 14.5, color: text.secondary, fontWeight: 400 },
|
||||
body1: { fontSize: 13, color: text.tertiary, fontWeight: 400 },
|
||||
body2: { fontSize: 12, color: text.tertiary, fontWeight: 400 },
|
||||
},
|
||||
chart: {
|
||||
header: {
|
||||
fontWeight: 400,
|
||||
fill: text.tertiary,
|
||||
fontSize: 11,
|
||||
},
|
||||
subheader: {
|
||||
fontWeight: 400,
|
||||
fill: text.tertiary,
|
||||
fontSize: 9,
|
||||
},
|
||||
},
|
||||
palette: {
|
||||
mode: "dark",
|
||||
primary: { main: "#1570ef" },
|
||||
secondary: { main: "#2D2D33" },
|
||||
text: text,
|
||||
background: background,
|
||||
border: border,
|
||||
info: {
|
||||
text: text.primary,
|
||||
main: text.secondary,
|
||||
bg: background.main,
|
||||
light: background.main,
|
||||
border: border.light,
|
||||
},
|
||||
success: {
|
||||
text: "#079455",
|
||||
main: "#45bb7a",
|
||||
light: "#1c4428",
|
||||
bg: "#12261e",
|
||||
},
|
||||
error: {
|
||||
text: "#f04438",
|
||||
main: "#d32f2f",
|
||||
light: "#542426",
|
||||
bg: "#301a1f",
|
||||
dark: "#932020",
|
||||
border: "#f04438",
|
||||
},
|
||||
warning: {
|
||||
text: "#e88c30",
|
||||
main: "#FF9F00",
|
||||
light: "#624711",
|
||||
bg: "#262115",
|
||||
border: "#e88c30",
|
||||
},
|
||||
percentage: {
|
||||
uptimePoor: "#d32f2f",
|
||||
uptimeFair: "#e88c30",
|
||||
uptimeGood: "#ffd600",
|
||||
uptimeExcellent: "#079455",
|
||||
},
|
||||
unresolved: { main: "#664eff", light: "#3a1bff", bg: "#f2f4f7" },
|
||||
divider: border.light,
|
||||
other: {
|
||||
icon: "#e6e6e6",
|
||||
line: "#27272a",
|
||||
fill: "#18181a",
|
||||
grid: "#454546",
|
||||
autofill: "#2d2d33",
|
||||
},
|
||||
},
|
||||
spacing: 2,
|
||||
components: {
|
||||
MuiCssBaseline: {
|
||||
styleOverrides: {
|
||||
body: {
|
||||
backgroundImage:
|
||||
"radial-gradient(circle, #09090b, #0c0c0e, #0f0f11, #111113, #131315, #131315, #131315, #131315, #111113, #0f0f11, #0c0c0e, #09090b)",
|
||||
lineHeight: "inherit",
|
||||
paddingLeft: "calc(100vw - 100%)",
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiButton: {
|
||||
defaultProps: {
|
||||
disableRipple: true,
|
||||
},
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
variants: [
|
||||
{
|
||||
props: (props) => props.variant === "group",
|
||||
style: {
|
||||
color: theme.palette.secondary.contrastText,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
},
|
||||
},
|
||||
{
|
||||
props: (props) => props.variant === "group" && props.filled === "true",
|
||||
style: {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
},
|
||||
{
|
||||
props: (props) =>
|
||||
props.variant === "contained" && props.color === "secondary",
|
||||
style: {
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.dark,
|
||||
},
|
||||
},
|
||||
],
|
||||
fontWeight: 400,
|
||||
borderRadius: 4,
|
||||
boxShadow: "none",
|
||||
textTransform: "none",
|
||||
"&:focus": {
|
||||
outline: "none",
|
||||
},
|
||||
"&:hover": {
|
||||
boxShadow: "none",
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiIconButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: 4,
|
||||
transition: "none",
|
||||
"&:hover": {
|
||||
backgroundColor: border.light,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPaper: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
marginTop: 4,
|
||||
padding: 0,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: border.light,
|
||||
borderRadius: 4,
|
||||
boxShadow: shadow,
|
||||
backgroundColor: background.main,
|
||||
backgroundImage: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiList: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiListItemButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
transition: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiMenuItem: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 4,
|
||||
backgroundColor: "inherit",
|
||||
padding: "4px 6px",
|
||||
color: text.secondary,
|
||||
fontSize: 13,
|
||||
margin: 2,
|
||||
minWidth: 100,
|
||||
"&:hover, &.Mui-selected, &.Mui-selected:hover, &.Mui-selected.Mui-focusVisible":
|
||||
{
|
||||
backgroundColor: background.fill,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableCell: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderBottomColor: border.light,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableHead: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: background.accent,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPagination: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: background.main,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: border.light,
|
||||
"& button": {
|
||||
color: text.tertiary,
|
||||
borderRadius: 4,
|
||||
},
|
||||
"& li:first-of-type button, & li:last-of-type button": {
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: border.light,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPaginationItem: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
"&:not(.MuiPaginationItem-ellipsis):hover, &.Mui-selected": {
|
||||
backgroundColor: background.fill,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiSkeleton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: "#151518",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
shape: {
|
||||
borderRadius: 2,
|
||||
borderThick: 2,
|
||||
boxShadow: shadow,
|
||||
},
|
||||
palette,
|
||||
...baseTheme(palette),
|
||||
});
|
||||
|
||||
export default darkTheme;
|
||||
@@ -0,0 +1,220 @@
|
||||
import { typographyLevels } from "./constants";
|
||||
|
||||
const fontFamilyPrimary = '"Inter" , sans-serif';
|
||||
// const fontFamilySecondary = '"Avenir", sans-serif';
|
||||
|
||||
/* TODO take the color out from here */
|
||||
const shadow =
|
||||
"0px 4px 24px -4px rgba(16, 24, 40, 0.08), 0px 3px 3px -3px rgba(16, 24, 40, 0.03)";
|
||||
|
||||
const baseTheme = (palette) => ({
|
||||
typography: {
|
||||
fontFamily: fontFamilyPrimary,
|
||||
fontSize: 14,
|
||||
h1: {
|
||||
fontSize: typographyLevels.xl,
|
||||
color: palette.text.primary,
|
||||
fontWeight: 500,
|
||||
},
|
||||
h2: {
|
||||
fontSize: typographyLevels.l,
|
||||
color: palette.text.secondary,
|
||||
fontWeight: 400,
|
||||
},
|
||||
body1: {
|
||||
fontSize: typographyLevels.m,
|
||||
color: palette.text.tertiary,
|
||||
fontWeight: 400,
|
||||
},
|
||||
body2: {
|
||||
fontSize: typographyLevels.s,
|
||||
color: palette.text.tertiary,
|
||||
fontWeight: 400,
|
||||
},
|
||||
},
|
||||
/* TODO take chart from here, it should live inside of the gauge, and get info from the theme */
|
||||
chart: {
|
||||
header: {
|
||||
fontWeight: 400,
|
||||
fill: palette.text.tertiary,
|
||||
fontSize: typographyLevels.m,
|
||||
},
|
||||
subheader: {
|
||||
fontWeight: 400,
|
||||
fill: palette.text.tertiary,
|
||||
fontSize: typographyLevels.xs,
|
||||
},
|
||||
},
|
||||
spacing: 2,
|
||||
/* TODO All these should live inside of a component*/
|
||||
components: {
|
||||
MuiButton: {
|
||||
defaultProps: {
|
||||
disableRipple: true,
|
||||
},
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
variants: [
|
||||
{
|
||||
props: (props) => props.variant === "group",
|
||||
style: {
|
||||
color: theme.palette.secondary.contrastText,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
},
|
||||
},
|
||||
{
|
||||
props: (props) => props.variant === "group" && props.filled === "true",
|
||||
style: {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
},
|
||||
{
|
||||
props: (props) =>
|
||||
props.variant === "contained" && props.color === "secondary",
|
||||
style: {
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
},
|
||||
},
|
||||
{
|
||||
props: (props) => props.variant === "contained" && props.disabled,
|
||||
style: {
|
||||
backgroundColor: `${theme.palette.secondary.main} !important`,
|
||||
color: `${theme.palette.secondary.contrastText} !important`,
|
||||
},
|
||||
},
|
||||
],
|
||||
fontWeight: 400,
|
||||
borderRadius: 4,
|
||||
boxShadow: "none",
|
||||
textTransform: "none",
|
||||
"&:focus": {
|
||||
outline: "none",
|
||||
},
|
||||
"&:hover": {
|
||||
boxShadow: "none",
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiIconButton: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
padding: 4,
|
||||
transition: "none",
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.background.fill,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiPaper: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => {
|
||||
return {
|
||||
marginTop: 4,
|
||||
padding: 0,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
borderRadius: 4,
|
||||
boxShadow: shadow,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundImage: "none",
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiList: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiListItemButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
transition: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiMenuItem: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
borderRadius: 4,
|
||||
backgroundColor: "inherit",
|
||||
padding: "4px 6px",
|
||||
color: theme.palette.text.secondary,
|
||||
fontSize: 13,
|
||||
margin: 2,
|
||||
minWidth: 100,
|
||||
"&:hover, &.Mui-selected, &.Mui-selected:hover, &.Mui-selected.Mui-focusVisible":
|
||||
{
|
||||
backgroundColor: theme.palette.background.fill,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiTableCell: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
borderBottomColor: theme.palette.border.light,
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiTableHead: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiPagination: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
backgroundColor: theme.palette.background.main,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
"& button": {
|
||||
color: theme.palette.text.tertiary,
|
||||
borderRadius: 4,
|
||||
},
|
||||
"& li:first-of-type button, & li:last-of-type button": {
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiPaginationItem: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
"&:not(.MuiPaginationItem-ellipsis):hover, &.Mui-selected": {
|
||||
backgroundColor: theme.palette.background.fill,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiSkeleton: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
backgroundColor: theme.palette.unresolved.bg,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
shape: {
|
||||
borderRadius: 2,
|
||||
borderThick: 2,
|
||||
boxShadow: shadow,
|
||||
},
|
||||
});
|
||||
|
||||
export { baseTheme };
|
||||
@@ -1,265 +1,114 @@
|
||||
import { createTheme } from "@mui/material";
|
||||
import { baseTheme } from "./globalTheme";
|
||||
import { colors } from "./constants";
|
||||
|
||||
const text = {
|
||||
primary: "#1c2130",
|
||||
secondary: "#344054",
|
||||
tertiary: "#475467",
|
||||
accent: "#838c99",
|
||||
};
|
||||
const background = {
|
||||
main: "#FFFFFF",
|
||||
alt: "#FCFCFD",
|
||||
fill: "#F4F4F4",
|
||||
accent: "#f9fafb",
|
||||
/*
|
||||
TODO
|
||||
Next step: check if all keys here are being used in the codebase. e.g.: Search codebase for palette.primary; also check for destructuring palette ('= theme.palette')
|
||||
*/
|
||||
|
||||
const {
|
||||
primary,
|
||||
secondary,
|
||||
success,
|
||||
error,
|
||||
warning,
|
||||
gradient: {
|
||||
color1: { light: color1 },
|
||||
color2: { light: color2 },
|
||||
color3: { light: color3 },
|
||||
color4: { light: color4 },
|
||||
color5: { light: color5 },
|
||||
},
|
||||
background,
|
||||
text,
|
||||
border,
|
||||
unresolved,
|
||||
other,
|
||||
} = colors;
|
||||
|
||||
const palette = {
|
||||
primary: { main: primary.main.light },
|
||||
secondary: {
|
||||
main: secondary.main.light,
|
||||
contrastText: secondary.contrastText.light,
|
||||
light: secondary.dark.light,
|
||||
dark: secondary.dark.light,
|
||||
},
|
||||
success: {
|
||||
main: success.main.light,
|
||||
contrastText: success.contrastText.light,
|
||||
light: success.light.light,
|
||||
dark: success.dark.light,
|
||||
},
|
||||
error: {
|
||||
main: error.main.light,
|
||||
contrastText: error.contrastText.light,
|
||||
light: error.light.light,
|
||||
dark: error.dark.light,
|
||||
},
|
||||
warning: {
|
||||
main: warning.main.light,
|
||||
light: warning.light.light,
|
||||
contrastText: warning.contrastText.light,
|
||||
dark: warning.dark.light,
|
||||
},
|
||||
/* From this part on, try to create semantic structure, not feature based structure */
|
||||
percentage: {
|
||||
uptimePoor: error.main.light,
|
||||
uptimeFair: warning.contrastText.light,
|
||||
uptimeGood: warning.main.light /* Change for a success color? */,
|
||||
uptimeExcellent: success.main.light,
|
||||
},
|
||||
unresolved: {
|
||||
main: unresolved.main.light,
|
||||
light: unresolved.light.light,
|
||||
bg: unresolved.bg.light,
|
||||
},
|
||||
divider: border.light.light,
|
||||
other: {
|
||||
icon: other.icon.light,
|
||||
line: other.line.light,
|
||||
fill: secondary.dark.light,
|
||||
grid: other.grid.light,
|
||||
autofill: other.autofill.light,
|
||||
},
|
||||
gradient: {
|
||||
color1,
|
||||
color2,
|
||||
color3,
|
||||
color4,
|
||||
color5,
|
||||
},
|
||||
text: {
|
||||
primary: text.primary.light,
|
||||
secondary: text.secondary.light,
|
||||
tertiary: text.tertiary.light,
|
||||
accent: text.accent.light,
|
||||
},
|
||||
background: {
|
||||
main: background.main.light,
|
||||
alt: background.alt.light,
|
||||
fill: background.fill.light,
|
||||
accent: background.accent.light,
|
||||
},
|
||||
border: {
|
||||
light: border.light.light,
|
||||
dark: border.dark.light,
|
||||
},
|
||||
info: {
|
||||
text: text.primary.light,
|
||||
main: text.tertiary.light,
|
||||
bg: background.main.light,
|
||||
light: background.main.light,
|
||||
border: border.dark.light,
|
||||
},
|
||||
};
|
||||
|
||||
const border = { light: "#eaecf0", dark: "#d0d5dd" };
|
||||
|
||||
const fontFamilyDefault =
|
||||
'"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif';
|
||||
const shadow =
|
||||
"0px 4px 24px -4px rgba(16, 24, 40, 0.08), 0px 3px 3px -3px rgba(16, 24, 40, 0.03)";
|
||||
|
||||
/* TODO I figured out we could have just one theme by passing mode as parameter for theme function. Implement later */
|
||||
const lightTheme = createTheme({
|
||||
typography: {
|
||||
fontFamily: fontFamilyDefault,
|
||||
fontSize: 13,
|
||||
h1: { fontSize: 22, color: text.primary, fontWeight: 500 },
|
||||
h2: { fontSize: 14.5, color: text.secondary, fontWeight: 400 },
|
||||
body1: { fontSize: 13, color: text.tertiary, fontWeight: 400 },
|
||||
body2: { fontSize: 12, color: text.tertiary, fontWeight: 400 },
|
||||
},
|
||||
chart: {
|
||||
header: {
|
||||
fontWeight: 400,
|
||||
fill: text.tertiary,
|
||||
fontSize: 11,
|
||||
},
|
||||
subheader: {
|
||||
fontWeight: 400,
|
||||
fill: text.tertiary,
|
||||
fontSize: 9,
|
||||
},
|
||||
},
|
||||
palette: {
|
||||
primary: { main: "#1570EF" },
|
||||
secondary: { main: "#F4F4F4", dark: "#e3e3e3", contrastText: "#475467" },
|
||||
text: text,
|
||||
background: background,
|
||||
border: border,
|
||||
info: {
|
||||
text: text.primary,
|
||||
main: text.tertiary,
|
||||
bg: background.main,
|
||||
light: background.main,
|
||||
border: border.dark,
|
||||
},
|
||||
success: {
|
||||
text: "#079455",
|
||||
main: "#17b26a",
|
||||
light: "#d4f4e1",
|
||||
bg: "#ecfdf3",
|
||||
},
|
||||
error: {
|
||||
text: "#f04438",
|
||||
main: "#d32f2f",
|
||||
light: "#fbd1d1",
|
||||
bg: "#f9eced",
|
||||
border: "#f04438",
|
||||
},
|
||||
warning: {
|
||||
text: "#DC6803",
|
||||
main: "#fdb022",
|
||||
light: "#ffecbc",
|
||||
bg: "#fef8ea",
|
||||
border: "#fec84b",
|
||||
},
|
||||
percentage: {
|
||||
uptimePoor: "#d32f2f",
|
||||
uptimeFair: "#ec8013",
|
||||
uptimeGood: "#ffb800",
|
||||
uptimeExcellent: "#079455",
|
||||
},
|
||||
unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" },
|
||||
divider: border.light,
|
||||
other: {
|
||||
icon: "#667085",
|
||||
line: "#d6d9dd",
|
||||
fill: "#e3e3e3",
|
||||
grid: "#a2a3a3",
|
||||
autofill: "#e8f0fe",
|
||||
},
|
||||
},
|
||||
spacing: 2,
|
||||
components: {
|
||||
MuiCssBaseline: {
|
||||
styleOverrides: {
|
||||
body: {
|
||||
backgroundImage:
|
||||
"radial-gradient(circle, #fcfcfd, #fdfcfd, #fdfdfd, #fefdfe, #fefefe, #fefefe, #fefefe, #fefefe, #fefdfe, #fdfdfd, #fdfcfd, #fcfcfd)",
|
||||
lineHeight: "inherit",
|
||||
paddingLeft: "calc(100vw - 100%)",
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiButton: {
|
||||
defaultProps: {
|
||||
disableRipple: true,
|
||||
},
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
variants: [
|
||||
{
|
||||
props: (props) => props.variant === "group",
|
||||
style: {
|
||||
color: theme.palette.secondary.contrastText,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
},
|
||||
},
|
||||
{
|
||||
props: (props) => props.variant === "group" && props.filled === "true",
|
||||
style: {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
},
|
||||
{
|
||||
props: (props) =>
|
||||
props.variant === "contained" && props.color === "secondary",
|
||||
style: {
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
},
|
||||
},
|
||||
],
|
||||
fontWeight: 400,
|
||||
borderRadius: 4,
|
||||
boxShadow: "none",
|
||||
textTransform: "none",
|
||||
"&:focus": {
|
||||
outline: "none",
|
||||
},
|
||||
"&:hover": {
|
||||
boxShadow: "none",
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiIconButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: 4,
|
||||
transition: "none",
|
||||
"&:hover": {
|
||||
backgroundColor: background.fill,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPaper: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
marginTop: 4,
|
||||
padding: 0,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: border.light,
|
||||
borderRadius: 4,
|
||||
boxShadow: shadow,
|
||||
backgroundColor: background.main,
|
||||
backgroundImage: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiList: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiListItemButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
transition: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiMenuItem: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 4,
|
||||
backgroundColor: "inherit",
|
||||
padding: "4px 6px",
|
||||
color: text.secondary,
|
||||
fontSize: 13,
|
||||
margin: 2,
|
||||
minWidth: 100,
|
||||
"&:hover, &.Mui-selected, &.Mui-selected:hover, &.Mui-selected.Mui-focusVisible":
|
||||
{
|
||||
backgroundColor: background.fill,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableCell: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderBottomColor: border.light,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableHead: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: background.accent,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPagination: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: background.main,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: border.light,
|
||||
"& button": {
|
||||
color: text.tertiary,
|
||||
borderRadius: 4,
|
||||
},
|
||||
"& li:first-of-type button, & li:last-of-type button": {
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: border.light,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPaginationItem: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
"&:not(.MuiPaginationItem-ellipsis):hover, &.Mui-selected": {
|
||||
backgroundColor: background.fill,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiSkeleton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundColor: "#f2f4f7",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
shape: {
|
||||
borderRadius: 2,
|
||||
borderThick: 2,
|
||||
boxShadow: shadow,
|
||||
},
|
||||
palette,
|
||||
...baseTheme(palette),
|
||||
});
|
||||
|
||||
export default lightTheme;
|
||||
Reference in new issue
Block a user