Merge branch 'origin/dev'

This commit is contained in:
Proddy
2023-09-09 14:12:07 +02:00
71 changed files with 1485 additions and 2358 deletions

View File

@@ -1,5 +1,5 @@
{
"adapter": "react",
"baseLocale": "pl",
"$schema": "https://unpkg.com/typesafe-i18n@5.26.0/schema/typesafe-i18n.json"
"$schema": "https://unpkg.com/typesafe-i18n@5.26.2/schema/typesafe-i18n.json"
}

View File

@@ -12,7 +12,7 @@
"build-hosted": "vite build --mode hosted",
"preview": "vite preview",
"preview-standalone": "npm-run-all -p preview typesafe-i18n mock-api",
"mock-api": "nodemon --watch ../mock-api ../mock-api/server.js",
"mock-api": "node --watch ../mock-api ../mock-api/server.js",
"standalone": "npm-run-all -p dev typesafe-i18n mock-api",
"typesafe-i18n": "typesafe-i18n",
"format": "prettier --write '**/*.{ts,tsx,js,css,json,md}'",
@@ -22,55 +22,54 @@
"@alova/adapter-xhr": "^1.0.1",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.3",
"@mui/material": "^5.14.4",
"@mui/icons-material": "^5.14.8",
"@mui/material": "^5.14.8",
"@preact/compat": "^17.1.2",
"@prefresh/vite": "^2.4.1",
"@table-library/react-table-library": "4.1.7",
"@types/lodash-es": "^4.17.8",
"@types/node": "^20.4.10",
"@types/react": "^18.2.20",
"@types/lodash-es": "^4.17.9",
"@types/node": "^20.6.0",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@types/react-router-dom": "^5.3.3",
"alova": "^2.10.0",
"alova": "^2.11.1",
"async-validator": "^4.2.5",
"history": "^5.3.0",
"jwt-decode": "^3.1.2",
"lodash-es": "^4.17.21",
"mime-types": "^2.1.35",
"preact": "^10.16.0",
"preact": "^10.17.1",
"react": "latest",
"react-dom": "latest",
"react-dropzone": "^14.2.3",
"react-icons": "^4.10.1",
"react-icons": "^4.11.0",
"react-router-dom": "^6.15.0",
"react-toastify": "^9.1.3",
"sockette": "^2.0.6",
"typesafe-i18n": "^5.26.0",
"typescript": "^5.1.6"
"typesafe-i18n": "^5.26.2",
"typescript": "^5.2.2"
},
"devDependencies": {
"@babel/core": "^7.22.10",
"@babel/core": "^7.22.17",
"@preact/preset-vite": "^2.5.0",
"@types/babel__core": "^7",
"@typescript-eslint/eslint-plugin": "^6.3.0",
"@typescript-eslint/parser": "^6.3.0",
"eslint": "^8.47.0",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^6.6.0",
"eslint": "^8.49.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.6.0",
"eslint-plugin-autofix": "^1.1.0",
"eslint-plugin-import": "^2.28.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-prettier": "alpha",
"eslint-plugin-react": "^7.33.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"nodemon": "^3.0.1",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.1",
"prettier": "^3.0.3",
"rollup-plugin-visualizer": "^5.9.2",
"terser": "^5.19.2",
"terser": "^5.19.4",
"vite": "^4.4.9",
"vite-plugin-svgr": "^3.2.0",
"vite-tsconfig-paths": "^4.2.0"

View File

@@ -38,6 +38,15 @@ const networkStatusHighlight = ({ status }: NetworkStatus, theme: Theme) => {
}
};
const networkQualityHighlight = ({ rssi }: NetworkStatus, theme: Theme) => {
if (rssi <= -85) {
return theme.palette.error.main;
} else if (rssi <= -75) {
return theme.palette.warning.main;
}
return theme.palette.success.main;
};
export const isWiFi = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED;
export const isEthernet = ({ status }: NetworkStatus) => status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED;
@@ -110,11 +119,11 @@ const NetworkStatusForm: FC = () => {
<>
<ListItem>
<ListItemAvatar>
<Avatar>
<Avatar sx={{ bgcolor: networkQualityHighlight(data, theme) }}>
<SettingsInputAntennaIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary="SSID" secondary={data.ssid} />
<ListItemText primary="SSID (RSSI)" secondary={data.ssid + ' (' + data.rssi + ' dBm)'} />
</ListItem>
<Divider variant="inset" component="li" />
</>

View File

@@ -1,10 +1,11 @@
import LockIcon from '@mui/icons-material/Lock';
import LockOpenIcon from '@mui/icons-material/LockOpen';
import WifiIcon from '@mui/icons-material/Wifi';
import { Avatar, Badge, List, ListItem, ListItemAvatar, ListItemIcon, ListItemText } from '@mui/material';
import { Avatar, Badge, List, ListItem, ListItemAvatar, ListItemIcon, ListItemText, useTheme } from '@mui/material';
import { useContext } from 'react';
import { WiFiConnectionContext } from './WiFiConnectionContext';
import type { Theme } from '@mui/material';
import type { FC } from 'react';
import type { WiFiNetwork, WiFiNetworkList } from 'types';
import { MessageBox } from 'components';
@@ -42,8 +43,18 @@ export const networkSecurityMode = ({ encryption_type }: WiFiNetwork) => {
}
};
const networkQualityHighlight = ({ rssi }: WiFiNetwork, theme: Theme) => {
if (rssi <= -85) {
return theme.palette.error.main;
} else if (rssi <= -75) {
return theme.palette.warning.main;
}
return theme.palette.success.main;
};
const WiFiNetworkSelector: FC<WiFiNetworkSelectorProps> = ({ networkList }) => {
const { LL } = useI18nContext();
const theme = useTheme();
const wifiConnectionContext = useContext(WiFiConnectionContext);
@@ -57,8 +68,8 @@ const WiFiNetworkSelector: FC<WiFiNetworkSelectorProps> = ({ networkList }) => {
secondary={'Security: ' + networkSecurityMode(network) + ', Ch: ' + network.channel}
/>
<ListItemIcon>
<Badge badgeContent={network.rssi + 'db'}>
<WifiIcon />
<Badge badgeContent={network.rssi + 'dBm'}>
<WifiIcon sx={{ color: networkQualityHighlight(network, theme) }} />
</Badge>
</ListItemIcon>
</ListItem>

View File

@@ -86,7 +86,7 @@ const SettingsCustomization: FC = () => {
const entities_theme = useTheme({
Table: `
--data-table-library_grid-template-columns: 150px repeat(1, minmax(80px, 1fr)) 45px minmax(45px, auto) minmax(120px, auto);
--data-table-library_grid-template-columns: 156px repeat(1, minmax(80px, 1fr)) 45px minmax(45px, auto) minmax(120px, auto);
`,
BaseRow: `
font-size: 14px;
@@ -192,17 +192,9 @@ const SettingsCustomization: FC = () => {
return value;
}
function formatName(de: DeviceEntity) {
return (
<>
{de.n && (de.n[0] === '!' ? LL.COMMAND(1) + ': ' + de.n.slice(1) : de.cn && de.cn !== '' ? de.cn : de.n) + ' '}(
<Link target="_blank" href={APIURL + devices?.devices[selectedDevice].tn + '/' + de.id}>
{de.id}
</Link>
)
</>
);
}
const formatName = (de: DeviceEntity, withShortname: boolean) =>
(de.n && de.n[0] === '!' ? LL.COMMAND(1) + ': ' + de.n.slice(1) : de.cn && de.cn !== '' ? de.cn : de.n) +
(withShortname ? ' ' + de.id : '');
const getMaskNumber = (newMask: string[]) => {
let new_mask = 0;
@@ -232,10 +224,13 @@ const SettingsCustomization: FC = () => {
return new_masks;
};
const filter_entity = (de: DeviceEntity) =>
(de.m & selectedFilters || !selectedFilters) && formatName(de, true).includes(search.toLocaleLowerCase());
const maskDisabled = (set: boolean) => {
setDeviceEntities(
deviceEntities.map(function (de) {
if ((de.m & selectedFilters || !selectedFilters) && de.id.toLowerCase().includes(search.toLowerCase())) {
if (filter_entity(de)) {
return {
...de,
m: set
@@ -353,7 +348,7 @@ const SettingsCustomization: FC = () => {
margin="normal"
select
>
<MenuItem disabled key={0} value={-1}>
<MenuItem disabled key={-1} value={-1}>
{LL.SELECT_DEVICE()}...
</MenuItem>
{devices.devices.map((device: DeviceShort, index) => (
@@ -370,9 +365,7 @@ const SettingsCustomization: FC = () => {
return;
}
const shown_data = deviceEntities.filter(
(de) => (de.m & selectedFilters || !selectedFilters) && de.id.toLowerCase().includes(search.toLowerCase())
);
const shown_data = deviceEntities.filter((de) => filter_entity(de));
return (
<>
@@ -470,7 +463,13 @@ const SettingsCustomization: FC = () => {
<Cell stiff>
<EntityMaskToggle onUpdate={updateDeviceEntity} de={de} />
</Cell>
<Cell>{formatName(de)}</Cell>
<Cell>
{formatName(de, false)}&nbsp;(
<Link target="_blank" href={APIURL + devices?.devices[selectedDevice].tn + '/' + de.id}>
{de.id}
</Link>
)
</Cell>
<Cell>{!(de.m & DeviceEntityMask.DV_READONLY) && formatValue(de.mi)}</Cell>
<Cell>{!(de.m & DeviceEntityMask.DV_READONLY) && formatValue(de.ma)}</Cell>
<Cell>{formatValue(de.v)}</Cell>

View File

@@ -1,4 +1,5 @@
import CancelIcon from '@mui/icons-material/Cancel';
import CloseIcon from '@mui/icons-material/Close';
import DoneIcon from '@mui/icons-material/Done';
import {
@@ -67,15 +68,34 @@ const SettingsCustomizationDialog = ({ open, onClose, onSave, selectedItem }: Se
<Dialog sx={dialogStyle} open={open} onClose={close}>
<DialogTitle>{LL.EDIT() + ' ' + LL.ENTITY()}</DialogTitle>
<DialogContent dividers>
<Box color="warning.main">
<Typography variant="body2">{editItem.id}</Typography>
</Box>
<Box color="warning.main" mt={1} mb={2}>
<Typography variant="body2">
{LL.DEFAULT(1) + ' ' + LL.ENTITY_NAME(1)}:&nbsp;{editItem.n}
<Grid container direction="row">
<Typography variant="body2" color="warning.main">
{LL.ENTITY() + ' ID'}:&nbsp;
</Typography>
</Box>
<Box mb={3}>
<Typography variant="body2">{editItem.id}</Typography>
</Grid>
<Grid container direction="row">
<Typography variant="body2" color="warning.main">
{LL.DEFAULT(1) + ' ' + LL.ENTITY_NAME(1)}:&nbsp;
</Typography>
<Typography variant="body2">{editItem.n}</Typography>
</Grid>
<Grid container direction="row">
<Typography variant="body2" color="warning.main">
{LL.WRITEABLE()}:&nbsp;
</Typography>
<Typography variant="body2">
{editItem.w ? (
<DoneIcon color="success" sx={{ fontSize: 16 }} />
) : (
<CloseIcon color="error" sx={{ fontSize: 16 }} />
)}
</Typography>
</Grid>
<Box mt={1} mb={2}>
<EntityMaskToggle onUpdate={updateDeviceEntity} de={editItem} />
</Box>
<Grid container spacing={1}>

View File

@@ -13,7 +13,7 @@ import { toast } from 'react-toastify';
import SettingsEntitiesDialog from './SettingsEntitiesDialog';
import * as EMSESP from './api';
import { DeviceValueUOM_s } from './types';
import { DeviceValueTypeNames, DeviceValueUOM_s } from './types';
import { entityItemValidation } from './validators';
import type { EntityItem } from './types';
import type { FC } from 'react';
@@ -57,7 +57,7 @@ const SettingsEntities: FC = () => {
const entity_theme = useTheme({
Table: `
--data-table-library_grid-template-columns: repeat(1, minmax(60px, 1fr)) minmax(80px, auto) 80px 80px 80px;
--data-table-library_grid-template-columns: repeat(1, minmax(60px, 1fr)) minmax(80px, auto) 80px 80px 80px 90px;
`,
BaseRow: `
font-size: 14px;
@@ -81,6 +81,9 @@ const SettingsEntities: FC = () => {
&:nth-of-type(5) {
text-align: center;
}
&:nth-of-type(6) {
text-align: center;
}
`,
HeaderRow: `
text-transform: uppercase;
@@ -208,8 +211,9 @@ const SettingsEntities: FC = () => {
<HeaderCell>{LL.NAME(0)}</HeaderCell>
<HeaderCell stiff>{LL.ID_OF(LL.DEVICE())}</HeaderCell>
<HeaderCell stiff>{LL.ID_OF(LL.TYPE(1))}</HeaderCell>
<HeaderCell stiff>Offset</HeaderCell>
<HeaderCell stiff>{LL.VALUE(0)}</HeaderCell>
<HeaderCell stiff>{LL.OFFSET()}</HeaderCell>
<HeaderCell stiff>{LL.VALUE(1) + ' ' + LL.TYPE(1)}</HeaderCell>
<HeaderCell stiff>{LL.VALUE(1)}</HeaderCell>
</HeaderRow>
</Header>
<Body>
@@ -219,6 +223,7 @@ const SettingsEntities: FC = () => {
<Cell>{showHex(ei.device_id as number, 2)}</Cell>
<Cell>{showHex(ei.type_id as number, 3)}</Cell>
<Cell>{ei.offset}</Cell>
<Cell>{DeviceValueTypeNames[ei.value_type]}</Cell>
<Cell>{formatValue(ei.value, ei.uom)}</Cell>
</Row>
))}

View File

@@ -148,7 +148,7 @@ const SettingsEntitiesDialog = ({
<ValidatedTextField
fieldErrors={fieldErrors}
name="offset"
label="Offset"
label={LL.OFFSET()}
margin="normal"
fullWidth
type="number"
@@ -159,7 +159,7 @@ const SettingsEntitiesDialog = ({
<Grid item xs={4}>
<TextField
name="value_type"
label="Value Type"
label={LL.VALUE(1) + ' ' + LL.TYPE(1)}
value={editItem.value_type}
variant="outlined"
onChange={updateFormValue}

View File

@@ -1,6 +1,6 @@
import AddIcon from '@mui/icons-material/Add';
import CancelIcon from '@mui/icons-material/Cancel';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import CircleIcon from '@mui/icons-material/Circle';
import WarningIcon from '@mui/icons-material/Warning';
import { Box, Typography, Divider, Stack, Button } from '@mui/material';
@@ -216,7 +216,11 @@ const SettingsScheduler: FC = () => {
{tableList.map((si: ScheduleItem) => (
<Row key={si.id} item={si} onClick={() => editScheduleItem(si)}>
<Cell stiff>
{si.active && <CheckCircleIcon sx={{ color: '#79D200', fontSize: 16, verticalAlign: 'middle' }} />}
{si.active ? (
<CircleIcon color="success" sx={{ fontSize: 16, verticalAlign: 'middle' }} />
) : (
<CircleIcon color="error" sx={{ fontSize: 16, verticalAlign: 'middle' }} />
)}
</Cell>
<Cell stiff>
<Stack spacing={1} direction="row">

View File

@@ -1,6 +1,5 @@
import AddIcon from '@mui/icons-material/Add';
import CancelIcon from '@mui/icons-material/Cancel';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import DoneIcon from '@mui/icons-material/Done';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
@@ -184,11 +183,6 @@ const SettingsSchedulerDialog = ({
control={<Checkbox checked={editItem.active} onChange={updateFormValue} name="active" />}
label={LL.ACTIVE()}
/>
{editItem.active && (
<Grid item sx={{ mt: 1 }}>
<CheckCircleIcon sx={{ color: '#79D200', fontSize: 16, verticalAlign: 'middle' }} />
</Grid>
)}
</Grid>
<Grid container>
<TextField

View File

@@ -379,3 +379,16 @@ export const enum DeviceValueType {
STRING,
CMD
}
export const DeviceValueTypeNames = [
'BOOL',
'INT',
'UINT',
'SHORT',
'USHORT',
'ULONG',
'TIME',
'ENUM',
'STRING',
'CMD'
];

View File

@@ -50,9 +50,9 @@ export default defineConfig(({ command, mode }) => {
server: {
open: true,
port: 3000,
watch: {
usePolling: true
},
// watch: {
// usePolling: true
// },
proxy: {
'/rest': 'http://localhost:3080',
'/api': {

File diff suppressed because it is too large Load Diff