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

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'
}
};

View File

@@ -1,6 +0,0 @@
{
"singleQuote": true,
"semi": true,
"trailingComma": "none",
"printWidth": 120
}

View File

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

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>

14262
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) =>

View File

@@ -1,5 +1,5 @@
import Schema, { InternalRuleItem } from 'async-validator';
import { User } from '../types';
import { User } from 'types';
export const SECURITY_SETTINGS_VALIDATOR = new Schema({
jwt_secret: [

1
interface/src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@@ -1,21 +1,29 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"types": ["vite/client", "vite-plugin-svgr/client", "node"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"useUnknownInCatchVariables": false,
"jsx": "react-jsx"
"jsx": "react-jsx",
"noImplicitAny": false,
"baseUrl": "src",
"paths": {
"@": ["src"],
"@/*": ["src/*"]
}
},
"include": ["src"]
"include": ["src", "vite.config.ts", "progmem-generator.js"]
}

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