mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
This commit is contained in:
@@ -31,8 +31,8 @@
|
|||||||
"@table-library/react-table-library": "4.1.7",
|
"@table-library/react-table-library": "4.1.7",
|
||||||
"@types/imagemin": "^8.0.5",
|
"@types/imagemin": "^8.0.5",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^20.11.27",
|
"@types/node": "^20.11.28",
|
||||||
"@types/react": "^18.2.65",
|
"@types/react": "^18.2.66",
|
||||||
"@types/react-dom": "^18.2.22",
|
"@types/react-dom": "^18.2.22",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"alova": "^2.17.1",
|
"alova": "^2.17.1",
|
||||||
@@ -46,14 +46,14 @@
|
|||||||
"react-dropzone": "^14.2.3",
|
"react-dropzone": "^14.2.3",
|
||||||
"react-icons": "^5.0.1",
|
"react-icons": "^5.0.1",
|
||||||
"react-router-dom": "^6.22.3",
|
"react-router-dom": "^6.22.3",
|
||||||
"react-toastify": "^10.0.4",
|
"react-toastify": "^10.0.5",
|
||||||
"sockette": "^2.0.6",
|
"sockette": "^2.0.6",
|
||||||
"typesafe-i18n": "^5.26.2",
|
"typesafe-i18n": "^5.26.2",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@preact/compat": "^17.1.2",
|
"@preact/compat": "^17.1.2",
|
||||||
"@preact/preset-vite": "^2.8.1",
|
"@preact/preset-vite": "^2.8.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||||
"@typescript-eslint/parser": "^7.2.0",
|
"@typescript-eslint/parser": "^7.2.0",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
@@ -64,15 +64,15 @@
|
|||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
"eslint-plugin-jsx-a11y": "^6.8.0",
|
||||||
"eslint-plugin-prettier": "alpha",
|
"eslint-plugin-prettier": "alpha",
|
||||||
"eslint-plugin-react": "^7.34.0",
|
"eslint-plugin-react": "^7.34.1",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"preact": "^10.19.6",
|
"preact": "^10.19.6",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"rollup-plugin-visualizer": "^5.12.0",
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"terser": "^5.29.1",
|
"terser": "^5.29.2",
|
||||||
"vite": "^5.1.6",
|
"vite": "^5.1.6",
|
||||||
"vite-plugin-imagemin": "^0.6.1",
|
"vite-plugin-imagemin": "^0.6.1",
|
||||||
"vite-tsconfig-paths": "^4.3.1"
|
"vite-tsconfig-paths": "^4.3.2"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.1.1"
|
"packageManager": "yarn@4.1.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const App: FC = () => {
|
|||||||
<CustomTheme>
|
<CustomTheme>
|
||||||
<AppRouting />
|
<AppRouting />
|
||||||
<ToastContainer
|
<ToastContainer
|
||||||
position="bottom-left"
|
position="bottom-right"
|
||||||
autoClose={3000}
|
autoClose={3000}
|
||||||
hideProgressBar={false}
|
hideProgressBar={false}
|
||||||
newestOnTop={false}
|
newestOnTop={false}
|
||||||
|
|||||||
@@ -1,61 +1,63 @@
|
|||||||
import { Navigate, Routes, Route } from 'react-router-dom';
|
import { Navigate, Routes, Route } from 'react-router-dom';
|
||||||
import Dashboard from './project/Dashboard';
|
|
||||||
import Help from './project/Help';
|
import Help from './project/Help';
|
||||||
import Settings from './project/Settings';
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { Layout, RequireAdmin } from 'components';
|
import { Layout, RequireAdmin } from 'components';
|
||||||
|
import Settings from 'framework/Settings';
|
||||||
import AccessPoint from 'framework/ap/AccessPoint';
|
import AccessPoint from 'framework/ap/AccessPoint';
|
||||||
import Mqtt from 'framework/mqtt/Mqtt';
|
import Mqtt from 'framework/mqtt/Mqtt';
|
||||||
import NetworkConnection from 'framework/network/NetworkConnection';
|
import NetworkConnection from 'framework/network/NetworkConnection';
|
||||||
import NetworkTime from 'framework/ntp/NetworkTime';
|
import NetworkTime from 'framework/ntp/NetworkTime';
|
||||||
|
import OTASettingsForm from 'framework/ota/OTASettingsForm';
|
||||||
import Security from 'framework/security/Security';
|
import Security from 'framework/security/Security';
|
||||||
import System from 'framework/system/System';
|
import Status from 'framework/system/Status';
|
||||||
|
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 Scheduler from 'project/Scheduler';
|
||||||
|
import Sensors from 'project/Sensors';
|
||||||
|
|
||||||
const AuthenticatedRouting: FC = () => (
|
const AuthenticatedRouting: FC = () => (
|
||||||
// const location = useLocation();
|
|
||||||
// const navigate = useNavigate();
|
|
||||||
// const handleApiResponseError = useCallback(
|
|
||||||
// (error: AxiosError) => {
|
|
||||||
// if (error.response && error.response.status === 401) {
|
|
||||||
// AuthenticationApi.storeLoginRedirect(location);
|
|
||||||
// navigate('/unauthorized');
|
|
||||||
// }
|
|
||||||
// return Promise.reject(error);
|
|
||||||
// },
|
|
||||||
// [location, navigate]
|
|
||||||
// );
|
|
||||||
// useEffect(() => {
|
|
||||||
// const axiosHandlerId = AXIOS.interceptors.response.use((response) => response, handleApiResponseError);
|
|
||||||
// return () => AXIOS.interceptors.response.eject(axiosHandlerId);
|
|
||||||
// }, [handleApiResponseError]);
|
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/dashboard/*" element={<Dashboard />} />
|
<Route path="/devices/*" element={<Devices />} />
|
||||||
|
<Route path="/sensors/*" element={<Sensors />} />
|
||||||
|
|
||||||
|
<Route path="/customizations/*" element={<Customization />} />
|
||||||
|
<Route path="/scheduler/*" element={<Scheduler />} />
|
||||||
|
<Route path="/customentities/*" element={<CustomEntities />} />
|
||||||
|
|
||||||
|
{/* TODO only show the rest here if admin */}
|
||||||
|
|
||||||
|
<Route path="/status/*" element={<Status />} />
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/settings/*"
|
path="settings/*"
|
||||||
element={
|
element={
|
||||||
<RequireAdmin>
|
<RequireAdmin>
|
||||||
<Settings />
|
<Settings />
|
||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="/help/*" element={<Help />} />
|
<Route path="/settings/network/*" element={<NetworkConnection />} />
|
||||||
|
<Route path="/settings/ems-esp/*" element={<ApplicationSettings />} />
|
||||||
<Route path="/network/*" element={<NetworkConnection />} />
|
<Route path="/settings/ap/*" element={<AccessPoint />} />
|
||||||
<Route path="/ap/*" element={<AccessPoint />} />
|
<Route path="/settings/ntp/*" element={<NetworkTime />} />
|
||||||
<Route path="/ntp/*" element={<NetworkTime />} />
|
<Route path="/settings/mqtt/*" element={<Mqtt />} />
|
||||||
<Route path="/mqtt/*" element={<Mqtt />} />
|
<Route path="/settings/ota/*" element={<OTASettingsForm />} />
|
||||||
<Route
|
<Route
|
||||||
path="/security/*"
|
path="/settings/security/*"
|
||||||
element={
|
element={
|
||||||
<RequireAdmin>
|
<RequireAdmin>
|
||||||
<Security />
|
<Security />
|
||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="/system/*" element={<System />} />
|
<Route path="/settings/upload/*" element={<UploadDownload />} />
|
||||||
|
|
||||||
|
<Route path="/help/*" element={<Help />} />
|
||||||
|
|
||||||
<Route path="/*" element={<Navigate to="/" />} />
|
<Route path="/*" element={<Navigate to="/" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export function fetchLoginRedirect(): Partial<Path> {
|
|||||||
const signInSearch = getStorage().getItem(SIGN_IN_SEARCH);
|
const signInSearch = getStorage().getItem(SIGN_IN_SEARCH);
|
||||||
clearLoginRedirect();
|
clearLoginRedirect();
|
||||||
return {
|
return {
|
||||||
pathname: signInPathname || `/dashboard`,
|
pathname: signInPathname || `/devices`,
|
||||||
search: (signInPathname && signInSearch) || undefined
|
search: (signInPathname && signInSearch) || undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import type { FC } from 'react';
|
|||||||
import type { RequiredChildrenProps } from 'utils';
|
import type { RequiredChildrenProps } from 'utils';
|
||||||
|
|
||||||
interface SectionContentProps extends RequiredChildrenProps {
|
interface SectionContentProps extends RequiredChildrenProps {
|
||||||
title: string;
|
title?: string;
|
||||||
titleGutter?: boolean;
|
|
||||||
id?: string;
|
id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,7 +12,9 @@ const SectionContent: FC<SectionContentProps> = (props) => {
|
|||||||
const { children, title, id } = props;
|
const { children, title, id } = props;
|
||||||
return (
|
return (
|
||||||
<Paper id={id} sx={{ p: 2, m: 2 }}>
|
<Paper id={id} sx={{ p: 2, m: 2 }}>
|
||||||
<Divider sx={{ pb: 2, borderColor: 'primary.main', fontSize: 20, color: 'primary.main' }}>{title}</Divider>
|
{title && (
|
||||||
|
<Divider sx={{ pb: 2, borderColor: 'primary.main', fontSize: 20, color: 'primary.main' }}>{title}</Divider>
|
||||||
|
)}
|
||||||
{children}
|
{children}
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import MenuIcon from '@mui/icons-material/Menu';
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
import { AppBar, Box, IconButton, Toolbar, Typography } from '@mui/material';
|
import { AppBar, IconButton, Toolbar, Typography } from '@mui/material';
|
||||||
import LayoutAuthMenu from './LayoutAuthMenu';
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
export const DRAWER_WIDTH = 210;
|
export const DRAWER_WIDTH = 210;
|
||||||
@@ -27,8 +26,6 @@ const LayoutAppBar: FC<LayoutAppBarProps> = ({ title, onToggleDrawer }) => (
|
|||||||
<Typography variant="h6" noWrap component="div">
|
<Typography variant="h6" noWrap component="div">
|
||||||
{title}
|
{title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box flexGrow={1} />
|
|
||||||
<LayoutAuthMenu />
|
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,165 +0,0 @@
|
|||||||
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
|
||||||
import PersonIcon from '@mui/icons-material/Person';
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Divider,
|
|
||||||
IconButton,
|
|
||||||
Popover,
|
|
||||||
Typography,
|
|
||||||
Avatar,
|
|
||||||
styled,
|
|
||||||
MenuItem,
|
|
||||||
TextField
|
|
||||||
} from '@mui/material';
|
|
||||||
import { useState, useContext } from 'react';
|
|
||||||
import type { TypographyProps } from '@mui/material';
|
|
||||||
import type { Locales } from 'i18n/i18n-types';
|
|
||||||
import type { FC, ChangeEventHandler } from 'react';
|
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
import DEflag from 'i18n/DE.svg';
|
|
||||||
import FRflag from 'i18n/FR.svg';
|
|
||||||
import GBflag from 'i18n/GB.svg';
|
|
||||||
import ITflag from 'i18n/IT.svg';
|
|
||||||
import NLflag from 'i18n/NL.svg';
|
|
||||||
import NOflag from 'i18n/NO.svg';
|
|
||||||
import PLflag from 'i18n/PL.svg';
|
|
||||||
import SKflag from 'i18n/SK.svg';
|
|
||||||
import SVflag from 'i18n/SV.svg';
|
|
||||||
import TRflag from 'i18n/TR.svg';
|
|
||||||
|
|
||||||
import { I18nContext } from 'i18n/i18n-react';
|
|
||||||
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
|
||||||
|
|
||||||
const ItemTypography = styled(Typography)<TypographyProps>({
|
|
||||||
maxWidth: '250px',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis'
|
|
||||||
});
|
|
||||||
|
|
||||||
const LayoutAuthMenu: FC = () => {
|
|
||||||
const { me, signOut } = useContext(AuthenticatedContext);
|
|
||||||
|
|
||||||
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
|
||||||
|
|
||||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
||||||
setAnchorEl(event.currentTarget);
|
|
||||||
};
|
|
||||||
|
|
||||||
const { locale, LL, setLocale } = useContext(I18nContext);
|
|
||||||
|
|
||||||
const onLocaleSelected: ChangeEventHandler<HTMLInputElement> = async ({ target }) => {
|
|
||||||
const loc = target.value as Locales;
|
|
||||||
localStorage.setItem('lang', loc);
|
|
||||||
await loadLocaleAsync(loc);
|
|
||||||
setLocale(loc);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
setAnchorEl(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const open = Boolean(anchorEl);
|
|
||||||
const id = anchorEl ? 'app-menu-popover' : undefined;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<TextField
|
|
||||||
name="locale"
|
|
||||||
InputProps={{ style: { fontSize: 10 } }}
|
|
||||||
variant="outlined"
|
|
||||||
value={locale}
|
|
||||||
onChange={onLocaleSelected}
|
|
||||||
size="small"
|
|
||||||
select
|
|
||||||
>
|
|
||||||
<MenuItem key="de" value="de">
|
|
||||||
<img src={DEflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
DE
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="en" value="en">
|
|
||||||
<img src={GBflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
EN
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="fr" value="fr">
|
|
||||||
<img src={FRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
FR
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="it" value="it">
|
|
||||||
<img src={ITflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
IT
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="nl" value="nl">
|
|
||||||
<img src={NLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
NL
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="no" value="no">
|
|
||||||
<img src={NOflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
NO
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="pl" value="pl">
|
|
||||||
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
PL
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="sk" value="sk">
|
|
||||||
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
SK
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="sv" value="sv">
|
|
||||||
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
SV
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="tr" value="tr">
|
|
||||||
<img src={TRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
TR
|
|
||||||
</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
|
|
||||||
<IconButton
|
|
||||||
id="open-auth-menu"
|
|
||||||
sx={{ ml: 1, padding: 0 }}
|
|
||||||
aria-describedby={id}
|
|
||||||
color="inherit"
|
|
||||||
onClick={handleClick}
|
|
||||||
>
|
|
||||||
<AccountCircleIcon />
|
|
||||||
</IconButton>
|
|
||||||
<Popover
|
|
||||||
id="app-menu-popover"
|
|
||||||
sx={{ mt: 1 }}
|
|
||||||
open={open}
|
|
||||||
anchorEl={anchorEl}
|
|
||||||
onClose={handleClose}
|
|
||||||
anchorOrigin={{
|
|
||||||
vertical: 'bottom',
|
|
||||||
horizontal: 'center'
|
|
||||||
}}
|
|
||||||
transformOrigin={{
|
|
||||||
vertical: 'top',
|
|
||||||
horizontal: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box display="flex" flexDirection="row" alignItems="center" p={2}>
|
|
||||||
<Avatar sx={{ width: 80, height: 80 }}>
|
|
||||||
<PersonIcon fontSize="large" />
|
|
||||||
</Avatar>
|
|
||||||
<Box pl={2}>
|
|
||||||
<ItemTypography variant="h6">{me.username}</ItemTypography>
|
|
||||||
<ItemTypography variant="body1">
|
|
||||||
{me.admin ? LL.ADMIN() : LL.GUEST()} {LL.USER(2)}
|
|
||||||
</ItemTypography>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Divider />
|
|
||||||
<Box p={1.5}>
|
|
||||||
<Button variant="outlined" fullWidth color="primary" onClick={() => signOut(true)}>
|
|
||||||
{LL.SIGN_OUT()}
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Popover>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LayoutAuthMenu;
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Box, Divider, Drawer, Toolbar, Typography, styled } from '@mui/material';
|
import { Box, Divider, Drawer, Toolbar, Typography, styled } from '@mui/material';
|
||||||
import { DRAWER_WIDTH } from './Layout';
|
import { DRAWER_WIDTH } from './Layout';
|
||||||
|
|
||||||
import LayoutMenu from './LayoutMenu';
|
import LayoutMenu from './LayoutMenu';
|
||||||
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { PROJECT_NAME } from 'api/env';
|
import { PROJECT_NAME } from 'api/env';
|
||||||
|
|||||||
@@ -1,53 +1,188 @@
|
|||||||
import AccessTimeIcon from '@mui/icons-material/AccessTime';
|
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
||||||
|
import AssessmentIcon from '@mui/icons-material/Assessment';
|
||||||
import DashboardIcon from '@mui/icons-material/Dashboard';
|
import CategoryIcon from '@mui/icons-material/Category';
|
||||||
import DeviceHubIcon from '@mui/icons-material/DeviceHub';
|
import ConstructionIcon from '@mui/icons-material/Construction';
|
||||||
import InfoIcon from '@mui/icons-material/Info';
|
import InfoIcon from '@mui/icons-material/Info';
|
||||||
import LockIcon from '@mui/icons-material/Lock';
|
import MoreTimeIcon from '@mui/icons-material/MoreTime';
|
||||||
|
import PersonIcon from '@mui/icons-material/Person';
|
||||||
|
import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd';
|
||||||
|
import SensorsIcon from '@mui/icons-material/Sensors';
|
||||||
import SettingsIcon from '@mui/icons-material/Settings';
|
import SettingsIcon from '@mui/icons-material/Settings';
|
||||||
import SettingsEthernetIcon from '@mui/icons-material/SettingsEthernet';
|
import {
|
||||||
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
Divider,
|
||||||
import TuneIcon from '@mui/icons-material/Tune';
|
List,
|
||||||
import { Divider, List } from '@mui/material';
|
Box,
|
||||||
import { useContext } from 'react';
|
Button,
|
||||||
import type { FC } from 'react';
|
Popover,
|
||||||
|
Avatar,
|
||||||
|
MenuItem,
|
||||||
|
TextField,
|
||||||
|
ListItem,
|
||||||
|
ListItemButton,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemText
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import { useContext, useState } from 'react';
|
||||||
|
import type { Locales } from 'i18n/i18n-types';
|
||||||
|
import type { FC, ChangeEventHandler } from 'react';
|
||||||
import LayoutMenuItem from 'components/layout/LayoutMenuItem';
|
import LayoutMenuItem from 'components/layout/LayoutMenuItem';
|
||||||
|
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import DEflag from 'i18n/DE.svg';
|
||||||
|
import FRflag from 'i18n/FR.svg';
|
||||||
|
import GBflag from 'i18n/GB.svg';
|
||||||
|
import ITflag from 'i18n/IT.svg';
|
||||||
|
import NLflag from 'i18n/NL.svg';
|
||||||
|
import NOflag from 'i18n/NO.svg';
|
||||||
|
import PLflag from 'i18n/PL.svg';
|
||||||
|
import SKflag from 'i18n/SK.svg';
|
||||||
|
import SVflag from 'i18n/SV.svg';
|
||||||
|
import TRflag from 'i18n/TR.svg';
|
||||||
|
|
||||||
|
import { I18nContext } from 'i18n/i18n-react';
|
||||||
|
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
||||||
|
|
||||||
const LayoutMenu: FC = () => {
|
const LayoutMenu: FC = () => {
|
||||||
const authenticatedContext = useContext(AuthenticatedContext);
|
const { me, signOut } = useContext(AuthenticatedContext);
|
||||||
const { LL } = useI18nContext();
|
const { locale, LL, setLocale } = useContext(I18nContext);
|
||||||
|
|
||||||
|
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
|
const open = Boolean(anchorEl);
|
||||||
|
const id = anchorEl ? 'app-menu-popover' : undefined;
|
||||||
|
|
||||||
|
const onLocaleSelected: ChangeEventHandler<HTMLInputElement> = async ({ target }) => {
|
||||||
|
const loc = target.value as Locales;
|
||||||
|
localStorage.setItem('lang', loc);
|
||||||
|
await loadLocaleAsync(loc);
|
||||||
|
setLocale(loc);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClick = (event: any) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<List disablePadding component="nav">
|
<List component="nav">
|
||||||
<LayoutMenuItem icon={DashboardIcon} label={LL.DASHBOARD()} to={`/dashboard`} />
|
<LayoutMenuItem icon={CategoryIcon} label={LL.DEVICES()} to={`/devices`} />
|
||||||
<LayoutMenuItem
|
<LayoutMenuItem icon={SensorsIcon} label={LL.SENSORS()} to={`/sensors`} />
|
||||||
icon={TuneIcon}
|
|
||||||
label={LL.SETTINGS_OF('')}
|
|
||||||
to={`/settings`}
|
|
||||||
disabled={!authenticatedContext.me.admin}
|
|
||||||
/>
|
|
||||||
<LayoutMenuItem icon={InfoIcon} label={LL.HELP_OF('')} to={`/help`} />
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
<LayoutMenuItem icon={ConstructionIcon} label={LL.CUSTOMIZATIONS()} to={`/customizations`} />
|
||||||
|
<LayoutMenuItem icon={MoreTimeIcon} label={LL.SCHEDULER()} to={`/scheduler`} />
|
||||||
|
<LayoutMenuItem icon={PlaylistAddIcon} label={LL.CUSTOM_ENTITIES(0)} to={`/customentities`} />
|
||||||
</List>
|
</List>
|
||||||
<List disablePadding component="nav">
|
<List style={{ marginTop: `auto` }}>
|
||||||
<LayoutMenuItem icon={SettingsEthernetIcon} label={LL.NETWORK(0)} to="/network" />
|
<LayoutMenuItem icon={AssessmentIcon} label={LL.STATUS_OF('')} to="/status" />
|
||||||
<LayoutMenuItem icon={SettingsInputAntennaIcon} label={LL.ACCESS_POINT(0)} to="/ap" />
|
<LayoutMenuItem icon={SettingsIcon} label={LL.SETTINGS(0)} disabled={!me.admin} to="/settings" />
|
||||||
<LayoutMenuItem icon={AccessTimeIcon} label="NTP" to="/ntp" />
|
<LayoutMenuItem icon={InfoIcon} label={LL.HELP_OF('')} to={`/help`} />
|
||||||
<LayoutMenuItem icon={DeviceHubIcon} label="MQTT" to="/mqtt" />
|
|
||||||
<LayoutMenuItem
|
|
||||||
icon={LockIcon}
|
|
||||||
label={LL.SECURITY(0)}
|
|
||||||
to="/security"
|
|
||||||
disabled={!authenticatedContext.me.admin}
|
|
||||||
/>
|
|
||||||
<LayoutMenuItem icon={SettingsIcon} label={LL.SYSTEM(0)} to="/system" />
|
|
||||||
</List>
|
</List>
|
||||||
|
<Divider />
|
||||||
|
<List>
|
||||||
|
<ListItem disablePadding onClick={handleClick}>
|
||||||
|
<ListItemButton>
|
||||||
|
<ListItemIcon>
|
||||||
|
<AccountCircleIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>{me.username}</ListItemText>
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
|
||||||
|
<Popover
|
||||||
|
id={id}
|
||||||
|
sx={{ mt: 1 }}
|
||||||
|
open={open}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
onClose={handleClose}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'bottom',
|
||||||
|
horizontal: 'center'
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
p={2}
|
||||||
|
sx={{
|
||||||
|
borderRadius: 2,
|
||||||
|
border: '2px solid grey'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<List>
|
||||||
|
<ListItem disablePadding>
|
||||||
|
<Avatar sx={{ bgcolor: '#b1395f', color: 'white' }}>
|
||||||
|
<PersonIcon />
|
||||||
|
</Avatar>
|
||||||
|
<ListItemText sx={{ pl: 2 }} primary={me.username} secondary={me.admin ? LL.ADMIN() : LL.GUEST()} />
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
<Box p={2}>
|
||||||
|
<TextField
|
||||||
|
name="locale"
|
||||||
|
InputProps={{ style: { fontSize: 10 } }}
|
||||||
|
variant="outlined"
|
||||||
|
value={locale}
|
||||||
|
onChange={onLocaleSelected}
|
||||||
|
size="small"
|
||||||
|
select
|
||||||
|
>
|
||||||
|
<MenuItem key="de" value="de">
|
||||||
|
<img src={DEflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
DE
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="en" value="en">
|
||||||
|
<img src={GBflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
EN
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="fr" value="fr">
|
||||||
|
<img src={FRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
FR
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="it" value="it">
|
||||||
|
<img src={ITflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
IT
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="nl" value="nl">
|
||||||
|
<img src={NLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
NL
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="no" value="no">
|
||||||
|
<img src={NOflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
NO
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="pl" value="pl">
|
||||||
|
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
PL
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="sk" value="sk">
|
||||||
|
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
SK
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="sv" value="sv">
|
||||||
|
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
SV
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="tr" value="tr">
|
||||||
|
<img src={TRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
TR
|
||||||
|
</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Button variant="outlined" fullWidth color="primary" onClick={() => signOut(true)}>
|
||||||
|
{LL.SIGN_OUT()}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Popover>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import { useLocation } from 'react-router-dom';
|
import { useMatch, useResolvedPath } from 'react-router-dom';
|
||||||
|
|
||||||
export const useRouterTab = () => {
|
export const useRouterTab = () => {
|
||||||
const loc = useLocation().pathname;
|
const routerTabPathMatch = useMatch(useResolvedPath(':tab').pathname);
|
||||||
const routerTab = loc.substring(0, loc.lastIndexOf('/')) ? loc : false;
|
const routerTab = routerTabPathMatch?.params?.tab || false;
|
||||||
|
|
||||||
// const routerTabPath = useResolvedPath(':tab');
|
|
||||||
// const routerTabPathMatch = useMatch(routerTabPath.pathname);
|
|
||||||
// const routerTab = routerTabPathMatch?.params?.tab || false;
|
|
||||||
|
|
||||||
return { routerTab } as const;
|
return { routerTab } as const;
|
||||||
};
|
};
|
||||||
|
|||||||
171
interface/src/framework/Settings.tsx
Normal file
171
interface/src/framework/Settings.tsx
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
import AccessTimeIcon from '@mui/icons-material/AccessTime';
|
||||||
|
import CastIcon from '@mui/icons-material/Cast';
|
||||||
|
import DeviceHubIcon from '@mui/icons-material/DeviceHub';
|
||||||
|
import ImportExportIcon from '@mui/icons-material/ImportExport';
|
||||||
|
import LockIcon from '@mui/icons-material/Lock';
|
||||||
|
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
|
||||||
|
import SettingsEthernetIcon from '@mui/icons-material/SettingsEthernet';
|
||||||
|
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
||||||
|
import TuneIcon from '@mui/icons-material/Tune';
|
||||||
|
import { List, ListItem, ListItemAvatar, ListItemText, Avatar, ListItemButton, ListItemIcon } from '@mui/material';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
import { SectionContent, useLayoutTitle } from 'components';
|
||||||
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
|
const Settings: FC = () => {
|
||||||
|
const { LL } = useI18nContext();
|
||||||
|
useLayoutTitle(LL.SETTINGS(0));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SectionContent>
|
||||||
|
<List sx={{ borderRadius: 3, border: '2px solid grey' }}>
|
||||||
|
<ListItem
|
||||||
|
disablePadding
|
||||||
|
secondaryAction={
|
||||||
|
<ListItemIcon style={{ justifyContent: 'right', verticalAlign: 'middle' }}>
|
||||||
|
<NavigateNextIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton component={Link} to="ems-esp">
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#134ba2', color: 'white' }}>
|
||||||
|
<TuneIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary={LL.APPLICATION_SETTINGS()} secondary="Modify EMS-ESP system settings" />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem
|
||||||
|
disablePadding
|
||||||
|
secondaryAction={
|
||||||
|
<ListItemIcon style={{ justifyContent: 'right', color: 'lightblue', verticalAlign: 'middle' }}>
|
||||||
|
<NavigateNextIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton component={Link} to="network">
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#40828f', color: 'white' }}>
|
||||||
|
<SettingsEthernetIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary={LL.NETWORK(0)} secondary="Configure Network settings" />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem
|
||||||
|
disablePadding
|
||||||
|
secondaryAction={
|
||||||
|
<ListItemIcon style={{ justifyContent: 'right', color: 'lightblue', verticalAlign: 'middle' }}>
|
||||||
|
<NavigateNextIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton component={Link} to="ap">
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#5f9a5f', color: 'white' }}>
|
||||||
|
<SettingsInputAntennaIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary={LL.ACCESS_POINT(0)} secondary="Configure Access Point" />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem
|
||||||
|
disablePadding
|
||||||
|
secondaryAction={
|
||||||
|
<ListItemIcon style={{ justifyContent: 'right', color: 'lightblue', verticalAlign: 'middle' }}>
|
||||||
|
<NavigateNextIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton component={Link} to="ntp">
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#c5572c', color: 'white' }}>
|
||||||
|
<AccessTimeIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary="NTP" secondary="Configure Network Time" />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem
|
||||||
|
disablePadding
|
||||||
|
secondaryAction={
|
||||||
|
<ListItemIcon style={{ justifyContent: 'right', color: 'lightblue', verticalAlign: 'middle' }}>
|
||||||
|
<NavigateNextIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton component={Link} to="mqtt">
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#68374d', color: 'white' }}>
|
||||||
|
<DeviceHubIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary="MQTT" secondary="Configure MQTT" />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem
|
||||||
|
disablePadding
|
||||||
|
secondaryAction={
|
||||||
|
<ListItemIcon style={{ justifyContent: 'right', color: 'lightblue', verticalAlign: 'middle' }}>
|
||||||
|
<NavigateNextIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton component={Link} to="ota">
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#efc34b', color: 'white' }}>
|
||||||
|
<CastIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary="OTA" secondary="Configure OTA" />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem
|
||||||
|
disablePadding
|
||||||
|
secondaryAction={
|
||||||
|
<ListItemIcon style={{ justifyContent: 'right', color: 'lightblue', verticalAlign: 'middle' }}>
|
||||||
|
<NavigateNextIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton component={Link} to="security">
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#b1395f', color: 'white' }}>
|
||||||
|
<LockIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary={LL.SECURITY(0)} secondary="Configure user administration" />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem
|
||||||
|
disablePadding
|
||||||
|
secondaryAction={
|
||||||
|
<ListItemIcon style={{ justifyContent: 'right', color: 'lightblue', verticalAlign: 'middle' }}>
|
||||||
|
<NavigateNextIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ListItemButton component={Link} to="upload">
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar sx={{ bgcolor: '#5d89f7', color: 'white' }}>
|
||||||
|
<ImportExportIcon />
|
||||||
|
</Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary={LL.UPLOAD_DOWNLOAD()} secondary="Upload/Download Settings and Firmware" />
|
||||||
|
</ListItemButton>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
</SectionContent>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Settings;
|
||||||
@@ -205,7 +205,7 @@ const APSettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF(LL.ACCESS_POINT(1))} titleGutter>
|
<SectionContent title={LL.SETTINGS_OF(LL.ACCESS_POINT(1))}>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
|||||||
@@ -99,11 +99,7 @@ const APStatusForm: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return <SectionContent title={LL.STATUS_OF(LL.ACCESS_POINT(1))}>{content()}</SectionContent>;
|
||||||
<SectionContent title={LL.STATUS_OF(LL.ACCESS_POINT(1))} titleGutter>
|
|
||||||
{content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default APStatusForm;
|
export default APStatusForm;
|
||||||
|
|||||||
@@ -22,16 +22,11 @@ const AccessPoint: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/ap/status" label={LL.STATUS_OF(LL.ACCESS_POINT(1))} />
|
<Tab value="settings" label={LL.SETTINGS_OF(LL.ACCESS_POINT(1))} disabled={!authenticatedContext.me.admin} />
|
||||||
<Tab
|
<Tab value="status" label={LL.STATUS_OF(LL.ACCESS_POINT(1))} />
|
||||||
value="/ap/settings"
|
|
||||||
label={LL.SETTINGS_OF(LL.ACCESS_POINT(1))}
|
|
||||||
disabled={!authenticatedContext.me.admin}
|
|
||||||
/>
|
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<APStatusForm />} />
|
<Route path="status" element={<APStatusForm />} />
|
||||||
<Route index element={<Navigate to="status" />} />
|
|
||||||
<Route
|
<Route
|
||||||
path="settings"
|
path="settings"
|
||||||
element={
|
element={
|
||||||
@@ -40,7 +35,7 @@ const AccessPoint: FC = () => {
|
|||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="*" element={<Navigate replace to="/ap/status" />} />
|
<Route path="*" element={<Navigate replace to="settings" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ const Mqtt: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/mqtt/status" label={LL.STATUS_OF('MQTT')} />
|
<Tab value="settings" label={LL.SETTINGS_OF('MQTT')} disabled={!authenticatedContext.me.admin} />
|
||||||
<Tab value="/mqtt/settings" label={LL.SETTINGS_OF('MQTT')} disabled={!authenticatedContext.me.admin} />
|
<Tab value="status" label={LL.STATUS_OF('MQTT')} />
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<MqttStatusForm />} />
|
<Route path="status" element={<MqttStatusForm />} />
|
||||||
@@ -34,7 +34,7 @@ const Mqtt: FC = () => {
|
|||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="*" element={<Navigate replace to="/mqtt/status" />} />
|
<Route path="*" element={<Navigate replace to="settings" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -449,7 +449,7 @@ const MqttSettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF('MQTT')} titleGutter>
|
<SectionContent title={LL.SETTINGS_OF('MQTT')}>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
|||||||
@@ -146,11 +146,7 @@ const MqttStatusForm: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return <SectionContent title={LL.STATUS_OF('MQTT')}>{content()}</SectionContent>;
|
||||||
<SectionContent title={LL.STATUS_OF('MQTT')} titleGutter>
|
|
||||||
{content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MqttStatusForm;
|
export default MqttStatusForm;
|
||||||
|
|||||||
@@ -44,13 +44,9 @@ const NetworkConnection: FC = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/network/status" label={LL.STATUS_OF(LL.NETWORK(1))} />
|
<Tab value="settings" label={LL.SETTINGS_OF(LL.NETWORK(1))} disabled={!authenticatedContext.me.admin} />
|
||||||
<Tab value="/network/scan" label={LL.NETWORK_SCAN()} disabled={!authenticatedContext.me.admin} />
|
<Tab value="scan" label={LL.NETWORK_SCAN()} disabled={!authenticatedContext.me.admin} />
|
||||||
<Tab
|
<Tab value="status" label={LL.STATUS_OF(LL.NETWORK(1))} />
|
||||||
value="/network/settings"
|
|
||||||
label={LL.SETTINGS_OF(LL.NETWORK(1))}
|
|
||||||
disabled={!authenticatedContext.me.admin}
|
|
||||||
/>
|
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<NetworkStatusForm />} />
|
<Route path="status" element={<NetworkStatusForm />} />
|
||||||
@@ -70,7 +66,7 @@ const NetworkConnection: FC = () => {
|
|||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="*" element={<Navigate replace to="/network/status" />} />
|
<Route path="*" element={<Navigate replace to="settings" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</WiFiConnectionContext.Provider>
|
</WiFiConnectionContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF(LL.NETWORK(1))} titleGutter>
|
<SectionContent title={LL.SETTINGS_OF(LL.NETWORK(1))}>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{restarting ? <RestartMonitor /> : content()}
|
{restarting ? <RestartMonitor /> : content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
|||||||
@@ -193,11 +193,7 @@ const NetworkStatusForm: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return <SectionContent title={LL.STATUS_OF(LL.NETWORK(1))}>{content()}</SectionContent>;
|
||||||
<SectionContent title={LL.STATUS_OF(LL.NETWORK(1))} titleGutter>
|
|
||||||
{content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NetworkStatusForm;
|
export default NetworkStatusForm;
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ const NTPSettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF('NTP')} titleGutter>
|
<SectionContent title={LL.SETTINGS_OF('NTP')}>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
|||||||
@@ -216,11 +216,7 @@ const NTPStatusForm: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return <SectionContent title={LL.STATUS_OF('NTP')}>{content()}</SectionContent>;
|
||||||
<SectionContent title={LL.STATUS_OF('NTP')} titleGutter>
|
|
||||||
{content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NTPStatusForm;
|
export default NTPStatusForm;
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ const NetworkTime: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/ntp/status" label={LL.STATUS_OF('NTP')} />
|
<Tab value="settings" label={LL.SETTINGS_OF('NTP')} disabled={!authenticatedContext.me.admin} />
|
||||||
<Tab value="/ntp/settings" label={LL.SETTINGS_OF('NTP')} disabled={!authenticatedContext.me.admin} />
|
<Tab value="status" label={LL.STATUS_OF('NTP')} />
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<NTPStatusForm />} />
|
<Route path="status" element={<NTPStatusForm />} />
|
||||||
@@ -33,7 +33,7 @@ const NetworkTime: FC = () => {
|
|||||||
</RequireAdmin>
|
</RequireAdmin>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="*" element={<Navigate replace to="/ntp/status" />} />
|
<Route path="*" element={<Navigate replace to="settings" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import {
|
|||||||
SectionContent,
|
SectionContent,
|
||||||
ValidatedPasswordField,
|
ValidatedPasswordField,
|
||||||
ValidatedTextField,
|
ValidatedTextField,
|
||||||
BlockNavigation
|
BlockNavigation,
|
||||||
|
useLayoutTitle
|
||||||
} from 'components';
|
} from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
@@ -61,6 +62,8 @@ const OTASettingsForm: FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useLayoutTitle('OTA');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
@@ -117,7 +120,7 @@ const OTASettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF('OTA')} titleGutter>
|
<SectionContent title={LL.SETTINGS_OF('OTA')}>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
@@ -232,7 +232,7 @@ const ManageUsersForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.MANAGE_USERS()} titleGutter>
|
<SectionContent title={LL.MANAGE_USERS()}>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ const Security: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterTabs value={routerTab}>
|
<RouterTabs value={routerTab}>
|
||||||
<Tab value="/security/users" label={LL.MANAGE_USERS()} />
|
<Tab value="settings" label={LL.SETTINGS_OF(LL.SECURITY(1))} />
|
||||||
<Tab value="/security/settings" label={LL.SETTINGS_OF(LL.SECURITY(1))} />
|
<Tab value="users" label={LL.MANAGE_USERS()} />
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="users" element={<ManageUsersForm />} />
|
<Route path="users" element={<ManageUsersForm />} />
|
||||||
<Route path="settings" element={<SecuritySettingsForm />} />
|
<Route path="settings" element={<SecuritySettingsForm />} />
|
||||||
<Route path="*" element={<Navigate replace to="/security/users" />} />
|
<Route path="*" element={<Navigate replace to="settings" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ const SecuritySettingsForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF(LL.SECURITY(1))} titleGutter>
|
<SectionContent title={LL.SETTINGS_OF(LL.SECURITY(1))}>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
|||||||
36
interface/src/framework/system/Status.tsx
Normal file
36
interface/src/framework/system/Status.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { Tab } from '@mui/material';
|
||||||
|
import { Navigate, Routes, Route } from 'react-router-dom';
|
||||||
|
import SystemLog from './SystemLog';
|
||||||
|
import SystemStatusForm from './SystemStatusForm';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
import { useRouterTab, RouterTabs, useLayoutTitle } from 'components';
|
||||||
|
|
||||||
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
import EMSStatus from 'project/EMSStatus';
|
||||||
|
|
||||||
|
const Status: FC = () => {
|
||||||
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
|
useLayoutTitle(LL.STATUS_OF(''));
|
||||||
|
|
||||||
|
const { routerTab } = useRouterTab();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<RouterTabs value={routerTab}>
|
||||||
|
<Tab value="status" label={LL.SYSTEM(1)} />
|
||||||
|
<Tab value="emsesp-status" label="EMS-ESP" />
|
||||||
|
<Tab value="log" label={LL.LOG_OF(LL.SYSTEM(2))} />
|
||||||
|
</RouterTabs>
|
||||||
|
<Routes>
|
||||||
|
<Route path="status" element={<SystemStatusForm />} />
|
||||||
|
<Route path="emsesp-status" element={<EMSStatus />} />
|
||||||
|
<Route path="log" element={<SystemLog />} />
|
||||||
|
<Route path="*" element={<Navigate replace to="status" />} />
|
||||||
|
</Routes>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Status;
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import { Tab } from '@mui/material';
|
|
||||||
import { useContext } from 'react';
|
|
||||||
import { Navigate, Routes, Route } from 'react-router-dom';
|
|
||||||
import OTASettingsForm from './OTASettingsForm';
|
|
||||||
import SystemLog from './SystemLog';
|
|
||||||
import SystemStatusForm from './SystemStatusForm';
|
|
||||||
import UploadFileForm from './UploadFileForm';
|
|
||||||
import type { FC } from 'react';
|
|
||||||
|
|
||||||
import { useRouterTab, RouterTabs, useLayoutTitle, RequireAdmin } from 'components';
|
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
|
||||||
|
|
||||||
const System: FC = () => {
|
|
||||||
const { LL } = useI18nContext();
|
|
||||||
|
|
||||||
useLayoutTitle(LL.SYSTEM(0));
|
|
||||||
|
|
||||||
const { me } = useContext(AuthenticatedContext);
|
|
||||||
const { routerTab } = useRouterTab();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<RouterTabs value={routerTab}>
|
|
||||||
<Tab value="/system/status" label={LL.STATUS_OF(LL.SYSTEM(1))} />
|
|
||||||
<Tab value="/system/log" label={LL.LOG_OF(LL.SYSTEM(2))} />
|
|
||||||
<Tab value="/system/ota" label={LL.SETTINGS_OF('OTA')} disabled={!me.admin} />
|
|
||||||
<Tab value="/system/upload" label={LL.UPLOAD_DOWNLOAD()} disabled={!me.admin} />
|
|
||||||
</RouterTabs>
|
|
||||||
<Routes>
|
|
||||||
<Route path="status" element={<SystemStatusForm />} />
|
|
||||||
<Route path="log" element={<SystemLog />} />
|
|
||||||
<Route
|
|
||||||
path="ota"
|
|
||||||
element={
|
|
||||||
<RequireAdmin>
|
|
||||||
<OTASettingsForm />
|
|
||||||
</RequireAdmin>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="upload"
|
|
||||||
element={
|
|
||||||
<RequireAdmin>
|
|
||||||
<UploadFileForm />
|
|
||||||
</RequireAdmin>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route path="*" element={<Navigate replace to="/system/status" />} />
|
|
||||||
</Routes>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default System;
|
|
||||||
@@ -345,7 +345,7 @@ const SystemStatusForm: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.STATUS_OF(LL.SYSTEM(1))} titleGutter>
|
<SectionContent title={LL.STATUS_OF(LL.SYSTEM(1))}>
|
||||||
{restarting ? <RestartMonitor /> : content()}
|
{restarting ? <RestartMonitor /> : content()}
|
||||||
{data && (
|
{data && (
|
||||||
<SystemStatusVersionDialog
|
<SystemStatusVersionDialog
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import { toast } from 'react-toastify';
|
|||||||
import RestartMonitor from './RestartMonitor';
|
import RestartMonitor from './RestartMonitor';
|
||||||
|
|
||||||
import * as SystemApi from 'api/system';
|
import * as SystemApi from 'api/system';
|
||||||
import { SectionContent, SingleUpload } from 'components';
|
import { SectionContent, SingleUpload, useLayoutTitle } from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import * as EMSESP from 'project/api';
|
import * as EMSESP from 'project/api';
|
||||||
|
|
||||||
const UploadFileForm: FC = () => {
|
const UploadDownload: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [restarting, setRestarting] = useState<boolean>();
|
const [restarting, setRestarting] = useState<boolean>();
|
||||||
const [md5, setMd5] = useState<string>();
|
const [md5, setMd5] = useState<string>();
|
||||||
@@ -127,6 +127,8 @@ const UploadFileForm: FC = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useLayoutTitle(LL.UPLOAD_DOWNLOAD());
|
||||||
|
|
||||||
const content = () => (
|
const content = () => (
|
||||||
<>
|
<>
|
||||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||||
@@ -214,11 +216,7 @@ const UploadFileForm: FC = () => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
return (
|
return <SectionContent title={LL.UPLOAD_DOWNLOAD()}>{restarting ? <RestartMonitor /> : content()}</SectionContent>;
|
||||||
<SectionContent title={LL.UPLOAD_DOWNLOAD()} titleGutter>
|
|
||||||
{restarting ? <RestartMonitor /> : content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UploadFileForm;
|
export default UploadDownload;
|
||||||
@@ -12,7 +12,6 @@ const de: Translation = {
|
|||||||
USERNAME: 'Nutzername',
|
USERNAME: 'Nutzername',
|
||||||
PASSWORD: 'Passwort',
|
PASSWORD: 'Passwort',
|
||||||
SU_PASSWORD: 'su Passwort',
|
SU_PASSWORD: 'su Passwort',
|
||||||
DASHBOARD: 'Kontrollzentrum',
|
|
||||||
SETTINGS_OF: '{0} Einstellungen',
|
SETTINGS_OF: '{0} Einstellungen',
|
||||||
HELP_OF: '{0} Hilfe',
|
HELP_OF: '{0} Hilfe',
|
||||||
LOGGED_IN: 'Eingeloggt als {name}',
|
LOGGED_IN: 'Eingeloggt als {name}',
|
||||||
@@ -37,8 +36,6 @@ const de: Translation = {
|
|||||||
BRAND: 'Marke',
|
BRAND: 'Marke',
|
||||||
ENTITY_NAME: 'Entitätsname',
|
ENTITY_NAME: 'Entitätsname',
|
||||||
VALUE: '{{Wert|wert}}',
|
VALUE: '{{Wert|wert}}',
|
||||||
DEVICE_DATA: 'Gerätedaten',
|
|
||||||
SENSOR_DATA: 'Sensordaten',
|
|
||||||
DEVICES: 'Geräte',
|
DEVICES: 'Geräte',
|
||||||
SENSORS: 'Sensoren',
|
SENSORS: 'Sensoren',
|
||||||
RUN_COMMAND: 'Befehl ausführen',
|
RUN_COMMAND: 'Befehl ausführen',
|
||||||
@@ -163,9 +160,7 @@ const de: Translation = {
|
|||||||
OPTIONS: 'Optionen',
|
OPTIONS: 'Optionen',
|
||||||
NAME: 'Name',
|
NAME: 'Name',
|
||||||
CUSTOMIZATIONS_RESET: 'Möchten Sie wirklich alle Anpassungen entfernen, einschließlich der benutzerdefinierten Einstellungen der Temperatur- und Analogsensoren?',
|
CUSTOMIZATIONS_RESET: 'Möchten Sie wirklich alle Anpassungen entfernen, einschließlich der benutzerdefinierten Einstellungen der Temperatur- und Analogsensoren?',
|
||||||
DEVICE_ENTITIES: 'Geräteentitäten',
|
|
||||||
SUPPORT_INFORMATION: 'Unterstützende Informationen',
|
SUPPORT_INFORMATION: 'Unterstützende Informationen',
|
||||||
CLICK_HERE: 'Hier klicken',
|
|
||||||
HELP_INFORMATION_1: 'EMS-ESP Konfigurationsanweisungen und mehr finden Sie im Online-Wiki',
|
HELP_INFORMATION_1: 'EMS-ESP Konfigurationsanweisungen und mehr finden Sie im Online-Wiki',
|
||||||
HELP_INFORMATION_2: 'Für einen Live-Community-Chat besuchen Sie unseren Discord-Server',
|
HELP_INFORMATION_2: 'Für einen Live-Community-Chat besuchen Sie unseren Discord-Server',
|
||||||
HELP_INFORMATION_3: 'Um neue Funktionen anzufragen oder Fehler zu melden, eröffnen Sie ein Issue auf Github',
|
HELP_INFORMATION_3: 'Um neue Funktionen anzufragen oder Fehler zu melden, eröffnen Sie ein Issue auf Github',
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const en: Translation = {
|
|||||||
USERNAME: 'Username',
|
USERNAME: 'Username',
|
||||||
PASSWORD: 'Password',
|
PASSWORD: 'Password',
|
||||||
SU_PASSWORD: 'su Password',
|
SU_PASSWORD: 'su Password',
|
||||||
DASHBOARD: 'Dashboard',
|
|
||||||
SETTINGS_OF: '{0} Settings',
|
SETTINGS_OF: '{0} Settings',
|
||||||
HELP_OF: '{0} Help',
|
HELP_OF: '{0} Help',
|
||||||
LOGGED_IN: 'Logged in as {name}',
|
LOGGED_IN: 'Logged in as {name}',
|
||||||
@@ -37,8 +36,6 @@ const en: Translation = {
|
|||||||
BRAND: 'Brand',
|
BRAND: 'Brand',
|
||||||
ENTITY_NAME: 'Entity Name',
|
ENTITY_NAME: 'Entity Name',
|
||||||
VALUE: '{{Value|value}}',
|
VALUE: '{{Value|value}}',
|
||||||
DEVICE_DATA: 'Device Data',
|
|
||||||
SENSOR_DATA: 'Sensor Data',
|
|
||||||
DEVICES: 'Devices',
|
DEVICES: 'Devices',
|
||||||
SENSORS: 'Sensors',
|
SENSORS: 'Sensors',
|
||||||
RUN_COMMAND: 'Call Command',
|
RUN_COMMAND: 'Call Command',
|
||||||
@@ -163,9 +160,7 @@ const en: Translation = {
|
|||||||
OPTIONS: 'Options',
|
OPTIONS: 'Options',
|
||||||
NAME: 'Name',
|
NAME: 'Name',
|
||||||
CUSTOMIZATIONS_RESET: 'Are you sure you want remove all customizations including the custom settings of the Temperature and Analog sensors?',
|
CUSTOMIZATIONS_RESET: 'Are you sure you want remove all customizations including the custom settings of the Temperature and Analog sensors?',
|
||||||
DEVICE_ENTITIES: 'Device Entities',
|
|
||||||
SUPPORT_INFORMATION: 'Support Information',
|
SUPPORT_INFORMATION: 'Support Information',
|
||||||
CLICK_HERE: 'Click Here',
|
|
||||||
HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP',
|
HELP_INFORMATION_1: 'Visit the online wiki to get instructions on how to configure EMS-ESP',
|
||||||
HELP_INFORMATION_2: 'For live community chat join our Discord server',
|
HELP_INFORMATION_2: 'For live community chat join our Discord server',
|
||||||
HELP_INFORMATION_3: 'To request a feature or report a bug',
|
HELP_INFORMATION_3: 'To request a feature or report a bug',
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const fr: Translation = {
|
|||||||
USERNAME: 'Nom d\'utilisateur',
|
USERNAME: 'Nom d\'utilisateur',
|
||||||
PASSWORD: 'Mot de passe',
|
PASSWORD: 'Mot de passe',
|
||||||
SU_PASSWORD: 'Mot de passe su',
|
SU_PASSWORD: 'Mot de passe su',
|
||||||
DASHBOARD: 'Tableau de bord',
|
|
||||||
SETTINGS_OF: 'Paramètres {0}',
|
SETTINGS_OF: 'Paramètres {0}',
|
||||||
HELP_OF: 'Aide {0}',
|
HELP_OF: 'Aide {0}',
|
||||||
LOGGED_IN: 'Connecté en tant que {name}',
|
LOGGED_IN: 'Connecté en tant que {name}',
|
||||||
@@ -37,8 +36,6 @@ const fr: Translation = {
|
|||||||
BRAND: 'Marque',
|
BRAND: 'Marque',
|
||||||
ENTITY_NAME: 'Nom de l\'entité',
|
ENTITY_NAME: 'Nom de l\'entité',
|
||||||
VALUE: 'Valeur',
|
VALUE: 'Valeur',
|
||||||
DEVICE_DATA: 'Données des appareils',
|
|
||||||
SENSOR_DATA: 'Données des capteurs',
|
|
||||||
DEVICES: 'Appareils',
|
DEVICES: 'Appareils',
|
||||||
SENSORS: 'Capteurs',
|
SENSORS: 'Capteurs',
|
||||||
RUN_COMMAND: 'Lancer une commande',
|
RUN_COMMAND: 'Lancer une commande',
|
||||||
@@ -163,9 +160,7 @@ const fr: Translation = {
|
|||||||
OPTIONS: 'Options',
|
OPTIONS: 'Options',
|
||||||
NAME: 'Nom',
|
NAME: 'Nom',
|
||||||
CUSTOMIZATIONS_RESET: 'Êtes-vous sûr de vouloir supprimer toutes les personnalisations, y compris les paramètres personnalisés des capteurs de température et analogiques ?',
|
CUSTOMIZATIONS_RESET: 'Êtes-vous sûr de vouloir supprimer toutes les personnalisations, y compris les paramètres personnalisés des capteurs de température et analogiques ?',
|
||||||
DEVICE_ENTITIES: 'Entités de l\'appareil',
|
|
||||||
SUPPORT_INFORMATION: 'Information de support',
|
SUPPORT_INFORMATION: 'Information de support',
|
||||||
CLICK_HERE: 'Cliquez ici',
|
|
||||||
HELP_INFORMATION_1: 'Visitez le wiki en ligne pour obtenir des instructions sur la façon de configurer EMS-ESP.',
|
HELP_INFORMATION_1: 'Visitez le wiki en ligne pour obtenir des instructions sur la façon de configurer EMS-ESP.',
|
||||||
HELP_INFORMATION_2: 'Pour une discussion en direct avec la communauté, rejoignez notre serveur Discord',
|
HELP_INFORMATION_2: 'Pour une discussion en direct avec la communauté, rejoignez notre serveur Discord',
|
||||||
HELP_INFORMATION_3: 'Pour demander une fonctionnalité ou signaler un problème',
|
HELP_INFORMATION_3: 'Pour demander une fonctionnalité ou signaler un problème',
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const it: Translation = {
|
|||||||
USERNAME: 'Nome Utente',
|
USERNAME: 'Nome Utente',
|
||||||
PASSWORD: 'Password',
|
PASSWORD: 'Password',
|
||||||
SU_PASSWORD: 'su Password',
|
SU_PASSWORD: 'su Password',
|
||||||
DASHBOARD: 'Pannello di Controllo',
|
|
||||||
SETTINGS_OF: 'Impostazioni {0}',
|
SETTINGS_OF: 'Impostazioni {0}',
|
||||||
HELP_OF: '{0} Aiuto',
|
HELP_OF: '{0} Aiuto',
|
||||||
LOGGED_IN: 'Registrato come {name}',
|
LOGGED_IN: 'Registrato come {name}',
|
||||||
@@ -37,8 +36,6 @@ const it: Translation = {
|
|||||||
BRAND: 'Marca',
|
BRAND: 'Marca',
|
||||||
ENTITY_NAME: 'Nome Entità',
|
ENTITY_NAME: 'Nome Entità',
|
||||||
VALUE: '{{Valore|valore}}',
|
VALUE: '{{Valore|valore}}',
|
||||||
DEVICE_DATA: 'Device Data',
|
|
||||||
SENSOR_DATA: 'Sensor Data',
|
|
||||||
DEVICES: 'Dispositivi',
|
DEVICES: 'Dispositivi',
|
||||||
SENSORS: 'Sensori',
|
SENSORS: 'Sensori',
|
||||||
RUN_COMMAND: 'Esegui',
|
RUN_COMMAND: 'Esegui',
|
||||||
@@ -165,9 +162,7 @@ const it: Translation = {
|
|||||||
OPTIONS: 'Opzioni',
|
OPTIONS: 'Opzioni',
|
||||||
NAME: 'Nome',
|
NAME: 'Nome',
|
||||||
CUSTOMIZATIONS_RESET: 'Sei sicuro di voler rimuovere tutte le personalizzazioni incluse le impostazioni personalizzate dei sensori di temperatura e analogici?',
|
CUSTOMIZATIONS_RESET: 'Sei sicuro di voler rimuovere tutte le personalizzazioni incluse le impostazioni personalizzate dei sensori di temperatura e analogici?',
|
||||||
DEVICE_ENTITIES: 'Entità Dispositivo',
|
|
||||||
SUPPORT_INFORMATION: 'Informazioni di Supporto',
|
SUPPORT_INFORMATION: 'Informazioni di Supporto',
|
||||||
CLICK_HERE: 'Clicca qui',
|
|
||||||
HELP_INFORMATION_1: 'Visita il wiki online per ottenere istruzioni su come configurare EMS-ESP',
|
HELP_INFORMATION_1: 'Visita il wiki online per ottenere istruzioni su come configurare EMS-ESP',
|
||||||
HELP_INFORMATION_2: 'Per la chat della community dal vivo unisciti al nostro server Discord',
|
HELP_INFORMATION_2: 'Per la chat della community dal vivo unisciti al nostro server Discord',
|
||||||
HELP_INFORMATION_3: 'Per richiedere una funzionalità o segnalare un errore',
|
HELP_INFORMATION_3: 'Per richiedere una funzionalità o segnalare un errore',
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const nl: Translation = {
|
|||||||
USERNAME: 'Gebruikersnaam',
|
USERNAME: 'Gebruikersnaam',
|
||||||
PASSWORD: 'Wachtwoord',
|
PASSWORD: 'Wachtwoord',
|
||||||
SU_PASSWORD: 'su Wachtwoord',
|
SU_PASSWORD: 'su Wachtwoord',
|
||||||
DASHBOARD: 'Dashboard',
|
|
||||||
SETTINGS_OF: '{0} Instellingen',
|
SETTINGS_OF: '{0} Instellingen',
|
||||||
HELP_OF: '{0} Help',
|
HELP_OF: '{0} Help',
|
||||||
LOGGED_IN: 'Ingelogd als {name}',
|
LOGGED_IN: 'Ingelogd als {name}',
|
||||||
@@ -37,8 +36,6 @@ const nl: Translation = {
|
|||||||
BRAND: 'Merk',
|
BRAND: 'Merk',
|
||||||
ENTITY_NAME: 'Entiteit',
|
ENTITY_NAME: 'Entiteit',
|
||||||
VALUE: '{{Waarde|waarde}}',
|
VALUE: '{{Waarde|waarde}}',
|
||||||
SENSOR_DATA: 'Sensor data',
|
|
||||||
DEVICE_DATA: 'Apparaat data',
|
|
||||||
DEVICES: 'Apparaten',
|
DEVICES: 'Apparaten',
|
||||||
SENSORS: 'Sensoren',
|
SENSORS: 'Sensoren',
|
||||||
RUN_COMMAND: 'Call commando',
|
RUN_COMMAND: 'Call commando',
|
||||||
@@ -163,9 +160,7 @@ const nl: Translation = {
|
|||||||
OPTIONS: 'Opties',
|
OPTIONS: 'Opties',
|
||||||
NAME: 'Naam',
|
NAME: 'Naam',
|
||||||
CUSTOMIZATIONS_RESET: 'Weet je zeker dat je alle custom aanpassingen wilt verwijderen inclusief de custom instellingen voor analoge temperatuursensoren?',
|
CUSTOMIZATIONS_RESET: 'Weet je zeker dat je alle custom aanpassingen wilt verwijderen inclusief de custom instellingen voor analoge temperatuursensoren?',
|
||||||
DEVICE_ENTITIES: 'Apparaat Entiteiten',
|
|
||||||
SUPPORT_INFORMATION: 'Support Informatie',
|
SUPPORT_INFORMATION: 'Support Informatie',
|
||||||
CLICK_HERE: 'Klik Hier',
|
|
||||||
HELP_INFORMATION_1: 'Bezoek de online wiki om instructies te vinden om EMS-ESP te configureren',
|
HELP_INFORMATION_1: 'Bezoek de online wiki om instructies te vinden om EMS-ESP te configureren',
|
||||||
HELP_INFORMATION_2: 'Voor de live community ga naar de Discord server',
|
HELP_INFORMATION_2: 'Voor de live community ga naar de Discord server',
|
||||||
HELP_INFORMATION_3: 'Om een nieuwe feature te vragen of een bug te rapporteren',
|
HELP_INFORMATION_3: 'Om een nieuwe feature te vragen of een bug te rapporteren',
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const no: Translation = {
|
|||||||
USERNAME: 'Brukernavn',
|
USERNAME: 'Brukernavn',
|
||||||
PASSWORD: 'Passord',
|
PASSWORD: 'Passord',
|
||||||
SU_PASSWORD: 'su Passord',
|
SU_PASSWORD: 'su Passord',
|
||||||
DASHBOARD: 'Dashboard',
|
|
||||||
SETTINGS_OF: '{0} Innstillinger',
|
SETTINGS_OF: '{0} Innstillinger',
|
||||||
HELP_OF: '{0} Hjelp',
|
HELP_OF: '{0} Hjelp',
|
||||||
LOGGED_IN: 'Logget in som {name}',
|
LOGGED_IN: 'Logget in som {name}',
|
||||||
@@ -37,8 +36,6 @@ const no: Translation = {
|
|||||||
BRAND: 'Fabrikat',
|
BRAND: 'Fabrikat',
|
||||||
ENTITY_NAME: 'Objektsnavn',
|
ENTITY_NAME: 'Objektsnavn',
|
||||||
VALUE: '{{Verdi|verdi}}',
|
VALUE: '{{Verdi|verdi}}',
|
||||||
DEVICE_DATA: 'Enheterdata',
|
|
||||||
SENSOR_DATA: 'Sensordata',
|
|
||||||
DEVICES: 'Enheter',
|
DEVICES: 'Enheter',
|
||||||
SENSORS: 'Sensorer',
|
SENSORS: 'Sensorer',
|
||||||
RUN_COMMAND: 'Kjør kommando',
|
RUN_COMMAND: 'Kjør kommando',
|
||||||
@@ -163,9 +160,7 @@ const no: Translation = {
|
|||||||
OPTIONS: 'Alternativ',
|
OPTIONS: 'Alternativ',
|
||||||
NAME: 'Navn',
|
NAME: 'Navn',
|
||||||
CUSTOMIZATIONS_RESET: 'Er du sikker på att du vil fjerne tilpassninger inkludert innstillinger for Temperatur og Analoge sensorer?',
|
CUSTOMIZATIONS_RESET: 'Er du sikker på att du vil fjerne tilpassninger inkludert innstillinger for Temperatur og Analoge sensorer?',
|
||||||
DEVICE_ENTITIES: 'Enhets objekter',
|
|
||||||
SUPPORT_INFORMATION: 'Supportinformasjon',
|
SUPPORT_INFORMATION: 'Supportinformasjon',
|
||||||
CLICK_HERE: 'Klikk her',
|
|
||||||
HELP_INFORMATION_1: 'Besøk wiki for instruksjoner for å konfigurere EMS-ESP',
|
HELP_INFORMATION_1: 'Besøk wiki for instruksjoner for å konfigurere EMS-ESP',
|
||||||
HELP_INFORMATION_2: 'For community-support besøk vår Discord-server',
|
HELP_INFORMATION_2: 'For community-support besøk vår Discord-server',
|
||||||
HELP_INFORMATION_3: 'For å be om en ny funksjon eller melde feil',
|
HELP_INFORMATION_3: 'For å be om en ny funksjon eller melde feil',
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const pl: BaseTranslation = {
|
|||||||
USERNAME: '{{Użytkownik|Nazwa użytkownika|}}',
|
USERNAME: '{{Użytkownik|Nazwa użytkownika|}}',
|
||||||
PASSWORD: 'Hasło',
|
PASSWORD: 'Hasło',
|
||||||
SU_PASSWORD: 'Hasło "su"',
|
SU_PASSWORD: 'Hasło "su"',
|
||||||
DASHBOARD: 'Pulpit',
|
|
||||||
SETTINGS_OF: 'Ustawienia {0}',
|
SETTINGS_OF: 'Ustawienia {0}',
|
||||||
HELP_OF: 'Pomoc {0}',
|
HELP_OF: 'Pomoc {0}',
|
||||||
LOGGED_IN: 'Zalogowano użytkownika {name}.',
|
LOGGED_IN: 'Zalogowano użytkownika {name}.',
|
||||||
@@ -37,8 +36,6 @@ const pl: BaseTranslation = {
|
|||||||
VERSION: 'Wersja',
|
VERSION: 'Wersja',
|
||||||
ENTITY_NAME: '{{N|n|}}azwa encji',
|
ENTITY_NAME: '{{N|n|}}azwa encji',
|
||||||
VALUE: '{{W|w|}}artość',
|
VALUE: '{{W|w|}}artość',
|
||||||
DEVICE_DATA: 'Dane z urządzeń',
|
|
||||||
SENSOR_DATA: 'Dane z czujników',
|
|
||||||
DEVICES: 'Urządzenia',
|
DEVICES: 'Urządzenia',
|
||||||
SENSORS: 'Czujniki',
|
SENSORS: 'Czujniki',
|
||||||
RUN_COMMAND: 'Wykonaj komendę',
|
RUN_COMMAND: 'Wykonaj komendę',
|
||||||
@@ -163,9 +160,7 @@ const pl: BaseTranslation = {
|
|||||||
OPTIONS: 'Opcje',
|
OPTIONS: 'Opcje',
|
||||||
NAME: '{{Nazwa|nazwa|}}',
|
NAME: '{{Nazwa|nazwa|}}',
|
||||||
CUSTOMIZATIONS_RESET: 'Na pewno chcesz usunąć wszystkie personalizacje łącznie z ustawieniami dla czujników temperatury 1-Wire® i urządzeń podłączonych do EMS-ESP?',
|
CUSTOMIZATIONS_RESET: 'Na pewno chcesz usunąć wszystkie personalizacje łącznie z ustawieniami dla czujników temperatury 1-Wire® i urządzeń podłączonych do EMS-ESP?',
|
||||||
DEVICE_ENTITIES: 'Encje urządzenia',
|
|
||||||
SUPPORT_INFORMATION: '{{I|i|}}nformacj{{e|i|}} o systemie',
|
SUPPORT_INFORMATION: '{{I|i|}}nformacj{{e|i|}} o systemie',
|
||||||
CLICK_HERE: 'Kliknij tu',
|
|
||||||
HELP_INFORMATION_1: 'Aby uzyskać instrukcje dotyczące konfiguracji EMS-ESP, skorzystaj z wiki w internecie',
|
HELP_INFORMATION_1: 'Aby uzyskać instrukcje dotyczące konfiguracji EMS-ESP, skorzystaj z wiki w internecie',
|
||||||
HELP_INFORMATION_2: 'Aby dołączyć do naszego serwera Discord i komunikować się na żywo ze społecznością',
|
HELP_INFORMATION_2: 'Aby dołączyć do naszego serwera Discord i komunikować się na żywo ze społecznością',
|
||||||
HELP_INFORMATION_3: 'Aby zaproponować nową funkcjonalność lub zgłosić problem',
|
HELP_INFORMATION_3: 'Aby zaproponować nową funkcjonalność lub zgłosić problem',
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const sk: Translation = {
|
|||||||
USERNAME: 'Užívateľské meno',
|
USERNAME: 'Užívateľské meno',
|
||||||
PASSWORD: 'Heslo',
|
PASSWORD: 'Heslo',
|
||||||
SU_PASSWORD: 'su heslo',
|
SU_PASSWORD: 'su heslo',
|
||||||
DASHBOARD: 'Panel',
|
|
||||||
SETTINGS_OF: '{0} Nastavenia',
|
SETTINGS_OF: '{0} Nastavenia',
|
||||||
HELP_OF: '{0} Pomoc',
|
HELP_OF: '{0} Pomoc',
|
||||||
LOGGED_IN: 'Prihlásený ako {name}',
|
LOGGED_IN: 'Prihlásený ako {name}',
|
||||||
@@ -37,8 +36,6 @@ const sk: Translation = {
|
|||||||
BRAND: 'Značka',
|
BRAND: 'Značka',
|
||||||
ENTITY_NAME: 'Názov entity',
|
ENTITY_NAME: 'Názov entity',
|
||||||
VALUE: '{{Value|value}}',
|
VALUE: '{{Value|value}}',
|
||||||
DEVICE_DATA: 'Dáta zariadenia',
|
|
||||||
SENSOR_DATA: 'Dáta snímača',
|
|
||||||
DEVICES: 'Zariadenia',
|
DEVICES: 'Zariadenia',
|
||||||
SENSORS: 'Snímače',
|
SENSORS: 'Snímače',
|
||||||
RUN_COMMAND: 'Volať príkaz',
|
RUN_COMMAND: 'Volať príkaz',
|
||||||
@@ -163,9 +160,7 @@ const sk: Translation = {
|
|||||||
OPTIONS: 'Možnosti',
|
OPTIONS: 'Možnosti',
|
||||||
NAME: 'Názov',
|
NAME: 'Názov',
|
||||||
CUSTOMIZATIONS_RESET: 'Naozaj chcete odstrániť všetky prispôsobenia vrátane vlastných nastavení snímačov teploty a analógových snímačov?',
|
CUSTOMIZATIONS_RESET: 'Naozaj chcete odstrániť všetky prispôsobenia vrátane vlastných nastavení snímačov teploty a analógových snímačov?',
|
||||||
DEVICE_ENTITIES: 'Entity zariadenia',
|
|
||||||
SUPPORT_INFORMATION: 'Informácie o podpore',
|
SUPPORT_INFORMATION: 'Informácie o podpore',
|
||||||
CLICK_HERE: 'Kliknite tu',
|
|
||||||
HELP_INFORMATION_1: 'Navštívte online wiki, kde nájdete pokyny na konfiguráciu EMS-ESP',
|
HELP_INFORMATION_1: 'Navštívte online wiki, kde nájdete pokyny na konfiguráciu EMS-ESP',
|
||||||
HELP_INFORMATION_2: 'Pre živý komunitný chat sa pripojte na náš Discord server',
|
HELP_INFORMATION_2: 'Pre živý komunitný chat sa pripojte na náš Discord server',
|
||||||
HELP_INFORMATION_3: 'Ak chcete požiadať o funkciu alebo nahlásiť chybu',
|
HELP_INFORMATION_3: 'Ak chcete požiadať o funkciu alebo nahlásiť chybu',
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const sv: Translation = {
|
|||||||
USERNAME: 'Användarnamn',
|
USERNAME: 'Användarnamn',
|
||||||
PASSWORD: 'Lösenord',
|
PASSWORD: 'Lösenord',
|
||||||
SU_PASSWORD: 'su Lösenord',
|
SU_PASSWORD: 'su Lösenord',
|
||||||
DASHBOARD: 'Kontrollpanel',
|
|
||||||
SETTINGS_OF: '{0} Inställningar',
|
SETTINGS_OF: '{0} Inställningar',
|
||||||
HELP_OF: '{0} Hjälp',
|
HELP_OF: '{0} Hjälp',
|
||||||
LOGGED_IN: 'Inloggad som {name}',
|
LOGGED_IN: 'Inloggad som {name}',
|
||||||
@@ -37,8 +36,6 @@ const sv: Translation = {
|
|||||||
BRAND: 'Fabrikat',
|
BRAND: 'Fabrikat',
|
||||||
ENTITY_NAME: 'Entitetsnamn',
|
ENTITY_NAME: 'Entitetsnamn',
|
||||||
VALUE: '{{Värde|värde}}',
|
VALUE: '{{Värde|värde}}',
|
||||||
DEVICE_DATA: 'Enhets data',
|
|
||||||
SENSOR_DATA: 'Sensor data',
|
|
||||||
DEVICES: 'Enheter',
|
DEVICES: 'Enheter',
|
||||||
SENSORS: 'Sensorer',
|
SENSORS: 'Sensorer',
|
||||||
RUN_COMMAND: 'Kör Kommando',
|
RUN_COMMAND: 'Kör Kommando',
|
||||||
@@ -163,9 +160,7 @@ const sv: Translation = {
|
|||||||
OPTIONS: 'Alternativ',
|
OPTIONS: 'Alternativ',
|
||||||
NAME: 'Namn',
|
NAME: 'Namn',
|
||||||
CUSTOMIZATIONS_RESET: 'Är du säker på att du vill ta bort alla anpassningar inklusive inställningar för Temperatur och Analoga sensorer?',
|
CUSTOMIZATIONS_RESET: 'Är du säker på att du vill ta bort alla anpassningar inklusive inställningar för Temperatur och Analoga sensorer?',
|
||||||
DEVICE_ENTITIES: 'Enhets-entiteter',
|
|
||||||
SUPPORT_INFORMATION: 'Supportinformation',
|
SUPPORT_INFORMATION: 'Supportinformation',
|
||||||
CLICK_HERE: 'Klicka Här',
|
|
||||||
HELP_INFORMATION_1: 'Besök Wikin för instruktioner för hur du kan konfigurera EMS-ESP',
|
HELP_INFORMATION_1: 'Besök Wikin för instruktioner för hur du kan konfigurera EMS-ESP',
|
||||||
HELP_INFORMATION_2: 'För community-support besök vår Discord-server',
|
HELP_INFORMATION_2: 'För community-support besök vår Discord-server',
|
||||||
HELP_INFORMATION_3: 'Önska en ny funktion eller rapportera en bugg',
|
HELP_INFORMATION_3: 'Önska en ny funktion eller rapportera en bugg',
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ const tr: Translation = {
|
|||||||
USERNAME: 'Kullanıcı Adı',
|
USERNAME: 'Kullanıcı Adı',
|
||||||
PASSWORD: 'Şifre',
|
PASSWORD: 'Şifre',
|
||||||
SU_PASSWORD: 'SK Şifresi',
|
SU_PASSWORD: 'SK Şifresi',
|
||||||
DASHBOARD: 'Gösterge Paneli',
|
|
||||||
SETTINGS_OF: '{0} Ayarlar',
|
SETTINGS_OF: '{0} Ayarlar',
|
||||||
HELP_OF: '{0} Yardım',
|
HELP_OF: '{0} Yardım',
|
||||||
LOGGED_IN: '{name} olarak giriş yapıldı',
|
LOGGED_IN: '{name} olarak giriş yapıldı',
|
||||||
@@ -37,8 +36,6 @@ const tr: Translation = {
|
|||||||
BRAND: 'Marka',
|
BRAND: 'Marka',
|
||||||
ENTITY_NAME: 'Valık Adı',
|
ENTITY_NAME: 'Valık Adı',
|
||||||
VALUE: '{{Değer|değer}}',
|
VALUE: '{{Değer|değer}}',
|
||||||
DEVICE_DATA: 'Cihaz Bilgisi',
|
|
||||||
SENSOR_DATA: 'Sensör Bilgisi',
|
|
||||||
DEVICES: 'Cihazlar',
|
DEVICES: 'Cihazlar',
|
||||||
SENSORS: 'Sensörler',
|
SENSORS: 'Sensörler',
|
||||||
RUN_COMMAND: 'Çalıştırma Komutu',
|
RUN_COMMAND: 'Çalıştırma Komutu',
|
||||||
@@ -163,9 +160,7 @@ const tr: Translation = {
|
|||||||
OPTIONS: 'Seçenekler',
|
OPTIONS: 'Seçenekler',
|
||||||
NAME: 'İsim',
|
NAME: 'İsim',
|
||||||
CUSTOMIZATIONS_RESET: 'Sıcaklık ve Analog Sensörlerin özelleştirilmiş seçenekleri dahil bütün özelleştirmeleri kaldırmak istediğinizden emin misiniz?',
|
CUSTOMIZATIONS_RESET: 'Sıcaklık ve Analog Sensörlerin özelleştirilmiş seçenekleri dahil bütün özelleştirmeleri kaldırmak istediğinizden emin misiniz?',
|
||||||
DEVICE_ENTITIES: 'Cihaz Varlıkları',
|
|
||||||
SUPPORT_INFORMATION: 'Destek Bilgileri',
|
SUPPORT_INFORMATION: 'Destek Bilgileri',
|
||||||
CLICK_HERE: 'Buraya Tıklayın',
|
|
||||||
HELP_INFORMATION_1: 'EMS-ESPnin nasıl ayarlanacağı ile ilgili bilgileri edinmek için çevrimiçi WIKI sayfasını ziyaret edin',
|
HELP_INFORMATION_1: 'EMS-ESPnin nasıl ayarlanacağı ile ilgili bilgileri edinmek için çevrimiçi WIKI sayfasını ziyaret edin',
|
||||||
HELP_INFORMATION_2: 'Canlı topluluk sohbeti için Discord sunucumuza katılın',
|
HELP_INFORMATION_2: 'Canlı topluluk sohbeti için Discord sunucumuza katılın',
|
||||||
HELP_INFORMATION_3: 'Yeni bir özellik talep etmek yada hata bildirmek için',
|
HELP_INFORMATION_3: 'Yeni bir özellik talep etmek yada hata bildirmek için',
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ import {
|
|||||||
ValidatedTextField,
|
ValidatedTextField,
|
||||||
ButtonRow,
|
ButtonRow,
|
||||||
MessageBox,
|
MessageBox,
|
||||||
BlockNavigation
|
BlockNavigation,
|
||||||
|
useLayoutTitle
|
||||||
} from 'components';
|
} from 'components';
|
||||||
|
|
||||||
import RestartMonitor from 'framework/system/RestartMonitor';
|
import RestartMonitor from 'framework/system/RestartMonitor';
|
||||||
@@ -36,7 +37,7 @@ export function boardProfileSelectItems() {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
const SettingsApplication: FC = () => {
|
const ApplicationSettings: FC = () => {
|
||||||
const {
|
const {
|
||||||
loadData,
|
loadData,
|
||||||
saveData,
|
saveData,
|
||||||
@@ -97,6 +98,8 @@ const SettingsApplication: FC = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useLayoutTitle(LL.APPLICATION_SETTINGS());
|
||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
||||||
@@ -680,11 +683,11 @@ const SettingsApplication: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.APPLICATION_SETTINGS()} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{restarting ? <RestartMonitor /> : content()}
|
{restarting ? <RestartMonitor /> : content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SettingsApplication;
|
export default ApplicationSettings;
|
||||||
@@ -13,17 +13,17 @@ import { useBlocker } from 'react-router-dom';
|
|||||||
|
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import SettingsCustomEntitiesDialog from './SettingsCustomEntitiesDialog';
|
import SettingsCustomEntitiesDialog from './CustomEntitiesDialog';
|
||||||
import * as EMSESP from './api';
|
import * as EMSESP from './api';
|
||||||
import { DeviceValueTypeNames, DeviceValueUOM_s } from './types';
|
import { DeviceValueTypeNames, DeviceValueUOM_s } from './types';
|
||||||
import { entityItemValidation } from './validators';
|
import { entityItemValidation } from './validators';
|
||||||
import type { EntityItem } from './types';
|
import type { EntityItem } from './types';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { ButtonRow, FormLoader, SectionContent, BlockNavigation } from 'components';
|
import { ButtonRow, FormLoader, SectionContent, BlockNavigation, useLayoutTitle } from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
const SettingsCustomEntities: FC = () => {
|
const CustomEntities: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [numChanges, setNumChanges] = useState<number>(0);
|
const [numChanges, setNumChanges] = useState<number>(0);
|
||||||
const blocker = useBlocker(numChanges !== 0);
|
const blocker = useBlocker(numChanges !== 0);
|
||||||
@@ -31,6 +31,8 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
const [creating, setCreating] = useState<boolean>(false);
|
const [creating, setCreating] = useState<boolean>(false);
|
||||||
const [dialogOpen, setDialogOpen] = useState<boolean>(false);
|
const [dialogOpen, setDialogOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
|
useLayoutTitle(LL.CUSTOM_ENTITIES(0));
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: entities,
|
data: entities,
|
||||||
send: fetchEntities,
|
send: fetchEntities,
|
||||||
@@ -246,7 +248,7 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.CUSTOM_ENTITIES(0)} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
<Box mb={2} color="warning.main">
|
<Box mb={2} color="warning.main">
|
||||||
<Typography variant="body2">{LL.ENTITIES_HELP_1()}</Typography>
|
<Typography variant="body2">{LL.ENTITIES_HELP_1()}</Typography>
|
||||||
@@ -298,4 +300,4 @@ const SettingsCustomEntities: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SettingsCustomEntities;
|
export default CustomEntities;
|
||||||
@@ -30,7 +30,7 @@ import { useI18nContext } from 'i18n/i18n-react';
|
|||||||
import { numberValue, updateValue } from 'utils';
|
import { numberValue, updateValue } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { validate } from 'validators';
|
||||||
|
|
||||||
type SettingsCustomEntitiesDialogProps = {
|
type CustomEntitiesDialogProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
creating: boolean;
|
creating: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@@ -39,14 +39,14 @@ type SettingsCustomEntitiesDialogProps = {
|
|||||||
validator: Schema;
|
validator: Schema;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SettingsCustomEntitiesDialog = ({
|
const CustomEntitiesDialog = ({
|
||||||
open,
|
open,
|
||||||
creating,
|
creating,
|
||||||
onClose,
|
onClose,
|
||||||
onSave,
|
onSave,
|
||||||
selectedItem,
|
selectedItem,
|
||||||
validator
|
validator
|
||||||
}: SettingsCustomEntitiesDialogProps) => {
|
}: CustomEntitiesDialogProps) => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [editItem, setEditItem] = useState<EntityItem>(selectedItem);
|
const [editItem, setEditItem] = useState<EntityItem>(selectedItem);
|
||||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||||
@@ -281,4 +281,4 @@ const SettingsCustomEntitiesDialog = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SettingsCustomEntitiesDialog;
|
export default CustomEntitiesDialog;
|
||||||
@@ -26,9 +26,9 @@ import { useState, useEffect, useCallback } from 'react';
|
|||||||
import { useBlocker, useLocation } from 'react-router-dom';
|
import { useBlocker, useLocation } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import SettingsCustomizationDialog from './CustomizationDialog';
|
||||||
import EntityMaskToggle from './EntityMaskToggle';
|
import EntityMaskToggle from './EntityMaskToggle';
|
||||||
import OptionIcon from './OptionIcon';
|
import OptionIcon from './OptionIcon';
|
||||||
import SettingsCustomizationDialog from './SettingsCustomizationDialog';
|
|
||||||
|
|
||||||
import * as EMSESP from './api';
|
import * as EMSESP from './api';
|
||||||
|
|
||||||
@@ -37,14 +37,14 @@ import type { DeviceShort, DeviceEntity } from './types';
|
|||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { dialogStyle } from 'CustomTheme';
|
import { dialogStyle } from 'CustomTheme';
|
||||||
import * as SystemApi from 'api/system';
|
import * as SystemApi from 'api/system';
|
||||||
import { ButtonRow, SectionContent, MessageBox, BlockNavigation } from 'components';
|
import { ButtonRow, SectionContent, MessageBox, BlockNavigation, useLayoutTitle } from 'components';
|
||||||
|
|
||||||
import RestartMonitor from 'framework/system/RestartMonitor';
|
import RestartMonitor from 'framework/system/RestartMonitor';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
export const APIURL = window.location.origin + '/api/';
|
export const APIURL = window.location.origin + '/api/';
|
||||||
|
|
||||||
const SettingsCustomization: FC = () => {
|
const Customization: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [numChanges, setNumChanges] = useState<number>(0);
|
const [numChanges, setNumChanges] = useState<number>(0);
|
||||||
const blocker = useBlocker(numChanges !== 0);
|
const blocker = useBlocker(numChanges !== 0);
|
||||||
@@ -58,6 +58,8 @@ const SettingsCustomization: FC = () => {
|
|||||||
const [selectedDeviceEntity, setSelectedDeviceEntity] = useState<DeviceEntity>();
|
const [selectedDeviceEntity, setSelectedDeviceEntity] = useState<DeviceEntity>();
|
||||||
const [dialogOpen, setDialogOpen] = useState<boolean>(false);
|
const [dialogOpen, setDialogOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
|
useLayoutTitle(LL.CUSTOMIZATIONS());
|
||||||
|
|
||||||
// fetch devices first
|
// fetch devices first
|
||||||
const { data: devices } = useRequest(EMSESP.readDevices);
|
const { data: devices } = useRequest(EMSESP.readDevices);
|
||||||
|
|
||||||
@@ -508,9 +510,6 @@ const SettingsCustomization: FC = () => {
|
|||||||
|
|
||||||
const renderContent = () => (
|
const renderContent = () => (
|
||||||
<>
|
<>
|
||||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
|
||||||
{LL.DEVICE_ENTITIES()}
|
|
||||||
</Typography>
|
|
||||||
{devices && renderDeviceList()}
|
{devices && renderDeviceList()}
|
||||||
{deviceEntities && renderDeviceData()}
|
{deviceEntities && renderDeviceData()}
|
||||||
{restartNeeded && (
|
{restartNeeded && (
|
||||||
@@ -561,7 +560,7 @@ const SettingsCustomization: FC = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.CUSTOMIZATIONS()} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{restarting ? <RestartMonitor /> : renderContent()}
|
{restarting ? <RestartMonitor /> : renderContent()}
|
||||||
{selectedDeviceEntity && (
|
{selectedDeviceEntity && (
|
||||||
@@ -576,4 +575,4 @@ const SettingsCustomization: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SettingsCustomization;
|
export default Customization;
|
||||||
@@ -31,7 +31,7 @@ type SettingsCustomizationDialogProps = {
|
|||||||
selectedItem: DeviceEntity;
|
selectedItem: DeviceEntity;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SettingsCustomizationDialog = ({ open, onClose, onSave, selectedItem }: SettingsCustomizationDialogProps) => {
|
const CustomizationDialog = ({ open, onClose, onSave, selectedItem }: SettingsCustomizationDialogProps) => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [editItem, setEditItem] = useState<DeviceEntity>(selectedItem);
|
const [editItem, setEditItem] = useState<DeviceEntity>(selectedItem);
|
||||||
const [error, setError] = useState<boolean>(false);
|
const [error, setError] = useState<boolean>(false);
|
||||||
@@ -152,4 +152,4 @@ const SettingsCustomizationDialog = ({ open, onClose, onSave, selectedItem }: Se
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SettingsCustomizationDialog;
|
export default CustomizationDialog;
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import { Tab } from '@mui/material';
|
|
||||||
import { Navigate, Route, Routes } from 'react-router-dom';
|
|
||||||
|
|
||||||
import DashboardDevices from './DashboardDevices';
|
|
||||||
import DashboardSensors from './DashboardSensors';
|
|
||||||
import DashboardStatus from './DashboardStatus';
|
|
||||||
|
|
||||||
import type { FC } from 'react';
|
|
||||||
|
|
||||||
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
|
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
|
||||||
|
|
||||||
const Dashboard: FC = () => {
|
|
||||||
const { routerTab } = useRouterTab();
|
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
|
||||||
useLayoutTitle(LL.DASHBOARD());
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<RouterTabs value={routerTab}>
|
|
||||||
<Tab value="/dashboard/devices" label={LL.DEVICES()} />
|
|
||||||
<Tab value="/dashboard/sensors" label={LL.SENSORS()} />
|
|
||||||
<Tab value="/dashboard/status" label="Status" />
|
|
||||||
</RouterTabs>
|
|
||||||
<Routes>
|
|
||||||
<Route path="devices" element={<DashboardDevices />} />
|
|
||||||
<Route path="sensors" element={<DashboardSensors />} />
|
|
||||||
<Route path="status" element={<DashboardStatus />} />
|
|
||||||
<Route path="*" element={<Navigate replace to="/dashboard/devices" />} />
|
|
||||||
</Routes>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Dashboard;
|
|
||||||
@@ -38,8 +38,8 @@ import { useState, useContext, useEffect, useCallback, useLayoutEffect } from 'r
|
|||||||
import { IconContext } from 'react-icons';
|
import { IconContext } from 'react-icons';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import DashboardDevicesDialog from './DashboardDevicesDialog';
|
|
||||||
import DeviceIcon from './DeviceIcon';
|
import DeviceIcon from './DeviceIcon';
|
||||||
|
import DashboardDevicesDialog from './DevicesDialog';
|
||||||
|
|
||||||
import * as EMSESP from './api';
|
import * as EMSESP from './api';
|
||||||
import { formatValue } from './deviceValue';
|
import { formatValue } from './deviceValue';
|
||||||
@@ -49,12 +49,12 @@ import { deviceValueItemValidation } from './validators';
|
|||||||
import type { Device, DeviceValue } from './types';
|
import type { Device, DeviceValue } from './types';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { dialogStyle } from 'CustomTheme';
|
import { dialogStyle } from 'CustomTheme';
|
||||||
import { ButtonRow, SectionContent, MessageBox } from 'components';
|
import { ButtonRow, SectionContent, MessageBox, useLayoutTitle } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
const DashboardDevices: FC = () => {
|
const Devices: FC = () => {
|
||||||
const { me } = useContext(AuthenticatedContext);
|
const { me } = useContext(AuthenticatedContext);
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [size, setSize] = useState([0, 0]);
|
const [size, setSize] = useState([0, 0]);
|
||||||
@@ -66,6 +66,8 @@ const DashboardDevices: FC = () => {
|
|||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useLayoutTitle(LL.DEVICES());
|
||||||
|
|
||||||
const { data: coreData, send: readCoreData } = useRequest(() => EMSESP.readCoreData(), {
|
const { data: coreData, send: readCoreData } = useRequest(() => EMSESP.readCoreData(), {
|
||||||
initialData: {
|
initialData: {
|
||||||
connected: true,
|
connected: true,
|
||||||
@@ -608,7 +610,7 @@ const DashboardDevices: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.DEVICE_DATA()} titleGutter id="devices-window">
|
<SectionContent id="devices-window">
|
||||||
{renderCoreData()}
|
{renderCoreData()}
|
||||||
{renderDeviceData()}
|
{renderDeviceData()}
|
||||||
{renderDeviceDetails()}
|
{renderDeviceDetails()}
|
||||||
@@ -636,4 +638,4 @@ const DashboardDevices: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DashboardDevices;
|
export default Devices;
|
||||||
@@ -40,7 +40,7 @@ type DashboardDevicesDialogProps = {
|
|||||||
progress: boolean;
|
progress: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DashboardDevicesDialog = ({
|
const DevicesDialog = ({
|
||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
onSave,
|
onSave,
|
||||||
@@ -204,4 +204,4 @@ const DashboardDevicesDialog = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DashboardDevicesDialog;
|
export default DevicesDialog;
|
||||||
@@ -64,7 +64,7 @@ const showQuality = (stat: Stat) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const DashboardStatus: FC = () => {
|
const EMSStatus: FC = () => {
|
||||||
const { data: data, send: loadData, error } = useRequest(EMSESP.readStatus);
|
const { data: data, send: loadData, error } = useRequest(EMSESP.readStatus);
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
@@ -272,11 +272,7 @@ const DashboardStatus: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return <SectionContent title={LL.EMS_BUS_STATUS_TITLE()}>{content()}</SectionContent>;
|
||||||
<SectionContent title={LL.EMS_BUS_STATUS_TITLE()} titleGutter>
|
|
||||||
{content()}
|
|
||||||
</SectionContent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DashboardStatus;
|
export default EMSStatus;
|
||||||
@@ -1,9 +1,19 @@
|
|||||||
import CommentIcon from '@mui/icons-material/CommentTwoTone';
|
import CommentIcon from '@mui/icons-material/CommentTwoTone';
|
||||||
import EastIcon from '@mui/icons-material/East';
|
|
||||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||||
import GitHubIcon from '@mui/icons-material/GitHub';
|
import GitHubIcon from '@mui/icons-material/GitHub';
|
||||||
import MenuBookIcon from '@mui/icons-material/MenuBookTwoTone';
|
import MenuBookIcon from '@mui/icons-material/MenuBookTwoTone';
|
||||||
import { Box, List, ListItem, ListItemAvatar, ListItemText, Link, Typography, Button } from '@mui/material';
|
import {
|
||||||
|
Box,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
ListItemAvatar,
|
||||||
|
ListItemText,
|
||||||
|
Link,
|
||||||
|
Typography,
|
||||||
|
Button,
|
||||||
|
ListItemButton,
|
||||||
|
Avatar
|
||||||
|
} from '@mui/material';
|
||||||
import { useRequest } from 'alova';
|
import { useRequest } from 'alova';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
@@ -39,59 +49,56 @@ const Help: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SUPPORT_INFORMATION(0)} titleGutter>
|
<SectionContent>
|
||||||
<List>
|
<List sx={{ borderRadius: 3, border: '2px solid grey' }}>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemAvatar>
|
<ListItemButton component="a" href="https://emsesp.github.io/docs">
|
||||||
<MenuBookIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
<ListItemAvatar>
|
||||||
</ListItemAvatar>
|
<Avatar sx={{ bgcolor: '#72caf9' }}>
|
||||||
<ListItemText>
|
<MenuBookIcon />
|
||||||
{LL.HELP_INFORMATION_1()}
|
</Avatar>
|
||||||
<EastIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary={LL.HELP_INFORMATION_1()} />
|
||||||
<Link target="_blank" href="https://emsesp.github.io/docs" color="primary">
|
</ListItemButton>
|
||||||
{LL.CLICK_HERE()}
|
|
||||||
</Link>
|
|
||||||
</ListItemText>
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemAvatar>
|
<ListItemButton component="a" href="https://discord.gg/3J3GgnzpyT">
|
||||||
<CommentIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
<ListItemAvatar>
|
||||||
</ListItemAvatar>
|
<Avatar sx={{ bgcolor: '#72caf9' }}>
|
||||||
<ListItemText>
|
<CommentIcon />
|
||||||
{LL.HELP_INFORMATION_2()}
|
</Avatar>
|
||||||
<EastIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
</ListItemAvatar>
|
||||||
|
<ListItemText primary={LL.HELP_INFORMATION_2()} />
|
||||||
<Link target="_blank" href="https://discord.gg/3J3GgnzpyT" color="primary">
|
</ListItemButton>
|
||||||
{LL.CLICK_HERE()}
|
|
||||||
</Link>
|
|
||||||
</ListItemText>
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemAvatar>
|
<ListItemButton component="a" href="https://github.com/emsesp/EMS-ESP32/issues/new/choose">
|
||||||
<GitHubIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
<ListItemAvatar>
|
||||||
</ListItemAvatar>
|
<Avatar sx={{ bgcolor: '#72caf9' }}>
|
||||||
<ListItemText>
|
<GitHubIcon />
|
||||||
{LL.HELP_INFORMATION_3()}
|
</Avatar>
|
||||||
<EastIcon style={{ fontSize: 24, color: 'lightblue', verticalAlign: 'middle' }} />
|
</ListItemAvatar>
|
||||||
<Link target="_blank" href="https://github.com/emsesp/EMS-ESP32/issues/new/choose" color="primary">
|
<ListItemText primary={LL.HELP_INFORMATION_3()} />
|
||||||
{LL.CLICK_HERE()}
|
</ListItemButton>
|
||||||
</Link>
|
|
||||||
<br />
|
|
||||||
</ListItemText>
|
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
<Box color="warning.main">
|
<Box p={2} color="warning.main">
|
||||||
<Typography mb={1} variant="body2">
|
<Typography mb={1} variant="body2">
|
||||||
{LL.HELP_INFORMATION_4()}
|
{LL.HELP_INFORMATION_4()}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<Button
|
||||||
|
startIcon={<DownloadIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => callAPI('system', 'info')}
|
||||||
|
>
|
||||||
|
{LL.SUPPORT_INFORMATION(0)}
|
||||||
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={() => callAPI('system', 'info')}>
|
|
||||||
{LL.SUPPORT_INFORMATION(0)}
|
|
||||||
</Button>
|
|
||||||
<Button
|
<Button
|
||||||
sx={{ ml: 2 }}
|
sx={{ ml: 2 }}
|
||||||
startIcon={<DownloadIcon />}
|
startIcon={<DownloadIcon />}
|
||||||
@@ -102,7 +109,7 @@ const Help: FC = () => {
|
|||||||
All Values
|
All Values
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Box border={1} p={1} mt={4} color="orange">
|
<Box border={1} p={1} mt={4}>
|
||||||
<Typography align="center" variant="subtitle1" color="orange">
|
<Typography align="center" variant="subtitle1" color="orange">
|
||||||
<b>{LL.HELP_INFORMATION_5()}</b>
|
<b>{LL.HELP_INFORMATION_5()}</b>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -11,18 +11,18 @@ import { updateState, useRequest } from 'alova';
|
|||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { useBlocker } from 'react-router-dom';
|
import { useBlocker } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import SettingsSchedulerDialog from './SettingsSchedulerDialog';
|
import SettingsSchedulerDialog from './SchedulerDialog';
|
||||||
import * as EMSESP from './api';
|
import * as EMSESP from './api';
|
||||||
import { ScheduleFlag } from './types';
|
import { ScheduleFlag } from './types';
|
||||||
import { schedulerItemValidation } from './validators';
|
import { schedulerItemValidation } from './validators';
|
||||||
import type { ScheduleItem } from './types';
|
import type { ScheduleItem } from './types';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { ButtonRow, FormLoader, SectionContent, BlockNavigation } from 'components';
|
import { ButtonRow, FormLoader, SectionContent, BlockNavigation, useLayoutTitle } from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
const SettingsScheduler: FC = () => {
|
const Scheduler: FC = () => {
|
||||||
const { LL, locale } = useI18nContext();
|
const { LL, locale } = useI18nContext();
|
||||||
const [numChanges, setNumChanges] = useState<number>(0);
|
const [numChanges, setNumChanges] = useState<number>(0);
|
||||||
const blocker = useBlocker(numChanges !== 0);
|
const blocker = useBlocker(numChanges !== 0);
|
||||||
@@ -194,6 +194,8 @@ const SettingsScheduler: FC = () => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useLayoutTitle(LL.SCHEDULER());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table
|
<Table
|
||||||
data={{ nodes: schedule.filter((si) => !si.deleted).sort((a, b) => a.time.localeCompare(b.time)) }}
|
data={{ nodes: schedule.filter((si) => !si.deleted).sort((a, b) => a.time.localeCompare(b.time)) }}
|
||||||
@@ -249,7 +251,7 @@ const SettingsScheduler: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SCHEDULER()} titleGutter>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
<Box mb={2} color="warning.main">
|
<Box mb={2} color="warning.main">
|
||||||
<Typography variant="body2">{LL.SCHEDULER_HELP_1()}</Typography>
|
<Typography variant="body2">{LL.SCHEDULER_HELP_1()}</Typography>
|
||||||
@@ -298,4 +300,4 @@ const SettingsScheduler: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SettingsScheduler;
|
export default Scheduler;
|
||||||
@@ -32,7 +32,7 @@ import { useI18nContext } from 'i18n/i18n-react';
|
|||||||
import { updateValue } from 'utils';
|
import { updateValue } from 'utils';
|
||||||
import { validate } from 'validators';
|
import { validate } from 'validators';
|
||||||
|
|
||||||
type SettingsSchedulerDialogProps = {
|
type SchedulerDialogProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
creating: boolean;
|
creating: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@@ -42,15 +42,7 @@ type SettingsSchedulerDialogProps = {
|
|||||||
dow: string[];
|
dow: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const SettingsSchedulerDialog = ({
|
const SchedulerDialog = ({ open, creating, onClose, onSave, selectedItem, validator, dow }: SchedulerDialogProps) => {
|
||||||
open,
|
|
||||||
creating,
|
|
||||||
onClose,
|
|
||||||
onSave,
|
|
||||||
selectedItem,
|
|
||||||
validator,
|
|
||||||
dow
|
|
||||||
}: SettingsSchedulerDialogProps) => {
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [editItem, setEditItem] = useState<ScheduleItem>(selectedItem);
|
const [editItem, setEditItem] = useState<ScheduleItem>(selectedItem);
|
||||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||||
@@ -246,4 +238,4 @@ const SettingsSchedulerDialog = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SettingsSchedulerDialog;
|
export default SchedulerDialog;
|
||||||
@@ -12,20 +12,20 @@ import { useState, useContext, useEffect } from 'react';
|
|||||||
|
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import DashboardSensorsAnalogDialog from './DashboardSensorsAnalogDialog';
|
import DashboardSensorsAnalogDialog from './SensorsAnalogDialog';
|
||||||
import DashboardSensorsTemperatureDialog from './DashboardSensorsTemperatureDialog';
|
import DashboardSensorsTemperatureDialog from './SensorsTemperatureDialog';
|
||||||
import * as EMSESP from './api';
|
import * as EMSESP from './api';
|
||||||
|
|
||||||
import { DeviceValueUOM, DeviceValueUOM_s, AnalogTypeNames, AnalogType } from './types';
|
import { DeviceValueUOM, DeviceValueUOM_s, AnalogTypeNames, AnalogType } from './types';
|
||||||
import { temperatureSensorItemValidation, analogSensorItemValidation } from './validators';
|
import { temperatureSensorItemValidation, analogSensorItemValidation } from './validators';
|
||||||
import type { TemperatureSensor, AnalogSensor } from './types';
|
import type { TemperatureSensor, AnalogSensor } from './types';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { ButtonRow, SectionContent } from 'components';
|
import { ButtonRow, SectionContent, useLayoutTitle } from 'components';
|
||||||
|
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
const DashboardSensors: FC = () => {
|
const Sensors: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const { me } = useContext(AuthenticatedContext);
|
const { me } = useContext(AuthenticatedContext);
|
||||||
const [selectedTemperatureSensor, setSelectedTemperatureSensor] = useState<TemperatureSensor>();
|
const [selectedTemperatureSensor, setSelectedTemperatureSensor] = useState<TemperatureSensor>();
|
||||||
@@ -170,6 +170,8 @@ const DashboardSensors: FC = () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useLayoutTitle(LL.SENSORS());
|
||||||
|
|
||||||
const formatDurationMin = (duration_min: number) => {
|
const formatDurationMin = (duration_min: number) => {
|
||||||
const days = Math.trunc((duration_min * 60000) / 86400000);
|
const days = Math.trunc((duration_min * 60000) / 86400000);
|
||||||
const hours = Math.trunc((duration_min * 60000) / 3600000) % 24;
|
const hours = Math.trunc((duration_min * 60000) / 3600000) % 24;
|
||||||
@@ -406,7 +408,7 @@ const DashboardSensors: FC = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SENSOR_DATA()} titleGutter>
|
<SectionContent>
|
||||||
{sensorData.ts.length > 0 && (
|
{sensorData.ts.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Typography sx={{ pt: 2, pb: 1 }} variant="h6" color="secondary">
|
<Typography sx={{ pt: 2, pb: 1 }} variant="h6" color="secondary">
|
||||||
@@ -467,4 +469,4 @@ const DashboardSensors: FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DashboardSensors;
|
export default Sensors;
|
||||||
@@ -38,7 +38,7 @@ type DashboardSensorsAnalogDialogProps = {
|
|||||||
validator: Schema;
|
validator: Schema;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DashboardSensorsAnalogDialog = ({
|
const SensorsAnalogDialog = ({
|
||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
onSave,
|
onSave,
|
||||||
@@ -296,4 +296,4 @@ const DashboardSensorsAnalogDialog = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DashboardSensorsAnalogDialog;
|
export default SensorsAnalogDialog;
|
||||||
@@ -26,7 +26,7 @@ import { numberValue, updateValue } from 'utils';
|
|||||||
|
|
||||||
import { validate } from 'validators';
|
import { validate } from 'validators';
|
||||||
|
|
||||||
type DashboardSensorsTemperatureDialogProps = {
|
type SensorsTemperatureDialogProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onSave: (ts: TemperatureSensor) => void;
|
onSave: (ts: TemperatureSensor) => void;
|
||||||
@@ -34,13 +34,13 @@ type DashboardSensorsTemperatureDialogProps = {
|
|||||||
validator: Schema;
|
validator: Schema;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DashboardSensorsTemperatureDialog = ({
|
const SensorsTemperatureDialog = ({
|
||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
onSave,
|
onSave,
|
||||||
selectedItem,
|
selectedItem,
|
||||||
validator
|
validator
|
||||||
}: DashboardSensorsTemperatureDialogProps) => {
|
}: SensorsTemperatureDialogProps) => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||||
const [editItem, setEditItem] = useState<TemperatureSensor>(selectedItem);
|
const [editItem, setEditItem] = useState<TemperatureSensor>(selectedItem);
|
||||||
@@ -119,4 +119,4 @@ const DashboardSensorsTemperatureDialog = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DashboardSensorsTemperatureDialog;
|
export default SensorsTemperatureDialog;
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import { Tab } from '@mui/material';
|
|
||||||
import { Navigate, Route, Routes } from 'react-router-dom';
|
|
||||||
|
|
||||||
import SettingsApplication from './SettingsApplication';
|
|
||||||
import SettingsCustomEntities from './SettingsCustomEntities';
|
|
||||||
import SettingsCustomization from './SettingsCustomization';
|
|
||||||
import SettingsScheduler from './SettingsScheduler';
|
|
||||||
import type { FC } from 'react';
|
|
||||||
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
|
||||||
|
|
||||||
const Settings: FC = () => {
|
|
||||||
const { LL } = useI18nContext();
|
|
||||||
const { routerTab } = useRouterTab();
|
|
||||||
|
|
||||||
useLayoutTitle(LL.SETTINGS_OF(''));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<RouterTabs value={routerTab}>
|
|
||||||
<Tab value="/settings/application" label={LL.APPLICATION_SETTINGS()} />
|
|
||||||
<Tab value="/settings/customization" label={LL.CUSTOMIZATIONS()} />
|
|
||||||
<Tab value="/settings/scheduler" label={LL.SCHEDULER()} />
|
|
||||||
<Tab value="/settings/customentities" label={LL.CUSTOM_ENTITIES(0)} />
|
|
||||||
</RouterTabs>
|
|
||||||
<Routes>
|
|
||||||
<Route path="application" element={<SettingsApplication />} />
|
|
||||||
<Route path="customization" element={<SettingsCustomization />} />
|
|
||||||
<Route path="scheduler" element={<SettingsScheduler />} />
|
|
||||||
<Route path="customentities" element={<SettingsCustomEntities />} />
|
|
||||||
<Route path="*" element={<Navigate replace to="/settings/application" />} />
|
|
||||||
</Routes>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Settings;
|
|
||||||
@@ -1054,9 +1054,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@preact/preset-vite@npm:^2.8.1":
|
"@preact/preset-vite@npm:^2.8.2":
|
||||||
version: 2.8.1
|
version: 2.8.2
|
||||||
resolution: "@preact/preset-vite@npm:2.8.1"
|
resolution: "@preact/preset-vite@npm:2.8.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/plugin-transform-react-jsx": "npm:^7.22.15"
|
"@babel/plugin-transform-react-jsx": "npm:^7.22.15"
|
||||||
"@babel/plugin-transform-react-jsx-development": "npm:^7.22.5"
|
"@babel/plugin-transform-react-jsx-development": "npm:^7.22.5"
|
||||||
@@ -1068,10 +1068,12 @@ __metadata:
|
|||||||
magic-string: "npm:0.30.5"
|
magic-string: "npm:0.30.5"
|
||||||
node-html-parser: "npm:^6.1.10"
|
node-html-parser: "npm:^6.1.10"
|
||||||
resolve: "npm:^1.22.8"
|
resolve: "npm:^1.22.8"
|
||||||
|
source-map: "npm:^0.7.4"
|
||||||
|
stack-trace: "npm:^1.0.0-pre2"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@babel/core": 7.x
|
"@babel/core": 7.x
|
||||||
vite: 2.x || 3.x || 4.x || 5.x
|
vite: 2.x || 3.x || 4.x || 5.x
|
||||||
checksum: 10/ac91fc701e078d2910b386b9e793f5429f9db04e3c56ea0f41f5f777fb21f5610acd9091def7bb2da9aaadbb9e687e1c276ff0d636fe3427ebd452dce5f98838
|
checksum: 10/a54b14afbd3a6a09836ec1469bc7924e128778a092cca875c3434989974023bf6f21f09d5c090d12c23fdb81ce9e6499bdf52a2f35c81141e9f2687158c56460
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1394,12 +1396,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/node@npm:*, @types/node@npm:^20.11.27":
|
"@types/node@npm:*, @types/node@npm:^20.11.28":
|
||||||
version: 20.11.27
|
version: 20.11.28
|
||||||
resolution: "@types/node@npm:20.11.27"
|
resolution: "@types/node@npm:20.11.28"
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: "npm:~5.26.4"
|
undici-types: "npm:~5.26.4"
|
||||||
checksum: 10/4be53485d499dd7c7896190e76a0ce1f6c6917d1f4d0b4b240b3670160fcbc548daed32beaac0fc92429b37dbeaa2496fc56f460acaab969bddb77394318a89b
|
checksum: 10/b03f69213ac6e7cd5f7efa86139f24e23ff70a12fed04adeac5413b62d6982343ce94906f74c401c5afefda48d36ae0efd6a575240996b15a5cf80b456ab4221
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1456,14 +1458,14 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/react@npm:*, @types/react@npm:^18.2.65":
|
"@types/react@npm:*, @types/react@npm:^18.2.66":
|
||||||
version: 18.2.65
|
version: 18.2.66
|
||||||
resolution: "@types/react@npm:18.2.65"
|
resolution: "@types/react@npm:18.2.66"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/prop-types": "npm:*"
|
"@types/prop-types": "npm:*"
|
||||||
"@types/scheduler": "npm:*"
|
"@types/scheduler": "npm:*"
|
||||||
csstype: "npm:^3.0.2"
|
csstype: "npm:^3.0.2"
|
||||||
checksum: 10/8022689f6c68e76b5e7b3c95af794fb3d128d5b2ccac408adaa80b117724c48b04dd4a2750e5c2ca29cd70ac7719b4ed5c5b1c12cb739d6f1d52188c09fb3060
|
checksum: 10/8a82bda6c254681536fa8348dc15d52345d8203d5d322406feef865f74ebfe2475ebde0be4e2f9a18ffbb587dac946dfb5d0974b598779ff282259aff7e8209a
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1640,12 +1642,12 @@ __metadata:
|
|||||||
"@mui/icons-material": "npm:^5.15.13"
|
"@mui/icons-material": "npm:^5.15.13"
|
||||||
"@mui/material": "npm:^5.15.13"
|
"@mui/material": "npm:^5.15.13"
|
||||||
"@preact/compat": "npm:^17.1.2"
|
"@preact/compat": "npm:^17.1.2"
|
||||||
"@preact/preset-vite": "npm:^2.8.1"
|
"@preact/preset-vite": "npm:^2.8.2"
|
||||||
"@table-library/react-table-library": "npm:4.1.7"
|
"@table-library/react-table-library": "npm:4.1.7"
|
||||||
"@types/imagemin": "npm:^8.0.5"
|
"@types/imagemin": "npm:^8.0.5"
|
||||||
"@types/lodash-es": "npm:^4.17.12"
|
"@types/lodash-es": "npm:^4.17.12"
|
||||||
"@types/node": "npm:^20.11.27"
|
"@types/node": "npm:^20.11.28"
|
||||||
"@types/react": "npm:^18.2.65"
|
"@types/react": "npm:^18.2.66"
|
||||||
"@types/react-dom": "npm:^18.2.22"
|
"@types/react-dom": "npm:^18.2.22"
|
||||||
"@types/react-router-dom": "npm:^5.3.3"
|
"@types/react-router-dom": "npm:^5.3.3"
|
||||||
"@typescript-eslint/eslint-plugin": "npm:^7.2.0"
|
"@typescript-eslint/eslint-plugin": "npm:^7.2.0"
|
||||||
@@ -1660,7 +1662,7 @@ __metadata:
|
|||||||
eslint-plugin-import: "npm:^2.29.1"
|
eslint-plugin-import: "npm:^2.29.1"
|
||||||
eslint-plugin-jsx-a11y: "npm:^6.8.0"
|
eslint-plugin-jsx-a11y: "npm:^6.8.0"
|
||||||
eslint-plugin-prettier: "npm:alpha"
|
eslint-plugin-prettier: "npm:alpha"
|
||||||
eslint-plugin-react: "npm:^7.34.0"
|
eslint-plugin-react: "npm:^7.34.1"
|
||||||
eslint-plugin-react-hooks: "npm:^4.6.0"
|
eslint-plugin-react-hooks: "npm:^4.6.0"
|
||||||
history: "npm:^5.3.0"
|
history: "npm:^5.3.0"
|
||||||
jwt-decode: "npm:^4.0.0"
|
jwt-decode: "npm:^4.0.0"
|
||||||
@@ -1673,15 +1675,15 @@ __metadata:
|
|||||||
react-dropzone: "npm:^14.2.3"
|
react-dropzone: "npm:^14.2.3"
|
||||||
react-icons: "npm:^5.0.1"
|
react-icons: "npm:^5.0.1"
|
||||||
react-router-dom: "npm:^6.22.3"
|
react-router-dom: "npm:^6.22.3"
|
||||||
react-toastify: "npm:^10.0.4"
|
react-toastify: "npm:^10.0.5"
|
||||||
rollup-plugin-visualizer: "npm:^5.12.0"
|
rollup-plugin-visualizer: "npm:^5.12.0"
|
||||||
sockette: "npm:^2.0.6"
|
sockette: "npm:^2.0.6"
|
||||||
terser: "npm:^5.29.1"
|
terser: "npm:^5.29.2"
|
||||||
typesafe-i18n: "npm:^5.26.2"
|
typesafe-i18n: "npm:^5.26.2"
|
||||||
typescript: "npm:^5.4.2"
|
typescript: "npm:^5.4.2"
|
||||||
vite: "npm:^5.1.6"
|
vite: "npm:^5.1.6"
|
||||||
vite-plugin-imagemin: "npm:^0.6.1"
|
vite-plugin-imagemin: "npm:^0.6.1"
|
||||||
vite-tsconfig-paths: "npm:^4.3.1"
|
vite-tsconfig-paths: "npm:^4.3.2"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
@@ -3008,9 +3010,9 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"electron-to-chromium@npm:^1.4.668":
|
"electron-to-chromium@npm:^1.4.668":
|
||||||
version: 1.4.703
|
version: 1.4.708
|
||||||
resolution: "electron-to-chromium@npm:1.4.703"
|
resolution: "electron-to-chromium@npm:1.4.708"
|
||||||
checksum: 10/e7927fbe75e56508dd0b4efeb0e69dfb8ee1e6e6aaf6f07c047b96ff530d8f49e1eaf51cae64c2d3c179e3932fb37661012ccaa4f36956dd96480219f3a23013
|
checksum: 10/a051ea46f9cddbda4218edfff69cdc8007a50554f4875d09706d43d7c1641267e9f81394c07f04e2d0616e989b227fe5ef36433a8b5bcfbb2185a84ebf346334
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -3686,9 +3688,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"eslint-plugin-react@npm:^7.34.0":
|
"eslint-plugin-react@npm:^7.34.1":
|
||||||
version: 7.34.0
|
version: 7.34.1
|
||||||
resolution: "eslint-plugin-react@npm:7.34.0"
|
resolution: "eslint-plugin-react@npm:7.34.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
array-includes: "npm:^3.1.7"
|
array-includes: "npm:^3.1.7"
|
||||||
array.prototype.findlast: "npm:^1.2.4"
|
array.prototype.findlast: "npm:^1.2.4"
|
||||||
@@ -3710,7 +3712,7 @@ __metadata:
|
|||||||
string.prototype.matchall: "npm:^4.0.10"
|
string.prototype.matchall: "npm:^4.0.10"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
|
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
|
||||||
checksum: 10/e09623d715e25e012cc442648616ea5f8029c17a397e7b4f54c47da7cc4edb0ffec91af3269c259c1a92b8d83802b10f9c7148280a0c8d7659b15724ee8b50d8
|
checksum: 10/ee059971065ea7e73ab5d8728774235c7dbf7a5e9f937c3b47e97f8fa9a5a96ab511d2ae6d5ec76a7e705ca666673d454f1e75a94033720819d041827f50f9c8
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -6858,15 +6860,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"react-toastify@npm:^10.0.4":
|
"react-toastify@npm:^10.0.5":
|
||||||
version: 10.0.4
|
version: 10.0.5
|
||||||
resolution: "react-toastify@npm:10.0.4"
|
resolution: "react-toastify@npm:10.0.5"
|
||||||
dependencies:
|
dependencies:
|
||||||
clsx: "npm:^2.1.0"
|
clsx: "npm:^2.1.0"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ">=16"
|
react: ">=18"
|
||||||
react-dom: ">=16"
|
react-dom: ">=18"
|
||||||
checksum: 10/57f4d0032bf328381bdfeb78ab5efa988d425627a61ffa43b0caa184633a0ea44253a349d6b967247fa3d480ad82a2bbaa9063ce3f89be9550eb9b30398a6837
|
checksum: 10/6630f4b6d6902d827efd5e66c09df693c7ab8abeeb6ef24d880080f47b636614ef9cc251dd5e6564d49fe2f6f25f720ce0f7ef72cd4b0cd58a65b7c4b8052fac
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -7605,6 +7607,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"stack-trace@npm:^1.0.0-pre2":
|
||||||
|
version: 1.0.0-pre2
|
||||||
|
resolution: "stack-trace@npm:1.0.0-pre2"
|
||||||
|
checksum: 10/a64099f86acc01980b0a7fbc662f3233bf8626daf95c53e31c835b2252ae11fc3dbfe8f3e77a7f8310132dd488af2795057cd7db599de0c41a6fa99b16068273
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"strict-uri-encode@npm:^1.0.0":
|
"strict-uri-encode@npm:^1.0.0":
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
resolution: "strict-uri-encode@npm:1.1.0"
|
resolution: "strict-uri-encode@npm:1.1.0"
|
||||||
@@ -7928,9 +7937,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"terser@npm:^5.29.1":
|
"terser@npm:^5.29.2":
|
||||||
version: 5.29.1
|
version: 5.29.2
|
||||||
resolution: "terser@npm:5.29.1"
|
resolution: "terser@npm:5.29.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jridgewell/source-map": "npm:^0.3.3"
|
"@jridgewell/source-map": "npm:^0.3.3"
|
||||||
acorn: "npm:^8.8.2"
|
acorn: "npm:^8.8.2"
|
||||||
@@ -7938,7 +7947,7 @@ __metadata:
|
|||||||
source-map-support: "npm:~0.5.20"
|
source-map-support: "npm:~0.5.20"
|
||||||
bin:
|
bin:
|
||||||
terser: bin/terser
|
terser: bin/terser
|
||||||
checksum: 10/e8c036e7cd7d9e988765272453acdc52a019827e10710cf109c86d6f31248c8d4d8aa3a3deef30f931a2bb75a8ffc731ca947bd126e7d4e6dda157e6fe892ac0
|
checksum: 10/062df6a8f99ea2635d1b3ce41cfd4180dea6e1c83db9b2cf4b525170b2446d10e069d2877d8dcb59fbf6045870efa17b56462b67045ef2d2b420870f9d144690
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -8020,7 +8029,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"tsconfck@npm:^3.0.1":
|
"tsconfck@npm:^3.0.3":
|
||||||
version: 3.0.3
|
version: 3.0.3
|
||||||
resolution: "tsconfck@npm:3.0.3"
|
resolution: "tsconfck@npm:3.0.3"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -8329,19 +8338,19 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"vite-tsconfig-paths@npm:^4.3.1":
|
"vite-tsconfig-paths@npm:^4.3.2":
|
||||||
version: 4.3.1
|
version: 4.3.2
|
||||||
resolution: "vite-tsconfig-paths@npm:4.3.1"
|
resolution: "vite-tsconfig-paths@npm:4.3.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: "npm:^4.1.1"
|
debug: "npm:^4.1.1"
|
||||||
globrex: "npm:^0.1.2"
|
globrex: "npm:^0.1.2"
|
||||||
tsconfck: "npm:^3.0.1"
|
tsconfck: "npm:^3.0.3"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: "*"
|
vite: "*"
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
vite:
|
vite:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10/1432f80750f5cbe181c265eb9fc2e9fff8b25a2858f176dc0a02311e3e826333526ee9c16bb0aaaa8555a417ea944d68a2e8225181215cd9502370f913eb3f79
|
checksum: 10/c12e2087fd01ac8a694850c649b79d5b9798cdba0ef9ab4116f669d8ffa1a9a3195c5a14410d3d9a12d2f08cd35ddd74f03d9c7b13a2d590d002055cdaab45c0
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user