This commit is contained in:
MichaelDvP
2026-04-14 08:09:50 +02:00
55 changed files with 577 additions and 393 deletions

View File

@@ -41,7 +41,7 @@
"react": "^19.2.5", "react": "^19.2.5",
"react-dom": "^19.2.5", "react-dom": "^19.2.5",
"react-icons": "^5.6.0", "react-icons": "^5.6.0",
"react-router": "^7.14.0", "react-router": "^7.14.1",
"react-toastify": "^11.0.5", "react-toastify": "^11.0.5",
"typesafe-i18n": "^5.27.1", "typesafe-i18n": "^5.27.1",
"typescript": "^6.0.2" "typescript": "^6.0.2"
@@ -55,14 +55,14 @@
"@types/node": "^25.6.0", "@types/node": "^25.6.0",
"@types/react": "^19.2.14", "@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"axe-core": "^4.11.2", "axe-core": "^4.11.3",
"concurrently": "^9.2.1", "concurrently": "^9.2.1",
"eslint": "^10.2.0", "eslint": "^10.2.0",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",
"prettier": "^3.8.2", "prettier": "^3.8.2",
"rollup-plugin-visualizer": "^7.0.1", "rollup-plugin-visualizer": "^7.0.1",
"terser": "^5.46.1", "terser": "^5.46.1",
"typescript-eslint": "^8.58.1", "typescript-eslint": "^8.58.2",
"vite": "^8.0.8", "vite": "^8.0.8",
"vite-plugin-imagemin": "^0.6.1", "vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^6.1.1" "vite-tsconfig-paths": "^6.1.1"

164
interface/pnpm-lock.yaml generated
View File

@@ -63,8 +63,8 @@ importers:
specifier: ^5.6.0 specifier: ^5.6.0
version: 5.6.0(react@19.2.5) version: 5.6.0(react@19.2.5)
react-router: react-router:
specifier: ^7.14.0 specifier: ^7.14.1
version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) version: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
react-toastify: react-toastify:
specifier: ^11.0.5 specifier: ^11.0.5
version: 11.0.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) version: 11.0.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
@@ -97,8 +97,8 @@ importers:
specifier: ^19.2.3 specifier: ^19.2.3
version: 19.2.3(@types/react@19.2.14) version: 19.2.3(@types/react@19.2.14)
axe-core: axe-core:
specifier: ^4.11.2 specifier: ^4.11.3
version: 4.11.2 version: 4.11.3
concurrently: concurrently:
specifier: ^9.2.1 specifier: ^9.2.1
version: 9.2.1 version: 9.2.1
@@ -118,8 +118,8 @@ importers:
specifier: ^5.46.1 specifier: ^5.46.1
version: 5.46.1 version: 5.46.1
typescript-eslint: typescript-eslint:
specifier: ^8.58.1 specifier: ^8.58.2
version: 8.58.1(eslint@10.2.0)(typescript@6.0.2) version: 8.58.2(eslint@10.2.0)(typescript@6.0.2)
vite: vite:
specifier: ^8.0.8 specifier: ^8.0.8
version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1) version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)
@@ -1036,63 +1036,63 @@ packages:
'@types/svgo@2.6.4': '@types/svgo@2.6.4':
resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==} resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==}
'@typescript-eslint/eslint-plugin@8.58.1': '@typescript-eslint/eslint-plugin@8.58.2':
resolution: {integrity: sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==} resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
'@typescript-eslint/parser': ^8.58.1 '@typescript-eslint/parser': ^8.58.2
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/parser@8.58.1': '@typescript-eslint/parser@8.58.2':
resolution: {integrity: sha512-gGkiNMPqerb2cJSVcruigx9eHBlLG14fSdPdqMoOcBfh+vvn4iCq2C8MzUB89PrxOXk0y3GZ1yIWb9aOzL93bw==} resolution: {integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/project-service@8.58.1': '@typescript-eslint/project-service@8.58.2':
resolution: {integrity: sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g==} resolution: {integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/scope-manager@8.58.1': '@typescript-eslint/scope-manager@8.58.2':
resolution: {integrity: sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w==} resolution: {integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/tsconfig-utils@8.58.1': '@typescript-eslint/tsconfig-utils@8.58.2':
resolution: {integrity: sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw==} resolution: {integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/type-utils@8.58.1': '@typescript-eslint/type-utils@8.58.2':
resolution: {integrity: sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w==} resolution: {integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/types@8.58.1': '@typescript-eslint/types@8.58.2':
resolution: {integrity: sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw==} resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.58.1': '@typescript-eslint/typescript-estree@8.58.2':
resolution: {integrity: sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg==} resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/utils@8.58.1': '@typescript-eslint/utils@8.58.2':
resolution: {integrity: sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ==} resolution: {integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/visitor-keys@8.58.1': '@typescript-eslint/visitor-keys@8.58.2':
resolution: {integrity: sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ==} resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
acorn-jsx@5.3.2: acorn-jsx@5.3.2:
@@ -1161,8 +1161,8 @@ packages:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
axe-core@4.11.2: axe-core@4.11.3:
resolution: {integrity: sha512-byD6KPdvo72y/wj2T/4zGEvvlis+PsZsn/yPS3pEO+sFpcrqRpX/TJCxvVaEsNeMrfQbCr7w163YqoD9IYwHXw==} resolution: {integrity: sha512-zBQouZixDTbo3jMGqHKyePxYxr1e5W8UdTmBQ7sNtaA9M2bE32daxxPLS/jojhKOHxQ7LWwPjfiwf/fhaJWzlg==}
engines: {node: '>=4'} engines: {node: '>=4'}
babel-plugin-macros@3.1.0: babel-plugin-macros@3.1.0:
@@ -1283,8 +1283,8 @@ packages:
resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==} resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
caniuse-lite@1.0.30001787: caniuse-lite@1.0.30001788:
resolution: {integrity: sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==} resolution: {integrity: sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==}
caw@2.0.1: caw@2.0.1:
resolution: {integrity: sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==} resolution: {integrity: sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==}
@@ -1519,8 +1519,8 @@ packages:
duplexer3@0.1.5: duplexer3@0.1.5:
resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==} resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==}
electron-to-chromium@1.5.335: electron-to-chromium@1.5.336:
resolution: {integrity: sha512-q9n5T4BR4Xwa2cwbrwcsDJtHD/enpQ5S1xF1IAtdqf5AAgqDFmR/aakqH3ChFdqd/QXJhS3rnnXFtexU7rax6Q==} resolution: {integrity: sha512-AbH9q9J455r/nLmdNZes0G0ZKcRX73FicwowalLs6ijwOmCJSRRrLX63lcAlzy9ux3dWK1w1+1nsBJEWN11hcQ==}
emoji-regex@10.6.0: emoji-regex@10.6.0:
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
@@ -2790,8 +2790,8 @@ packages:
react-is@19.2.5: react-is@19.2.5:
resolution: {integrity: sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==} resolution: {integrity: sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==}
react-router@7.14.0: react-router@7.14.1:
resolution: {integrity: sha512-m/xR9N4LQLmAS0ZhkY2nkPA1N7gQ5TUVa5n8TgANuDTARbn1gt+zLPXEm7W0XDTbrQ2AJSJKhoa6yx1D8BcpxQ==} resolution: {integrity: sha512-5BCvFskyAAVumqhEKh/iPhLOIkfxcEUz8WqFIARCkMg8hZZzDYX9CtwxXA0e+qT8zAxmMC0x3Ckb9iMONwc5jg==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
peerDependencies: peerDependencies:
react: '>=18' react: '>=18'
@@ -3206,8 +3206,8 @@ packages:
peerDependencies: peerDependencies:
typescript: '>=3.5.1' typescript: '>=3.5.1'
typescript-eslint@8.58.1: typescript-eslint@8.58.2:
resolution: {integrity: sha512-gf6/oHChByg9HJvhMO1iBexJh12AqqTfnuxscMDOVqfJW3htsdRJI/GfPpHTTcyeB8cSTUY2JcZmVgoyPqcrDg==} resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
@@ -4187,14 +4187,14 @@ snapshots:
dependencies: dependencies:
'@types/node': 25.6.0 '@types/node': 25.6.0
'@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2)': '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2)':
dependencies: dependencies:
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@6.0.2) '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
'@typescript-eslint/scope-manager': 8.58.1 '@typescript-eslint/scope-manager': 8.58.2
'@typescript-eslint/type-utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
'@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
'@typescript-eslint/visitor-keys': 8.58.1 '@typescript-eslint/visitor-keys': 8.58.2
eslint: 10.2.0 eslint: 10.2.0
ignore: 7.0.5 ignore: 7.0.5
natural-compare: 1.4.0 natural-compare: 1.4.0
@@ -4203,41 +4203,41 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2)': '@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2)':
dependencies: dependencies:
'@typescript-eslint/scope-manager': 8.58.1 '@typescript-eslint/scope-manager': 8.58.2
'@typescript-eslint/types': 8.58.1 '@typescript-eslint/types': 8.58.2
'@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2)
'@typescript-eslint/visitor-keys': 8.58.1 '@typescript-eslint/visitor-keys': 8.58.2
debug: 4.4.3 debug: 4.4.3
eslint: 10.2.0 eslint: 10.2.0
typescript: 6.0.2 typescript: 6.0.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/project-service@8.58.1(typescript@6.0.2)': '@typescript-eslint/project-service@8.58.2(typescript@6.0.2)':
dependencies: dependencies:
'@typescript-eslint/tsconfig-utils': 8.58.1(typescript@6.0.2) '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2)
'@typescript-eslint/types': 8.58.1 '@typescript-eslint/types': 8.58.2
debug: 4.4.3 debug: 4.4.3
typescript: 6.0.2 typescript: 6.0.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/scope-manager@8.58.1': '@typescript-eslint/scope-manager@8.58.2':
dependencies: dependencies:
'@typescript-eslint/types': 8.58.1 '@typescript-eslint/types': 8.58.2
'@typescript-eslint/visitor-keys': 8.58.1 '@typescript-eslint/visitor-keys': 8.58.2
'@typescript-eslint/tsconfig-utils@8.58.1(typescript@6.0.2)': '@typescript-eslint/tsconfig-utils@8.58.2(typescript@6.0.2)':
dependencies: dependencies:
typescript: 6.0.2 typescript: 6.0.2
'@typescript-eslint/type-utils@8.58.1(eslint@10.2.0)(typescript@6.0.2)': '@typescript-eslint/type-utils@8.58.2(eslint@10.2.0)(typescript@6.0.2)':
dependencies: dependencies:
'@typescript-eslint/types': 8.58.1 '@typescript-eslint/types': 8.58.2
'@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2)
'@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
debug: 4.4.3 debug: 4.4.3
eslint: 10.2.0 eslint: 10.2.0
ts-api-utils: 2.5.0(typescript@6.0.2) ts-api-utils: 2.5.0(typescript@6.0.2)
@@ -4245,14 +4245,14 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/types@8.58.1': {} '@typescript-eslint/types@8.58.2': {}
'@typescript-eslint/typescript-estree@8.58.1(typescript@6.0.2)': '@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2)':
dependencies: dependencies:
'@typescript-eslint/project-service': 8.58.1(typescript@6.0.2) '@typescript-eslint/project-service': 8.58.2(typescript@6.0.2)
'@typescript-eslint/tsconfig-utils': 8.58.1(typescript@6.0.2) '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2)
'@typescript-eslint/types': 8.58.1 '@typescript-eslint/types': 8.58.2
'@typescript-eslint/visitor-keys': 8.58.1 '@typescript-eslint/visitor-keys': 8.58.2
debug: 4.4.3 debug: 4.4.3
minimatch: 10.2.5 minimatch: 10.2.5
semver: 7.7.4 semver: 7.7.4
@@ -4262,20 +4262,20 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/utils@8.58.1(eslint@10.2.0)(typescript@6.0.2)': '@typescript-eslint/utils@8.58.2(eslint@10.2.0)(typescript@6.0.2)':
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0) '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0)
'@typescript-eslint/scope-manager': 8.58.1 '@typescript-eslint/scope-manager': 8.58.2
'@typescript-eslint/types': 8.58.1 '@typescript-eslint/types': 8.58.2
'@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2)
eslint: 10.2.0 eslint: 10.2.0
typescript: 6.0.2 typescript: 6.0.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/visitor-keys@8.58.1': '@typescript-eslint/visitor-keys@8.58.2':
dependencies: dependencies:
'@typescript-eslint/types': 8.58.1 '@typescript-eslint/types': 8.58.2
eslint-visitor-keys: 5.0.1 eslint-visitor-keys: 5.0.1
acorn-jsx@5.3.2(acorn@8.16.0): acorn-jsx@5.3.2(acorn@8.16.0):
@@ -4328,7 +4328,7 @@ snapshots:
dependencies: dependencies:
possible-typed-array-names: 1.1.0 possible-typed-array-names: 1.1.0
axe-core@4.11.2: {} axe-core@4.11.3: {}
babel-plugin-macros@3.1.0: babel-plugin-macros@3.1.0:
dependencies: dependencies:
@@ -4408,8 +4408,8 @@ snapshots:
browserslist@4.28.2: browserslist@4.28.2:
dependencies: dependencies:
baseline-browser-mapping: 2.10.18 baseline-browser-mapping: 2.10.18
caniuse-lite: 1.0.30001787 caniuse-lite: 1.0.30001788
electron-to-chromium: 1.5.335 electron-to-chromium: 1.5.336
node-releases: 2.0.37 node-releases: 2.0.37
update-browserslist-db: 1.2.3(browserslist@4.28.2) update-browserslist-db: 1.2.3(browserslist@4.28.2)
@@ -4471,7 +4471,7 @@ snapshots:
camelcase@2.1.1: {} camelcase@2.1.1: {}
caniuse-lite@1.0.30001787: {} caniuse-lite@1.0.30001788: {}
caw@2.0.1: caw@2.0.1:
dependencies: dependencies:
@@ -4773,7 +4773,7 @@ snapshots:
duplexer3@0.1.5: {} duplexer3@0.1.5: {}
electron-to-chromium@1.5.335: {} electron-to-chromium@1.5.336: {}
emoji-regex@10.6.0: {} emoji-regex@10.6.0: {}
@@ -5991,7 +5991,7 @@ snapshots:
react-is@19.2.5: {} react-is@19.2.5: {}
react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5):
dependencies: dependencies:
cookie: 1.1.1 cookie: 1.1.1
react: 19.2.5 react: 19.2.5
@@ -6417,12 +6417,12 @@ snapshots:
dependencies: dependencies:
typescript: 6.0.2 typescript: 6.0.2
typescript-eslint@8.58.1(eslint@10.2.0)(typescript@6.0.2): typescript-eslint@8.58.2(eslint@10.2.0)(typescript@6.0.2):
dependencies: dependencies:
'@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2) '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2)
'@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@6.0.2) '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
'@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2)
'@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2)
eslint: 10.2.0 eslint: 10.2.0
typescript: 6.0.2 typescript: 6.0.2
transitivePeerDependencies: transitivePeerDependencies:

