diff --git a/client/src/Components/design-elements/BasePage.tsx b/client/src/Components/design-elements/BasePage.tsx index 845d20a4c..c955fb6b7 100644 --- a/client/src/Components/design-elements/BasePage.tsx +++ b/client/src/Components/design-elements/BasePage.tsx @@ -38,9 +38,9 @@ export const PageSpeedKeyPriorityFallback = () => { diff --git a/client/src/Components/design-elements/MonitorStatus.tsx b/client/src/Components/design-elements/MonitorStatus.tsx index dbeb5fa84..14f33d934 100644 --- a/client/src/Components/design-elements/MonitorStatus.tsx +++ b/client/src/Components/design-elements/MonitorStatus.tsx @@ -17,7 +17,7 @@ export const MonitorStatus = ({ monitor }: { monitor: Monitor }) => { return ( = { info: "ⓘ", @@ -25,29 +27,26 @@ export const NoticeBanner = ({ severity = "info", children }: NoticeBannerProps) direction="row" alignItems="flex-start" gap={theme.spacing(LAYOUT.SM)} - sx={{ - width: "100%", - p: theme.spacing(LAYOUT.MD), - borderRadius: 1, - border: `1px solid ${alpha(tone, 0.45)}`, - backgroundColor: alpha(tone, 0.08), - textAlign: "left", - }} + width={"100%"} + p={theme.spacing(LAYOUT.MD)} + borderRadius={theme.shape.borderRadius} + border={`1px solid ${alpha(tone, 0.45)}`} + bgcolor={alpha(tone, 0.08)} + textAlign={"left"} > {SEVERITY_GLYPH[severity]} {children} diff --git a/client/src/Components/inputs/Button.tsx b/client/src/Components/inputs/Button.tsx index 54f776075..4eae654b2 100644 --- a/client/src/Components/inputs/Button.tsx +++ b/client/src/Components/inputs/Button.tsx @@ -1,19 +1,43 @@ import Button from "@mui/material/Button"; import type { ButtonProps } from "@mui/material/Button"; -import { useTheme } from "@mui/material/styles"; +import { useTheme, darken } from "@mui/material/styles"; +import { HOVER } from "@/Utils/Theme/constants"; + +const PALETTE_COLORS = [ + "primary", + "secondary", + "error", + "warning", + "info", + "success", +] as const; +type PaletteColor = (typeof PALETTE_COLORS)[number]; export const ButtonInput = ({ sx, ...props }: ButtonProps) => { const theme = useTheme(); - const outlinedSx = + + const hoverOverrides: Record = { boxShadow: "none" }; + + if (props.variant === "outlined") { + hoverOverrides.borderColor = theme.palette.text.secondary; + } + + if (props.variant === "contained") { + const colorKey = (props.color ?? "primary") as PaletteColor; + const palette = theme.palette[colorKey]; + if (palette && typeof palette === "object" && "main" in palette) { + hoverOverrides.backgroundColor = darken(palette.main, HOVER.DARKEN); + } + } + + const variantSx = props.variant === "outlined" ? { color: theme.palette.text.primary, borderColor: theme.palette.divider, - "&:hover": { - borderColor: theme.palette.text.secondary, - }, } : {}; + return ( } > - + { + const theme = useTheme(); + + return ( + + {children} + + ); +}; + +const Cell = ({ children }: { children: React.ReactNode }) => ( + {children} +); + export const CardDetails = ({ incident, monitor, sx }: CardDetailsProps) => { const { t } = useTranslation(); const theme = useTheme(); @@ -33,22 +52,18 @@ export const CardDetails = ({ incident, monitor, sx }: CardDetailsProps) => { gap={theme.spacing(LAYOUT.MD)} sx={sx} > - - {t("pages.incidents.dialog.details.title")} - + {t("pages.incidents.dialog.details.title")} - - {t("pages.incidents.dialog.details.overview")} - - - + {t("pages.incidents.dialog.details.overview")} - {t("pages.incidents.dialog.details.status")} + + {t("pages.incidents.dialog.details.status")} + { {monitor && ( <> - {t("pages.incidents.dialog.details.monitor")} + + {t("pages.incidents.dialog.details.monitor")} + - {monitor.name ?? "N/A"} + {monitor.name ?? "N/A"} - {t("pages.incidents.dialog.details.url")} + {t("pages.incidents.dialog.details.url")} - {monitor.url ?? "N/A"} + {monitor.url ?? "N/A"} )} @@ -78,51 +95,48 @@ export const CardDetails = ({ incident, monitor, sx }: CardDetailsProps) => { - - {t("pages.incidents.dialog.details.analysis")} - - + {t("pages.incidents.dialog.details.analysis")} - {t("pages.incidents.dialog.details.timeline")} + {t("pages.incidents.dialog.details.timeline")} - {t("pages.incidents.dialog.details.detailsLabel")} + {t("pages.incidents.dialog.details.detailsLabel")} - + - + - {t("pages.incidents.dialog.details.startedAt")} + {t("pages.incidents.dialog.details.startedAt")} - + {formatDateWithTz(incident.startTime, "D MMM YYYY, h:mm A", uiTimezone)} - + - {t("pages.incidents.dialog.details.statusCode")} + {t("pages.incidents.dialog.details.statusCode")} - {incident.statusCode ?? "N/A"} + {incident.statusCode ?? "N/A"} - {t("pages.incidents.dialog.details.downtime")} + {t("pages.incidents.dialog.details.downtime")} - {getIncidentsDuration(incident)} + {getIncidentsDuration(incident)} - {t("pages.incidents.dialog.details.message")} + {t("pages.incidents.dialog.details.message")} - {incident.message ?? "N/A"} + {incident.message ?? "N/A"} @@ -130,60 +144,53 @@ export const CardDetails = ({ incident, monitor, sx }: CardDetailsProps) => { {!incident.status && ( - + {t("pages.incidents.dialog.details.resolutionDetails")} - - + - {t("pages.incidents.dialog.details.resolvedAt")} + {t("pages.incidents.dialog.details.resolvedAt")} - + {incident.endTime ? formatDateWithTz(incident.endTime, "D MMM YYYY, h:mm A", uiTimezone) : "N/A"} - + - - {t("pages.incidents.dialog.details.resolutionType")} - + {t("pages.incidents.dialog.details.resolutionType")} - + {incident.resolutionType ? t( `pages.incidents.dialog.details.resolutionTypes.${incident.resolutionType}` ) : "N/A"} - + {incident.resolvedBy && ( <> - - {t("pages.incidents.dialog.details.resolvedBy")} - + {t("pages.incidents.dialog.details.resolvedBy")} - - {incident.resolvedByEmail ?? incident.resolvedBy} - + {incident.resolvedByEmail ?? incident.resolvedBy} )} {incident.comment && ( <> - {t("pages.incidents.dialog.details.comment")} + {t("pages.incidents.dialog.details.comment")} - {incident.comment} + {incident.comment} )} diff --git a/client/src/Pages/Incidents/Components/CardSummary.tsx b/client/src/Pages/Incidents/Components/CardSummary.tsx index 938455808..60dadaa74 100644 --- a/client/src/Pages/Incidents/Components/CardSummary.tsx +++ b/client/src/Pages/Incidents/Components/CardSummary.tsx @@ -1,8 +1,7 @@ import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; -import Divider from "@mui/material/Divider"; import Grid from "@mui/material/Grid"; -import { BaseBox, ValueLabel } from "@/Components/design-elements"; +import { BaseBox, Icon, ValueLabel } from "@/Components/design-elements"; import { CircleCheck, TriangleAlert, Bell, Wrench, Globe } from "lucide-react"; import Box from "@mui/material/Box"; @@ -25,6 +24,7 @@ const SummaryItem = ({ icon, label, value }: SummaryItemProps) => { alignItems="center" justifyContent="space-between" gap={theme.spacing(2)} + minHeight={32} > { gap={theme.spacing(2)} > {icon} - {label} + {label} {value} @@ -67,15 +67,11 @@ export const SummaryCard = ({ > {title} - {children} @@ -97,10 +93,13 @@ export const SummaryCardActiveIncidents = ({ const activeCount = summary.totalActive; const hasActive = activeCount > 0; const color = hasActive ? theme.palette.error.main : theme.palette.success.main; - const icon = hasActive ? ( - - ) : ( - + const icon = ( + + + ); const msg = t("pages.incidents.summaryCard.activeIncidents.active", { count: activeCount, @@ -133,10 +132,7 @@ const SummaryIncidentItem = ({ incident }: { incident: IncidentSummaryItem }) => container alignItems="center" spacing={2} - sx={{ - width: "100%", - py: theme.spacing(0.5), - }} + sx={{ width: "100%", minHeight: 32 }} > gap: theme.spacing(2), }} > - + size={{ xs: 12, md: 6, lg: 4 }} sx={{ textAlign: { xs: "left", md: "right" }, - fontWeight: 500, + fontWeight: 600, }} > {duration} @@ -190,22 +184,17 @@ export const SummaryCardLatestIncidents = ({ summary, }: SummaryCardLatestIncidentsProps) => { const { t } = useTranslation(); - const theme = useTheme(); const latestIncidents = summary?.latestIncidents ?? []; return ( - - {latestIncidents.slice(0, 3).map((incident, index) => ( - - - {index < latestIncidents.length - 1 && ( - - )} - - ))} - + {latestIncidents.slice(0, 3).map((incident) => ( + + ))} ); }; @@ -224,17 +213,17 @@ export const SummaryCardStats = ({ summary }: SummaryCardStatsProps) => { return ( } + icon={} label={t("pages.incidents.summaryCard.incidentStats.totalIncidents")} value={summary?.total || 0} /> } + icon={} label={t("pages.incidents.summaryCard.incidentStats.mostAffectedMonitor")} value={mostAffected} /> } + icon={} label={t("pages.incidents.summaryCard.incidentStats.avgResolutionTime")} value={ summary.total > 0 diff --git a/client/src/Pages/Incidents/Components/ControlsIncidentFilter.tsx b/client/src/Pages/Incidents/Components/ControlsIncidentFilter.tsx index a0f4eb15a..af7cba105 100644 --- a/client/src/Pages/Incidents/Components/ControlsIncidentFilter.tsx +++ b/client/src/Pages/Incidents/Components/ControlsIncidentFilter.tsx @@ -75,7 +75,7 @@ export const ControlsIncidentFilter = ({ variant="contained" onClick={onClearFilters} > - {t("pages.incidents.filters.clearFilters")} + {t("common.buttons.clearFilters")} )} diff --git a/client/src/Pages/Incidents/index.tsx b/client/src/Pages/Incidents/index.tsx index 84c414b26..63cd18889 100644 --- a/client/src/Pages/Incidents/index.tsx +++ b/client/src/Pages/Incidents/index.tsx @@ -15,6 +15,7 @@ import { HeaderTimeRange } from "@/Components/common"; import { ControlsIncidentFilter } from "@/Pages/Incidents/Components/ControlsIncidentFilter"; import { useGet } from "@/Hooks/UseApi"; +import { LAYOUT } from "@/Utils/Theme/constants"; import { useState, useEffect, useMemo } from "react"; import { useParams } from "react-router-dom"; import type { Incident, IncidentsResponse, IncidentSummary } from "@/Types/Incident"; @@ -186,8 +187,9 @@ const IncidentsPage = () => { {activeIncidentsCount > 0 && ( <> {t("pages.incidents.table.activeIncidents")} @@ -208,8 +210,9 @@ const IncidentsPage = () => { )} {t("pages.incidents.table.resolvedIncidents")} diff --git a/client/src/Pages/Infrastructure/Details/Components/ChartsNetwork.tsx b/client/src/Pages/Infrastructure/Details/Components/ChartsNetwork.tsx index 54e3cc1ed..c7ebac5be 100644 --- a/client/src/Pages/Infrastructure/Details/Components/ChartsNetwork.tsx +++ b/client/src/Pages/Infrastructure/Details/Components/ChartsNetwork.tsx @@ -1,4 +1,6 @@ import Grid from "@mui/material/Grid"; +import Stack from "@mui/material/Stack"; +import { NoticeBanner } from "@/Components/design-elements"; import { HistogramInfrastructure } from "@/Components/monitors"; import { useTranslation } from "react-i18next"; @@ -6,6 +8,7 @@ import type { HardwareCheckStats } from "@/Types/Monitor"; import { useMemo } from "react"; import { useTheme } from "@mui/material/styles"; import useMediaQuery from "@mui/material/useMediaQuery"; +import { LAYOUT } from "@/Utils/Theme/constants"; const formatBytesToMB = (value: number) => `${(value / (1024 * 1024)).toFixed(2)} MB`; @@ -60,6 +63,11 @@ const getChartConfigs = ( return configs; }; +const hasAnyNetworkTraffic = (checks: HardwareCheckStats[]): boolean => + checks.some((c) => + c.net?.some((iface) => iface.bytesSentPerSecond > 0 || iface.deltaBytesRecv > 0) + ); + export const InfraNetworkCharts = ({ checks, dateRange, @@ -74,35 +82,43 @@ export const InfraNetworkCharts = ({ () => getChartConfigs(theme, checks, t), [theme, checks, t] ); + const showNoTrafficNotice = chartConfigs.length > 0 && !hasAnyNetworkTraffic(checks); return ( - - {chartConfigs.map((config) => { - return ( - - - - ); - })} - + + {showNoTrafficNotice && ( + + {t("pages.infrastructure.charts.labels.netNoTraffic")} + + )} + + {chartConfigs.map((config) => { + return ( + + + + ); + })} + + ); }; diff --git a/client/src/Utils/Theme/Palette.ts b/client/src/Utils/Theme/Palette.ts index 0fe08583a..92c08cd2f 100644 --- a/client/src/Utils/Theme/Palette.ts +++ b/client/src/Utils/Theme/Palette.ts @@ -1,12 +1,13 @@ const typographyBase = 13; export const typographyLevels = { - base: typographyBase, - xs: `${(typographyBase - 4) / 16}rem`, - s: `${(typographyBase - 2) / 16}rem`, - m: `${typographyBase / 16}rem`, - l: `${(typographyBase + 2) / 16}rem`, - xl: `${(typographyBase + 10) / 16}rem`, + base: typographyBase, // 13px + xs: `${(typographyBase - 4) / 16}rem`, // 9px + s: `${(typographyBase - 2) / 16}rem`, // 11px + m: `${typographyBase / 16}rem`, // 13px + l: `${(typographyBase + 2) / 16}rem`, // 15px + xl: `${(typographyBase + 5) / 16}rem`, // 18px + xxl: `${(typographyBase + 10) / 16}rem`, // 23px }; export const colors = { diff --git a/client/src/Utils/Theme/Theme.ts b/client/src/Utils/Theme/Theme.ts index 19f864c6f..7c712d66d 100644 --- a/client/src/Utils/Theme/Theme.ts +++ b/client/src/Utils/Theme/Theme.ts @@ -58,7 +58,7 @@ export const theme = (mode: string, palette: any) => fontFamilyMonospace, fontSize: typographyLevels.base, h1: { - fontSize: typographyLevels.xl, + fontSize: typographyLevels.xxl, fontWeight: 500, }, h2: { diff --git a/client/src/Utils/Theme/constants.ts b/client/src/Utils/Theme/constants.ts index 8b045f9f6..d718d61dc 100644 --- a/client/src/Utils/Theme/constants.ts +++ b/client/src/Utils/Theme/constants.ts @@ -8,6 +8,7 @@ export const SPACING = { } as const; export const LAYOUT = { + XXS: 2, XS: 4, SM: 6, MD: 8, @@ -15,3 +16,7 @@ export const LAYOUT = { XL: 12, XXL: 16, } as const; + +export const HOVER = { + DARKEN: 0.06, // This is a coefficient for darkening function +} as const; diff --git a/client/src/locales/ar.json b/client/src/locales/ar.json index 011660918..11fa81309 100644 --- a/client/src/locales/ar.json +++ b/client/src/locales/ar.json @@ -769,6 +769,7 @@ "memory": "استخدام الذاكرة", "netBytesRecv": "{{name}} - البايتات المستلمة", "netBytesSent": "{{name}} - البايتات المرسلة", + "netNoTraffic": "Capture يبلغ عن عدم وجود حركة بيانات على أي واجهة. هذا أمر طبيعي عندما يعمل Capture داخل حاوية لا ترى سوى واجهات الاسترجاع — قم بتشغيل Capture مباشرة على المضيف لرؤية نشاط الشبكة الحقيقي.", "temp": "الحرارة" } }, diff --git a/client/src/locales/cs.json b/client/src/locales/cs.json index 47c669b0c..454f0b673 100644 --- a/client/src/locales/cs.json +++ b/client/src/locales/cs.json @@ -769,6 +769,7 @@ "memory": "Využití paměti", "netBytesRecv": "{{name}} - přijaté bajty", "netBytesSent": "{{name}} - odeslané bajty", + "netNoTraffic": "Capture hlásí nulový provoz na všech rozhraních. To je normální, když Capture běží uvnitř kontejneru, který vidí pouze loopback rozhraní — spusťte Capture přímo na hostiteli, abyste viděli skutečnou síťovou aktivitu.", "temp": "Teplota" } }, diff --git a/client/src/locales/de.json b/client/src/locales/de.json index c9495f52f..8090aa5f3 100644 --- a/client/src/locales/de.json +++ b/client/src/locales/de.json @@ -769,6 +769,7 @@ "memory": "Arbeitsspeicherauslastung", "netBytesRecv": "{{name}} - Empfangene Bytes", "netBytesSent": "{{name}} - Gesendete Bytes", + "netNoTraffic": "Capture meldet null Datenverkehr auf allen Schnittstellen. Das ist normal, wenn Capture in einem Container läuft, der nur Loopback-Schnittstellen sieht — führe Capture direkt auf dem Host aus, um echten Netzwerkverkehr zu sehen.", "temp": "Temp." } }, diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 289282bb5..7f132ccee 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -769,6 +769,7 @@ "memory": "Memory usage", "netBytesRecv": "{{name}} - Bytes Received", "netBytesSent": "{{name}} - Bytes Sent", + "netNoTraffic": "Capture is reporting zero traffic on every interface. This is normal when Capture runs inside a container that can only see loopback interfaces — run Capture directly on the host to see real network activity.", "temp": "Temp" } }, diff --git a/client/src/locales/es.json b/client/src/locales/es.json index 834a6005c..506c317e3 100644 --- a/client/src/locales/es.json +++ b/client/src/locales/es.json @@ -776,6 +776,7 @@ "memory": "Uso de memoria", "netBytesRecv": "{{name}} - Bytes recibidos", "netBytesSent": "{{name}} - Bytes enviados", + "netNoTraffic": "Capture no informa tráfico en ninguna interfaz. Esto es normal cuando Capture se ejecuta dentro de un contenedor que solo ve interfaces de loopback — ejecuta Capture directamente en el host para ver actividad de red real.", "temp": "Temp" } }, diff --git a/client/src/locales/fi.json b/client/src/locales/fi.json index e5741151f..6238837f2 100644 --- a/client/src/locales/fi.json +++ b/client/src/locales/fi.json @@ -769,6 +769,7 @@ "memory": "Muistin käyttö", "netBytesRecv": "{{name}} - tavua vastaanotettu", "netBytesSent": "{{name}} - tavua lähetetty", + "netNoTraffic": "Capture ilmoittaa nollaliikennettä kaikilla rajapinnoilla. Tämä on normaalia, kun Capture käynnistetään säiliössä, joka näkee vain loopback-rajapinnat — suorita Capture suoraan isännällä nähdäksesi todellisen verkkoaktiviteetin.", "temp": "Lämpö" } }, diff --git a/client/src/locales/fr.json b/client/src/locales/fr.json index 5a83ff55f..306a2bd61 100644 --- a/client/src/locales/fr.json +++ b/client/src/locales/fr.json @@ -769,6 +769,7 @@ "memory": "Utilisation mémoire", "netBytesRecv": "{{name}} - Octets reçus", "netBytesSent": "{{name}} - Octets envoyés", + "netNoTraffic": "Capture ne signale aucun trafic sur toutes les interfaces. C'est normal lorsque Capture s'exécute dans un conteneur qui ne voit que les interfaces de loopback — exécutez Capture directement sur l'hôte pour voir l'activité réseau réelle.", "temp": "Temp." } }, diff --git a/client/src/locales/ja.json b/client/src/locales/ja.json index ad5351fc0..923213a46 100644 --- a/client/src/locales/ja.json +++ b/client/src/locales/ja.json @@ -769,6 +769,7 @@ "memory": "メモリ使用率", "netBytesRecv": "{{name}} - 受信バイト数", "netBytesSent": "{{name}} - 送信バイト数", + "netNoTraffic": "Capture はすべてのインターフェイスでゼロのトラフィックを報告しています。これは Capture がループバックインターフェイスのみを認識できるコンテナ内で実行されている場合に正常です — 実際のネットワークアクティビティを表示するには、ホスト上で Capture を直接実行してください。", "temp": "温度" } }, diff --git a/client/src/locales/pt-BR.json b/client/src/locales/pt-BR.json index 9fdd709b5..f7b7c4cbc 100644 --- a/client/src/locales/pt-BR.json +++ b/client/src/locales/pt-BR.json @@ -769,6 +769,7 @@ "memory": "Uso de memória", "netBytesRecv": "{{name}} - Bytes recebidos", "netBytesSent": "{{name}} - Bytes enviados", + "netNoTraffic": "Capture está reportando zero tráfego em todas as interfaces. Isso é normal quando Capture é executado dentro de um container que só consegue ver interfaces de loopback — execute Capture diretamente no host para ver a atividade real da rede.", "temp": "Temp" } }, diff --git a/client/src/locales/ru.json b/client/src/locales/ru.json index 3547252c2..1a5d12452 100644 --- a/client/src/locales/ru.json +++ b/client/src/locales/ru.json @@ -769,6 +769,7 @@ "memory": "Использование памяти", "netBytesRecv": "{{name}} - байт получено", "netBytesSent": "{{name}} - байт отправлено", + "netNoTraffic": "Capture сообщает о нулевом трафике на всех интерфейсах. Это нормально, когда Capture работает внутри контейнера, который видит только loopback-интерфейсы — запустите Capture непосредственно на хосте, чтобы увидеть реальную сетевую активность.", "temp": "Температура" } }, diff --git a/client/src/locales/th.json b/client/src/locales/th.json index 4d0a6b2cd..433ee10cd 100644 --- a/client/src/locales/th.json +++ b/client/src/locales/th.json @@ -769,6 +769,7 @@ "memory": "การใช้งานหน่วยความจำ", "netBytesRecv": "{{name}} - ไบต์ที่รับ", "netBytesSent": "{{name}} - ไบต์ที่ส่ง", + "netNoTraffic": "Capture รายงานว่าไม่มีการรับส่งข้อมูลบนอินเทอร์เฟซใดๆ เลย ซึ่งเป็นเรื่องปกติเมื่อ Capture ทำงานอยู่ในคอนเทนเนอร์ที่มองเห็นเพียงอินเทอร์เฟซ loopback เท่านั้น — รัน Capture บนโฮสต์โดยตรงเพื่อดูกิจกรรมเครือข่ายจริง", "temp": "อุณหภูมิ" } }, diff --git a/client/src/locales/tr.json b/client/src/locales/tr.json index 39af85f57..a77dd8eb3 100644 --- a/client/src/locales/tr.json +++ b/client/src/locales/tr.json @@ -769,6 +769,7 @@ "memory": "Bellek kullanımı", "netBytesRecv": "{{name}} - Alınan bayt", "netBytesSent": "{{name}} - Gönderilen bayt", + "netNoTraffic": "Capture tüm arabirimlerde sıfır trafik raporluyor. Bu, Capture yalnızca loopback arabirimlerini görebilen bir konteyner içinde çalışırken normaldir — gerçek ağ etkinliğini görmek için Capture'ı doğrudan host üzerinde çalıştırın.", "temp": "Sıcaklık" } }, diff --git a/client/src/locales/uk.json b/client/src/locales/uk.json index 81e0af90a..5b467e4b4 100644 --- a/client/src/locales/uk.json +++ b/client/src/locales/uk.json @@ -769,6 +769,7 @@ "memory": "Використання пам'яті", "netBytesRecv": "{{name}} - Отримано байтів", "netBytesSent": "{{name}} - Надіслано байтів", + "netNoTraffic": "Capture повідомляє про нульовий трафік на всіх інтерфейсах. Це нормально, коли Capture працює всередині контейнера, який бачить лише loopback-інтерфейси — запустіть Capture безпосередньо на хості, щоб побачити реальну мережеву активність.", "temp": "Темп." } }, diff --git a/client/src/locales/vi.json b/client/src/locales/vi.json index e3ce4d006..dc3e804de 100644 --- a/client/src/locales/vi.json +++ b/client/src/locales/vi.json @@ -769,6 +769,7 @@ "memory": "Sử dụng bộ nhớ", "netBytesRecv": "{{name}} - Byte nhận", "netBytesSent": "{{name}} - Byte gửi", + "netNoTraffic": "Capture đang báo cáo lưu lượng bằng không trên mọi giao diện. Điều này là bình thường khi Capture chạy bên trong một container chỉ có thể thấy các giao diện loopback — hãy chạy Capture trực tiếp trên máy chủ để xem hoạt động mạng thực tế.", "temp": "Nhiệt độ" } }, diff --git a/client/src/locales/zh-CN.json b/client/src/locales/zh-CN.json index bb6f3b696..ed5e70c1e 100644 --- a/client/src/locales/zh-CN.json +++ b/client/src/locales/zh-CN.json @@ -769,6 +769,7 @@ "memory": "内存使用率", "netBytesRecv": "{{name}} - 接收字节", "netBytesSent": "{{name}} - 发送字节", + "netNoTraffic": "Capture 报告所有接口的流量均为零。当 Capture 在只能看到回环接口的容器内运行时,这属于正常情况——请直接在主机上运行 Capture 才能看到真实的网络活动。", "temp": "温度" } }, diff --git a/client/src/locales/zh-TW.json b/client/src/locales/zh-TW.json index dd3056181..ff6e9f6dd 100644 --- a/client/src/locales/zh-TW.json +++ b/client/src/locales/zh-TW.json @@ -769,6 +769,7 @@ "memory": "記憶體使用率", "netBytesRecv": "{{name}} - 接收位元組", "netBytesSent": "{{name}} - 發送位元組", + "netNoTraffic": "Capture 回報所有介面的流量皆為零。當 Capture 在只能看到回環介面的容器中執行時,這是正常情況——請直接在主機上執行 Capture 才能看到實際的網路活動。", "temp": "溫度" } },