replace React bunder based on webpack with Vite #952

This commit is contained in:
Proddy
2023-02-09 20:23:31 +01:00
parent ea8850f8bd
commit 9501f02aa2
108 changed files with 3011 additions and 15196 deletions

6
.gitignore vendored
View File

@@ -29,6 +29,8 @@ node_modules
test.sh
scripts/__pycache__
.temp
*.sln
*.sw?
# i18n generated files
interface/src/i18n/i18n-react.tsx
@@ -47,4 +49,6 @@ dump_entities.csv
dump_entities.xls*
scripts/run.sh
test_results.txt
interface/build-analysis-*.html
# bundle analyzer
stats.html

3
.prettierignore Normal file
View File

@@ -0,0 +1,3 @@
node_modules/
build/
.prettierrc

View File

@@ -1,6 +1,8 @@
{
"singleQuote": true,
"semi": true,
"trailingComma": "none",
"printWidth": 120
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"printWidth": 120,
"bracketSpacing": true
}

View File

@@ -1,5 +0,0 @@
# ![logo](https://github.com/emsesp/EMS-ESP32/blob/main/media/EMS-ESP_logo_dark.png)
# Firmware Installation
Follow the instructions in the [documentation](https://emsesp.github.io/docs) on how to install the firmware binaries in the Assets below.

View File

@@ -1,7 +0,0 @@
# ![logo](https://github.com/emsesp/EMS-ESP32/blob/main/media/EMS-ESP_logo_dark.png)
This is a snapshot of the current "beta" development code and firmware binaries for the ESP32. It has all the latest features and fixes but please be aware that this is still experimental firmware used for testing and thus may contain the odd bug. Use at your own risk and remember to report an issue if you find something unusual.
# Firmware Installation
Follow the instructions in the [documentation](https://emsesp.github.io/docs) on how to install the firmware binaries in the Assets below.

View File

@@ -1,8 +0,0 @@
# This enables lint extensions
EXTEND_ESLINT=true
# This is the name of your project. It appears on the sign-in page and in the menu bar.
REACT_APP_PROJECT_NAME=EMS-ESP
# This is the url path your project will be exposed under.
REACT_APP_PROJECT_PATH=ems-esp

View File

@@ -1,3 +0,0 @@
GENERATE_SOURCEMAP=false
REACT_APP_HOSTED=true

View File

@@ -1 +0,0 @@
GENERATE_SOURCEMAP=false

5
interface/.eslintignore Normal file
View File

@@ -0,0 +1,5 @@
node_modules/
build/
.prettierrc
.eslintrc.js
env.d.ts

48
interface/.eslintrc.js Normal file
View File

@@ -0,0 +1,48 @@
module.exports = {
plugins: ['react-refresh'],
extends: [
// By extending from a plugin config, we can get recommended rules without having to add them manually.
'eslint:recommended',
'plugin:react/recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'plugin:jsx-a11y/recommended',
'plugin:@typescript-eslint/recommended',
// 'plugin:react-refresh/recommended',
// This disables the formatting rules in ESLint that Prettier is going to be responsible for handling.
// Make sure it's always the last config, so it gets the chance to override other configs.
'eslint-config-prettier'
],
settings: {
react: {
// Tells eslint-plugin-react to automatically detect the version of React to use.
version: 'detect'
},
// Tells eslint how to resolve imports
'import/resolver': {
node: {
paths: ['src'],
extensions: ['.js', '.jsx', '.ts', '.tsx']
},
typescript: {
alwaysTryTypes: true // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
}
}
},
parserOptions: {
project: ['tsconfig.json'],
createDefaultProgram: true
},
rules: {
// Add your own rules here to override ones from the extended configs.
'react/react-in-jsx-scope': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'jsx-a11y/no-autofocus': 'off',
'react-refresh/only-export-components': 'off',
'no-console': 'warn',
'react/prop-types': 'off',
'react/self-closing-comp': 'warn',
'@typescript-eslint/consistent-type-definitions': ['off', 'type'],
'@typescript-eslint/explicit-function-return-type': 'off'
}
};

31
interface/.vscode Normal file
View File

@@ -0,0 +1,31 @@
{
"emmet.excludeLanguages": [],
"emmet.includeLanguages": {
"markdown": "html",
"javascript": "javascriptreact",
"typescript": "typescriptreact"
},
"emmet.showSuggestionsAsSnippets": true,
"emmet.triggerExpansionOnTab": true,
"files.exclude": {
"**/*.js.map": {
"when": "$(basename)"
},
"**/node_modules": true
},
"html.autoClosingTags": true,
"javascript.autoClosingTags": true,
"javascript.suggest.completeFunctionCalls": true,
"typescript.suggest.completeFunctionCalls": true,
"javascript.inlayHints.functionLikeReturnTypes.enabled": true,
"typescript.inlayHints.functionLikeReturnTypes.enabled": true,
"javascript.inlayHints.parameterNames.enabled": "all",
"typescript.inlayHints.parameterNames.enabled": "all",
"javascript.suggest.autoImports": true,
"search.exclude": {
"**/coverage": true,
"**/node_modules": true
},
"typescript.autoClosingTags": true,
"typescript.suggest.autoImports": true
}

View File

@@ -1,38 +0,0 @@
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ProgmemGenerator = require('./progmem-generator.js');
const TerserPlugin = require('terser-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = function override(config, env) {
const hosted = process.env.REACT_APP_HOSTED;
if (env === 'production' && !hosted) {
// rename the output file, we need it's path to be short, for embedded FS
config.output.filename = 'js/[id].[chunkhash:4].js';
config.output.chunkFilename = 'js/[id].[chunkhash:4].js';
// take out the manifest plugin
config.plugins = config.plugins.filter((plugin) => !(plugin instanceof WebpackManifestPlugin));
// shorten css filenames
const miniCssExtractPlugin = config.plugins.find((plugin) => plugin instanceof MiniCssExtractPlugin);
miniCssExtractPlugin.options.filename = 'css/[id].[contenthash:4].css';
miniCssExtractPlugin.options.chunkFilename = 'css/[id].[contenthash:4].c.css';
// don't emit license file
const terserPlugin = config.optimization.minimizer.find((plugin) => plugin instanceof TerserPlugin);
terserPlugin.options.extractComments = false;
// create size map
// config.plugins.push(new BundleAnalyzerPlugin());
// build progmem data files
config.plugins.push(new ProgmemGenerator({ outputPath: '../lib/framework/WWWData.h', bytesPerLine: 20 }));
}
return config;
};

14
interface/index.html Normal file
View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0, maximum-scale=1, minimum-scale=1" />
<link rel="stylesheet" href="/css/roboto.css" />
<link rel="manifest" href="/app/manifest.json" />
<title>EMS-ESP</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

14278
interface/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,18 @@
{
"name": "EMS-ESP",
"version": "3.5.0",
"version": "3.6.0",
"private": true,
"proxy": "http://localhost:3080",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"preview_standalone": "npm-run-all -p preview typesafe-i18n mock-api",
"mock-api": "nodemon --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}'",
"lint": "eslint . --ext .ts,.tsx"
},
"dependencies": {
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
@@ -10,96 +20,47 @@
"@mui/icons-material": "^5.11.0",
"@mui/material": "^5.11.8",
"@table-library/react-table-library": "4.0.24",
"@types/lodash-es": "^4.17.6",
"@types/node": "^18.13.0",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@types/react-router-dom": "^5.3.3",
"@types/lodash-es": "^4.17.6",
"async-validator": "^4.2.5",
"axios": "^1.3.2",
"jwt-decode": "^3.1.2",
"lodash-es": "^4.17.21",
"notistack": "^2.0.8",
"react": "^18.2.0",
"react-app-rewired": "^2.2.1",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",
"react-icons": "^4.7.1",
"react-router-dom": "^6.8.1",
"react-scripts": "^5.0.1",
"sockette": "^2.0.6",
"typesafe-i18n": "^5.24.0",
"typescript": "^4.9.5"
},
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject",
"format": "prettier --write '**/*.{ts,tsx,js,css,json,md}'",
"build-hosted": "env-cmd -f .env.hosted npm run build",
"build-localhost": "PUBLIC_URL=/ react-app-rewired build",
"mock-api": "nodemon --watch ../mock-api ../mock-api/server.js",
"standalone": "npm-run-all -p start typesafe-i18n mock-api",
"lint": "eslint . --ext .ts,.tsx",
"typesafe-i18n": "typesafe-i18n"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
],
"rules": {
"eol-last": 1,
"react/jsx-closing-bracket-location": 1,
"react/jsx-closing-tag-location": 1,
"react/jsx-wrap-multilines": 1,
"react/jsx-curly-newline": 1,
"no-multiple-empty-lines": [
1,
{
"max": 1
}
],
"no-trailing-spaces": 1,
"semi": 1,
"no-extra-semi": 1,
"react/jsx-max-props-per-line": [
1,
{
"when": "multiline"
}
],
"react/jsx-first-prop-new-line": [
1,
"multiline"
],
"@typescript-eslint/no-shadow": 1,
"max-len": [
1,
{
"code": 220
}
],
"arrow-parens": 1
}
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"http-proxy-middleware": "^2.0.6",
"@typescript-eslint/eslint-plugin": "^5.51.0",
"@typescript-eslint/parser": "^5.51.0",
"@vitejs/plugin-react-swc": "^3.1.0",
"babel-plugin-styled-components": "^2.0.7",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"eslint": "^8.33.0",
"eslint-config-prettier": "^8.6.0",
"eslint-import-resolver-typescript": "^3.5.3",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-refresh": "^0.3.3",
"nodemon": "^2.0.20",
"npm-run-all": "^4.1.5",
"webpack-bundle-analyzer": "^4.7.0"
"prettier": "^2.8.4",
"rollup-plugin-visualizer": "^5.9.0",
"vite": "^4.1.1",
"vite-plugin-svgr": "^2.4.0",
"vite-tsconfig-paths": "^4.0.5",
"@types/styled-components": "^5.1.26",
"@swc/plugin-styled-components": "^1.5.41",
"styled-components": "^5.3.6"
}
}

