Merge pull request #1556 from bluewave-labs/fix/colors-general
Fix/colors general
This commit is contained in:
108 files changed
+1479
-1129
No files matched your search
@@ -40,6 +40,7 @@ function App() {
|
||||
return {
|
||||
body: {
|
||||
backgroundImage: `radial-gradient(circle, ${palette.gradient.color1}, ${palette.gradient.color2}, ${palette.gradient.color3}, ${palette.gradient.color4}, ${palette.gradient.color5})`,
|
||||
color: palette.primary.contrastText,
|
||||
},
|
||||
};
|
||||
}}
|
||||
|
||||
@@ -32,9 +32,12 @@ 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];
|
||||
Do we need other variants for alert?
|
||||
*/
|
||||
|
||||
const text = theme.palette.secondary.contrastText;
|
||||
const bg = theme.palette.secondary.main;
|
||||
const border = theme.palette.secondary.contrastText;
|
||||
const icon = icons[variant];
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import PropTypes from "prop-types";
|
||||
import { Box, Stack } from "@mui/material";
|
||||
import { Box, Stack, useTheme } from "@mui/material";
|
||||
// import useUtils from "../../Pages/Uptime/utils";
|
||||
|
||||
/**
|
||||
* A component that renders a pulsating dot with a specified color.
|
||||
@@ -15,6 +16,11 @@ import { Box, Stack } from "@mui/material";
|
||||
*/
|
||||
|
||||
const PulseDot = ({ color }) => {
|
||||
const theme = useTheme();
|
||||
// const { statusToTheme } = useUtils();
|
||||
/* TODO refactor so it gets status and gets theme color. Then uses theme.palette.[themeColor].lowContrast */
|
||||
/* const themeColor = statusToTheme[status]; */
|
||||
|
||||
return (
|
||||
<Stack
|
||||
width="26px"
|
||||
@@ -44,7 +50,7 @@ const PulseDot = ({ color }) => {
|
||||
width: "7px",
|
||||
height: "7px",
|
||||
borderRadius: "50%",
|
||||
backgroundColor: "white",
|
||||
backgroundColor: theme.palette.accent.contrastText,
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
|
||||
@@ -32,13 +32,16 @@ const Avatar = ({ src, small, sx }) => {
|
||||
return (
|
||||
<MuiAvatar
|
||||
alt={`${user?.firstName} ${user?.lastName}`}
|
||||
/* TODO What is the /static/images/avatar/2.jpg ?*/
|
||||
src={src ? src : user?.avatarImage ? image : "/static/images/avatar/2.jpg"}
|
||||
sx={{
|
||||
fontSize: small ? "16px" : "22px",
|
||||
color: "white",
|
||||
fontWeight: 400,
|
||||
backgroundColor: theme.palette.primary.main, // Same BG color as checkmate BG in sidebar
|
||||
color: theme.palette.accent.contrastText,
|
||||
backgroundColor: theme.palette.accent.main, // Same BG color as checkmate BG in sidebar
|
||||
display: "inline-flex",
|
||||
/*
|
||||
TODO not sure what this is for*/
|
||||
"&::before": {
|
||||
content: `""`,
|
||||
position: "absolute",
|
||||
@@ -54,7 +57,7 @@ const Avatar = ({ src, small, sx }) => {
|
||||
}}
|
||||
>
|
||||
{user.firstName?.charAt(0)}
|
||||
{user.lastName?.charAt(0) || ''}
|
||||
{user.lastName?.charAt(0) || ""}
|
||||
</MuiAvatar>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
/* TODO
|
||||
|
||||
Should we delete this?
|
||||
*/
|
||||
|
||||
import PropTypes from "prop-types";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import {
|
||||
TableContainer,
|
||||
Paper,
|
||||
Table,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableBody,
|
||||
TablePagination,
|
||||
Box,
|
||||
Typography,
|
||||
Stack,
|
||||
Button,
|
||||
} from "@mui/material";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { setRowsPerPage } from "../../Features/UI/uiSlice";
|
||||
import LeftArrowDouble from "../../assets/icons/left-arrow-double.svg?react";
|
||||
import RightArrowDouble from "../../assets/icons/right-arrow-double.svg?react";
|
||||
import LeftArrow from "../../assets/icons/left-arrow.svg?react";
|
||||
import RightArrow from "../../assets/icons/right-arrow.svg?react";
|
||||
import SelectorVertical from "../../assets/icons/selector-vertical.svg?react";
|
||||
import "./index.css";
|
||||
/**
|
||||
* Component for pagination actions (first, previous, next, last).
|
||||
*
|
||||
* @component
|
||||
* @param {Object} props
|
||||
* @param {number} props.count - Total number of items.
|
||||
* @param {number} props.page - Current page number.
|
||||
* @param {number} props.rowsPerPage - Number of rows per page.
|
||||
* @param {function} props.onPageChange - Callback function to handle page change.
|
||||
*
|
||||
* @returns {JSX.Element} Pagination actions component.
|
||||
*/
|
||||
const TablePaginationActions = (props) => {
|
||||
const { count, page, rowsPerPage, onPageChange } = props;
|
||||
|
||||
const handleFirstPageButtonClick = (event) => {
|
||||
onPageChange(event, 0);
|
||||
};
|
||||
const handleBackButtonClick = (event) => {
|
||||
onPageChange(event, page - 1);
|
||||
};
|
||||
const handleNextButtonClick = (event) => {
|
||||
onPageChange(event, page + 1);
|
||||
};
|
||||
const handleLastPageButtonClick = (event) => {
|
||||
onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ flexShrink: 0, ml: "24px" }}>
|
||||
<Button
|
||||
variant="group"
|
||||
onClick={handleFirstPageButtonClick}
|
||||
disabled={page === 0}
|
||||
aria-label="first page"
|
||||
>
|
||||
<LeftArrowDouble />
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
onClick={handleBackButtonClick}
|
||||
disabled={page === 0}
|
||||
aria-label="previous page"
|
||||
>
|
||||
<LeftArrow />
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
onClick={handleNextButtonClick}
|
||||
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
|
||||
aria-label="next page"
|
||||
>
|
||||
<RightArrow />
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
onClick={handleLastPageButtonClick}
|
||||
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
|
||||
aria-label="last page"
|
||||
>
|
||||
<RightArrowDouble />
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
TablePaginationActions.propTypes = {
|
||||
count: PropTypes.number.isRequired,
|
||||
page: PropTypes.number.isRequired,
|
||||
rowsPerPage: PropTypes.number.isRequired,
|
||||
onPageChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
/**
|
||||
* BasicTable Component
|
||||
* Renders a table with optional pagination.
|
||||
*
|
||||
* @component
|
||||
* @param {Object} props - Component props.
|
||||
* @param {Object} props.data - Data for the table including columns and rows.
|
||||
* @param {Array} props.data.cols - Array of objects for column headers.
|
||||
* @param {number} props.data.cols[].id - Unique identifier for the column.
|
||||
* @param {string} props.data.cols[].name - Name of the column to display as header.
|
||||
* @param {Array} props.data.rows - Array of row objects.
|
||||
* @param {number} props.data.rows[].id - Unique identifier for the row.
|
||||
* @param {Array} props.data.rows[].data - Array of cell data objects for the row.
|
||||
* @param {number} props.data.rows[].data[].id - Unique identifier for the cell.
|
||||
* @param {JSX.Element} props.data.rows[].data[].data - The content to display in the cell.
|
||||
* @param {function} props.data.rows.data.handleClick - Function to call when the row is clicked.
|
||||
* @param {boolean} [props.paginated=false] - Flag to enable pagination.
|
||||
* @param {boolean} [props.reversed=false] - Flag to enable reverse order.
|
||||
* @param {number} props.rowsPerPage- Number of rows per page (table).
|
||||
* @param {string} props.emptyMessage - Message to display when there is no data.
|
||||
* @example
|
||||
* const data = {
|
||||
* cols: [
|
||||
* { id: 1, name: "First Col" },
|
||||
* { id: 2, name: "Second Col" },
|
||||
* { id: 3, name: "Third Col" },
|
||||
* { id: 4, name: "Fourth Col" },
|
||||
* ],
|
||||
* rows: [
|
||||
* {
|
||||
* id: 1,
|
||||
* data: [
|
||||
* { id: 1, data: <div>Data for Row 1 Col 1</div> },
|
||||
* { id: 2, data: <div>Data for Row 1 Col 2</div> },
|
||||
* { id: 3, data: <div>Data for Row 1 Col 3</div> },
|
||||
* { id: 4, data: <div>Data for Row 1 Col 4</div> },
|
||||
* ],
|
||||
* },
|
||||
* {
|
||||
* id: 2,
|
||||
* data: [
|
||||
* { id: 5, data: <div>Data for Row 2 Col 1</div> },
|
||||
* { id: 6, data: <div>Data for Row 2 Col 2</div> },
|
||||
* { id: 7, data: <div>Data for Row 2 Col 3</div> },
|
||||
* { id: 8, data: <div>Data for Row 2 Col 4</div> },
|
||||
* ],
|
||||
* },
|
||||
* ],
|
||||
* };
|
||||
*
|
||||
* <BasicTable data={data} rows={rows} paginated={true} />
|
||||
*/
|
||||
|
||||
const BasicTable = ({ data, paginated, reversed, table, emptyMessage = "No data" }) => {
|
||||
const DEFAULT_ROWS_PER_PAGE = 5;
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
const uiState = useSelector((state) => state.ui);
|
||||
let rowsPerPage = uiState?.[table]?.rowsPerPage ?? DEFAULT_ROWS_PER_PAGE;
|
||||
const [page, setPage] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
setPage(0);
|
||||
}, [data]);
|
||||
|
||||
const handleChangePage = (event, newPage) => {
|
||||
setPage(newPage);
|
||||
};
|
||||
|
||||
const handleChangeRowsPerPage = (event) => {
|
||||
dispatch(
|
||||
setRowsPerPage({
|
||||
value: parseInt(event.target.value, 10),
|
||||
table: table,
|
||||
})
|
||||
);
|
||||
setPage(0);
|
||||
};
|
||||
|
||||
let displayData = [];
|
||||
|
||||
if (data && data.rows) {
|
||||
let rows = reversed ? [...data.rows].reverse() : data.rows;
|
||||
displayData = paginated
|
||||
? rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||
: rows;
|
||||
}
|
||||
|
||||
if (!data || !data.cols || !data.rows) {
|
||||
return <div>No data</div>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to calculate the range of displayed rows.
|
||||
* @returns {string}
|
||||
*/
|
||||
const getRange = () => {
|
||||
let start = page * rowsPerPage + 1;
|
||||
let end = Math.min(page * rowsPerPage + rowsPerPage, data.rows.length);
|
||||
return `${start} - ${end}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableContainer component={Paper}>
|
||||
<Table
|
||||
sx={{
|
||||
"&.MuiTable-root :is(.MuiTableHead-root, .MuiTableBody-root) :is(th, td)": {
|
||||
paddingLeft: theme.spacing(12),
|
||||
},
|
||||
"& th": {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
color: theme.palette.secondary.contrastText,
|
||||
/*
|
||||
TODO all general styling for th should live here
|
||||
*/
|
||||
},
|
||||
"& td": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
/*
|
||||
TODO all general styling for td should live here
|
||||
*/
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{data.cols.map((col) => (
|
||||
<TableCell key={col.id}>{col.name}</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{displayData.map((row) => {
|
||||
return (
|
||||
<TableRow
|
||||
sx={{
|
||||
cursor: row.handleClick ? "pointer" : "default",
|
||||
"&:hover": {
|
||||
filter: "brightness(.75)",
|
||||
opacity: 0.75,
|
||||
transition: "filter 0.3s ease, opacity 0.3s ease",
|
||||
},
|
||||
}}
|
||||
key={row.id}
|
||||
onClick={row.handleClick ? row.handleClick : null}
|
||||
>
|
||||
{row.data.map((cell) => {
|
||||
return <TableCell key={cell.id}>{cell.data}</TableCell>;
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
{displayData.length === 0 && (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
sx={{ textAlign: "center" }}
|
||||
colSpan={data.cols.length}
|
||||
>
|
||||
{emptyMessage}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
{paginated && (
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
px={theme.spacing(4)}
|
||||
sx={{
|
||||
"& p": {
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
px={theme.spacing(2)}
|
||||
fontSize={12}
|
||||
sx={{ opacity: 0.7 }}
|
||||
>
|
||||
Showing {getRange()} of {data.rows.length} monitor(s)
|
||||
</Typography>
|
||||
<TablePagination
|
||||
component="div"
|
||||
count={data.rows.length}
|
||||
page={page}
|
||||
onPageChange={handleChangePage}
|
||||
rowsPerPage={rowsPerPage}
|
||||
rowsPerPageOptions={[5, 10, 15, 25]}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
ActionsComponent={TablePaginationActions}
|
||||
labelRowsPerPage="Rows per page"
|
||||
labelDisplayedRows={({ page, count }) =>
|
||||
`Page ${page + 1} of ${Math.max(0, Math.ceil(count / rowsPerPage))}`
|
||||
}
|
||||
slotProps={{
|
||||
select: {
|
||||
MenuProps: {
|
||||
keepMounted: true,
|
||||
PaperProps: {
|
||||
className: "pagination-dropdown",
|
||||
sx: {
|
||||
mt: 0,
|
||||
mb: theme.spacing(2),
|
||||
},
|
||||
},
|
||||
transformOrigin: { vertical: "bottom", horizontal: "left" },
|
||||
anchorOrigin: { vertical: "top", horizontal: "left" },
|
||||
sx: { mt: theme.spacing(-2) },
|
||||
},
|
||||
inputProps: { id: "pagination-dropdown" },
|
||||
IconComponent: SelectorVertical,
|
||||
sx: {
|
||||
ml: theme.spacing(4),
|
||||
mr: theme.spacing(12),
|
||||
minWidth: theme.spacing(20),
|
||||
textAlign: "left",
|
||||
"&.Mui-focused > div": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
mt: theme.spacing(6),
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
"& svg path": {
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
strokeWidth: 1.3,
|
||||
},
|
||||
"& .MuiSelect-select": {
|
||||
border: 1,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
BasicTable.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
paginated: PropTypes.bool,
|
||||
reversed: PropTypes.bool,
|
||||
rowPerPage: PropTypes.number,
|
||||
table: PropTypes.string,
|
||||
emptyMessage: PropTypes.string,
|
||||
};
|
||||
|
||||
export default BasicTable;
|
||||
@@ -1,9 +1,9 @@
|
||||
.MuiBreadcrumbs-root {
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
}
|
||||
.MuiBreadcrumbs-root svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
min-height: 16px;
|
||||
}
|
||||
.MuiBreadcrumbs-root .MuiBreadcrumbs-li a {
|
||||
font-size: var(--env-var-font-size-medium);
|
||||
|
||||
@@ -28,13 +28,16 @@ const Breadcrumbs = ({ list }) => {
|
||||
px={theme.spacing(2)}
|
||||
py={theme.spacing(3.5)}
|
||||
width="fit-content"
|
||||
backgroundColor={theme.palette.background.fill}
|
||||
backgroundColor={theme.palette.secondary.main}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
lineHeight="18px"
|
||||
sx={{
|
||||
"& .MuiBreadcrumbs-li a": {
|
||||
transition: "background-color 0.2s ease-in-out, color 0.2s ease-in-out",
|
||||
},
|
||||
"& .MuiBreadcrumbs-li:not(:last-of-type):hover a": {
|
||||
backgroundColor: theme.palette.other.fill,
|
||||
opacity: 1,
|
||||
backgroundColor: theme.palette.secondary.contrastText,
|
||||
color: theme.palette.secondary.main,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -52,7 +55,7 @@ const Breadcrumbs = ({ list }) => {
|
||||
opacity: 0.8,
|
||||
textTransform: "capitalize",
|
||||
"&, &:hover": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.secondary.contrastText,
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -149,7 +149,7 @@ const CustomAreaChart = ({
|
||||
/>
|
||||
|
||||
<CartesianGrid
|
||||
stroke={theme.palette.border.light}
|
||||
stroke={theme.palette.primary.lowContrast}
|
||||
strokeWidth={1}
|
||||
strokeOpacity={1}
|
||||
fill="transparent"
|
||||
@@ -180,7 +180,7 @@ const CustomAreaChart = ({
|
||||
})}
|
||||
{customTooltip ? (
|
||||
<Tooltip
|
||||
cursor={{ stroke: theme.palette.border.light }}
|
||||
cursor={{ stroke: theme.palette.primary.lowContrast }}
|
||||
content={customTooltip}
|
||||
wrapperStyle={{ pointerEvents: "none" }}
|
||||
/>
|
||||
|
||||
@@ -39,12 +39,15 @@ const BarChart = ({ checks = [] }) => {
|
||||
>
|
||||
{checks.map((check, index) =>
|
||||
check === "placeholder" ? (
|
||||
/* TODO what is the purpose of this box? */
|
||||
// CAIO_REVIEW the purpose of this box is to make sure there are always at least 25 bars
|
||||
// even if there are less than 25 checks
|
||||
<Box
|
||||
key={`${check}-${index}`}
|
||||
position="relative"
|
||||
width={theme.spacing(4.5)}
|
||||
height="100%"
|
||||
backgroundColor={theme.palette.border.light}
|
||||
backgroundColor={theme.palette.primary.lowContrast}
|
||||
sx={{
|
||||
borderRadius: theme.spacing(1.5),
|
||||
}}
|
||||
@@ -67,8 +70,8 @@ const BarChart = ({ checks = [] }) => {
|
||||
height={theme.spacing(4)}
|
||||
backgroundColor={
|
||||
check.status
|
||||
? theme.palette.success.main
|
||||
: theme.palette.error.contrastText
|
||||
? theme.palette.success.lowContrast
|
||||
: theme.palette.error.lowContrast
|
||||
}
|
||||
sx={{ borderRadius: "50%" }}
|
||||
/>
|
||||
@@ -116,20 +119,22 @@ const BarChart = ({ checks = [] }) => {
|
||||
"& .MuiTooltip-tooltip": {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
boxShadow: theme.shape.boxShadow,
|
||||
px: theme.spacing(4),
|
||||
py: theme.spacing(2),
|
||||
py: theme.spacing(3),
|
||||
},
|
||||
"& .MuiTooltip-tooltip p": {
|
||||
/* TODO Font size should point to theme */
|
||||
fontSize: 12,
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.secondary.contrastText,
|
||||
fontWeight: 500,
|
||||
},
|
||||
"& .MuiTooltip-tooltip span": {
|
||||
/* TODO Font size should point to theme */
|
||||
fontSize: 11,
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.secondary.contrastText,
|
||||
fontWeight: 600,
|
||||
},
|
||||
},
|
||||
@@ -140,16 +145,14 @@ const BarChart = ({ checks = [] }) => {
|
||||
position="relative"
|
||||
width="9px"
|
||||
height="100%"
|
||||
backgroundColor={
|
||||
check.status
|
||||
? theme.palette.success.contrastText
|
||||
: theme.palette.error.dark
|
||||
}
|
||||
backgroundColor={theme.palette.primary.lowContrast} // CAIO_REVIEW
|
||||
sx={{
|
||||
borderRadius: theme.spacing(1.5),
|
||||
/*
|
||||
TODO this doesn't seem to be used
|
||||
"&:hover > .MuiBox-root": {
|
||||
filter: "brightness(0.8)",
|
||||
},
|
||||
}, */
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
@@ -158,7 +161,9 @@ const BarChart = ({ checks = [] }) => {
|
||||
width="100%"
|
||||
height={`${animate ? check.responseTime : 0}%`}
|
||||
backgroundColor={
|
||||
check.status ? theme.palette.success.main : theme.palette.error.main
|
||||
check.status
|
||||
? theme.palette.success.lowContrast
|
||||
: theme.palette.error.lowContrast
|
||||
}
|
||||
sx={{
|
||||
borderRadius: theme.spacing(1.5),
|
||||
|
||||
@@ -54,8 +54,8 @@ const CustomGauge = ({ progress = 0, radius = 70, strokeWidth = 15, threshold =
|
||||
|
||||
const fillColor =
|
||||
progressWithinRange > threshold
|
||||
? theme.palette.percentage.uptimePoor
|
||||
: theme.palette.primary.main;
|
||||
? theme.palette.error.lowContrast // CAIO_REVIEW
|
||||
: theme.palette.accent.main; // CAIO_REVIEW
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -70,7 +70,7 @@ const CustomGauge = ({ progress = 0, radius = 70, strokeWidth = 15, threshold =
|
||||
>
|
||||
<circle
|
||||
className="radial-chart-base"
|
||||
stroke={theme.palette.background.fill}
|
||||
stroke={theme.palette.primary.lowContrast} // CAIO_REVIEW
|
||||
strokeWidth={strokeWidth}
|
||||
fill="none"
|
||||
cx={totalSize / 2} // Center the circle
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
import { RadialBarChart, RadialBar, ResponsiveContainer } from "recharts";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
/* TODO delete component */
|
||||
|
||||
const MINIMUM_VALUE = 0;
|
||||
const MAXIMUM_VALUE = 100;
|
||||
const CHART_MAXIMUM_DATA = {
|
||||
value: MAXIMUM_VALUE,
|
||||
fill: "transparent",
|
||||
};
|
||||
const PROGRESS_THRESHOLD = 50;
|
||||
const DEFAULT_WIDTH = 60;
|
||||
|
||||
const RADIUS_SIZE = "90%";
|
||||
const START_ANGLE = 90;
|
||||
const CHART_RANGE = 360;
|
||||
const RADIAL_BAR_CHART_PROPS = {
|
||||
innerRadius: RADIUS_SIZE,
|
||||
outerRadius: RADIUS_SIZE,
|
||||
barSize: 6,
|
||||
startAngle: START_ANGLE,
|
||||
endAngle: START_ANGLE - CHART_RANGE,
|
||||
margin: { top: 0, right: 0, bottom: 0, left: 0 },
|
||||
};
|
||||
|
||||
const RADIAL_BAR_PROPS = {
|
||||
dataKey: "value",
|
||||
cornerRadius: 8,
|
||||
};
|
||||
|
||||
Gauge.propTypes = {
|
||||
progressValue: PropTypes.number.isRequired,
|
||||
width: PropTypes.number,
|
||||
};
|
||||
|
||||
/**
|
||||
* A circular gauge component that displays a progress value and text.
|
||||
* The gauge fills based on the progress value and changes color at a 50% threshold.
|
||||
*
|
||||
* @component
|
||||
* @param {Object} props - Component props
|
||||
* @param {number} props.progressValue - The value to display in the gauge (0-100)
|
||||
* @param {number} props.width - Width of the gauge container in pixels
|
||||
* @returns {JSX.Element} A circular gauge chart with progress value and text
|
||||
*
|
||||
* @example
|
||||
* <Gauge
|
||||
* progressValue={75}
|
||||
* width={200}
|
||||
* />
|
||||
*/
|
||||
|
||||
function Gauge({ progressValue, width = DEFAULT_WIDTH }) {
|
||||
const theme = useTheme();
|
||||
const myProgressValue = Math.max(MINIMUM_VALUE, Math.min(progressValue, MAXIMUM_VALUE));
|
||||
const chartColor =
|
||||
progressValue > PROGRESS_THRESHOLD
|
||||
? theme.palette.primary.main
|
||||
: theme.palette.percentage.uptimePoor;
|
||||
const chartData = [
|
||||
CHART_MAXIMUM_DATA,
|
||||
{
|
||||
value: myProgressValue,
|
||||
fill: chartColor,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<ResponsiveContainer
|
||||
aspect={1}
|
||||
width={width}
|
||||
style={{ marginInline: "auto" }}
|
||||
>
|
||||
<RadialBarChart
|
||||
{...RADIAL_BAR_CHART_PROPS}
|
||||
data={chartData}
|
||||
>
|
||||
<RadialBar
|
||||
{...RADIAL_BAR_PROPS}
|
||||
fill={
|
||||
progressValue > PROGRESS_THRESHOLD
|
||||
? theme.palette.primary.main
|
||||
: theme.palette.percentage.uptimePoor
|
||||
}
|
||||
background={{ fill: theme.palette.background.fill }}
|
||||
label={{
|
||||
position: "center",
|
||||
content: () => (
|
||||
<text
|
||||
x="50%"
|
||||
y="50%"
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
style={{
|
||||
...theme.typography.body2,
|
||||
fill: theme.typography.body2.color,
|
||||
}}
|
||||
>
|
||||
{`${myProgressValue}%`}
|
||||
</text>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</RadialBarChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export { Gauge };
|
||||
@@ -31,9 +31,9 @@ const CustomToolTip = ({ active, payload, label, dateRange }) => {
|
||||
<Box
|
||||
className="area-tooltip"
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
py: theme.spacing(2),
|
||||
px: theme.spacing(4),
|
||||
@@ -41,7 +41,7 @@ const CustomToolTip = ({ active, payload, label, dateRange }) => {
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
@@ -63,7 +63,7 @@ const CustomToolTip = ({ active, payload, label, dateRange }) => {
|
||||
ml={theme.spacing(3)}
|
||||
sx={{
|
||||
"& span": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 11,
|
||||
fontWeight: 500,
|
||||
},
|
||||
@@ -109,7 +109,7 @@ CustomToolTip.propTypes = {
|
||||
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
dateRange: PropTypes.string,
|
||||
};
|
||||
const CustomTick = ({ x, y, payload, index, dateRange }) => {
|
||||
const CustomTick = ({ x, y, payload, dateRange }) => {
|
||||
const format = tickDateFormatLookup(dateRange);
|
||||
const theme = useTheme();
|
||||
const uiTimezone = useSelector((state) => state.ui.timezone);
|
||||
@@ -118,7 +118,7 @@ const CustomTick = ({ x, y, payload, index, dateRange }) => {
|
||||
x={x}
|
||||
y={y + 10}
|
||||
textAnchor="middle"
|
||||
fill={theme.palette.text.tertiary}
|
||||
fill={theme.palette.primary.contrastTextTertiary}
|
||||
fontSize={11}
|
||||
fontWeight={400}
|
||||
>
|
||||
@@ -139,7 +139,6 @@ const MonitorDetailsAreaChart = ({ checks, dateRange }) => {
|
||||
const theme = useTheme();
|
||||
const memoizedChecks = useMemo(() => checks, [checks[0]]);
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
|
||||
return (
|
||||
<ResponsiveContainer
|
||||
width="100%"
|
||||
@@ -160,7 +159,7 @@ const MonitorDetailsAreaChart = ({ checks, dateRange }) => {
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
<CartesianGrid
|
||||
stroke={theme.palette.border.light}
|
||||
stroke={theme.palette.primary.lowContrast}
|
||||
strokeWidth={1}
|
||||
strokeOpacity={1}
|
||||
fill="transparent"
|
||||
@@ -176,18 +175,18 @@ const MonitorDetailsAreaChart = ({ checks, dateRange }) => {
|
||||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor={theme.palette.primary.main}
|
||||
stopColor={theme.palette.accent.main}
|
||||
stopOpacity={0.8}
|
||||
/>
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor={theme.palette.primary.light}
|
||||
stopColor={theme.palette.accent.light}
|
||||
stopOpacity={0}
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<XAxis
|
||||
stroke={theme.palette.border.dark}
|
||||
stroke={theme.palette.primary.lowContrast}
|
||||
dataKey="_id"
|
||||
tick={<CustomTick dateRange={dateRange} />}
|
||||
axisLine={false}
|
||||
@@ -195,17 +194,17 @@ const MonitorDetailsAreaChart = ({ checks, dateRange }) => {
|
||||
height={20}
|
||||
/>
|
||||
<Tooltip
|
||||
cursor={{ stroke: theme.palette.border.light }}
|
||||
cursor={{ stroke: theme.palette.primary.lowContrast }}
|
||||
content={<CustomToolTip dateRange={dateRange} />}
|
||||
wrapperStyle={{ pointerEvents: "none" }}
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="avgResponseTime"
|
||||
stroke={theme.palette.primary.main}
|
||||
stroke={theme.palette.accent.main} // CAIO_REVIEW
|
||||
fill="url(#colorUv)"
|
||||
strokeWidth={isHovered ? 2.5 : 1.5}
|
||||
activeDot={{ stroke: theme.palette.background.main, r: 5 }}
|
||||
activeDot={{ stroke: theme.palette.accent.main, r: 5 }} // CAIO_REVIEW
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
|
||||
@@ -24,7 +24,7 @@ export const TzTick = ({ x, y, payload, index, dateRange }) => {
|
||||
x={x}
|
||||
y={y + 10}
|
||||
textAnchor="middle"
|
||||
fill={theme.palette.text.tertiary}
|
||||
fill={theme.palette.primary.contrastTextTertiary}
|
||||
fontSize={11}
|
||||
fontWeight={400}
|
||||
>
|
||||
@@ -59,7 +59,7 @@ export const PercentTick = ({ x, y, payload, index }) => {
|
||||
x={x - 20}
|
||||
y={y}
|
||||
textAnchor="middle"
|
||||
fill={theme.palette.text.tertiary}
|
||||
fill={theme.palette.primary.contrastTextTertiary}
|
||||
fontSize={11}
|
||||
fontWeight={400}
|
||||
>
|
||||
@@ -123,9 +123,9 @@ export const InfrastructureTooltip = ({
|
||||
<Box
|
||||
className="area-tooltip"
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
py: theme.spacing(2),
|
||||
px: theme.spacing(4),
|
||||
@@ -133,7 +133,7 @@ export const InfrastructureTooltip = ({
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
@@ -155,7 +155,7 @@ export const InfrastructureTooltip = ({
|
||||
ml={theme.spacing(3)}
|
||||
sx={{
|
||||
"& span": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 11,
|
||||
fontWeight: 500,
|
||||
},
|
||||
@@ -212,9 +212,9 @@ export const TemperatureTooltip = ({
|
||||
<Box
|
||||
className="area-tooltip"
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
py: theme.spacing(2),
|
||||
px: theme.spacing(4),
|
||||
@@ -222,7 +222,7 @@ export const TemperatureTooltip = ({
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
@@ -241,7 +241,7 @@ export const TemperatureTooltip = ({
|
||||
ml={theme.spacing(3)}
|
||||
sx={{
|
||||
"& span": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 11,
|
||||
fontWeight: 500,
|
||||
},
|
||||
|
||||
@@ -49,7 +49,10 @@ const Check = ({ text, noHighlightText, variant = "info", outlined = false }) =>
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
color: variant === "info" ? theme.palette.text.tertiary : colors[variant],
|
||||
color:
|
||||
variant === "info"
|
||||
? theme.palette.primary.contrastTextTertiary
|
||||
: colors[variant],
|
||||
opacity: 0.8,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -5,10 +5,10 @@ const ConfigBox = styled(Stack)(({ theme }) => ({
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
gap: theme.spacing(20),
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.spacing(2),
|
||||
"& > *": {
|
||||
paddingTop: theme.spacing(12),
|
||||
@@ -18,7 +18,7 @@ const ConfigBox = styled(Stack)(({ theme }) => ({
|
||||
flex: 0.7,
|
||||
borderRight: 1,
|
||||
borderRightStyle: "solid",
|
||||
borderRightColor: theme.palette.border.light,
|
||||
borderRightColor: theme.palette.primary.lowContrast,
|
||||
paddingRight: theme.spacing(15),
|
||||
paddingLeft: theme.spacing(15),
|
||||
},
|
||||
@@ -28,10 +28,10 @@ const ConfigBox = styled(Stack)(({ theme }) => ({
|
||||
paddingLeft: theme.spacing(18),
|
||||
},
|
||||
"& h1, & h2": {
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
"& p": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ const GenericDialog = ({ title, description, open, onClose, theme, children }) =
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
width: 400,
|
||||
bgcolor: theme.palette.background.main,
|
||||
bgcolor: theme.palette.primary.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
boxShadow: 24,
|
||||
p: theme.spacing(15),
|
||||
@@ -37,7 +37,7 @@ const GenericDialog = ({ title, description, open, onClose, theme, children }) =
|
||||
id={titleId}
|
||||
component="h2"
|
||||
fontSize={16}
|
||||
color={theme.palette.text.primary}
|
||||
color={theme.palette.primary.contrastText}
|
||||
fontWeight={600}
|
||||
>
|
||||
{title}
|
||||
@@ -45,7 +45,7 @@ const GenericDialog = ({ title, description, open, onClose, theme, children }) =
|
||||
{description && (
|
||||
<Typography
|
||||
id={descriptionId}
|
||||
color={theme.palette.text.tertiary}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
{description}
|
||||
</Typography>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
width: max-content;
|
||||
}
|
||||
[class*="fallback__"] button.MuiButtonBase-root {
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
}
|
||||
[class*="fallback__"] .check span.MuiTypography-root,
|
||||
[class*="fallback__"] button.MuiButtonBase-root {
|
||||
|
||||
@@ -40,7 +40,7 @@ const Fallback = ({ title, checks, link = "/", isAdmin, vowelStart = false }) =>
|
||||
className="background-pattern-svg"
|
||||
sx={{
|
||||
"& svg g g:last-of-type path": {
|
||||
stroke: theme.palette.border.light,
|
||||
stroke: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -54,7 +54,7 @@ const Fallback = ({ title, checks, link = "/", isAdmin, vowelStart = false }) =>
|
||||
<Typography
|
||||
component="h1"
|
||||
marginY={theme.spacing(4)}
|
||||
color={theme.palette.text.tertiary}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
{vowelStart ? "An" : "A"} {title} is used to:
|
||||
</Typography>
|
||||
@@ -70,7 +70,7 @@ const Fallback = ({ title, checks, link = "/", isAdmin, vowelStart = false }) =>
|
||||
{isAdmin && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
sx={{ alignSelf: "center" }}
|
||||
onClick={() => navigate(link)}
|
||||
>
|
||||
|
||||
@@ -6,16 +6,18 @@ import PropTypes from "prop-types";
|
||||
*
|
||||
* @param {Object} props - The properties passed to the Heading component.
|
||||
* @param {('h1'|'h2'|'h3')} props.component - The heading level for the component.
|
||||
* @param {Object} props.style - Custom styles to apply to the heading.
|
||||
* @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 }) {
|
||||
function Heading({ component, style, children }) {
|
||||
return (
|
||||
<Typography
|
||||
component={component}
|
||||
variant="h2"
|
||||
fontWeight={600}
|
||||
style={style}
|
||||
>
|
||||
{children}
|
||||
</Typography>
|
||||
@@ -24,6 +26,7 @@ function Heading({ component, children }) {
|
||||
|
||||
Heading.propTypes = {
|
||||
component: PropTypes.oneOf(["h1", "h2", "h3"]).isRequired,
|
||||
style: PropTypes.object,
|
||||
children: PropTypes.string.isRequired,
|
||||
};
|
||||
export { Heading };
|
||||
@@ -30,32 +30,28 @@ const HttpStatusLabel = ({ status, customStyles }) => {
|
||||
const theme = useTheme();
|
||||
const colors = {
|
||||
400: {
|
||||
dotColor: theme.palette.warning.main,
|
||||
bgColor: theme.palette.warning.dark,
|
||||
borderColor: theme.palette.warning.light,
|
||||
color: theme.palette.warning.main,
|
||||
borderColor: theme.palette.warning.lowContrast,
|
||||
},
|
||||
500: {
|
||||
dotColor: theme.palette.error.main,
|
||||
bgColor: theme.palette.error.dark,
|
||||
borderColor: theme.palette.error.light,
|
||||
color: theme.palette.error.main,
|
||||
borderColor: theme.palette.error.lowContrast,
|
||||
},
|
||||
default: {
|
||||
dotColor: theme.palette.unresolved.main,
|
||||
bgColor: theme.palette.unresolved.bg,
|
||||
borderColor: theme.palette.unresolved.light,
|
||||
color: theme.palette.primary.contrastText,
|
||||
borderColor: theme.palette.primary.contrastText,
|
||||
},
|
||||
};
|
||||
|
||||
const statusCode = handleStatusCode(status);
|
||||
|
||||
const { borderColor, bgColor, dotColor } =
|
||||
const { borderColor, color } =
|
||||
colors[getRoundedStatusCode(statusCode)] || colors.default;
|
||||
return (
|
||||
<BaseLabel
|
||||
label={String(statusCode)}
|
||||
styles={{
|
||||
color: dotColor,
|
||||
backgroundColor: bgColor,
|
||||
color: color,
|
||||
borderColor: borderColor,
|
||||
...customStyles,
|
||||
}}
|
||||
|
||||
@@ -48,9 +48,9 @@ const IconBox = styled(Box)(
|
||||
position: "relative",
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: borderRadius,
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
"& svg": {
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
@@ -59,7 +59,7 @@ const IconBox = styled(Box)(
|
||||
width: svgWidth,
|
||||
height: svgHeight,
|
||||
"& path": {
|
||||
stroke: theme.palette.text.tertiary,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -90,14 +90,14 @@ const Checkbox = ({
|
||||
mr: theme.spacing(6),
|
||||
},
|
||||
"&:not(:has(.Mui-disabled)):hover": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
},
|
||||
"& span.MuiTypography-root": {
|
||||
fontSize: 13,
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
".MuiFormControlLabel-label.Mui-disabled": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
opacity: 0.25,
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -39,7 +39,7 @@ const ImageField = ({ id, src, loading, onChange }) => {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
borderColor: isDragging
|
||||
? theme.palette.primary.main
|
||||
: theme.palette.border.light,
|
||||
: theme.palette.primary.lowContrast,
|
||||
borderWidth: "2px",
|
||||
transition: "0.2s",
|
||||
"&:hover": {
|
||||
@@ -86,7 +86,7 @@ const ImageField = ({ id, src, loading, onChange }) => {
|
||||
sx={{
|
||||
pointerEvents: "none",
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
border: `solid ${theme.shape.borderThick}px ${theme.palette.border.light}`,
|
||||
border: `solid ${theme.shape.borderThick}px ${theme.palette.primary.lowContrast}`,
|
||||
boxShadow: theme.shape.boxShadow,
|
||||
}}
|
||||
>
|
||||
@@ -94,7 +94,7 @@ const ImageField = ({ id, src, loading, onChange }) => {
|
||||
</IconButton>
|
||||
<Typography
|
||||
component="h2"
|
||||
color={theme.palette.text.tertiary}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
<Typography
|
||||
component="span"
|
||||
@@ -108,7 +108,7 @@ const ImageField = ({ id, src, loading, onChange }) => {
|
||||
</Typography>
|
||||
<Typography
|
||||
component="p"
|
||||
color={theme.palette.text.tertiary}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
sx={{ opacity: 0.6 }}
|
||||
>
|
||||
(maximum size: 3MB)
|
||||
@@ -117,7 +117,7 @@ const ImageField = ({ id, src, loading, onChange }) => {
|
||||
</Box>
|
||||
<Typography
|
||||
component="p"
|
||||
color={theme.palette.text.tertiary}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
sx={{ opacity: 0.6 }}
|
||||
>
|
||||
Supported formats: JPG, PNG
|
||||
|
||||
@@ -43,7 +43,7 @@ const Radio = (props) => {
|
||||
height: 16,
|
||||
boxShadow: `inset 0 0 0 1px ${theme.palette.secondary.main}`,
|
||||
"&:not(.Mui-checked)": {
|
||||
boxShadow: `inset 0 0 0 1px ${theme.palette.text.primary}70`, // Use theme text color for the outline
|
||||
boxShadow: `inset 0 0 0 1px ${theme.palette.primary.contrastText}70`, // Use theme text color for the outline
|
||||
},
|
||||
mt: theme.spacing(0.5),
|
||||
}}
|
||||
@@ -56,7 +56,7 @@ const Radio = (props) => {
|
||||
<Typography
|
||||
component="h6"
|
||||
mt={theme.spacing(1)}
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
{props.desc}
|
||||
</Typography>
|
||||
@@ -69,7 +69,7 @@ const Radio = (props) => {
|
||||
m: theme.spacing(-2.5),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
},
|
||||
"& .MuiButtonBase-root": {
|
||||
p: 0,
|
||||
|
||||
@@ -27,7 +27,7 @@ const SearchAdornment = () => {
|
||||
width: 16,
|
||||
height: 16,
|
||||
"& path": {
|
||||
stroke: theme.palette.text.tertiary,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
strokeWidth: 1.2,
|
||||
},
|
||||
},
|
||||
@@ -79,7 +79,7 @@ const Search = ({
|
||||
<Typography
|
||||
component="h3"
|
||||
fontSize={"var(--env-var-font-size-medium)"}
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
fontWeight={500}
|
||||
>
|
||||
{label}
|
||||
@@ -94,12 +94,12 @@ const Search = ({
|
||||
}}
|
||||
sx={{
|
||||
"& fieldset": {
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
"& .MuiOutlinedInput-root:hover:not(:has(input:focus)):not(:has(textarea:focus)) fieldset":
|
||||
{
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
"& .MuiOutlinedInput-root": {
|
||||
paddingY: 0,
|
||||
@@ -142,7 +142,7 @@ const Search = ({
|
||||
option.noOptions
|
||||
? {
|
||||
pointerEvents: "none",
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
}
|
||||
: {}
|
||||
}
|
||||
@@ -155,16 +155,21 @@ const Search = ({
|
||||
popper: {
|
||||
keepMounted: true,
|
||||
sx: {
|
||||
"& ul": { p: 2 },
|
||||
"& ul": { p: 2, backgroundColor: theme.palette.primary.main },
|
||||
"& li.MuiAutocomplete-option": {
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
px: 4,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
|
||||
"& .MuiAutocomplete-listbox .MuiAutocomplete-option[aria-selected='true'], & .MuiAutocomplete-listbox .MuiAutocomplete-option[aria-selected='true'].Mui-focused, & .MuiAutocomplete-listbox .MuiAutocomplete-option[aria-selected='true']:hover":
|
||||
{
|
||||
backgroundColor: theme.palette.background.fill,
|
||||
backgroundColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
"& li.MuiAutocomplete-option:hover:not([aria-selected='true'])": {
|
||||
color: theme.palette.primary.main,
|
||||
backgroundColor: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
"& .MuiAutocomplete-noOptions": {
|
||||
px: theme.spacing(6),
|
||||
py: theme.spacing(5),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.select-wrapper .select-component > .MuiSelect-select {
|
||||
padding: 0 10px;
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
|
||||
@@ -54,11 +54,11 @@ const Select = ({
|
||||
const theme = useTheme();
|
||||
const itemStyles = {
|
||||
fontSize: "var(--env-var-font-size-medium)",
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
margin: theme.spacing(2),
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<Stack
|
||||
gap={theme.spacing(labelControlSpacing)}
|
||||
@@ -67,7 +67,7 @@ const Select = ({
|
||||
{label && (
|
||||
<Typography
|
||||
component="h3"
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
fontWeight={500}
|
||||
fontSize={13}
|
||||
>
|
||||
@@ -89,13 +89,13 @@ const Select = ({
|
||||
minWidth: "125px",
|
||||
"& fieldset": {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
"&:not(.Mui-focused):hover fieldset": {
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
"& svg path": {
|
||||
fill: theme.palette.other.icon,
|
||||
fill: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
...sx,
|
||||
}}
|
||||
|
||||
@@ -12,15 +12,15 @@ export const HttpAdornment = ({ https }) => {
|
||||
alignItems="center"
|
||||
height="100%"
|
||||
sx={{
|
||||
borderRight: `solid 1px ${theme.palette.border.dark}`,
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
borderRight: `solid 1px ${theme.palette.primary.lowContrast}`,
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
pl: theme.spacing(6),
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
component="h5"
|
||||
paddingRight={"var(--env-var-spacing-1-minus)"}
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
sx={{ lineHeight: 1, opacity: 0.8 }}
|
||||
>
|
||||
{https ? "https" : "http"}://
|
||||
@@ -41,7 +41,7 @@ export const PasswordEndAdornment = ({ fieldType, setFieldType }) => {
|
||||
aria-label="toggle password visibility"
|
||||
onClick={() => setFieldType(fieldType === "password" ? "text" : "password")}
|
||||
sx={{
|
||||
color: theme.palette.border.dark,
|
||||
color: theme.palette.primary.lowContrast,
|
||||
padding: theme.spacing(1),
|
||||
"&:focus-visible": {
|
||||
outline: `2px solid ${theme.palette.primary.main}`,
|
||||
|
||||
@@ -6,6 +6,19 @@ import PropTypes from "prop-types";
|
||||
const getSx = (theme, type, maxWidth) => {
|
||||
const sx = {
|
||||
maxWidth: maxWidth,
|
||||
"& .MuiOutlinedInput-root ": {
|
||||
"&:hover .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: theme.palette.primary.contrastText, // Adjust hover border color
|
||||
},
|
||||
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: theme.palette.accent.main, // Adjust focus border color
|
||||
},
|
||||
"&.Mui-disabled .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: theme.palette.primary.contrastText, // CAIO_REVIEW
|
||||
opacity: 0.5,
|
||||
},
|
||||
},
|
||||
|
||||
"& .MuiFormHelperText-root": {
|
||||
position: "absolute",
|
||||
bottom: `-${theme.spacing(24)}`,
|
||||
@@ -101,7 +114,7 @@ const TextInput = forwardRef(
|
||||
<Typography
|
||||
component="h3"
|
||||
fontSize={"var(--env-var-font-size-medium)"}
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
fontWeight={500}
|
||||
>
|
||||
{label}
|
||||
|
||||
@@ -24,15 +24,15 @@ const BaseLabel = ({ label, styles, children }) => {
|
||||
// Grab the default borderRadius from the theme to match button style
|
||||
const { borderRadius } = theme.shape;
|
||||
// Calculate padding for the label to mimic button. Appears to scale correctly, not 100% sure though.
|
||||
const padding = theme.spacing(1 * 0.75, 2);
|
||||
const padding = theme.spacing(3, 5);
|
||||
|
||||
return (
|
||||
<Box
|
||||
className="label"
|
||||
sx={{
|
||||
borderRadius: borderRadius,
|
||||
border: `1px solid ${theme.palette.text.tertiary}`,
|
||||
color: theme.palette.text.tertiary,
|
||||
border: `1px solid ${theme.palette.primary.lowContrast}`,
|
||||
color: theme.palette.primary.contrastText,
|
||||
padding: padding,
|
||||
...styles,
|
||||
}}
|
||||
@@ -87,7 +87,7 @@ const ColoredLabel = ({ label, color }) => {
|
||||
const theme = useTheme();
|
||||
// If an invalid color is passed, default to the labelGray color
|
||||
if (typeof color !== "string" || !/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color)) {
|
||||
color = theme.palette.border.light;
|
||||
color = theme.palette.primary.lowContrast;
|
||||
}
|
||||
|
||||
// Calculate lighter shades for border and bg
|
||||
@@ -122,53 +122,32 @@ ColoredLabel.propTypes = {
|
||||
* <StatusLabel status="up" text="Active" />
|
||||
*/
|
||||
|
||||
const statusToTheme = {
|
||||
up: "success",
|
||||
down: "error",
|
||||
paused: "warning",
|
||||
pending: "warning",
|
||||
"cannot resolve": "error",
|
||||
};
|
||||
|
||||
const StatusLabel = ({ status, text, customStyles }) => {
|
||||
const theme = useTheme();
|
||||
const colors = {
|
||||
up: {
|
||||
dotColor: theme.palette.success.main,
|
||||
bgColor: theme.palette.success.contrastText /* dark */,
|
||||
borderColor: theme.palette.success.main /* light */,
|
||||
},
|
||||
down: {
|
||||
dotColor: theme.palette.error.main,
|
||||
bgColor: theme.palette.error.dark,
|
||||
borderColor: theme.palette.error.light,
|
||||
},
|
||||
paused: {
|
||||
dotColor: theme.palette.warning.main,
|
||||
bgColor: theme.palette.warning.dark,
|
||||
borderColor: theme.palette.warning.light,
|
||||
},
|
||||
pending: {
|
||||
dotColor: theme.palette.text.secondary,
|
||||
bgColor: theme.palette.background.main,
|
||||
borderColor: theme.palette.border.dark,
|
||||
},
|
||||
"cannot resolve": {
|
||||
dotColor: theme.palette.unresolved.main,
|
||||
bgColor: theme.palette.unresolved.bg,
|
||||
borderColor: theme.palette.unresolved.light,
|
||||
},
|
||||
};
|
||||
|
||||
// Look up the color for the status
|
||||
const { borderColor, bgColor, dotColor } = colors[status];
|
||||
const themeColor = statusToTheme[status];
|
||||
|
||||
return (
|
||||
<BaseLabel
|
||||
label={text}
|
||||
styles={{
|
||||
color: dotColor,
|
||||
backgroundColor: bgColor,
|
||||
borderColor: borderColor,
|
||||
color: theme.palette[themeColor].main,
|
||||
borderColor: theme.palette[themeColor].lowContrast,
|
||||
...customStyles,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
width={7}
|
||||
height={7}
|
||||
bgcolor={dotColor}
|
||||
bgcolor={theme.palette[themeColor].lowContrast}
|
||||
borderRadius="50%"
|
||||
marginRight="5px"
|
||||
/>
|
||||
|
||||
@@ -16,24 +16,24 @@ const Link = ({ level, label, url }) => {
|
||||
const levelConfig = {
|
||||
primary: {},
|
||||
secondary: {
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
sx: {
|
||||
":hover": {
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
},
|
||||
},
|
||||
tertiary: {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
sx: {
|
||||
textDecoration: "underline",
|
||||
textDecorationStyle: "dashed",
|
||||
textDecorationColor: theme.palette.primary.main,
|
||||
textUnderlineOffset: "1px",
|
||||
":hover": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
textDecorationColor: theme.palette.primary.main,
|
||||
backgroundColor: theme.palette.background.fill,
|
||||
backgroundColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Box, IconButton, LinearProgress, Stack, Typography } from "@mui/material";
|
||||
@@ -30,11 +29,11 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick, error }) =>
|
||||
height: "fit-content",
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
backgroundColor: theme.palette.background.fill,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
backgroundColor: theme.palette.primary.lowContrast,
|
||||
"&:has(.input-error)": {
|
||||
borderColor: theme.palette.error.main,
|
||||
backgroundColor: theme.palette.error.dark,
|
||||
backgroundColor: theme.palette.error.lowContrast,
|
||||
py: theme.spacing(4),
|
||||
px: theme.spacing(8),
|
||||
"& > .MuiStack-root > svg": {
|
||||
@@ -60,9 +59,9 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick, error }) =>
|
||||
height: 30,
|
||||
minWidth: 30,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: 2,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
"& svg": {
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
@@ -71,7 +70,7 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick, error }) =>
|
||||
width: 23,
|
||||
height: 23,
|
||||
"& path": {
|
||||
fill: theme.palette.other.icon,
|
||||
fill: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
},
|
||||
}}
|
||||
@@ -90,7 +89,7 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick, error }) =>
|
||||
{error}
|
||||
</Typography>
|
||||
) : (
|
||||
<Box color={theme.palette.text.tertiary}>
|
||||
<Box color={theme.palette.primary.contrastTextTertiary}>
|
||||
<Typography
|
||||
component="h2"
|
||||
mb={theme.spacing(1.5)}
|
||||
@@ -148,7 +147,7 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick, error }) =>
|
||||
height: "10px",
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
maxWidth: "500px",
|
||||
backgroundColor: theme.palette.border.light,
|
||||
backgroundColor: theme.palette.primary.lowContrast,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -7,9 +7,9 @@ import PropTypes from "prop-types";
|
||||
const CustomStepIcon = (props) => {
|
||||
const { completed, active } = props;
|
||||
return completed ? (
|
||||
<CheckCircle color="primary" />
|
||||
<CheckCircle color="accent" />
|
||||
) : (
|
||||
<RadioButtonCheckedIcon color={active ? "primary" : "disabled"} />
|
||||
<RadioButtonCheckedIcon color={active ? "accent" : "disabled"} />
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* TODO */
|
||||
aside .MuiList-root svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
@@ -156,35 +156,105 @@ function Sidebar() {
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
/* TODO refactor this, there are a some ternaries and comments in the return */
|
||||
const iconColor = theme.palette.primary.contrastTextTertiary;
|
||||
|
||||
/* TODO refactor this, there are a some ternaries and comments in the return */
|
||||
return (
|
||||
<Stack
|
||||
component="aside"
|
||||
className={collapsed ? "collapsed" : "expanded"}
|
||||
/* TODO general padding should be here */
|
||||
py={theme.spacing(6)}
|
||||
gap={theme.spacing(6)}
|
||||
/* TODO set all style in this sx if possible (when general)
|
||||
This is the top lever for styles
|
||||
*/
|
||||
sx={{
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
"& .selected-path, & .MuiListItemButton-root:hover": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
"& :is(p, span, .MuiListSubheader-root)": {
|
||||
/*
|
||||
Text color for unselected menu items and menu headings
|
||||
Secondary contrast text against main background
|
||||
*/
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
"& .MuiList-root svg path": {
|
||||
stroke: theme.palette.text.tertiary,
|
||||
/* Menu Icons */
|
||||
stroke: iconColor,
|
||||
},
|
||||
"& p, & span, & .MuiListSubheader-root": {
|
||||
color: theme.palette.text.secondary,
|
||||
"& .selected-path": {
|
||||
/* Selected menu item */
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
"& .MuiListItemIcon-root svg path": {
|
||||
/* Selected menu item icon */
|
||||
stroke: theme.palette.secondary.contrastText,
|
||||
},
|
||||
"& .MuiListItemText-root :is(p, span)": {
|
||||
/* Selected menu item text */
|
||||
color: theme.palette.secondary.contrastText,
|
||||
},
|
||||
},
|
||||
"& .MuiListItemButton-root:not(.selected-path)": {
|
||||
transition: "background-color .3s",
|
||||
" &:hover": {
|
||||
/* Hovered menu item bg color */
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
"& :is(p, span)": {
|
||||
/* Hovered menu item text color */
|
||||
color: theme.palette.tertiary.contrastText,
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
sx={{
|
||||
position: "absolute",
|
||||
/* TODO 60 is a magic number. if logo chnges size this might break */
|
||||
top: 60,
|
||||
right: 0,
|
||||
transform: `translate(50%, 0)`,
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
p: theme.spacing(2.5),
|
||||
"& svg": {
|
||||
width: theme.spacing(8),
|
||||
height: theme.spacing(8),
|
||||
"& path": {
|
||||
/* TODO this should be set at the top level if possible */
|
||||
stroke: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
},
|
||||
"&:focus": { outline: "none" },
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.primary.lowContrast,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
setOpen((prev) =>
|
||||
Object.fromEntries(Object.keys(prev).map((key) => [key, false]))
|
||||
);
|
||||
dispatch(toggleSidebar());
|
||||
}}
|
||||
>
|
||||
{collapsed ? <ArrowRight /> : <ArrowLeft />}
|
||||
</IconButton>
|
||||
|
||||
{/* TODO Alignment done using padding. Use single source of truth to that*/}
|
||||
<Stack
|
||||
pt={theme.spacing(6)}
|
||||
pb={theme.spacing(12)}
|
||||
pl={theme.spacing(8)}
|
||||
>
|
||||
{/* TODO Abstract logo into component */}
|
||||
{/* TODO Turn logo into a link */}
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
@@ -199,10 +269,11 @@ function Sidebar() {
|
||||
minHeight={theme.spacing(16)}
|
||||
pl="1px"
|
||||
fontSize={18}
|
||||
color="white"
|
||||
color={theme.palette.accent.contrastText}
|
||||
sx={{
|
||||
position: "relative",
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
backgroundColor: theme.palette.accent.main,
|
||||
color: theme.palette.accent.contrastText,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
userSelect: "none",
|
||||
}}
|
||||
@@ -217,40 +288,7 @@ function Sidebar() {
|
||||
Checkmate
|
||||
</Typography>
|
||||
</Stack>
|
||||
<IconButton
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: 60,
|
||||
right: 0,
|
||||
transform: `translate(50%, 0)`,
|
||||
backgroundColor: theme.palette.background.fill,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
p: theme.spacing(2.5),
|
||||
"& svg": {
|
||||
width: theme.spacing(8),
|
||||
height: theme.spacing(8),
|
||||
"& path": {
|
||||
stroke: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
"&:focus": { outline: "none" },
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.border.light,
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
setOpen((prev) =>
|
||||
Object.fromEntries(Object.keys(prev).map((key) => [key, false]))
|
||||
);
|
||||
dispatch(toggleSidebar());
|
||||
}}
|
||||
>
|
||||
{collapsed ? <ArrowRight /> : <ArrowLeft />}
|
||||
</IconButton>
|
||||
</Stack>
|
||||
{/* menu */}
|
||||
<List
|
||||
component="nav"
|
||||
aria-labelledby="nested-menu-subheader"
|
||||
@@ -260,7 +298,8 @@ function Sidebar() {
|
||||
component="div"
|
||||
id="nested-menu-subheader"
|
||||
sx={{
|
||||
pt: theme.spacing(4),
|
||||
py: theme.spacing(4),
|
||||
/* TODO px should be centralized in container */
|
||||
px: collapsed ? theme.spacing(2) : theme.spacing(4),
|
||||
backgroundColor: "transparent",
|
||||
}}
|
||||
@@ -271,11 +310,12 @@ function Sidebar() {
|
||||
sx={{
|
||||
px: theme.spacing(6),
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
/* overflow: "hidden", */
|
||||
}}
|
||||
>
|
||||
{menu.map((item) =>
|
||||
item.path ? (
|
||||
/* If item has a path */
|
||||
<Tooltip
|
||||
key={item.path}
|
||||
placement="right"
|
||||
@@ -298,10 +338,12 @@ function Sidebar() {
|
||||
className={location.pathname.includes(item.path) ? "selected-path" : ""}
|
||||
onClick={() => navigate(`/${item.path}`)}
|
||||
sx={{
|
||||
height: "37px",
|
||||
/*
|
||||
TODO we do not need this height
|
||||
minHeight: "37px", */
|
||||
p: theme.spacing(5),
|
||||
gap: theme.spacing(4),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
px: theme.spacing(4),
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: 0 }}>{item.icon}</ListItemIcon>
|
||||
@@ -309,7 +351,7 @@ function Sidebar() {
|
||||
</ListItemButton>
|
||||
</Tooltip>
|
||||
) : collapsed ? (
|
||||
/* TODO Do we ever get here? */
|
||||
/* TODO Do we ever get here? If item does not have a path and collapsed state is true */
|
||||
<React.Fragment key={item.name}>
|
||||
<Tooltip
|
||||
placement="right"
|
||||
@@ -365,8 +407,9 @@ function Sidebar() {
|
||||
MenuListProps={{ sx: { px: 1, py: 2 } }}
|
||||
sx={{
|
||||
ml: theme.spacing(8),
|
||||
/* TODO what is this selection? */
|
||||
"& .selected-path": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -397,9 +440,10 @@ function Sidebar() {
|
||||
sx={{
|
||||
gap: theme.spacing(4),
|
||||
opacity: 0.9,
|
||||
/* TODO this has no effect? */
|
||||
"& svg": {
|
||||
"& path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
strokeWidth: 1.1,
|
||||
},
|
||||
},
|
||||
@@ -413,6 +457,7 @@ function Sidebar() {
|
||||
</Menu>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
/* TODO Do we ever get here? If item does not have a path and collapsed state is false */
|
||||
<React.Fragment key={item.name}>
|
||||
<ListItemButton
|
||||
onClick={() =>
|
||||
@@ -474,7 +519,7 @@ function Sidebar() {
|
||||
left: "-7px",
|
||||
height: "100%",
|
||||
borderLeft: 1,
|
||||
borderLeftColor: theme.palette.other.line,
|
||||
borderLeftColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
"&:last-child::before": {
|
||||
height: "50%",
|
||||
@@ -487,10 +532,11 @@ function Sidebar() {
|
||||
height: "3px",
|
||||
width: "3px",
|
||||
borderRadius: "50%",
|
||||
backgroundColor: theme.palette.other.line,
|
||||
backgroundColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
"&.selected-path::after": {
|
||||
backgroundColor: theme.palette.text.tertiary,
|
||||
/* TODO what is this selector doing? */
|
||||
backgroundColor: theme.palette.primary.contrastTextTertiary,
|
||||
transform: "scale(1.2)",
|
||||
},
|
||||
}}
|
||||
@@ -562,7 +608,7 @@ function Sidebar() {
|
||||
marginLeft={"auto"}
|
||||
columnGap={theme.spacing(2)}
|
||||
>
|
||||
<ThemeSwitch />
|
||||
<ThemeSwitch color={iconColor} />
|
||||
<Tooltip
|
||||
title="Controls"
|
||||
disableInteractive
|
||||
@@ -573,14 +619,15 @@ function Sidebar() {
|
||||
mr: "-8px",
|
||||
"&:focus": { outline: "none" },
|
||||
alignSelf: "center",
|
||||
padding: '10px',
|
||||
padding: "10px",
|
||||
|
||||
"& svg": {
|
||||
width: "22px",
|
||||
height: "22px",
|
||||
},
|
||||
"& svg path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
/* Vertical three dots */
|
||||
stroke: iconColor,
|
||||
},
|
||||
}}
|
||||
onClick={(event) => openPopup(event, "logout")}
|
||||
@@ -638,6 +685,7 @@ function Sidebar() {
|
||||
</Box>
|
||||
</MenuItem>
|
||||
)}
|
||||
{/* TODO Do we need two dividers? */}
|
||||
{collapsed && <Divider />}
|
||||
<Divider />
|
||||
<MenuItem
|
||||
@@ -647,7 +695,7 @@ function Sidebar() {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
pl: theme.spacing(4),
|
||||
"& svg path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
stroke: iconColor,
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import PropTypes from "prop-types";
|
||||
import useUtils from "../../Pages/Uptime/utils";
|
||||
|
||||
/**
|
||||
* StatBox Component
|
||||
@@ -12,6 +13,8 @@ import PropTypes from "prop-types";
|
||||
* @param {Object} props - The component props
|
||||
* @param {string} props.heading - The primary heading/title of the statistic
|
||||
* @param {string|React.ReactNode} props.subHeading - The value or description of the statistic
|
||||
* @param {boolean} [props.gradient=false] - Determines if the box should have a gradient background
|
||||
* @param {string} [props.status] - The status of the statistic
|
||||
* @param {Object} [props.sx] - Additional custom styling to be applied to the box
|
||||
*
|
||||
* @example
|
||||
@@ -26,35 +29,68 @@ import PropTypes from "prop-types";
|
||||
* @returns {React.ReactElement} A styled box containing the statistic
|
||||
*/
|
||||
|
||||
const StatBox = ({ heading, subHeading, sx }) => {
|
||||
const StatBox = ({ heading, subHeading, gradient = false, status = "", sx }) => {
|
||||
const theme = useTheme();
|
||||
const { statusToTheme } = useUtils();
|
||||
const themeColor = statusToTheme[status];
|
||||
|
||||
const statusBoxStyles = gradient
|
||||
? {
|
||||
background: `linear-gradient(to bottom right, ${theme.palette[themeColor].main} 30%, ${theme.palette[themeColor].lowContrast} 70%)`,
|
||||
borderColor: theme.palette[themeColor].lowContrast,
|
||||
}
|
||||
: {
|
||||
background: `linear-gradient(340deg, ${theme.palette.tertiary.main} 20%, ${theme.palette.primary.main} 45%)`,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
};
|
||||
|
||||
const headingStyles = gradient
|
||||
? {
|
||||
color: theme.palette[themeColor].contrastText,
|
||||
}
|
||||
: {
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
};
|
||||
|
||||
const spanFixedStyles = { marginLeft: theme.spacing(2), fontSize: 15 };
|
||||
const detailTextStyles = gradient
|
||||
? {
|
||||
color: theme.palette[themeColor].contrastText,
|
||||
"& span": {
|
||||
color: theme.palette[themeColor].contrastText,
|
||||
...spanFixedStyles,
|
||||
},
|
||||
}
|
||||
: {
|
||||
color: theme.palette.primary.contrastText,
|
||||
"& span": {
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
...spanFixedStyles,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
padding: `${theme.spacing(4)} ${theme.spacing(8)}`,
|
||||
/* TODO why are we using width and min width here? */
|
||||
minWidth: 200,
|
||||
width: 225,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
borderRadius: 4,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
background: `linear-gradient(340deg, ${theme.palette.background.accent} 20%, ${theme.palette.background.main} 45%)`,
|
||||
...statusBoxStyles,
|
||||
"& h2": {
|
||||
/* TODO font size should come from theme */
|
||||
fontSize: 13,
|
||||
fontWeight: 500,
|
||||
color: theme.palette.text.secondary,
|
||||
textTransform: "uppercase",
|
||||
...headingStyles,
|
||||
},
|
||||
"& p": {
|
||||
fontSize: 18,
|
||||
color: theme.palette.text.primary,
|
||||
marginTop: theme.spacing(2),
|
||||
"& span": {
|
||||
color: theme.palette.text.tertiary,
|
||||
marginLeft: theme.spacing(2),
|
||||
fontSize: 15,
|
||||
},
|
||||
...detailTextStyles,
|
||||
},
|
||||
...sx,
|
||||
}}
|
||||
@@ -68,6 +104,8 @@ const StatBox = ({ heading, subHeading, sx }) => {
|
||||
StatBox.propTypes = {
|
||||
heading: PropTypes.string.isRequired,
|
||||
subHeading: PropTypes.node.isRequired,
|
||||
gradient: PropTypes.bool,
|
||||
status: PropTypes.string,
|
||||
sx: PropTypes.object,
|
||||
};
|
||||
|
||||
|
||||
@@ -28,8 +28,7 @@ const PasswordPanel = () => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
||||
const SPACING_GAP = theme.spacing(12);
|
||||
const SPACING_GAP = theme.spacing(12);
|
||||
|
||||
//redux state
|
||||
const { authToken, isLoading } = useSelector((state) => state.auth);
|
||||
@@ -116,7 +115,7 @@ const PasswordPanel = () => {
|
||||
value="password"
|
||||
sx={{
|
||||
"& h1, & input": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -126,8 +125,7 @@ const PasswordPanel = () => {
|
||||
noValidate
|
||||
spellCheck="false"
|
||||
gap={theme.spacing(26)}
|
||||
maxWidth={"80ch"} // Keep maxWidth
|
||||
|
||||
maxWidth={"80ch"} // Keep maxWidth
|
||||
>
|
||||
<TextInput
|
||||
type="text"
|
||||
@@ -142,7 +140,7 @@ const PasswordPanel = () => {
|
||||
direction="row"
|
||||
justifyContent={"flex-start"}
|
||||
alignItems={"center"}
|
||||
gap={SPACING_GAP}
|
||||
gap={SPACING_GAP}
|
||||
flexWrap={"wrap"}
|
||||
>
|
||||
<Typography
|
||||
@@ -167,7 +165,7 @@ const PasswordPanel = () => {
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems={"flex-start"}
|
||||
gap={SPACING_GAP}
|
||||
gap={SPACING_GAP}
|
||||
flexWrap={"wrap"}
|
||||
>
|
||||
<Typography
|
||||
@@ -193,7 +191,7 @@ const PasswordPanel = () => {
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems={"flex-start"}
|
||||
gap={SPACING_GAP}
|
||||
gap={SPACING_GAP}
|
||||
flexWrap={"wrap"}
|
||||
>
|
||||
<Typography
|
||||
@@ -230,7 +228,7 @@ const PasswordPanel = () => {
|
||||
>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
type="submit"
|
||||
loading={isLoading}
|
||||
loadingIndicator="Saving..."
|
||||
@@ -255,4 +253,4 @@ PasswordPanel.propTypes = {
|
||||
// No props are being passed to this component, hence no specific PropTypes are defined.
|
||||
};
|
||||
|
||||
export default PasswordPanel;
|
||||
export default PasswordPanel;
|
||||
@@ -29,7 +29,7 @@ import Dialog from "../../Dialog";
|
||||
const ProfilePanel = () => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
||||
const SPACING_GAP = theme.spacing(12);
|
||||
|
||||
//redux state
|
||||
@@ -216,7 +216,7 @@ const ProfilePanel = () => {
|
||||
value="profile"
|
||||
sx={{
|
||||
"& h1, & p, & input": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -225,9 +225,13 @@ const ProfilePanel = () => {
|
||||
className="edit-profile-form"
|
||||
noValidate
|
||||
spellCheck="false"
|
||||
gap={SPACING_GAP}
|
||||
gap={SPACING_GAP}
|
||||
>
|
||||
<Stack direction="row" gap={SPACING_GAP}>
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={SPACING_GAP}
|
||||
>
|
||||
{/* This 0.9 is a bit magic numbering, refactor */}
|
||||
<Box flex={0.9}>
|
||||
<Typography component="h1">First name</Typography>
|
||||
</Box>
|
||||
@@ -242,7 +246,10 @@ const ProfilePanel = () => {
|
||||
flex={1}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack direction="row" gap={SPACING_GAP}>
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={SPACING_GAP}
|
||||
>
|
||||
<Box flex={0.9}>
|
||||
<Typography component="h1">Last name</Typography>
|
||||
</Box>
|
||||
@@ -257,7 +264,10 @@ const ProfilePanel = () => {
|
||||
flex={1}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack direction="row" gap={SPACING_GAP}>
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={SPACING_GAP}
|
||||
>
|
||||
<Stack flex={0.9}>
|
||||
<Typography component="h1">Email</Typography>
|
||||
<Typography
|
||||
@@ -277,7 +287,10 @@ const ProfilePanel = () => {
|
||||
flex={1}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack direction="row" gap={SPACING_GAP}>
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={SPACING_GAP}
|
||||
>
|
||||
<Stack flex={0.9}>
|
||||
<Typography component="h1">Your photo</Typography>
|
||||
<Typography
|
||||
@@ -291,6 +304,7 @@ const ProfilePanel = () => {
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
flex={1}
|
||||
gap={"8px"}
|
||||
>
|
||||
<Avatar
|
||||
src={
|
||||
@@ -300,18 +314,18 @@ const ProfilePanel = () => {
|
||||
? localData.file
|
||||
: ""
|
||||
}
|
||||
sx={{ mr: "8px" }}
|
||||
sx={{ marginRight: "8px" }}
|
||||
/>
|
||||
<Button
|
||||
variant="text"
|
||||
color="info"
|
||||
variant="contained" // CAIO_REIVEW
|
||||
color="error"
|
||||
onClick={handleDeletePicture}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
<Button
|
||||
variant="text"
|
||||
color="primary"
|
||||
variant="contained" // CAIO_REVIEW
|
||||
color="accent"
|
||||
onClick={openPictureModal}
|
||||
>
|
||||
Update
|
||||
@@ -332,7 +346,7 @@ const ProfilePanel = () => {
|
||||
<Box width="fit-content">
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={handleSaveProfile}
|
||||
loading={isLoading}
|
||||
loadingIndicator="Saving..."
|
||||
@@ -348,7 +362,7 @@ const ProfilePanel = () => {
|
||||
aria-hidden="true"
|
||||
sx={{
|
||||
marginY: theme.spacing(20),
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
}}
|
||||
/>
|
||||
{!user.role.includes("demo") && (
|
||||
@@ -438,7 +452,7 @@ const ProfilePanel = () => {
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={handleUpdatePicture}
|
||||
disabled={
|
||||
(Object.keys(errors).length !== 0 && errors?.picture) ||
|
||||
|
||||
@@ -43,7 +43,7 @@ const TeamPanel = () => {
|
||||
render: (row) => {
|
||||
return (
|
||||
<Stack>
|
||||
<Typography color={theme.palette.text.secondary}>
|
||||
<Typography color={theme.palette.primary.contrastTextSecondary}>
|
||||
{row.firstName + " " + row.lastName}
|
||||
</Typography>
|
||||
<Typography>
|
||||
@@ -180,11 +180,11 @@ const TeamPanel = () => {
|
||||
value="team"
|
||||
sx={{
|
||||
"& h1": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
"& .MuiTable-root .MuiTableBody-root .MuiTableCell-root, & .MuiTable-root p + p":
|
||||
{
|
||||
color: theme.palette.text.accent,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -232,7 +232,7 @@ const TeamPanel = () => {
|
||||
<LoadingButton
|
||||
loading={isSendingInvite}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={() => setIsOpen(true)}
|
||||
>
|
||||
Invite a team member
|
||||
@@ -289,15 +289,15 @@ const TeamPanel = () => {
|
||||
>
|
||||
<LoadingButton
|
||||
loading={isSendingInvite}
|
||||
variant="text"
|
||||
color="info"
|
||||
variant="contained" // CAIO_REVIEW
|
||||
color="error"
|
||||
onClick={closeInviteModal}
|
||||
>
|
||||
Cancel
|
||||
</LoadingButton>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={handleInviteMember}
|
||||
loading={isSendingInvite}
|
||||
disabled={isDisabled}
|
||||
|
||||
@@ -92,7 +92,7 @@ function Pagination({
|
||||
minWidth: theme.spacing(20),
|
||||
textAlign: "left",
|
||||
"&.Mui-focused > div": {
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
"& .MuiSelect-icon": {
|
||||
// Add this style override
|
||||
@@ -105,14 +105,14 @@ function Pagination({
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
"& svg path": {
|
||||
stroke: theme.palette.text.tertiary,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
strokeWidth: 1.3,
|
||||
},
|
||||
"& .MuiSelect-select": {
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -40,16 +40,30 @@ const DataTable = ({ headers, data, config = { emptyView: "No data" } }) => {
|
||||
|
||||
return (
|
||||
<TableContainer component={Paper}>
|
||||
<Table stickyHeader>
|
||||
<TableHead sx={{ backgroundColor: theme.palette.background.accent }}>
|
||||
<Table
|
||||
stickyHeader
|
||||
sx={{
|
||||
"&.MuiTable-root :is(.MuiTableHead-root, .MuiTableBody-root) :is(th, td)": {
|
||||
paddingLeft: theme.spacing(8),
|
||||
},
|
||||
"& :is(th)": {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
color: theme.palette.secondary.contrastText,
|
||||
fontWeight: 600,
|
||||
fontSize: "12px",
|
||||
},
|
||||
"& :is(td)": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{headers.map((header, index) => (
|
||||
<TableCell
|
||||
key={header.id}
|
||||
align={index === 0 ? "left" : "center"}
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
}}
|
||||
>
|
||||
{header.content}
|
||||
</TableCell>
|
||||
|
||||
@@ -35,12 +35,12 @@ const SunAndMoonIcon = () => {
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="6"
|
||||
fill={theme.palette.text.secondary}
|
||||
fill={theme.palette.primary.contrastTextSecondary}
|
||||
mask="url(#moon-mask)"
|
||||
/>
|
||||
<g
|
||||
className="sun-beams"
|
||||
stroke={theme.palette.text.secondary}
|
||||
stroke={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
<line
|
||||
x1="12"
|
||||
|
||||
@@ -15,7 +15,7 @@ import { useDispatch, useSelector } from "react-redux";
|
||||
import { setMode } from "../../Features/UI/uiSlice";
|
||||
import "./index.css";
|
||||
|
||||
const ThemeSwitch = ({ width = 48, height = 48 }) => {
|
||||
const ThemeSwitch = ({ width = 48, height = 48, color }) => {
|
||||
const mode = useSelector((state) => state.ui.mode);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
@@ -37,6 +37,10 @@ const ThemeSwitch = ({ width = 48, height = 48 }) => {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
"& svg >:is(circle, g)": {
|
||||
fill: color,
|
||||
stroke: color,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SunAndMoonIcon />
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
margin-top: 50px;
|
||||
}
|
||||
.account button:not(.MuiIconButton-root) {
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
}
|
||||
.account .field {
|
||||
flex: 1;
|
||||
|
||||
@@ -57,22 +57,27 @@ const Account = ({ open = "profile" }) => {
|
||||
className="account"
|
||||
px={theme.spacing(20)}
|
||||
py={theme.spacing(12)}
|
||||
backgroundColor={theme.palette.primary.main}
|
||||
border={1}
|
||||
borderColor={theme.palette.border.light}
|
||||
borderColor={theme.palette.primary.lowContrast}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
backgroundColor={theme.palette.background.main}
|
||||
>
|
||||
<TabContext value={tab}>
|
||||
<Box
|
||||
sx={{
|
||||
borderBottom: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
"& .MuiTabs-root": { height: "fit-content", minHeight: "0" },
|
||||
}}
|
||||
>
|
||||
<TabList
|
||||
onChange={handleTabChange}
|
||||
aria-label="account tabs"
|
||||
sx={{
|
||||
"& .MuiTabs-indicator": {
|
||||
backgroundColor: theme.palette.tertiary.contrastText,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{tabList.map((label, index) => (
|
||||
<Tab
|
||||
@@ -84,21 +89,29 @@ const Account = ({ open = "profile" }) => {
|
||||
tabIndex={index}
|
||||
sx={{
|
||||
fontSize: 13,
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.tertiary.contrastText,
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
textTransform: "none",
|
||||
minWidth: "fit-content",
|
||||
minHeight: 0,
|
||||
paddingLeft: 0,
|
||||
paddingY: theme.spacing(4),
|
||||
paddingY: theme.spacing(6),
|
||||
fontWeight: 400,
|
||||
marginRight: theme.spacing(8),
|
||||
borderBottom: "2px solid transparent",
|
||||
"&:focus": {
|
||||
borderBottom: `2px solid ${theme.palette.border.light}`,
|
||||
borderRight: `1px solid ${theme.palette.primary.lowContrast}`,
|
||||
"&:first-child": { borderTopLeftRadius: "8px" },
|
||||
"&:last-child": { borderTopRightRadius: "8px", borderRight: 0 },
|
||||
"&:focus-visible": {
|
||||
color: theme.palette.primary.contrastText,
|
||||
borderColor: theme.palette.tertiary.contrastText,
|
||||
borderRightColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
"&.Mui-selected": {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
color: theme.palette.secondary.contrastText,
|
||||
borderColor: theme.palette.secondary.contrastText,
|
||||
borderRightColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
|
||||
"&:hover": {
|
||||
borderBottom: `2px solid ${theme.palette.border.light}`,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -94,7 +94,8 @@ const CheckEmail = () => {
|
||||
fontWeight: 600,
|
||||
fontSize: 22,
|
||||
},
|
||||
"& p": { color: theme.palette.text.accent, fontSize: 13.5 },
|
||||
/* TODO font size from theme */
|
||||
"& p": { color: theme.palette.primary.contrastTextSecondary, fontSize: 13.5 },
|
||||
"& span": { fontSize: "inherit" },
|
||||
}}
|
||||
>
|
||||
@@ -102,7 +103,7 @@ const CheckEmail = () => {
|
||||
className="background-pattern-svg"
|
||||
sx={{
|
||||
"& svg g g:last-of-type path": {
|
||||
stroke: theme.palette.border.light,
|
||||
stroke: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -129,8 +130,8 @@ const CheckEmail = () => {
|
||||
"& > .MuiStack-root": {
|
||||
border: 1,
|
||||
borderRadius: theme.spacing(5),
|
||||
borderColor: theme.palette.border.light,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: {
|
||||
xs: theme.spacing(12),
|
||||
sm: theme.spacing(20),
|
||||
@@ -173,7 +174,7 @@ const CheckEmail = () => {
|
||||
</Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={openMail}
|
||||
sx={{
|
||||
width: "100%",
|
||||
|
||||
@@ -95,8 +95,9 @@ const ForgotPassword = () => {
|
||||
fontSize: 21,
|
||||
},
|
||||
"& p": {
|
||||
/* TODO font size from theme */
|
||||
fontSize: 14,
|
||||
color: theme.palette.text.accent,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -104,7 +105,7 @@ const ForgotPassword = () => {
|
||||
className="background-pattern-svg"
|
||||
sx={{
|
||||
"& svg g g:last-of-type path": {
|
||||
stroke: theme.palette.border.light,
|
||||
stroke: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -131,8 +132,8 @@ const ForgotPassword = () => {
|
||||
"& > .MuiStack-root": {
|
||||
border: 1,
|
||||
borderRadius: theme.spacing(5),
|
||||
borderColor: theme.palette.border.light,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: {
|
||||
xs: theme.spacing(12),
|
||||
sm: theme.spacing(20),
|
||||
@@ -186,7 +187,7 @@ const ForgotPassword = () => {
|
||||
/>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
loading={isLoading}
|
||||
disabled={errors.email !== undefined}
|
||||
onClick={handleSubmit}
|
||||
|
||||
@@ -65,7 +65,7 @@ const EmailStep = ({ form, errors, onSubmit, onChange }) => {
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
type="submit"
|
||||
disabled={errors.email && true}
|
||||
sx={{
|
||||
|
||||
@@ -24,7 +24,7 @@ const ForgotPasswordLabel = ({ email, errorEmail }) => {
|
||||
</Typography>
|
||||
<Typography
|
||||
component="span"
|
||||
color={theme.palette.primary.main}
|
||||
color={theme.palette.accent.main}
|
||||
ml={theme.spacing(2)}
|
||||
sx={{ userSelect: "none" }}
|
||||
onClick={handleNavigate}
|
||||
|
||||
@@ -91,7 +91,7 @@ const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => {
|
||||
</Button>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
type="submit"
|
||||
loading={authState.isLoading}
|
||||
disabled={errors.password && true}
|
||||
|
||||
@@ -145,7 +145,8 @@ const Login = () => {
|
||||
fontWeight: 600,
|
||||
fontSize: 28,
|
||||
},
|
||||
"& p": { fontSize: 14, color: theme.palette.text.accent },
|
||||
/* TODO set font size from theme */
|
||||
"& p": { fontSize: 14, color: theme.palette.primary.contrastTextSecondary },
|
||||
"& span": { fontSize: "inherit" },
|
||||
}}
|
||||
>
|
||||
@@ -153,7 +154,7 @@ const Login = () => {
|
||||
className="background-pattern-svg"
|
||||
sx={{
|
||||
"& svg g g:last-of-type path": {
|
||||
stroke: theme.palette.border.light,
|
||||
stroke: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -181,8 +182,8 @@ const Login = () => {
|
||||
"& > .MuiStack-root": {
|
||||
border: 1,
|
||||
borderRadius: theme.spacing(5),
|
||||
borderColor: theme.palette.border.light,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: {
|
||||
xs: theme.spacing(12),
|
||||
sm: theme.spacing(20),
|
||||
|
||||
@@ -31,14 +31,15 @@ const NewPasswordConfirmed = () => {
|
||||
fontWeight: 600,
|
||||
fontSize: 21,
|
||||
},
|
||||
"& p": { fontSize: 13.5, color: theme.palette.text.accent },
|
||||
/* TODO font size from theme*/
|
||||
"& p": { fontSize: 13.5, color: theme.palette.primary.contrastTextSecondary },
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
className="background-pattern-svg"
|
||||
sx={{
|
||||
"& svg g g:last-of-type path": {
|
||||
stroke: theme.palette.border.light,
|
||||
stroke: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -65,8 +66,8 @@ const NewPasswordConfirmed = () => {
|
||||
"& > .MuiStack-root": {
|
||||
border: 1,
|
||||
borderRadius: theme.spacing(5),
|
||||
borderColor: theme.palette.border.light,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: {
|
||||
xs: theme.spacing(12),
|
||||
sm: theme.spacing(20),
|
||||
@@ -103,7 +104,6 @@ const NewPasswordConfirmed = () => {
|
||||
</Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => navigate("/uptime")}
|
||||
sx={{
|
||||
width: "100%",
|
||||
|
||||
@@ -50,7 +50,7 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
|
||||
"& svg": {
|
||||
mr: theme.spacing(4),
|
||||
"& path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
},
|
||||
"&:focus-visible": {
|
||||
@@ -77,7 +77,7 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
|
||||
}}
|
||||
sx={{
|
||||
"&:hover": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -95,7 +95,7 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
|
||||
}}
|
||||
sx={{
|
||||
"&:hover": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -285,7 +285,8 @@ const Register = ({ isSuperAdmin }) => {
|
||||
fontWeight: 600,
|
||||
fontSize: 28,
|
||||
},
|
||||
"& p": { fontSize: 14, color: theme.palette.text.accent },
|
||||
/* TODO set fontsize from theme */
|
||||
"& p": { fontSize: 14, color: theme.palette.primary.contrastTextSecondary },
|
||||
"& span": { fontSize: "inherit" },
|
||||
}}
|
||||
>
|
||||
@@ -293,7 +294,7 @@ const Register = ({ isSuperAdmin }) => {
|
||||
className="background-pattern-svg"
|
||||
sx={{
|
||||
"& svg g g:last-of-type path": {
|
||||
stroke: theme.palette.border.light,
|
||||
stroke: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -320,8 +321,8 @@ const Register = ({ isSuperAdmin }) => {
|
||||
"& > .MuiStack-root": {
|
||||
border: 1,
|
||||
borderRadius: theme.spacing(5),
|
||||
borderColor: theme.palette.border.light,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: {
|
||||
xs: theme.spacing(12),
|
||||
sm: theme.spacing(20),
|
||||
|
||||
@@ -111,7 +111,7 @@ function StepOne({ form, errors, onSubmit, onChange, onBack }) {
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
type="submit"
|
||||
disabled={(errors.firstName || errors.lastName) && true}
|
||||
sx={{
|
||||
|
||||
@@ -134,7 +134,7 @@ function StepThree({ onSubmit, onBack }) {
|
||||
mr: theme.spacing(3),
|
||||
},
|
||||
":focus-visible": {
|
||||
outline: `2px solid ${theme.palette.primary.dark}`,
|
||||
outline: `2px solid ${theme.palette.primary.lowContrast}`,
|
||||
outlineOffset: "4px",
|
||||
},
|
||||
}}
|
||||
@@ -145,7 +145,7 @@ function StepThree({ onSubmit, onBack }) {
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
disabled={
|
||||
form.password.length === 0 ||
|
||||
form.confirm.length === 0 ||
|
||||
|
||||
@@ -93,7 +93,7 @@ function StepTwo({ form, errors, onSubmit, onChange, onBack }) {
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={onSubmit}
|
||||
disabled={errors.email && true}
|
||||
sx={{
|
||||
|
||||
@@ -74,8 +74,9 @@ const SetNewPassword = () => {
|
||||
fontSize: 24,
|
||||
},
|
||||
"& p": {
|
||||
/* TODO font size from theme */
|
||||
fontSize: 14,
|
||||
color: theme.palette.text.accent,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -83,7 +84,7 @@ const SetNewPassword = () => {
|
||||
className="background-pattern-svg"
|
||||
sx={{
|
||||
"& svg g g:last-of-type path": {
|
||||
stroke: theme.palette.border.light,
|
||||
stroke: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -110,8 +111,8 @@ const SetNewPassword = () => {
|
||||
"& > .MuiStack-root": {
|
||||
border: 1,
|
||||
borderRadius: theme.spacing(5),
|
||||
borderColor: theme.palette.border.light,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
padding: {
|
||||
xs: theme.spacing(12),
|
||||
sm: theme.spacing(20),
|
||||
@@ -233,7 +234,7 @@ const SetNewPassword = () => {
|
||||
</Box>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
loading={isLoading}
|
||||
onClick={handleSubmit}
|
||||
disabled={
|
||||
|
||||
@@ -16,7 +16,7 @@ const Empty = ({ styles, mode }) => {
|
||||
</Box>
|
||||
<Typography
|
||||
textAlign="center"
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
No incidents recorded yet.
|
||||
</Typography>
|
||||
|
||||
@@ -158,9 +158,9 @@ const IncidentTable = ({ monitors, selectedMonitor, filter }) => {
|
||||
|
||||
let sharedStyles = {
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
p: theme.spacing(30),
|
||||
};
|
||||
|
||||
@@ -187,7 +187,7 @@ const IncidentTable = ({ monitors, selectedMonitor, filter }) => {
|
||||
</Box>
|
||||
<Typography
|
||||
textAlign="center"
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
The monitor you have selected has no recorded incidents yet.
|
||||
</Typography>
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
font-size: var(--env-var-font-size-medium);
|
||||
}
|
||||
.incidents button.MuiButtonBase-root {
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
}
|
||||
@@ -83,7 +83,7 @@ const Incidents = () => {
|
||||
<Typography
|
||||
display="inline-block"
|
||||
component="h1"
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
Incidents for
|
||||
</Typography>
|
||||
@@ -94,14 +94,15 @@ const Incidents = () => {
|
||||
onChange={handleSelect}
|
||||
items={Object.values(monitors)}
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
}}
|
||||
/>
|
||||
<ButtonGroup
|
||||
sx={{
|
||||
ml: "auto",
|
||||
"& .MuiButtonBase-root, & .MuiButtonBase-root:hover": {
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -407,7 +407,7 @@ const CreateInfrastructureMonitor = () => {
|
||||
>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={handleCreateInfrastructureMonitor}
|
||||
loading={monitorState?.isLoading}
|
||||
>
|
||||
|
||||
@@ -19,7 +19,7 @@ const Empty = ({ styles }) => {
|
||||
<Typography variant="h2">Your infrastructure dashboard will show here</Typography>
|
||||
<Typography
|
||||
textAlign="center"
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
Hang tight! Data is loading
|
||||
</Typography>
|
||||
|
||||
@@ -108,10 +108,10 @@ const BaseBox = ({ children, sx = {} }) => {
|
||||
padding: `${theme.spacing(BASE_BOX_PADDING_VERTICAL)} ${theme.spacing(BASE_BOX_PADDING_HORIZONTAL)}`,
|
||||
minWidth: 200,
|
||||
width: 225,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
...sx,
|
||||
}}
|
||||
>
|
||||
@@ -155,7 +155,7 @@ const GaugeBox = ({ value, heading, metricOne, valueOne, metricTwo, valueTwo })
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
borderTop: `1px solid ${theme.palette.border.light}`,
|
||||
borderTop: `1px solid ${theme.palette.primary.lowContrast}`,
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
@@ -408,8 +408,8 @@ const InfrastructureDetails = () => {
|
||||
data: checks,
|
||||
dataKeys: ["avgMemoryUsage"],
|
||||
heading: "Memory usage",
|
||||
strokeColor: theme.palette.primary.main,
|
||||
gradientStartColor: theme.palette.primary.main,
|
||||
strokeColor: theme.palette.accent.main, // CAIO_REVIEW
|
||||
gradientStartColor: theme.palette.accent.main, // CAIO_REVIEW
|
||||
yLabel: "Memory usage",
|
||||
yDomain: [0, 1],
|
||||
yTick: <PercentTick />,
|
||||
@@ -668,9 +668,9 @@ const InfrastructureDetails = () => {
|
||||
<Empty
|
||||
styles={{
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
p: theme.spacing(30),
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -83,7 +83,7 @@ const InfrastructureMenu = ({ monitor, isAdmin, updateCallback }) => {
|
||||
outline: "none",
|
||||
},
|
||||
"& svg path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
}}
|
||||
ref={anchor}
|
||||
|
||||
@@ -137,13 +137,7 @@ function Infrastructure() {
|
||||
id: "actions",
|
||||
content: "Actions",
|
||||
render: (row) => (
|
||||
<IconButton
|
||||
sx={{
|
||||
"& svg path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<IconButton>
|
||||
<InfrastructureMenu
|
||||
monitor={row}
|
||||
isAdmin={isAdmin}
|
||||
@@ -166,12 +160,12 @@ function Infrastructure() {
|
||||
.toString();
|
||||
const percentageColor =
|
||||
monitor.uptimePercentage < 0.25
|
||||
? theme.palette.percentage.uptimePoor
|
||||
? theme.palette.error.main
|
||||
: monitor.uptimePercentage < 0.5
|
||||
? theme.palette.percentage.uptimeFair
|
||||
: monitor.uptimePercentage < 0.75
|
||||
? theme.palette.percentage.uptimeGood
|
||||
: theme.palette.percentage.uptimeExcellent;
|
||||
: theme.palette.success.lowContrast;
|
||||
return {
|
||||
id: monitor._id,
|
||||
name: monitor.name,
|
||||
@@ -194,10 +188,10 @@ function Infrastructure() {
|
||||
':has(> [class*="fallback__"])': {
|
||||
position: "relative",
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
borderStyle: "dashed",
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
overflow: "hidden",
|
||||
},
|
||||
}}
|
||||
@@ -217,7 +211,7 @@ function Infrastructure() {
|
||||
{isAdmin && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={navigateToCreate}
|
||||
sx={{ fontWeight: 500, whiteSpace: "nowrap" }}
|
||||
>
|
||||
@@ -240,14 +234,19 @@ function Infrastructure() {
|
||||
}}
|
||||
>
|
||||
<Heading component="h2">Infrastructure monitors</Heading>
|
||||
{/* TODO Correct the class current-monitors-counter, there are some unnecessary things there */}
|
||||
{/* TODO Same as the one in UptimaDataTable. Create component */}
|
||||
<Box
|
||||
component="span"
|
||||
className="current-monitors-counter"
|
||||
color={theme.palette.text.primary}
|
||||
border={1}
|
||||
borderColor={theme.palette.border.light}
|
||||
backgroundColor={theme.palette.background.accent}
|
||||
color={theme.palette.tertiary.contrastText}
|
||||
border={2}
|
||||
borderColor={theme.palette.accent.main}
|
||||
backgroundColor={theme.palette.tertiary.main}
|
||||
sx={{
|
||||
padding: ".25em .75em",
|
||||
borderRadius: "50%",
|
||||
fontSize: "12px",
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
{summary?.totalMonitors ?? 0}
|
||||
</Box>
|
||||
@@ -255,10 +254,12 @@ function Infrastructure() {
|
||||
|
||||
<DataTable
|
||||
config={{
|
||||
/* TODO this behavior seems to be repeated. Put it on the root table? */
|
||||
rowSX: {
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
"&:hover td": {
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
transition: "background-color .3s ease",
|
||||
},
|
||||
},
|
||||
onRowClick: (row) => openDetails(row.id),
|
||||
@@ -266,6 +267,7 @@ function Infrastructure() {
|
||||
headers={headers}
|
||||
data={monitorsAsRows}
|
||||
/>
|
||||
|
||||
<Pagination
|
||||
monitorCount={summary?.totalMonitors ?? 0}
|
||||
page={page}
|
||||
|
||||
@@ -33,9 +33,9 @@ const IntegrationsComponent = ({ icon, header, info, onClick }) => {
|
||||
pl={theme.spacing(12)}
|
||||
height="100%"
|
||||
border={1}
|
||||
borderColor={theme.palette.border.light}
|
||||
borderColor={theme.palette.primary.lowContrast}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
backgroundColor={theme.palette.background.main}
|
||||
backgroundColor={theme.palette.primary.main}
|
||||
>
|
||||
{icon}
|
||||
<Stack
|
||||
@@ -54,7 +54,7 @@ const IntegrationsComponent = ({ icon, header, info, onClick }) => {
|
||||
</Stack>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={onClick}
|
||||
sx={{ alignSelf: "center" }}
|
||||
disabled={true}
|
||||
@@ -126,7 +126,7 @@ const Integrations = () => {
|
||||
gap={theme.spacing(2)}
|
||||
sx={{
|
||||
"& h1, & p": {
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -360,7 +360,6 @@ const CreateMaintenance = () => {
|
||||
<DatePicker
|
||||
id="startDate"
|
||||
disablePast
|
||||
label="Date"
|
||||
disableHighlightToday
|
||||
value={form.startDate}
|
||||
slots={{ openPickerIcon: CalendarIcon }}
|
||||
@@ -374,17 +373,17 @@ const CreateMaintenance = () => {
|
||||
flexDirection: "row-reverse",
|
||||
},
|
||||
"& input": {
|
||||
height: 34,
|
||||
minHeight: 34,
|
||||
p: 0,
|
||||
pr: theme.spacing(5),
|
||||
},
|
||||
"& fieldset": {
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
"&:not(:has(.Mui-disabled)):not(:has(.Mui-error)) .MuiOutlinedInput-root:not(:has(input:focus)):hover fieldset":
|
||||
{
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -394,12 +393,36 @@ const CreateMaintenance = () => {
|
||||
py: 0,
|
||||
mr: 0,
|
||||
"& path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
strokeWidth: 1.1,
|
||||
},
|
||||
"&:hover": { backgroundColor: "transparent" },
|
||||
},
|
||||
},
|
||||
// CAIO_REVIEW, entire popper
|
||||
popper: {
|
||||
sx: {
|
||||
"& .MuiPickersDay-root": {
|
||||
color: theme.palette.primary.contrastText,
|
||||
"&.Mui-selected": {
|
||||
backgroundColor: theme.palette.accent.main, // Selected day background
|
||||
color: theme.palette.primary.contrastText, // Selected day text color
|
||||
},
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.accent.light, // Hover background
|
||||
},
|
||||
"&.Mui-disabled": {
|
||||
color: theme.palette.primary.lowContrast, // Disabled day color
|
||||
},
|
||||
},
|
||||
"& .MuiDayCalendar-weekDayLabel": {
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
"& .MuiPickersCalendarHeader-label": {
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
sx={{}}
|
||||
onChange={(newDate) => {
|
||||
@@ -439,17 +462,17 @@ const CreateMaintenance = () => {
|
||||
flexDirection: "row-reverse",
|
||||
},
|
||||
"& input": {
|
||||
height: 34,
|
||||
minHeight: 34,
|
||||
p: 0,
|
||||
pl: theme.spacing(5),
|
||||
},
|
||||
"& fieldset": {
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
"&:not(:has(.Mui-disabled)):not(:has(.Mui-error)) .MuiOutlinedInput-root:not(:has(input:focus)):hover fieldset":
|
||||
{
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -532,7 +555,7 @@ const CreateMaintenance = () => {
|
||||
<LoadingButton
|
||||
loading={isLoading}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={handleSubmit}
|
||||
disabled={false}
|
||||
>
|
||||
|
||||
@@ -95,7 +95,7 @@ const ActionsMenu = ({ /* isAdmin, */ maintenanceWindow, updateCallback }) => {
|
||||
outline: "none",
|
||||
},
|
||||
"& svg path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -322,21 +322,21 @@ const MaintenanceTable = ({
|
||||
minWidth: theme.spacing(20),
|
||||
textAlign: "left",
|
||||
"&.Mui-focused > div": {
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
mt: theme.spacing(6),
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
"& svg path": {
|
||||
stroke: theme.palette.text.tertiary,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
strokeWidth: 1.3,
|
||||
},
|
||||
"& .MuiSelect-select": {
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -51,10 +51,10 @@ const Maintenance = () => {
|
||||
':has(> [class*="fallback__"])': {
|
||||
position: "relative",
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
borderStyle: "dashed",
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
overflow: "hidden",
|
||||
},
|
||||
}}
|
||||
@@ -70,7 +70,7 @@ const Maintenance = () => {
|
||||
<Breadcrumbs list={[{ name: "maintenance", path: "/maintenance" }]} />
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={() => {
|
||||
navigate("/maintenance/create");
|
||||
}}
|
||||
|
||||
@@ -58,7 +58,7 @@ const NotFound = ({ title = DefaultValue.title, desc = DefaultValue.desc }) => {
|
||||
<Typography variant="body1">{desc}</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
sx={{ mt: theme.spacing(10) }}
|
||||
onClick={() => navigate("/")}
|
||||
>
|
||||
|
||||
@@ -249,7 +249,7 @@ const PageSpeedConfigure = () => {
|
||||
width: 4,
|
||||
height: 4,
|
||||
borderRadius: "50%",
|
||||
backgroundColor: theme.palette.text.tertiary,
|
||||
backgroundColor: theme.palette.primary.contrastTextTertiary,
|
||||
opacity: 0.8,
|
||||
left: -10,
|
||||
top: "50%",
|
||||
@@ -276,7 +276,7 @@ const PageSpeedConfigure = () => {
|
||||
"& svg": {
|
||||
mr: theme.spacing(2),
|
||||
"& path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
strokeWidth: 0.1,
|
||||
},
|
||||
},
|
||||
@@ -319,7 +319,7 @@ const PageSpeedConfigure = () => {
|
||||
gap={theme.spacing(20)}
|
||||
sx={{
|
||||
".MuiInputBase-root:has(> .Mui-disabled)": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -426,7 +426,7 @@ const PageSpeedConfigure = () => {
|
||||
loading={isLoading}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={handleSave}
|
||||
sx={{ px: theme.spacing(12) }}
|
||||
>
|
||||
|
||||
@@ -179,7 +179,7 @@ const CreatePageSpeed = () => {
|
||||
className="create-monitor"
|
||||
sx={{
|
||||
"& h1": {
|
||||
color: theme.palette.text.primary,
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -207,7 +207,7 @@ const CreatePageSpeed = () => {
|
||||
component="span"
|
||||
fontSize="inherit"
|
||||
fontWeight="inherit"
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
PageSpeed monitor
|
||||
</Typography>
|
||||
@@ -337,7 +337,7 @@ const CreatePageSpeed = () => {
|
||||
>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={handleCreateMonitor}
|
||||
disabled={!Object.values(errors).every((value) => value === undefined)}
|
||||
loading={isLoading}
|
||||
|
||||
@@ -18,7 +18,7 @@ const config = {
|
||||
seo: {
|
||||
id: "seo",
|
||||
text: "SEO",
|
||||
color: "unresolved",
|
||||
color: "secondary",
|
||||
},
|
||||
performance: {
|
||||
id: "performance",
|
||||
@@ -33,7 +33,7 @@ const config = {
|
||||
accessibility: {
|
||||
id: "accessibility",
|
||||
text: "accessibility",
|
||||
color: "primary",
|
||||
color: "accent",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -54,9 +54,9 @@ const CustomToolTip = ({ active, payload, label, config }) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
py: theme.spacing(2),
|
||||
px: theme.spacing(4),
|
||||
@@ -64,7 +64,7 @@ const CustomToolTip = ({ active, payload, label, config }) => {
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
@@ -86,7 +86,7 @@ const CustomToolTip = ({ active, payload, label, config }) => {
|
||||
mt={theme.spacing(1)}
|
||||
sx={{
|
||||
"& span": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 11,
|
||||
fontWeight: 500,
|
||||
},
|
||||
@@ -186,7 +186,7 @@ const CustomTick = ({ x, y, payload, index }) => {
|
||||
x={x}
|
||||
y={y + 8}
|
||||
textAnchor="middle"
|
||||
fill={theme.palette.text.tertiary}
|
||||
fill={theme.palette.primary.contrastTextTertiary}
|
||||
fontSize={11}
|
||||
fontWeight={400}
|
||||
>
|
||||
@@ -238,14 +238,14 @@ const PagespeedDetailsAreaChart = ({ data, interval, metrics }) => {
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
<CartesianGrid
|
||||
stroke={theme.palette.border.light}
|
||||
stroke={theme.palette.primary.lowContrast}
|
||||
strokeWidth={1}
|
||||
strokeOpacity={1}
|
||||
fill="transparent"
|
||||
vertical={false}
|
||||
/>
|
||||
<XAxis
|
||||
stroke={theme.palette.border.dark}
|
||||
stroke={theme.palette.primary.lowContrast}
|
||||
dataKey="createdAt"
|
||||
tick={<CustomTick />}
|
||||
axisLine={false}
|
||||
@@ -255,13 +255,14 @@ const PagespeedDetailsAreaChart = ({ data, interval, metrics }) => {
|
||||
interval="equidistantPreserveStart"
|
||||
/>
|
||||
<Tooltip
|
||||
cursor={{ stroke: theme.palette.border.light }}
|
||||
cursor={{ stroke: theme.palette.primary.lowContrast }}
|
||||
content={<CustomToolTip config={filteredConfig} />}
|
||||
/>
|
||||
<defs>
|
||||
{Object.values(filteredConfig).map(({ id, color }) => {
|
||||
/* TODO not working? */
|
||||
const startColor = theme.palette[color].main;
|
||||
const endColor = theme.palette[color].light;
|
||||
const endColor = theme.palette[color].lowContrast;
|
||||
|
||||
return (
|
||||
<linearGradient
|
||||
@@ -289,7 +290,7 @@ const PagespeedDetailsAreaChart = ({ data, interval, metrics }) => {
|
||||
{Object.keys(filteredConfig).map((key) => {
|
||||
const { color } = filteredConfig[key];
|
||||
const strokeColor = theme.palette[color].main;
|
||||
const bgColor = theme.palette.background.main;
|
||||
const bgColor = theme.palette.primary.main;
|
||||
|
||||
return (
|
||||
<Area
|
||||
|
||||
@@ -126,29 +126,29 @@ const PieChart = ({ audits }) => {
|
||||
if (value >= 90 && value <= 100)
|
||||
return {
|
||||
stroke: theme.palette.success.main,
|
||||
strokeBg: theme.palette.success.light,
|
||||
strokeBg: theme.palette.success.lowContrast,
|
||||
text: theme.palette.success.contrastText,
|
||||
bg: theme.palette.success.light,
|
||||
bg: theme.palette.success.lowContrast,
|
||||
};
|
||||
else if (value >= 50 && value < 90)
|
||||
return {
|
||||
stroke: theme.palette.warning.main,
|
||||
strokeBg: theme.palette.warning.light,
|
||||
strokeBg: theme.palette.warning.lowContrast,
|
||||
text: theme.palette.warning.contrastText,
|
||||
bg: theme.palette.warning.dark,
|
||||
bg: theme.palette.warning.lowContrast,
|
||||
};
|
||||
else if (value >= 0 && value < 50)
|
||||
return {
|
||||
stroke: theme.palette.error.contrastText,
|
||||
strokeBg: theme.palette.error.light,
|
||||
strokeBg: theme.palette.error.lowContrast,
|
||||
text: theme.palette.error.contrastText,
|
||||
bg: theme.palette.error.dark,
|
||||
bg: theme.palette.error.lowContrast,
|
||||
};
|
||||
return {
|
||||
stroke: theme.palette.unresolved.main,
|
||||
strokeBg: theme.palette.unresolved.light,
|
||||
text: theme.palette.unresolved.main,
|
||||
bg: theme.palette.unresolved.bg,
|
||||
stroke: theme.palette.tertiary.contrastText,
|
||||
strokeBg: theme.palette.tertiary.contrastText,
|
||||
text: theme.palette.tertiary.contrastText,
|
||||
bg: theme.palette.tertiary.main,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.page-speed-details button.MuiButtonBase-root {
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
}
|
||||
|
||||
.page-speed-details .MuiPieArcLabel-root {
|
||||
|
||||
@@ -151,7 +151,7 @@ const PageSpeedDetails = () => {
|
||||
width: 4,
|
||||
height: 4,
|
||||
borderRadius: "50%",
|
||||
backgroundColor: theme.palette.text.tertiary,
|
||||
backgroundColor: theme.palette.primary.contrastTextTertiary,
|
||||
opacity: 0.8,
|
||||
left: -9,
|
||||
top: "50%",
|
||||
@@ -175,7 +175,7 @@ const PageSpeedDetails = () => {
|
||||
"& svg": {
|
||||
mr: theme.spacing(3),
|
||||
"& path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
},
|
||||
}}
|
||||
@@ -372,7 +372,7 @@ const PageSpeedDetails = () => {
|
||||
? theme.palette.warning.main
|
||||
: score >= 0
|
||||
? theme.palette.error.contrastText
|
||||
: theme.palette.unresolved.main;
|
||||
: theme.palette.tertiary.main;
|
||||
|
||||
// Find the position where the number ends and the unit begins
|
||||
const match = audit.displayValue.match(/(\d+\.?\d*)\s*([a-zA-Z]+)/);
|
||||
@@ -393,7 +393,7 @@ const PageSpeedDetails = () => {
|
||||
gap={theme.spacing(4)}
|
||||
p={theme.spacing(3)}
|
||||
border={1}
|
||||
borderColor={theme.palette.border.light}
|
||||
borderColor={theme.palette.primary.lowContrast}
|
||||
borderRadius={4}
|
||||
>
|
||||
<Box>
|
||||
@@ -410,7 +410,7 @@ const PageSpeedDetails = () => {
|
||||
component="span"
|
||||
fontSize={14}
|
||||
fontWeight={500}
|
||||
color={theme.palette.text.primary}
|
||||
color={theme.palette.primary.contrastText}
|
||||
>
|
||||
{value}
|
||||
<Typography
|
||||
|
||||
@@ -6,17 +6,17 @@ export const ChartBox = styled(Stack)(({ theme }) => ({
|
||||
minWidth: 250,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: 4,
|
||||
borderTopRightRadius: 16,
|
||||
borderBottomRightRadius: 16,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
"& h2": {
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
fontSize: 15,
|
||||
fontWeight: 500,
|
||||
},
|
||||
"& p": { color: theme.palette.text.tertiary },
|
||||
"& p": { color: theme.palette.primary.contrastTextTertiary },
|
||||
"& > :nth-of-type(1)": {
|
||||
gridColumn: 1,
|
||||
gridRow: 1,
|
||||
@@ -31,10 +31,10 @@ export const ChartBox = styled(Stack)(({ theme }) => ({
|
||||
padding: theme.spacing(8),
|
||||
borderLeft: 1,
|
||||
borderLeftStyle: "solid",
|
||||
borderLeftColor: theme.palette.border.light,
|
||||
borderLeftColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: 16,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
background: `linear-gradient(325deg, ${theme.palette.background.accent} 20%, ${theme.palette.background.main} 45%)`,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
background: `linear-gradient(325deg, ${theme.palette.tertiary.main} 20%, ${theme.palette.primary.main} 45%)`,
|
||||
},
|
||||
"& path": {
|
||||
transition: "stroke-width 400ms ease",
|
||||
|
||||
@@ -23,9 +23,9 @@ const CustomToolTip = ({ payload }) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.dark,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
py: theme.spacing(2),
|
||||
px: theme.spacing(4),
|
||||
@@ -33,7 +33,7 @@ const CustomToolTip = ({ payload }) => {
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
@@ -52,7 +52,7 @@ const CustomToolTip = ({ payload }) => {
|
||||
mt={theme.spacing(1)}
|
||||
sx={{
|
||||
"& span": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 11,
|
||||
fontWeight: 500,
|
||||
},
|
||||
@@ -81,6 +81,7 @@ CustomToolTip.propTypes = {
|
||||
payload: PropTypes.array,
|
||||
};
|
||||
|
||||
/* TODO separate utils in folder*/
|
||||
/**
|
||||
* Processes the raw data to include a score for each entry.
|
||||
* @param {Array<Object>} data - The raw data array.
|
||||
@@ -104,6 +105,7 @@ const processData = (data) => {
|
||||
return formattedData;
|
||||
};
|
||||
|
||||
/* TODO separate component*/
|
||||
/**
|
||||
* Renders an area chart displaying page speed scores.
|
||||
* @param {Object} props
|
||||
@@ -114,7 +116,9 @@ const processData = (data) => {
|
||||
const PagespeedAreaChart = ({ data, status }) => {
|
||||
const theme = useTheme();
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const { pagespeedStyles } = useUtils();
|
||||
const { statusToTheme } = useUtils();
|
||||
|
||||
const themeColor = statusToTheme[status];
|
||||
|
||||
const formattedData = processData(data);
|
||||
|
||||
@@ -134,14 +138,14 @@ const PagespeedAreaChart = ({ data, status }) => {
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
<CartesianGrid
|
||||
stroke={theme.palette.border.light}
|
||||
stroke={theme.palette.primary.lowContrast}
|
||||
strokeWidth={1}
|
||||
strokeOpacity={1}
|
||||
fill="transparent"
|
||||
vertical={false}
|
||||
/>
|
||||
<Tooltip
|
||||
cursor={{ stroke: theme.palette.border.light }}
|
||||
cursor={{ stroke: theme.palette.primary.lowContrast }}
|
||||
content={<CustomToolTip />}
|
||||
/>
|
||||
<defs>
|
||||
@@ -154,24 +158,24 @@ const PagespeedAreaChart = ({ data, status }) => {
|
||||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor={pagespeedStyles[status].stroke}
|
||||
stopColor={theme.palette[themeColor].lowContrast}
|
||||
stopOpacity={0.8}
|
||||
/>
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor={pagespeedStyles[status].light}
|
||||
stopColor={theme.palette[themeColor].main}
|
||||
stopOpacity={0}
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<Area
|
||||
dataKey="score"
|
||||
stroke={pagespeedStyles[status].stroke}
|
||||
stroke={theme.palette[themeColor].lowContrast}
|
||||
strokeWidth={isHovered ? 2.5 : 1.5}
|
||||
fill={`url(#pagespeed-chart-${status})`}
|
||||
activeDot={{
|
||||
stroke: pagespeedStyles[status].light,
|
||||
fill: pagespeedStyles[status].stroke,
|
||||
stroke: theme.palette[themeColor].main,
|
||||
fill: theme.palette[themeColor].lowContrast,
|
||||
r: 4.5,
|
||||
}}
|
||||
/>
|
||||
@@ -192,6 +196,7 @@ PagespeedAreaChart.propTypes = {
|
||||
status: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
/* TODO separate component */
|
||||
/**
|
||||
* Renders a card displaying monitor details and an area chart.
|
||||
* @param {Object} props
|
||||
@@ -215,9 +220,9 @@ const Card = ({ monitor }) => {
|
||||
p={theme.spacing(8)}
|
||||
onClick={() => navigate(`/pagespeed/${monitor._id}`)}
|
||||
border={1}
|
||||
borderColor={theme.palette.border.light}
|
||||
borderColor={theme.palette.primary.lowContrast}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
backgroundColor={theme.palette.background.main}
|
||||
backgroundColor={theme.palette.primary.main}
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "34px 2fr 1fr",
|
||||
@@ -225,7 +230,7 @@ const Card = ({ monitor }) => {
|
||||
gridTemplateRows: "34px 1fr 3fr",
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
},
|
||||
"& path": {
|
||||
transition: "stroke-width 400ms ease",
|
||||
@@ -278,8 +283,8 @@ const Card = ({ monitor }) => {
|
||||
px={theme.spacing(4)}
|
||||
borderTop={1}
|
||||
borderRight={1}
|
||||
borderColor={theme.palette.border.light}
|
||||
backgroundColor={theme.palette.background.accent}
|
||||
borderColor={theme.palette.primary.lowContrast}
|
||||
backgroundColor={theme.palette.tertiary.main}
|
||||
sx={{
|
||||
pointerEvents: "none",
|
||||
userSelect: "none",
|
||||
@@ -289,7 +294,7 @@ const Card = ({ monitor }) => {
|
||||
>
|
||||
<Typography
|
||||
fontSize={11}
|
||||
color={theme.palette.text.accent}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
Checking every{" "}
|
||||
{(() => {
|
||||
@@ -299,7 +304,7 @@ const Card = ({ monitor }) => {
|
||||
<Typography
|
||||
component="span"
|
||||
fontSize={12}
|
||||
color={theme.palette.text.primary}
|
||||
color={theme.palette.primary.contrastText}
|
||||
>
|
||||
{time}{" "}
|
||||
</Typography>
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
font-size: var(--env-var-font-size-small);
|
||||
}
|
||||
.page-speed:not(:has([class*="fallback__"])) button {
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
}
|
||||
@@ -60,10 +60,10 @@ const PageSpeed = () => {
|
||||
':has(> [class*="fallback__"])': {
|
||||
position: "relative",
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
borderStyle: "dashed",
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
overflow: "hidden",
|
||||
},
|
||||
}}
|
||||
@@ -83,7 +83,7 @@ const PageSpeed = () => {
|
||||
{isAdmin && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={() => navigate("/pagespeed/create")}
|
||||
sx={{ fontWeight: 500, whiteSpace: "nowrap" }}
|
||||
>
|
||||
@@ -105,10 +105,10 @@ const PageSpeed = () => {
|
||||
<Box
|
||||
component="span"
|
||||
className="current-monitors-counter"
|
||||
color={theme.palette.text.primary}
|
||||
color={theme.palette.primary.contrastText}
|
||||
border={1}
|
||||
borderColor={theme.palette.border.light}
|
||||
backgroundColor={theme.palette.background.accent}
|
||||
borderColor={theme.palette.primary.lowContrast}
|
||||
backgroundColor={theme.palette.tertiary.main}
|
||||
>
|
||||
{summary?.totalMonitors ?? 0}
|
||||
</Box>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
.settings button {
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
}
|
||||
.settings span.MuiTypography-root {
|
||||
opacity: 0.6;
|
||||
|
||||
@@ -287,7 +287,7 @@ const Settings = () => {
|
||||
<Typography>Add demo monitors</Typography>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
loading={isLoading || authIsLoading || checksIsLoading}
|
||||
onClick={handleInsertDemoMonitors}
|
||||
sx={{ mt: theme.spacing(4) }}
|
||||
@@ -346,7 +346,7 @@ const Settings = () => {
|
||||
loading={isLoading || authIsLoading || checksIsLoading}
|
||||
disabled={Object.keys(errors).length > 0}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
sx={{ px: theme.spacing(12), mt: theme.spacing(20) }}
|
||||
onClick={handleSave}
|
||||
>
|
||||
|
||||
@@ -12,10 +12,10 @@ const Status = () => {
|
||||
':has(> [class*="fallback__"])': {
|
||||
position: "relative",
|
||||
border: 1,
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
borderStyle: "dashed",
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
overflow: "hidden",
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -274,7 +274,7 @@ const Configure = () => {
|
||||
width: 4,
|
||||
height: 4,
|
||||
borderRadius: "50%",
|
||||
backgroundColor: theme.palette.text.tertiary,
|
||||
backgroundColor: theme.palette.primary.contrastTextTertiary,
|
||||
opacity: 0.8,
|
||||
left: -10,
|
||||
top: "50%",
|
||||
@@ -305,7 +305,7 @@ const Configure = () => {
|
||||
width: 22,
|
||||
height: 22,
|
||||
"& path": {
|
||||
stroke: theme.palette.text.tertiary,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
strokeWidth: 1.7,
|
||||
},
|
||||
},
|
||||
@@ -445,7 +445,7 @@ const Configure = () => {
|
||||
>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
loading={isLoading}
|
||||
sx={{ px: theme.spacing(12) }}
|
||||
onClick={handleSubmit}
|
||||
|
||||
@@ -402,7 +402,7 @@ const CreateMonitor = () => {
|
||||
>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={handleCreateMonitor}
|
||||
disabled={!Object.values(errors).every((value) => value === undefined)}
|
||||
loading={isLoading}
|
||||
|
||||
@@ -31,7 +31,7 @@ const DownBarChart = memo(({ monitor, type, onBarHover }) => {
|
||||
}}
|
||||
>
|
||||
<XAxis
|
||||
stroke={theme.palette.border.dark}
|
||||
stroke={theme.palette.primary.lowContrast}
|
||||
height={15}
|
||||
tick={false}
|
||||
label={
|
||||
@@ -53,26 +53,28 @@ const DownBarChart = memo(({ monitor, type, onBarHover }) => {
|
||||
maxBarSize={7}
|
||||
background={{ fill: "transparent" }}
|
||||
>
|
||||
{monitor.groupedDownChecks.map((entry, index) => (
|
||||
<Cell
|
||||
key={`cell-${entry.time}`}
|
||||
fill={
|
||||
hoveredBarIndex === index
|
||||
? theme.palette.error.main
|
||||
: chartHovered
|
||||
? theme.palette.error.light
|
||||
: theme.palette.error.main
|
||||
}
|
||||
onMouseEnter={() => {
|
||||
setHoveredBarIndex(index);
|
||||
onBarHover(entry);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setHoveredBarIndex(null);
|
||||
onBarHover({ time: null, totalChecks: 0 });
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{monitor.groupedDownChecks.map((entry, index) => {
|
||||
return (
|
||||
<Cell
|
||||
key={`cell-${entry.time}`}
|
||||
fill={
|
||||
hoveredBarIndex === index
|
||||
? theme.palette.error.main
|
||||
: chartHovered
|
||||
? theme.palette.error.light // CAIO_REVIEW
|
||||
: theme.palette.error.main
|
||||
}
|
||||
onMouseEnter={() => {
|
||||
setHoveredBarIndex(index);
|
||||
onBarHover(entry);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setHoveredBarIndex(null);
|
||||
onBarHover({ time: null, totalChecks: 0 });
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Bar>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
|
||||
@@ -29,12 +29,12 @@ const ResponseGaugeChart = ({ avgResponseTime }) => {
|
||||
? {
|
||||
category: "Acceptable",
|
||||
main: theme.palette.warning.main,
|
||||
bg: theme.palette.warning.dark,
|
||||
bg: theme.palette.warning.lowContrast,
|
||||
}
|
||||
: {
|
||||
category: "Poor",
|
||||
main: theme.palette.error.main,
|
||||
bg: theme.palette.error.light,
|
||||
bg: theme.palette.error.contrastText,
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,19 +4,21 @@ import { ResponsiveContainer, BarChart, XAxis, Bar, Cell } from "recharts";
|
||||
import PropTypes from "prop-types";
|
||||
import CustomLabels from "./CustomLabels";
|
||||
|
||||
const getThemeColor = (responseTime) => {
|
||||
if (responseTime < 200) {
|
||||
return "success";
|
||||
} else if (responseTime < 300) {
|
||||
return "warning";
|
||||
} else {
|
||||
return "error";
|
||||
}
|
||||
};
|
||||
|
||||
const UpBarChart = memo(({ monitor, type, onBarHover }) => {
|
||||
const theme = useTheme();
|
||||
const [chartHovered, setChartHovered] = useState(false);
|
||||
const [hoveredBarIndex, setHoveredBarIndex] = useState(null);
|
||||
|
||||
const getColorRange = (responseTime) => {
|
||||
return responseTime < 200
|
||||
? { main: theme.palette.success.main, light: theme.palette.success.light }
|
||||
: responseTime < 300
|
||||
? { main: theme.palette.warning.main, light: theme.palette.warning.light }
|
||||
: { main: theme.palette.error.main, light: theme.palette.error.light };
|
||||
};
|
||||
|
||||
return (
|
||||
<ResponsiveContainer
|
||||
width="100%"
|
||||
@@ -38,7 +40,7 @@ const UpBarChart = memo(({ monitor, type, onBarHover }) => {
|
||||
}}
|
||||
>
|
||||
<XAxis
|
||||
stroke={theme.palette.border.dark}
|
||||
stroke={theme.palette.primary.lowContrast}
|
||||
height={15}
|
||||
tick={false}
|
||||
label={
|
||||
@@ -59,11 +61,17 @@ const UpBarChart = memo(({ monitor, type, onBarHover }) => {
|
||||
background={{ fill: "transparent" }}
|
||||
>
|
||||
{monitor.groupedUpChecks.map((entry, index) => {
|
||||
let { main, light } = getColorRange(entry.avgResponseTime);
|
||||
const themeColor = getThemeColor(entry.avgResponseTime);
|
||||
return (
|
||||
<Cell
|
||||
key={`cell-${entry.time}`}
|
||||
fill={hoveredBarIndex === index ? main : chartHovered ? light : main}
|
||||
fill={
|
||||
hoveredBarIndex === index
|
||||
? theme.palette[themeColor].main
|
||||
: chartHovered
|
||||
? theme.palette[themeColor].light // CAIO_REVIEW
|
||||
: theme.palette[themeColor].main
|
||||
}
|
||||
onMouseEnter={() => {
|
||||
setHoveredBarIndex(index);
|
||||
onBarHover(entry);
|
||||
|
||||
@@ -19,8 +19,9 @@ import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded";
|
||||
import ArrowForwardRoundedIcon from "@mui/icons-material/ArrowForwardRounded";
|
||||
import { logger } from "../../../../Utils/Logger";
|
||||
import { formatDateWithTz } from "../../../../Utils/timeUtils";
|
||||
|
||||
import { useTheme } from "@emotion/react";
|
||||
const PaginationTable = ({ monitorId, dateRange }) => {
|
||||
const theme = useTheme();
|
||||
const { authToken } = useSelector((state) => state.auth);
|
||||
const [checks, setChecks] = useState([]);
|
||||
const [checksCount, setChecksCount] = useState(0);
|
||||
@@ -96,7 +97,23 @@ const PaginationTable = ({ monitorId, dateRange }) => {
|
||||
return (
|
||||
<>
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<Table
|
||||
sx={{
|
||||
"&.MuiTable-root :is(.MuiTableHead-root, .MuiTableBody-root) :is(th, td)": {
|
||||
paddingLeft: theme.spacing(8),
|
||||
},
|
||||
"& :is(th)": {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
color: theme.palette.secondary.contrastText,
|
||||
fontWeight: 600,
|
||||
fontSize: "12px",
|
||||
},
|
||||
"& :is(td)": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Status</TableCell>
|
||||
|
||||
@@ -33,7 +33,7 @@ import ResponseGaugeChart from "./Charts/ResponseGaugeChart";
|
||||
*/
|
||||
const DetailsPage = () => {
|
||||
const theme = useTheme();
|
||||
const { statusColor, statusStyles, statusMsg, determineState } = useUtils();
|
||||
const { statusColor, statusMsg, determineState } = useUtils();
|
||||
const isAdmin = useIsAdmin();
|
||||
const [monitor, setMonitor] = useState({});
|
||||
const { monitorId } = useParams();
|
||||
@@ -136,6 +136,7 @@ const DetailsPage = () => {
|
||||
height="fit-content"
|
||||
gap={theme.spacing(2)}
|
||||
>
|
||||
{/* TODO there is a tooltip at BarChart component. Wrap the Tooltip on our own component */}
|
||||
<Tooltip
|
||||
title={statusMsg[determineState(monitor)]}
|
||||
disableInteractive
|
||||
@@ -149,6 +150,21 @@ const DetailsPage = () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
sx: {
|
||||
"& .MuiTooltip-tooltip": {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
color: theme.palette.secondary.contrastText,
|
||||
px: theme.spacing(4),
|
||||
py: theme.spacing(3),
|
||||
border: 1,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
boxShadow: theme.shape.boxShadow,
|
||||
/* TODO Font size should point to theme */
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -174,7 +190,7 @@ const DetailsPage = () => {
|
||||
width: 4,
|
||||
height: 4,
|
||||
borderRadius: "50%",
|
||||
backgroundColor: theme.palette.text.tertiary,
|
||||
backgroundColor: theme.palette.primary.contrastTextTertiary,
|
||||
opacity: 0.8,
|
||||
left: -9,
|
||||
top: "50%",
|
||||
@@ -204,7 +220,8 @@ const DetailsPage = () => {
|
||||
"& svg": {
|
||||
mr: theme.spacing(3),
|
||||
"& path": {
|
||||
stroke: theme.palette.text.tertiary,
|
||||
/* Should always be contrastText for the button color */
|
||||
stroke: theme.palette.secondary.contrastText,
|
||||
},
|
||||
},
|
||||
}}
|
||||
@@ -219,7 +236,10 @@ const DetailsPage = () => {
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<StatBox
|
||||
sx={statusStyles[determineState(monitor)]}
|
||||
/* sx={getStatusStyles(determineState(monitor))} */
|
||||
/* statusStyles[determineState(monitor)] */
|
||||
gradient={true}
|
||||
status={determineState(monitor)}
|
||||
heading={"active for"}
|
||||
subHeading={splitDuration(monitor?.uptimeStreak)}
|
||||
/>
|
||||
@@ -242,7 +262,7 @@ const DetailsPage = () => {
|
||||
<Typography
|
||||
component="span"
|
||||
fontSize={13}
|
||||
color={theme.palette.text.primary}
|
||||
color={theme.palette.primary.contrastText}
|
||||
>
|
||||
{certificateExpiry}
|
||||
</Typography>
|
||||
@@ -318,7 +338,7 @@ const DetailsPage = () => {
|
||||
position="absolute"
|
||||
top="100%"
|
||||
fontSize={11}
|
||||
color={theme.palette.text.tertiary}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
{formatDateWithTz(
|
||||
hoveredUptimeData._id,
|
||||
@@ -377,7 +397,7 @@ const DetailsPage = () => {
|
||||
position="absolute"
|
||||
top="100%"
|
||||
fontSize={11}
|
||||
color={theme.palette.text.tertiary}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
{formatDateWithTz(
|
||||
hoveredIncidentsData._id,
|
||||
@@ -431,7 +451,7 @@ const DetailsPage = () => {
|
||||
</IconBox>
|
||||
<Typography
|
||||
component="h2"
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
History
|
||||
</Typography>
|
||||
|
||||
@@ -8,20 +8,20 @@ export const ChartBox = styled(Stack)(({ theme }) => ({
|
||||
padding: theme.spacing(8),
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: 4,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
"& h2": {
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
fontSize: 15,
|
||||
fontWeight: 500,
|
||||
},
|
||||
"& .MuiBox-root:not(.area-tooltip) p": {
|
||||
color: theme.palette.text.tertiary,
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 13,
|
||||
},
|
||||
"& .MuiBox-root > span": {
|
||||
color: theme.palette.text.primary,
|
||||
color: theme.palette.primary.contrastText,
|
||||
fontSize: 20,
|
||||
"& span": {
|
||||
opacity: 0.8,
|
||||
@@ -37,7 +37,7 @@ export const ChartBox = styled(Stack)(({ theme }) => ({
|
||||
alignItems: "center",
|
||||
},
|
||||
"& tspan, & text": {
|
||||
fill: theme.palette.text.tertiary,
|
||||
fill: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
"& path": {
|
||||
transition: "fill 300ms ease, stroke-width 400ms ease",
|
||||
|
||||
@@ -12,27 +12,27 @@ const StatusBox = ({ title, value }) => {
|
||||
position: "absolute",
|
||||
right: 8,
|
||||
opacity: 0.5,
|
||||
"& svg path": { stroke: theme.palette.other.icon },
|
||||
"& svg path": { stroke: theme.palette.primary.contrastTextTertiary },
|
||||
};
|
||||
|
||||
let color;
|
||||
let icon;
|
||||
if (title === "up") {
|
||||
color = theme.palette.success.main;
|
||||
color = theme.palette.success.lowContrast;
|
||||
icon = (
|
||||
<Box sx={{ ...sharedStyles, top: 8 }}>
|
||||
<Arrow />
|
||||
</Box>
|
||||
);
|
||||
} else if (title === "down") {
|
||||
color = theme.palette.error.main;
|
||||
color = theme.palette.error.lowContrast;
|
||||
icon = (
|
||||
<Box sx={{ ...sharedStyles, transform: "rotate(180deg)", top: 5 }}>
|
||||
<Arrow />
|
||||
</Box>
|
||||
);
|
||||
} else if (title === "paused") {
|
||||
color = theme.palette.warning.main;
|
||||
color = theme.palette.warning.lowContrast;
|
||||
icon = (
|
||||
<Box sx={{ ...sharedStyles, top: 12, right: 12 }}>
|
||||
<ClockSnooze />
|
||||
@@ -45,16 +45,11 @@ const StatusBox = ({ title, value }) => {
|
||||
position="relative"
|
||||
flex={1}
|
||||
border={1}
|
||||
borderColor={theme.palette.border.light}
|
||||
backgroundColor={theme.palette.primary.main}
|
||||
borderColor={theme.palette.primary.lowContrast}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
backgroundColor={theme.palette.background.main}
|
||||
p={theme.spacing(8)}
|
||||
overflow="hidden"
|
||||
sx={{
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
@@ -63,7 +58,7 @@ const StatusBox = ({ title, value }) => {
|
||||
left: "5%",
|
||||
pointerEvents: "none",
|
||||
"& svg g g:last-of-type path": {
|
||||
stroke: theme.palette.other.grid,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -73,9 +68,8 @@ const StatusBox = ({ title, value }) => {
|
||||
textTransform="uppercase"
|
||||
fontSize={15}
|
||||
letterSpacing={0.5}
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
mb={theme.spacing(8)}
|
||||
sx={{ opacity: 0.6 }}
|
||||
>
|
||||
{title}
|
||||
</Box>
|
||||
@@ -89,11 +83,12 @@ const StatusBox = ({ title, value }) => {
|
||||
gap="2px"
|
||||
>
|
||||
{value}
|
||||
|
||||
<Typography
|
||||
component="span"
|
||||
fontSize={20}
|
||||
fontWeight={300}
|
||||
color={theme.palette.text.secondary}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
sx={{ opacity: 0.3 }}
|
||||
>
|
||||
#
|
||||
|
||||
@@ -156,7 +156,7 @@ const UptimeDataTable = ({
|
||||
direction="row"
|
||||
gap={theme.spacing(4)}
|
||||
alignItems="center"
|
||||
width="max-content"
|
||||
display={"inline-flex"}
|
||||
onClick={() => handleSort("status")}
|
||||
>
|
||||
{" "}
|
||||
@@ -168,9 +168,9 @@ const UptimeDataTable = ({
|
||||
}}
|
||||
>
|
||||
{sort.order === "asc" ? (
|
||||
<ArrowUpwardRoundedIcon />
|
||||
<ArrowUpwardRoundedIcon fontSize="18px" />
|
||||
) : (
|
||||
<ArrowDownwardRoundedIcon />
|
||||
<ArrowDownwardRoundedIcon fontSize="18px" />
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
@@ -222,15 +222,22 @@ const UptimeDataTable = ({
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
mb={theme.spacing(8)}
|
||||
gap={theme.spacing(2)}
|
||||
>
|
||||
<Heading component="h2">Uptime monitors</Heading>
|
||||
|
||||
{/* TODO Same as the one in Infrastructure. Create component */}
|
||||
<Box
|
||||
className="current-monitors-counter"
|
||||
color={theme.palette.text.primary}
|
||||
border={1}
|
||||
borderColor={theme.palette.border.light}
|
||||
backgroundColor={theme.palette.background.accent}
|
||||
component="span"
|
||||
color={theme.palette.tertiary.contrastText}
|
||||
border={2}
|
||||
borderColor={theme.palette.accent.main}
|
||||
backgroundColor={theme.palette.tertiary.main}
|
||||
sx={{
|
||||
padding: ".25em .75em",
|
||||
borderRadius: "50%",
|
||||
fontSize: "12px",
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
{monitorCount}
|
||||
</Box>
|
||||
@@ -250,7 +257,7 @@ const UptimeDataTable = ({
|
||||
height="100%"
|
||||
position="absolute"
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.main,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
opacity: 0.8,
|
||||
zIndex: 100,
|
||||
}}
|
||||
@@ -267,7 +274,7 @@ const UptimeDataTable = ({
|
||||
>
|
||||
<CircularProgress
|
||||
sx={{
|
||||
color: theme.palette.other.icon,
|
||||
color: theme.palette.accent.main,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
@@ -279,8 +286,9 @@ const UptimeDataTable = ({
|
||||
config={{
|
||||
rowSX: {
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
"&:hover td": {
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
transition: "background-color .3s ease",
|
||||
},
|
||||
},
|
||||
onRowClick: (row) => {
|
||||
|
||||
@@ -95,7 +95,7 @@ const ActionsMenu = ({
|
||||
outline: "none",
|
||||
},
|
||||
"& svg path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
stroke: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -111,11 +111,16 @@ const ActionsMenu = ({
|
||||
slotProps={{
|
||||
paper: {
|
||||
sx: {
|
||||
"& ul": { p: theme.spacing(2.5) },
|
||||
"& li": { m: 0 },
|
||||
"& ul": {
|
||||
p: theme.spacing(2.5),
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
"& li": { m: 0, color: theme.palette.primary.contrastTextSecondary },
|
||||
/*
|
||||
This should not be set automatically on the last of type
|
||||
"& li:last-of-type": {
|
||||
color: theme.palette.error.main,
|
||||
},
|
||||
}, */
|
||||
},
|
||||
},
|
||||
}}
|
||||
@@ -189,6 +194,7 @@ const ActionsMenu = ({
|
||||
e.stopPropagation();
|
||||
openRemove(e);
|
||||
}}
|
||||
sx={{ "&.MuiButtonBase-root": { color: theme.palette.error.main } }}
|
||||
>
|
||||
Remove
|
||||
</MenuItem>
|
||||
|
||||
@@ -14,14 +14,14 @@ const Fallback = ({ isAdmin }) => {
|
||||
return (
|
||||
<Stack
|
||||
alignItems="center"
|
||||
backgroundColor={theme.palette.background.main}
|
||||
backgroundColor={theme.palette.primary.main}
|
||||
p={theme.spacing(30)}
|
||||
pt={theme.spacing(25)}
|
||||
gap={theme.spacing(2)}
|
||||
border={1}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
borderColor={theme.palette.border.light}
|
||||
color={theme.palette.text.secondary}
|
||||
borderColor={theme.palette.primary.lowContrast}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
<Box pb={theme.spacing(20)}>
|
||||
{mode === "light" ? <PlaceholderLight /> : <PlaceholderDark />}
|
||||
@@ -39,7 +39,7 @@ const Fallback = ({ isAdmin }) => {
|
||||
{isAdmin && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
color="accent"
|
||||
onClick={() => {
|
||||
navigate("/uptime/create");
|
||||
}}
|
||||
|
||||
@@ -42,6 +42,7 @@ const Host = ({ url, title, percentageColor, percentage }) => {
|
||||
sx={{
|
||||
color: percentageColor,
|
||||
fontWeight: 500,
|
||||
/* TODO point font weight to theme */
|
||||
ml: "15px",
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -4,17 +4,3 @@
|
||||
height: var(--env-var-height-2);
|
||||
min-width: fit-content;
|
||||
}
|
||||
|
||||
.current-monitors-counter {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
min-width: 25px;
|
||||
min-height: 25px;
|
||||
border-radius: 50%;
|
||||
font-size: var(--env-var-font-size-medium);
|
||||
font-weight: 500;
|
||||
margin-left: 10px;
|
||||
line-height: 0.8;
|
||||
}
|
||||
@@ -41,6 +41,7 @@ const UptimeMonitors = () => {
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
const isAdmin = useIsAdmin();
|
||||
|
||||
const authState = useSelector((state) => state.auth);
|
||||
|
||||
const fetchParams = useMemo(
|
||||
@@ -57,7 +58,7 @@ const UptimeMonitors = () => {
|
||||
|
||||
const getMonitorWithPercentage = useCallback((monitor, theme) => {
|
||||
let uptimePercentage = "";
|
||||
let percentageColor = theme.palette.percentage.uptimeExcellent;
|
||||
let percentageColor = "";
|
||||
|
||||
if (monitor.uptimePercentage !== undefined) {
|
||||
uptimePercentage =
|
||||
@@ -67,12 +68,12 @@ const UptimeMonitors = () => {
|
||||
|
||||
percentageColor =
|
||||
monitor.uptimePercentage < 0.25
|
||||
? theme.palette.percentage.uptimePoor
|
||||
? theme.palette.error.main
|
||||
: monitor.uptimePercentage < 0.5
|
||||
? theme.palette.percentage.uptimeFair
|
||||
? theme.palette.warning.main
|
||||
: monitor.uptimePercentage < 0.75
|
||||
? theme.palette.percentage.uptimeGood
|
||||
: theme.palette.percentage.uptimeExcellent;
|
||||
? theme.palette.success.main
|
||||
: theme.palette.success.main;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -158,16 +159,26 @@ const UptimeMonitors = () => {
|
||||
gap={theme.spacing(6)}
|
||||
>
|
||||
{canAddMonitor && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
navigate("/uptime/create");
|
||||
}}
|
||||
sx={{ fontWeight: 500, whiteSpace: "nowrap" }}
|
||||
>
|
||||
Create new
|
||||
</Button>
|
||||
<>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="accent"
|
||||
onClick={() => {
|
||||
navigate("/uptime/create");
|
||||
}}
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
whiteSpace: "nowrap",
|
||||
/* TODO IMPORTANT this should be applied to all buttons */
|
||||
"&:focus-visible": {
|
||||
outline: `2px solid ${theme.palette.primary.contrastText}`,
|
||||
outlineOffset: 4,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Create new
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
<Greeting type="uptime" />
|
||||
|
||||
Loaded 100 of 108 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user