mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-18 23:48:43 -05:00
Merge branch 'develop' into fix/incidents
This commit is contained in:
@@ -14,15 +14,7 @@
|
||||
}
|
||||
} */
|
||||
|
||||
/* .home-layout aside {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
max-width: var(--env-var-side-bar-width);
|
||||
} */
|
||||
|
||||
.home-layout > div {
|
||||
.home-layout > .home-content-wrapper {
|
||||
min-height: calc(100vh - var(--env-var-spacing-2) * 2);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
import Sidebar from "../../Sidebar/index.jsx";
|
||||
import { Outlet } from "react-router";
|
||||
import { Stack } from "@mui/material";
|
||||
import { Box, Stack } from "@mui/material";
|
||||
import { useSidebar } from "@/Hooks/useSidebar.js";
|
||||
|
||||
import "./index.css";
|
||||
|
||||
const HomeLayout = () => {
|
||||
const { width, transition } = useSidebar();
|
||||
|
||||
return (
|
||||
<Stack
|
||||
className="home-layout"
|
||||
flexDirection="row"
|
||||
gap={14}
|
||||
>
|
||||
<Sidebar />
|
||||
{/* Spacer for fixed sidebar */}
|
||||
<Box
|
||||
sx={{
|
||||
width,
|
||||
flexShrink: 0,
|
||||
transition,
|
||||
}}
|
||||
/>
|
||||
<Stack className="home-content-wrapper">
|
||||
<Outlet />
|
||||
</Stack>
|
||||
|
||||
@@ -12,9 +12,9 @@ import Icon from "../Icon";
|
||||
|
||||
// Utils
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router";
|
||||
import { useSidebar } from "@/Hooks/useSidebar.js";
|
||||
|
||||
const URL_MAP = {
|
||||
support: "https://discord.com/invite/NAb6H3UTjK",
|
||||
@@ -65,8 +65,7 @@ const Sidebar = () => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
// Redux state
|
||||
const collapsed = useSelector((state) => state.ui.sidebar?.collapsed ?? false);
|
||||
const { collapsed, width, transition } = useSidebar();
|
||||
|
||||
const menu = getMenu(t);
|
||||
const otherMenuItems = getOtherMenuItems(t);
|
||||
@@ -75,20 +74,19 @@ const Sidebar = () => {
|
||||
return (
|
||||
<Stack
|
||||
height="100vh"
|
||||
width={
|
||||
collapsed
|
||||
? "var(--env-var-side-bar-collapsed-width)"
|
||||
: "var(--env-var-side-bar-width)"
|
||||
}
|
||||
width={width}
|
||||
component="aside"
|
||||
position="sticky"
|
||||
position="fixed"
|
||||
top={0}
|
||||
borderRight={`1px solid ${theme.palette.primary.lowContrast}`}
|
||||
left={0}
|
||||
paddingTop={theme.spacing(6)}
|
||||
paddingBottom={theme.spacing(6)}
|
||||
gap={theme.spacing(6)}
|
||||
sx={{
|
||||
transition: "width 650ms cubic-bezier(0.36, -0.01, 0, 0.77)",
|
||||
transition,
|
||||
backgroundColor: "#000000",
|
||||
borderRight: "1px solid #344054",
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<CollapseButton collapsed={collapsed} />
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
// CSS variable names for sidebar widths
|
||||
const SIDEBAR_WIDTH_VAR = "var(--env-var-side-bar-width)";
|
||||
const SIDEBAR_COLLAPSED_WIDTH_VAR = "var(--env-var-side-bar-collapsed-width)";
|
||||
|
||||
// Transition timing for sidebar width changes
|
||||
const SIDEBAR_TRANSITION = "width 650ms cubic-bezier(0.36, -0.01, 0, 0.77)";
|
||||
|
||||
/**
|
||||
* Hook to get sidebar state and computed width
|
||||
* Centralizes sidebar width logic to avoid duplication between Sidebar and HomeLayout
|
||||
*
|
||||
* @returns {Object} Sidebar state and styles
|
||||
* @returns {boolean} collapsed - Whether the sidebar is collapsed
|
||||
* @returns {string} width - CSS width value based on collapsed state
|
||||
* @returns {string} transition - CSS transition for width changes
|
||||
*/
|
||||
export const useSidebar = () => {
|
||||
const collapsed = useSelector((state) => state.ui.sidebar?.collapsed ?? false);
|
||||
|
||||
return {
|
||||
collapsed,
|
||||
width: collapsed ? SIDEBAR_COLLAPSED_WIDTH_VAR : SIDEBAR_WIDTH_VAR,
|
||||
transition: SIDEBAR_TRANSITION,
|
||||
};
|
||||
};
|
||||
|
||||
export default useSidebar;
|
||||
@@ -129,7 +129,9 @@ const CreateInfrastructureMonitor = () => {
|
||||
const onSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
const form = buildForm(infrastructureMonitor, https);
|
||||
const error = validateForm(form);
|
||||
// When editing, exclude URL from validation since it's disabled and can't be changed
|
||||
const formToValidate = isCreate ? form : { ...form, url: monitor.url };
|
||||
const error = validateForm(formToValidate);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
@@ -205,14 +207,14 @@ const CreateInfrastructureMonitor = () => {
|
||||
<></>
|
||||
)}
|
||||
</Typography>
|
||||
{!isCreate && (
|
||||
{!isCreate && monitor && (
|
||||
<MonitorStatusHeader
|
||||
monitor={monitor}
|
||||
infrastructureMonitor={infrastructureMonitor}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
{!isCreate && (
|
||||
{!isCreate && monitor && (
|
||||
<MonitorActionButtons
|
||||
monitor={monitor}
|
||||
isBusy={isBusy}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useTheme } from "@emotion/react";
|
||||
import { useHardwareUtils } from "../../Hooks/useHardwareUtils.jsx";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const BaseContainer = ({ children, sx = {} }) => {
|
||||
const BaseContainer = ({ children, sx = {}, shouldExpand = false }) => {
|
||||
const theme = useTheme();
|
||||
const { getDimensions } = useHardwareUtils();
|
||||
return (
|
||||
@@ -22,7 +22,7 @@ const BaseContainer = ({ children, sx = {} }) => {
|
||||
sx={{
|
||||
padding: `${theme.spacing(getDimensions().baseBoxPaddingVertical)} ${theme.spacing(getDimensions().baseBoxPaddingHorizontal)}`,
|
||||
minWidth: 200,
|
||||
width: 225,
|
||||
width: shouldExpand ? "100%" : 225,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
@@ -38,6 +38,7 @@ const BaseContainer = ({ children, sx = {} }) => {
|
||||
BaseContainer.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
sx: PropTypes.object,
|
||||
shouldExpand: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default BaseContainer;
|
||||
|
||||
@@ -17,21 +17,26 @@ const Gauge = ({
|
||||
valueThree,
|
||||
metricFour,
|
||||
valueFour,
|
||||
shouldExpand = false,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const valueStyle = {
|
||||
borderRadius: theme.spacing(2),
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
width: "40%",
|
||||
minWidth: "40%",
|
||||
maxWidth: "60%",
|
||||
mb: theme.spacing(2),
|
||||
mt: theme.spacing(2),
|
||||
pr: theme.spacing(2),
|
||||
textAlign: "right",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
};
|
||||
|
||||
return (
|
||||
<BaseContainer>
|
||||
<BaseContainer shouldExpand={shouldExpand}>
|
||||
<Stack
|
||||
direction="column"
|
||||
gap={theme.spacing(2)}
|
||||
@@ -116,6 +121,7 @@ Gauge.propTypes = {
|
||||
valueThree: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||
metricFour: PropTypes.string,
|
||||
valueFour: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||
shouldExpand: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default Gauge;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Components
|
||||
import { Stack } from "@mui/material";
|
||||
import { Box } from "@mui/material";
|
||||
import Gauge from "./Gauge.jsx";
|
||||
import SkeletonLayout from "./skeleton.jsx";
|
||||
import PropTypes from "prop-types";
|
||||
@@ -65,16 +65,23 @@ const Gauges = ({ isLoading = false, monitor }) => {
|
||||
valueTwo: formatBytes(disk.total_bytes, true),
|
||||
metricThree: t("device"),
|
||||
valueThree: formatDeviceName(disk.device),
|
||||
metricFour: t("mountpoint"),
|
||||
metricFour: t("mountedOn"),
|
||||
valueFour: formatMountpoint(disk.mountpoint),
|
||||
})),
|
||||
];
|
||||
|
||||
// Only expand gauges to fill row when there are 4 or more
|
||||
const shouldExpand = gauges.length >= 4;
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
flexWrap="wrap"
|
||||
gap={theme.spacing(8)}
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: shouldExpand
|
||||
? "repeat(auto-fill, minmax(200px, 1fr))"
|
||||
: "repeat(auto-fill, 225px)",
|
||||
gap: theme.spacing(4),
|
||||
}}
|
||||
>
|
||||
{gauges.map((gauge) => {
|
||||
return (
|
||||
@@ -90,10 +97,11 @@ const Gauges = ({ isLoading = false, monitor }) => {
|
||||
valueThree={gauge.valueThree}
|
||||
metricFour={gauge.metricFour}
|
||||
valueFour={gauge.valueFour}
|
||||
shouldExpand={shouldExpand}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -123,14 +123,7 @@ const useHardwareUtils = () => {
|
||||
const formatDeviceName = (device) => {
|
||||
const deviceStr = String(device || "");
|
||||
|
||||
// Extract the last part of the path (after last '/')
|
||||
const parts = deviceStr.split("/");
|
||||
const lastPart = parts[parts.length - 1];
|
||||
|
||||
// If there's more than one part, show with "..." prefix
|
||||
const displayText = parts.length > 1 ? `.../${lastPart}` : deviceStr;
|
||||
|
||||
// Always show tooltip with full device path
|
||||
// Show full device path
|
||||
return (
|
||||
<Tooltip
|
||||
title={deviceStr}
|
||||
@@ -149,7 +142,7 @@ const useHardwareUtils = () => {
|
||||
maxWidth: "100%",
|
||||
}}
|
||||
>
|
||||
{displayText}
|
||||
{deviceStr}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
);
|
||||
@@ -181,14 +174,7 @@ const useHardwareUtils = () => {
|
||||
);
|
||||
}
|
||||
|
||||
// Extract the last part of the path (after last '/')
|
||||
const parts = mountpointStr.split("/");
|
||||
const lastPart = parts[parts.length - 1];
|
||||
|
||||
// If there's more than one part, show with "..." prefix
|
||||
const displayText = parts.length > 1 ? `.../${lastPart}` : mountpointStr;
|
||||
|
||||
// Always show tooltip with full mountpoint path
|
||||
// Show full mountpoint path
|
||||
return (
|
||||
<Tooltip
|
||||
title={mountpointStr}
|
||||
@@ -207,7 +193,7 @@ const useHardwareUtils = () => {
|
||||
maxWidth: "100%",
|
||||
}}
|
||||
>
|
||||
{displayText}
|
||||
{mountpointStr}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
background-color: #000000;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
@@ -193,6 +193,8 @@
|
||||
"total": "Total",
|
||||
"cores": "Cores",
|
||||
"frequency": "Frequency",
|
||||
"device": "Device",
|
||||
"mountedOn": "Mounted on",
|
||||
"status": "Status",
|
||||
"cpuPhysical": "CPU (Physical)",
|
||||
"cpuLogical": "CPU (Logical)",
|
||||
|
||||
Reference in New Issue
Block a user