View File

@@ -3,6 +3,7 @@ import { toast } from 'react-toastify';
import ForwardIcon from '@mui/icons-material/Forward'; import ForwardIcon from '@mui/icons-material/Forward';
import { Box, Button, Paper, Typography } from '@mui/material'; import { Box, Button, Paper, Typography } from '@mui/material';
import type { Theme } from '@mui/material/styles';
import * as AuthenticationApi from 'components/routing/authentication'; import * as AuthenticationApi from 'components/routing/authentication';
import { useRequest } from 'alova/client'; import { useRequest } from 'alova/client';
@@ -36,7 +37,7 @@ const SignIn = memo(() => {
{ {
immediate: false immediate: false
} }
).onSuccess((response) => { ).onSuccess((response: { data: { access_token: string } }) => {
if (response.data) { if (response.data) {
authenticationContext.signIn(response.data.access_token); authenticationContext.signIn(response.data.access_token);
} }
@@ -78,7 +79,6 @@ const SignIn = memo(() => {
} }
}, [signInRequest, signIn, LL]); }, [signInRequest, signIn, LL]);
// Memoize callback to prevent recreation on every render
const submitOnEnter = useMemo(() => onEnterCallback(signIn), [signIn]); const submitOnEnter = useMemo(() => onEnterCallback(signIn), [signIn]);
// get rid of scrollbar // get rid of scrollbar
@@ -92,13 +92,15 @@ const SignIn = memo(() => {
return ( return (
<Box <Box
display="flex" sx={(theme: Theme) => ({
height="100vh" display: 'flex',
margin="auto" height: '100vh',
padding={2} margin: 'auto',
justifyContent="center" padding: 2,
flexDirection="column" justifyContent: 'center',
maxWidth={(theme) => theme.breakpoints.values.sm} flexDirection: 'column',
maxWidth: theme.breakpoints.values.sm
})}
> >
<Paper <Paper
sx={(theme) => ({ sx={(theme) => ({
@@ -111,16 +113,18 @@ const SignIn = memo(() => {
width: '100%' width: '100%'
})} })}
> >
<Typography mb={1} variant="h4"> <Typography sx={{ mb: 1 }} variant="h4">
{PROJECT_NAME} {PROJECT_NAME}
</Typography> </Typography>
<LanguageSelector /> <LanguageSelector />
<Box <Box
mt={1} sx={{
display="flex" mt: 1,
flexDirection="column" display: 'flex',
gap={1} flexDirection: 'column',
alignItems="center" gap: 1,
alignItems: 'center'
}}
> >
<ValidatedTextField <ValidatedTextField
fieldErrors={fieldErrors || {}} fieldErrors={fieldErrors || {}}

View File

@@ -343,9 +343,9 @@ const CustomEntities = () => {
return ( return (
<SectionContent> <SectionContent>
{blocker ? <BlockNavigation blocker={blocker} /> : null} {blocker ? <BlockNavigation blocker={blocker} /> : null}
<Box mb={2} color="warning.main"> <Typography sx={{ mb: 2 }} color="warning" variant="body1">
<Typography variant="body1">{LL.ENTITIES_HELP_1()}.</Typography> {LL.ENTITIES_HELP_1()}.
</Box> </Typography>
{renderEntity()} {renderEntity()}
@@ -361,8 +361,8 @@ const CustomEntities = () => {
/> />
)} )}
<Box mt={2} display="flex" flexWrap="wrap"> <Box sx={{ mt: 2, display: 'flex', flexWrap: 'wrap' }}>
<Box flexGrow={1}> <Box sx={{ flexGrow: 1 }}>
{numChanges > 0 && ( {numChanges > 0 && (
<ButtonRow> <ButtonRow>
<Button <Button
@@ -384,7 +384,7 @@ const CustomEntities = () => {
</ButtonRow> </ButtonRow>
)} )}
</Box> </Box>
<Box flexWrap="nowrap" whiteSpace="nowrap"> <Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
<Button <Button
startIcon={<AddIcon />} startIcon={<AddIcon />}
variant="outlined" variant="outlined"

View File

@@ -7,7 +7,7 @@ import DoneIcon from '@mui/icons-material/Done';
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined'; import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined'; import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlineOutlined'; import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined';
import { import {
Box, Box,
Button, Button,
@@ -178,7 +178,7 @@ const CustomEntitiesDialog = ({
onChange={updateFormValue} onChange={updateFormValue}
/> />
</Grid> </Grid>
<Grid mt={3}> <Grid sx={{ mt: 3 }}>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox
@@ -238,7 +238,7 @@ const CustomEntitiesDialog = ({
)} )}
{editItem.ram === 0 && ( {editItem.ram === 0 && (
<> <>
<Grid mt={3}> <Grid sx={{ mt: 3 }}>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox
@@ -404,7 +404,7 @@ const CustomEntitiesDialog = ({
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
{!creating && ( {!creating && (
<Box flexGrow={1}> <Box sx={{ flexGrow: 1 }}>
<Button <Button
startIcon={<RemoveIcon />} startIcon={<RemoveIcon />}
variant="outlined" variant="outlined"

View File

@@ -470,10 +470,10 @@ const Customizations = () => {
const renderDeviceList = () => ( const renderDeviceList = () => (
<> <>
<Box mb={1} color="warning.main"> <Typography sx={{ mb: 1 }} color="warning" variant="body1">
<Typography variant="body1">{LL.CUSTOMIZATIONS_HELP_1()}.</Typography> {LL.CUSTOMIZATIONS_HELP_1()}.
</Box> </Typography>
<Box display="flex" flexWrap="wrap" alignItems="center" gap={2}> <Box sx={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 2 }}>
{rename ? ( {rename ? (
<> <>
<TextField <TextField
@@ -570,27 +570,22 @@ const Customizations = () => {
const renderDeviceData = () => { const renderDeviceData = () => {
return ( return (
<> <>
<Box color="warning.main"> <Typography sx={{ mt: 1, mb: 1 }} color="warning" variant="body2">
<Typography variant="body2" mt={1} mb={1}>
<OptionIcon type="favorite" isSet={true} />={LL.CUSTOMIZATIONS_HELP_2()} <OptionIcon type="favorite" isSet={true} />={LL.CUSTOMIZATIONS_HELP_2()}
&nbsp;&nbsp; &nbsp;&nbsp;
<OptionIcon type="readonly" isSet={true} />={LL.CUSTOMIZATIONS_HELP_3()} <OptionIcon type="readonly" isSet={true} />={LL.CUSTOMIZATIONS_HELP_3()}
&nbsp;&nbsp; &nbsp;&nbsp;
<OptionIcon type="api_mqtt_exclude" isSet={true} />= <OptionIcon type="api_mqtt_exclude" isSet={true} />=
{LL.CUSTOMIZATIONS_HELP_4()}&nbsp;&nbsp; {LL.CUSTOMIZATIONS_HELP_4()}&nbsp;&nbsp;
<OptionIcon type="web_exclude" isSet={true} />= <OptionIcon type="web_exclude" isSet={true} />={LL.CUSTOMIZATIONS_HELP_5()}
{LL.CUSTOMIZATIONS_HELP_5()}&nbsp;&nbsp; &nbsp;&nbsp;
<OptionIcon type="deleted" isSet={true} />={LL.CUSTOMIZATIONS_HELP_6()} <OptionIcon type="deleted" isSet={true} />={LL.CUSTOMIZATIONS_HELP_6()}
</Typography> </Typography>
</Box>
<Grid <Grid
container container
mb={1}
mt={0}
spacing={2} spacing={2}
direction="row" direction="row"
justifyContent="flex-start" sx={{ mb: 1, mt: 0, justifyContent: 'flex-start', alignItems: 'center' }}
alignItems="center"
> >
<Grid> <Grid>
<TextField <TextField
@@ -779,8 +774,8 @@ const Customizations = () => {
</Button> </Button>
</MessageBox> </MessageBox>
) : ( ) : (
<Box display="flex" flexWrap="wrap"> <Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
<Box flexGrow={1}> <Box sx={{ flexGrow: 1 }}>
{numChanges !== 0 && ( {numChanges !== 0 && (
<ButtonRow> <ButtonRow>
<Button <Button

View File

@@ -37,7 +37,7 @@ interface LabelValueProps {
const LabelValue = memo(({ label, value }: LabelValueProps) => ( const LabelValue = memo(({ label, value }: LabelValueProps) => (
<Grid container direction="row"> <Grid container direction="row">
<Typography variant="body2" color="warning.main"> <Typography variant="body2" color="warning">
{label}:&nbsp; {label}:&nbsp;
</Typography> </Typography>
<Typography variant="body2">{value}</Typography> <Typography variant="body2">{value}</Typography>
@@ -131,7 +131,7 @@ const CustomizationsDialog = ({
/> />
<LabelValue label={LL.WRITEABLE()} value={writeableIcon} /> <LabelValue label={LL.WRITEABLE()} value={writeableIcon} />
<Box mt={1} mb={2}> <Box sx={{ mt: 1, mb: 2 }}>
<EntityMaskToggle onUpdate={updateDeviceEntity} de={editItem} /> <EntityMaskToggle onUpdate={updateDeviceEntity} de={editItem} />
</Box> </Box>
@@ -172,7 +172,7 @@ const CustomizationsDialog = ({
</Grid> </Grid>
{error && ( {error && (
<Typography variant="body2" color="error" mt={2}> <Typography sx={{ mt: 2 }} variant="body2" color="error">
Error: Check min and max values Error: Check min and max values
</Typography> </Typography>
)} )}

View File

@@ -6,7 +6,7 @@ import { toast } from 'react-toastify';
import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import EditIcon from '@mui/icons-material/Edit'; import EditIcon from '@mui/icons-material/Edit';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import HelpOutlineIcon from '@mui/icons-material/HelpOutlineOutlined'; import HelpOutlineIcon from '@mui/icons-material/HelpOutlined';
import UnfoldLessIcon from '@mui/icons-material/UnfoldLess'; import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore'; import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
import { import {
@@ -263,7 +263,7 @@ const Dashboard = memo(() => {
return ( return (
<> <>
{data.connected && data.nodes.length > 0 && !hasFavEntities && ( {data.connected && data.nodes.length > 0 && !hasFavEntities && (
<MessageBox mb={2} level="warning"> <MessageBox sx={{ mb: 2 }} level="warning">
<Typography> <Typography>
{LL.NO_DATA_1()}&nbsp; {LL.NO_DATA_1()}&nbsp;
<Link to="/customizations" style={{ color: 'white' }}> <Link to="/customizations" style={{ color: 'white' }}>
@@ -280,10 +280,12 @@ const Dashboard = memo(() => {
)} )}
<Box <Box
display="flex" sx={{
justifyContent="flex-end" display: 'flex',
flexWrap="nowrap" justifyContent: 'flex-end',
whiteSpace="nowrap" flexWrap: 'nowrap',
whiteSpace: 'nowrap'
}}
> >
<ToggleButtonGroup <ToggleButtonGroup
size="small" size="small"
@@ -306,7 +308,7 @@ const Dashboard = memo(() => {
</Box> </Box>
{data.nodes.length > 0 ? ( {data.nodes.length > 0 ? (
<Box mt={1} justifyContent="center" flexDirection="column"> <Box sx={{ mt: 1, justifyContent: 'center', flexDirection: 'column' }}>
<IconContext.Provider <IconContext.Provider
value={{ value={{
color: 'lightblue', color: 'lightblue',
@@ -373,14 +375,9 @@ const Dashboard = memo(() => {
</IconContext.Provider> </IconContext.Provider>
</Box> </Box>
) : ( ) : (
<Box <Box sx={{ display: 'flex' }}>
display="flex" <Typography sx={{ mt: 1 }} color="warning" variant="body1">
// justifyContent="flex-end" no data
// flexWrap="nowrap"
// whiteSpace="nowrap"
>
<Typography mt={1} color="warning.main" variant="body1">
{LL.NO_DATA()}
</Typography> </Typography>
<Tooltip title={LL.DASHBOARD_1()}> <Tooltip title={LL.DASHBOARD_1()}>
<HelpOutlineIcon <HelpOutlineIcon

View File

@@ -1,4 +1,5 @@
import { memo } from 'react'; import { memo } from 'react';
import type { IconType } from 'react-icons';
import { AiOutlineAlert, AiOutlineControl, AiOutlineGateway } from 'react-icons/ai'; import { AiOutlineAlert, AiOutlineControl, AiOutlineGateway } from 'react-icons/ai';
import { CgSmartHomeBoiler } from 'react-icons/cg'; import { CgSmartHomeBoiler } from 'react-icons/cg';
import { FaSolarPanel } from 'react-icons/fa'; import { FaSolarPanel } from 'react-icons/fa';
@@ -15,14 +16,9 @@ import { PiFan, PiGauge } from 'react-icons/pi';
import { TiFlowSwitch, TiThermometer } from 'react-icons/ti'; import { TiFlowSwitch, TiThermometer } from 'react-icons/ti';
import { VscVmConnect } from 'react-icons/vsc'; import { VscVmConnect } from 'react-icons/vsc';
import type { SvgIconProps } from '@mui/material';
import { DeviceType } from './types'; import { DeviceType } from './types';
const deviceIconLookup: Record< const deviceIconLookup: Record<DeviceType, IconType | null> = {
DeviceType,
React.ComponentType<SvgIconProps> | null
> = {
[DeviceType.TEMPERATURESENSOR]: TiThermometer, [DeviceType.TEMPERATURESENSOR]: TiThermometer,
[DeviceType.ANALOGSENSOR]: PiGauge, [DeviceType.ANALOGSENSOR]: PiGauge,
[DeviceType.BOILER]: CgSmartHomeBoiler, [DeviceType.BOILER]: CgSmartHomeBoiler,

View File

@@ -546,7 +546,7 @@ const Devices = memo(() => {
) )
</MessageBox> </MessageBox>
) : ( ) : (
<Box justifyContent="center" flexDirection="column"> <Box sx={{ justifyContent: 'center', flexDirection: 'column' }}>
<IconContext.Provider <IconContext.Provider
value={{ value={{
color: 'lightblue', color: 'lightblue',
@@ -670,12 +670,12 @@ const Devices = memo(() => {
}} }}
> >
<Box sx={{ p: 1 }}> <Box sx={{ p: 1 }}>
<Grid container justifyContent="space-between"> <Grid container sx={{ justifyContent: 'space-between' }}>
<Typography noWrap variant="subtitle1" color="warning.main"> <Typography noWrap variant="subtitle1" color="warning">
{deviceInfo.n}&nbsp;( {deviceInfo.n}&nbsp;(
{deviceInfo.tn}) {deviceInfo.tn})
</Typography> </Typography>
<Grid justifyContent="flex-end"> <Grid sx={{ justifyContent: 'flex-end' }}>
<ButtonTooltip title={LL.CLOSE()}> <ButtonTooltip title={LL.CLOSE()}>
<IconButton onClick={resetDeviceSelect} aria-label={LL.CLOSE()}> <IconButton onClick={resetDeviceSelect} aria-label={LL.CLOSE()}>
<HighlightOffIcon color="primary" sx={{ fontSize: 18 }} /> <HighlightOffIcon color="primary" sx={{ fontSize: 18 }} />

View File

@@ -128,9 +128,9 @@ const DevicesDialog = ({
<Dialog sx={dialogStyle} open={open} onClose={onClose}> <Dialog sx={dialogStyle} open={open} onClose={onClose}>
<DialogTitle>{dialogTitle}</DialogTitle> <DialogTitle>{dialogTitle}</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Box color="warning.main" mb={2}> <Typography sx={{ mb: 2 }} color="warning" variant="body2">
<Typography variant="body2">{editItem.id.slice(2)}</Typography> {editItem.id.slice(2)}
</Box> </Typography>
<Grid container> <Grid container>
<Grid size={12}> <Grid size={12}>
{editItem.l ? ( {editItem.l ? (

View File

@@ -71,7 +71,6 @@ const HelpComponent = () => {
}); });
const [imgError, setImgError] = useState<boolean>(false); const [imgError, setImgError] = useState<boolean>(false);
// Memoize the request method to prevent re-creation on every render
const getCustomSupportMethod = useMemo( const getCustomSupportMethod = useMemo(
() => callAction({ action: 'getCustomSupport' }), () => callAction({ action: 'getCustomSupport' }),
[] []
@@ -146,11 +145,9 @@ const HelpComponent = () => {
<SectionContent> <SectionContent>
{customSupport.html && ( {customSupport.html && (
<Stack <Stack
padding={1}
mb={2}
direction="row" direction="row"
divider={<Divider orientation="vertical" flexItem />} divider={<Divider orientation="vertical" flexItem />}
sx={SUPPORT_BOX_STYLES} sx={{ padding: 1, mb: 2, ...SUPPORT_BOX_STYLES }}
> >
<Typography variant="subtitle1"> <Typography variant="subtitle1">
<div dangerouslySetInnerHTML={{ __html: customSupport.html }} /> <div dangerouslySetInnerHTML={{ __html: customSupport.html }} />
@@ -185,8 +182,7 @@ const HelpComponent = () => {
</List> </List>
)} )}
<Box p={2} color="warning.main"> <Typography sx={{ mb: 1 }} color="warning" variant="body1">
<Typography mb={1} variant="body1">
{LL.HELP_INFORMATION_4()}. {LL.HELP_INFORMATION_4()}.
</Typography> </Typography>
<Button <Button
@@ -197,11 +193,10 @@ const HelpComponent = () => {
> >
{LL.SUPPORT_INFORMATION(0)} {LL.SUPPORT_INFORMATION(0)}
</Button> </Button>
</Box>
<Divider sx={{ mt: 4 }} /> <Divider sx={{ mt: 4 }} />
<Typography color="white" variant="subtitle1" align="center" mt={1}> <Typography color="white" variant="subtitle1" align="center" sx={{ mt: 1 }}>
&copy;&nbsp; &copy;&nbsp;
<Link <Link
target="_blank" target="_blank"

View File

@@ -186,9 +186,9 @@ const Modules = () => {
return ( return (
<> <>
<Box mb={2} color="warning.main"> <Typography sx={{ mb: 2 }} color="warning" variant="body1">
<Typography variant="body1">{LL.MODULES_DESCRIPTION()}.</Typography> {LL.MODULES_DESCRIPTION()}.
</Box> </Typography>
<Table <Table
data={{ nodes: modules }} data={{ nodes: modules }}
theme={modules_theme} theme={modules_theme}
@@ -236,8 +236,8 @@ const Modules = () => {
)} )}
</Table> </Table>
<Box mt={1} display="flex" flexWrap="wrap"> <Box sx={{ mt: 1, display: 'flex', flexWrap: 'wrap' }}>
<Box flexGrow={1}> <Box sx={{ flexGrow: 1 }}>
{numChanges !== 0 && ( {numChanges !== 0 && (
<ButtonRow> <ButtonRow>
<Button <Button

View File

@@ -79,7 +79,7 @@ const ModulesDialog = ({
label="Enabled" label="Enabled"
/> />
</Grid> </Grid>
<Box mt={2} mb={1}> <Box sx={{ mt: 2, mb: 1 }}>
<TextField <TextField
name="license" name="license"
label="License Key" label="License Key"

View File

@@ -2,12 +2,12 @@ import { memo } from 'react';
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined'; import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutlineOutlined'; import DeleteOutlineIcon from '@mui/icons-material/DeleteOutlined';
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined'; import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined'; import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
import StarIcon from '@mui/icons-material/Star'; import StarIcon from '@mui/icons-material/Star';
import StarOutlineIcon from '@mui/icons-material/StarOutlineOutlined'; import StarOutlineIcon from '@mui/icons-material/StarOutlined';
import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined'; import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
import type { SvgIconProps } from '@mui/material'; import type { SvgIconProps } from '@mui/material';

View File

@@ -358,9 +358,9 @@ const Scheduler = () => {
return ( return (
<SectionContent> <SectionContent>
{blocker ? <BlockNavigation blocker={blocker} /> : null} {blocker ? <BlockNavigation blocker={blocker} /> : null}
<Box mb={2} color="warning.main"> <Typography sx={{ mb: 2 }} color="warning" variant="body1">
<Typography variant="body1">{LL.SCHEDULER_HELP_1()}.</Typography> {LL.SCHEDULER_HELP_1()}.
</Box> </Typography>
{renderSchedule()} {renderSchedule()}
{selectedScheduleItem && ( {selectedScheduleItem && (
@@ -375,8 +375,8 @@ const Scheduler = () => {
/> />
)} )}
<Box display="flex" flexWrap="wrap"> <Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
<Box flexGrow={1}> <Box sx={{ flexGrow: 1 }}>
{numChanges !== 0 && ( {numChanges !== 0 && (
<ButtonRow> <ButtonRow>
<Button <Button
@@ -398,7 +398,7 @@ const Scheduler = () => {
</ButtonRow> </ButtonRow>
)} )}
</Box> </Box>
<Box flexWrap="nowrap" whiteSpace="nowrap"> <Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
<ButtonRow> <ButtonRow>
<Button <Button
startIcon={<AddIcon />} startIcon={<AddIcon />}

View File

@@ -4,7 +4,7 @@ import AddIcon from '@mui/icons-material/Add';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import DoneIcon from '@mui/icons-material/Done'; import DoneIcon from '@mui/icons-material/Done';
import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlineOutlined'; import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined';
import { import {
Box, Box,
Button, Button,
@@ -338,11 +338,13 @@ const SchedulerDialog = ({
onChange={updateFormValue} onChange={updateFormValue}
/> />
{isTimerSchedule && ( {isTimerSchedule && (
<Box color="warning.main" ml={2} mt={4}> <Typography
<Typography variant="body2"> sx={{ ml: 2, mt: 4 }}
color="warning"
variant="body2"
>
{LL.SCHEDULER_HELP_2()} {LL.SCHEDULER_HELP_2()}
</Typography> </Typography>
</Box>
)} )}
</> </>
) : ( ) : (
@@ -391,7 +393,7 @@ const SchedulerDialog = ({
<DialogActions> <DialogActions>
{!creating && ( {!creating && (
<Box flexGrow={1}> <Box sx={{ flexGrow: 1 }}>
<Button <Button
startIcon={<RemoveIcon />} startIcon={<RemoveIcon />}
variant="outlined" variant="outlined"

View File

@@ -591,7 +591,14 @@ const Sensors = () => {
/> />
)} )}
{sensorData?.analog_enabled === true && me.admin && ( {sensorData?.analog_enabled === true && me.admin && (
<Box mt={2} display="flex" flexWrap="wrap" justifyContent="flex-end"> <Box
sx={{
mt: 2,
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'flex-end'
}}
>
<Button <Button
variant="outlined" variant="outlined"
color="primary" color="primary"

View File

@@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import DoneIcon from '@mui/icons-material/Done'; import DoneIcon from '@mui/icons-material/Done';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutlineOutlined'; import RemoveIcon from '@mui/icons-material/RemoveCircleOutlined';
import WarningIcon from '@mui/icons-material/Warning'; import WarningIcon from '@mui/icons-material/Warning';
import { import {
Box, Box,
@@ -479,7 +479,7 @@ const SensorsAnalogDialog = ({
)} )}
</Grid> </Grid>
{fieldErrors && Object.keys(fieldErrors).length > 0 && ( {fieldErrors && Object.keys(fieldErrors).length > 0 && (
<Box mt={1}> <Box sx={{ mt: 1 }}>
{Object.values(fieldErrors).map((errArr, idx) => {Object.values(fieldErrors).map((errArr, idx) =>
Array.isArray(errArr) Array.isArray(errArr)
? errArr.map((err, j) => ( ? errArr.map((err, j) => (
@@ -487,7 +487,7 @@ const SensorsAnalogDialog = ({
key={`${idx}-${j}`} key={`${idx}-${j}`}
color="error" color="error"
variant="caption" variant="caption"
display="block" sx={{ display: 'block' }}
> >
{err.message} {err.message}
</Typography> </Typography>
@@ -498,7 +498,7 @@ const SensorsAnalogDialog = ({
)} )}
{editItem.s && ( {editItem.s && (
<Grid> <Grid>
<Typography mt={1} color="warning.main" variant="body2"> <Typography sx={{ mt: 1 }} color="warning" variant="body2">
<WarningIcon <WarningIcon
fontSize="small" fontSize="small"
sx={{ mr: 1, verticalAlign: 'middle' }} sx={{ mr: 1, verticalAlign: 'middle' }}
@@ -511,7 +511,7 @@ const SensorsAnalogDialog = ({
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
{!creating && ( {!creating && (
<Box flexGrow={1} sx={{ '& button': { mt: 0 } }}> <Box sx={{ flexGrow: 1, '& button': { mt: 0 } }}>
<Button <Button
startIcon={<RemoveIcon />} startIcon={<RemoveIcon />}
disabled={editItem.s} disabled={editItem.s}

View File

@@ -4,7 +4,6 @@ import CancelIcon from '@mui/icons-material/Cancel';
import DoneIcon from '@mui/icons-material/Done'; import DoneIcon from '@mui/icons-material/Done';
import WarningIcon from '@mui/icons-material/Warning'; import WarningIcon from '@mui/icons-material/Warning';
import { import {
Box,
Button, Button,
Dialog, Dialog,
DialogActions, DialogActions,
@@ -111,11 +110,9 @@ const SensorsTemperatureDialog = ({
<Dialog sx={dialogStyle} open={open} onClose={handleClose}> <Dialog sx={dialogStyle} open={open} onClose={handleClose}>
<DialogTitle>{dialogTitle}</DialogTitle> <DialogTitle>{dialogTitle}</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Box color="warning.main" mb={2}> <Typography sx={{ mb: 2 }} color="warning" variant="body2">
<Typography variant="body2">
{LL.ID_OF(LL.SENSOR(0))}: {editItem.id} {LL.ID_OF(LL.SENSOR(0))}: {editItem.id}
</Typography> </Typography>
</Box>
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid> <Grid>
<ValidatedTextField <ValidatedTextField
@@ -142,7 +139,7 @@ const SensorsTemperatureDialog = ({
</Grid> </Grid>
{editItem.s && ( {editItem.s && (
<Grid> <Grid>
<Typography mt={1} color="warning.main" variant="body2"> <Typography sx={{ mt: 1 }} color="warning" variant="body2">
<WarningIcon <WarningIcon
fontSize="small" fontSize="small"
sx={{ mr: 1, verticalAlign: 'middle' }} sx={{ mr: 1, verticalAlign: 'middle' }}

View File

@@ -41,8 +41,12 @@ const UserProfileComponent = () => {
/> />
</ListItem> </ListItem>
</List> </List>
<Box mt={2} mb={2} display="flex" alignItems="center"> <Box sx={{ mt: 2, mb: 2, display: 'flex', alignItems: 'center' }}>
<Typography mr={2} variant="body1" align="center"> <Typography
sx={{ mr: 2, textAlign: 'center' }}
color="warning"
variant="body1"
>
{LL.LANGUAGE()}: {LL.LANGUAGE()}:
</Typography> </Typography>
<LanguageSelector /> <LanguageSelector />

View File

@@ -771,7 +771,7 @@ const ApplicationSettings = () => {
label={LL.REMOTE_TIMEOUT_EN()} label={LL.REMOTE_TIMEOUT_EN()}
/> />
{data.remote_timeout_en && ( {data.remote_timeout_en && (
<Box mt={2}> <Box sx={{ mt: 2 }}>
<ValidatedTextField <ValidatedTextField
fieldErrors={fieldErrors || {}} fieldErrors={fieldErrors || {}}
name="remote_timeout" name="remote_timeout"

View File

@@ -1,12 +1,23 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import CancelIcon from '@mui/icons-material/Cancel';
import DownloadIcon from '@mui/icons-material/GetApp'; import DownloadIcon from '@mui/icons-material/GetApp';
import { Box, Button, Grid, Typography } from '@mui/material'; import WarningIcon from '@mui/icons-material/Warning';
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Grid,
Typography
} from '@mui/material';
import * as SystemApi from 'api/system'; import * as SystemApi from 'api/system';
import { API, callAction } from 'api/app'; import { API, callAction } from 'api/app';
import { dialogStyle } from '@/CustomTheme';
import { useRequest } from 'alova/client'; import { useRequest } from 'alova/client';
import type { APIcall } from 'app/main/types'; import type { APIcall } from 'app/main/types';
import SystemMonitor from 'app/status/SystemMonitor'; import SystemMonitor from 'app/status/SystemMonitor';
@@ -19,15 +30,11 @@ import {
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import { saveFile } from 'utils'; import { saveFile } from 'utils';
interface DownloadButton {
type: string;
label: string | number;
isGridButton: boolean;
}
const DownloadUpload = () => { const DownloadUpload = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [confirmBackup, setConfirmBackup] = useState<boolean>(false);
const [restarting, setRestarting] = useState<boolean>(false); const [restarting, setRestarting] = useState<boolean>(false);
const { send: sendExportData } = useRequest( const { send: sendExportData } = useRequest(
@@ -62,40 +69,44 @@ const DownloadUpload = () => {
useLayoutTitle(LL.DOWNLOAD_UPLOAD()); useLayoutTitle(LL.DOWNLOAD_UPLOAD());
const downloadButtons: DownloadButton[] = useMemo( const handleCloseBackupDialog = useCallback(() => {
() => [ setConfirmBackup(false);
{ }, []);
type: 'settings',
label: LL.SETTINGS_OF(LL.APPLICATION()), const renderBackupDialog = useMemo(
isGridButton: true () => (
}, <Dialog
{ sx={dialogStyle}
type: 'customizations', open={confirmBackup}
label: LL.CUSTOMIZATIONS(), onClose={handleCloseBackupDialog}
isGridButton: true >
}, <DialogTitle>{LL.DOWNLOAD_SYSTEM_BACKUP()}</DialogTitle>
{ <DialogContent dividers>
type: 'entities', <WarningIcon color="warning" sx={{ fontSize: 18 }} />
label: LL.CUSTOM_ENTITIES(0), &nbsp;
isGridButton: true {LL.WARNING_SYSTEM_BACKUP()}
}, </DialogContent>
{ <DialogActions>
type: 'schedule', <Button
label: LL.SCHEDULE(0), startIcon={<CancelIcon />}
isGridButton: true variant="outlined"
}, onClick={handleCloseBackupDialog}
{ color="secondary"
type: 'systembackup', >
label: LL.DOWNLOAD_SYSTEM_BACKUP(), {LL.CANCEL()}
isGridButton: true </Button>
}, <Button
{ startIcon={<DownloadIcon />}
type: 'allvalues', variant="outlined"
label: LL.ALLVALUES(), onClick={() => handleDownload('systembackup')()}
isGridButton: false color="primary"
} >
], {LL.DOWNLOAD(0)}
[LL] </Button>
</DialogActions>
</Dialog>
),
[confirmBackup, handleCloseBackupDialog, LL]
); );
const handleDownload = useCallback( const handleDownload = useCallback(
@@ -117,58 +128,57 @@ const DownloadUpload = () => {
); );
} }
const gridButtons = downloadButtons.filter((btn) => btn.isGridButton);
const standaloneButton = downloadButtons.find((btn) => !btn.isGridButton);
return ( return (
<SectionContent> <SectionContent>
{renderBackupDialog}
<Typography sx={{ pb: 2 }} variant="h6" color="primary"> <Typography sx={{ pb: 2 }} variant="h6" color="primary">
{LL.DOWNLOAD(0)} {LL.DOWNLOAD(0)}
</Typography> </Typography>
<Typography mb={1} variant="body1" color="warning"> <Grid
{LL.DOWNLOAD_SETTINGS_TEXT()}. container
spacing={2}
sx={{
alignItems: 'center'
}}
>
<Typography variant="body1" color="warning">
{LL.DOWNLOAD_SETTINGS_TEXT()}:
</Typography> </Typography>
<Grid container spacing={2}>
{gridButtons.map((button) => (
<Grid key={button.type}>
<Button <Button
startIcon={<DownloadIcon />} startIcon={<DownloadIcon />}
variant="outlined" variant="outlined"
color="primary" color="primary"
onClick={handleDownload(button.type)} onClick={() => setConfirmBackup(true)}
> >
{button.label} {LL.DOWNLOAD_SYSTEM_BACKUP()}
</Button> </Button>
</Grid> </Grid>
))}
</Grid>
<Typography mt={2} mb={1} variant="body1" color="warning"> <Grid container spacing={2} sx={{ mt: 2, alignItems: 'center' }}>
{LL.DOWNLOAD_SETTINGS_TEXT2()}. <Typography variant="body1" color="warning">
{LL.DOWNLOAD_SETTINGS_TEXT2()}:
</Typography> </Typography>
{standaloneButton && (
<Button <Button
startIcon={<DownloadIcon />} startIcon={<DownloadIcon />}
variant="outlined" variant="outlined"
color="primary" color="primary"
onClick={handleDownload(standaloneButton.type)} onClick={handleDownload('allvalues')}
> >
{standaloneButton.label} {LL.ALLVALUES()}
</Button> </Button>
)} </Grid>
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary"> <Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
{LL.UPLOAD()} {LL.UPLOAD()}
</Typography> </Typography>
<Box color="warning.main" sx={{ pb: 2 }}> <Typography sx={{ pb: 2 }} color="warning" variant="body1">
<Typography variant="body1">{LL.UPLOAD_TEXT()}.</Typography> {LL.UPLOAD_TEXT()}:
</Box> </Typography>
<SingleUpload text={LL.UPLOAD_DRAG()} doRestart={doRestart} /> <SingleUpload doRestart={doRestart} />
</SectionContent> </SectionContent>
); );
}; };

View File

@@ -129,7 +129,7 @@ const MqttSettings = () => {
<SectionContent> <SectionContent>
{blocker ? <BlockNavigation blocker={blocker} /> : null} {blocker ? <BlockNavigation blocker={blocker} /> : null}
<> <>
<Box display="flex" gap={2} mb={1}> <Box sx={{ display: 'flex', gap: 2, mb: 1 }}>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox

View File

@@ -193,9 +193,9 @@ const NTPSettings = () => {
{timeZoneItems} {timeZoneItems}
</ValidatedTextField> </ValidatedTextField>
<Box display="flex" flexWrap="wrap"> <Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
{!data.enabled && !dirtyFlags.length && ( {!data.enabled && !dirtyFlags.length && (
<Box flexWrap="nowrap" whiteSpace="nowrap"> <Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
<ButtonRow> <ButtonRow>
<Button <Button
onClick={openSetTime} onClick={openSetTime}
@@ -259,9 +259,9 @@ const NTPSettings = () => {
<Dialog sx={dialogStyle} open={settingTime} onClose={handleCloseSetTime}> <Dialog sx={dialogStyle} open={settingTime} onClose={handleCloseSetTime}>
<DialogTitle>{LL.SET_TIME(1)}</DialogTitle> <DialogTitle>{LL.SET_TIME(1)}</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Box color="warning.main" p={0} pl={0} pr={0} mt={0} mb={2}> <Typography color="warning" variant="body2">
<Typography variant="body2">{LL.SET_TIME_TEXT()}</Typography> {LL.SET_TIME_TEXT()}
</Box> </Typography>
<TextField <TextField
label={LL.LOCAL_TIME(0)} label={LL.LOCAL_TIME(0)}
type="datetime-local" type="datetime-local"

View File

@@ -156,11 +156,13 @@ const Settings = () => {
<Divider /> <Divider />
<Box <Box
mt={2} sx={{
display="flex" mt: 2,
justifyContent="flex-end" display: 'flex',
flexWrap="nowrap" justifyContent: 'flex-end',
whiteSpace="nowrap" flexWrap: 'nowrap',
whiteSpace: 'nowrap'
}}
> >
<Button <Button
startIcon={<SettingsBackupRestoreIcon />} startIcon={<SettingsBackupRestoreIcon />}

View File

@@ -54,19 +54,27 @@ const GenerateToken = ({ username, onClose }: GenerateTokenProps) => {
<DialogContent dividers> <DialogContent dividers>
{token ? ( {token ? (
<> <>
<MessageBox message={LL.ACCESS_TOKEN_TEXT()} level="info" my={2} /> <MessageBox
<Box mt={2} mb={2}> message={LL.ACCESS_TOKEN_TEXT()}
level="info"
sx={{ mt: 2, mb: 2 }}
/>
<Box sx={{ mt: 2, mb: 2 }}>
<TextField <TextField
label="Token" label="Token"
multiline multiline
value={token.token} value={token.token}
fullWidth fullWidth
contentEditable={false} slotProps={{
input: {
readOnly: true
}
}}
/> />
</Box> </Box>
</> </>
) : ( ) : (
<Box m={4} textAlign="center"> <Box sx={{ m: 4, textAlign: 'center' }}>
<LinearProgress /> <LinearProgress />
<Typography variant="h6">{LL.GENERATING_TOKEN()}&hellip;</Typography> <Typography variant="h6">{LL.GENERATING_TOKEN()}&hellip;</Typography>
</Box> </Box>

View File

@@ -240,12 +240,16 @@ const ManageUsers = () => {
</Table> </Table>
{noAdminConfigured() && ( {noAdminConfigured() && (
<MessageBox level="warning" message={LL.USER_WARNING()} my={2} /> <MessageBox
level="warning"
message={LL.USER_WARNING()}
sx={{ mt: 2, mb: 2 }}
/>
)} )}
<Box display="flex" flexWrap="wrap"> <Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
{changed !== 0 && ( {changed !== 0 && (
<Box flexGrow={1} sx={{ '& button': { mt: 2 } }}> <Box sx={{ flexGrow: 1, '& button': { mt: 2 } }}>
<ButtonRow> <ButtonRow>
<Button <Button
startIcon={<CancelIcon />} startIcon={<CancelIcon />}
@@ -270,7 +274,7 @@ const ManageUsers = () => {
</ButtonRow> </ButtonRow>
</Box> </Box>
)} )}
<Box flexWrap="nowrap" whiteSpace="nowrap"> <Box sx={{ flexWrap: 'nowrap', whiteSpace: 'nowrap' }}>
<ButtonRow> <ButtonRow>
<Button <Button
startIcon={<PersonAddIcon />} startIcon={<PersonAddIcon />}

View File

@@ -266,7 +266,7 @@ const SystemLog = () => {
return ( return (
<> <>
<Grid container spacing={2} alignItems="center"> <Grid container spacing={2} sx={{ alignItems: 'center' }}>
<Grid> <Grid>
<TextField <TextField
name="level" name="level"

View File

@@ -118,17 +118,15 @@ const SystemMonitor = () => {
p: 3 p: 3
}} }}
> >
<Box display="flex" alignItems="center" flexDirection="column"> <Box sx={{ display: 'flex', alignItems: 'center', flexDirection: 'column' }}>
<img <img
src="/app/icon.png" src="/app/icon.png"
alt="EMS-ESP" alt="EMS-ESP"
style={{ width: '40px', height: '40px', marginBottom: '16px' }} style={{ width: '40px', height: '40px', marginBottom: '16px' }}
/> />
<Typography <Typography
color="secondary" sx={{ color: 'secondary', fontWeight: 400, textAlign: 'center' }}
variant="h6" variant="h6"
fontWeight={400}
textAlign="center"
> >
{statusMessage} {statusMessage}
</Typography> </Typography>
@@ -148,11 +146,14 @@ const SystemMonitor = () => {
</MessageBox> </MessageBox>
) : ( ) : (
<> <>
<Typography mt={2} variant="h6" fontWeight={400} textAlign="center"> <Typography
sx={{ mt: 2, fontWeight: 400, textAlign: 'center' }}
variant="h6"
>
{LL.PLEASE_WAIT()}&hellip; {LL.PLEASE_WAIT()}&hellip;
</Typography> </Typography>
{isUploading && ( {isUploading && (
<Box width="100%" pl={2} pr={2} py={2}> <Box sx={{ width: '100%', pl: 2, pr: 2, py: 2 }}>
<LinearProgressWithLabel value={progressValue} /> <LinearProgressWithLabel value={progressValue} />
</Box> </Box>
)} )}

View File

@@ -307,7 +307,7 @@ const InstallDialog = memo(
{`${LL.INSTALL()} ${fetchDevVersion ? LL.DEVELOPMENT() : LL.STABLE()} Firmware`} {`${LL.INSTALL()} ${fetchDevVersion ? LL.DEVELOPMENT() : LL.STABLE()} Firmware`}
</DialogTitle> </DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Typography mb={2}> <Typography sx={{ mb: 2 }}>
{LL.INSTALL_VERSION( {LL.INSTALL_VERSION(
downloadOnly ? LL.DOWNLOAD(1) : LL.INSTALL(), downloadOnly ? LL.DOWNLOAD(1) : LL.INSTALL(),
fetchDevVersion ? latestDevVersion?.name : latestVersion?.name fetchDevVersion ? latestDevVersion?.name : latestVersion?.name
@@ -371,7 +371,9 @@ const InstallPartitionDialog = memo(
{LL.INSTALL()} {LL.STORED_VERSIONS()} {LL.INSTALL()} {LL.STORED_VERSIONS()}
</DialogTitle> </DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<Typography mb={2}>{LL.INSTALL_VERSION(LL.INSTALL(), version)}</Typography> <Typography sx={{ mb: 2 }}>
{LL.INSTALL_VERSION(LL.INSTALL(), version)}
</Typography>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button <Button
@@ -637,8 +639,8 @@ const Version = () => {
return ( return (
<> <>
<Box p={2} border="1px solid grey" borderRadius={2}> <Box sx={{ p: 2, border: '1px solid #565656', borderRadius: 2 }}>
<Typography mb={1} variant="h6" color="primary"> <Typography sx={{ mb: 1 }} variant="h6" color="primary">
{LL.THIS_VERSION()} {LL.THIS_VERSION()}
</Typography> </Typography>
@@ -703,7 +705,7 @@ const Version = () => {
{internetLive ? ( {internetLive ? (
<> <>
<Typography mt={4} mb={1} variant="h6" color="primary"> <Typography sx={{ mt: 4, mb: 1 }} variant="h6" color="primary">
{LL.AVAILABLE_VERSION()} {LL.AVAILABLE_VERSION()}
</Typography> </Typography>
@@ -725,7 +727,7 @@ const Version = () => {
</Grid> </Grid>
<Grid size={{ xs: 8, md: 10 }}> <Grid size={{ xs: 8, md: 10 }}>
{otherPartitions.map((partition) => ( {otherPartitions.map((partition) => (
<Typography key={partition.partition} mb={1}> <Typography key={partition.partition} sx={{ mb: 1 }}>
{partition.version} {partition.version}
<IconButton <IconButton
onClick={() => onClick={() =>
@@ -791,7 +793,7 @@ const Version = () => {
</Grid> </Grid>
</> </>
) : ( ) : (
<Typography mt={2} color="warning"> <Typography sx={{ mt: 2 }} color="warning">
<WarningIcon color="warning" sx={{ verticalAlign: 'middle', mr: 2 }} /> <WarningIcon color="warning" sx={{ verticalAlign: 'middle', mr: 2 }} />
{LL.INTERNET_CONNECTION_REQUIRED()} {LL.INTERNET_CONNECTION_REQUIRED()}
</Typography> </Typography>
@@ -832,7 +834,7 @@ const Version = () => {
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary"> <Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
{LL.UPLOAD()} {LL.UPLOAD()}
</Typography> </Typography>
<SingleUpload text={LL.UPLOAD_DROP_TEXT()} doRestart={doRestart} /> <SingleUpload doRestart={doRestart} />
</> </>
)} )}
</Box> </Box>

View File

@@ -53,12 +53,16 @@ const MessageBox: FC<PropsWithChildren<MessageBoxProps>> = ({
return ( return (
<Box <Box
p={2}
display="flex"
alignItems="center"
borderRadius={1}
sx={{ backgroundColor, color: 'white', ...sx }}
{...rest} {...rest}
sx={{
display: 'flex',
alignItems: 'center',
borderRadius: 1,
backgroundColor,
color: 'white',
p: 2,
...sx
}}
> >
<Icon /> <Icon />
{(message || children) && ( {(message || children) && (

View File

@@ -29,7 +29,7 @@ const LayoutDrawerComponent = ({ mobileOpen, onClose }: LayoutDrawerProps) => {
() => ( () => (
<> <>
<Toolbar disableGutters> <Toolbar disableGutters>
<Box display="flex" alignItems="center" px={2}> <Box sx={{ display: 'flex', alignItems: 'center', p: 2 }}>
<LayoutDrawerLogo src="/app/icon.png" alt={PROJECT_NAME} /> <LayoutDrawerLogo src="/app/icon.png" alt={PROJECT_NAME} />
<Typography variant="h6">{PROJECT_NAME}</Typography> <Typography variant="h6">{PROJECT_NAME}</Typography>
</Box> </Box>

View File

@@ -51,9 +51,7 @@ const LayoutMenuComponent = () => {
sx={{ my: 0 }} sx={{ my: 0 }}
slotProps={{ slotProps={{
primary: { primary: {
fontWeight: '600', sx: { fontWeight: 600, mb: '2px', color: 'lightblue' }
mb: '2px',
color: 'lightblue'
} }
}} }}
/> />

View File

@@ -32,8 +32,16 @@ const FormLoaderComponent = ({ errorMessage, onRetry }: FormLoaderProps) => {
); );
} }
return ( return (
<Box m={2} py={2} display="flex" alignItems="center" flexDirection="column"> <Box
<Box py={2}> sx={{
m: 2,
py: 2,
display: 'flex',
alignItems: 'center',
flexDirection: 'column'
}}
>
<Box sx={{ p: 2 }}>
<CircularProgress size={100} /> <CircularProgress size={100} />
</Box> </Box>
</Box> </Box>

View File

@@ -15,12 +15,14 @@ const circularProgressStyles: SxProps<Theme> = (theme: Theme) => ({
const LoadingSpinner = ({ height = '100%' }: LoadingSpinnerProps) => { const LoadingSpinner = ({ height = '100%' }: LoadingSpinnerProps) => {
return ( return (
<Box <Box
display="flex" sx={{
alignItems="center" display: 'flex',
justifyContent="center" alignItems: 'center',
flexDirection="column" justifyContent: 'center',
padding={2} flexDirection: 'column',
height={height} padding: 2,
height
}}
> >
<CircularProgress sx={circularProgressStyles} size={100} /> <CircularProgress sx={circularProgressStyles} size={100} />
</Box> </Box>

View File

@@ -1,4 +1,4 @@
// Code inspired by Prince Azubuike from https://medium.com/@dprincecoder/creating-a-drag-and-drop-file-upload-component-in-react-a-step-by-step-guide-4d93b6cc21e0 // drag/drop code inspired by Prince Azubuike from https://medium.com/@dprincecoder/creating-a-drag-and-drop-file-upload-component-in-react-a-step-by-step-guide-4d93b6cc21e0
import { import {
type ChangeEvent, type ChangeEvent,
type DragEvent, type DragEvent,
@@ -6,12 +6,27 @@ import {
useRef, useRef,
useState useState
} from 'react'; } from 'react';
import { toast } from 'react-toastify';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import CloudUploadIcon from '@mui/icons-material/CloudUpload'; import CloudUploadIcon from '@mui/icons-material/CloudUpload';
import UploadIcon from '@mui/icons-material/Upload'; import UploadIcon from '@mui/icons-material/Upload';
import { Box, Button, Typography, styled } from '@mui/material'; import WarningIcon from '@mui/icons-material/Warning';
import {
Box,
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Typography,
styled
} from '@mui/material';
import { callAction } from 'api/app';
import { dialogStyle } from '@/CustomTheme';
import { useRequest } from 'alova/client';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
const DocumentUploader = styled(Box)<{ active?: boolean }>(({ theme, active }) => ({ const DocumentUploader = styled(Box)<{ active?: boolean }>(({ theme, active }) => ({
@@ -58,6 +73,23 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
const [dragged, setDragged] = useState(false); const [dragged, setDragged] = useState(false);
const inputRef = useRef<HTMLInputElement | null>(null); const inputRef = useRef<HTMLInputElement | null>(null);
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [showUpgradeDialog, setShowUpgradeDialog] = useState(false);
const [upgradeImportantMessageType, setUpgradeImportantMessageType] =
useState<number>(0);
const { send: checkUpgradeImportantMessages } = useRequest(
(type: string) =>
callAction({ action: 'upgradeImportantMessages', param: type }),
{
immediate: false
}
)
.onSuccess((event: { data: number }) => {
setUpgradeImportantMessageType(event.data);
})
.onError((error: { error?: { message?: string } }) => {
toast.error(String(error.error?.message || 'An error occurred'));
});
const checkFileExtension = (file: File) => { const checkFileExtension = (file: File) => {
const validExtensions = ['.json', '.bin', '.md5']; const validExtensions = ['.json', '.bin', '.md5'];
@@ -97,9 +129,8 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
const handleUploadClick = (event: MouseEvent<HTMLButtonElement>) => { const handleUploadClick = (event: MouseEvent<HTMLButtonElement>) => {
event.stopPropagation(); event.stopPropagation();
if (file) { void checkUpgradeImportantMessages(file?.name || '');
onFileSelected(file); setShowUpgradeDialog(true);
}
}; };
const handleBrowseClick = () => { const handleBrowseClick = () => {
@@ -158,6 +189,46 @@ const DragNdrop = ({ text, onFileSelected }: DragNdropProps) => {
{LL.UPLOAD()} {LL.UPLOAD()}
</Button> </Button>
</Box> </Box>
{showUpgradeDialog && (
<Dialog
sx={dialogStyle}
open={showUpgradeDialog}
onClose={() => setShowUpgradeDialog(false)}
>
<DialogTitle>
<WarningIcon
color="warning"
sx={{ fontSize: 18, verticalAlign: 'middle' }}
/>
&nbsp;&nbsp;
{LL.UPGRADE_IMPORTANT_MESSAGES()}
</DialogTitle>
<DialogContent dividers>
{upgradeImportantMessageType === 1 &&
LL.UPGRADE_IMPORTANT_MESSAGES_1()}
{upgradeImportantMessageType === 2 &&
LL.UPGRADE_IMPORTANT_MESSAGES_2()}
</DialogContent>
<DialogActions>
<Button
startIcon={<CancelIcon />}
variant="outlined"
onClick={() => setShowUpgradeDialog(false)}
color="secondary"
>
{LL.CANCEL()}
</Button>
<Button
startIcon={<UploadIcon />}
variant="outlined"
onClick={() => onFileSelected(file)}
color="primary"
>
{LL.UPLOAD()}
</Button>
</DialogActions>
</Dialog>
)}
</> </>
)} )}
</DocumentUploader> </DocumentUploader>

View File

@@ -13,11 +13,10 @@ import DragNdrop from './DragNdrop';
import { LinearProgressWithLabel } from './LinearProgressWithLabel'; import { LinearProgressWithLabel } from './LinearProgressWithLabel';
interface SingleUploadProps { interface SingleUploadProps {
text: string;
doRestart: () => void; doRestart: () => void;
} }
const SingleUpload = ({ text, doRestart }: SingleUploadProps) => { const SingleUpload = ({ doRestart }: SingleUploadProps) => {
const [md5, setMd5] = useState<string>(); const [md5, setMd5] = useState<string>();
const [file, setFile] = useState<File>(); const [file, setFile] = useState<File>();
const { LL } = useI18nContext(); const { LL } = useI18nContext();
@@ -58,7 +57,7 @@ const SingleUpload = ({ text, doRestart }: SingleUploadProps) => {
<> <>
{isUploading ? ( {isUploading ? (
<> <>
<Box width="100%" pl={2} pr={2}> <Box sx={{ width: '100%', pl: 2, pr: 2 }}>
<LinearProgressWithLabel <LinearProgressWithLabel
value={ value={
progress.total === 0 || progress.loaded === 0 progress.total === 0 || progress.loaded === 0
@@ -81,11 +80,11 @@ const SingleUpload = ({ text, doRestart }: SingleUploadProps) => {
</Button> </Button>
</> </>
) : ( ) : (
<DragNdrop text={text} onFileSelected={setFile} /> <DragNdrop text={LL.UPLOAD_DROP_TEXT()} onFileSelected={setFile} />
)} )}
{md5 && ( {md5 && (
<Box mt={2}> <Box sx={{ mt: 2 }}>
<Typography variant="body2">{'MD5: ' + md5}</Typography> <Typography variant="body2">{'MD5: ' + md5}</Typography>
</Box> </Box>
)} )}

View File

@@ -188,8 +188,12 @@ const cz: Translation = {
DOWNLOAD_SETTINGS_TEXT: 'Vytvořte zálohu svého nastavení a konfigurace', DOWNLOAD_SETTINGS_TEXT: 'Vytvořte zálohu svého nastavení a konfigurace',
DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechny hodnoty', DOWNLOAD_SETTINGS_TEXT2: 'Exportovat všechny hodnoty',
DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha', DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha',
WARNING_SYSTEM_BACKUP: 'Toto vytvoří zálohu vašich nastavení a konfigurace. Všechna hesla budou v zálohovém souboru čitelná. Opravdu chcete pokračovat?',
UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)', UPLOAD_TEXT: 'Nahrajte nový soubor firmwaru (.bin) nebo záložní soubor (.json)',
UPLOAD_DROP_TEXT: 'Přetáhněte soubor sem nebo klikněte pro výběr', UPLOAD_DROP_TEXT: 'Přetáhněte soubor sem nebo klikněte pro výběr',
UPGRADE_IMPORTANT_MESSAGES: 'Důležité zprávy pro aktualizaci',
UPGRADE_IMPORTANT_MESSAGES_1: 'Aktualizujete se z hlavní verze. Vezměte prosím na vědomí, že to může způsobit problémy s vaší konfigurací.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujete se z dílčí verze. Vezměte prosím na vědomí, že to může způsobit problémy s vaší konfigurací.',
ERROR: 'Neočekávaná chyba, zkuste to prosím znovu', ERROR: 'Neočekávaná chyba, zkuste to prosím znovu',
TIME_SET: 'Čas nastaven', TIME_SET: 'Čas nastaven',
MANAGE_USERS: 'Spravovat uživatele', MANAGE_USERS: 'Spravovat uživatele',
@@ -347,18 +351,17 @@ const cz: Translation = {
BITMASK: 'Bit Mask', BITMASK: 'Bit Mask',
DUPLICATE: 'Duplikát', DUPLICATE: 'Duplikát',
DASHBOARD_1: 'Všechny aktivní entity EMS jsou označené jako oblíbené. Všechny vlastní entity, harmonogramy a externí sensory jsou zobrazeny níže.', DASHBOARD_1: 'Všechny aktivní entity EMS jsou označené jako oblíbené. Všechny vlastní entity, harmonogramy a externí sensory jsou zobrazeny níže.',
NO_DATA: 'No data', NO_DATA: 'žádné údaje',
NO_DATA_1: 'Nebyly nalezeny žádné oblíbené entity. Použijte modul', NO_DATA_1: 'Nebyly nalezeny žádné oblíbené entity. Použijte modul',
NO_DATA_2: 'pro jejich výběr.', NO_DATA_2: 'pro jejich výběr.',
NO_DATA_3: 'Pro zobrazení všech dostupných entit navštivte stránku', NO_DATA_3: 'Pro zobrazení všech dostupných entit navštivte stránku',
NO_GPIO:'No available GPIO found', NO_GPIO:'Nebylo nalezeno žádné volné GPIO',
THIS_VERSION: 'Tato verze', THIS_VERSION: 'Tato verze',
PLATFORM: 'Platforma', PLATFORM: 'Platforma',
RELEASE_TYPE: 'Typ sestavení', RELEASE_TYPE: 'Typ sestavení',
INTERNET_CONNECTION_REQUIRED: 'Pro automatickou kontrolu a instalaci aktualizací je třeba internetové připojení', INTERNET_CONNECTION_REQUIRED: 'Pro automatickou kontrolu a instalaci aktualizací je třeba internetové připojení',
SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi', SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi',
FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru', FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru',
NO_DATA: 'Žádná data',
USER_PROFILE: 'Uživatelský profil', USER_PROFILE: 'Uživatelský profil',
STORED_VERSIONS: 'Uložené verze', STORED_VERSIONS: 'Uložené verze',
ONLINE_HELP: 'online nápověda' ONLINE_HELP: 'online nápověda'

View File

@@ -188,8 +188,12 @@ const de: Translation = {
DOWNLOAD_SETTINGS_TEXT: 'Erstellen Sie eine Sicherung Ihrer Konfigurationen und Einstellungen', DOWNLOAD_SETTINGS_TEXT: 'Erstellen Sie eine Sicherung Ihrer Konfigurationen und Einstellungen',
DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Werte', DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Werte',
DOWNLOAD_SYSTEM_BACKUP: 'System Sicherung', DOWNLOAD_SYSTEM_BACKUP: 'System Sicherung',
WARNING_SYSTEM_BACKUP: 'Dies wird eine Sicherung Ihrer Konfigurationen und Einstellungen erstellen. Alle Passwörter werden im Sicherungsdatei lesbar. Möchten Sie fortfahren?',
UPLOAD_TEXT: 'Laden Sie eine neue Firmware-Datei (.bin) oder eine Sicherungsdatei (.json) hoch', UPLOAD_TEXT: 'Laden Sie eine neue Firmware-Datei (.bin) oder eine Sicherungsdatei (.json) hoch',
UPLOAD_DROP_TEXT: 'Legen Sie eine Firmware-Datei (.bin) ab oder klicken Sie hier', UPLOAD_DROP_TEXT: 'Legen Sie eine Firmware-Datei (.bin) ab oder klicken Sie hier',
UPGRADE_IMPORTANT_MESSAGES: 'Wichtige Nachrichten für das Upgrade',
UPGRADE_IMPORTANT_MESSAGES_1: 'Sie sind von einer Major-Version auf eine neue Version aktualisiert. Bitte beachten Sie, dass dies zu Problemen mit Ihrer Konfiguration führen kann.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Sie sind von einer Minor-Version auf eine neue Version aktualisiert. Bitte beachten Sie, dass dies zu Problemen mit Ihrer Konfiguration führen kann.',
ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut.', ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut.',
TIME_SET: 'Zeit gesetzt', TIME_SET: 'Zeit gesetzt',
MANAGE_USERS: 'Nutzerverwaltung', MANAGE_USERS: 'Nutzerverwaltung',
@@ -347,7 +351,6 @@ const de: Translation = {
BITMASK: 'Bit Maske', BITMASK: 'Bit Maske',
DUPLICATE: 'Kopieren', DUPLICATE: 'Kopieren',
DASHBOARD_1: 'Alle EMS-Entitäten, die aktiv und als Favorit markiert sind, sowie alle benutzerdefinierten Entitäten, Zeitpläne und externen Sensordaten werden unten angezeigt.', DASHBOARD_1: 'Alle EMS-Entitäten, die aktiv und als Favorit markiert sind, sowie alle benutzerdefinierten Entitäten, Zeitpläne und externen Sensordaten werden unten angezeigt.',
NO_DATA: 'Keine Daten',
NO_DATA_1: 'Keine favorisierten EMS-Entitäten gefunden! Verwenden Sie das Modul', NO_DATA_1: 'Keine favorisierten EMS-Entitäten gefunden! Verwenden Sie das Modul',
NO_DATA_2: ', um sie zu markieren.', NO_DATA_2: ', um sie zu markieren.',
NO_DATA_3: 'Um alle verfügbaren Entitäten anzuzeigen, gehen Sie zu', NO_DATA_3: 'Um alle verfügbaren Entitäten anzuzeigen, gehen Sie zu',

View File

@@ -188,8 +188,12 @@ const en: Translation = {
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
DOWNLOAD_SETTINGS_TEXT2: 'Export all values', DOWNLOAD_SETTINGS_TEXT2: 'Export all values',
DOWNLOAD_SYSTEM_BACKUP: 'System Backup', DOWNLOAD_SYSTEM_BACKUP: 'System Backup',
WARNING_SYSTEM_BACKUP: 'This will create a backup of your configuration and settings. All passwords will be readable in the backup file. Do you want to continue?',
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
UPGRADE_IMPORTANT_MESSAGES: 'Upgrade Important Messages',
UPGRADE_IMPORTANT_MESSAGES_1: 'You are upgrading from a major version. Please be aware that this may cause issues with your configuration.',
UPGRADE_IMPORTANT_MESSAGES_2: 'You are upgrading from a minor version. Please be aware that this may cause issues with your configuration.',
ERROR: 'Unexpected Error, please try again', ERROR: 'Unexpected Error, please try again',
TIME_SET: 'Time set', TIME_SET: 'Time set',
MANAGE_USERS: 'Manage Users', MANAGE_USERS: 'Manage Users',
@@ -347,7 +351,6 @@ const en: Translation = {
BYTES: 'Bytes', BYTES: 'Bytes',
BITMASK: 'Bit Mask', BITMASK: 'Bit Mask',
DUPLICATE: 'Duplicate', DUPLICATE: 'Duplicate',
NO_DATA: 'No data',
NO_DATA_1: 'No favorite EMS entities found yet. Use the', NO_DATA_1: 'No favorite EMS entities found yet. Use the',
NO_DATA_2: 'module to mark them.', NO_DATA_2: 'module to mark them.',
NO_DATA_3: 'To see all available entities go to', NO_DATA_3: 'To see all available entities go to',

View File

@@ -188,8 +188,12 @@ const fr: Translation = {
DOWNLOAD_SETTINGS_TEXT: 'Créer une sauvegarde de vos paramètres et configurations', DOWNLOAD_SETTINGS_TEXT: 'Créer une sauvegarde de vos paramètres et configurations',
DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les valeurs', DOWNLOAD_SETTINGS_TEXT2: 'Exporter toutes les valeurs',
DOWNLOAD_SYSTEM_BACKUP: 'Sauvegarde système', DOWNLOAD_SYSTEM_BACKUP: 'Sauvegarde système',
WARNING_SYSTEM_BACKUP: 'Cela créera une sauvegarde de vos paramètres et configurations. Tous les mots de passe seront lisibles dans le fichier de sauvegarde. Voulez-vous continuer ?',
UPLOAD_TEXT: 'Télécharger un nouveau fichier firmware (.bin) ou une sauvegarde (.json)', UPLOAD_TEXT: 'Télécharger un nouveau fichier firmware (.bin) ou une sauvegarde (.json)',
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
UPGRADE_IMPORTANT_MESSAGES: 'Messages importants pour la mise à jour',
UPGRADE_IMPORTANT_MESSAGES_1: 'Vous mettez à jour à partir d\'une version majeure. Veuillez prendre en compte que cela peut causer des problèmes avec votre configuration.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Vous mettez à jour à partir d\'une version mineure. Veuillez prendre en compte que cela peut causer des problèmes avec votre configuration.',
ERROR: 'Erreur inattendue, veuillez réessayer', ERROR: 'Erreur inattendue, veuillez réessayer',
TIME_SET: 'Time set', TIME_SET: 'Time set',
MANAGE_USERS: 'Gérer les utilisateurs', MANAGE_USERS: 'Gérer les utilisateurs',
@@ -347,11 +351,10 @@ const fr: Translation = {
BITMASK: 'Masque de bits', BITMASK: 'Masque de bits',
DUPLICATE: 'Dupliquer', DUPLICATE: 'Dupliquer',
DASHBOARD_1: 'Toutes les entités EMS actives et marquées comme favoris, plus toutes les entités personnalisées, les programmes et les données des capteurs externes sont affichées ci-dessous.', DASHBOARD_1: 'Toutes les entités EMS actives et marquées comme favoris, plus toutes les entités personnalisées, les programmes et les données des capteurs externes sont affichées ci-dessous.',
NO_DATA: 'No data',
NO_DATA_1: 'Aucune entité EMS favorite trouvée. Utilisez le', NO_DATA_1: 'Aucune entité EMS favorite trouvée. Utilisez le',
NO_DATA_2: 'module pour les marquer.', NO_DATA_2: 'module pour les marquer.',
NO_DATA_3: 'Pour voir toutes les entités disponibles, aller à', NO_DATA_3: 'Pour voir toutes les entités disponibles, aller à',
NO_GPIO:'No available GPIO found', NO_GPIO:"Aucun GPIO disponible n'a été détecté",
THIS_VERSION: 'Cette version', THIS_VERSION: 'Cette version',
PLATFORM: 'Plateforme', PLATFORM: 'Plateforme',
RELEASE_TYPE: 'Type de version', RELEASE_TYPE: 'Type de version',

View File

@@ -188,8 +188,12 @@ const it: Translation = {
DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings', DOWNLOAD_SETTINGS_TEXT: 'Create a backup of your configuration and settings',
DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i valori', DOWNLOAD_SETTINGS_TEXT2: 'Esporta tutti i valori',
DOWNLOAD_SYSTEM_BACKUP: 'Backup sistema', DOWNLOAD_SYSTEM_BACKUP: 'Backup sistema',
WARNING_SYSTEM_BACKUP: 'Questo creerà un backup delle tue configurazioni e impostazioni. Tutte le password saranno leggibili nel file di backup. Vuoi continuare?',
UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)', UPLOAD_TEXT: 'Upload a new firmware file (.bin) or a backup file (.json)',
UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here', UPLOAD_DROP_TEXT: 'Drop a firmware .bin file or click here',
UPGRADE_IMPORTANT_MESSAGES: 'Messaggi importanti per l\'aggiornamento',
UPGRADE_IMPORTANT_MESSAGES_1: 'Stai aggiornando da una versione principale. Si prega di essere consapevoli che questo può causare problemi con la tua configurazione.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Stai aggiornando da una versione secondaria. Si prega di essere consapevoli che questo può causare problemi con la tua configurazione.',
ERROR: 'Errore Inaspettato, prego tenta ancora', ERROR: 'Errore Inaspettato, prego tenta ancora',
TIME_SET: 'Imposta Ora', TIME_SET: 'Imposta Ora',
MANAGE_USERS: 'Gestione Utenti', MANAGE_USERS: 'Gestione Utenti',
@@ -347,11 +351,10 @@ const it: Translation = {
BITMASK: 'Bitmask', BITMASK: 'Bitmask',
DUPLICATE: 'Duplicato', DUPLICATE: 'Duplicato',
DASHBOARD_1: 'Tutte le entità EMS che sono attive e marcate come preferite, più tutte le entità personalizzate, piani di programmazione e dati dei sensori esterni sono visualizzati di seguito.', DASHBOARD_1: 'Tutte le entità EMS che sono attive e marcate come preferite, più tutte le entità personalizzate, piani di programmazione e dati dei sensori esterni sono visualizzati di seguito.',
NO_DATA: 'No data',
NO_DATA_1: 'Nessuna entità EMS preferita trovata. Usa il', NO_DATA_1: 'Nessuna entità EMS preferita trovata. Usa il',
NO_DATA_2: 'modulo per marcarle.', NO_DATA_2: 'modulo per marcarle.',
NO_DATA_3: 'Per vedere tutte le entità disponibili vai a', NO_DATA_3: 'Per vedere tutte le entità disponibili vai a',
NO_GPIO:'No available GPIO found', NO_GPIO:'Non è stato trovato alcun GPIO disponibile',
THIS_VERSION: 'Questa versione', THIS_VERSION: 'Questa versione',
PLATFORM: 'Piattaforma', PLATFORM: 'Piattaforma',
RELEASE_TYPE: 'Tipo di rilascio', RELEASE_TYPE: 'Tipo di rilascio',

View File

@@ -188,8 +188,12 @@ const nl: Translation = {
DOWNLOAD_SETTINGS_TEXT: 'Maak een back-up van uw configuratie en instellingen', DOWNLOAD_SETTINGS_TEXT: 'Maak een back-up van uw configuratie en instellingen',
DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle waarden', DOWNLOAD_SETTINGS_TEXT2: 'Exporteer alle waarden',
DOWNLOAD_SYSTEM_BACKUP: 'Systeem Backup', DOWNLOAD_SYSTEM_BACKUP: 'Systeem Backup',
WARNING_SYSTEM_BACKUP: 'Dit zal een backup maken van uw configuratie en instellingen. Alle wachtwoorden zullen leesbaar zijn in het backup bestand. Weet je zeker dat je wilt doorgaan?',
UPLOAD_TEXT: 'Upload een nieuw firmwarebestand (.bin) of een back-upbestand (.json)', UPLOAD_TEXT: 'Upload een nieuw firmwarebestand (.bin) of een back-upbestand (.json)',
UPLOAD_DROP_TEXT: 'Sleep en firmware .bin bestand hierheen of klik hier', UPLOAD_DROP_TEXT: 'Sleep en firmware .bin bestand hierheen of klik hier',
UPGRADE_IMPORTANT_MESSAGES: 'Belangrijke berichten voor upgrade',
UPGRADE_IMPORTANT_MESSAGES_1: 'U updatet van een grote versie. Wees bewust dat dit problemen met uw configuratie kan veroorzaken.',
UPGRADE_IMPORTANT_MESSAGES_2: 'U updatet van een kleine versie. Wees bewust dat dit problemen met uw configuratie kan veroorzaken.',
ERROR: 'Onverwachte fout, probeer opnieuw', ERROR: 'Onverwachte fout, probeer opnieuw',
TIME_SET: 'Tijd ingesteld', TIME_SET: 'Tijd ingesteld',
MANAGE_USERS: 'Gebruikersbeheer', MANAGE_USERS: 'Gebruikersbeheer',
@@ -347,11 +351,10 @@ const nl: Translation = {
BITMASK: 'Bit Mask', BITMASK: 'Bit Mask',
DUPLICATE: 'Duplicaat', DUPLICATE: 'Duplicaat',
DASHBOARD_1: 'Alle EMS-entiteiten die actief zijn en als favoriet zijn gemarkeerd, plus alle aangepaste entiteiten en externe sensorgegevens worden hieronder weergegeven.', DASHBOARD_1: 'Alle EMS-entiteiten die actief zijn en als favoriet zijn gemarkeerd, plus alle aangepaste entiteiten en externe sensorgegevens worden hieronder weergegeven.',
NO_DATA: 'No data',
NO_DATA_1: 'Er zijn nog geen favoriete EMS-entiteiten gevonden. Gebruik de', NO_DATA_1: 'Er zijn nog geen favoriete EMS-entiteiten gevonden. Gebruik de',
NO_DATA_2: 'module om ze te markeren.', NO_DATA_2: 'module om ze te markeren.',
NO_DATA_3: 'Om alle beschikbare entiteiten te zien, ga naar', NO_DATA_3: 'Om alle beschikbare entiteiten te zien, ga naar',
NO_GPIO:'No available GPIO found', NO_GPIO:'Er is geen beschikbare GPIO gevonden',
THIS_VERSION: 'Deze Versie', THIS_VERSION: 'Deze Versie',
PLATFORM: 'Platform', PLATFORM: 'Platform',
RELEASE_TYPE: 'Release Typ', RELEASE_TYPE: 'Release Typ',

View File

@@ -188,8 +188,12 @@ const no: Translation = {
DOWNLOAD_SETTINGS_TEXT: 'Lag en sikkerhetskopi av dine konfigurasjon og innstillinger', DOWNLOAD_SETTINGS_TEXT: 'Lag en sikkerhetskopi av dine konfigurasjon og innstillinger',
DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle verdier', DOWNLOAD_SETTINGS_TEXT2: 'Eksporter alle verdier',
DOWNLOAD_SYSTEM_BACKUP: 'System Sikkerhetskopi', DOWNLOAD_SYSTEM_BACKUP: 'System Sikkerhetskopi',
WARNING_SYSTEM_BACKUP: 'Dette vil lage en sikkerhetskopi av dine konfigurasjon og innstillinger. Alle passord vil være lesbare i sikkerhetskopien. Er du sikker på at du vil fortsette?',
UPLOAD_TEXT: 'Last opp en ny firmware fil (.bin) eller en sikkerhetskopi fil (.json)', UPLOAD_TEXT: 'Last opp en ny firmware fil (.bin) eller en sikkerhetskopi fil (.json)',
UPLOAD_DROP_TEXT: 'Dropp en firmware fil (.bin) eller klikk her', UPLOAD_DROP_TEXT: 'Dropp en firmware fil (.bin) eller klikk her',
UPGRADE_IMPORTANT_MESSAGES: 'Viktige meldinger for oppgradering',
UPGRADE_IMPORTANT_MESSAGES_1: 'Du oppgraderer fra en stor versjon. Vær oppmerksom på at dette kan føre til problemer med din konfigurasjon.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Du oppgraderer fra en liten versjon. Vær oppmerksom på at dette kan føre til problemer med din konfigurasjon.',
ERROR: 'Ukjent feil, prøv igjen', ERROR: 'Ukjent feil, prøv igjen',
TIME_SET: 'Still in tid', TIME_SET: 'Still in tid',
MANAGE_USERS: 'Administrer Brukere', MANAGE_USERS: 'Administrer Brukere',
@@ -347,11 +351,10 @@ const no: Translation = {
BITMASK: 'Bitmask', BITMASK: 'Bitmask',
DUPLICATE: 'Duplikat', DUPLICATE: 'Duplikat',
DASHBOARD_1: 'Alle EMS enheter som er aktive og merket som favoritt, pluss alle personlige enheter, planlegg og eksterne sensor data er vist nedenfor.', DASHBOARD_1: 'Alle EMS enheter som er aktive og merket som favoritt, pluss alle personlige enheter, planlegg og eksterne sensor data er vist nedenfor.',
NO_DATA: 'No data',
NO_DATA_1: 'Ingen favoritte EMS enheter funnet enda. Bruk', NO_DATA_1: 'Ingen favoritte EMS enheter funnet enda. Bruk',
NO_DATA_2: 'modul for å markere dem.', NO_DATA_2: 'modul for å markere dem.',
NO_DATA_3: 'For å se alle tilgjengelige enheter, gå til', NO_DATA_3: 'For å se alle tilgjengelige enheter, gå til',
NO_GPIO:'No available GPIO found', NO_GPIO:'Det ble ikke funnet noen tilgjengelige GPIO-porter',
THIS_VERSION: 'Denne versjonen', THIS_VERSION: 'Denne versjonen',
PLATFORM: 'Plattform', PLATFORM: 'Plattform',
RELEASE_TYPE: 'Utgivelses type', RELEASE_TYPE: 'Utgivelses type',

View File

@@ -188,8 +188,12 @@ const pl: BaseTranslation = {
DOWNLOAD_SETTINGS_TEXT: 'Utwórz kopię swoich ustawień i konfiguracji', DOWNLOAD_SETTINGS_TEXT: 'Utwórz kopię swoich ustawień i konfiguracji',
DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie wartości', DOWNLOAD_SETTINGS_TEXT2: 'Eksportuj wszystkie wartości',
DOWNLOAD_SYSTEM_BACKUP: 'Kopia zapasowa systemu', DOWNLOAD_SYSTEM_BACKUP: 'Kopia zapasowa systemu',
WARNING_SYSTEM_BACKUP: 'To utworzy kopię swoich ustawień i konfiguracji. Wszystkie hasła będą widoczne w kopii zapasowej. Czy na pewno chcesz kontynuować?',
UPLOAD_TEXT: 'Wgraj nowy plik firmware (.bin) lub kopię ustawień (.json)', UPLOAD_TEXT: 'Wgraj nowy plik firmware (.bin) lub kopię ustawień (.json)',
UPLOAD_DROP_TEXT: 'Upuść plik firmware .bin lub kliknij tutaj', UPLOAD_DROP_TEXT: 'Upuść plik firmware .bin lub kliknij tutaj',
UPGRADE_IMPORTANT_MESSAGES: 'Ważne informacje dotyczące aktualizacji',
UPGRADE_IMPORTANT_MESSAGES_1: 'Aktualizujesz się z głównej wersji. Proszę mieć świadomość, że to może spowodować problemy z konfiguracją.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujesz się z drugorzędnej wersji. Proszę mieć świadomość, że to może spowodować problemy z konfiguracją.',
ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!', ERROR: 'Nieoczekiwany błąd, spróbuj ponownie!',
TIME_SET: 'Zegar został ustawiony.', TIME_SET: 'Zegar został ustawiony.',
MANAGE_USERS: 'Zarządzanie użytkownikami', MANAGE_USERS: 'Zarządzanie użytkownikami',
@@ -347,11 +351,10 @@ const pl: BaseTranslation = {
BITMASK: 'Bit Mask', BITMASK: 'Bit Mask',
DUPLICATE: 'Duplicate', DUPLICATE: 'Duplicate',
DASHBOARD_1: 'All EMS entities that are active and marked as Favorite, plus all Custom Entities, Schedules and external Sensors data are displayed below.', DASHBOARD_1: 'All EMS entities that are active and marked as Favorite, plus all Custom Entities, Schedules and external Sensors data are displayed below.',
NO_DATA: 'No data',
NO_DATA_1: 'Brak ulubionych encji EMS. Użyj', NO_DATA_1: 'Brak ulubionych encji EMS. Użyj',
NO_DATA_2: 'moduł do ich oznaczenia.', NO_DATA_2: 'moduł do ich oznaczenia.',
NO_DATA_3: 'Aby zobaczyć wszystkie dostępne encje przejdź do', NO_DATA_3: 'Aby zobaczyć wszystkie dostępne encje przejdź do',
NO_GPIO:'No available GPIO found', NO_GPIO:'Nie znaleziono dostępnych pinów GPIO',
THIS_VERSION: 'Ta wersja', THIS_VERSION: 'Ta wersja',
PLATFORM: 'Platforma', PLATFORM: 'Platforma',
RELEASE_TYPE: 'Typ wydania', RELEASE_TYPE: 'Typ wydania',

View File

@@ -188,8 +188,12 @@ const sk: Translation = {
DOWNLOAD_SETTINGS_TEXT: 'Vytvorte zálohu svojej konfigurácie a nastavení', DOWNLOAD_SETTINGS_TEXT: 'Vytvorte zálohu svojej konfigurácie a nastavení',
DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky hodnoty', DOWNLOAD_SETTINGS_TEXT2: 'Exportovať všetky hodnoty',
DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha', DOWNLOAD_SYSTEM_BACKUP: 'Systémová záloha',
WARNING_SYSTEM_BACKUP: 'Toto vytvorí zálohu vašich nastavení a konfigurácií. Všetky hesla budú v zálohovom súbore čitateľné. Naozaj chcete pokračovať?',
UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)', UPLOAD_TEXT: 'Nahrajte nový súbor firmvéru (.bin) alebo súbor zálohy (.json)',
UPLOAD_DROP_TEXT: 'Presuňte súbor .bin firmvéru alebo kliknite sem', UPLOAD_DROP_TEXT: 'Presuňte súbor .bin firmvéru alebo kliknite sem',
UPGRADE_IMPORTANT_MESSAGES: 'Dôležité informácie pre aktualizáciu',
UPGRADE_IMPORTANT_MESSAGES_1: 'Aktualizujete sa z hlavného verzie. Prosím, buďte si vedomí, že to môže spôsobiť problémy s vašou konfiguráciou.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Aktualizujete sa z menšieho verzie. Prosím, buďte si vedomí, že to môže spôsobiť problémy s vašou konfiguráciou.',
ERROR: 'Neočakávaná chyba, prosím skúste to znova', ERROR: 'Neočakávaná chyba, prosím skúste to znova',
TIME_SET: 'Nastavený čas', TIME_SET: 'Nastavený čas',
MANAGE_USERS: 'Správa používateľov', MANAGE_USERS: 'Správa používateľov',
@@ -347,11 +351,10 @@ const sk: Translation = {
BITMASK: 'Bitová maska', BITMASK: 'Bitová maska',
DUPLICATE: 'Duplicitné', DUPLICATE: 'Duplicitné',
DASHBOARD_1: 'Všetky entity EMS, ktoré sú aktívne a označené ako obľúbené, plus všetky vlastné entity, plány a údaje externých senzorov sú zobrazené nižšie.', DASHBOARD_1: 'Všetky entity EMS, ktoré sú aktívne a označené ako obľúbené, plus všetky vlastné entity, plány a údaje externých senzorov sú zobrazené nižšie.',
NO_DATA: 'No data',
NO_DATA_1: 'Nenašli sa žiadne obľúbené entity EMS. Použite', NO_DATA_1: 'Nenašli sa žiadne obľúbené entity EMS. Použite',
NO_DATA_2: 'modul na ich označenie.', NO_DATA_2: 'modul na ich označenie.',
NO_DATA_3: 'Ak chcete zobraziť všetky dostupné entity, prejdite na', NO_DATA_3: 'Ak chcete zobraziť všetky dostupné entity, prejdite na',
NO_GPIO:'No available GPIO found', NO_GPIO:'Nebol nájdený žiadny dostupný GPIO',
THIS_VERSION: 'Táto verzia', THIS_VERSION: 'Táto verzia',
PLATFORM: 'Platforma', PLATFORM: 'Platforma',
RELEASE_TYPE: 'Typ vydania', RELEASE_TYPE: 'Typ vydania',

View File

@@ -188,8 +188,12 @@ const sv: Translation = {
DOWNLOAD_SETTINGS_TEXT: 'Skapa en säkerhetskopia av din konfiguration och inställningar', DOWNLOAD_SETTINGS_TEXT: 'Skapa en säkerhetskopia av din konfiguration och inställningar',
DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla värden', DOWNLOAD_SETTINGS_TEXT2: 'Exportera alla värden',
DOWNLOAD_SYSTEM_BACKUP: 'System säkerhetskopia', DOWNLOAD_SYSTEM_BACKUP: 'System säkerhetskopia',
WARNING_SYSTEM_BACKUP: 'Detta kommer att skapa en säkerhetskopia av dina inställningar och konfiguration. Alla lösenord kommer att vara läsbara i säkerhetskopian. Är du säker på att du vill fortsätta?',
UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)', UPLOAD_TEXT: 'Ladda upp en ny firmwarefil (.bin) eller en säkerhetskopiafil (.json)',
UPLOAD_DROP_TEXT: 'Droppa en firmware .bin fil eller klicka här', UPLOAD_DROP_TEXT: 'Droppa en firmware .bin fil eller klicka här',
UPGRADE_IMPORTANT_MESSAGES: 'Viktiga meddelanden för uppgradering',
UPGRADE_IMPORTANT_MESSAGES_1: 'Du uppgraderar från en major version. Vänligen var medveten om att detta kan orsaka problem med din konfiguration.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Du uppgraderar från en minor version. Vänligen var medveten om att detta kan orsaka problem med din konfiguration.',
ERROR: 'Okänt fel, var god försök igen', ERROR: 'Okänt fel, var god försök igen',
TIME_SET: 'Ställ in tid', TIME_SET: 'Ställ in tid',
MANAGE_USERS: 'Användare', MANAGE_USERS: 'Användare',
@@ -347,11 +351,10 @@ const sv: Translation = {
BITMASK: 'Bitmask', BITMASK: 'Bitmask',
DUPLICATE: 'Dublett', DUPLICATE: 'Dublett',
DASHBOARD_1: 'Alla EMS-enheter som är aktiva och markerade som favorit, plus alla anpassade entiteter, scheman och externa sensor-data visas nedan.', DASHBOARD_1: 'Alla EMS-enheter som är aktiva och markerade som favorit, plus alla anpassade entiteter, scheman och externa sensor-data visas nedan.',
NO_DATA: 'No data',
NO_DATA_1: 'Inga favorit EMS enheter hittade än. Använd', NO_DATA_1: 'Inga favorit EMS enheter hittade än. Använd',
NO_DATA_2: 'modul för att markera dem.', NO_DATA_2: 'modul för att markera dem.',
NO_DATA_3: 'För att se alla tillgängliga enheter, gå till', NO_DATA_3: 'För att se alla tillgängliga enheter, gå till',
NO_GPIO:'No available GPIO found', NO_GPIO:'Inga tillgängliga GPIO-portar hittades',
THIS_VERSION: 'Denna version', THIS_VERSION: 'Denna version',
PLATFORM: 'Plattform', PLATFORM: 'Plattform',
RELEASE_TYPE: 'Utgivelsestyp', RELEASE_TYPE: 'Utgivelsestyp',

View File

@@ -188,8 +188,12 @@ const tr: Translation = {
DOWNLOAD_SETTINGS_TEXT: 'Yapılandırma ve ayarlarınızın yedekleme yapın', DOWNLOAD_SETTINGS_TEXT: 'Yapılandırma ve ayarlarınızın yedekleme yapın',
DOWNLOAD_SETTINGS_TEXT2: 'Tüm değerleri dışarı al', DOWNLOAD_SETTINGS_TEXT2: 'Tüm değerleri dışarı al',
DOWNLOAD_SYSTEM_BACKUP: 'Sistem yedekleme', DOWNLOAD_SYSTEM_BACKUP: 'Sistem yedekleme',
WARNING_SYSTEM_BACKUP: 'Bu, yapılandırma ve ayarlarınızın bir yedeklemesi oluşturacaktır. Tüm şifreler yedekleme dosyasında okunabilir olacaktır. Devam etmek istediğinize emin misiniz?',
UPLOAD_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle', UPLOAD_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle',
UPLOAD_DROP_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın', UPLOAD_DROP_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın',
UPGRADE_IMPORTANT_MESSAGES: 'Yükseltme Önemli Mesajları',
UPGRADE_IMPORTANT_MESSAGES_1: 'Bir ana sürümden yükselteysiniz. Lütfen bu, yapılandırmanızın sorunlarına neden olabileceğini unutmayın.',
UPGRADE_IMPORTANT_MESSAGES_2: 'Bir küçük sürümden yükselteysiniz. Lütfen bu, yapılandırmanızın sorunlarına neden olabileceğini unutmayın.',
ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.', ERROR: 'Beklenemedik hata, lütfen tekrar deneyin.',
TIME_SET: 'Zaman ayarı', TIME_SET: 'Zaman ayarı',
MANAGE_USERS: 'Kullanıcıları yönet', MANAGE_USERS: 'Kullanıcıları yönet',
@@ -347,11 +351,10 @@ const tr: Translation = {
BITMASK: 'Bit Maskesi', BITMASK: 'Bit Maskesi',
DUPLICATE: 'Çift', DUPLICATE: 'Çift',
DASHBOARD_1: 'Tüm aktif ve Favori olarak işaretlenmiş EMS varlıkları, artı tüm özel varlıklar, zamanlayıcılar ve harici sensör verileri aşağıda görüntüleniyor.', DASHBOARD_1: 'Tüm aktif ve Favori olarak işaretlenmiş EMS varlıkları, artı tüm özel varlıklar, zamanlayıcılar ve harici sensör verileri aşağıda görüntüleniyor.',
NO_DATA: 'No data',
NO_DATA_1: 'Henüz bir favori EMS varlığı bulunamadı. Kullanın', NO_DATA_1: 'Henüz bir favori EMS varlığı bulunamadı. Kullanın',
NO_DATA_2: 'modülünü kullanın.', NO_DATA_2: 'modülünü kullanın.',
NO_DATA_3: 'Tüm kullanılabilir varlıkları görmek için git', NO_DATA_3: 'Tüm kullanılabilir varlıkları görmek için git',
NO_GPIO:'No available GPIO found', NO_GPIO:'Kullanılabilir GPIO bulunamadı',
THIS_VERSION: 'Bu Sürüm', THIS_VERSION: 'Bu Sürüm',
PLATFORM: 'Platforma', PLATFORM: 'Platforma',
RELEASE_TYPE: 'Sürüm Tipi', RELEASE_TYPE: 'Sürüm Tipi',

View File

@@ -13,7 +13,7 @@
"@trivago/prettier-plugin-sort-imports": "^6.0.2", "@trivago/prettier-plugin-sort-imports": "^6.0.2",
"formidable": "^3.5.4", "formidable": "^3.5.4",
"itty-router": "^5.0.23", "itty-router": "^5.0.23",
"prettier": "^3.8.1" "prettier": "^3.8.2"
}, },
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319" "packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
} }

View File

@@ -13,7 +13,7 @@ importers:
version: 3.1.3 version: 3.1.3
'@trivago/prettier-plugin-sort-imports': '@trivago/prettier-plugin-sort-imports':
specifier: ^6.0.2 specifier: ^6.0.2
version: 6.0.2(prettier@3.8.1) version: 6.0.2(prettier@3.8.2)
formidable: formidable:
specifier: ^3.5.4 specifier: ^3.5.4
version: 3.5.4 version: 3.5.4
@@ -21,8 +21,8 @@ importers:
specifier: ^5.0.23 specifier: ^5.0.23
version: 5.0.23 version: 5.0.23
prettier: prettier:
specifier: ^3.8.1 specifier: ^3.8.2
version: 3.8.1 version: 3.8.2
packages: packages:
@@ -112,8 +112,8 @@ packages:
balanced-match@1.0.2: balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
brace-expansion@2.0.3: brace-expansion@2.1.0:
resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==}
debug@4.4.3: debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
@@ -145,8 +145,8 @@ packages:
engines: {node: '>=6'} engines: {node: '>=6'}
hasBin: true hasBin: true
lodash-es@4.17.23: lodash-es@4.18.1:
resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==}
minimatch@9.0.9: minimatch@9.0.9:
resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
@@ -167,8 +167,8 @@ packages:
picocolors@1.1.1: picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
prettier@3.8.1: prettier@3.8.2:
resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} resolution: {integrity: sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==}
engines: {node: '>=14'} engines: {node: '>=14'}
hasBin: true hasBin: true
@@ -246,17 +246,17 @@ snapshots:
dependencies: dependencies:
'@noble/hashes': 1.8.0 '@noble/hashes': 1.8.0
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.1)': '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.2)':
dependencies: dependencies:
'@babel/generator': 7.29.1 '@babel/generator': 7.29.1
'@babel/parser': 7.29.2 '@babel/parser': 7.29.2
'@babel/traverse': 7.29.0 '@babel/traverse': 7.29.0
'@babel/types': 7.29.0 '@babel/types': 7.29.0
javascript-natural-sort: 0.7.1 javascript-natural-sort: 0.7.1
lodash-es: 4.17.23 lodash-es: 4.18.1
minimatch: 9.0.9 minimatch: 9.0.9
parse-imports-exports: 0.2.4 parse-imports-exports: 0.2.4
prettier: 3.8.1 prettier: 3.8.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -264,7 +264,7 @@ snapshots:
balanced-match@1.0.2: {} balanced-match@1.0.2: {}
brace-expansion@2.0.3: brace-expansion@2.1.0:
dependencies: dependencies:
balanced-match: 1.0.2 balanced-match: 1.0.2
@@ -291,11 +291,11 @@ snapshots:
jsesc@3.1.0: {} jsesc@3.1.0: {}
lodash-es@4.17.23: {} lodash-es@4.18.1: {}
minimatch@9.0.9: minimatch@9.0.9:
dependencies: dependencies:
brace-expansion: 2.0.3 brace-expansion: 2.1.0
ms@2.1.3: {} ms@2.1.3: {}
@@ -311,6 +311,6 @@ snapshots:
picocolors@1.1.1: {} picocolors@1.1.1: {}
prettier@3.8.1: {} prettier@3.8.2: {}
wrappy@1.0.2: {} wrappy@1.0.2: {}

View File

@@ -5170,6 +5170,32 @@ router
// set partition // set partition
console.log('setting partition to', content.param); console.log('setting partition to', content.param);
return status(200); return status(200);
} else if (action === 'upgradeImportantMessages') {
// check upgrade important messages
console.log(
'checking upgrade important messages for version ',
content.param
);
// determine message based on if we're upgrading a minor or major version
// TODO finish this
let message = 0;
const version = content.param;
const majorVersion = version.split('.')[0];
const minorVersion = version.split('.')[1];
const currentMajorVersion = THIS_VERSION.split('.')[0];
const currentMinorVersion = THIS_VERSION.split('.')[1];
if (majorVersion > currentMajorVersion) {
message = 1;
} else if (majorVersion < currentMajorVersion) {
message = 2;
} else if (minorVersion > currentMinorVersion) {
message = 1;
} else if (minorVersion < currentMinorVersion) {
message = 2;
} else {
message = 0;
}
return message;
} }
} }
return status(404); // cmd not found return status(404); // cmd not found

View File

@@ -1649,6 +1649,7 @@ bool System::check_upgrade() {
} }
// map each config filename to its human-readable section key // map each config filename to its human-readable section key
#ifndef EMSESP_STANDALONE
static const std::pair<const char *, const char *> SECTION_MAP[] = { static const std::pair<const char *, const char *> SECTION_MAP[] = {
{NETWORK_SETTINGS_FILE, "Network"}, {NETWORK_SETTINGS_FILE, "Network"},
{AP_SETTINGS_FILE, "AP"}, {AP_SETTINGS_FILE, "AP"},
@@ -1661,6 +1662,7 @@ static const std::pair<const char *, const char *> SECTION_MAP[] = {
{EMSESP_CUSTOMENTITY_FILE, "Entities"}, {EMSESP_CUSTOMENTITY_FILE, "Entities"},
{EMSESP_MODULES_FILE, "Modules"}, {EMSESP_MODULES_FILE, "Modules"},
}; };
#endif
// convert a single config file into a section of the output json object // convert a single config file into a section of the output json object
void System::exportSettings(const std::string & type, const char * filename, JsonObject output) { void System::exportSettings(const std::string & type, const char * filename, JsonObject output) {

View File

@@ -216,6 +216,8 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json)
} else if (action == "resetMQTT" && is_admin) { } else if (action == "resetMQTT" && is_admin) {
EMSESP::mqtt_.reset_mqtt(); EMSESP::mqtt_.reset_mqtt();
ok = true; ok = true;
} else if (action == "upgradeImportantMessages") {
ok = upgradeImportantMessages(param.c_str());
} }
#if defined(EMSESP_STANDALONE) && !defined(EMSESP_UNITY) #if defined(EMSESP_STANDALONE) && !defined(EMSESP_UNITY)
@@ -237,6 +239,20 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json)
request->send(response); request->send(response);
} }
// action = upgradeImportantMessages
// returns the type of upgrade important message to show\
// 0 = no message
// 1 = major version upgrade
// 2 = minor version upgrade
// TODO finish this
bool WebStatusService::upgradeImportantMessages(const char * version) {
version::Semver200_version current_version(current_version_s);
version::Semver200_version latest_version(version);
if (latest_version > current_version) {
return 1;
}
}
// action = checkUpgrade // action = checkUpgrade
// versions holds the latest development version and stable version in one string, comma separated // versions holds the latest development version and stable version in one string, comma separated
bool WebStatusService::checkUpgrade(JsonObject root, std::string & versions) { bool WebStatusService::checkUpgrade(JsonObject root, std::string & versions) {

View File

@@ -36,6 +36,7 @@ class WebStatusService {
bool uploadURL(const char * url); bool uploadURL(const char * url);
bool setSystemStatus(const char * status); bool setSystemStatus(const char * status);
void allvalues(JsonObject output); void allvalues(JsonObject output);
bool upgradeImportantMessages(const char * version);
std::string current_version_s = EMSESP_APP_VERSION; std::string current_version_s = EMSESP_APP_VERSION;
}; };