View File

@@ -4,6 +4,7 @@ var zlib = require('zlib');
var mime = require('mime-types');
const ARDUINO_INCLUDES = '#include <Arduino.h>\n\n';
const INDENT = ' ';
function getFilesSync(dir, files = []) {
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
@@ -28,17 +29,16 @@ function cleanAndOpen(path) {
return createWriteStream(path, { flags: 'w+' });
}
class ProgmemGenerator {
constructor(options = {}) {
const { outputPath, bytesPerLine = 20, indent = ' ', includes = ARDUINO_INCLUDES } = options;
this.options = { outputPath, bytesPerLine, indent, includes };
}
apply(compiler) {
compiler.hooks.emit.tapAsync({ name: 'ProgmemGenerator' }, (compilation, callback) => {
const { outputPath, bytesPerLine, indent, includes } = this.options;
export default function ProgmemGenerator({ outputPath = './WWWData.h', bytesPerLine = 20 }) {
return {
name: 'ProgmemGenerator',
writeBundle: () => {
console.log('Generating ' + outputPath);
const includes = ARDUINO_INCLUDES;
const indent = INDENT;
const fileInfo = [];
const writeStream = cleanAndOpen(resolve(compilation.options.context, outputPath));
const writeStream = cleanAndOpen(resolve(outputPath));
try {
const writeIncludes = () => {
writeStream.write(includes);
@@ -73,17 +73,18 @@ class ProgmemGenerator {
const writeFiles = () => {
// process static files
const buildPath = compilation.options.output.path;
const buildPath = resolve('build');
for (const filePath of getFilesSync(buildPath)) {
const readStream = readFileSync(filePath);
const relativeFilePath = relative(buildPath, filePath);
writeFile(relativeFilePath, readStream);
}
// process assets
const { assets } = compilation;
Object.keys(assets).forEach((relativeFilePath) => {
writeFile(relativeFilePath, coherseToBuffer(assets[relativeFilePath].source()));
});
// const { assets } = compilation;
// Object.keys(assets).forEach((relativeFilePath) => {
// writeFile(relativeFilePath, coherseToBuffer(assets[relativeFilePath].source()));
// });
};
const generateWWWClass = () => {
@@ -110,13 +111,11 @@ ${indent.repeat(2)}}
writeWWWClass();
writeStream.on('finish', () => {
callback();
// callback();
});
} finally {
writeStream.end();
}
});
}
};
}
module.exports = ProgmemGenerator;

View File

@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, user-scalable=0, maximum-scale=1, minimum-scale=1"
/>
<link rel="stylesheet" href="%PUBLIC_URL%/css/roboto.css" />
<link rel="manifest" href="%PUBLIC_URL%/app/manifest.json" />
<title>EMS-ESP</title>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div>
</body>
</html>

View File

@@ -4,13 +4,13 @@ import { SnackbarProvider } from 'notistack';
import { IconButton } from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import CustomTheme from './CustomTheme';
import AppRouting from './AppRouting';
import CustomTheme from 'CustomTheme';
import AppRouting from 'AppRouting';
import { localStorageDetector } from 'typesafe-i18n/detectors';
import TypesafeI18n from './i18n/i18n-react';
import { detectLocale } from './i18n/i18n-util';
import { loadLocaleAsync } from './i18n/i18n-util.async';
import TypesafeI18n from 'i18n/i18n-react';
import { detectLocale } from 'i18n/i18n-util';
import { loadLocaleAsync } from 'i18n/i18n-util.async';
const detectedLocale = detectLocale(localStorageDetector);

View File

@@ -4,13 +4,13 @@ import { Route, Routes, Navigate, useLocation } from 'react-router-dom';
import { useSnackbar, VariantType } from 'notistack';
import { useI18nContext } from './i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import { Authentication, AuthenticationContext } from './contexts/authentication';
import { RequireAuthenticated, RequireUnauthenticated } from './components';
import { Authentication, AuthenticationContext } from 'contexts/authentication';
import { RequireAuthenticated, RequireUnauthenticated } from 'components';
import SignIn from './SignIn';
import AuthenticatedRouting from './AuthenticatedRouting';
import SignIn from 'SignIn';
import AuthenticatedRouting from 'AuthenticatedRouting';
interface SecurityRedirectProps {
message: string;
@@ -28,7 +28,6 @@ const RootRedirect: FC<SecurityRedirectProps> = ({ message, variant, signOut })
return <Navigate to="/" />;
};
// TODO still need this?
export const RemoveTrailingSlashes = () => {
const location = useLocation();
return (

View File

@@ -2,19 +2,19 @@ import { FC, useCallback, useEffect } from 'react';
import { Navigate, Routes, Route, useNavigate, useLocation } from 'react-router-dom';
import { AxiosError } from 'axios';
import * as AuthenticationApi from './api/authentication';
import { PROJECT_PATH } from './api/env';
import { AXIOS } from './api/endpoints';
import { Layout, RequireAdmin } from './components';
import * as AuthenticationApi from 'api/authentication';
import { PROJECT_PATH } from 'api/env';
import { AXIOS } from 'api/endpoints';
import { Layout, RequireAdmin } from 'components';
import ProjectRouting from './project/ProjectRouting';
import ProjectRouting from 'project/ProjectRouting';
import NetworkConnection from './framework/network/NetworkConnection';
import AccessPoint from './framework/ap/AccessPoint';
import NetworkTime from './framework/ntp/NetworkTime';
import Mqtt from './framework/mqtt/Mqtt';
import System from './framework/system/System';
import Security from './framework/security/Security';
import NetworkConnection from 'framework/network/NetworkConnection';
import AccessPoint from 'framework/ap/AccessPoint';
import NetworkTime from 'framework/ntp/NetworkTime';
import Mqtt from 'framework/mqtt/Mqtt';
import System from 'framework/system/System';
import Security from 'framework/security/Security';
const AuthenticatedRouting: FC = () => {
const location = useLocation();

View File

@@ -4,7 +4,7 @@ import { CssBaseline } from '@mui/material';
import { createTheme, responsiveFontSizes, ThemeProvider } from '@mui/material/styles';
import { blueGrey, blue } from '@mui/material/colors';
import { RequiredChildrenProps } from './utils';
import { RequiredChildrenProps } from 'utils';
const theme = responsiveFontSizes(
createTheme({

View File

@@ -5,26 +5,26 @@ import { useSnackbar } from 'notistack';
import { Box, Fab, Paper, Typography, Button } from '@mui/material';
import ForwardIcon from '@mui/icons-material/Forward';
import * as AuthenticationApi from './api/authentication';
import { PROJECT_NAME } from './api/env';
import { AuthenticationContext } from './contexts/authentication';
import * as AuthenticationApi from 'api/authentication';
import { PROJECT_NAME } from 'api/env';
import { AuthenticationContext } from 'contexts/authentication';
import { extractErrorMessage, onEnterCallback, updateValue } from './utils';
import { SignInRequest } from './types';
import { ValidatedTextField } from './components';
import { SIGN_IN_REQUEST_VALIDATOR, validate } from './validators';
import { extractErrorMessage, onEnterCallback, updateValue } from 'utils';
import { SignInRequest } from 'types';
import { ValidatedTextField } from 'components';
import { SIGN_IN_REQUEST_VALIDATOR, validate } from 'validators';
import { I18nContext } from './i18n/i18n-react';
import type { Locales } from './i18n/i18n-types';
import { loadLocaleAsync } from './i18n/i18n-util.async';
import { I18nContext } from 'i18n/i18n-react';
import type { Locales } from 'i18n/i18n-types';
import { loadLocaleAsync } from 'i18n/i18n-util.async';
import { ReactComponent as NLflag } from './i18n/NL.svg';
import { ReactComponent as DEflag } from './i18n/DE.svg';
import { ReactComponent as GBflag } from './i18n/GB.svg';
import { ReactComponent as SVflag } from './i18n/SV.svg';
import { ReactComponent as PLflag } from './i18n/PL.svg';
import { ReactComponent as NOflag } from './i18n/NO.svg';
import { ReactComponent as FRflag } from './i18n/FR.svg';
import { ReactComponent as NLflag } from 'i18n/NL.svg';
import { ReactComponent as DEflag } from 'i18n/DE.svg';
import { ReactComponent as GBflag } from 'i18n/GB.svg';
import { ReactComponent as SVflag } from 'i18n/SV.svg';
import { ReactComponent as PLflag } from 'i18n/PL.svg';
import { ReactComponent as NOflag } from 'i18n/NO.svg';
import { ReactComponent as FRflag } from 'i18n/FR.svg';
const SignIn: FC = () => {
const authenticationContext = useContext(AuthenticationContext);

View File

@@ -1,6 +1,6 @@
import { AxiosPromise } from 'axios';
import { APSettings, APStatus } from '../types';
import { APSettings, APStatus } from 'types';
import { AXIOS } from './endpoints';
export function readAPStatus(): AxiosPromise<APStatus> {

View File

@@ -3,7 +3,7 @@ import * as H from 'history';
import jwtDecode from 'jwt-decode';
import { Path } from 'react-router-dom';
import { Me, SignInRequest, SignInResponse } from '../types';
import { Me, SignInRequest, SignInResponse } from 'types';
import { ACCESS_TOKEN, AXIOS } from './endpoints';
import { PROJECT_PATH } from './env';

View File

@@ -1,2 +1,2 @@
export const PROJECT_NAME = process.env.REACT_APP_PROJECT_NAME || 'EMS-ESP';
export const PROJECT_PATH = process.env.REACT_APP_PROJECT_PATH || 'project';
export const PROJECT_NAME = 'EMS-ESP';
export const PROJECT_PATH = 'project';

View File

@@ -1,6 +1,6 @@
import { AxiosPromise } from 'axios';
import { Features } from '../types';
import { Features } from 'types';
import { AXIOS } from './endpoints';

View File

@@ -1,5 +1,5 @@
import { AxiosPromise } from 'axios';
import { MqttSettings, MqttStatus } from '../types';
import { MqttSettings, MqttStatus } from 'types';
import { AXIOS } from './endpoints';

View File

@@ -1,6 +1,6 @@
import { AxiosPromise } from 'axios';
import { WiFiNetworkList, NetworkSettings, NetworkStatus } from '../types';
import { WiFiNetworkList, NetworkSettings, NetworkStatus } from 'types';
import { AXIOS } from './endpoints';

View File

@@ -1,5 +1,5 @@
import { AxiosPromise } from 'axios';
import { NTPSettings, NTPStatus, Time } from '../types';
import { NTPSettings, NTPStatus, Time } from 'types';
import { AXIOS } from './endpoints';

View File

@@ -1,6 +1,6 @@
import { AxiosPromise } from 'axios';
import { SecuritySettings, Token } from '../types';
import { SecuritySettings, Token } from 'types';
import { AXIOS } from './endpoints';

View File

@@ -1,6 +1,6 @@
import { AxiosPromise } from 'axios';
import { OTASettings, SystemStatus, LogSettings, LogEntries } from '../types';
import { OTASettings, SystemStatus, LogSettings, LogEntries } from 'types';
import { AXIOS, AXIOS_BIN, FileUploadConfig, startUploadFile } from './endpoints';

View File

@@ -2,7 +2,7 @@ import { FC } from 'react';
import { Paper, Divider } from '@mui/material';
import { RequiredChildrenProps } from '../utils';
import { RequiredChildrenProps } from 'utils';
interface SectionContentProps extends RequiredChildrenProps {
title: string;

View File

@@ -3,8 +3,8 @@ import { useLocation } from 'react-router-dom';
import { Box, Toolbar } from '@mui/material';
import { PROJECT_NAME } from '../../api/env';
import { RequiredChildrenProps } from '../../utils';
import { PROJECT_NAME } from 'api/env';
import { RequiredChildrenProps } from 'utils';
import LayoutDrawer from './LayoutDrawer';
import LayoutAppBar from './LayoutAppBar';

View File

@@ -17,19 +17,19 @@ import {
import PersonIcon from '@mui/icons-material/Person';
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
import { AuthenticatedContext } from '../../contexts/authentication';
import { AuthenticatedContext } from 'contexts/authentication';
import { I18nContext } from '../../i18n/i18n-react';
import type { Locales } from '../../i18n/i18n-types';
import { loadLocaleAsync } from '../../i18n/i18n-util.async';
import { I18nContext } from 'i18n/i18n-react';
import type { Locales } from 'i18n/i18n-types';
import { loadLocaleAsync } from 'i18n/i18n-util.async';
import { ReactComponent as NLflag } from '../../i18n/NL.svg';
import { ReactComponent as DEflag } from '../../i18n/DE.svg';
import { ReactComponent as GBflag } from '../../i18n/GB.svg';
import { ReactComponent as SVflag } from '../../i18n/SV.svg';
import { ReactComponent as PLflag } from '../../i18n/PL.svg';
import { ReactComponent as NOflag } from '../../i18n/NO.svg';
import { ReactComponent as FRflag } from '../../i18n/FR.svg';
import { ReactComponent as NLflag } from 'i18n/NL.svg';
import { ReactComponent as DEflag } from 'i18n/DE.svg';
import { ReactComponent as GBflag } from 'i18n/GB.svg';
import { ReactComponent as SVflag } from 'i18n/SV.svg';
import { ReactComponent as PLflag } from 'i18n/PL.svg';
import { ReactComponent as NOflag } from 'i18n/NO.svg';
import { ReactComponent as FRflag } from 'i18n/FR.svg';
const ItemTypography = styled(Typography)<TypographyProps>({
maxWidth: '250px',

View File

@@ -2,7 +2,7 @@ import { FC } from 'react';
import { Box, Divider, Drawer, Toolbar, Typography, styled } from '@mui/material';
import { PROJECT_NAME } from '../../api/env';
import { PROJECT_NAME } from 'api/env';
import LayoutMenu from './LayoutMenu';
import { DRAWER_WIDTH } from './Layout';

View File

@@ -9,12 +9,12 @@ import SettingsIcon from '@mui/icons-material/Settings';
import LockIcon from '@mui/icons-material/Lock';
import SettingsEthernetIcon from '@mui/icons-material/SettingsEthernet';
import ProjectMenu from '../../project/ProjectMenu';
import ProjectMenu from 'project/ProjectMenu';
import LayoutMenuItem from './LayoutMenuItem';
import { AuthenticatedContext } from '../../contexts/authentication';
import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const LayoutMenu: FC = () => {
const authenticatedContext = useContext(AuthenticatedContext);

View File

@@ -5,7 +5,7 @@ import { ListItem, ListItemButton, ListItemIcon, ListItemText, SvgIconProps } fr
import { grey } from '@mui/material/colors';
import { routeMatches } from '../../utils';
import { routeMatches } from 'utils';
interface LayoutMenuItemProps {
icon: React.ComponentType<SvgIconProps>;

View File

@@ -3,9 +3,9 @@ import { FC } from 'react';
import { Box, Button, CircularProgress, Typography } from '@mui/material';
import RefreshIcon from '@mui/icons-material/Refresh';
import { MessageBox } from '..';
import { MessageBox } from 'components';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
interface FormLoaderProps {
message?: string;

View File

@@ -2,7 +2,7 @@ import { FC } from 'react';
import { CircularProgress, Box, Typography, Theme } from '@mui/material';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
interface LoadingSpinnerProps {
height?: number | string;

View File

@@ -2,7 +2,7 @@ import { FC } from 'react';
import type { Blocker } from '@remix-run/router';
import { Button, Dialog, DialogActions, DialogContent, DialogTitle } from '@mui/material';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
interface BlockNavigationProps {
blocker: Blocker;
@@ -19,7 +19,7 @@ const BlockNavigation: FC<BlockNavigationProps> = ({ blocker }) => {
<Button variant="outlined" onClick={() => blocker.reset?.()} color="secondary">
{LL.STAY()}
</Button>
<Button variant="contained" onClick={() => blocker.proceed?.()} color="primary" autoFocus>
<Button variant="contained" onClick={() => blocker.proceed?.()} color="primary">
{LL.LEAVE()}
</Button>
</DialogActions>

View File

@@ -1,8 +1,8 @@
import { FC, useContext } from 'react';
import { Navigate } from 'react-router-dom';
import { AuthenticatedContext } from '../../contexts/authentication';
import { RequiredChildrenProps } from '../../utils';
import { AuthenticatedContext } from 'contexts/authentication';
import { RequiredChildrenProps } from 'utils';
const RequireAdmin: FC<RequiredChildrenProps> = ({ children }) => {
const authenticatedContext = useContext(AuthenticatedContext);

View File

@@ -5,10 +5,10 @@ import {
AuthenticatedContext,
AuthenticatedContextValue,
AuthenticationContext
} from '../../contexts/authentication/context';
import { storeLoginRedirect } from '../../api/authentication';
} from 'contexts/authentication/context';
import { storeLoginRedirect } from 'api/authentication';
import { RequiredChildrenProps } from '../../utils';
import { RequiredChildrenProps } from 'utils';
const RequireAuthenticated: FC<RequiredChildrenProps> = ({ children }) => {
const authenticationContext = useContext(AuthenticationContext);

View File

@@ -1,9 +1,9 @@
import { FC, useContext } from 'react';
import { Navigate } from 'react-router-dom';
import * as AuthenticationApi from '../../api/authentication';
import { AuthenticationContext } from '../../contexts/authentication';
import { RequiredChildrenProps } from '../../utils';
import * as AuthenticationApi from 'api/authentication';
import { AuthenticationContext } from 'contexts/authentication';
import { RequiredChildrenProps } from 'utils';
const RequireUnauthenticated: FC<RequiredChildrenProps> = ({ children }) => {
const authenticationContext = useContext(AuthenticationContext);

View File

@@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom';
import { Tabs, useMediaQuery, useTheme } from '@mui/material';
import { RequiredChildrenProps } from '../../utils';
import { RequiredChildrenProps } from 'utils';
interface RouterTabsProps extends RequiredChildrenProps {
value: string | false;
@@ -15,6 +15,7 @@ const RouterTabs: FC<RouterTabsProps> = ({ value, children }) => {
const theme = useTheme();
const smallDown = useMediaQuery(theme.breakpoints.down('sm'));
// TODO fix this
const handleTabChange = (event: React.ChangeEvent<{}>, path: string) => {
navigate(path);
};

View File

@@ -8,7 +8,7 @@ import { Box, Button, LinearProgress, Theme, Typography, useTheme } from '@mui/m
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
import CancelIcon from '@mui/icons-material/Cancel';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const getBorderColor = (theme: Theme, props: DropzoneState) => {
if (props.isDragAccept) {

View File

@@ -2,10 +2,10 @@ import { useCallback, useEffect, useState } from 'react';
import axios, { AxiosPromise, CancelTokenSource, AxiosProgressEvent } from 'axios';
import { useSnackbar } from 'notistack';
import { extractErrorMessage } from '../../utils';
import { FileUploadConfig } from '../../api/endpoints';
import { extractErrorMessage } from 'utils';
import { FileUploadConfig } from 'api/endpoints';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
interface MediaUploadOptions {
upload: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;

View File

@@ -2,13 +2,13 @@ import { FC, useCallback, useEffect, useState } from 'react';
import { useSnackbar } from 'notistack';
import { useNavigate } from 'react-router-dom';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import * as AuthenticationApi from '../../api/authentication';
import { ACCESS_TOKEN } from '../../api/endpoints';
import { RequiredChildrenProps } from '../../utils';
import { LoadingSpinner } from '../../components';
import { Me } from '../../types';
import * as AuthenticationApi from 'api/authentication';
import { ACCESS_TOKEN } from 'api/endpoints';
import { RequiredChildrenProps } from 'utils';
import { LoadingSpinner } from 'components';
import { Me } from 'types';
import { AuthenticationContext } from './context';
const Authentication: FC<RequiredChildrenProps> = ({ children }) => {

View File

@@ -1,5 +1,5 @@
import { createContext } from 'react';
import { Me } from '../../types';
import { Me } from 'types';
export interface AuthenticationContextValue {
refresh: () => Promise<void>;

View File

@@ -1,10 +1,10 @@
import { FC, useCallback, useEffect, useState } from 'react';
import * as FeaturesApi from '../../api/features';
import * as FeaturesApi from 'api/features';
import { extractErrorMessage, RequiredChildrenProps } from '../../utils';
import { Features } from '../../types';
import { ApplicationError, LoadingSpinner } from '../../components';
import { extractErrorMessage, RequiredChildrenProps } from 'utils';
import { Features } from 'types';
import { ApplicationError, LoadingSpinner } from 'components';
import { FeaturesContext } from '.';

View File

@@ -1,6 +1,6 @@
import { createContext } from 'react';
import { Features } from '../../types';
import { Features } from 'types';
export interface FeaturesContextValue {
features: Features;

View File

@@ -6,7 +6,7 @@ import { Button, Checkbox, MenuItem } from '@mui/material';
import WarningIcon from '@mui/icons-material/Warning';
import CancelIcon from '@mui/icons-material/Cancel';
import { createAPSettingsValidator, validate } from '../../validators';
import { createAPSettingsValidator, validate } from 'validators';
import {
BlockFormControlLabel,
ButtonRow,
@@ -15,13 +15,13 @@ import {
ValidatedPasswordField,
ValidatedTextField,
BlockNavigation
} from '../../components';
} from 'components';
import { APProvisionMode, APSettings } from '../../types';
import { numberValue, updateValueDirty, useRest } from '../../utils';
import * as APApi from '../../api/ap';
import { APProvisionMode, APSettings } from 'types';
import { numberValue, updateValueDirty, useRest } from 'utils';
import * as APApi from 'api/ap';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
export const isAPEnabled = ({ provision_mode }: APSettings) => {
return provision_mode === APProvisionMode.AP_MODE_ALWAYS || provision_mode === APProvisionMode.AP_MODE_DISCONNECTED;

View File

@@ -6,12 +6,12 @@ import DeviceHubIcon from '@mui/icons-material/DeviceHub';
import ComputerIcon from '@mui/icons-material/Computer';
import RefreshIcon from '@mui/icons-material/Refresh';
import * as APApi from '../../api/ap';
import { APNetworkStatus, APStatus } from '../../types';
import { ButtonRow, FormLoader, SectionContent } from '../../components';
import { useRest } from '../../utils';
import * as APApi from 'api/ap';
import { APNetworkStatus, APStatus } from 'types';
import { ButtonRow, FormLoader, SectionContent } from 'components';
import { useRest } from 'utils';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => {
switch (status) {

View File

@@ -3,12 +3,12 @@ import { Navigate, Routes, Route } from 'react-router-dom';
import { Tab } from '@mui/material';
import { AuthenticatedContext } from '../../contexts/authentication';
import { AuthenticatedContext } from 'contexts/authentication';
import APStatusForm from './APStatusForm';
import APSettingsForm from './APSettingsForm';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from '../../components';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const AccessPoint: FC = () => {
const { LL } = useI18nContext();

View File

@@ -3,13 +3,13 @@ import { Navigate, Route, Routes } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from '../../components';
import { AuthenticatedContext } from '../../contexts/authentication';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
import { AuthenticatedContext } from 'contexts/authentication';
import MqttStatusForm from './MqttStatusForm';
import MqttSettingsForm from './MqttSettingsForm';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const Mqtt: FC = () => {
const { LL } = useI18nContext();

View File

@@ -6,7 +6,7 @@ import { Button, Checkbox, MenuItem, Grid, Typography, InputAdornment } from '@m
import WarningIcon from '@mui/icons-material/Warning';
import CancelIcon from '@mui/icons-material/Cancel';
import { createMqttSettingsValidator, validate } from '../../validators';
import { createMqttSettingsValidator, validate } from 'validators';
import {
BlockFormControlLabel,
ButtonRow,
@@ -15,12 +15,12 @@ import {
ValidatedPasswordField,
ValidatedTextField,
BlockNavigation
} from '../../components';
import { MqttSettings } from '../../types';
import { numberValue, updateValueDirty, useRest } from '../../utils';
import * as MqttApi from '../../api/mqtt';
} from 'components';
import { MqttSettings } from 'types';
import { numberValue, updateValueDirty, useRest } from 'utils';
import * as MqttApi from 'api/mqtt';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const MqttSettingsForm: FC = () => {
const { loadData, saving, data, setData, origData, dirtyFlags, setDirtyFlags, blocker, saveData, errorMessage } =

View File

@@ -7,12 +7,12 @@ import ReportIcon from '@mui/icons-material/Report';
import SpeakerNotesOffIcon from '@mui/icons-material/SpeakerNotesOff';
import AutoAwesomeMotionIcon from '@mui/icons-material/AutoAwesomeMotion';
import { ButtonRow, FormLoader, SectionContent } from '../../components';
import { MqttStatus, MqttDisconnectReason } from '../../types';
import * as MqttApi from '../../api/mqtt';
import { useRest } from '../../utils';
import { ButtonRow, FormLoader, SectionContent } from 'components';
import { MqttStatus, MqttDisconnectReason } from 'types';
import * as MqttApi from 'api/mqtt';
import { useRest } from 'utils';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
export const mqttStatusHighlight = ({ enabled, connected }: MqttStatus, theme: Theme) => {
if (!enabled) {

View File

@@ -3,15 +3,15 @@ import { Navigate, Routes, Route, useNavigate } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from '../../components';
import { WiFiNetwork } from '../../types';
import { AuthenticatedContext } from '../../contexts/authentication';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
import { WiFiNetwork } from 'types';
import { AuthenticatedContext } from 'contexts/authentication';
import { WiFiConnectionContext } from './WiFiConnectionContext';
import NetworkStatusForm from './NetworkStatusForm';
import WiFiNetworkScanner from './WiFiNetworkScanner';
import NetworkSettingsForm from './NetworkSettingsForm';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const NetworkConnection: FC = () => {
const { LL } = useI18nContext();

View File

@@ -31,19 +31,19 @@ import {
ValidatedTextField,
MessageBox,
BlockNavigation
} from '../../components';
import { NetworkSettings } from '../../types';
import * as NetworkApi from '../../api/network';
import { numberValue, updateValueDirty, useRest } from '../../utils';
import * as EMSESP from '../../project/api';
} from 'components';
import { NetworkSettings } from 'types';
import * as NetworkApi from 'api/network';
import { numberValue, updateValueDirty, useRest } from 'utils';
import * as EMSESP from 'project/api';
import { WiFiConnectionContext } from './WiFiConnectionContext';
import { isNetworkOpen, networkSecurityMode } from './WiFiNetworkSelector';
import { ValidateFieldsError } from 'async-validator';
import { validate } from '../../validators';
import { createNetworkSettingsValidator } from '../../validators/network';
import { validate } from 'validators';
import { createNetworkSettingsValidator } from 'validators/network';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import RestartMonitor from '../system/RestartMonitor';
const WiFiSettingsForm: FC = () => {

View File

@@ -9,12 +9,12 @@ import DnsIcon from '@mui/icons-material/Dns';
import RefreshIcon from '@mui/icons-material/Refresh';
import RouterIcon from '@mui/icons-material/Router';
import { ButtonRow, FormLoader, SectionContent } from '../../components';
import { NetworkConnectionStatus, NetworkStatus } from '../../types';
import * as NetworkApi from '../../api/network';
import { useRest } from '../../utils';
import { ButtonRow, FormLoader, SectionContent } from 'components';
import { NetworkConnectionStatus, NetworkStatus } from 'types';
import * as NetworkApi from 'api/network';
import { useRest } from 'utils';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const isConnected = ({ status }: NetworkStatus) =>
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED ||

View File

@@ -1,5 +1,5 @@
import { createContext } from 'react';
import { WiFiNetwork } from '../../types';
import { WiFiNetwork } from 'types';
export interface WiFiConnectionContextValue {
selectedNetwork?: WiFiNetwork;

View File

@@ -4,13 +4,13 @@ import { useSnackbar } from 'notistack';
import { Button } from '@mui/material';
import PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
import * as NetworkApi from '../../api/network';
import { WiFiNetwork, WiFiNetworkList } from '../../types';
import { ButtonRow, FormLoader, SectionContent } from '../../components';
import * as NetworkApi from 'api/network';
import { WiFiNetwork, WiFiNetworkList } from 'types';
import { ButtonRow, FormLoader, SectionContent } from 'components';
import WiFiNetworkSelector from './WiFiNetworkSelector';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const NUM_POLLS = 10;
const POLLING_FREQUENCY = 500;

View File

@@ -6,13 +6,13 @@ import LockOpenIcon from '@mui/icons-material/LockOpen';
import LockIcon from '@mui/icons-material/Lock';
import WifiIcon from '@mui/icons-material/Wifi';
import { MessageBox } from '../../components';
import { MessageBox } from 'components';
import { WiFiEncryptionType, WiFiNetwork, WiFiNetworkList } from '../../types';
import { WiFiEncryptionType, WiFiNetwork, WiFiNetworkList } from 'types';
import { WiFiConnectionContext } from './WiFiConnectionContext';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
interface WiFiNetworkSelectorProps {
networkList: WiFiNetworkList;

View File

@@ -5,7 +5,7 @@ import { Button, Checkbox, MenuItem } from '@mui/material';
import WarningIcon from '@mui/icons-material/Warning';
import CancelIcon from '@mui/icons-material/Cancel';
import { validate } from '../../validators';
import { validate } from 'validators';
import {
BlockFormControlLabel,
ButtonRow,
@@ -13,14 +13,14 @@ import {
SectionContent,
ValidatedTextField,
BlockNavigation
} from '../../components';
import { NTPSettings } from '../../types';
import { updateValueDirty, useRest } from '../../utils';
import * as NTPApi from '../../api/ntp';
} from 'components';
import { NTPSettings } from 'types';
import { updateValueDirty, useRest } from 'utils';
import * as NTPApi from 'api/ntp';
import { selectedTimeZone, timeZoneSelectItems, TIME_ZONES } from './TZ';
import { NTP_SETTINGS_VALIDATOR } from '../../validators/ntp';
import { NTP_SETTINGS_VALIDATOR } from 'validators/ntp';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const NTPSettingsForm: FC = () => {
const { loadData, saving, data, setData, origData, dirtyFlags, setDirtyFlags, blocker, saveData, errorMessage } =

View File

@@ -26,13 +26,13 @@ import UpdateIcon from '@mui/icons-material/Update';
import DnsIcon from '@mui/icons-material/Dns';
import CancelIcon from '@mui/icons-material/Cancel';
import * as NTPApi from '../../api/ntp';
import { NTPStatus, NTPSyncStatus } from '../../types';
import { ButtonRow, FormLoader, SectionContent } from '../../components';
import { extractErrorMessage, formatDateTime, formatLocalDateTime, useRest } from '../../utils';
import { AuthenticatedContext } from '../../contexts/authentication';
import * as NTPApi from 'api/ntp';
import { NTPStatus, NTPSyncStatus } from 'types';
import { ButtonRow, FormLoader, SectionContent } from 'components';
import { extractErrorMessage, formatDateTime, formatLocalDateTime, useRest } from 'utils';
import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
export const isNtpActive = ({ status }: NTPStatus) => status === NTPSyncStatus.NTP_ACTIVE;
export const isNtpEnabled = ({ status }: NTPStatus) => status !== NTPSyncStatus.NTP_DISABLED;
@@ -127,7 +127,6 @@ const NTPStatusForm: FC = () => {
onClick={configureTime}
disabled={processing}
color="primary"
autoFocus
>
{LL.UPDATE()}
</Button>

View File

@@ -3,13 +3,13 @@ import { Navigate, Route, Routes } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from '../../components';
import { AuthenticatedContext } from '../../contexts/authentication';
import { RequireAdmin, RouterTabs, useLayoutTitle, useRouterTab } from 'components';
import { AuthenticatedContext } from 'contexts/authentication';
import NTPStatusForm from './NTPStatusForm';
import NTPSettingsForm from './NTPSettingsForm';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const NetworkTime: FC = () => {
const { LL } = useI18nContext();

View File

@@ -13,13 +13,13 @@ import {
import CloseIcon from '@mui/icons-material/Close';
import { extractErrorMessage } from '../../utils';
import { extractErrorMessage } from 'utils';
import { useSnackbar } from 'notistack';
import { MessageBox } from '../../components';
import * as SecurityApi from '../../api/security';
import { Token } from '../../types';
import { MessageBox } from 'components';
import * as SecurityApi from 'api/security';
import { Token } from 'types';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
interface GenerateTokenProps {
username?: string;

View File

@@ -9,18 +9,17 @@ import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close';
import VpnKeyIcon from '@mui/icons-material/VpnKey';
import { Table } from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme';
import { Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import * as SecurityApi from '../../api/security';
import { SecuritySettings, User } from '../../types';
import { ButtonRow, FormLoader, MessageBox, SectionContent } from '../../components';
import { createUserValidator } from '../../validators';
import { useRest } from '../../utils';
import { AuthenticatedContext } from '../../contexts/authentication';
import * as SecurityApi from 'api/security';
import { SecuritySettings, User } from 'types';
import { ButtonRow, FormLoader, MessageBox, SectionContent } from 'components';
import { createUserValidator } from 'validators';
import { useRest } from 'utils';
import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import GenerateToken from './GenerateToken';
import UserForm from './UserForm';

View File

@@ -3,12 +3,12 @@ import { Navigate, Routes, Route } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RouterTabs, useRouterTab, useLayoutTitle } from '../../components';
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
import SecuritySettingsForm from './SecuritySettingsForm';
import ManageUsersForm from './ManageUsersForm';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const Security: FC = () => {
const { LL } = useI18nContext();

View File

@@ -5,21 +5,14 @@ import { Button } from '@mui/material';
import WarningIcon from '@mui/icons-material/Warning';
import CancelIcon from '@mui/icons-material/Cancel';
import * as SecurityApi from '../../api/security';
import { SecuritySettings } from '../../types';
import {
ButtonRow,
FormLoader,
MessageBox,
SectionContent,
ValidatedPasswordField,
BlockNavigation
} from '../../components';
import { SECURITY_SETTINGS_VALIDATOR, validate } from '../../validators';
import { updateValueDirty, useRest } from '../../utils';
import { AuthenticatedContext } from '../../contexts/authentication';
import * as SecurityApi from 'api/security';
import { SecuritySettings } from 'types';
import { ButtonRow, FormLoader, MessageBox, SectionContent, ValidatedPasswordField, BlockNavigation } from 'components';
import { SECURITY_SETTINGS_VALIDATOR, validate } from 'validators';
import { updateValueDirty, useRest } from 'utils';
import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const SecuritySettingsForm: FC = () => {
const { LL } = useI18nContext();

View File

@@ -7,12 +7,12 @@ import SaveIcon from '@mui/icons-material/Save';
import { Button, Checkbox, Dialog, DialogActions, DialogContent, DialogTitle } from '@mui/material';
import { BlockFormControlLabel, ValidatedPasswordField, ValidatedTextField } from '../../components';
import { User } from '../../types';
import { updateValue } from '../../utils';
import { validate } from '../../validators';
import { BlockFormControlLabel, ValidatedPasswordField, ValidatedTextField } from 'components';
import { User } from 'types';
import { updateValue } from 'utils';
import { validate } from 'validators';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
interface UserFormProps {
creating: boolean;
@@ -93,7 +93,6 @@ const UserForm: FC<UserFormProps> = ({ creating, validator, user, setUser, onDon
variant="outlined"
onClick={validateAndDone}
color="primary"
autoFocus
>
{creating ? LL.ADD(0) : LL.UPDATE()}
</Button>

View File

@@ -3,19 +3,19 @@ import { AxiosPromise } from 'axios';
import { Typography, Button, Box } from '@mui/material';
import { FileUploadConfig } from '../../api/endpoints';
import { FileUploadConfig } from 'api/endpoints';
import { SingleUpload, useFileUpload } from '../../components';
import { SingleUpload, useFileUpload } from 'components';
import DownloadIcon from '@mui/icons-material/GetApp';
import { useSnackbar } from 'notistack';
import { extractErrorMessage } from '../../utils';
import { extractErrorMessage } from 'utils';
import * as EMSESP from '../../project/api';
import * as EMSESP from 'project/api';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
interface UploadFileProps {
uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;

View File

@@ -4,7 +4,7 @@ import { Button, Checkbox } from '@mui/material';
import WarningIcon from '@mui/icons-material/Warning';
import CancelIcon from '@mui/icons-material/Cancel';
import * as SystemApi from '../../api/system';
import * as SystemApi from 'api/system';
import {
BlockFormControlLabel,
ButtonRow,
@@ -13,16 +13,16 @@ import {
ValidatedPasswordField,
ValidatedTextField,
BlockNavigation
} from '../../components';
} from 'components';
import { OTASettings } from '../../types';
import { numberValue, updateValueDirty, useRest } from '../../utils';
import { OTASettings } from 'types';
import { numberValue, updateValueDirty, useRest } from 'utils';
import { ValidateFieldsError } from 'async-validator';
import { validate } from '../../validators';
import { OTA_SETTINGS_VALIDATOR } from '../../validators/system';
import { validate } from 'validators';
import { OTA_SETTINGS_VALIDATOR } from 'validators/system';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const OTASettingsForm: FC = () => {
const { loadData, saving, data, setData, origData, dirtyFlags, setDirtyFlags, blocker, saveData, errorMessage } =

View File

@@ -1,10 +1,9 @@
import { useEffect } from 'react';
import { FC, useRef, useState } from 'react';
import { FC, useRef, useState, useEffect } from 'react';
import * as SystemApi from '../../api/system';
import { FormLoader } from '../../components';
import * as SystemApi from 'api/system';
import { FormLoader } from 'components';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const RESTART_TIMEOUT = 2 * 60 * 1000;
const POLL_TIMEOUT = 2000;

View File

@@ -3,15 +3,15 @@ import { Navigate, Routes, Route } from 'react-router-dom';
import { Tab } from '@mui/material';
import { useRouterTab, RouterTabs, useLayoutTitle, RequireAdmin } from '../../components';
import { AuthenticatedContext } from '../../contexts/authentication';
import { useRouterTab, RouterTabs, useLayoutTitle, RequireAdmin } from 'components';
import { AuthenticatedContext } from 'contexts/authentication';
import UploadFileForm from './UploadFileForm';
import SystemStatusForm from './SystemStatusForm';
import OTASettingsForm from './OTASettingsForm';
import SystemLog from './SystemLog';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const System: FC = () => {
const { LL } = useI18nContext();

View File

@@ -2,21 +2,21 @@ import { FC, useState, useEffect, useCallback, useLayoutEffect } from 'react';
import { Box, styled, Button, Checkbox, MenuItem, Grid, Slider, FormLabel } from '@mui/material';
import * as SystemApi from '../../api/system';
import { addAccessTokenParameter } from '../../api/authentication';
import * as SystemApi from 'api/system';
import { addAccessTokenParameter } from 'api/authentication';
import { SectionContent, FormLoader, BlockFormControlLabel, ValidatedTextField } from '../../components';
import { SectionContent, FormLoader, BlockFormControlLabel, ValidatedTextField } from 'components';
import { LogSettings, LogEntry, LogEntries, LogLevel } from '../../types';
import { updateValue, useRest, extractErrorMessage } from '../../utils';
import { LogSettings, LogEntry, LogEntries, LogLevel } from 'types';
import { updateValue, useRest, extractErrorMessage } from 'utils';
import DownloadIcon from '@mui/icons-material/GetApp';
import { useSnackbar } from 'notistack';
import { EVENT_SOURCE_ROOT } from '../../api/endpoints';
import { EVENT_SOURCE_ROOT } from 'api/endpoints';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
export const LOG_EVENTSOURCE_URL = EVENT_SOURCE_ROOT + 'log';
@@ -137,7 +137,7 @@ const SystemLog: FC = () => {
const onDownload = () => {
let result = '';
for (let i of logEntries.events) {
for (const i of logEntries.events) {
result += i.t + ' ' + levelLabel(i.l) + ' ' + i.i + ': [' + i.n + '] ' + i.m + '\n';
}
const a = document.createElement('a');

View File

@@ -31,17 +31,17 @@ import BuildIcon from '@mui/icons-material/Build';
import TimerIcon from '@mui/icons-material/Timer';
import CancelIcon from '@mui/icons-material/Cancel';
import { ButtonRow, FormLoader, SectionContent, MessageBox } from '../../components';
import { SystemStatus, Version } from '../../types';
import * as SystemApi from '../../api/system';
import { extractErrorMessage, useRest } from '../../utils';
import { ButtonRow, FormLoader, SectionContent, MessageBox } from 'components';
import { SystemStatus, Version } from 'types';
import * as SystemApi from 'api/system';
import { extractErrorMessage, useRest } from 'utils';
import { AuthenticatedContext } from '../../contexts/authentication';
import { AuthenticatedContext } from 'contexts/authentication';
import axios from 'axios';
import RestartMonitor from './RestartMonitor';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
export const VERSIONCHECK_ENDPOINT = 'https://api.github.com/repos/emsesp/EMS-ESP32/releases/latest';
export const VERSIONCHECK_DEV_ENDPOINT = 'https://api.github.com/repos/emsesp/EMS-ESP32/releases/tags/latest';
@@ -131,7 +131,6 @@ const SystemStatusForm: FC = () => {
onClick={restart}
disabled={processing}
color="primary"
autoFocus
>
{LL.RESTART()}
</Button>
@@ -238,7 +237,6 @@ const SystemStatusForm: FC = () => {
variant="outlined"
onClick={factoryReset}
disabled={processing}
autoFocus
color="error"
>
{LL.FACTORY_RESET()}

View File

@@ -1,13 +1,13 @@
import { FC, useRef, useState } from 'react';
import * as SystemApi from '../../api/system';
import { SectionContent } from '../../components';
import { FileUploadConfig } from '../../api/endpoints';
import * as SystemApi from 'api/system';
import { SectionContent } from 'components';
import { FileUploadConfig } from 'api/endpoints';
import GeneralFileUpload from './GeneralFileUpload';
import RestartMonitor from './RestartMonitor';
import { useI18nContext } from '../../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const UploadFileForm: FC = () => {
const [restarting, setRestarting] = useState<boolean>();

0
interface/src/i18n/FR.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 243 B

After

Width:  |  Height:  |  Size: 243 B

View File

@@ -2,9 +2,9 @@ import React from 'react';
import ReactDOM from 'react-dom/client';
import { createBrowserRouter, createRoutesFromElements, Route, RouterProvider } from 'react-router-dom';
import App from './App';
import App from 'App';
const router = createBrowserRouter(createRoutesFromElements(<Route path="/*" element={<App />}></Route>));
const router = createBrowserRouter(createRoutesFromElements(<Route path="/*" element={<App />} />));
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>

View File

@@ -3,9 +3,9 @@ import { Navigate, Route, Routes } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RouterTabs, useRouterTab, useLayoutTitle } from '../components';
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
import { useI18nContext } from '../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import DashboardStatus from './DashboardStatus';
import DashboardData from './DashboardData';

View File

@@ -22,10 +22,9 @@ import {
import { useSnackbar } from 'notistack';
import { Table } from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme';
import { useSort, SortToggleType } from '@table-library/react-table-library/sort';
import { Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import { useRowSelect } from '@table-library/react-table-library/select';
import DownloadIcon from '@mui/icons-material/GetApp';
@@ -49,13 +48,13 @@ import DeviceIcon from './DeviceIcon';
import { IconContext } from 'react-icons';
import { AuthenticatedContext } from '../contexts/authentication';
import { AuthenticatedContext } from 'contexts/authentication';
import { ButtonRow, ValidatedTextField, SectionContent, MessageBox } from '../components';
import { ButtonRow, ValidatedTextField, SectionContent, MessageBox } from 'components';
import * as EMSESP from './api';
import { numberValue, updateValue, extractErrorMessage } from '../utils';
import { numberValue, updateValue, extractErrorMessage } from 'utils';
import {
SensorData,
@@ -72,7 +71,7 @@ import {
DeviceEntityMask
} from './types';
import { useI18nContext } from '../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
const DashboardData: FC = () => {
const { me } = useContext(AuthenticatedContext);
@@ -502,7 +501,9 @@ const DashboardData: FC = () => {
onChange={updateValue(setDeviceValue)}
>
{deviceValue.l.map((val) => (
<MenuItem value={val}>{val}</MenuItem>
<MenuItem value={val} key={val}>
{val}
</MenuItem>
))}
</ValidatedTextField>
)}

View File

@@ -16,9 +16,8 @@ import {
useTheme
} from '@mui/material';
import { Table } from '@table-library/react-table-library/table';
import { useTheme as tableTheme } from '@table-library/react-table-library/theme';
import { Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import DeviceHubIcon from '@mui/icons-material/DeviceHub';
import RefreshIcon from '@mui/icons-material/Refresh';
@@ -26,18 +25,18 @@ import PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
import CancelIcon from '@mui/icons-material/Cancel';
import DirectionsBusIcon from '@mui/icons-material/DirectionsBus';
import { AuthenticatedContext } from '../contexts/authentication';
import { AuthenticatedContext } from 'contexts/authentication';
import { ButtonRow, FormLoader, SectionContent } from '../components';
import { ButtonRow, FormLoader, SectionContent } from 'components';
import { Status, busConnectionStatus, Stat } from './types';
import { extractErrorMessage, useRest } from '../utils';
import { extractErrorMessage, useRest } from 'utils';
import * as EMSESP from './api';
import type { Translation } from '../i18n/i18n-types';
import { useI18nContext } from '../i18n/i18n-react';
import type { Translation } from 'i18n/i18n-types';
import { useI18nContext } from 'i18n/i18n-react';
export const isConnected = ({ status }: Status) => status !== busConnectionStatus.BUS_STATUS_OFFLINE;
@@ -80,7 +79,7 @@ const DashboardStatus: FC = () => {
const { me } = useContext(AuthenticatedContext);
const showName = (id: any) => {
let name: keyof Translation['STATUS_NAMES'] = id;
const name: keyof Translation['STATUS_NAMES'] = id;
return LL.STATUS_NAMES[name]();
};
@@ -183,7 +182,7 @@ const DashboardStatus: FC = () => {
<Button startIcon={<CancelIcon />} variant="outlined" onClick={() => setConfirmScan(false)} color="secondary">
{LL.CANCEL()}
</Button>
<Button startIcon={<PermScanWifiIcon />} variant="outlined" onClick={scan} color="primary" autoFocus>
<Button startIcon={<PermScanWifiIcon />} variant="outlined" onClick={scan} color="primary">
{LL.SCAN()}
</Button>
</DialogActions>
@@ -226,13 +225,13 @@ const DashboardStatus: FC = () => {
}
/>
</ListItem>
<Box m={3}></Box>
<Box m={3} />
<Table data={{ nodes: data.stats }} theme={stats_theme} layout={{ custom: true }}>
{(tableList: any) => (
<>
<Header>
<HeaderRow>
<HeaderCell resize></HeaderCell>
<HeaderCell resize />
<HeaderCell stiff>{LL.SUCCESS()}</HeaderCell>
<HeaderCell stiff>{LL.FAIL()}</HeaderCell>
<HeaderCell stiff>{LL.QUALITY()}</HeaderCell>

View File

@@ -1,16 +1,12 @@
import { FC } from 'react';
import { CgSmartHomeBoiler } from 'react-icons/cg';
import { MdOutlineSensors } from 'react-icons/md';
import { FaSolarPanel } from 'react-icons/fa';
import { MdThermostatAuto } from 'react-icons/md';
import { AiOutlineControl } from 'react-icons/ai';
import { MdThermostatAuto, MdOutlineSensors } from 'react-icons/md';
import { GiHeatHaze } from 'react-icons/gi';
import { TiFlowSwitch } from 'react-icons/ti';
import { VscVmConnect } from 'react-icons/vsc';
import { AiOutlineGateway } from 'react-icons/ai';
import { AiOutlineAlert } from 'react-icons/ai';
import { AiOutlineChrome } from 'react-icons/ai';
import { AiOutlineControl, AiOutlineGateway, AiOutlineAlert, AiOutlineChrome } from 'react-icons/ai';
interface DeviceIconProps {
type_id: number;

View File

@@ -3,9 +3,9 @@ import { Navigate, Route, Routes } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RouterTabs, useRouterTab, useLayoutTitle } from '../components';
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
import { useI18nContext } from '../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import HelpInformation from './HelpInformation';

View File

@@ -2,7 +2,7 @@ import { FC } from 'react';
import { Typography, Button, Box, List, ListItem, ListItemText, Link, ListItemAvatar } from '@mui/material';
import { SectionContent } from '../components';
import { SectionContent } from 'components';
import { useSnackbar } from 'notistack';
@@ -12,9 +12,9 @@ import GitHubIcon from '@mui/icons-material/GitHub';
import DownloadIcon from '@mui/icons-material/GetApp';
import EastIcon from '@mui/icons-material/East';
import { extractErrorMessage } from '../utils';
import { extractErrorMessage } from 'utils';
import { useI18nContext } from '../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import * as EMSESP from './api';

View File

@@ -2,15 +2,15 @@ import { FC, useContext } from 'react';
import { List } from '@mui/material';
import { AuthenticatedContext } from '../contexts/authentication';
import { AuthenticatedContext } from 'contexts/authentication';
import { PROJECT_PATH } from '../api/env';
import { PROJECT_PATH } from 'api/env';
import { useI18nContext } from '../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import TuneIcon from '@mui/icons-material/Tune';
import DashboardIcon from '@mui/icons-material/Dashboard';
import LayoutMenuItem from '../components/layout/LayoutMenuItem';
import LayoutMenuItem from 'components/layout/LayoutMenuItem';
import InfoIcon from '@mui/icons-material/Info';
const ProjectMenu: FC = () => {

View File

@@ -1,7 +1,7 @@
import { FC } from 'react';
import { Navigate, Routes, Route } from 'react-router-dom';
import { RequireAdmin } from '../components';
import { RequireAdmin } from 'components';
import Dashboard from './Dashboard';
import Settings from './Settings';

View File

@@ -3,9 +3,9 @@ import { Navigate, Route, Routes } from 'react-router-dom';
import { Tab } from '@mui/material';
import { RouterTabs, useRouterTab, useLayoutTitle } from '../components';
import { RouterTabs, useRouterTab, useLayoutTitle } from 'components';
import { useI18nContext } from '../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import SettingsApplication from './SettingsApplication';
import SettingsCustomization from './SettingsCustomization';

View File

@@ -9,7 +9,7 @@ import WarningIcon from '@mui/icons-material/Warning';
import CancelIcon from '@mui/icons-material/Cancel';
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
import { validate } from '../validators';
import { validate } from 'validators';
import { createSettingsValidator } from './validators';
import {
@@ -20,14 +20,14 @@ import {
ButtonRow,
MessageBox,
BlockNavigation
} from '../components';
import { numberValue, extractErrorMessage, updateValueDirty, useRest } from '../utils';
} from 'components';
import { numberValue, extractErrorMessage, updateValueDirty, useRest } from 'utils';
import * as EMSESP from './api';
import { Settings, BOARD_PROFILES } from './types';
import { useI18nContext } from '../i18n/i18n-react';
import RestartMonitor from '../framework/system/RestartMonitor';
import { useI18nContext } from 'i18n/i18n-react';
import RestartMonitor from 'framework/system/RestartMonitor';
export function boardProfileSelectItems() {
return Object.keys(BOARD_PROFILES).map((code) => (
@@ -505,9 +505,9 @@ const SettingsApplication: FC = () => {
>
<MenuItem value={1}>{LL.ONOFF()}</MenuItem>
<MenuItem value={2}>{LL.ONOFF_CAP()}</MenuItem>
<MenuItem value={3}>"true"/"false"</MenuItem>
<MenuItem value={3}>&quot;true&quot;/&quot;false&quot;</MenuItem>
<MenuItem value={4}>true/false</MenuItem>
<MenuItem value={5}>"1"/"0"</MenuItem>
<MenuItem value={5}>&quot;1&quot;/&quot;0&quot;</MenuItem>
<MenuItem value={6}>1/0</MenuItem>
</ValidatedTextField>
</Grid>

View File

@@ -19,9 +19,8 @@ import {
Link
} from '@mui/material';
import { Table } from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme';
import { Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import { useSnackbar } from 'notistack';
@@ -36,17 +35,17 @@ import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
import OptionIcon from './OptionIcon';
import { ButtonRow, FormLoader, ValidatedTextField, SectionContent, MessageBox, BlockNavigation } from '../components';
import { ButtonRow, FormLoader, ValidatedTextField, SectionContent, MessageBox, BlockNavigation } from 'components';
import * as EMSESP from './api';
import { extractErrorMessage, updateValue } from '../utils';
import { extractErrorMessage, updateValue } from 'utils';
import { DeviceShort, Devices, DeviceEntity, DeviceEntityMask } from './types';
import { useI18nContext } from '../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import RestartMonitor from '../framework/system/RestartMonitor';
import RestartMonitor from 'framework/system/RestartMonitor';
export const APIURL = window.location.origin + '/api/';
@@ -57,7 +56,7 @@ const SettingsCustomization: FC = () => {
const emptyDeviceEntity = { id: '', v: 0, n: '', cn: '', m: 0, w: false };
const [numChanges, setNumChanges] = useState<number>(0);
let blocker = useBlocker(numChanges !== 0);
const blocker = useBlocker(numChanges !== 0);
const [restarting, setRestarting] = useState<boolean>(false);
const [restartNeeded, setRestartNeeded] = useState<boolean>(false);
@@ -201,15 +200,15 @@ const SettingsCustomization: FC = () => {
}
const getMaskNumber = (newMask: string[]) => {
var new_mask = 0;
for (let entry of newMask) {
let new_mask = 0;
for (const entry of newMask) {
new_mask |= Number(entry);
}
return new_mask;
};
const getMaskString = (m: number) => {
var new_masks = [];
let new_masks: string[] = [];
if ((m & 1) === 1) {
new_masks.push('1');
}
@@ -561,7 +560,6 @@ const SettingsCustomization: FC = () => {
</ToggleButtonGroup>
)}
</Cell>
<Cell>{!deviceEntity && formatName(de)}</Cell>
<Cell>{!deviceEntity && !(de.m & DeviceEntityMask.DV_READONLY) && formatValue(de.mi)}</Cell>
<Cell>{!deviceEntity && !(de.m & DeviceEntityMask.DV_READONLY) && formatValue(de.ma)}</Cell>
@@ -584,13 +582,7 @@ const SettingsCustomization: FC = () => {
<Button startIcon={<CancelIcon />} variant="outlined" onClick={() => setConfirmReset(false)} color="secondary">
{LL.CANCEL()}
</Button>
<Button
startIcon={<SettingsBackupRestoreIcon />}
variant="outlined"
onClick={resetCustomization}
autoFocus
color="error"
>
<Button startIcon={<SettingsBackupRestoreIcon />} variant="outlined" onClick={resetCustomization} color="error">
{LL.RESET(0)}
</Button>
</DialogActions>

View File

@@ -1,5 +1,5 @@
import { AxiosPromise } from 'axios';
import { AXIOS, AXIOS_API, AXIOS_BIN } from '../api/endpoints';
import { AXIOS, AXIOS_API, AXIOS_BIN } from 'api/endpoints';
import {
BoardProfile,

View File

@@ -1,5 +1,5 @@
import Schema, { InternalRuleItem } from 'async-validator';
import { IP_OR_HOSTNAME_VALIDATOR } from '../validators/shared';
import { IP_OR_HOSTNAME_VALIDATOR } from 'validators/shared';
import { Settings } from './types';
export const GPIO_VALIDATOR = {

View File

@@ -1 +0,0 @@
/// <reference types="react-scripts" />

View File

@@ -1,19 +0,0 @@
const pkg = require('../package.json');
const { createProxyMiddleware } = require('http-proxy-middleware');
const target = process.env.PROXY || pkg.proxy;
module.exports = function (app) {
app.use(
createProxyMiddleware('/api', {
target
})
);
// app.use(
// createProxyMiddleware('/ws', {
// target: target,
// // target: target.replace(/^http(s?):\/\//, 'ws$1://'),
// ws: true
// })
// );
};

View File

@@ -1,42 +0,0 @@
import * as React from 'react';
import { useBeforeUnload, unstable_useBlocker as useBlocker } from 'react-router-dom';
// You can abstract `useBlocker` to use the browser's `window.confirm` dialog to
// determine whether or not the user should navigate within the current origin.
// `useBlocker` can also be used in conjunction with `useBeforeUnload` to
// prevent navigation away from the current origin.
//
// IMPORTANT: There are edge cases with this behavior in which React Router
// cannot reliably access the correct location in the history stack. In such
// cases the user may attempt to stay on the page but the app navigates anyway,
// or the app may stay on the correct page but the browser's history stack gets
// out of whack. You should test your own implementation thoroughly to make sure
// the tradeoffs are right for your users.
export default function usePrompt(
message: string | null | undefined | false,
{ beforeUnload }: { beforeUnload?: boolean } = {}
) {
let blocker = useBlocker(
React.useCallback(() => (typeof message === 'string' ? !window.confirm(message) : false), [message])
);
let prevState = React.useRef(blocker.state);
React.useEffect(() => {
if (blocker.state === 'blocked') {
blocker.reset();
}
prevState.current = blocker.state;
}, [blocker]);
useBeforeUnload(
React.useCallback(
(event) => {
if (beforeUnload && typeof message === 'string') {
event.preventDefault();
event.returnValue = message;
}
},
[message, beforeUnload]
),
{ capture: true }
);
}

View File

@@ -4,7 +4,7 @@ import { AxiosPromise } from 'axios';
import { extractErrorMessage } from '.';
import { useI18nContext } from '../i18n/i18n-react';
import { useI18nContext } from 'i18n/i18n-react';
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
@@ -26,7 +26,7 @@ export const useRest = <D>({ read, update }: RestRequestOptions<D>) => {
const [origData, setOrigData] = useState<D>();
const [dirtyFlags, setDirtyFlags] = useState<string[]>();
let blocker = useBlocker(dirtyFlags?.length !== 0);
const blocker = useBlocker(dirtyFlags?.length !== 0);
const loadData = useCallback(async () => {
setData(undefined);

View File

@@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import Sockette from 'sockette';
import { debounce } from 'lodash-es';
import { addAccessTokenParameter } from '../api/authentication';
import { addAccessTokenParameter } from 'api/authentication';
interface WebSocketIdMessage {
type: 'id';
@@ -17,7 +17,7 @@ interface WebSocketPayloadMessage<D> {
export type WebSocketMessage<D> = WebSocketIdMessage | WebSocketPayloadMessage<D>;
export const useWs = <D>(wsUrl: string, wsThrottle: number = 100) => {
export const useWs = <D>(wsUrl: string, wsThrottle = 100) => {
const ws = useRef<Sockette>();
const clientId = useRef<string>();
@@ -43,7 +43,7 @@ export const useWs = <D>(wsUrl: string, wsThrottle: number = 100) => {
}
}, []);
const doSaveData = useCallback((newData: D, clearData: boolean = false) => {
const doSaveData = useCallback((newData: D, clearData = false) => {
if (!ws.current) {
return;
}
@@ -55,11 +55,7 @@ export const useWs = <D>(wsUrl: string, wsThrottle: number = 100) => {
const saveData = useRef(debounce(doSaveData, wsThrottle));
const updateData = (
newData: React.SetStateAction<D | undefined>,
transmitData: boolean = true,
clearData: boolean = false
) => {
const updateData = (newData: React.SetStateAction<D | undefined>, transmitData: true, clearData: false) => {
setData(newData);
setTransmit(transmitData);
setClear(clearData);

View File

@@ -1,6 +1,6 @@
import Schema from 'async-validator';
import { isAPEnabled } from '../framework/ap/APSettingsForm';
import { APSettings } from '../types';
import { isAPEnabled } from 'framework/ap/APSettingsForm';
import { APSettings } from 'types';
import { IP_ADDRESS_VALIDATOR } from './shared';
export const createAPSettingsValidator = (apSettings: APSettings) =>

View File

@@ -1,5 +1,5 @@
import Schema from 'async-validator';
import { MqttSettings } from '../types';
import { MqttSettings } from 'types';
import { IP_OR_HOSTNAME_VALIDATOR } from './shared';
export const createMqttSettingsValidator = (mqttSettings: MqttSettings) =>

View File

@@ -1,5 +1,5 @@
import Schema from 'async-validator';
import { NetworkSettings } from '../types';
import { NetworkSettings } from 'types';
import { HOSTNAME_VALIDATOR, IP_ADDRESS_VALIDATOR } from './shared';
export const createNetworkSettingsValidator = (networkSettings: NetworkSettings) =>

Some files were not shown because too many files have changed in this diff Show More