import { type FC, useContext, useState } from 'react'; import { toast } from 'react-toastify'; import AccessTimeIcon from '@mui/icons-material/AccessTime'; import BuildIcon from '@mui/icons-material/Build'; import CancelIcon from '@mui/icons-material/Cancel'; import DeviceHubIcon from '@mui/icons-material/DeviceHub'; import DirectionsBusIcon from '@mui/icons-material/DirectionsBus'; import MemoryIcon from '@mui/icons-material/Memory'; import PermScanWifiIcon from '@mui/icons-material/PermScanWifi'; import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew'; import RefreshIcon from '@mui/icons-material/Refresh'; import RouterIcon from '@mui/icons-material/Router'; import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna'; import TimerIcon from '@mui/icons-material/Timer'; import WifiIcon from '@mui/icons-material/Wifi'; import { Avatar, Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Divider, List, ListItem, ListItemAvatar, ListItemText, useTheme } from '@mui/material'; import * as SystemApi from 'api/system'; import * as EMSESP from 'project/api'; import { dialogStyle } from 'CustomTheme'; import { useRequest } from 'alova'; import { FormLoader, SectionContent, useLayoutTitle } from 'components'; import ListMenuItem from 'components/layout/ListMenuItem'; import { AuthenticatedContext } from 'contexts/authentication'; import { useI18nContext } from 'i18n/i18n-react'; import { busConnectionStatus } from 'project/types'; import { NTPSyncStatus, NetworkConnectionStatus } from 'types'; import RestartMonitor from './RestartMonitor'; const SystemStatus: FC = () => { const { LL } = useI18nContext(); useLayoutTitle(LL.STATUS_OF('')); const { me } = useContext(AuthenticatedContext); const [confirmRestart, setConfirmRestart] = useState(false); const [confirmScan, setConfirmScan] = useState(false); const [processing, setProcessing] = useState(false); const [restarting, setRestarting] = useState(); const { send: restartCommand } = useRequest(SystemApi.restart(), { immediate: false }); const { send: partitionCommand } = useRequest(SystemApi.partition(), { immediate: false }); const { data: data, send: loadData, error } = useRequest(SystemApi.readSystemStatus, { force: true }); const { send: scanDevices } = useRequest(EMSESP.scanDevices, { immediate: false }); const theme = useTheme(); const formatDurationSec = (duration_sec: number) => { const days = Math.trunc((duration_sec * 1000) / 86400000); const hours = Math.trunc((duration_sec * 1000) / 3600000) % 24; const minutes = Math.trunc((duration_sec * 1000) / 60000) % 60; const seconds = Math.trunc((duration_sec * 1000) / 1000) % 60; let formatted = ''; if (days) { formatted += LL.NUM_DAYS({ num: days }) + ' '; } if (hours) { formatted += LL.NUM_HOURS({ num: hours }) + ' '; } if (minutes) { formatted += LL.NUM_MINUTES({ num: minutes }) + ' '; } formatted += LL.NUM_SECONDS({ num: seconds }); return formatted; }; function formatNumber(num: number) { return new Intl.NumberFormat().format(num); } const busStatus = () => { if (data) { switch (data.status) { case busConnectionStatus.BUS_STATUS_CONNECTED: return LL.CONNECTED(0) + ' (' + formatDurationSec(data.bus_uptime) + ')'; case busConnectionStatus.BUS_STATUS_TX_ERRORS: return LL.TX_ISSUES(); case busConnectionStatus.BUS_STATUS_OFFLINE: return LL.DISCONNECTED(); } } return 'Unknown'; }; const busStatusHighlight = () => { switch (data.status) { case busConnectionStatus.BUS_STATUS_TX_ERRORS: return theme.palette.warning.main; case busConnectionStatus.BUS_STATUS_CONNECTED: return theme.palette.success.main; case busConnectionStatus.BUS_STATUS_OFFLINE: return theme.palette.error.main; default: return theme.palette.warning.main; } }; const ntpStatus = () => { switch (data.ntp_status) { case NTPSyncStatus.NTP_DISABLED: return LL.NOT_ENABLED(); case NTPSyncStatus.NTP_INACTIVE: return LL.INACTIVE(0); case NTPSyncStatus.NTP_ACTIVE: return LL.ACTIVE(); default: return LL.UNKNOWN(); } }; const ntpStatusHighlight = () => { switch (data.ntp_status) { case NTPSyncStatus.NTP_DISABLED: return theme.palette.info.main; case NTPSyncStatus.NTP_INACTIVE: return theme.palette.error.main; case NTPSyncStatus.NTP_ACTIVE: return theme.palette.success.main; default: return theme.palette.error.main; } }; const networkStatusHighlight = () => { switch (data.network_status) { case NetworkConnectionStatus.WIFI_STATUS_IDLE: case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED: case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD: return theme.palette.info.main; case NetworkConnectionStatus.WIFI_STATUS_CONNECTED: case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED: return theme.palette.success.main; case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED: case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST: return theme.palette.error.main; default: return theme.palette.warning.main; } }; const networkStatus = () => { switch (data.network_status) { case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD: return LL.INACTIVE(1); case NetworkConnectionStatus.WIFI_STATUS_IDLE: return LL.IDLE(); case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL: return 'No SSID Available'; case NetworkConnectionStatus.WIFI_STATUS_CONNECTED: return LL.CONNECTED(0) + ' (WiFi, ' + data.wifi_rssi + ' dBm)'; case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED: return LL.CONNECTED(0) + ' (Ethernet)'; case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED: return LL.CONNECTED(1) + ' ' + LL.FAILED(0); case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST: return LL.CONNECTED(1) + ' ' + LL.LOST(); case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED: return LL.DISCONNECTED(); default: return LL.UNKNOWN(); } }; const activeHighlight = (value: boolean) => value ? theme.palette.success.main : theme.palette.info.main; const scan = async () => { await scanDevices() .then(() => { toast.info(LL.SCANNING() + '...'); }) .catch((error: Error) => { toast.error(error.message); }); setConfirmScan(false); }; const renderScanDialog = () => ( setConfirmScan(false)} > {LL.SCAN_DEVICES()} {LL.EMS_SCAN()} ); const restart = async () => { setProcessing(true); await restartCommand() .then(() => { setRestarting(true); }) .catch((error: Error) => { toast.error(error.message); }) .finally(() => { setConfirmRestart(false); setProcessing(false); }); }; const partition = async () => { setProcessing(true); await partitionCommand() .then(() => { setRestarting(true); }) .catch((error: Error) => { toast.error(error.message); }) .finally(() => { setConfirmRestart(false); setProcessing(false); }); }; const renderRestartDialog = () => ( setConfirmRestart(false)} > {LL.RESTART()} {LL.RESTART_CONFIRM()} ); const content = () => { if (!data) { return ; } return ( <> {me.admin && ( )} {me.admin && ( )} {renderScanDialog()} {renderRestartDialog()} ); }; return ( {restarting ? : content()} ); }; export default SystemStatus;