mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-04-29 20:15:13 +00:00
sync with dev
This commit is contained in:
@@ -3,6 +3,7 @@ import { toast } from 'react-toastify';
|
||||
|
||||
import ForwardIcon from '@mui/icons-material/Forward';
|
||||
import { Box, Button, Paper, Typography } from '@mui/material';
|
||||
import type { Theme } from '@mui/material/styles';
|
||||
|
||||
import * as AuthenticationApi from 'components/routing/authentication';
|
||||
import { useRequest } from 'alova/client';
|
||||
@@ -36,7 +37,7 @@ const SignIn = memo(() => {
|
||||
{
|
||||
immediate: false
|
||||
}
|
||||
).onSuccess((response) => {
|
||||
).onSuccess((response: { data: { access_token: string } }) => {
|
||||
if (response.data) {
|
||||
authenticationContext.signIn(response.data.access_token);
|
||||
}
|
||||
@@ -78,7 +79,6 @@ const SignIn = memo(() => {
|
||||
}
|
||||
}, [signInRequest, signIn, LL]);
|
||||
|
||||
// Memoize callback to prevent recreation on every render
|
||||
const submitOnEnter = useMemo(() => onEnterCallback(signIn), [signIn]);
|
||||
|
||||
// get rid of scrollbar
|
||||
@@ -92,13 +92,15 @@ const SignIn = memo(() => {
|
||||
|
||||
return (
|
||||
<Box
|
||||
display="flex"
|
||||
height="100vh"
|
||||
margin="auto"
|
||||
padding={2}
|
||||
justifyContent="center"
|
||||
flexDirection="column"
|
||||
maxWidth={(theme) => theme.breakpoints.values.sm}
|
||||
sx={(theme: Theme) => ({
|
||||
display: 'flex',
|
||||
height: '100vh',
|
||||
margin: 'auto',
|
||||
padding: 2,
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
maxWidth: theme.breakpoints.values.sm
|
||||
})}
|
||||
>
|
||||
<Paper
|
||||
sx={(theme) => ({
|
||||
@@ -111,16 +113,18 @@ const SignIn = memo(() => {
|
||||
width: '100%'
|
||||
})}
|
||||
>
|
||||
<Typography mb={1} variant="h4">
|
||||
<Typography sx={{ mb: 1 }} variant="h4">
|
||||
{PROJECT_NAME}
|
||||
</Typography>
|
||||
<LanguageSelector />
|
||||
<Box
|
||||
mt={1}
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
gap={1}
|
||||
alignItems="center"
|
||||
sx={{
|
||||
mt: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 1,
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
|
||||
@@ -343,9 +343,9 @@ const CustomEntities = () => {
|
||||
return (
|
||||
<SectionContent>
|
||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||
<Box mb={2} color="warning.main">
|
||||
<Typography variant="body1">{LL.ENTITIES_HELP_1()}.</Typography>
|
||||
</Box>
|
||||
<Typography sx={{ mb: 2 }} color="warning" variant="body1">
|
||||
{LL.ENTITIES_HELP_1()}.
|
||||
</Typography>
|
||||
|
||||
{renderEntity()}
|
||||
|
||||
@@ -361,8 +361,8 @@ const CustomEntities = () => {
|
||||
/>
|
||||
)}
|
||||
|
||||
<Box mt={2} display="flex" flexWrap="wrap">
|
||||
<Box flexGrow={1}>
|
||||
<Box sx={{ mt: 2, display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
{numChanges > 0 && (
|
||||
<ButtonRow>
|
||||
<Button
|
||||
@@ -384,7 +384,7 @@ const CustomEntities = () => {
|
||||
</ButtonRow>
|
||||
)}
|
||||
</Box>
|
||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
||||
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
|
||||
<Button
|
||||
startIcon={<AddIcon />}
|
||||
variant="outlined"
|
||||
|
||||
@@ -7,7 +7,7 @@ import DoneIcon from '@mui/icons-material/Done';
|
||||
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
|
||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -178,7 +178,7 @@ const CustomEntitiesDialog = ({
|
||||
onChange={updateFormValue}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid mt={3}>
|
||||
<Grid sx={{ mt: 3 }}>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
@@ -238,7 +238,7 @@ const CustomEntitiesDialog = ({
|
||||
)}
|
||||
{editItem.ram === 0 && (
|
||||
<>
|
||||
<Grid mt={3}>
|
||||
<Grid sx={{ mt: 3 }}>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
@@ -404,7 +404,7 @@ const CustomEntitiesDialog = ({
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
{!creating && (
|
||||
<Box flexGrow={1}>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Button
|
||||
startIcon={<RemoveIcon />}
|
||||
variant="outlined"
|
||||
|
||||
@@ -470,10 +470,10 @@ const Customizations = () => {
|
||||
|
||||
const renderDeviceList = () => (
|
||||
<>
|
||||
<Box mb={1} color="warning.main">
|
||||
<Typography variant="body1">{LL.CUSTOMIZATIONS_HELP_1()}.</Typography>
|
||||
</Box>
|
||||
<Box display="flex" flexWrap="wrap" alignItems="center" gap={2}>
|
||||
<Typography sx={{ mb: 1 }} color="warning" variant="body1">
|
||||
{LL.CUSTOMIZATIONS_HELP_1()}.
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 2 }}>
|
||||
{rename ? (
|
||||
<>
|
||||
<TextField
|
||||
@@ -570,27 +570,22 @@ const Customizations = () => {
|
||||
const renderDeviceData = () => {
|
||||
return (
|
||||
<>
|
||||
<Box color="warning.main">
|
||||
<Typography variant="body2" mt={1} mb={1}>
|
||||
<OptionIcon type="favorite" isSet={true} />={LL.CUSTOMIZATIONS_HELP_2()}
|
||||
|
||||
<OptionIcon type="readonly" isSet={true} />={LL.CUSTOMIZATIONS_HELP_3()}
|
||||
|
||||
<OptionIcon type="api_mqtt_exclude" isSet={true} />=
|
||||
{LL.CUSTOMIZATIONS_HELP_4()}
|
||||
<OptionIcon type="web_exclude" isSet={true} />=
|
||||
{LL.CUSTOMIZATIONS_HELP_5()}
|
||||
<OptionIcon type="deleted" isSet={true} />={LL.CUSTOMIZATIONS_HELP_6()}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography sx={{ mt: 1, mb: 1 }} color="warning" variant="body2">
|
||||
<OptionIcon type="favorite" isSet={true} />={LL.CUSTOMIZATIONS_HELP_2()}
|
||||
|
||||
<OptionIcon type="readonly" isSet={true} />={LL.CUSTOMIZATIONS_HELP_3()}
|
||||
|
||||
<OptionIcon type="api_mqtt_exclude" isSet={true} />=
|
||||
{LL.CUSTOMIZATIONS_HELP_4()}
|
||||
<OptionIcon type="web_exclude" isSet={true} />={LL.CUSTOMIZATIONS_HELP_5()}
|
||||
|
||||
<OptionIcon type="deleted" isSet={true} />={LL.CUSTOMIZATIONS_HELP_6()}
|
||||
</Typography>
|
||||
<Grid
|
||||
container
|
||||
mb={1}
|
||||
mt={0}
|
||||
spacing={2}
|
||||
direction="row"
|
||||
justifyContent="flex-start"
|
||||
alignItems="center"
|
||||
sx={{ mb: 1, mt: 0, justifyContent: 'flex-start', alignItems: 'center' }}
|
||||
>
|
||||
<Grid>
|
||||
<TextField
|
||||
@@ -779,8 +774,8 @@ const Customizations = () => {
|
||||
</Button>
|
||||
</MessageBox>
|
||||
) : (
|
||||
<Box display="flex" flexWrap="wrap">
|
||||
<Box flexGrow={1}>
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
{numChanges !== 0 && (
|
||||
<ButtonRow>
|
||||
<Button
|
||||
|
||||
@@ -37,7 +37,7 @@ interface LabelValueProps {
|
||||
|
||||
const LabelValue = memo(({ label, value }: LabelValueProps) => (
|
||||
<Grid container direction="row">
|
||||
<Typography variant="body2" color="warning.main">
|
||||
<Typography variant="body2" color="warning">
|
||||
{label}:
|
||||
</Typography>
|
||||
<Typography variant="body2">{value}</Typography>
|
||||
@@ -131,7 +131,7 @@ const CustomizationsDialog = ({
|
||||
/>
|
||||
<LabelValue label={LL.WRITEABLE()} value={writeableIcon} />
|
||||
|
||||
<Box mt={1} mb={2}>
|
||||
<Box sx={{ mt: 1, mb: 2 }}>
|
||||
<EntityMaskToggle onUpdate={updateDeviceEntity} de={editItem} />
|
||||
</Box>
|
||||
|
||||
@@ -172,7 +172,7 @@ const CustomizationsDialog = ({
|
||||
</Grid>
|
||||
|
||||
{error && (
|
||||
<Typography variant="body2" color="error" mt={2}>
|
||||
<Typography sx={{ mt: 2 }} variant="body2" color="error">
|
||||
Error: Check min and max values
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { toast } from 'react-toastify';
|
||||
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
|
||||
import HelpOutlineIcon from '@mui/icons-material/HelpOutlined';
|
||||
import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
|
||||
import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
|
||||
import {
|
||||
@@ -263,7 +263,7 @@ const Dashboard = memo(() => {
|
||||
return (
|
||||
<>
|
||||
{data.connected && data.nodes.length > 0 && !hasFavEntities && (
|
||||
<MessageBox mb={2} level="warning">
|
||||
<MessageBox sx={{ mb: 2 }} level="warning">
|
||||
<Typography>
|
||||
{LL.NO_DATA_1()}
|
||||
<Link to="/customizations" style={{ color: 'white' }}>
|
||||
@@ -280,10 +280,12 @@ const Dashboard = memo(() => {
|
||||
)}
|
||||
|
||||
<Box
|
||||
display="flex"
|
||||
justifyContent="flex-end"
|
||||
flexWrap="nowrap"
|
||||
whiteSpace="nowrap"
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
flexWrap: 'nowrap',
|
||||
whiteSpace: 'nowrap'
|
||||
}}
|
||||
>
|
||||
<ToggleButtonGroup
|
||||
size="small"
|
||||
@@ -306,7 +308,7 @@ const Dashboard = memo(() => {
|
||||
</Box>
|
||||
|
||||
{data.nodes.length > 0 ? (
|
||||
<Box mt={1} justifyContent="center" flexDirection="column">
|
||||
<Box sx={{ mt: 1, justifyContent: 'center', flexDirection: 'column' }}>
|
||||
<IconContext.Provider
|
||||
value={{
|
||||
color: 'lightblue',
|
||||
@@ -373,13 +375,8 @@ const Dashboard = memo(() => {
|
||||
</IconContext.Provider>
|
||||
</Box>
|
||||
) : (
|
||||
<Box
|
||||
display="flex"
|
||||
// justifyContent="flex-end"
|
||||
// flexWrap="nowrap"
|
||||
// whiteSpace="nowrap"
|
||||
>
|
||||
<Typography mt={1} color="warning.main" variant="body1">
|
||||
<Box sx={{ display: 'flex' }}>
|
||||
<Typography sx={{ mt: 1 }} color="warning" variant="body1">
|
||||
no data
|
||||
</Typography>
|
||||
<Tooltip title={LL.DASHBOARD_1()}>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { memo } from 'react';
|
||||
import type { IconType } from 'react-icons';
|
||||
import { AiOutlineAlert, AiOutlineControl, AiOutlineGateway } from 'react-icons/ai';
|
||||
import { CgSmartHomeBoiler } from 'react-icons/cg';
|
||||
import { FaSolarPanel } from 'react-icons/fa';
|
||||
@@ -15,14 +16,9 @@ import { PiFan, PiGauge } from 'react-icons/pi';
|
||||
import { TiFlowSwitch, TiThermometer } from 'react-icons/ti';
|
||||
import { VscVmConnect } from 'react-icons/vsc';
|
||||
|
||||
import type { SvgIconProps } from '@mui/material';
|
||||
|
||||
import { DeviceType } from './types';
|
||||
|
||||
const deviceIconLookup: Record<
|
||||
DeviceType,
|
||||
React.ComponentType<SvgIconProps> | null
|
||||
> = {
|
||||
const deviceIconLookup: Record<DeviceType, IconType | null> = {
|
||||
[DeviceType.TEMPERATURESENSOR]: TiThermometer,
|
||||
[DeviceType.ANALOGSENSOR]: PiGauge,
|
||||
[DeviceType.BOILER]: CgSmartHomeBoiler,
|
||||
|
||||
@@ -546,7 +546,7 @@ const Devices = memo(() => {
|
||||
)
|
||||
</MessageBox>
|
||||
) : (
|
||||
<Box justifyContent="center" flexDirection="column">
|
||||
<Box sx={{ justifyContent: 'center', flexDirection: 'column' }}>
|
||||
<IconContext.Provider
|
||||
value={{
|
||||
color: 'lightblue',
|
||||
@@ -670,12 +670,12 @@ const Devices = memo(() => {
|
||||
}}
|
||||
>
|
||||
<Box sx={{ p: 1 }}>
|
||||
<Grid container justifyContent="space-between">
|
||||
<Typography noWrap variant="subtitle1" color="warning.main">
|
||||
<Grid container sx={{ justifyContent: 'space-between' }}>
|
||||
<Typography noWrap variant="subtitle1" color="warning">
|
||||
{deviceInfo.n} (
|
||||
{deviceInfo.tn})
|
||||
</Typography>
|
||||
<Grid justifyContent="flex-end">
|
||||
<Grid sx={{ justifyContent: 'flex-end' }}>
|
||||
<ButtonTooltip title={LL.CLOSE()}>
|
||||
<IconButton onClick={resetDeviceSelect} aria-label={LL.CLOSE()}>
|
||||
<HighlightOffIcon color="primary" sx={{ fontSize: 18 }} />
|
||||
|
||||
@@ -128,9 +128,9 @@ const DevicesDialog = ({
|
||||
<Dialog sx={dialogStyle} open={open} onClose={onClose}>
|
||||
<DialogTitle>{dialogTitle}</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Box color="warning.main" mb={2}>
|
||||
<Typography variant="body2">{editItem.id.slice(2)}</Typography>
|
||||
</Box>
|
||||
<Typography sx={{ mb: 2 }} color="warning" variant="body2">
|
||||
{editItem.id.slice(2)}
|
||||
</Typography>
|
||||
<Grid container>
|
||||
<Grid size={12}>
|
||||
{editItem.l ? (
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
Box,
|
||||
Button,
|
||||
Divider,
|
||||
Grid,
|
||||
Link,
|
||||
List,
|
||||
ListItem,
|
||||
@@ -42,7 +43,7 @@ interface CustomSupport {
|
||||
html: string | null;
|
||||
}
|
||||
|
||||
const DEFAULT_IMAGE_URL = 'https://emsesp.org/_media/images/installer.jpeg';
|
||||
const DEFAULT_IMAGE_URL = 'https://emsesp.org/media/images/installer.jpeg';
|
||||
|
||||
const SUPPORT_BOX_STYLES: SxProps<Theme> = {
|
||||
borderRadius: 3,
|
||||
@@ -71,7 +72,6 @@ const HelpComponent = () => {
|
||||
});
|
||||
const [imgError, setImgError] = useState<boolean>(false);
|
||||
|
||||
// Memoize the request method to prevent re-creation on every render
|
||||
const getCustomSupportMethod = useMemo(
|
||||
() => callAction({ action: 'getCustomSupport' }),
|
||||
[]
|
||||
@@ -146,11 +146,9 @@ const HelpComponent = () => {
|
||||
<SectionContent>
|
||||
{customSupport.html && (
|
||||
<Stack
|
||||
padding={1}
|
||||
mb={2}
|
||||
direction="row"
|
||||
divider={<Divider orientation="vertical" flexItem />}
|
||||
sx={SUPPORT_BOX_STYLES}
|
||||
sx={{ padding: 1, mb: 2, ...SUPPORT_BOX_STYLES }}
|
||||
>
|
||||
<Typography variant="subtitle1">
|
||||
<div dangerouslySetInnerHTML={{ __html: customSupport.html }} />
|
||||
@@ -185,9 +183,9 @@ const HelpComponent = () => {
|
||||
</List>
|
||||
)}
|
||||
|
||||
<Box p={2} color="warning.main">
|
||||
<Typography mb={1} variant="body1">
|
||||
{LL.HELP_INFORMATION_4()}.
|
||||
<Grid container spacing={2} sx={{ mt: 2, alignItems: 'center' }}>
|
||||
<Typography sx={{ mb: 1 }} color="warning" variant="body1">
|
||||
{LL.HELP_INFORMATION_4()}:
|
||||
</Typography>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
@@ -197,11 +195,11 @@ const HelpComponent = () => {
|
||||
>
|
||||
{LL.SUPPORT_INFORMATION(0)}
|
||||
</Button>
|
||||
</Box>
|
||||
</Grid>
|
||||
|
||||
<Divider sx={{ mt: 4 }} />
|
||||
|
||||
<Typography color="white" variant="subtitle1" align="center" mt={1}>
|
||||
<Typography color="white" variant="subtitle1" align="center" sx={{ mt: 1 }}>
|
||||
©
|
||||
<Link
|
||||
target="_blank"
|
||||
|
||||
@@ -186,9 +186,9 @@ const Modules = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box mb={2} color="warning.main">
|
||||
<Typography variant="body1">{LL.MODULES_DESCRIPTION()}.</Typography>
|
||||
</Box>
|
||||
<Typography sx={{ mb: 2 }} color="warning" variant="body1">
|
||||
{LL.MODULES_DESCRIPTION()}.
|
||||
</Typography>
|
||||
<Table
|
||||
data={{ nodes: modules }}
|
||||
theme={modules_theme}
|
||||
@@ -236,8 +236,8 @@ const Modules = () => {
|
||||
)}
|
||||
</Table>
|
||||
|
||||
<Box mt={1} display="flex" flexWrap="wrap">
|
||||
<Box flexGrow={1}>
|
||||
<Box sx={{ mt: 1, display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
{numChanges !== 0 && (
|
||||
<ButtonRow>
|
||||
<Button
|
||||
|
||||
@@ -79,7 +79,7 @@ const ModulesDialog = ({
|
||||
label="Enabled"
|
||||
/>
|
||||
</Grid>
|
||||
<Box mt={2} mb={1}>
|
||||
<Box sx={{ mt: 2, mb: 1 }}>
|
||||
<TextField
|
||||
name="license"
|
||||
label="License Key"
|
||||
|
||||
@@ -2,12 +2,12 @@ import { memo } from 'react';
|
||||
|
||||
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
|
||||
import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
|
||||
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
||||
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutlined';
|
||||
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
|
||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
|
||||
import StarIcon from '@mui/icons-material/Star';
|
||||
import StarOutlineIcon from '@mui/icons-material/StarOutline';
|
||||
import StarOutlineIcon from '@mui/icons-material/StarOutlined';
|
||||
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
|
||||
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
|
||||
import type { SvgIconProps } from '@mui/material';
|
||||
|
||||
@@ -358,9 +358,9 @@ const Scheduler = () => {
|
||||
return (
|
||||
<SectionContent>
|
||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||
<Box mb={2} color="warning.main">
|
||||
<Typography variant="body1">{LL.SCHEDULER_HELP_1()}.</Typography>
|
||||
</Box>
|
||||
<Typography sx={{ mb: 2 }} color="warning" variant="body1">
|
||||
{LL.SCHEDULER_HELP_1()}.
|
||||
</Typography>
|
||||
{renderSchedule()}
|
||||
|
||||
{selectedScheduleItem && (
|
||||
@@ -375,8 +375,8 @@ const Scheduler = () => {
|
||||
/>
|
||||
)}
|
||||
|
||||
<Box display="flex" flexWrap="wrap">
|
||||
<Box flexGrow={1}>
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
{numChanges !== 0 && (
|
||||
<ButtonRow>
|
||||
<Button
|
||||
@@ -398,7 +398,7 @@ const Scheduler = () => {
|
||||
</ButtonRow>
|
||||
)}
|
||||
</Box>
|
||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
||||
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
|
||||
<ButtonRow>
|
||||
<Button
|
||||
startIcon={<AddIcon />}
|
||||
|
||||
@@ -4,7 +4,7 @@ import AddIcon from '@mui/icons-material/Add';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import DoneIcon from '@mui/icons-material/Done';
|
||||
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -338,11 +338,13 @@ const SchedulerDialog = ({
|
||||
onChange={updateFormValue}
|
||||
/>
|
||||
{isTimerSchedule && (
|
||||
<Box color="warning.main" ml={2} mt={4}>
|
||||
<Typography variant="body2">
|
||||
{LL.SCHEDULER_HELP_2()}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{ ml: 2, mt: 4 }}
|
||||
color="warning"
|
||||
variant="body2"
|
||||
>
|
||||
{LL.SCHEDULER_HELP_2()}
|
||||
</Typography>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
@@ -391,7 +393,7 @@ const SchedulerDialog = ({
|
||||
|
||||
<DialogActions>
|
||||
{!creating && (
|
||||
<Box flexGrow={1}>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Button
|
||||
startIcon={<RemoveIcon />}
|
||||
variant="outlined"
|
||||
|
||||
@@ -591,7 +591,14 @@ const Sensors = () => {
|
||||
/>
|
||||
)}
|
||||
{sensorData?.analog_enabled === true && me.admin && (
|
||||
<Box mt={2} display="flex" flexWrap="wrap" justifyContent="flex-end">
|
||||
<Box
|
||||
sx={{
|
||||
mt: 2,
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'flex-end'
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import DoneIcon from '@mui/icons-material/Done';
|
||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
|
||||
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined';
|
||||
import WarningIcon from '@mui/icons-material/Warning';
|
||||
import {
|
||||
Box,
|
||||
@@ -479,7 +479,7 @@ const SensorsAnalogDialog = ({
|
||||
)}
|
||||
</Grid>
|
||||
{fieldErrors && Object.keys(fieldErrors).length > 0 && (
|
||||
<Box mt={1}>
|
||||
<Box sx={{ mt: 1 }}>
|
||||
{Object.values(fieldErrors).map((errArr, idx) =>
|
||||
Array.isArray(errArr)
|
||||
? errArr.map((err, j) => (
|
||||
@@ -487,7 +487,7 @@ const SensorsAnalogDialog = ({
|
||||
key={`${idx}-${j}`}
|
||||
color="error"
|
||||
variant="caption"
|
||||
display="block"
|
||||
sx={{ display: 'block' }}
|
||||
>
|
||||
{err.message}
|
||||
</Typography>
|
||||
@@ -498,7 +498,7 @@ const SensorsAnalogDialog = ({
|
||||
)}
|
||||
{editItem.s && (
|
||||
<Grid>
|
||||
<Typography mt={1} color="warning.main" variant="body2">
|
||||
<Typography sx={{ mt: 1 }} color="warning" variant="body2">
|
||||
<WarningIcon
|
||||
fontSize="small"
|
||||
sx={{ mr: 1, verticalAlign: 'middle' }}
|
||||
@@ -511,7 +511,7 @@ const SensorsAnalogDialog = ({
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
{!creating && (
|
||||
<Box flexGrow={1} sx={{ '& button': { mt: 0 } }}>
|
||||
<Box sx={{ flexGrow: 1, '& button': { mt: 0 } }}>
|
||||
<Button
|
||||
startIcon={<RemoveIcon />}
|
||||
disabled={editItem.s}
|
||||
|
||||
@@ -4,7 +4,6 @@ import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import DoneIcon from '@mui/icons-material/Done';
|
||||
import WarningIcon from '@mui/icons-material/Warning';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
@@ -111,11 +110,9 @@ const SensorsTemperatureDialog = ({
|
||||
<Dialog sx={dialogStyle} open={open} onClose={handleClose}>
|
||||
<DialogTitle>{dialogTitle}</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Box color="warning.main" mb={2}>
|
||||
<Typography variant="body2">
|
||||
{LL.ID_OF(LL.SENSOR(0))}: {editItem.id}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography sx={{ mb: 2 }} color="warning" variant="body2">
|
||||
{LL.ID_OF(LL.SENSOR(0))}: {editItem.id}
|
||||
</Typography>
|
||||
<Grid container spacing={2}>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
@@ -142,7 +139,7 @@ const SensorsTemperatureDialog = ({
|
||||
</Grid>
|
||||
{editItem.s && (
|
||||
<Grid>
|
||||
<Typography mt={1} color="warning.main" variant="body2">
|
||||
<Typography sx={{ mt: 1 }} color="warning" variant="body2">
|
||||
<WarningIcon
|
||||
fontSize="small"
|
||||
sx={{ mr: 1, verticalAlign: 'middle' }}
|
||||
|
||||
@@ -41,8 +41,12 @@ const UserProfileComponent = () => {
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
<Box mt={2} mb={2} display="flex" alignItems="center">
|
||||
<Typography mr={2} variant="body1" align="center">
|
||||
<Box sx={{ mt: 2, mb: 2, display: 'flex', alignItems: 'center' }}>
|
||||
<Typography
|
||||
sx={{ mr: 2, textAlign: 'center' }}
|
||||
color="warning"
|
||||
variant="body1"
|
||||
>
|
||||
{LL.LANGUAGE()}:
|
||||
</Typography>
|
||||
<LanguageSelector />
|
||||
|
||||
@@ -43,16 +43,6 @@ export interface Settings {
|
||||
modbus_port: number;
|
||||
modbus_max_clients: number;
|
||||
modbus_timeout: number;
|
||||
email_enabled: boolean;
|
||||
email_ssl?: boolean;
|
||||
email_starttls?: boolean;
|
||||
email_server: string;
|
||||
email_port: number;
|
||||
email_login: string;
|
||||
email_pass: string;
|
||||
email_sender: string;
|
||||
email_recp: string;
|
||||
email_subject: string;
|
||||
developer_mode: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
FormLoader,
|
||||
MessageBox,
|
||||
SectionContent,
|
||||
ValidatedPasswordField,
|
||||
ValidatedTextField,
|
||||
useLayoutTitle
|
||||
} from 'components';
|
||||
@@ -352,156 +351,6 @@ const ApplicationSettings = () => {
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
<Typography color="secondary">eMail</Typography>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.email_enabled}
|
||||
onChange={updateFormValue}
|
||||
name="email_enabled"
|
||||
disabled={!hardwareData.psram}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Typography color={!hardwareData.psram ? 'grey' : 'default'}>
|
||||
Enable eMail notification
|
||||
{!hardwareData.psram && (
|
||||
<Typography variant="caption">
|
||||
({LL.IS_REQUIRED('PSRAM')})
|
||||
</Typography>
|
||||
)}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
{data.email_enabled && (
|
||||
<>
|
||||
<Grid
|
||||
container
|
||||
spacing={2}
|
||||
direction="row"
|
||||
justifyContent="flex-start"
|
||||
alignItems="flex-start"
|
||||
>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_server"
|
||||
label="SMTP Server"
|
||||
variant="outlined"
|
||||
value={data.email_server}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
sx={{ width: '12ch' }}
|
||||
name="email_port"
|
||||
variant="outlined"
|
||||
label="Port"
|
||||
value={numberValue(data.email_port)}
|
||||
type="number"
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid size={4} mt={!data.email_ssl && !data.email_starttls ? 0 : 3}>
|
||||
{!data.email_starttls && (
|
||||
<BlockFormControlLabel
|
||||
sx={{ width: '12ch' }}
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.email_ssl}
|
||||
onChange={updateFormValue}
|
||||
name="email_ssl"
|
||||
disabled={
|
||||
data.email_starttls || data.email_ssl === undefined
|
||||
}
|
||||
/>
|
||||
}
|
||||
label="SSL/TLS"
|
||||
/>
|
||||
)}
|
||||
{!data.email_ssl && (
|
||||
<BlockFormControlLabel
|
||||
sx={{ width: '12ch' }}
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.email_starttls}
|
||||
onChange={updateFormValue}
|
||||
name="email_starttls"
|
||||
disabled={
|
||||
data.email_ssl || data.email_starttls === undefined
|
||||
}
|
||||
/>
|
||||
}
|
||||
label="STARTTLS"
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={2} rowSpacing={0}>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_login"
|
||||
label="Login"
|
||||
variant="outlined"
|
||||
value={data.email_login}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ValidatedPasswordField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_pass"
|
||||
label="Password"
|
||||
variant="outlined"
|
||||
value={data.email_pass}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={2} rowSpacing={0}>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_sender"
|
||||
label="From"
|
||||
variant="outlined"
|
||||
value={data.email_sender}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_recp"
|
||||
label="To"
|
||||
variant="outlined"
|
||||
value={data.email_recp}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="email_subject"
|
||||
label="Subject"
|
||||
variant="outlined"
|
||||
value={data.email_subject}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
<Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary">
|
||||
{LL.SENSORS()}
|
||||
</Typography>
|
||||
@@ -922,7 +771,7 @@ const ApplicationSettings = () => {
|
||||
label={LL.REMOTE_TIMEOUT_EN()}
|
||||
/>
|
||||
{data.remote_timeout_en && (
|
||||
<Box mt={2}>
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="remote_timeout"
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||
import { Box, Button, Grid, Typography } from '@mui/material';
|
||||
import WarningIcon from '@mui/icons-material/Warning';
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Grid,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
|
||||
import * as SystemApi from 'api/system';
|
||||
import { API, callAction } from 'api/app';
|
||||
|
||||
import { dialogStyle } from '@/CustomTheme';
|
||||
import { useRequest } from 'alova/client';
|
||||
import type { APIcall } from 'app/main/types';
|
||||
import SystemMonitor from 'app/status/SystemMonitor';
|
||||
@@ -19,15 +30,11 @@ import {
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { saveFile } from 'utils';
|
||||
|
||||
interface DownloadButton {
|
||||
type: string;
|
||||
label: string | number;
|
||||
isGridButton: boolean;
|
||||
}
|
||||
|
||||
const DownloadUpload = () => {
|
||||
const { LL } = useI18nContext();
|
||||
|
||||
const [confirmBackup, setConfirmBackup] = useState<boolean>(false);
|
||||
|
||||
const [restarting, setRestarting] = useState<boolean>(false);
|
||||
|
||||
const { send: sendExportData } = useRequest(
|
||||
@@ -62,40 +69,44 @@ const DownloadUpload = () => {
|
||||
|
||||
useLayoutTitle(LL.DOWNLOAD_UPLOAD());
|
||||
|
||||
const downloadButtons: DownloadButton[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
type: 'settings',
|
||||
label: LL.SETTINGS_OF(LL.APPLICATION()),
|
||||
isGridButton: true
|
||||
},
|
||||
{
|
||||
type: 'customizations',
|
||||
label: LL.CUSTOMIZATIONS(),
|
||||
isGridButton: true
|
||||
},
|
||||
{
|
||||
type: 'entities',
|
||||
label: LL.CUSTOM_ENTITIES(0),
|
||||
isGridButton: true
|
||||
},
|
||||
{
|
||||
type: 'schedule',
|
||||
label: LL.SCHEDULE(0),
|
||||
isGridButton: true
|
||||
},
|
||||
{
|
||||
type: 'systembackup',
|
||||
label: LL.DOWNLOAD_SYSTEM_BACKUP(),
|
||||
isGridButton: true
|
||||
},
|
||||
{
|
||||
type: 'allvalues',
|
||||
label: LL.ALLVALUES(),
|
||||
isGridButton: false
|
||||
}
|
||||
],
|
||||
[LL]
|
||||
const handleCloseBackupDialog = useCallback(() => {
|
||||
setConfirmBackup(false);
|
||||
}, []);
|
||||
|
||||
const renderBackupDialog = useMemo(
|
||||
() => (
|
||||
<Dialog
|
||||
sx={dialogStyle}
|
||||
open={confirmBackup}
|
||||
onClose={handleCloseBackupDialog}
|
||||
>
|
||||
<DialogTitle>{LL.DOWNLOAD_SYSTEM_BACKUP()}</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<WarningIcon color="warning" sx={{ fontSize: 18 }} />
|
||||
|
||||
{LL.WARNING_SYSTEM_BACKUP()}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
startIcon={<CancelIcon />}
|
||||
variant="outlined"
|
||||
onClick={handleCloseBackupDialog}
|
||||
color="secondary"
|
||||
>
|
||||
{LL.CANCEL()}
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
onClick={() => handleDownload('systembackup')()}
|
||||
color="primary"
|
||||
>
|
||||
{LL.DOWNLOAD(0)}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
),
|
||||
[confirmBackup, handleCloseBackupDialog, LL]
|
||||
);
|
||||
|
||||
const handleDownload = useCallback(
|
||||
@@ -117,58 +128,57 @@ const DownloadUpload = () => {
|
||||
);
|
||||
}
|
||||
|
||||
const gridButtons = downloadButtons.filter((btn) => btn.isGridButton);
|
||||
const standaloneButton = downloadButtons.find((btn) => !btn.isGridButton);
|
||||
|
||||
return (
|
||||
<SectionContent>
|
||||
{renderBackupDialog}
|
||||
|
||||
<Typography sx={{ pb: 2 }} variant="h6" color="primary">
|
||||
{LL.DOWNLOAD(0)}
|
||||
</Typography>
|
||||
|
||||
<Typography mb={1} variant="body1" color="warning">
|
||||
{LL.DOWNLOAD_SETTINGS_TEXT()}.
|
||||
</Typography>
|
||||
|
||||
<Grid container spacing={2}>
|
||||
{gridButtons.map((button) => (
|
||||
<Grid key={button.type}>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={handleDownload(button.type)}
|
||||
>
|
||||
{button.label}
|
||||
</Button>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
|
||||
<Typography mt={2} mb={1} variant="body1" color="warning">
|
||||
{LL.DOWNLOAD_SETTINGS_TEXT2()}.
|
||||
</Typography>
|
||||
|
||||
{standaloneButton && (
|
||||
<Grid
|
||||
container
|
||||
spacing={2}
|
||||
sx={{
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography variant="body1" color="warning">
|
||||
{LL.DOWNLOAD_SETTINGS_TEXT()}:
|
||||
</Typography>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={handleDownload(standaloneButton.type)}
|
||||
onClick={() => setConfirmBackup(true)}
|
||||
>
|
||||
{standaloneButton.label}
|
||||
{LL.DOWNLOAD_SYSTEM_BACKUP()}
|
||||
</Button>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
<Grid container spacing={2} sx={{ mt: 2, alignItems: 'center' }}>
|
||||
<Typography variant="body1" color="warning">
|
||||
{LL.DOWNLOAD_SETTINGS_TEXT2()}:
|
||||
</Typography>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={handleDownload('allvalues')}
|
||||
>
|
||||
{LL.ALLVALUES()}
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||
{LL.UPLOAD()}
|
||||
</Typography>
|
||||
|
||||
<Box color="warning.main" sx={{ pb: 2 }}>
|
||||
<Typography variant="body1">{LL.UPLOAD_TEXT()}.</Typography>
|
||||
</Box>
|
||||
<Typography sx={{ pb: 2 }} color="warning" variant="body1">
|
||||
{LL.UPLOAD_TEXT()}:
|
||||
</Typography>
|
||||
|
||||
<SingleUpload text={LL.UPLOAD_DRAG()} doRestart={doRestart} />
|
||||
<SingleUpload doRestart={doRestart} />
|
||||
</SectionContent>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -129,7 +129,7 @@ const MqttSettings = () => {
|
||||
<SectionContent>
|
||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||
<>
|
||||
<Box display="flex" gap={2} mb={1}>
|
||||
<Box sx={{ display: 'flex', gap: 2, mb: 1 }}>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
|
||||
@@ -193,9 +193,9 @@ const NTPSettings = () => {
|
||||
{timeZoneItems}
|
||||
</ValidatedTextField>
|
||||
|
||||
<Box display="flex" flexWrap="wrap">
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
{!data.enabled && !dirtyFlags.length && (
|
||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
||||
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
|
||||
<ButtonRow>
|
||||
<Button
|
||||
onClick={openSetTime}
|
||||
@@ -259,9 +259,9 @@ const NTPSettings = () => {
|
||||
<Dialog sx={dialogStyle} open={settingTime} onClose={handleCloseSetTime}>
|
||||
<DialogTitle>{LL.SET_TIME(1)}</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Box color="warning.main" p={0} pl={0} pr={0} mt={0} mb={2}>
|
||||
<Typography variant="body2">{LL.SET_TIME_TEXT()}</Typography>
|
||||
</Box>
|
||||
<Typography color="warning" variant="body2">
|
||||
{LL.SET_TIME_TEXT()}
|
||||
</Typography>
|
||||
<TextField
|
||||
label={LL.LOCAL_TIME(0)}
|
||||
type="datetime-local"
|
||||
|
||||
@@ -156,11 +156,13 @@ const Settings = () => {
|
||||
<Divider />
|
||||
|
||||
<Box
|
||||
mt={2}
|
||||
display="flex"
|
||||
justifyContent="flex-end"
|
||||
flexWrap="nowrap"
|
||||
whiteSpace="nowrap"
|
||||
sx={{
|
||||
mt: 2,
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
flexWrap: 'nowrap',
|
||||
whiteSpace: 'nowrap'
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
startIcon={<SettingsBackupRestoreIcon />}
|
||||
|
||||
@@ -54,19 +54,27 @@ const GenerateToken = ({ username, onClose }: GenerateTokenProps) => {
|
||||
<DialogContent dividers>
|
||||
{token ? (
|
||||
<>
|
||||
<MessageBox message={LL.ACCESS_TOKEN_TEXT()} level="info" my={2} />
|
||||
<Box mt={2} mb={2}>
|
||||
<MessageBox
|
||||
message={LL.ACCESS_TOKEN_TEXT()}
|
||||
level="info"
|
||||
sx={{ mt: 2, mb: 2 }}
|
||||
/>
|
||||
<Box sx={{ mt: 2, mb: 2 }}>
|
||||
<TextField
|
||||
label="Token"
|
||||
multiline
|
||||
value={token.token}
|
||||
fullWidth
|
||||
contentEditable={false}
|
||||
slotProps={{
|
||||
input: {
|
||||
readOnly: true
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
<Box m={4} textAlign="center">
|
||||
<Box sx={{ m: 4, textAlign: 'center' }}>
|
||||
<LinearProgress />
|
||||
<Typography variant="h6">{LL.GENERATING_TOKEN()}…</Typography>
|
||||
</Box>
|
||||
|
||||
@@ -240,12 +240,16 @@ const ManageUsers = () => {
|
||||
</Table>
|
||||
|
||||
{noAdminConfigured() && (
|
||||
<MessageBox level="warning" message={LL.USER_WARNING()} my={2} />
|
||||
<MessageBox
|
||||
level="warning"
|
||||
message={LL.USER_WARNING()}
|
||||
sx={{ mt: 2, mb: 2 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Box display="flex" flexWrap="wrap">
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
{changed !== 0 && (
|
||||
<Box flexGrow={1} sx={{ '& button': { mt: 2 } }}>
|
||||
<Box sx={{ flexGrow: 1, '& button': { mt: 2 } }}>
|
||||
<ButtonRow>
|
||||
<Button
|
||||
startIcon={<CancelIcon />}
|
||||
@@ -270,7 +274,7 @@ const ManageUsers = () => {
|
||||
</ButtonRow>
|
||||
</Box>
|
||||
)}
|
||||
<Box flexWrap="nowrap" whiteSpace="nowrap">
|
||||
<Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
|
||||
<ButtonRow>
|
||||
<Button
|
||||
startIcon={<PersonAddIcon />}
|
||||
|
||||
@@ -266,7 +266,7 @@ const SystemLog = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid container spacing={2} alignItems="center">
|
||||
<Grid container spacing={2} sx={{ alignItems: 'center' }}>
|
||||
<Grid>
|
||||
<TextField
|
||||
name="level"
|
||||
|
||||
@@ -118,17 +118,15 @@ const SystemMonitor = () => {
|
||||
p: 3
|
||||
}}
|
||||
>
|
||||
<Box display="flex" alignItems="center" flexDirection="column">
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', flexDirection: 'column' }}>
|
||||
<img
|
||||
src="/app/icon.png"
|
||||
alt="EMS-ESP"
|
||||
style={{ width: '40px', height: '40px', marginBottom: '16px' }}
|
||||
/>
|
||||
<Typography
|
||||
color="secondary"
|
||||
sx={{ color: 'secondary', fontWeight: 400, textAlign: 'center' }}
|
||||
variant="h6"
|
||||
fontWeight={400}
|
||||
textAlign="center"
|
||||
>
|
||||
{statusMessage}
|
||||
</Typography>
|
||||
@@ -148,11 +146,14 @@ const SystemMonitor = () => {
|
||||
</MessageBox>
|
||||
) : (
|
||||
<>
|
||||
<Typography mt={2} variant="h6" fontWeight={400} textAlign="center">
|
||||
<Typography
|
||||
sx={{ mt: 2, fontWeight: 400, textAlign: 'center' }}
|
||||
variant="h6"
|
||||
>
|
||||
{LL.PLEASE_WAIT()}…
|
||||
</Typography>
|
||||
{isUploading && (
|
||||
<Box width="100%" pl={2} pr={2} py={2}>
|
||||
<Box sx={{ width: '100%', pl: 2, pr: 2, py: 2 }}>
|
||||
<LinearProgressWithLabel value={progressValue} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -274,6 +274,8 @@ const InstallDialog = memo(
|
||||
fetchDevVersion,
|
||||
latestVersion,
|
||||
latestDevVersion,
|
||||
upgradeImportantMessageType,
|
||||
downloadOnly,
|
||||
platform,
|
||||
LL,
|
||||
onClose,
|
||||
@@ -283,6 +285,8 @@ const InstallDialog = memo(
|
||||
fetchDevVersion: boolean;
|
||||
latestVersion?: VersionInfo;
|
||||
latestDevVersion?: VersionInfo;
|
||||
upgradeImportantMessageType: number;
|
||||
downloadOnly: boolean;
|
||||
platform: string;
|
||||
LL: TranslationFunctions;
|
||||
onClose: () => void;
|
||||
@@ -305,12 +309,24 @@ const InstallDialog = memo(
|
||||
{`${LL.INSTALL()} ${fetchDevVersion ? LL.DEVELOPMENT() : LL.STABLE()} Firmware`}
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Typography mb={2}>
|
||||
<Typography sx={{ mb: 2 }}>
|
||||
{LL.INSTALL_VERSION(
|
||||
LL.INSTALL(),
|
||||
downloadOnly ? LL.DOWNLOAD(1) : LL.INSTALL(),
|
||||
fetchDevVersion ? latestDevVersion?.name : latestVersion?.name
|
||||
)}
|
||||
</Typography>
|
||||
|
||||
{upgradeImportantMessageType === 1 && LL.UPGRADE_IMPORTANT_MESSAGES_1()}
|
||||
{upgradeImportantMessageType === 2 && LL.UPGRADE_IMPORTANT_MESSAGES_2()}
|
||||
<Typography sx={{ mt: 2 }}>
|
||||
<Link
|
||||
target="_blank"
|
||||
to="https://docs.emsesp.org/FAQ#upgrading-the-firmware"
|
||||
style={{ color: 'lightblue' }}
|
||||
>
|
||||
{LL.ONLINE_HELP()}
|
||||
</Link>
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
@@ -331,14 +347,16 @@ const InstallDialog = memo(
|
||||
{LL.DOWNLOAD(0)}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<WarningIcon color="warning" />}
|
||||
variant="outlined"
|
||||
onClick={() => onInstall(binURL)}
|
||||
color="primary"
|
||||
>
|
||||
{LL.INSTALL()}
|
||||
</Button>
|
||||
{!downloadOnly && (
|
||||
<Button
|
||||
startIcon={<WarningIcon color="warning" />}
|
||||
variant="outlined"
|
||||
onClick={() => onInstall(binURL)}
|
||||
color="primary"
|
||||
>
|
||||
{LL.INSTALL()}
|
||||
</Button>
|
||||
)}
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
@@ -367,7 +385,9 @@ const InstallPartitionDialog = memo(
|
||||
{LL.INSTALL()} {LL.STORED_VERSIONS()}
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Typography mb={2}>{LL.INSTALL_VERSION(LL.INSTALL(), version)}</Typography>
|
||||
<Typography sx={{ mb: 2 }}>
|
||||
{LL.INSTALL_VERSION(LL.INSTALL(), version)}
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
@@ -419,6 +439,7 @@ const Version = () => {
|
||||
const [stableUpgradeAvailable, setStableUpgradeAvailable] =
|
||||
useState<boolean>(false);
|
||||
const [internetLive, setInternetLive] = useState<boolean>(false);
|
||||
const [downloadOnly, setDownloadOnly] = useState<boolean>(false);
|
||||
const [showVersionInfo, setShowVersionInfo] = useState<number>(0); // 1 = stable, 2 = dev, 3 = partition
|
||||
const [firmwareSize, setFirmwareSize] = useState<number>(0);
|
||||
|
||||
@@ -444,6 +465,9 @@ const Version = () => {
|
||||
error
|
||||
} = useRequest(SystemApi.readSystemStatus).onSuccess((event) => {
|
||||
const systemData = event.data as VersionData;
|
||||
if (systemData.arduino_version.startsWith('Tasmota')) {
|
||||
setDownloadOnly(true);
|
||||
}
|
||||
setUsingDevVersion(systemData.emsesp_version.includes('dev'));
|
||||
});
|
||||
|
||||
@@ -459,6 +483,26 @@ const Version = () => {
|
||||
immediate: false
|
||||
});
|
||||
|
||||
const [upgradeImportantMessageType, setUpgradeImportantMessageType] =
|
||||
useState<number>(0);
|
||||
|
||||
const { send: checkUpgradeImportantMessages } = useRequest(
|
||||
(version: string) =>
|
||||
callAction({ action: 'upgradeImportantMessages', param: version }),
|
||||
{
|
||||
immediate: false
|
||||
}
|
||||
)
|
||||
.onSuccess((event) => {
|
||||
const upgradeImportantMessageType_n = (
|
||||
event.data as { upgradeImportantMessageType: number }
|
||||
).upgradeImportantMessageType;
|
||||
setUpgradeImportantMessageType(upgradeImportantMessageType_n);
|
||||
})
|
||||
.onError((error) => {
|
||||
toast.error(String(error.error?.message || 'An error occurred'));
|
||||
});
|
||||
|
||||
// Memoized values
|
||||
const platform = useMemo(() => (data ? getPlatform(data) : ''), [data]);
|
||||
|
||||
@@ -524,10 +568,16 @@ const Version = () => {
|
||||
[]
|
||||
);
|
||||
|
||||
const showFirmwareDialog = useCallback((useDevVersion: boolean) => {
|
||||
setFetchDevVersion(useDevVersion);
|
||||
setOpenInstallDialog(true);
|
||||
}, []);
|
||||
const showFirmwareDialog = useCallback(
|
||||
(useDevVersion: boolean) => {
|
||||
setFetchDevVersion(useDevVersion);
|
||||
void checkUpgradeImportantMessages(
|
||||
useDevVersion ? latestDevVersion?.name : latestVersion?.name
|
||||
);
|
||||
setOpenInstallDialog(true);
|
||||
},
|
||||
[latestDevVersion, latestVersion, fetchDevVersion]
|
||||
);
|
||||
|
||||
const closeInstallDialog = useCallback(() => {
|
||||
setOpenInstallDialog(false);
|
||||
@@ -629,8 +679,8 @@ const Version = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box p={2} border="1px solid grey" borderRadius={2}>
|
||||
<Typography mb={1} variant="h6" color="primary">
|
||||
<Box sx={{ p: 2, border: '1px solid #565656', borderRadius: 2 }}>
|
||||
<Typography sx={{ mb: 1 }} variant="h6" color="primary">
|
||||
{LL.THIS_VERSION()}
|
||||
</Typography>
|
||||
|
||||
@@ -695,7 +745,7 @@ const Version = () => {
|
||||
|
||||
{internetLive ? (
|
||||
<>
|
||||
<Typography mt={4} mb={1} variant="h6" color="primary">
|
||||
<Typography sx={{ mt: 4, mb: 1 }} variant="h6" color="primary">
|
||||
{LL.AVAILABLE_VERSION()}
|
||||
</Typography>
|
||||
|
||||
@@ -717,7 +767,7 @@ const Version = () => {
|
||||
</Grid>
|
||||
<Grid size={{ xs: 8, md: 10 }}>
|
||||
{otherPartitions.map((partition) => (
|
||||
<Typography key={partition.partition} mb={1}>
|
||||
<Typography key={partition.partition} sx={{ mb: 1 }}>
|
||||
{partition.version}
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
@@ -783,7 +833,7 @@ const Version = () => {
|
||||
</Grid>
|
||||
</>
|
||||
) : (
|
||||
<Typography mt={2} color="warning">
|
||||
<Typography sx={{ mt: 2 }} color="warning">
|
||||
<WarningIcon color="warning" sx={{ verticalAlign: 'middle', mr: 2 }} />
|
||||
{LL.INTERNET_CONNECTION_REQUIRED()}
|
||||
</Typography>
|
||||
@@ -807,6 +857,8 @@ const Version = () => {
|
||||
fetchDevVersion={fetchDevVersion}
|
||||
latestVersion={latestVersion}
|
||||
latestDevVersion={latestDevVersion}
|
||||
upgradeImportantMessageType={upgradeImportantMessageType}
|
||||
downloadOnly={downloadOnly}
|
||||
platform={platform}
|
||||
LL={LL}
|
||||
onClose={closeInstallDialog}
|
||||
@@ -823,7 +875,7 @@ const Version = () => {
|
||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||
{LL.UPLOAD()}
|
||||
</Typography>
|
||||
<SingleUpload text={LL.UPLOAD_DROP_TEXT()} doRestart={doRestart} />
|
||||
<SingleUpload doRestart={doRestart} />
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
@@ -842,6 +894,7 @@ const Version = () => {
|
||||
locale,
|
||||
openInstallDialog,
|
||||
fetchDevVersion,
|
||||
downloadOnly,
|
||||
me.admin,
|
||||
showButtons,
|
||||
handleVersionInfoClose,
|
||||
|
||||
@@ -53,12 +53,16 @@ const MessageBox: FC<PropsWithChildren<MessageBoxProps>> = ({
|
||||
|
||||
return (
|
||||
<Box
|
||||
p={2}
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
borderRadius={1}
|
||||
sx={{ backgroundColor, color: 'white', ...sx }}
|
||||
{...rest}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
borderRadius: 1,
|
||||
backgroundColor,
|
||||
color: 'white',
|
||||
p: 2,
|
||||
...sx
|
||||
}}
|
||||
>
|
||||
<Icon />
|
||||
{(message || children) && (
|
||||
|
||||
@@ -29,7 +29,7 @@ const LayoutDrawerComponent = ({ mobileOpen, onClose }: LayoutDrawerProps) => {
|
||||
() => (
|
||||
<>
|
||||
<Toolbar disableGutters>
|
||||
<Box display="flex" alignItems="center" px={2}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', p: 2 }}>
|
||||
<LayoutDrawerLogo src="/app/icon.png" alt={PROJECT_NAME} />
|
||||
<Typography variant="h6">{PROJECT_NAME}</Typography>
|
||||
</Box>
|
||||
|
||||
@@ -51,9 +51,7 @@ const LayoutMenuComponent = () => {
|
||||
sx={{ my: 0 }}
|
||||
slotProps={{
|
||||
primary: {
|
||||
fontWeight: '600',
|
||||
mb: '2px',
|
||||
color: 'lightblue'
|
||||
sx: { fontWeight: 600, mb: '2px', color: 'lightblue' }
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -32,8 +32,16 @@ const FormLoaderComponent = ({ errorMessage, onRetry }: FormLoaderProps) => {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Box m={2} py={2} display="flex" alignItems="center" flexDirection="column">
|
||||
<Box py={2}>
|
||||
<Box
|
||||
sx={{
|
||||
m: 2,
|
||||
py: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column'
|
||||
}}
|
||||
>
|
||||
<Box sx={{ p: 2 }}>
|
||||
<CircularProgress size={100} />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -15,12 +15,14 @@ const circularProgressStyles: SxProps<Theme> = (theme: Theme) => ({
|
||||
const LoadingSpinner = ({ height = '100%' }: LoadingSpinnerProps) => {
|
||||
return (
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
flexDirection="column"
|
||||
padding={2}
|
||||
height={height}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
padding: 2,
|
||||
height
|
||||
}}
|
||||
>
|
||||
<CircularProgress sx={circularProgressStyles} size={100} />
|
||||
</Box>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code inspired by Prince Azubuike from https://medium.com/@dprincecoder/creating-a-drag-and-drop-file-upload-component-in-react-a-step-by-step-guide-4d93b6cc21e0
|
||||
// drag/drop code inspired by Prince Azubuike from https://medium.com/@dprincecoder/creating-a-drag-and-drop-file-upload-component-in-react-a-step-by-step-guide-4d93b6cc21e0
|
||||
import {
|
||||
type ChangeEvent,
|
||||
type DragEvent,
|
||||
@@ -6,12 +6,28 @@ import {
|
||||
useRef,
|
||||
useState
|
||||
} from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import { Box, Button, Typography, styled } from '@mui/material';
|
||||
import WarningIcon from '@mui/icons-material/Warning';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Typography,
|
||||
styled
|
||||
} from '@mui/material';
|
||||
|
||||
import { callAction } from 'api/app';
|
||||
|
||||
import { dialogStyle } from '@/CustomTheme';
|
||||
import { useRequest } from 'alova/client';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
|
||||
const DocumentUploader = styled(Box)<{ active?: boolean }>(({ theme, active }) => ({
|
||||
@@ -58,6 +74,29 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
|
||||
const [dragged, setDragged] = useState(false);
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
const { LL } = useI18nContext();
|
||||
const [showUpgradeDialog, setShowUpgradeDialog] = useState(false);
|
||||
const [upgradeImportantMessageType, setUpgradeImportantMessageType] =
|
||||
useState<number>(0);
|
||||
|
||||
const { send: checkUpgradeImportantMessages } = useRequest(
|
||||
(version: string) =>
|
||||
callAction({ action: 'upgradeImportantMessages', param: version }),
|
||||
{
|
||||
immediate: false
|
||||
}
|
||||
)
|
||||
.onSuccess((event) => {
|
||||
const upgradeImportantMessageType_n = (
|
||||
event.data as { upgradeImportantMessageType: number }
|
||||
).upgradeImportantMessageType;
|
||||
setUpgradeImportantMessageType(upgradeImportantMessageType_n);
|
||||
if (upgradeImportantMessageType_n === 0) {
|
||||
onFileSelected(file);
|
||||
}
|
||||
})
|
||||
.onError((error) => {
|
||||
toast.error(String(error.error?.message || 'An error occurred'));
|
||||
});
|
||||
|
||||
const checkFileExtension = (file: File) => {
|
||||
const validExtensions = ['.json', '.bin', '.md5'];
|
||||
@@ -97,9 +136,8 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
|
||||
|
||||
const handleUploadClick = (event: MouseEvent<HTMLButtonElement>) => {
|
||||
event.stopPropagation();
|
||||
if (file) {
|
||||
onFileSelected(file);
|
||||
}
|
||||
void checkUpgradeImportantMessages(file?.name || '');
|
||||
setShowUpgradeDialog(true);
|
||||
};
|
||||
|
||||
const handleBrowseClick = () => {
|
||||
@@ -158,6 +196,55 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
|
||||
{LL.UPLOAD()}
|
||||
</Button>
|
||||
</Box>
|
||||
{showUpgradeDialog && upgradeImportantMessageType > 0 && (
|
||||
<Dialog
|
||||
sx={dialogStyle}
|
||||
open={showUpgradeDialog}
|
||||
onClose={() => setShowUpgradeDialog(false)}
|
||||
>
|
||||
<DialogTitle>
|
||||
<WarningIcon
|
||||
color="warning"
|
||||
sx={{ fontSize: 18, verticalAlign: 'middle' }}
|
||||
/>
|
||||
|
||||
{LL.UPGRADE_IMPORTANT_MESSAGES()}
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
{upgradeImportantMessageType === 1 &&
|
||||
LL.UPGRADE_IMPORTANT_MESSAGES_1()}
|
||||
{upgradeImportantMessageType === 2 &&
|
||||
LL.UPGRADE_IMPORTANT_MESSAGES_2()}
|
||||
<Typography sx={{ mt: 2 }}>
|
||||
<Link
|
||||
target="_blank"
|
||||
to="https://docs.emsesp.org/FAQ#upgrading-the-firmware"
|
||||
style={{ color: 'lightblue' }}
|
||||
>
|
||||
{LL.ONLINE_HELP()}
|
||||
</Link>
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
startIcon={<CancelIcon />}
|
||||
variant="outlined"
|
||||
onClick={() => setShowUpgradeDialog(false)}
|
||||
color="secondary"
|
||||
>
|
||||
{LL.CANCEL()}
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<UploadIcon />}
|
||||
variant="outlined"
|
||||
onClick={() => onFileSelected(file)}
|
||||
color="primary"
|
||||
>
|
||||
{LL.UPLOAD()}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</DocumentUploader>
|
||||
|
||||
@@ -13,11 +13,10 @@ import DragNdrop from './DragNdrop';
|
||||
import { LinearProgressWithLabel } from './LinearProgressWithLabel';
|
||||
|
||||
interface SingleUploadProps {
|
||||
text: string;
|
||||
doRestart: () => void;
|
||||
}
|
||||
|
||||
const SingleUpload = ({ text, doRestart }: SingleUploadProps) => {
|
||||
const SingleUpload = ({ doRestart }: SingleUploadProps) => {
|
||||
const [md5, setMd5] = useState<string>();
|
||||
const [file, setFile] = useState<File>();
|
||||
const { LL } = useI18nContext();
|
||||
@@ -58,7 +57,7 @@ const SingleUpload = ({ text, doRestart }: SingleUploadProps) => {
|
||||
<>
|
||||
{isUploading ? (
|
||||
<>
|
||||
<Box width="100%" pl={2} pr={2}>
|
||||
<Box sx={{ width: '100%', pl: 2, pr: 2 }}>
|
||||
<LinearProgressWithLabel
|
||||
value={
|
||||
progress.total === 0 || progress.loaded === 0
|
||||
@@ -81,11 +80,11 @@ const SingleUpload = ({ text, doRestart }: SingleUploadProps) => {
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<DragNdrop text={text} onFileSelected={setFile} />
|
||||
<DragNdrop text={LL.UPLOAD_DROP_TEXT()} onFileSelected={setFile} />
|
||||
)}
|
||||
|
||||
{md5 && (
|
||||
<Box mt={2}>
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="body2">{'MD5: ' + md5}</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -359,7 +359,12 @@ const cz: Translation = {
|
||||
NO_DATA: 'Žádná data',
|
||||
USER_PROFILE: 'Uživatelský profil',
|
||||
STORED_VERSIONS: 'Uložené verze',
|
||||
ONLINE_HELP: 'online nápověda'
|
||||
ONLINE_HELP: 'online nápověda',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Aktualizovat důležité zprávy',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Tato aktualizace vyžaduje obnovení továrního nastavení. Ujistěte se, že jste vytvořili zálohu své konfigurace a nastavení před pokračováním a nahrajte ji po instalaci nové verze.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujete se na novou hlavní verzi. Ujistěte se, že jste přečetli ChangeLog pro jakékoliv závažné změny.',
|
||||
WARNING_SYSTEM_BACKUP: 'Toto vytvoří zálohu vašich celých systémových konfigurací a nastavení. Všechna hesla budou v zálohovém souboru čitelná. Buďte opatrní při sdílení! Opravdu chcete pokračovat?'
|
||||
|
||||
};
|
||||
|
||||
export default cz;
|
||||
|
||||
@@ -359,7 +359,12 @@ const de: Translation = {
|
||||
NO_DATA: 'Keine Daten',
|
||||
USER_PROFILE: 'Benutzerprofil',
|
||||
STORED_VERSIONS: 'Gespeicherte Versionen',
|
||||
ONLINE_HELP: 'Online-Hilfe'
|
||||
ONLINE_HELP: 'Online-Hilfe',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Wichtige Nachrichten aktualisieren',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Diese Aktualisierung erfordert eine Werkseinstellung. Stellen Sie sicher, dass Sie eine Sicherung Ihrer Konfiguration und Einstellungen vor dem Fortfahren erstellt haben und diese nach der Installation der neuen Version hochladen.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'Sie aktualisieren auf eine neue Hauptversion. Stellen Sie sicher, dass Sie den ChangeLog für alle wichtigen Änderungen gelesen haben.',
|
||||
WARNING_SYSTEM_BACKUP: 'Dies wird eine Sicherung Ihrer vollständigen Systemkonfiguration und -einstellungen erstellen. Alle Passwörter werden im Sicherungsdatei lesbar sein. Seien Sie vorsichtig beim Teilen! Möchten Sie fortfahren?'
|
||||
|
||||
};
|
||||
|
||||
export default de;
|
||||
|
||||
@@ -359,7 +359,12 @@ const en: Translation = {
|
||||
NO_DATA: 'No data',
|
||||
USER_PROFILE: 'User Profile',
|
||||
STORED_VERSIONS: 'Stored Versions',
|
||||
ONLINE_HELP: 'online help'
|
||||
ONLINE_HELP: 'online help',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Upgrade Important Messages',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'This upgrade requires a factory reset. Make sure you have made a backup of your configuration and settings before continuing, and upload this after the new version is installed.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'You are upgrading to a new major version. Make sure you have read the ChangeLog for any breaking changes.',
|
||||
WARNING_SYSTEM_BACKUP: 'This will create a backup of your full system configuration and settings. All passwords will be readable in the backup file. Be careful with sharing! Do you want to continue?'
|
||||
|
||||
};
|
||||
|
||||
export default en;
|
||||
|
||||
@@ -359,7 +359,12 @@ const fr: Translation = {
|
||||
NO_DATA: 'Aucune donnée',
|
||||
USER_PROFILE: 'Profil utilisateur',
|
||||
STORED_VERSIONS: 'Versions stockées',
|
||||
ONLINE_HELP: 'aide en ligne'
|
||||
ONLINE_HELP: 'aide en ligne',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Mettre à jour les messages importants',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Cette mise à jour nécessite une réinitialisation de fabrique. Assurez-vous d\'avoir créé une sauvegarde de vos configurations et paramètres avant de continuer et de la charger après l\'installation de la nouvelle version.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'Vous mettez à jour vers une nouvelle version majeure. Assurez-vous de lire le ChangeLog pour tout changement important.',
|
||||
WARNING_SYSTEM_BACKUP: 'Cela créera une sauvegarde de votre configuration et paramètres complets. Tous les mots de passe seront lisibles dans le fichier de sauvegarde. Soyez prudent avec le partage ! Voulez-vous continuer ?'
|
||||
|
||||
};
|
||||
|
||||
export default fr;
|
||||
|
||||
@@ -359,7 +359,12 @@ const it: Translation = {
|
||||
NO_DATA: 'Nessun dato',
|
||||
USER_PROFILE: 'Profilo utente',
|
||||
STORED_VERSIONS: 'Versioni memorizzate',
|
||||
ONLINE_HELP: 'aiuto online'
|
||||
ONLINE_HELP: 'aiuto online',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Aggiorna Messaggi Importanti',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Questa aggiornamento richiede un ripristino di fabbrica. Assicurati di aver creato un backup delle tue configurazioni e impostazioni prima di continuare e di caricarlo dopo l\'installazione della nuova versione.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'Stai aggiornando a una nuova versione principale. Assicurati di aver letto il ChangeLog per qualsiasi cambiamento importante.',
|
||||
WARNING_SYSTEM_BACKUP: 'Questo creerà un backup delle tue configurazioni e impostazioni complete. Tutte le password saranno leggibili nel file di backup. Sei sicuro di voler continuare?'
|
||||
|
||||
};
|
||||
|
||||
export default it;
|
||||
|
||||
@@ -359,7 +359,12 @@ const nl: Translation = {
|
||||
NO_DATA: 'Geen data',
|
||||
USER_PROFILE: 'Gebruikersprofiel',
|
||||
STORED_VERSIONS: 'Opgeslagen versies',
|
||||
ONLINE_HELP: 'online help'
|
||||
ONLINE_HELP: 'online help',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Upgrade Belangrijke Berichten',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Deze upgrade vereist een fabrieksinstelling. Zorg ervoor dat u een back-up van uw configuratie en instellingen hebt gemaakt voordat u doorgaat en upload deze na de installatie van de nieuwe versie.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'U updatet naar een nieuwe grote versie. Zorg ervoor dat u de ChangeLog hebt gelezen voor alle brekende wijzigingen.',
|
||||
WARNING_SYSTEM_BACKUP: 'Dit zal een back-up van uw volledige systeemconfiguratie en instellingen maken. Alle wachtwoorden zijn leesbaar in het back-upbestand. Wees voorzichtig bij delen! Wilt u doorgaan?'
|
||||
|
||||
};
|
||||
|
||||
export default nl;
|
||||
|
||||
@@ -359,7 +359,12 @@ const no: Translation = {
|
||||
NO_DATA: 'Ingen data',
|
||||
USER_PROFILE: 'Brukerprofil',
|
||||
STORED_VERSIONS: 'Lagret versjoner',
|
||||
ONLINE_HELP: 'online hjelp'
|
||||
ONLINE_HELP: 'online hjelp',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Oppdater viktige meldinger',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Denne oppdateringen krever en fabriksinstilling. Sørg for at du har laget en sikkerhetskopi av din konfigurasjon og innstillinger før du fortsetter, og last denne opp etter at den nye versjonen er installert.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'Du oppdaterer til en ny hovedversjon. Sørg for at du har lest ChangeLog for eventuelle bruddende endringer.',
|
||||
WARNING_SYSTEM_BACKUP: 'Dette vil lage en sikkerhetskopi av din fullstendige systemkonfigurasjon og innstillinger. Alle passord vil være lesbare i sikkerhetskopien. Vær forsiktig med deling! Vil du fortsette?'
|
||||
|
||||
};
|
||||
|
||||
export default no;
|
||||
|
||||
@@ -359,7 +359,12 @@ const pl: BaseTranslation = {
|
||||
NO_DATA: 'Brak danych',
|
||||
USER_PROFILE: 'Profil użytkownika',
|
||||
STORED_VERSIONS: 'Zapisane wersje',
|
||||
ONLINE_HELP: 'pomoc online'
|
||||
ONLINE_HELP: 'pomoc online',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Aktualizuj ważne wiadomości',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Ta aktualizacja wymaga resetu fabrycznego. Upewnij się, że masz utworzoną kopię swoich ustawień i konfiguracji przed kontynuowaniem i przesuń ją po zainstalowaniu nowej wersji.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujesz się do nowej głównej wersji. Upewnij się, że przeczytałeś ChangeLog dla wszelkich istotnych zmian.',
|
||||
WARNING_SYSTEM_BACKUP: 'To spowoduje utworzenie kopii zapasowej całej konfiguracji i ustawień systemu. Wszystkie hasła będą widoczne w pliku kopii zapasowej. Bądź ostrożny przy udostępnianiu! Chcesz kontynuować?'
|
||||
|
||||
};
|
||||
|
||||
export default pl;
|
||||
|
||||
@@ -4,7 +4,7 @@ const sk: Translation = {
|
||||
LANGUAGE: 'Jazyk',
|
||||
RETRY: 'Opakovať',
|
||||
LOADING: 'Načítanie',
|
||||
IS_REQUIRED: '{0} je požadovaných',
|
||||
IS_REQUIRED: '{0} je požadovaná',
|
||||
SIGN_IN: 'Prihlásiť sa',
|
||||
SIGN_OUT: 'Odhlásiť sa',
|
||||
USERNAME: 'Užívateľské meno',
|
||||
@@ -276,11 +276,11 @@ const sk: Translation = {
|
||||
NETWORK_SUBNET: 'Maska podsiete',
|
||||
NETWORK_DNS: 'DNS servery',
|
||||
ADDRESS_OF: '{0} adresa',
|
||||
ADMINISTRATOR: 'Administrator',
|
||||
ADMINISTRATOR: 'Administrátor',
|
||||
GUEST: 'Hosť',
|
||||
NEW: 'Nová',
|
||||
NEW: 'Novú',
|
||||
NEW_NAME_OF: 'Nový názov {0}',
|
||||
ENTITY: 'entita',
|
||||
ENTITY: 'entitu',
|
||||
MIN: 'min',
|
||||
MAX: 'max',
|
||||
BLOCK_NAVIGATE_1: 'Máte neuložené zmeny',
|
||||
@@ -359,7 +359,12 @@ const sk: Translation = {
|
||||
NO_DATA: 'Žiadne dáta',
|
||||
USER_PROFILE: 'Profil používateľa',
|
||||
STORED_VERSIONS: 'Uložené verzie',
|
||||
ONLINE_HELP: 'online pomoc'
|
||||
ONLINE_HELP: 'online pomoc',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Aktualizovať dôležité správy',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Táto aktualizácia vyžaduje reštart základných nastavení. Uistite sa, že ste vytvorili zálohu svojich konfigurácií a nastavení pred pokračovaním a nahrajte ju po instalácii novej verzie.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujete sa na novú hlavnú verziu. Uistite sa, že ste prečítali ChangeLog pre akékoľvek dôležité zmeny.',
|
||||
WARNING_SYSTEM_BACKUP: 'Toto vytvorí zálohu všetkých vašich celých systémových konfigurácií a nastavení. Všetky hesla budú čitateľné v zálohovom súbore. Buďte opatrní pri zdieľaní! Chcete pokračovať?'
|
||||
|
||||
};
|
||||
|
||||
export default sk;
|
||||
|
||||
@@ -359,7 +359,12 @@ const sv: Translation = {
|
||||
NO_DATA: 'Ingen data',
|
||||
USER_PROFILE: 'Användarprofil',
|
||||
STORED_VERSIONS: 'Lagrad versioner',
|
||||
ONLINE_HELP: 'online hjälp'
|
||||
ONLINE_HELP: 'online hjälp',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Uppdatera viktiga meddelanden',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Denna uppdatering kräver en fabriksåterställning. Se till att du har gjort en säkerhetskopia av din konfiguration och inställningar innan du fortsätter och ladda upp denna efter att den nya versionen är installerad.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'Du uppdaterar till en ny huvudversion. Se till att du har läst ChangeLog för eventuella brkande ändringar.',
|
||||
WARNING_SYSTEM_BACKUP: 'Detta kommer att skapa en säkerhetskopia av din fullständiga systemkonfiguration och inställningar. Alla lösenord kommer att vara läsbara i säkerhetskopien. Var försiktig med att dela! Vill du fortsätta?'
|
||||
|
||||
};
|
||||
|
||||
export default sv;
|
||||
|
||||
@@ -359,7 +359,12 @@ const tr: Translation = {
|
||||
NO_DATA: 'Hiçbir veri yok',
|
||||
USER_PROFILE: 'Kullanıcı Profili',
|
||||
STORED_VERSIONS: 'Kaydedilmiş Sürümler',
|
||||
ONLINE_HELP: 'online yardım'
|
||||
ONLINE_HELP: 'online yardım',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Önemli Mesajları Güncelle',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Bu güncelleme továrnı ayarlarını gerektirir. Yapılandırmanızı ve ayarlarınızı önce yedekleyin ve ardından yeni sürüm yüklendikten sonra yükleyin.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'Yeni bir büyük sürüme yükselteceksiniz. Değişiklikleri ChangeLogı okuduğunuzdan emin olun.',
|
||||
WARNING_SYSTEM_BACKUP: 'Bu, sistem yapılandırmanızı ve ayarlarınızın bir yedeklemesi oluşturacaktır. Tüm şifreler yedekleme dosyasında okunabilir olacaktır. Paylaşırken dikkatli olun! Devam etmek istediğinize emin misiniz?'
|
||||
|
||||
};
|
||||
|
||||
export default tr;
|
||||
|
||||
Reference in New Issue
Block a user