mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-01-01 07:09:43 -06:00
Merge pull request #3088 from bluewave-labs/fix-traslator-error
fix translator error and add format
This commit is contained in:
@@ -7,81 +7,84 @@ import { useTranslation } from "react-i18next";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const DiskSelection = ({ availableDisks, selectedDisks, onChange }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleDiskChange = (event, mountpoint) => {
|
||||
const isChecked = event.target.checked;
|
||||
let newSelectedDisks = [];
|
||||
const handleDiskChange = (event, mountpoint) => {
|
||||
const isChecked = event.target.checked;
|
||||
let newSelectedDisks = [];
|
||||
|
||||
if (isChecked) {
|
||||
newSelectedDisks = [...selectedDisks, mountpoint];
|
||||
} else {
|
||||
newSelectedDisks = selectedDisks.filter((disk) => disk !== mountpoint);
|
||||
}
|
||||
if (isChecked) {
|
||||
newSelectedDisks = [...selectedDisks, mountpoint];
|
||||
} else {
|
||||
newSelectedDisks = selectedDisks.filter((disk) => disk !== mountpoint);
|
||||
}
|
||||
|
||||
onChange(newSelectedDisks);
|
||||
};
|
||||
onChange(newSelectedDisks);
|
||||
};
|
||||
|
||||
return (
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2" variant="h2">
|
||||
{t("v1.infrastructure.disk_selection_title")}
|
||||
</Typography>
|
||||
<Typography component="p">
|
||||
{t("v1.infrastructure.disk_selection_description")}
|
||||
</Typography>
|
||||
</Box>
|
||||
return (
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography
|
||||
component="h2"
|
||||
variant="h2"
|
||||
>
|
||||
{t("v1.infrastructure.disk_selection_title")}
|
||||
</Typography>
|
||||
<Typography component="p">
|
||||
{t("v1.infrastructure.disk_selection_description")}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
{(!availableDisks || availableDisks.length === 0) ? (
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ fontStyle: 'italic', opacity: 0.8 }}
|
||||
>
|
||||
{t("v1.infrastructure.disk_selection_info")}
|
||||
</Typography>
|
||||
) : (
|
||||
availableDisks.map((disk) => {
|
||||
const identifier = disk.mountpoint || disk.device;
|
||||
return (
|
||||
<Stack
|
||||
key={identifier}
|
||||
direction={{ sm: "column", md: "row" }}
|
||||
spacing={theme.spacing(2)}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
justifyContent="flex-start"
|
||||
>
|
||||
<Checkbox
|
||||
id={`disk-${identifier}`}
|
||||
name={identifier}
|
||||
label={identifier}
|
||||
isChecked={selectedDisks.includes(identifier)}
|
||||
onChange={(e) => handleDiskChange(e, identifier)}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</Stack>
|
||||
</ConfigBox>
|
||||
);
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
{!availableDisks || availableDisks.length === 0 ? (
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ fontStyle: "italic", opacity: 0.8 }}
|
||||
>
|
||||
{t("v1.infrastructure.disk_selection_info")}
|
||||
</Typography>
|
||||
) : (
|
||||
availableDisks.map((disk) => {
|
||||
const identifier = disk.mountpoint || disk.device;
|
||||
return (
|
||||
<Stack
|
||||
key={identifier}
|
||||
direction={{ sm: "column", md: "row" }}
|
||||
spacing={theme.spacing(2)}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
justifyContent="flex-start"
|
||||
>
|
||||
<Checkbox
|
||||
id={`disk-${identifier}`}
|
||||
name={identifier}
|
||||
label={identifier}
|
||||
isChecked={selectedDisks.includes(identifier)}
|
||||
onChange={(e) => handleDiskChange(e, identifier)}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</Stack>
|
||||
</ConfigBox>
|
||||
);
|
||||
};
|
||||
|
||||
DiskSelection.propTypes = {
|
||||
availableDisks: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
mountpoint: PropTypes.string.isRequired,
|
||||
})
|
||||
),
|
||||
selectedDisks: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
availableDisks: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
mountpoint: PropTypes.string.isRequired,
|
||||
})
|
||||
),
|
||||
selectedDisks: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default DiskSelection;
|
||||
export default DiskSelection;
|
||||
|
||||
@@ -75,9 +75,9 @@ const CreateInfrastructureMonitor = () => {
|
||||
...(isCreate
|
||||
? [{ name: "Create", path: "/infrastructure/create" }]
|
||||
: [
|
||||
{ name: "Details", path: `/infrastructure/${monitorId}` },
|
||||
{ name: "Configure", path: `/infrastructure/configure/${monitorId}` },
|
||||
]),
|
||||
{ name: "Details", path: `/infrastructure/${monitorId}` },
|
||||
{ name: "Configure", path: `/infrastructure/configure/${monitorId}` },
|
||||
]),
|
||||
];
|
||||
// Populate form fields if editing
|
||||
useEffect(() => {
|
||||
@@ -161,8 +161,6 @@ const CreateInfrastructureMonitor = () => {
|
||||
isPausing ||
|
||||
notificationsAreLoading;
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Box className="create-infrastructure-monitor">
|
||||
<Breadcrumbs list={CRUMBS} />
|
||||
|
||||
@@ -6,8 +6,18 @@ import { Stack, Typography, Box } from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const Gauge = ({ value, heading, metricOne, valueOne, metricTwo, valueTwo,
|
||||
metricThree, valueThree, metricFour, valueFour }) => {
|
||||
const Gauge = ({
|
||||
value,
|
||||
heading,
|
||||
metricOne,
|
||||
valueOne,
|
||||
metricTwo,
|
||||
valueTwo,
|
||||
metricThree,
|
||||
valueThree,
|
||||
metricFour,
|
||||
valueFour,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const valueStyle = {
|
||||
|
||||
@@ -10,7 +10,8 @@ import { useTheme } from "@emotion/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const Gauges = ({ isLoading = false, monitor }) => {
|
||||
const { decimalToPercentage, formatBytes, formatDeviceName, formatMountpoint } = useHardwareUtils();
|
||||
const { decimalToPercentage, formatBytes, formatDeviceName, formatMountpoint } =
|
||||
useHardwareUtils();
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
@@ -121,28 +121,32 @@ const useHardwareUtils = () => {
|
||||
};
|
||||
|
||||
const formatDeviceName = (device) => {
|
||||
const deviceStr = String(device || '');
|
||||
|
||||
const deviceStr = String(device || "");
|
||||
|
||||
// Extract the last part of the path (after last '/')
|
||||
const parts = deviceStr.split('/');
|
||||
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
|
||||
return (
|
||||
<Tooltip title={deviceStr} arrow placement="top">
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
cursor: 'default',
|
||||
display: 'inline-block',
|
||||
userSelect: 'none',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
maxWidth: '100%'
|
||||
<Tooltip
|
||||
title={deviceStr}
|
||||
arrow
|
||||
placement="top"
|
||||
>
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
cursor: "default",
|
||||
display: "inline-block",
|
||||
userSelect: "none",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
maxWidth: "100%",
|
||||
}}
|
||||
>
|
||||
{displayText}
|
||||
@@ -152,19 +156,23 @@ const useHardwareUtils = () => {
|
||||
};
|
||||
|
||||
const formatMountpoint = (mountpoint) => {
|
||||
const mountpointStr = String(mountpoint || '');
|
||||
|
||||
const mountpointStr = String(mountpoint || "");
|
||||
|
||||
if (!mountpointStr) {
|
||||
return (
|
||||
<Tooltip title="No mountpoint available" arrow placement="top">
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
cursor: 'default',
|
||||
display: 'inline-block',
|
||||
userSelect: 'none',
|
||||
color: 'text.secondary',
|
||||
fontStyle: 'italic'
|
||||
<Tooltip
|
||||
title="No mountpoint available"
|
||||
arrow
|
||||
placement="top"
|
||||
>
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
cursor: "default",
|
||||
display: "inline-block",
|
||||
userSelect: "none",
|
||||
color: "text.secondary",
|
||||
fontStyle: "italic",
|
||||
}}
|
||||
>
|
||||
N/A
|
||||
@@ -172,34 +180,38 @@ const useHardwareUtils = () => {
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Extract the last part of the path (after last '/')
|
||||
const parts = mountpointStr.split('/');
|
||||
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
|
||||
return (
|
||||
<Tooltip title={mountpointStr} arrow placement="top">
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
cursor: 'default',
|
||||
display: 'inline-block',
|
||||
userSelect: 'none',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
maxWidth: '100%'
|
||||
<Tooltip
|
||||
title={mountpointStr}
|
||||
arrow
|
||||
placement="top"
|
||||
>
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
cursor: "default",
|
||||
display: "inline-block",
|
||||
userSelect: "none",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
maxWidth: "100%",
|
||||
}}
|
||||
>
|
||||
{displayText}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a decimal value to a percentage
|
||||
|
||||
@@ -144,44 +144,44 @@ const monitorValidation = joi.object({
|
||||
// Regex from https://gist.github.com/dperini/729294
|
||||
var urlRegex = new RegExp(
|
||||
"^" +
|
||||
// protocol identifier (optional)
|
||||
// short syntax // still required
|
||||
"(?:(?:https?|ftp):\\/\\/)?" +
|
||||
// user:pass BasicAuth (optional)
|
||||
"(?:" +
|
||||
// IP address dotted notation octets
|
||||
// excludes loopback network 0.0.0.0
|
||||
// excludes reserved space >= 224.0.0.0
|
||||
// excludes network & broadcast addresses
|
||||
// (first & last IP address of each class)
|
||||
"(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
|
||||
"(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
|
||||
"(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
|
||||
"|" +
|
||||
// host & domain names, may end with dot
|
||||
// can be replaced by a shortest alternative
|
||||
// (?![-_])(?:[-\\w\\u00a1-\\uffff]{0,63}[^-_]\\.)+
|
||||
"(?:" +
|
||||
// Single hostname without dots (like localhost)
|
||||
"[a-z0-9\\u00a1-\\uffff][a-z0-9\\u00a1-\\uffff_-]{0,62}" +
|
||||
"|" +
|
||||
// Domain with dots
|
||||
"(?:" +
|
||||
"(?:" +
|
||||
"[a-z0-9\\u00a1-\\uffff]" +
|
||||
"[a-z0-9\\u00a1-\\uffff_-]{0,62}" +
|
||||
")?" +
|
||||
"[a-z0-9\\u00a1-\\uffff]\\." +
|
||||
")+" +
|
||||
// TLD identifier name, may end with dot
|
||||
"(?:[a-z\\u00a1-\\uffff]{2,}\\.?)" +
|
||||
")" +
|
||||
")" +
|
||||
// port number (optional)
|
||||
"(?::\\d{2,5})?" +
|
||||
// resource path (optional)
|
||||
"(?:[/?#]\\S*)?" +
|
||||
"$",
|
||||
// protocol identifier (optional)
|
||||
// short syntax // still required
|
||||
"(?:(?:https?|ftp):\\/\\/)?" +
|
||||
// user:pass BasicAuth (optional)
|
||||
"(?:" +
|
||||
// IP address dotted notation octets
|
||||
// excludes loopback network 0.0.0.0
|
||||
// excludes reserved space >= 224.0.0.0
|
||||
// excludes network & broadcast addresses
|
||||
// (first & last IP address of each class)
|
||||
"(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
|
||||
"(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
|
||||
"(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
|
||||
"|" +
|
||||
// host & domain names, may end with dot
|
||||
// can be replaced by a shortest alternative
|
||||
// (?![-_])(?:[-\\w\\u00a1-\\uffff]{0,63}[^-_]\\.)+
|
||||
"(?:" +
|
||||
// Single hostname without dots (like localhost)
|
||||
"[a-z0-9\\u00a1-\\uffff][a-z0-9\\u00a1-\\uffff_-]{0,62}" +
|
||||
"|" +
|
||||
// Domain with dots
|
||||
"(?:" +
|
||||
"(?:" +
|
||||
"[a-z0-9\\u00a1-\\uffff]" +
|
||||
"[a-z0-9\\u00a1-\\uffff_-]{0,62}" +
|
||||
")?" +
|
||||
"[a-z0-9\\u00a1-\\uffff]\\." +
|
||||
")+" +
|
||||
// TLD identifier name, may end with dot
|
||||
"(?:[a-z\\u00a1-\\uffff]{2,}\\.?)" +
|
||||
")" +
|
||||
")" +
|
||||
// port number (optional)
|
||||
"(?::\\d{2,5})?" +
|
||||
// resource path (optional)
|
||||
"(?:[/?#]\\S*)?" +
|
||||
"$",
|
||||
"i"
|
||||
);
|
||||
if (!urlRegex.test(value)) {
|
||||
|
||||
@@ -1144,10 +1144,11 @@
|
||||
"selectInterface": "Select Interface",
|
||||
"v1": {
|
||||
"infrastructure": {
|
||||
"disk_selection_title": "Disk Selection",
|
||||
"disk_selection_info": "No disk detected for the moment.",
|
||||
"disk_selection_description": "Select the specific disks you want to monitor."
|
||||
"disk_selection_title": "Disk Selection",
|
||||
"disk_selection_info": "No disk detected for the moment.",
|
||||
"disk_selection_description": "Select the specific disks you want to monitor."
|
||||
}
|
||||
},
|
||||
"incidentsPage": {
|
||||
"title": "Incidents",
|
||||
"description": "Manage incidents for your monitors. You can resolve incidents here.",
|
||||
|
||||
@@ -12,8 +12,8 @@ export default defineConfig(({}) => {
|
||||
return {
|
||||
base: "/",
|
||||
plugins: [svgr(), react()],
|
||||
server: {
|
||||
host: true,
|
||||
server: {
|
||||
host: true,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
Reference in New Issue
Block a user