refactor web file structure and seperate settings from status

This commit is contained in:
proddy
2024-07-22 14:46:22 +02:00
parent d0976cd660
commit 53e9a062e8
60 changed files with 149 additions and 251 deletions

1
.gitignore vendored
View File

@@ -40,6 +40,7 @@ yarn.lock
analyse.html analyse.html
interface/vite.config.ts.timestamp* interface/vite.config.ts.timestamp*
*.local *.local
# i18n generated files # i18n generated files
interface/src/i18n/i18n-react.tsx interface/src/i18n/i18n-react.tsx
interface/src/i18n/i18n-types.ts interface/src/i18n/i18n-types.ts

View File

@@ -1,26 +1,32 @@
import { type FC, useContext } from 'react'; import { type FC, useContext } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router-dom';
import CustomEntities from 'app/main/CustomEntities';
import Customization from 'app/main/Customization';
import Devices from 'app/main/Devices';
import Modules from 'app/main/Modules';
import Scheduler from 'app/main/Scheduler';
import Sensors from 'app/main/Sensors';
import APSettings from 'app/settings/APSettings';
import ApplicationSettings from 'app/settings/ApplicationSettings';
import MqttSettings from 'app/settings/MqttSettings';
import NTPSettings from 'app/settings/NTPSettings';
import Settings from 'app/settings/Settings';
import UploadDownload from 'app/settings/UploadDownload';
import Network from 'app/settings/network/Network';
import Security from 'app/settings/security/Security';
import APStatus from 'app/status/APStatus';
import Activity from 'app/status/Activity';
import HardwareStatus from 'app/status/HardwareStatus';
import MqttStatus from 'app/status/MqttStatus';
import NTPStatus from 'app/status/NTPStatus';
import NetworkStatus from 'app/status/NetworkStatus';
import Status from 'app/status/Status';
import SystemLog from 'app/status/SystemLog';
import { Layout } from 'components'; import { Layout } from 'components';
import { AuthenticatedContext } from 'contexts/authentication'; import { AuthenticatedContext } from 'contexts/authentication';
import Settings from 'framework/Settings';
import AccessPoint from 'framework/ap/AccessPoint';
import Mqtt from 'framework/mqtt/Mqtt';
import Network from 'framework/network/Network';
import NetworkTime from 'framework/ntp/NetworkTime';
import Security from 'framework/security/Security';
import ESPSystemStatus from 'framework/system/ESPSystemStatus';
import System from 'framework/system/System';
import UploadDownload from 'framework/system/UploadDownload';
import ApplicationSettings from 'project/ApplicationSettings';
import CustomEntities from 'project/CustomEntities';
import Customization from 'project/Customization';
import Devices from 'project/Devices';
import Modules from 'project/Modules';
import Scheduler from 'project/Scheduler';
import Sensors from 'project/Sensors';
import Help from './project/Help'; import Help from './app/main/Help';
const AuthenticatedRouting: FC = () => { const AuthenticatedRouting: FC = () => {
const { me } = useContext(AuthenticatedContext); const { me } = useContext(AuthenticatedContext);
@@ -29,24 +35,34 @@ const AuthenticatedRouting: FC = () => {
<Routes> <Routes>
<Route path="/devices/*" element={<Devices />} /> <Route path="/devices/*" element={<Devices />} />
<Route path="/sensors/*" element={<Sensors />} /> <Route path="/sensors/*" element={<Sensors />} />
<Route path="/system/*" element={<System />} /> <Route path="/status/*" element={<Status />} />
<Route path="/help/*" element={<Help />} /> <Route path="/help/*" element={<Help />} />
<Route path="/*" element={<Navigate to="/" />} /> <Route path="/*" element={<Navigate to="/" />} />
<Route path="/status/hardwarestatus/*" element={<HardwareStatus />} />
<Route path="/status/activity" element={<Activity />} />
<Route path="/status/log" element={<SystemLog />} />
<Route path="/status/mqtt" element={<MqttStatus />} />
<Route path="/status/ntp" element={<NTPStatus />} />
<Route path="/status/ap" element={<APStatus />} />
<Route path="/status/network" element={<NetworkStatus />} />
{me.admin && ( {me.admin && (
<> <>
<Route path="/customizations/*" element={<Customization />} /> <Route path="/settings" element={<Settings />} />
<Route path="/scheduler/*" element={<Scheduler />} /> <Route path="/settings/application" element={<ApplicationSettings />} />
<Route path="/customentities/*" element={<CustomEntities />} /> <Route path="/settings/mqtt" element={<MqttSettings />} />
<Route path="/settings/*" element={<Settings />} /> <Route path="/settings/ntp" element={<NTPSettings />} />
<Route path="/settings/ap" element={<APSettings />} />
<Route path="/settings/modules" element={<Modules />} />
<Route path="/settings/upload" element={<UploadDownload />} />
<Route path="/settings/network/*" element={<Network />} /> <Route path="/settings/network/*" element={<Network />} />
<Route path="/settings/ems-esp/*" element={<ApplicationSettings />} />
<Route path="/settings/ap/*" element={<AccessPoint />} />
<Route path="/settings/ntp/*" element={<NetworkTime />} />
<Route path="/settings/mqtt/*" element={<Mqtt />} />
<Route path="/settings/security/*" element={<Security />} /> <Route path="/settings/security/*" element={<Security />} />
<Route path="/settings/modules/*" element={<Modules />} />
<Route path="/system/espsystemstatus/*" element={<ESPSystemStatus />} /> <Route path="/customizations" element={<Customization />} />
<Route path="/settings/upload/*" element={<UploadDownload />} /> <Route path="/scheduler" element={<Scheduler />} />
<Route path="/customentities" element={<CustomEntities />} />
</> </>
)} )}
</Routes> </Routes>

View File

@@ -41,6 +41,7 @@ import {
import { useTheme } from '@table-library/react-table-library/theme'; import { useTheme } from '@table-library/react-table-library/theme';
import { dialogStyle } from 'CustomTheme'; import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import RestartMonitor from 'app/status/RestartMonitor';
import { import {
BlockNavigation, BlockNavigation,
ButtonRow, ButtonRow,
@@ -48,7 +49,6 @@ import {
SectionContent, SectionContent,
useLayoutTitle useLayoutTitle
} from 'components'; } from 'components';
import RestartMonitor from 'framework/system/RestartMonitor';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import * as EMSESP from './api'; import * as EMSESP from './api';

View File

@@ -18,7 +18,7 @@ import {
Typography Typography
} from '@mui/material'; } from '@mui/material';
import * as EMSESP from 'project/api'; import * as EMSESP from 'app/main/api';
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import { SectionContent, useLayoutTitle } from 'components'; import { SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';

View File

@@ -15,7 +15,8 @@ import {
FormLoader, FormLoader,
SectionContent, SectionContent,
ValidatedPasswordField, ValidatedPasswordField,
ValidatedTextField ValidatedTextField,
useLayoutTitle
} from 'components'; } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import { range } from 'lodash-es'; import { range } from 'lodash-es';
@@ -47,6 +48,8 @@ const APSettings: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SETTINGS_OF(LL.ACCESS_POINT(0)));
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>(); const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
const updateFormValue = updateValueDirty( const updateFormValue = updateValueDirty(

View File

@@ -20,6 +20,7 @@ import {
import * as SystemApi from 'api/system'; import * as SystemApi from 'api/system';
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import RestartMonitor from 'app/status/RestartMonitor';
import type { ValidateFieldsError } from 'async-validator'; import type { ValidateFieldsError } from 'async-validator';
import { import {
BlockFormControlLabel, BlockFormControlLabel,
@@ -31,15 +32,14 @@ import {
ValidatedTextField, ValidatedTextField,
useLayoutTitle useLayoutTitle
} from 'components'; } from 'components';
import RestartMonitor from 'framework/system/RestartMonitor';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import { numberValue, updateValueDirty, useRest } from 'utils'; import { numberValue, updateValueDirty, useRest } from 'utils';
import { validate } from 'validators'; import { validate } from 'validators';
import * as EMSESP from './api'; import * as EMSESP from '../main/api';
import { BOARD_PROFILES } from './types'; import { BOARD_PROFILES } from '../main/types';
import type { Settings } from './types'; import type { Settings } from '../main/types';
import { createSettingsValidator } from './validators'; import { createSettingsValidator } from '../main/validators';
export function boardProfileSelectItems() { export function boardProfileSelectItems() {
return Object.keys(BOARD_PROFILES).map((code) => ( return Object.keys(BOARD_PROFILES).map((code) => (
@@ -115,7 +115,7 @@ const ApplicationSettings: FC = () => {
}); });
}; };
useLayoutTitle(LL.APPLICATION()); useLayoutTitle(LL.SETTINGS_OF(LL.APPLICATION()));
const content = () => { const content = () => {
if (!data) { if (!data) {

View File

@@ -23,7 +23,8 @@ import {
FormLoader, FormLoader,
SectionContent, SectionContent,
ValidatedPasswordField, ValidatedPasswordField,
ValidatedTextField ValidatedTextField,
useLayoutTitle
} from 'components'; } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import type { MqttSettingsType } from 'types'; import type { MqttSettingsType } from 'types';
@@ -48,6 +49,7 @@ const MqttSettings: FC = () => {
}); });
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SETTINGS_OF('MQTT'));
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>(); const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();

View File

@@ -15,7 +15,8 @@ import {
ButtonRow, ButtonRow,
FormLoader, FormLoader,
SectionContent, SectionContent,
ValidatedTextField ValidatedTextField,
useLayoutTitle
} from 'components'; } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import type { NTPSettingsType } from 'types'; import type { NTPSettingsType } from 'types';
@@ -43,6 +44,7 @@ const NTPSettings: FC = () => {
}); });
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SETTINGS_OF('NTP'));
const updateFormValue = updateValueDirty( const updateFormValue = updateValueDirty(
origData, origData,

View File

@@ -79,15 +79,15 @@ const Settings: FC = () => {
<ListMenuItem <ListMenuItem
icon={TuneIcon} icon={TuneIcon}
bgcolor="#134ba2" bgcolor="#134ba2"
label={LL.APPLICATION()} label={LL.SETTINGS_OF(LL.APPLICATION())}
text={LL.APPLICATION_SETTINGS_1()} text={LL.APPLICATION_SETTINGS_1()}
to="ems-esp" to="application"
/> />
<ListMenuItem <ListMenuItem
icon={SettingsEthernetIcon} icon={SettingsEthernetIcon}
bgcolor="#40828f" bgcolor="#40828f"
label={LL.NETWORK(0)} label={LL.SETTINGS_OF(LL.NETWORK(0))}
text={LL.CONFIGURE(LL.SETTINGS_OF(LL.NETWORK(1)))} text={LL.CONFIGURE(LL.SETTINGS_OF(LL.NETWORK(1)))}
to="network" to="network"
/> />
@@ -95,7 +95,7 @@ const Settings: FC = () => {
<ListMenuItem <ListMenuItem
icon={SettingsInputAntennaIcon} icon={SettingsInputAntennaIcon}
bgcolor="#5f9a5f" bgcolor="#5f9a5f"
label={LL.ACCESS_POINT(0)} label={LL.SETTINGS_OF(LL.ACCESS_POINT(0))}
text={LL.CONFIGURE(LL.ACCESS_POINT(1))} text={LL.CONFIGURE(LL.ACCESS_POINT(1))}
to="ap" to="ap"
/> />
@@ -103,7 +103,7 @@ const Settings: FC = () => {
<ListMenuItem <ListMenuItem
icon={AccessTimeIcon} icon={AccessTimeIcon}
bgcolor="#c5572c" bgcolor="#c5572c"
label="NTP" label={LL.SETTINGS_OF('NTP')}
text={LL.CONFIGURE(LL.LOCAL_TIME(1))} text={LL.CONFIGURE(LL.LOCAL_TIME(1))}
to="ntp" to="ntp"
/> />
@@ -111,14 +111,14 @@ const Settings: FC = () => {
<ListMenuItem <ListMenuItem
icon={DeviceHubIcon} icon={DeviceHubIcon}
bgcolor="#68374d" bgcolor="#68374d"
label="MQTT" label={LL.SETTINGS_OF('MQTT')}
text={LL.CONFIGURE('MQTT')} text={LL.CONFIGURE('MQTT')}
to="mqtt" to="mqtt"
/> />
<ListMenuItem <ListMenuItem
icon={LockIcon} icon={LockIcon}
label={LL.SECURITY(0)} label={LL.SETTINGS_OF(LL.SECURITY(0))}
text={LL.SECURITY_1()} text={LL.SECURITY_1()}
to="security" to="security"
/> />

View File

@@ -6,8 +6,9 @@ import { Box, Button, Divider, Link, Typography } from '@mui/material';
import * as SystemApi from 'api/system'; import * as SystemApi from 'api/system';
import * as EMSESP from 'project/api'; import * as EMSESP from 'app/main/api';
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import type { APIcall } from 'app/main/types';
import { import {
FormLoader, FormLoader,
SectionContent, SectionContent,
@@ -15,9 +16,8 @@ import {
useLayoutTitle useLayoutTitle
} from 'components'; } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import type { APIcall } from 'project/types';
import RestartMonitor from './RestartMonitor'; import RestartMonitor from '../status/RestartMonitor';
const UploadDownload: FC = () => { const UploadDownload: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();

View File

@@ -9,13 +9,12 @@ import { useI18nContext } from 'i18n/i18n-react';
import type { WiFiNetwork } from 'types'; import type { WiFiNetwork } from 'types';
import NetworkSettings from './NetworkSettings'; import NetworkSettings from './NetworkSettings';
import NetworkStatus from './NetworkStatus';
import { WiFiConnectionContext } from './WiFiConnectionContext'; import { WiFiConnectionContext } from './WiFiConnectionContext';
import WiFiNetworkScanner from './WiFiNetworkScanner'; import WiFiNetworkScanner from './WiFiNetworkScanner';
const Network: FC = () => { const Network: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.NETWORK(0)); useLayoutTitle(LL.SETTINGS_OF(LL.NETWORK(0)));
const { routerTab } = useRouterTab(); const { routerTab } = useRouterTab();
@@ -45,11 +44,9 @@ const Network: FC = () => {
> >
<RouterTabs value={routerTab}> <RouterTabs value={routerTab}>
<Tab value="settings" label={LL.SETTINGS_OF(LL.NETWORK(1))} /> <Tab value="settings" label={LL.SETTINGS_OF(LL.NETWORK(1))} />
<Tab value="status" label={LL.STATUS_OF(LL.NETWORK(1))} />
<Tab value="scan" label={LL.NETWORK_SCAN()} /> <Tab value="scan" label={LL.NETWORK_SCAN()} />
</RouterTabs> </RouterTabs>
<Routes> <Routes>
<Route path="status" element={<NetworkStatus />} />
<Route path="scan" element={<WiFiNetworkScanner />} /> <Route path="scan" element={<WiFiNetworkScanner />} />
<Route path="settings" element={<NetworkSettings />} /> <Route path="settings" element={<NetworkSettings />} />
<Route path="*" element={<Navigate replace to="settings" />} /> <Route path="*" element={<Navigate replace to="settings" />} />

View File

@@ -44,7 +44,7 @@ import { updateValueDirty, useRest } from 'utils';
import { validate } from 'validators'; import { validate } from 'validators';
import { createNetworkSettingsValidator } from 'validators/network'; import { createNetworkSettingsValidator } from 'validators/network';
import RestartMonitor from '../system/RestartMonitor'; import RestartMonitor from '../../status/RestartMonitor';
import { WiFiConnectionContext } from './WiFiConnectionContext'; import { WiFiConnectionContext } from './WiFiConnectionContext';
import { isNetworkOpen, networkSecurityMode } from './WiFiNetworkSelector'; import { isNetworkOpen, networkSecurityMode } from './WiFiNetworkSelector';

View File

@@ -11,7 +11,7 @@ import SecuritySettings from './SecuritySettings';
const Security: FC = () => { const Security: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SECURITY(0)); useLayoutTitle(LL.SETTINGS_OF(LL.SECURITY(0)));
const { routerTab } = useRouterTab(); const { routerTab } = useRouterTab();

View File

@@ -19,7 +19,7 @@ import type { Theme } from '@mui/material';
import * as APApi from 'api/ap'; import * as APApi from 'api/ap';
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent } from 'components'; import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import type { APStatusType } from 'types'; import type { APStatusType } from 'types';
import { APNetworkStatus } from 'types'; import { APNetworkStatus } from 'types';
@@ -41,6 +41,7 @@ const APStatus: FC = () => {
const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus); const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus);
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.STATUS_OF(LL.ACCESS_POINT(0)));
const theme = useTheme(); const theme = useTheme();

View File

@@ -19,15 +19,15 @@ import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'component
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import type { Translation } from 'i18n/i18n-types'; import type { Translation } from 'i18n/i18n-types';
import * as EMSESP from './api'; import * as EMSESP from '../main/api';
import type { Stat } from './types'; import type { Stat } from '../main/types';
const SystemActivity: FC = () => { const SystemActivity: FC = () => {
const { data: data, send: loadData, error } = useRequest(EMSESP.readActivity); const { data: data, send: loadData, error } = useRequest(EMSESP.readActivity);
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SYSTEM(0)); useLayoutTitle(LL.EMS_BUS_STATUS());
const stats_theme = tableTheme({ const stats_theme = tableTheme({
Table: ` Table: `

View File

@@ -26,7 +26,7 @@ import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components'; import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import BBQKeesIcon from '../../project/bbqkees.svg'; import BBQKeesIcon from './bbqkees.svg';
function formatNumber(num: number) { function formatNumber(num: number) {
return new Intl.NumberFormat().format(num); return new Intl.NumberFormat().format(num);

View File

@@ -20,7 +20,7 @@ import type { Theme } from '@mui/material';
import * as MqttApi from 'api/mqtt'; import * as MqttApi from 'api/mqtt';
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent } from 'components'; import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import type { MqttStatusType } from 'types'; import type { MqttStatusType } from 'types';
import { MqttDisconnectReason } from 'types'; import { MqttDisconnectReason } from 'types';
@@ -61,6 +61,7 @@ const MqttStatus: FC = () => {
const { data: data, send: loadData, error } = useRequest(MqttApi.readMqttStatus); const { data: data, send: loadData, error } = useRequest(MqttApi.readMqttStatus);
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.STATUS_OF('MQTT'));
const theme = useTheme(); const theme = useTheme();

View File

@@ -31,7 +31,7 @@ import * as NTPApi from 'api/ntp';
import { dialogStyle } from 'CustomTheme'; import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent } from 'components'; import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import type { NTPStatusType, Time } from 'types'; import type { NTPStatusType, Time } from 'types';
import { NTPSyncStatus } from 'types'; import { NTPSyncStatus } from 'types';
@@ -45,6 +45,7 @@ const NTPStatus: FC = () => {
const [processing, setProcessing] = useState<boolean>(false); const [processing, setProcessing] = useState<boolean>(false);
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.STATUS_OF('NTP'));
const { send: updateTime } = useRequest( const { send: updateTime } = useRequest(
(local_time: Time) => NTPApi.updateTime(local_time), (local_time: Time) => NTPApi.updateTime(local_time),

View File

@@ -23,7 +23,7 @@ import type { Theme } from '@mui/material';
import * as NetworkApi from 'api/network'; import * as NetworkApi from 'api/network';
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent } from 'components'; import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import type { NetworkStatusType } from 'types'; import type { NetworkStatusType } from 'types';
import { NetworkConnectionStatus } from 'types'; import { NetworkConnectionStatus } from 'types';
@@ -91,6 +91,7 @@ const NetworkStatus: FC = () => {
} = useRequest(NetworkApi.readNetworkStatus); } = useRequest(NetworkApi.readNetworkStatus);
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.STATUS_OF(LL.NETWORK(1)));
const theme = useTheme(); const theme = useTheme();

View File

@@ -1,4 +1,5 @@
import { type FC, useContext, useState } from 'react'; import { type FC, useContext, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import AccessTimeIcon from '@mui/icons-material/AccessTime'; import AccessTimeIcon from '@mui/icons-material/AccessTime';
@@ -6,6 +7,7 @@ import BuildIcon from '@mui/icons-material/Build';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import DeviceHubIcon from '@mui/icons-material/DeviceHub'; import DeviceHubIcon from '@mui/icons-material/DeviceHub';
import DirectionsBusIcon from '@mui/icons-material/DirectionsBus'; import DirectionsBusIcon from '@mui/icons-material/DirectionsBus';
import LogoDevIcon from '@mui/icons-material/LogoDev';
import MemoryIcon from '@mui/icons-material/Memory'; import MemoryIcon from '@mui/icons-material/Memory';
import PermScanWifiIcon from '@mui/icons-material/PermScanWifi'; import PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew'; import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
@@ -13,6 +15,7 @@ import RefreshIcon from '@mui/icons-material/Refresh';
import RouterIcon from '@mui/icons-material/Router'; import RouterIcon from '@mui/icons-material/Router';
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna'; import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
import TimerIcon from '@mui/icons-material/Timer'; import TimerIcon from '@mui/icons-material/Timer';
import UpgradeIcon from '@mui/icons-material/Upgrade';
import WifiIcon from '@mui/icons-material/Wifi'; import WifiIcon from '@mui/icons-material/Wifi';
import { import {
Avatar, Avatar,
@@ -32,14 +35,14 @@ import {
import * as SystemApi from 'api/system'; import * as SystemApi from 'api/system';
import * as EMSESP from 'project/api'; import * as EMSESP from 'app/main/api';
import { dialogStyle } from 'CustomTheme'; import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import { busConnectionStatus } from 'app/main/types';
import { FormLoader, SectionContent, useLayoutTitle } from 'components'; import { FormLoader, SectionContent, useLayoutTitle } from 'components';
import ListMenuItem from 'components/layout/ListMenuItem'; import ListMenuItem from 'components/layout/ListMenuItem';
import { AuthenticatedContext } from 'contexts/authentication'; import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import { busConnectionStatus } from 'project/types';
import { NTPSyncStatus, NetworkConnectionStatus } from 'types'; import { NTPSyncStatus, NetworkConnectionStatus } from 'types';
import RestartMonitor from './RestartMonitor'; import RestartMonitor from './RestartMonitor';
@@ -47,7 +50,9 @@ import RestartMonitor from './RestartMonitor';
const SystemStatus: FC = () => { const SystemStatus: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SYSTEM(0)); const navigate = useNavigate();
useLayoutTitle(LL.STATUS_OF(''));
const { me } = useContext(AuthenticatedContext); const { me } = useContext(AuthenticatedContext);
@@ -313,7 +318,7 @@ const SystemStatus: FC = () => {
return ( return (
<> <>
<List> <List sx={{ borderRadius: 3, border: '2px solid grey' }}>
<ListItem> <ListItem>
<ListItemAvatar> <ListItemAvatar>
<Avatar sx={{ bgcolor: '#c5572c', color: 'white' }}> <Avatar sx={{ bgcolor: '#c5572c', color: 'white' }}>
@@ -336,6 +341,16 @@ const SystemStatus: FC = () => {
)} )}
</ListItem> </ListItem>
<Divider variant="inset" component="li" />
<ListMenuItem
disabled={!me.admin}
icon={LogoDevIcon}
bgcolor="#40828f"
label={LL.LOG_OF(LL.SYSTEM(0))}
text={data.emsesp_version}
to="/status/log"
/>
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
<ListItem> <ListItem>
<ListItemAvatar> <ListItemAvatar>
@@ -366,14 +381,27 @@ const SystemStatus: FC = () => {
</ListItem> </ListItem>
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
<ListMenuItem <ListItem>
disabled={!me.admin} <ListItemAvatar>
icon={BuildIcon} <Avatar sx={{ bgcolor: '#134ba2', color: 'white' }}>
bgcolor="#134ba2" <BuildIcon />
label={LL.EMS_ESP_VER()} </Avatar>
text={data.emsesp_version} </ListItemAvatar>
to="/settings/upload" <ListItemText
primary={LL.EMS_ESP_VER()}
secondary={data.emsesp_version}
/> />
{me.admin && (
<Button
startIcon={<UpgradeIcon />}
variant="outlined"
color="primary"
onClick={() => navigate('/settings/upload')}
>
{LL.UPDATE()}
</Button>
)}
</ListItem>
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
<ListMenuItem <ListMenuItem
@@ -382,7 +410,7 @@ const SystemStatus: FC = () => {
bgcolor={busStatusHighlight()} bgcolor={busStatusHighlight()}
label={LL.EMS_BUS_STATUS()} label={LL.EMS_BUS_STATUS()}
text={busStatus()} text={busStatus()}
to="/system/activity" to="/status/activity"
/> />
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
@@ -392,7 +420,7 @@ const SystemStatus: FC = () => {
bgcolor="#68374d" bgcolor="#68374d"
label={LL.STATUS_OF(LL.HARDWARE())} label={LL.STATUS_OF(LL.HARDWARE())}
text={formatNumber(data.free_heap) + ' KB' + ' ' + LL.FREE_MEMORY()} text={formatNumber(data.free_heap) + ' KB' + ' ' + LL.FREE_MEMORY()}
to="/system/espsystemstatus" to="/status/hardwarestatus"
/> />
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
@@ -406,7 +434,7 @@ const SystemStatus: FC = () => {
bgcolor={networkStatusHighlight()} bgcolor={networkStatusHighlight()}
label={LL.STATUS_OF(LL.NETWORK(1))} label={LL.STATUS_OF(LL.NETWORK(1))}
text={networkStatus()} text={networkStatus()}
to="/settings/network/status" to="/status/network"
/> />
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
@@ -416,7 +444,7 @@ const SystemStatus: FC = () => {
bgcolor={activeHighlight(data.mqtt_status)} bgcolor={activeHighlight(data.mqtt_status)}
label={LL.STATUS_OF('MQTT')} label={LL.STATUS_OF('MQTT')}
text={data.mqtt_status ? LL.ACTIVE() : LL.INACTIVE(0)} text={data.mqtt_status ? LL.ACTIVE() : LL.INACTIVE(0)}
to="/settings/mqtt/status" to="/status/mqtt"
/> />
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
@@ -426,7 +454,7 @@ const SystemStatus: FC = () => {
bgcolor={ntpStatusHighlight()} bgcolor={ntpStatusHighlight()}
label={LL.STATUS_OF('NTP')} label={LL.STATUS_OF('NTP')}
text={ntpStatus()} text={ntpStatus()}
to="/settings/ntp/status" to="/status/ntp"
/> />
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
@@ -434,11 +462,10 @@ const SystemStatus: FC = () => {
disabled={!me.admin} disabled={!me.admin}
icon={SettingsInputAntennaIcon} icon={SettingsInputAntennaIcon}
bgcolor={activeHighlight(data.ap_status)} bgcolor={activeHighlight(data.ap_status)}
label={LL.ACCESS_POINT(0)} label={LL.STATUS_OF(LL.ACCESS_POINT(0))}
text={data.ap_status ? LL.ACTIVE() : LL.INACTIVE(0)} text={data.ap_status ? LL.ACTIVE() : LL.INACTIVE(0)}
to="/settings/ap/status" to="/status/ap"
/> />
<Divider variant="inset" component="li" />
</List> </List>
{renderScanDialog()} {renderScanDialog()}

View File

@@ -75,7 +75,7 @@ const levelLabel = (level: LogLevel) => {
const SystemLog: FC = () => { const SystemLog: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
useLayoutTitle(LL.SYSTEM(0)); useLayoutTitle(LL.LOG_OF(LL.SYSTEM(0)));
const { const {
loadData, loadData,

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -16,11 +16,9 @@ const LayoutAppBar: FC<LayoutAppBarProps> = ({ title, onToggleDrawer }) => {
const pathnames = useLocation() const pathnames = useLocation()
.pathname.split('/') .pathname.split('/')
.filter((x) => x); .filter((x) => x);
const show_back = pathnames.length > 1;
const navigate = useNavigate(); const navigate = useNavigate();
let show_back = false;
if (pathnames.length > 1) {
show_back = pathnames[0] !== 'system' || pathnames[1] === 'espsystemstatus';
}
return ( return (
<AppBar <AppBar

View File

@@ -128,7 +128,11 @@ const LayoutMenu: FC = () => {
</List> </List>
<List style={{ marginTop: `auto` }}> <List style={{ marginTop: `auto` }}>
<LayoutMenuItem icon={AssessmentIcon} label={LL.SYSTEM(0)} to="/system" /> <LayoutMenuItem
icon={AssessmentIcon}
label={LL.STATUS_OF('')}
to="/status"
/>
<LayoutMenuItem <LayoutMenuItem
icon={SettingsIcon} icon={SettingsIcon}
label={LL.SETTINGS(0)} label={LL.SETTINGS(0)}

View File

@@ -59,18 +59,12 @@ const LayoutMenuItem: FC<ListMenuItemProps> = ({
} }
> >
<ListItemButton component={Link} to={to}> <ListItemButton component={Link} to={to}>
<RenderIcon <RenderIcon icon={icon} bgcolor={bgcolor} label={label} text={text} />
icon={icon}
bgcolor={bgcolor}
label={label}
text={text}
to=""
/>
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
) : ( ) : (
<ListItem> <ListItem>
<RenderIcon icon={icon} bgcolor={bgcolor} label={label} text={text} to="" /> <RenderIcon icon={icon} bgcolor={bgcolor} label={label} text={text} />
</ListItem> </ListItem>
)} )}
</> </>

View File

@@ -1,34 +0,0 @@
import type { FC } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RouterTabs, useLayoutTitle, useRouterTab } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import APSettings from './APSettings';
import APStatus from './APStatus';
const AccessPoint: FC = () => {
const { LL } = useI18nContext();
useLayoutTitle(LL.ACCESS_POINT(0));
const { routerTab } = useRouterTab();
return (
<>
<RouterTabs value={routerTab}>
<Tab value="settings" label={LL.SETTINGS_OF(LL.ACCESS_POINT(1))} />
<Tab value="status" label={LL.STATUS_OF(LL.ACCESS_POINT(1))} />
</RouterTabs>
<Routes>
<Route path="status" element={<APStatus />} />
<Route path="settings" element={<APSettings />} />
<Route path="*" element={<Navigate replace to="settings" />} />
</Routes>
</>
);
};
export default AccessPoint;

View File

@@ -1,34 +0,0 @@
import type { FC } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RouterTabs, useLayoutTitle, useRouterTab } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import MqttSettings from './MqttSettings';
import MqttStatus from './MqttStatus';
const Mqtt: FC = () => {
const { LL } = useI18nContext();
useLayoutTitle('MQTT');
const { routerTab } = useRouterTab();
return (
<>
<RouterTabs value={routerTab}>
<Tab value="settings" label={LL.SETTINGS_OF('MQTT')} />
<Tab value="status" label={LL.STATUS_OF('MQTT')} />
</RouterTabs>
<Routes>
<Route path="status" element={<MqttStatus />} />
<Route path="settings" element={<MqttSettings />} />
<Route path="*" element={<Navigate replace to="settings" />} />
</Routes>
</>
);
};
export default Mqtt;

View File

@@ -1,33 +0,0 @@
import type { FC } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RouterTabs, useLayoutTitle, useRouterTab } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import NTPSettings from './NTPSettings';
import NTPStatus from './NTPStatus';
const NetworkTime: FC = () => {
const { LL } = useI18nContext();
useLayoutTitle('NTP');
const { routerTab } = useRouterTab();
return (
<>
<RouterTabs value={routerTab}>
<Tab value="settings" label={LL.SETTINGS_OF('NTP')} />
<Tab value="status" label={LL.STATUS_OF('NTP')} />
</RouterTabs>
<Routes>
<Route path="status" element={<NTPStatus />} />
<Route path="settings" element={<NTPSettings />} />
<Route path="*" element={<Navigate replace to="settings" />} />
</Routes>
</>
);
};
export default NetworkTime;

View File

@@ -1,50 +0,0 @@
import { type FC, useContext } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';
import SystemActivity from 'project/SystemActivity';
import SystemLog from './SystemLog';
import SystemStatus from './SystemStatus';
const System: FC = () => {
const { LL } = useI18nContext();
useLayoutTitle(LL.SYSTEM(0));
const { routerTab } = useRouterTab();
const { me } = useContext(AuthenticatedContext);
return (
<>
<RouterTabs value={routerTab}>
<Tab value="status" label={LL.STATUS_OF('')} />
<Tab value="activity" label={LL.ACTIVITY()} />
<Tab
disabled={!me.admin}
value="log"
label={me.admin ? LL.LOG_OF('') : ''}
/>
</RouterTabs>
<Routes>
<Route path="status" element={<SystemStatus />} />
<Route path="activity" element={<SystemActivity />} />
<Route
path="log"
element={
<RequireAdmin>
<SystemLog />
</RequireAdmin>
}
/>
<Route path="*" element={<Navigate replace to="status" />} />
</Routes>
</>
);
};
export default System;

View File

@@ -1,4 +1,4 @@
import type { busConnectionStatus } from 'project/types'; import type { busConnectionStatus } from 'app/main/types';
import type { NetworkConnectionStatus } from './network'; import type { NetworkConnectionStatus } from './network';

View File

@@ -1,5 +1,5 @@
import { isAPEnabled } from 'app/settings/APSettings';
import Schema from 'async-validator'; import Schema from 'async-validator';
import { isAPEnabled } from 'framework/ap/APSettings';
import type { APSettingsType } from 'types'; import type { APSettingsType } from 'types';
import { IP_ADDRESS_VALIDATOR } from './shared'; import { IP_ADDRESS_VALIDATOR } from './shared';

View File

@@ -411,6 +411,7 @@ const guest_signin = {
access_token: access_token:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0IiwiYWRtaW4iOmZhbHNlfQ.E_lylR_vGIQFZUGNwcl5F6OkHoaELGsC5zqhi0pAiJE' 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0IiwiYWRtaW4iOmZhbHNlfQ.E_lylR_vGIQFZUGNwcl5F6OkHoaELGsC5zqhi0pAiJE'
}; };
// modify here to simulate admin and guest logins // modify here to simulate admin and guest logins
const signin = admin_signin; const signin = admin_signin;
// const signin = guest_signin; // const signin = guest_signin;