Merge pull request #3088 from bluewave-labs/fix-traslator-error

fix translator error and add format
This commit is contained in:
Alexander Holliday
2025-12-22 09:41:58 -08:00
committed by GitHub
8 changed files with 187 additions and 162 deletions

View File

@@ -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;

View File

@@ -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} />

View File

@@ -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 = {

View File

@@ -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();

View File

@@ -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

View File

@@ -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)) {

View File

@@ -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.",

View File

@@ -12,8 +12,8 @@ export default defineConfig(({}) => {
return {
base: "/",
plugins: [svgr(), react()],
server: {
host: true,
server: {
host: true,
},
resolve: {
alias: {