diff --git a/package.json b/package.json
index 8501a68c..679864e3 100644
--- a/package.json
+++ b/package.json
@@ -13,15 +13,15 @@
},
"dependencies": {
"@headlessui/react": "^1.4.2",
- "@meshtastic/meshtasticjs": "^0.6.28",
+ "@meshtastic/meshtasticjs": "^0.6.29",
"@reduxjs/toolkit": "^1.6.2",
"boring-avatars": "^1.5.8",
- "i18next": "^21.5.1",
+ "i18next": "^21.5.2",
"i18next-browser-languagedetector": "^6.1.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-file-icon": "^1.1.0",
- "react-hook-form": "^7.19.5",
+ "react-hook-form": "^7.20.2",
"react-i18next": "^11.14.2",
"react-icons": "^4.3.1",
"react-json-pretty": "^2.2.0",
@@ -46,19 +46,20 @@
"babel-plugin-module-resolver": "^4.1.0",
"eslint": "8.2.0",
"eslint-config-prettier": "^8.3.0",
+ "eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-babel-module": "^5.3.1",
"eslint-import-resolver-typescript": "^2.5.0",
"eslint-plugin-import": "^2.25.3",
- "eslint-plugin-react": "^7.27.0",
+ "eslint-plugin-react": "^7.27.1",
"eslint-plugin-react-hooks": "^4.3.0",
"gzipper": "^6.0.0",
"postcss": "^8.3.11",
"prettier": "^2.4.1",
"tailwindcss": "^3.0.0-alpha.2",
"tar": "^6.1.11",
- "typescript": "^4.4.4",
+ "typescript": "^4.5.2",
"vite": "^2.6.14",
- "vite-plugin-pwa": "^0.11.5",
+ "vite-plugin-pwa": "^0.11.6",
"workbox-window": "^6.4.1"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 95aff183..3554e977 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -2,7 +2,7 @@ lockfileVersion: 5.3
specifiers:
'@headlessui/react': ^1.4.2
- '@meshtastic/meshtasticjs': ^0.6.28
+ '@meshtastic/meshtasticjs': ^0.6.29
'@reduxjs/toolkit': ^1.6.2
'@types/react': ^17.0.35
'@types/react-dom': ^17.0.11
@@ -18,20 +18,21 @@ specifiers:
boring-avatars: ^1.5.8
eslint: 8.2.0
eslint-config-prettier: ^8.3.0
+ eslint-import-resolver-alias: ^1.1.2
eslint-import-resolver-babel-module: ^5.3.1
eslint-import-resolver-typescript: ^2.5.0
eslint-plugin-import: ^2.25.3
- eslint-plugin-react: ^7.27.0
+ eslint-plugin-react: ^7.27.1
eslint-plugin-react-hooks: ^4.3.0
gzipper: ^6.0.0
- i18next: ^21.5.1
+ i18next: ^21.5.2
i18next-browser-languagedetector: ^6.1.2
postcss: ^8.3.11
prettier: ^2.4.1
react: ^17.0.2
react-dom: ^17.0.2
react-file-icon: ^1.1.0
- react-hook-form: ^7.19.5
+ react-hook-form: ^7.20.2
react-i18next: ^11.14.2
react-icons: ^4.3.1
react-json-pretty: ^2.2.0
@@ -42,24 +43,24 @@ specifiers:
tar: ^6.1.11
timeago-react: ^3.0.4
type-route: ^0.6.0
- typescript: ^4.4.4
+ typescript: ^4.5.2
use-breakpoint: ^2.0.2
vite: ^2.6.14
- vite-plugin-pwa: ^0.11.5
+ vite-plugin-pwa: ^0.11.6
workbox-window: ^6.4.1
dependencies:
'@headlessui/react': 1.4.2_react-dom@17.0.2+react@17.0.2
- '@meshtastic/meshtasticjs': 0.6.28
+ '@meshtastic/meshtasticjs': 0.6.29
'@reduxjs/toolkit': 1.6.2_react-redux@7.2.6+react@17.0.2
boring-avatars: 1.5.8
- i18next: 21.5.1
+ i18next: 21.5.2
i18next-browser-languagedetector: 6.1.2
react: 17.0.2
react-dom: 17.0.2_react@17.0.2
react-file-icon: 1.1.0_react-dom@17.0.2+react@17.0.2
- react-hook-form: 7.19.5_react@17.0.2
- react-i18next: 11.14.2_i18next@21.5.1+react@17.0.2
+ react-hook-form: 7.20.2_react@17.0.2
+ react-i18next: 11.14.2_i18next@21.5.2+react@17.0.2
react-icons: 4.3.1_react@17.0.2
react-json-pretty: 2.2.0_react-dom@17.0.2+react@17.0.2
react-redux: 7.2.6_react-dom@17.0.2+react@17.0.2
@@ -75,38 +76,39 @@ devDependencies:
'@types/react-file-icon': 1.0.1
'@types/w3c-web-serial': 1.0.2
'@types/web-bluetooth': 0.0.11
- '@typescript-eslint/eslint-plugin': 5.4.0_b983626bd16070d34b18187cb6bde052
- '@typescript-eslint/parser': 5.4.0_eslint@8.2.0+typescript@4.4.4
- '@verypossible/eslint-config': 1.6.1_typescript@4.4.4
+ '@typescript-eslint/eslint-plugin': 5.4.0_d6f2571581882eb2d6c9d9867e002185
+ '@typescript-eslint/parser': 5.4.0_eslint@8.2.0+typescript@4.5.2
+ '@verypossible/eslint-config': 1.6.1_typescript@4.5.2
'@vitejs/plugin-react': 1.0.9
autoprefixer: 10.4.0_postcss@8.3.11
babel-plugin-module-resolver: 4.1.0
eslint: 8.2.0
eslint-config-prettier: 8.3.0_eslint@8.2.0
+ eslint-import-resolver-alias: 1.1.2_eslint-plugin-import@2.25.3
eslint-import-resolver-babel-module: 5.3.1_e51044130ac762fd207a8cd2109b5344
eslint-import-resolver-typescript: 2.5.0_6e04a54c7bcd7530b1a4c2da0aa486b1
eslint-plugin-import: 2.25.3_eslint@8.2.0
- eslint-plugin-react: 7.27.0_eslint@8.2.0
+ eslint-plugin-react: 7.27.1_eslint@8.2.0
eslint-plugin-react-hooks: 4.3.0_eslint@8.2.0
gzipper: 6.0.0
postcss: 8.3.11
prettier: 2.4.1
tailwindcss: 3.0.0-alpha.2_0c54bdadaf9d9c9c6c134cb2c6c061a3
tar: 6.1.11
- typescript: 4.4.4
+ typescript: 4.5.2
vite: 2.6.14
- vite-plugin-pwa: 0.11.5_vite@2.6.14
+ vite-plugin-pwa: 0.11.6_vite@2.6.14
workbox-window: 6.4.1
packages:
- /@apideck/better-ajv-errors/0.2.7_ajv@8.8.0:
+ /@apideck/better-ajv-errors/0.2.7_ajv@8.8.1:
resolution: {integrity: sha512-J2dW+EHYudbwI7MGovcHWLBrxasl21uuroc2zT8bH2RxYuv2g5GqsO5jcKUZz4LaMST45xhKjVuyRYkhcWyMhA==}
engines: {node: '>=10'}
peerDependencies:
ajv: '>=8'
dependencies:
- ajv: 8.8.0
+ ajv: 8.8.1
json-schema: 0.3.0
jsonpointer: 5.0.0
leven: 3.1.0
@@ -125,8 +127,8 @@ packages:
'@babel/highlight': 7.16.0
dev: true
- /@babel/compat-data/7.16.0:
- resolution: {integrity: sha512-DGjt2QZse5SGd9nfOSqO4WLJ8NN/oHkijbXbPrxuoJO3oIPJL3TciZs9FX+cOHNiY9E9l0opL8g7BmLe3T+9ew==}
+ /@babel/compat-data/7.16.4:
+ resolution: {integrity: sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==}
engines: {node: '>=6.9.0'}
dev: true
@@ -139,7 +141,7 @@ packages:
'@babel/helper-compilation-targets': 7.16.3_@babel+core@7.16.0
'@babel/helper-module-transforms': 7.16.0
'@babel/helpers': 7.16.3
- '@babel/parser': 7.16.3
+ '@babel/parser': 7.16.4
'@babel/template': 7.16.0
'@babel/traverse': 7.16.3
'@babel/types': 7.16.0
@@ -183,7 +185,7 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0
dependencies:
- '@babel/compat-data': 7.16.0
+ '@babel/compat-data': 7.16.4
'@babel/core': 7.16.0
'@babel/helper-validator-option': 7.14.5
browserslist: 4.18.1
@@ -218,8 +220,8 @@ packages:
regexpu-core: 4.8.0
dev: true
- /@babel/helper-define-polyfill-provider/0.2.4_@babel+core@7.16.0:
- resolution: {integrity: sha512-OrpPZ97s+aPi6h2n1OXzdhVis1SGSsMU2aMHgLcOKfsp4/v1NWpx3CWT3lBj5eeBq9cDkPkh+YCfdF7O12uNDQ==}
+ /@babel/helper-define-polyfill-provider/0.3.0_@babel+core@7.16.0:
+ resolution: {integrity: sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg==}
peerDependencies:
'@babel/core': ^7.4.0-0
dependencies:
@@ -308,8 +310,8 @@ packages:
engines: {node: '>=6.9.0'}
dev: true
- /@babel/helper-remap-async-to-generator/7.16.0:
- resolution: {integrity: sha512-MLM1IOMe9aQBqMWxcRw8dcb9jlM86NIw7KA0Wri91Xkfied+dE0QuBFSBjMNvqzmS0OSIDsMNC24dBEkPUi7ew==}
+ /@babel/helper-remap-async-to-generator/7.16.4:
+ resolution: {integrity: sha512-vGERmmhR+s7eH5Y/cp8PCVzj4XEjerq8jooMfxFdA5xVtAk9Sh4AQsrWgiErUEBjtGrBtOFKDUcWQFW4/dFwMA==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-annotate-as-pure': 7.16.0
@@ -394,8 +396,8 @@ packages:
js-tokens: 4.0.0
dev: true
- /@babel/parser/7.16.3:
- resolution: {integrity: sha512-dcNwU1O4sx57ClvLBVFbEgx0UZWfd0JQX5X6fxFRCLHelFBGXFfSz6Y0FAq2PEwUqlqLkdVjVr4VASEOuUnLJw==}
+ /@babel/parser/7.16.4:
+ resolution: {integrity: sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==}
engines: {node: '>=6.0.0'}
hasBin: true
dev: true
@@ -422,15 +424,15 @@ packages:
'@babel/plugin-proposal-optional-chaining': 7.16.0_@babel+core@7.16.0
dev: true
- /@babel/plugin-proposal-async-generator-functions/7.16.0_@babel+core@7.16.0:
- resolution: {integrity: sha512-nyYmIo7ZqKsY6P4lnVmBlxp9B3a96CscbLotlsNuktMHahkDwoPYEjXrZHU0Tj844Z9f1IthVxQln57mhkcExw==}
+ /@babel/plugin-proposal-async-generator-functions/7.16.4_@babel+core@7.16.0:
+ resolution: {integrity: sha512-/CUekqaAaZCQHleSK/9HajvcD/zdnJiKRiuUFq8ITE+0HsPzquf53cpFiqAwl/UfmJbR6n5uGPQSPdrmKOvHHg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.16.0
'@babel/helper-plugin-utils': 7.14.5
- '@babel/helper-remap-async-to-generator': 7.16.0
+ '@babel/helper-remap-async-to-generator': 7.16.4
'@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.16.0
transitivePeerDependencies:
- supports-color
@@ -535,7 +537,7 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
- '@babel/compat-data': 7.16.0
+ '@babel/compat-data': 7.16.4
'@babel/core': 7.16.0
'@babel/helper-compilation-targets': 7.16.3_@babel+core@7.16.0
'@babel/helper-plugin-utils': 7.14.5
@@ -763,7 +765,7 @@ packages:
'@babel/core': 7.16.0
'@babel/helper-module-imports': 7.16.0
'@babel/helper-plugin-utils': 7.14.5
- '@babel/helper-remap-async-to-generator': 7.16.0
+ '@babel/helper-remap-async-to-generator': 7.16.4
transitivePeerDependencies:
- supports-color
dev: true
@@ -1146,20 +1148,20 @@ packages:
'@babel/helper-plugin-utils': 7.14.5
dev: true
- /@babel/preset-env/7.16.0_@babel+core@7.16.0:
- resolution: {integrity: sha512-cdTu/W0IrviamtnZiTfixPfIncr2M1VqRrkjzZWlr1B4TVYimCFK5jkyOdP4qw2MrlKHi+b3ORj6x8GoCew8Dg==}
+ /@babel/preset-env/7.16.4_@babel+core@7.16.0:
+ resolution: {integrity: sha512-v0QtNd81v/xKj4gNKeuAerQ/azeNn/G1B1qMLeXOcV8+4TWlD2j3NV1u8q29SDFBXx/NBq5kyEAO+0mpRgacjA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
- '@babel/compat-data': 7.16.0
+ '@babel/compat-data': 7.16.4
'@babel/core': 7.16.0
'@babel/helper-compilation-targets': 7.16.3_@babel+core@7.16.0
'@babel/helper-plugin-utils': 7.14.5
'@babel/helper-validator-option': 7.14.5
'@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.16.2_@babel+core@7.16.0
'@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.16.0_@babel+core@7.16.0
- '@babel/plugin-proposal-async-generator-functions': 7.16.0_@babel+core@7.16.0
+ '@babel/plugin-proposal-async-generator-functions': 7.16.4_@babel+core@7.16.0
'@babel/plugin-proposal-class-properties': 7.16.0_@babel+core@7.16.0
'@babel/plugin-proposal-class-static-block': 7.16.0_@babel+core@7.16.0
'@babel/plugin-proposal-dynamic-import': 7.16.0_@babel+core@7.16.0
@@ -1222,9 +1224,9 @@ packages:
'@babel/plugin-transform-unicode-regex': 7.16.0_@babel+core@7.16.0
'@babel/preset-modules': 0.1.5_@babel+core@7.16.0
'@babel/types': 7.16.0
- babel-plugin-polyfill-corejs2: 0.2.3_@babel+core@7.16.0
- babel-plugin-polyfill-corejs3: 0.3.0_@babel+core@7.16.0
- babel-plugin-polyfill-regenerator: 0.2.3_@babel+core@7.16.0
+ babel-plugin-polyfill-corejs2: 0.3.0_@babel+core@7.16.0
+ babel-plugin-polyfill-corejs3: 0.4.0_@babel+core@7.16.0
+ babel-plugin-polyfill-regenerator: 0.3.0_@babel+core@7.16.0
core-js-compat: 3.19.1
semver: 6.3.0
transitivePeerDependencies:
@@ -1255,7 +1257,7 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
'@babel/code-frame': 7.16.0
- '@babel/parser': 7.16.3
+ '@babel/parser': 7.16.4
'@babel/types': 7.16.0
dev: true
@@ -1268,7 +1270,7 @@ packages:
'@babel/helper-function-name': 7.16.0
'@babel/helper-hoist-variables': 7.16.0
'@babel/helper-split-export-declaration': 7.16.0
- '@babel/parser': 7.16.3
+ '@babel/parser': 7.16.4
'@babel/types': 7.16.0
debug: 4.3.2
globals: 11.12.0
@@ -1355,8 +1357,8 @@ packages:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
dev: true
- /@meshtastic/meshtasticjs/0.6.28:
- resolution: {integrity: sha512-yoFzIM+fktvYqgRr/IVA41h4JMEv5GJue/xtxWNhWweEX6fiPoy+MoGeDkwU2dRyNzzZ03RLa6xNXqYxiHRlLA==}
+ /@meshtastic/meshtasticjs/0.6.29:
+ resolution: {integrity: sha512-XcfHTGlWBLgdfXCK81U/ilDpepyId/OEvXRNiEerg40m9pD7FaNlqPnAKRhvoeOl56VQdKtCpsiWJdeknSI4tw==}
dependencies:
'@protobuf-ts/runtime': 2.0.7
sub-events: 1.8.9
@@ -1403,7 +1405,7 @@ packages:
react-redux: 7.2.6_react-dom@17.0.2+react@17.0.2
redux: 4.1.2
redux-thunk: 2.4.0_redux@4.1.2
- reselect: 4.1.3
+ reselect: 4.1.4
dev: false
/@rollup/plugin-babel/5.3.0_@babel+core@7.16.0+rollup@2.60.0:
@@ -1496,8 +1498,8 @@ packages:
resolution: {integrity: sha1-7ihweulOEdK4J7y+UnC86n8+ce4=}
dev: true
- /@types/node/16.11.7:
- resolution: {integrity: sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==}
+ /@types/node/16.11.9:
+ resolution: {integrity: sha512-MKmdASMf3LtPzwLyRrFjtFFZ48cMf8jmX5VRYrDQiJa8Ybu5VAmkqBWqKU8fdCwD8ysw4mQ9nrEHvzg6gunR7A==}
dev: true
/@types/parse-json/4.0.0:
@@ -1538,7 +1540,7 @@ packages:
/@types/resolve/1.17.1:
resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
dependencies:
- '@types/node': 16.11.7
+ '@types/node': 16.11.9
dev: true
/@types/scheduler/0.16.2:
@@ -1556,7 +1558,7 @@ packages:
resolution: {integrity: sha512-2CF3Kk2Rcvg/c2QzO7mXUhY7eL9CC3aKzrF+dNWNmp7Q8bmlvjmUM1nFPMSngawdJ+CcIdu8eJlQRytBgAZR9w==}
dev: true
- /@typescript-eslint/eslint-plugin/4.33.0_cc617358c89d3f38c52462f6d809db4c:
+ /@typescript-eslint/eslint-plugin/4.33.0_d00b196ac5df1286ea7e45797bebddbc:
resolution: {integrity: sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==}
engines: {node: ^10.12.0 || >=12.0.0}
peerDependencies:
@@ -1567,8 +1569,8 @@ packages:
typescript:
optional: true
dependencies:
- '@typescript-eslint/experimental-utils': 4.33.0_eslint@7.32.0+typescript@4.4.4
- '@typescript-eslint/parser': 4.33.0_eslint@7.32.0+typescript@4.4.4
+ '@typescript-eslint/experimental-utils': 4.33.0_eslint@7.32.0+typescript@4.5.2
+ '@typescript-eslint/parser': 4.33.0_eslint@7.32.0+typescript@4.5.2
'@typescript-eslint/scope-manager': 4.33.0
debug: 4.3.2
eslint: 7.32.0
@@ -1576,13 +1578,13 @@ packages:
ignore: 5.1.9
regexpp: 3.2.0
semver: 7.3.5
- tsutils: 3.21.0_typescript@4.4.4
- typescript: 4.4.4
+ tsutils: 3.21.0_typescript@4.5.2
+ typescript: 4.5.2
transitivePeerDependencies:
- supports-color
dev: true
- /@typescript-eslint/eslint-plugin/5.4.0_b983626bd16070d34b18187cb6bde052:
+ /@typescript-eslint/eslint-plugin/5.4.0_d6f2571581882eb2d6c9d9867e002185:
resolution: {integrity: sha512-9/yPSBlwzsetCsGEn9j24D8vGQgJkOTr4oMLas/w886ZtzKIs1iyoqFrwsX2fqYEeUwsdBpC21gcjRGo57u0eg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1593,8 +1595,8 @@ packages:
typescript:
optional: true
dependencies:
- '@typescript-eslint/experimental-utils': 5.4.0_eslint@8.2.0+typescript@4.4.4
- '@typescript-eslint/parser': 5.4.0_eslint@8.2.0+typescript@4.4.4
+ '@typescript-eslint/experimental-utils': 5.4.0_eslint@8.2.0+typescript@4.5.2
+ '@typescript-eslint/parser': 5.4.0_eslint@8.2.0+typescript@4.5.2
'@typescript-eslint/scope-manager': 5.4.0
debug: 4.3.2
eslint: 8.2.0
@@ -1602,13 +1604,13 @@ packages:
ignore: 5.1.9
regexpp: 3.2.0
semver: 7.3.5
- tsutils: 3.21.0_typescript@4.4.4
- typescript: 4.4.4
+ tsutils: 3.21.0_typescript@4.5.2
+ typescript: 4.5.2
transitivePeerDependencies:
- supports-color
dev: true
- /@typescript-eslint/experimental-utils/4.33.0_eslint@7.32.0+typescript@4.4.4:
+ /@typescript-eslint/experimental-utils/4.33.0_eslint@7.32.0+typescript@4.5.2:
resolution: {integrity: sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==}
engines: {node: ^10.12.0 || >=12.0.0}
peerDependencies:
@@ -1617,7 +1619,7 @@ packages:
'@types/json-schema': 7.0.9
'@typescript-eslint/scope-manager': 4.33.0
'@typescript-eslint/types': 4.33.0
- '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.4.4
+ '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.5.2
eslint: 7.32.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0_eslint@7.32.0
@@ -1626,7 +1628,7 @@ packages:
- typescript
dev: true
- /@typescript-eslint/experimental-utils/5.4.0_eslint@8.2.0+typescript@4.4.4:
+ /@typescript-eslint/experimental-utils/5.4.0_eslint@8.2.0+typescript@4.5.2:
resolution: {integrity: sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1635,7 +1637,7 @@ packages:
'@types/json-schema': 7.0.9
'@typescript-eslint/scope-manager': 5.4.0
'@typescript-eslint/types': 5.4.0
- '@typescript-eslint/typescript-estree': 5.4.0_typescript@4.4.4
+ '@typescript-eslint/typescript-estree': 5.4.0_typescript@4.5.2
eslint: 8.2.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0_eslint@8.2.0
@@ -1644,7 +1646,7 @@ packages:
- typescript
dev: true
- /@typescript-eslint/parser/4.33.0_eslint@7.32.0+typescript@4.4.4:
+ /@typescript-eslint/parser/4.33.0_eslint@7.32.0+typescript@4.5.2:
resolution: {integrity: sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==}
engines: {node: ^10.12.0 || >=12.0.0}
peerDependencies:
@@ -1656,15 +1658,15 @@ packages:
dependencies:
'@typescript-eslint/scope-manager': 4.33.0
'@typescript-eslint/types': 4.33.0
- '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.4.4
+ '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.5.2
debug: 4.3.2
eslint: 7.32.0
- typescript: 4.4.4
+ typescript: 4.5.2
transitivePeerDependencies:
- supports-color
dev: true
- /@typescript-eslint/parser/5.4.0_eslint@8.2.0+typescript@4.4.4:
+ /@typescript-eslint/parser/5.4.0_eslint@8.2.0+typescript@4.5.2:
resolution: {integrity: sha512-JoB41EmxiYpaEsRwpZEYAJ9XQURPFer8hpkIW9GiaspVLX8oqbqNM8P4EP8HOZg96yaALiLEVWllA2E8vwsIKw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1676,10 +1678,10 @@ packages:
dependencies:
'@typescript-eslint/scope-manager': 5.4.0
'@typescript-eslint/types': 5.4.0
- '@typescript-eslint/typescript-estree': 5.4.0_typescript@4.4.4
+ '@typescript-eslint/typescript-estree': 5.4.0_typescript@4.5.2
debug: 4.3.2
eslint: 8.2.0
- typescript: 4.4.4
+ typescript: 4.5.2
transitivePeerDependencies:
- supports-color
dev: true
@@ -1710,7 +1712,7 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
- /@typescript-eslint/typescript-estree/4.33.0_typescript@4.4.4:
+ /@typescript-eslint/typescript-estree/4.33.0_typescript@4.5.2:
resolution: {integrity: sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==}
engines: {node: ^10.12.0 || >=12.0.0}
peerDependencies:
@@ -1725,13 +1727,13 @@ packages:
globby: 11.0.4
is-glob: 4.0.3
semver: 7.3.5
- tsutils: 3.21.0_typescript@4.4.4
- typescript: 4.4.4
+ tsutils: 3.21.0_typescript@4.5.2
+ typescript: 4.5.2
transitivePeerDependencies:
- supports-color
dev: true
- /@typescript-eslint/typescript-estree/5.4.0_typescript@4.4.4:
+ /@typescript-eslint/typescript-estree/5.4.0_typescript@4.5.2:
resolution: {integrity: sha512-nhlNoBdhKuwiLMx6GrybPT3SFILm5Gij2YBdPEPFlYNFAXUJWX6QRgvi/lwVoadaQEFsizohs6aFRMqsXI2ewA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1746,8 +1748,8 @@ packages:
globby: 11.0.4
is-glob: 4.0.3
semver: 7.3.5
- tsutils: 3.21.0_typescript@4.4.4
- typescript: 4.4.4
+ tsutils: 3.21.0_typescript@4.5.2
+ typescript: 4.5.2
transitivePeerDependencies:
- supports-color
dev: true
@@ -1768,18 +1770,18 @@ packages:
eslint-visitor-keys: 3.1.0
dev: true
- /@verypossible/eslint-config/1.6.1_typescript@4.4.4:
+ /@verypossible/eslint-config/1.6.1_typescript@4.5.2:
resolution: {integrity: sha512-3qf2FSag49zqI6rZlwKcF8RryLX0RJ3W+koJuhDhdQNyelSEeTxiijQ+Y/Xss4ILFzyqpBnzqiphmABGcOgj1Q==}
dependencies:
- '@typescript-eslint/eslint-plugin': 4.33.0_cc617358c89d3f38c52462f6d809db4c
- '@typescript-eslint/parser': 4.33.0_eslint@7.32.0+typescript@4.4.4
+ '@typescript-eslint/eslint-plugin': 4.33.0_d00b196ac5df1286ea7e45797bebddbc
+ '@typescript-eslint/parser': 4.33.0_eslint@7.32.0+typescript@4.5.2
babel-plugin-module-resolver: 4.1.0
eslint: 7.32.0
eslint-config-prettier: 8.3.0_eslint@7.32.0
eslint-import-resolver-babel-module: 5.3.1_e51044130ac762fd207a8cd2109b5344
eslint-import-resolver-typescript: 2.5.0_a820dc868cc8cd66d8297be6779b9035
eslint-plugin-import: 2.25.3_eslint@7.32.0
- eslint-plugin-react: 7.27.0_eslint@7.32.0
+ eslint-plugin-react: 7.27.1_eslint@7.32.0
eslint-plugin-react-hooks: 4.3.0_eslint@7.32.0
prettier: 2.4.1
transitivePeerDependencies:
@@ -1812,12 +1814,12 @@ packages:
acorn: 7.4.1
dev: true
- /acorn-jsx/5.3.2_acorn@8.5.0:
+ /acorn-jsx/5.3.2_acorn@8.6.0:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
- acorn: 8.5.0
+ acorn: 8.6.0
dev: true
/acorn-node/1.8.2:
@@ -1839,8 +1841,8 @@ packages:
hasBin: true
dev: true
- /acorn/8.5.0:
- resolution: {integrity: sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==}
+ /acorn/8.6.0:
+ resolution: {integrity: sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
@@ -1854,8 +1856,8 @@ packages:
uri-js: 4.4.1
dev: true
- /ajv/8.8.0:
- resolution: {integrity: sha512-L+cJ/+pkdICMueKR6wIx3VP2fjIx3yAhuvadUv/osv9yFD7OVZy442xFF+Oeu3ZvmhBGQzoF6mTSt+LUWBmGQg==}
+ /ajv/8.8.1:
+ resolution: {integrity: sha512-6CiMNDrzv0ZR916u2T+iRunnD60uWmNn8SkdB44/6stVORUg0aAkWO7PkOhpCmjmW8f2I/G/xnowD66fxGyQJg==}
dependencies:
fast-deep-equal: 3.1.3
json-schema-traverse: 1.0.0
@@ -1965,7 +1967,7 @@ packages:
postcss: ^8.1.0
dependencies:
browserslist: 4.18.1
- caniuse-lite: 1.0.30001280
+ caniuse-lite: 1.0.30001282
fraction.js: 4.1.2
normalize-range: 0.1.2
picocolors: 1.0.0
@@ -1991,42 +1993,42 @@ packages:
find-babel-config: 1.2.0
glob: 7.2.0
pkg-up: 3.1.0
- reselect: 4.1.3
+ reselect: 4.1.4
resolve: 1.20.0
dev: true
- /babel-plugin-polyfill-corejs2/0.2.3_@babel+core@7.16.0:
- resolution: {integrity: sha512-NDZ0auNRzmAfE1oDDPW2JhzIMXUk+FFe2ICejmt5T4ocKgiQx3e0VCRx9NCAidcMtL2RUZaWtXnmjTCkx0tcbA==}
+ /babel-plugin-polyfill-corejs2/0.3.0_@babel+core@7.16.0:
+ resolution: {integrity: sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA==}
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
- '@babel/compat-data': 7.16.0
+ '@babel/compat-data': 7.16.4
'@babel/core': 7.16.0
- '@babel/helper-define-polyfill-provider': 0.2.4_@babel+core@7.16.0
+ '@babel/helper-define-polyfill-provider': 0.3.0_@babel+core@7.16.0
semver: 6.3.0
transitivePeerDependencies:
- supports-color
dev: true
- /babel-plugin-polyfill-corejs3/0.3.0_@babel+core@7.16.0:
- resolution: {integrity: sha512-JLwi9vloVdXLjzACL80j24bG6/T1gYxwowG44dg6HN/7aTPdyPbJJidf6ajoA3RPHHtW0j9KMrSOLpIZpAnPpg==}
+ /babel-plugin-polyfill-corejs3/0.4.0_@babel+core@7.16.0:
+ resolution: {integrity: sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw==}
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.16.0
- '@babel/helper-define-polyfill-provider': 0.2.4_@babel+core@7.16.0
+ '@babel/helper-define-polyfill-provider': 0.3.0_@babel+core@7.16.0
core-js-compat: 3.19.1
transitivePeerDependencies:
- supports-color
dev: true
- /babel-plugin-polyfill-regenerator/0.2.3_@babel+core@7.16.0:
- resolution: {integrity: sha512-JVE78oRZPKFIeUqFGrSORNzQnrDwZR16oiWeGM8ZyjBn2XAT5OjP+wXx5ESuo33nUsFUEJYjtklnsKbxW5L+7g==}
+ /babel-plugin-polyfill-regenerator/0.3.0_@babel+core@7.16.0:
+ resolution: {integrity: sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg==}
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.16.0
- '@babel/helper-define-polyfill-provider': 0.2.4_@babel+core@7.16.0
+ '@babel/helper-define-polyfill-provider': 0.3.0_@babel+core@7.16.0
transitivePeerDependencies:
- supports-color
dev: true
@@ -2063,8 +2065,8 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
- caniuse-lite: 1.0.30001280
- electron-to-chromium: 1.3.899
+ caniuse-lite: 1.0.30001282
+ electron-to-chromium: 1.3.904
escalade: 3.1.1
node-releases: 2.0.1
picocolors: 1.0.0
@@ -2096,8 +2098,8 @@ packages:
engines: {node: '>= 6'}
dev: true
- /caniuse-lite/1.0.30001280:
- resolution: {integrity: sha512-kFXwYvHe5rix25uwueBxC569o53J6TpnGu0BEEn+6Lhl2vsnAumRFWEBhDft1fwyo6m1r4i+RqA4+163FpeFcA==}
+ /caniuse-lite/1.0.30001282:
+ resolution: {integrity: sha512-YhF/hG6nqBEllymSIjLtR2iWDDnChvhnVJqp+vloyt2tEHFG1yBR+ac2B/rOw0qOK0m0lEXU2dv4E/sMk5P9Kg==}
dev: true
/chalk/2.4.2:
@@ -2167,8 +2169,8 @@ packages:
engines: {node: '>= 10'}
dev: true
- /common-tags/1.8.1:
- resolution: {integrity: sha512-uOZd85rJqrdEIE/JjhW5YAeatX8iqjjvVzIyfx7JL7G5r9Tep6YpYT9gEJWhWpVyDQEyzukWd6p2qULpJ8tmBw==}
+ /common-tags/1.8.2:
+ resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
engines: {node: '>=4.0.0'}
dev: true
@@ -2339,8 +2341,8 @@ packages:
jake: 10.8.2
dev: true
- /electron-to-chromium/1.3.899:
- resolution: {integrity: sha512-w16Dtd2zl7VZ4N4Db+FIa7n36sgPGCKjrKvUUmp5ialsikvcQLjcJR9RWnlYNxIyEHLdHaoIZEqKsPxU9MdyBg==}
+ /electron-to-chromium/1.3.904:
+ resolution: {integrity: sha512-x5uZWXcVNYkTh4JubD7KSC1VMKz0vZwJUqVwY3ihsW0bst1BXDe494Uqbg3Y0fDGVjJqA8vEeGuvO5foyH2+qw==}
dev: true
/emoji-regex/8.0.0:
@@ -2601,6 +2603,15 @@ packages:
eslint: 8.2.0
dev: true
+ /eslint-import-resolver-alias/1.1.2_eslint-plugin-import@2.25.3:
+ resolution: {integrity: sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w==}
+ engines: {node: '>= 4'}
+ peerDependencies:
+ eslint-plugin-import: '>=1.4.0'
+ dependencies:
+ eslint-plugin-import: 2.25.3_eslint@8.2.0
+ dev: true
+
/eslint-import-resolver-babel-module/5.3.1_e51044130ac762fd207a8cd2109b5344:
resolution: {integrity: sha512-WomQAkjO7lUNOdU3FG2zgNgylkoAVUmaw04bHgSpM9QrMWuOLLWa2qcP6CrsBd4VWuLRbUPyzrgBc9ZQIx9agw==}
engines: {node: '>=10.0.0'}
@@ -2633,7 +2644,7 @@ packages:
glob: 7.2.0
is-glob: 4.0.3
resolve: 1.20.0
- tsconfig-paths: 3.11.0
+ tsconfig-paths: 3.12.0
transitivePeerDependencies:
- supports-color
dev: true
@@ -2651,7 +2662,7 @@ packages:
glob: 7.2.0
is-glob: 4.0.3
resolve: 1.20.0
- tsconfig-paths: 3.11.0
+ tsconfig-paths: 3.12.0
transitivePeerDependencies:
- supports-color
dev: true
@@ -2684,7 +2695,7 @@ packages:
minimatch: 3.0.4
object.values: 1.1.5
resolve: 1.20.0
- tsconfig-paths: 3.11.0
+ tsconfig-paths: 3.12.0
dev: true
/eslint-plugin-import/2.25.3_eslint@8.2.0:
@@ -2706,7 +2717,7 @@ packages:
minimatch: 3.0.4
object.values: 1.1.5
resolve: 1.20.0
- tsconfig-paths: 3.11.0
+ tsconfig-paths: 3.12.0
dev: true
/eslint-plugin-react-hooks/4.3.0_eslint@7.32.0:
@@ -2727,8 +2738,8 @@ packages:
eslint: 8.2.0
dev: true
- /eslint-plugin-react/7.27.0_eslint@7.32.0:
- resolution: {integrity: sha512-0Ut+CkzpppgFtoIhdzi2LpdpxxBvgFf99eFqWxJnUrO7mMe0eOiNpou6rvNYeVVV6lWZvTah0BFne7k5xHjARg==}
+ /eslint-plugin-react/7.27.1_eslint@7.32.0:
+ resolution: {integrity: sha512-meyunDjMMYeWr/4EBLTV1op3iSG3mjT/pz5gti38UzfM4OPpNc2m0t2xvKCOMU5D6FSdd34BIMFOvQbW+i8GAA==}
engines: {node: '>=4'}
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
@@ -2750,8 +2761,8 @@ packages:
string.prototype.matchall: 4.0.6
dev: true
- /eslint-plugin-react/7.27.0_eslint@8.2.0:
- resolution: {integrity: sha512-0Ut+CkzpppgFtoIhdzi2LpdpxxBvgFf99eFqWxJnUrO7mMe0eOiNpou6rvNYeVVV6lWZvTah0BFne7k5xHjARg==}
+ /eslint-plugin-react/7.27.1_eslint@8.2.0:
+ resolution: {integrity: sha512-meyunDjMMYeWr/4EBLTV1op3iSG3mjT/pz5gti38UzfM4OPpNc2m0t2xvKCOMU5D6FSdd34BIMFOvQbW+i8GAA==}
engines: {node: '>=4'}
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
@@ -2940,8 +2951,8 @@ packages:
resolution: {integrity: sha512-r5EQJcYZ2oaGbeR0jR0fFVijGOcwai07/690YRXLINuhmVeRY4UKSAsQPe/0BNuDgwP7Ophoc1PRsr2E3tkbdQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
- acorn: 8.5.0
- acorn-jsx: 5.3.2_acorn@8.5.0
+ acorn: 8.6.0
+ acorn-jsx: 5.3.2_acorn@8.6.0
eslint-visitor-keys: 3.1.0
dev: true
@@ -3260,8 +3271,8 @@ packages:
'@babel/runtime': 7.16.3
dev: false
- /i18next/21.5.1:
- resolution: {integrity: sha512-fmpns1dbYYgyOkiATp1rg5gyXzvBdvM0YQFDCM38BoqybG2Rs3looAv+e24ghFeeozD1fteUtDTZ36SQ0a+ycg==}
+ /i18next/21.5.2:
+ resolution: {integrity: sha512-Iuztr2+7CPCh5SYQV0utw2HXMx1za18xfznrw/PmgX+98oIpm84bhIM7VUPODjLycwIZ299oP7sEVQ9oCgmzfg==}
dependencies:
'@babel/runtime': 7.16.3
dev: false
@@ -3516,7 +3527,7 @@ packages:
resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==}
engines: {node: '>= 10.13.0'}
dependencies:
- '@types/node': 16.11.7
+ '@types/node': 16.11.9
merge-stream: 2.0.0
supports-color: 7.2.0
dev: true
@@ -4091,15 +4102,16 @@ packages:
tinycolor2: 1.4.2
dev: false
- /react-hook-form/7.19.5_react@17.0.2:
- resolution: {integrity: sha512-+M9gd0nWWASuEitf5PQGOGNElnHknzY3rGISrPDXwsOmZb7c/jyvkRUqk4OJXaZit1ZwesSv+EysttdAeFEfmw==}
+ /react-hook-form/7.20.2_react@17.0.2:
+ resolution: {integrity: sha512-J5zkZW0Mf3KuMlk7Tl1tWYXoSjYhfKyEu//NfWTn2xzvv2vnDT5/EE/vHgtNb7kVeYpx6/mHIBd9aOfNnWcOsg==}
+ engines: {node: '>=12.0'}
peerDependencies:
react: ^16.8.0 || ^17
dependencies:
react: 17.0.2
dev: false
- /react-i18next/11.14.2_i18next@21.5.1+react@17.0.2:
+ /react-i18next/11.14.2_i18next@21.5.2+react@17.0.2:
resolution: {integrity: sha512-fmDhwNA0zDmSEL3BBT5qwNMvxrKu25oXDDAZyHprfB0AHZmWXfBmRLf8MX8i1iBd2I2C2vsA2D9wxYBIwzooEQ==}
peerDependencies:
i18next: '>= 19.0.0'
@@ -4107,7 +4119,7 @@ packages:
dependencies:
'@babel/runtime': 7.16.3
html-parse-stringify: 3.0.1
- i18next: 21.5.1
+ i18next: 21.5.2
react: 17.0.2
dev: false
@@ -4254,8 +4266,8 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
- /reselect/4.1.3:
- resolution: {integrity: sha512-TVpMknnmdSRNhLPgTDSCQKw32zt1ZIJtEcSxfL/ihtDqShEMUs2X2UY/g96YAVynUXxqLWSXObLGIcqKHQObHw==}
+ /reselect/4.1.4:
+ resolution: {integrity: sha512-i1LgXw8DKSU5qz1EV0ZIKz4yIUHJ7L3bODh+Da6HmVSm9vdL/hG7IpbgzQ3k2XSirzf8/eI7OMEs81gb1VV2fQ==}
/resolve-from/4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
@@ -4403,8 +4415,8 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
- /source-map-support/0.5.20:
- resolution: {integrity: sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==}
+ /source-map-support/0.5.21:
+ resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
dependencies:
buffer-from: 1.1.2
source-map: 0.6.1
@@ -4543,7 +4555,7 @@ packages:
resolution: {integrity: sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw==}
engines: {node: '>=10.0.0'}
dependencies:
- ajv: 8.8.0
+ ajv: 8.8.1
lodash.truncate: 4.4.2
slice-ansi: 4.0.0
string-width: 4.2.3
@@ -4624,7 +4636,7 @@ packages:
dependencies:
commander: 2.20.3
source-map: 0.7.3
- source-map-support: 0.5.20
+ source-map-support: 0.5.21
dev: true
/text-table/0.2.0:
@@ -4673,8 +4685,8 @@ packages:
punycode: 2.1.1
dev: true
- /tsconfig-paths/3.11.0:
- resolution: {integrity: sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==}
+ /tsconfig-paths/3.12.0:
+ resolution: {integrity: sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==}
dependencies:
'@types/json5': 0.0.29
json5: 1.0.1
@@ -4686,14 +4698,14 @@ packages:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
dev: true
- /tsutils/3.21.0_typescript@4.4.4:
+ /tsutils/3.21.0_typescript@4.5.2:
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies:
tslib: 1.14.1
- typescript: 4.4.4
+ typescript: 4.5.2
dev: true
/type-check/0.4.0:
@@ -4719,8 +4731,8 @@ packages:
history: 5.1.0
dev: false
- /typescript/4.4.4:
- resolution: {integrity: sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==}
+ /typescript/4.5.2:
+ resolution: {integrity: sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==}
engines: {node: '>=4.2.0'}
hasBin: true
dev: true
@@ -4803,8 +4815,8 @@ packages:
resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==}
dev: true
- /vite-plugin-pwa/0.11.5_vite@2.6.14:
- resolution: {integrity: sha512-qn79L7008ZMn9GS0ClxypOBRA3Ft8/a8saIQ03SC2R1QndbZVW+YQVHTlFno33Wp6fu5UJacoHWuZYCuKZKaOA==}
+ /vite-plugin-pwa/0.11.6_vite@2.6.14:
+ resolution: {integrity: sha512-C95xVO8csEedN29aHszKjRSb/P7Odd6+tCP3LfjqQQkNRkZPieT6y8mS5MlEbs9V+8D+z4THD6ksYB5mzLTzPg==}
peerDependencies:
vite: ^2.0.0
dependencies:
@@ -4924,16 +4936,16 @@ packages:
resolution: {integrity: sha512-cvH74tEO8SrziFrCntZ/35B0uaMZFKG+gnk3vZmKLSUTab/6MlhL+UwYXf1sMV5SD/W/v7pnFKZbdAOAg5Ne2w==}
engines: {node: '>=10.0.0'}
dependencies:
- '@apideck/better-ajv-errors': 0.2.7_ajv@8.8.0
+ '@apideck/better-ajv-errors': 0.2.7_ajv@8.8.1
'@babel/core': 7.16.0
- '@babel/preset-env': 7.16.0_@babel+core@7.16.0
+ '@babel/preset-env': 7.16.4_@babel+core@7.16.0
'@babel/runtime': 7.16.3
'@rollup/plugin-babel': 5.3.0_@babel+core@7.16.0+rollup@2.60.0
'@rollup/plugin-node-resolve': 11.2.1_rollup@2.60.0
'@rollup/plugin-replace': 2.4.2_rollup@2.60.0
'@surma/rollup-plugin-off-main-thread': 2.2.3
- ajv: 8.8.0
- common-tags: 1.8.1
+ ajv: 8.8.1
+ common-tags: 1.8.2
fast-json-stable-stringify: 2.1.0
fs-extra: 9.1.0
glob: 7.2.0
diff --git a/src/App.tsx b/src/App.tsx
index 2284ac14..c8651625 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,34 +1,14 @@
import React from 'react';
-import { useAppDispatch, useAppSelector } from '@app/hooks/redux';
-import { DeviceStatusDropdown } from '@components/menu/buttons/DeviceStatusDropdown';
+import { DeviceStatus } from '@app/components/menu/buttons/DeviceStatus';
+import { useAppSelector } from '@app/hooks/redux';
+import { Connection } from '@components/Connection';
import { MobileNavToggle } from '@components/menu/buttons/MobileNavToggle';
import { ThemeToggle } from '@components/menu/buttons/ThemeToggle';
import { Logo } from '@components/menu/Logo';
import { MobileNav } from '@components/menu/MobileNav';
import { Navigation } from '@components/menu/Navigation';
-import { connection, setConnection } from '@core/connection';
import { useRoute } from '@core/router';
-import {
- addChannel,
- addMessage,
- addNode,
- addPosition,
- addUser,
- setDeviceStatus,
- setLastMeshInterraction,
- setMyNodeInfo,
- setPreferences,
- setReady,
-} from '@core/slices/meshtasticSlice';
-import {
- IBLEConnection,
- IHTTPConnection,
- ISerialConnection,
- Protobuf,
- SettingsManager,
- Types,
-} from '@meshtastic/meshtasticjs';
import { Messages } from '@pages/Messages';
import { Nodes } from '@pages/Nodes/Index';
import { Settings } from '@pages/settings/Index';
@@ -36,128 +16,13 @@ import { Settings } from '@pages/settings/Index';
import { NotFound } from './pages/NotFound';
import { Plugins } from './pages/Plugins/Index';
-const App = (): JSX.Element => {
- const dispatch = useAppDispatch();
+export const App = (): JSX.Element => {
const route = useRoute();
-
- const myNodeInfo = useAppSelector((state) => state.meshtastic.myNodeInfo);
const darkMode = useAppSelector((state) => state.app.darkMode);
- const hostOverrideEnabled = useAppSelector(
- (state) => state.meshtastic.hostOverrideEnabled,
- );
-
- const hostOverride = useAppSelector((state) => state.meshtastic.hostOverride);
-
- const connectionURL = hostOverrideEnabled
- ? hostOverride
- : import.meta.env.PROD
- ? window.location.hostname
- : (import.meta.env.VITE_PUBLIC_DEVICE_IP as string) ??
- 'http://meshtastic.local';
-
- React.useEffect(() => {
- const connectionMethod = localStorage.getItem('connectionMethod');
-
- switch (connectionMethod) {
- case 'serial':
- setConnection(new ISerialConnection());
- //show connection dialogue
- break;
- case 'bluetooth':
- setConnection(new IBLEConnection());
- //show connection dialogue
- break;
- default:
- setConnection(new IHTTPConnection());
- void connection.connect({
- address: connectionURL,
- tls: false,
- receiveBatchRequests: false,
- fetchInterval: 2000,
- });
- break;
- }
- SettingsManager.debugMode = Protobuf.LogRecord_Level.TRACE;
- }, [hostOverrideEnabled, hostOverride, connectionURL]);
-
- React.useEffect(() => {
- connection.onDeviceStatus.subscribe((status) => {
- dispatch(setDeviceStatus(status));
-
- if (status === Types.DeviceStatusEnum.DEVICE_CONFIGURED) {
- dispatch(setReady(true));
- }
- if (status === Types.DeviceStatusEnum.DEVICE_DISCONNECTED) {
- dispatch(setReady(false));
- }
- });
-
- connection.onMyNodeInfo.subscribe((nodeInfo) => {
- dispatch(setMyNodeInfo(nodeInfo));
- });
-
- connection.onUserPacket.subscribe((user) => {
- dispatch(addUser(user));
- });
-
- connection.onPositionPacket.subscribe((position) => {
- dispatch(addPosition(position));
- });
-
- connection.onNodeInfoPacket.subscribe(
- (nodeInfoPacket): void | { payload: Protobuf.NodeInfo; type: string } => {
- dispatch(addNode(nodeInfoPacket.data));
- },
- );
-
- connection.onAdminPacket.subscribe((adminPacket) => {
- switch (adminPacket.data.variant.oneofKind) {
- case 'getChannelResponse':
- dispatch(addChannel(adminPacket.data.variant.getChannelResponse));
- break;
- case 'getRadioResponse':
- if (adminPacket.data.variant.getRadioResponse.preferences) {
- dispatch(
- setPreferences(
- adminPacket.data.variant.getRadioResponse.preferences,
- ),
- );
- }
- break;
- }
- });
-
- connection.onMeshHeartbeat.subscribe(
- (date): void | { payload: number; type: string } =>
- dispatch(setLastMeshInterraction(date.getTime())),
- );
-
- connection.onTextPacket.subscribe((message) => {
- dispatch(
- addMessage({
- message: message,
- ack: message.packet.from !== myNodeInfo.myNodeNum,
- isSender: message.packet.from === myNodeInfo.myNodeNum,
- received: new Date(message.packet.rxTime),
- }),
- );
- });
-
- return (): void => {
- connection.onDeviceStatus.cancelAll();
- connection.onMyNodeInfo.cancelAll();
- connection.onNodeInfoPacket.cancelAll();
- connection.onAdminPacket.cancelAll();
- connection.onMeshHeartbeat.cancelAll();
- connection.onTextPacket.cancelAll();
- connection.onRoutingPacket.cancelAll();
- };
- }, [dispatch, myNodeInfo.myNodeNum]);
return (
-
+
+
@@ -168,7 +33,7 @@ const App = (): JSX.Element => {
-
+
@@ -189,5 +54,3 @@ const App = (): JSX.Element => {
);
};
-
-export default App;
diff --git a/src/components/Connection.tsx b/src/components/Connection.tsx
new file mode 100644
index 00000000..0747d6eb
--- /dev/null
+++ b/src/components/Connection.tsx
@@ -0,0 +1,269 @@
+import React from 'react';
+
+import { FiCheck } from 'react-icons/fi';
+import JSONPretty from 'react-json-pretty';
+
+import { useAppDispatch, useAppSelector } from '@app/hooks/redux';
+import { Button } from '@components/generic/Button';
+import { Card } from '@components/generic/Card';
+import { Checkbox } from '@components/generic/form/Checkbox';
+import { Input } from '@components/generic/form/Input';
+import { Select } from '@components/generic/form/Select';
+import { IconButton } from '@components/generic/IconButton';
+import { Modal } from '@components/generic/Modal';
+import {
+ ble,
+ connection,
+ connectionUrl,
+ serial,
+ setConnection,
+} from '@core/connection';
+import { closeConnectionModal } from '@core/slices/appSlice';
+import {
+ IBLEConnection,
+ IHTTPConnection,
+ ISerialConnection,
+ Protobuf,
+ SettingsManager,
+} from '@meshtastic/meshtasticjs';
+import type {
+ BLEConnectionParameters,
+ HTTPConnectionParameters,
+ SerialConnectionParameters,
+} from '@meshtastic/meshtasticjs/dist/types';
+
+import { DeviceStatus } from './menu/buttons/DeviceStatus';
+
+enum connType {
+ HTTP,
+ BLE,
+ SERIAL,
+}
+
+export const Connection = (): JSX.Element => {
+ const dispatch = useAppDispatch();
+ const [selectedConnType, setSelectedConnType] = React.useState(connType.HTTP);
+ const [bleDevices, setBleDevices] = React.useState
([]);
+ const [serialDevices, setSerialDevices] = React.useState([]);
+ const [httpIpSource, setHttpIpSource] = React.useState<'local' | 'remote'>(
+ 'local',
+ );
+ const hostOverrideEnabled = useAppSelector(
+ (state) => state.meshtastic.hostOverrideEnabled,
+ );
+ const hostOverride = useAppSelector((state) => state.meshtastic.hostOverride);
+ const connectionModalOpen = useAppSelector(
+ (state) => state.app.connectionModalOpen,
+ );
+ const ready = useAppSelector((state) => state.meshtastic.ready);
+ const connect = async (
+ connectionType: connType,
+ params:
+ | HTTPConnectionParameters
+ | SerialConnectionParameters
+ | BLEConnectionParameters,
+ ): Promise => {
+ connection.complete();
+ await connection.disconnect();
+
+ if (connectionType === connType.BLE) {
+ setConnection(new IBLEConnection());
+ } else if (connectionType === connType.HTTP) {
+ setConnection(new IHTTPConnection());
+ } else {
+ setConnection(new ISerialConnection());
+ }
+
+ // @ts-ignore tmp
+ await connection.connect(params);
+ };
+
+ const updateBleDeviceList = React.useCallback(async (): Promise => {
+ const devices = await ble.getDevices();
+ setBleDevices(devices);
+ }, []);
+
+ const updateSerialDeviceList = React.useCallback(async (): Promise => {
+ const devices = await serial.getPorts();
+ setSerialDevices(devices);
+ }, []);
+
+ React.useEffect(() => {
+ if (ready) {
+ dispatch(closeConnectionModal());
+ }
+ }, [ready, dispatch]);
+
+ React.useEffect(() => {
+ if (selectedConnType === connType.BLE) {
+ void updateBleDeviceList();
+ }
+ if (selectedConnType === connType.SERIAL) {
+ void updateSerialDeviceList();
+ }
+ }, [selectedConnType, updateBleDeviceList, updateSerialDeviceList]);
+
+ React.useEffect(() => {
+ const connectionMethod = localStorage.getItem('connectionMethod');
+
+ switch (connectionMethod) {
+ case 'serial':
+ setConnection(new ISerialConnection());
+ //show connection dialogue
+ break;
+ case 'bluetooth':
+ setConnection(new IBLEConnection());
+ //show connection dialogue
+ break;
+ default:
+ setConnection(new IHTTPConnection());
+ void connection.connect({
+ address: connectionUrl,
+ tls: false,
+ receiveBatchRequests: false,
+ fetchInterval: 2000,
+ });
+ break;
+ }
+ SettingsManager.debugMode = Protobuf.LogRecord_Level.TRACE;
+ }, [hostOverrideEnabled, hostOverride]);
+
+ return (
+ {
+ dispatch(closeConnectionModal());
+ }}
+ >
+
+
+ {ready ? (
+
+ ) : (
+
+
+
+ )}
+
+
+
+ );
+};
diff --git a/src/components/LoraConfig.tsx b/src/components/LoraConfig.tsx
index 4c474464..c57ffc37 100644
--- a/src/components/LoraConfig.tsx
+++ b/src/components/LoraConfig.tsx
@@ -2,14 +2,13 @@ import React from 'react';
import { useForm } from 'react-hook-form';
+import { Card } from '@components/generic/Card';
+import { Checkbox } from '@components/generic/form/Checkbox';
+import { Input } from '@components/generic/form/Input';
import { Loading } from '@components/generic/Loading';
+import { connection } from '@core/connection';
import { Protobuf } from '@meshtastic/meshtasticjs';
-import { connection } from '../core/connection';
-import { Card } from './generic/Card';
-import { Checkbox } from './generic/form/Checkbox';
-import { Input } from './generic/form/Input';
-
export interface LoraConfigProps {
channel: Protobuf.Channel;
}
diff --git a/src/components/chat/MessageBar.tsx b/src/components/chat/MessageBar.tsx
index 0c3c1b82..8406b00d 100644
--- a/src/components/chat/MessageBar.tsx
+++ b/src/components/chat/MessageBar.tsx
@@ -3,30 +3,42 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import { FiSend } from 'react-icons/fi';
-import { ackMessage } from '@app/core/slices/meshtasticSlice';
import { useAppDispatch, useAppSelector } from '@app/hooks/redux';
import { Input } from '@components/generic/form/Input';
import { connection } from '@core/connection';
+import { ackMessage } from '@core/slices/meshtasticSlice';
import { Select } from '../generic/form/Select';
import { IconButton } from '../generic/IconButton';
-export const MessageBar = (): JSX.Element => {
+export interface MessageBarProps {
+ channelIndex: number;
+}
+
+export const MessageBar = ({ channelIndex }: MessageBarProps): JSX.Element => {
const dispatch = useAppDispatch();
const ready = useAppSelector((state) => state.meshtastic.ready);
const nodes = useAppSelector((state) => state.meshtastic.nodes);
- const users = useAppSelector((state) => state.meshtastic.users);
- const myNodeInfo = useAppSelector((state) => state.meshtastic.myNodeInfo);
+ const myNodeNum = useAppSelector(
+ (state) => state.meshtastic.radio.hardware,
+ ).myNodeNum;
+
const [currentMessage, setCurrentMessage] = React.useState('');
const [destinationNode, setDestinationNode] =
React.useState(0xffffffff);
const sendMessage = (): void => {
if (ready) {
- void connection.sendText(currentMessage, destinationNode, true, (id) => {
- dispatch(ackMessage(id));
+ void connection.sendText(
+ currentMessage,
+ destinationNode,
+ true,
+ channelIndex--,
+ (id) => {
+ dispatch(ackMessage({ channel: 0, messageId: id }));
- return Promise.resolve();
- });
+ return Promise.resolve();
+ },
+ );
setCurrentMessage('');
}
};
@@ -51,14 +63,11 @@ export const MessageBar = (): JSX.Element => {
value: 0xffffffff,
},
...nodes
- .filter((node) => node.num !== myNodeInfo.myNodeNum)
+ .filter((node) => node.number !== myNodeNum)
.map((node) => {
- const user = users.filter(
- (user) => user.packet.from === node.num,
- )[0]?.data;
return {
- name: user ? user.shortName : node.num,
- value: node.num,
+ name: node.user ? node.user.shortName : node.number,
+ value: node.number,
};
}),
]}
diff --git a/src/components/generic/Blur.tsx b/src/components/generic/Blur.tsx
index 14e21709..90446ce1 100644
--- a/src/components/generic/Blur.tsx
+++ b/src/components/generic/Blur.tsx
@@ -15,14 +15,14 @@ export const Blur = ({
return (
diff --git a/src/components/generic/Button.tsx b/src/components/generic/Button.tsx
index 3bd6a66b..51dad900 100644
--- a/src/components/generic/Button.tsx
+++ b/src/components/generic/Button.tsx
@@ -9,6 +9,7 @@ interface ButtonProps extends DefaultButtonProps {
circle?: boolean;
active?: boolean;
border?: boolean;
+ padding?: number;
confirmAction?: () => void;
}
@@ -21,6 +22,7 @@ export const Button = ({
confirmAction,
disabled,
children,
+ padding = 3,
...props
}: ButtonProps): JSX.Element => {
const [hasConfirmed, setHasConfirmed] = React.useState(false);
@@ -43,7 +45,9 @@ export const Button = ({
className={`items-center select-none flex dark:text-white active:scale-95 transition duration-200 ease-in-out ${
active && !disabled ? 'bg-gray-100 dark:bg-gray-700' : ''
} ${
- circle ? 'rounded-full h-10 w-10' : 'rounded-md p-3 space-x-3 text-sm'
+ circle
+ ? 'rounded-full h-10 w-10'
+ : `rounded-md p-${padding} space-x-3 text-sm`
} ${
disabled
? 'cursor-not-allowed dark:bg-primaryDark bg-white'
diff --git a/src/components/generic/Card.tsx b/src/components/generic/Card.tsx
index 2fd8d264..ed86e2fd 100644
--- a/src/components/generic/Card.tsx
+++ b/src/components/generic/Card.tsx
@@ -24,7 +24,7 @@ export const Card = ({
}: CardProps): JSX.Element => {
return (
{loading &&
}
diff --git a/src/components/generic/Modal.tsx b/src/components/generic/Modal.tsx
new file mode 100644
index 00000000..1ee81f48
--- /dev/null
+++ b/src/components/generic/Modal.tsx
@@ -0,0 +1,37 @@
+import type React from 'react';
+
+import { useAppSelector } from '@app/hooks/redux';
+import { Dialog } from '@headlessui/react';
+
+export interface ModalProps {
+ children: React.ReactNode;
+ open: boolean;
+ onClose: () => void;
+}
+
+export const Modal = ({ children, open, onClose }: ModalProps): JSX.Element => {
+ const darkMode = useAppSelector((state) => state.app.darkMode);
+ return (
+ <>
+
+ >
+ );
+};
diff --git a/src/components/generic/StatCard.tsx b/src/components/generic/StatCard.tsx
index 625f4f5d..c4554e48 100644
--- a/src/components/generic/StatCard.tsx
+++ b/src/components/generic/StatCard.tsx
@@ -7,7 +7,7 @@ export interface StatCardProps {
export const StatCard = ({ title, value }: StatCardProps): JSX.Element => {
return (
-
+
{title}
{value}
diff --git a/src/components/menu/buttons/DeviceStatusDropdown.tsx b/src/components/menu/buttons/DeviceStatus.tsx
similarity index 56%
rename from src/components/menu/buttons/DeviceStatusDropdown.tsx
rename to src/components/menu/buttons/DeviceStatus.tsx
index 764b91d3..0d9ea68c 100644
--- a/src/components/menu/buttons/DeviceStatusDropdown.tsx
+++ b/src/components/menu/buttons/DeviceStatus.tsx
@@ -2,20 +2,28 @@ import type React from 'react';
import { FiWifi, FiWifiOff } from 'react-icons/fi';
-import { useAppSelector } from '@app/hooks/redux';
-import { IconButton } from '@components/generic/IconButton';
+import { useAppDispatch, useAppSelector } from '@app/hooks/redux';
+import { Button } from '@components/generic/Button';
+import { openConnectionModal } from '@core/slices/appSlice';
import { Types } from '@meshtastic/meshtasticjs';
-export const DeviceStatusDropdown = (): JSX.Element => {
+export const DeviceStatus = (): JSX.Element => {
+ const dispatch = useAppDispatch();
const deviceStatus = useAppSelector((state) => state.meshtastic.deviceStatus);
const ready = useAppSelector((state) => state.meshtastic.ready);
return (
-
-
+
+
);
};
diff --git a/src/components/pwa/ReloadPrompt.tsx b/src/components/pwa/ReloadPrompt.tsx
index 977e5033..c1c0da45 100644
--- a/src/components/pwa/ReloadPrompt.tsx
+++ b/src/components/pwa/ReloadPrompt.tsx
@@ -6,7 +6,7 @@ import type React from 'react';
// eslint-disable-next-line import/no-unresolved
import { useRegisterSW } from 'virtual:pwa-register/react';
-const ReloadPrompt = (): JSX.Element => {
+export const ReloadPrompt = (): JSX.Element => {
const {
offlineReady: [offlineReady, setOfflineReady],
needRefresh: [needRefresh, setNeedRefresh],
@@ -58,5 +58,3 @@ const ReloadPrompt = (): JSX.Element => {
);
};
-
-export default ReloadPrompt;
diff --git a/src/core/connection.ts b/src/core/connection.ts
index 8ecd2242..f1166f6f 100644
--- a/src/core/connection.ts
+++ b/src/core/connection.ts
@@ -1,16 +1,119 @@
+import {
+ addChannel,
+ addMessage,
+ addNode,
+ addPosition,
+ addUser,
+ setDeviceStatus,
+ setLastMeshInterraction,
+ setMyNodeInfo,
+ setPreferences,
+ setReady,
+} from '@core/slices/meshtasticSlice';
+import { store } from '@core/store';
import {
IBLEConnection,
IHTTPConnection,
ISerialConnection,
+ Protobuf,
+ Types,
} from '@meshtastic/meshtasticjs';
type connectionType = IBLEConnection | IHTTPConnection | ISerialConnection;
export let connection: connectionType = new IHTTPConnection();
+const state = store.getState().meshtastic;
+export const connectionUrl = state.hostOverrideEnabled
+ ? state.hostOverride
+ : import.meta.env.PROD
+ ? window.location.hostname
+ : (import.meta.env.VITE_PUBLIC_DEVICE_IP as string) ??
+ 'http://meshtastic.local';
+
export const ble = new IBLEConnection();
export const serial = new ISerialConnection();
export const setConnection = (conn: connectionType): void => {
+ cleanupListeners();
connection = conn;
+
+ registerListeners();
+};
+
+const cleanupListeners = (): void => {
+ connection.onDeviceStatus.cancelAll();
+ connection.onMyNodeInfo.cancelAll();
+ connection.onUserPacket.cancelAll();
+ connection.onPositionPacket.cancelAll();
+ connection.onNodeInfoPacket.cancelAll();
+ connection.onAdminPacket.cancelAll();
+ connection.onMeshHeartbeat.cancelAll();
+ connection.onTextPacket.cancelAll();
+};
+
+const registerListeners = (): void => {
+ connection.onDeviceStatus.subscribe((status) => {
+ store.dispatch(setDeviceStatus(status));
+
+ if (status === Types.DeviceStatusEnum.DEVICE_CONFIGURED) {
+ store.dispatch(setReady(true));
+ }
+ if (status === Types.DeviceStatusEnum.DEVICE_DISCONNECTED) {
+ store.dispatch(setReady(false));
+ }
+ });
+
+ connection.onMyNodeInfo.subscribe((nodeInfo) => {
+ store.dispatch(setMyNodeInfo(nodeInfo));
+ });
+
+ connection.onUserPacket.subscribe((user) => {
+ store.dispatch(addUser(user));
+ });
+
+ connection.onPositionPacket.subscribe((position) => {
+ store.dispatch(addPosition(position));
+ });
+
+ connection.onNodeInfoPacket.subscribe(
+ (nodeInfoPacket): void | { payload: Protobuf.NodeInfo; type: string } => {
+ store.dispatch(addNode(nodeInfoPacket.data));
+ },
+ );
+
+ connection.onAdminPacket.subscribe((adminPacket) => {
+ switch (adminPacket.data.variant.oneofKind) {
+ case 'getChannelResponse':
+ store.dispatch(addChannel(adminPacket.data.variant.getChannelResponse));
+ break;
+ case 'getRadioResponse':
+ if (adminPacket.data.variant.getRadioResponse.preferences) {
+ store.dispatch(
+ setPreferences(
+ adminPacket.data.variant.getRadioResponse.preferences,
+ ),
+ );
+ }
+ break;
+ }
+ });
+
+ connection.onMeshHeartbeat.subscribe(
+ (date): void | { payload: number; type: string } =>
+ store.dispatch(setLastMeshInterraction(date.getTime())),
+ );
+
+ connection.onTextPacket.subscribe((message) => {
+ const myNodeNum = store.getState().meshtastic.radio.hardware.myNodeNum;
+
+ store.dispatch(
+ addMessage({
+ message: message,
+ ack: message.packet.from !== myNodeNum,
+ isSender: message.packet.from === myNodeNum,
+ received: new Date(message.packet.rxTime),
+ }),
+ );
+ });
};
diff --git a/src/core/slices/appSlice.ts b/src/core/slices/appSlice.ts
index 6016aa5f..c2a5550b 100644
--- a/src/core/slices/appSlice.ts
+++ b/src/core/slices/appSlice.ts
@@ -5,12 +5,14 @@ export type currentPageName = 'messages' | 'settings';
interface AppState {
mobileNavOpen: boolean;
+ connectionModalOpen: boolean;
darkMode: boolean;
currentPage: currentPageName;
}
const initialState: AppState = {
mobileNavOpen: false,
+ connectionModalOpen: true,
darkMode: localStorage.getItem('darkMode') === 'true' ?? false,
currentPage: 'messages',
};
@@ -25,6 +27,12 @@ export const appSlice = createSlice({
closeMobileNav(state) {
state.mobileNavOpen = false;
},
+ openConnectionModal(state) {
+ state.connectionModalOpen = true;
+ },
+ closeConnectionModal(state) {
+ state.connectionModalOpen = false;
+ },
setDarkModeEnabled(state, action: PayloadAction
) {
localStorage.setItem('darkMode', String(action.payload));
state.darkMode = action.payload;
@@ -38,6 +46,8 @@ export const appSlice = createSlice({
export const {
openMobileNav,
closeMobileNav,
+ openConnectionModal,
+ closeConnectionModal,
setDarkModeEnabled,
setCurrentPage,
} = appSlice.actions;
diff --git a/src/core/slices/meshtasticSlice.ts b/src/core/slices/meshtasticSlice.ts
index 6ddf887b..9132c459 100644
--- a/src/core/slices/meshtasticSlice.ts
+++ b/src/core/slices/meshtasticSlice.ts
@@ -2,7 +2,7 @@ import { Protobuf, Types } from '@meshtastic/meshtasticjs';
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
-import { connection } from '../connection';
+// import { connection } from '../connection';
export interface MessageWithAck {
message: Types.TextPacket;
@@ -16,17 +16,31 @@ enum connType {
SERIAL,
}
+export interface ChannelData {
+ channel: Protobuf.Channel;
+ messages: MessageWithAck[];
+}
+
+export interface Node {
+ number: number;
+ lastHeard: Date;
+ snr: number[];
+ positions: Protobuf.Position[];
+ user?: Protobuf.User;
+}
+
+export interface Radio {
+ channels: ChannelData[];
+ preferences: Protobuf.RadioConfig_UserPreferences;
+ hardware: Protobuf.MyNodeInfo;
+}
+
interface MeshtasticState {
deviceStatus: Types.DeviceStatusEnum;
lastMeshInterraction: number;
ready: boolean;
- myNodeInfo: Protobuf.MyNodeInfo;
- users: Types.UserPacket[];
- positionPackets: Types.PositionPacket[];
- nodes: Protobuf.NodeInfo[];
- channels: Protobuf.Channel[];
- preferences: Protobuf.RadioConfig_UserPreferences;
- messages: MessageWithAck[];
+ nodes: Node[];
+ radio: Radio;
hostOverrideEnabled: boolean;
hostOverride: string;
connectionType: connType;
@@ -36,13 +50,12 @@ const initialState: MeshtasticState = {
deviceStatus: Types.DeviceStatusEnum.DEVICE_DISCONNECTED,
lastMeshInterraction: 0,
ready: false,
- myNodeInfo: Protobuf.MyNodeInfo.create(),
- users: [],
- positionPackets: [],
nodes: [],
- channels: [],
- preferences: Protobuf.RadioConfig_UserPreferences.create(),
- messages: [],
+ radio: {
+ channels: [],
+ preferences: Protobuf.RadioConfig_UserPreferences.create(),
+ hardware: Protobuf.MyNodeInfo.create(),
+ },
//todo implement
// connectionMethod: localStorage.getItem('connectionMethod'),
hostOverrideEnabled:
@@ -65,76 +78,94 @@ export const meshtasticSlice = createSlice({
state.ready = action.payload;
},
setMyNodeInfo: (state, action: PayloadAction) => {
- state.myNodeInfo = action.payload;
+ state.radio.hardware = action.payload;
},
addUser: (state, action: PayloadAction) => {
- if (
- state.users.findIndex(
- (user) => user.data.id === action.payload.data.id,
- ) !== -1
- ) {
- state.users = state.users.map((user) => {
- return user.data.id === action.payload.data.id
- ? action.payload
- : user;
- });
- } else {
- state.users.push(action.payload);
+ const node = state.nodes.find(
+ (node) => node.number === action.payload.packet.from,
+ );
+ if (node) {
+ node.user = action.payload.data;
+ // todo: use rx time
+ node.lastHeard = new Date();
}
},
addPosition: (state, action: PayloadAction) => {
- if (
- state.positionPackets.findIndex(
- (position) => position.packet.from === action.payload.packet.from,
- ) !== -1
- ) {
- state.positionPackets = state.positionPackets.map((position) => {
- return position.packet.from === action.payload.packet.from
- ? action.payload
- : position;
- });
- } else {
- state.positionPackets.push(action.payload);
+ const node = state.nodes.find(
+ (node) => node.number === action.payload.packet.from,
+ );
+
+ node?.positions.push(action.payload.data);
+ if (node) {
+ // todo: use rx time
+ node.lastHeard = new Date();
}
},
addNode: (state, action: PayloadAction) => {
- if (
- state.nodes.findIndex((node) => node.num === action.payload.num) !== -1
- ) {
- state.nodes = state.nodes.map((node) => {
- return node.num === action.payload.num ? action.payload : node;
- });
+ const node = state.nodes.find(
+ (node) => node.number === action.payload.num,
+ );
+
+ if (node) {
+ console.log('node exists');
+
+ node.lastHeard = new Date(action.payload.lastHeard * 1000);
+ node.snr.push(action.payload.snr);
} else {
- state.nodes.push(action.payload);
+ console.log('node does not exist');
+
+ state.nodes.push({
+ number: action.payload.num,
+ lastHeard: new Date(action.payload.lastHeard * 1000),
+ snr: [action.payload.snr],
+ positions: [],
+ });
}
},
addChannel: (state, action: PayloadAction) => {
if (
- state.channels.findIndex(
- (channel) => channel.index === action.payload.index,
+ state.radio.channels.findIndex(
+ (channel) => channel.channel.index === action.payload.index,
) !== -1
) {
- state.channels = state.channels.map((channel) => {
- return channel.index === action.payload.index
- ? action.payload
+ state.radio.channels = state.radio.channels.map((channel) => {
+ return channel.channel.index === action.payload.index
+ ? {
+ channel: action.payload,
+ messages: channel.messages,
+ }
: channel;
});
} else {
- state.channels.push(action.payload);
+ state.radio.channels.push({
+ channel: action.payload,
+ messages: [],
+ });
}
},
setPreferences: (
state,
action: PayloadAction,
) => {
- state.preferences = action.payload;
+ state.radio.preferences = action.payload;
},
addMessage: (state, action: PayloadAction) => {
- state.messages.push(action.payload);
+ const channelIndex = state.radio.channels.findIndex(
+ (channel) =>
+ channel.channel.index === action.payload.message.packet.channel,
+ );
+ state.radio.channels[channelIndex].messages.push(action.payload);
},
- ackMessage: (state, messageId: PayloadAction) => {
- state.messages.map((message) => {
- if (message.message.packet.id === messageId.payload) {
+ ackMessage: (
+ state,
+ action: PayloadAction<{ channel: number; messageId: number }>,
+ ) => {
+ const channelIndex = state.radio.channels.findIndex(
+ (channel) => channel.channel.index === action.payload.channel,
+ );
+ // todo: update last mesh/user interraction here
+ state.radio.channels[channelIndex].messages.map((message) => {
+ if (message.message.packet.id === action.payload.messageId) {
message.ack = true;
}
});
@@ -143,21 +174,21 @@ export const meshtasticSlice = createSlice({
state.hostOverrideEnabled = action.payload;
localStorage.setItem('hostOverrideEnabled', String(action.payload));
if (state.hostOverrideEnabled !== action.payload) {
- connection.disconnect();
+ // connection.disconnect();
}
},
setHostOverride: (state, action: PayloadAction) => {
state.hostOverride = action.payload;
localStorage.setItem('hostOverride', action.payload);
if (state.hostOverride !== action.payload) {
- connection.disconnect();
+ // connection.disconnect();
}
},
setConnectionType: (state, action: PayloadAction) => {
state.connectionType = action.payload;
localStorage.setItem('connectionType', String(action.payload));
if (state.connectionType !== action.payload) {
- connection.disconnect();
+ // connection.disconnect();
}
},
},
diff --git a/src/index.tsx b/src/index.tsx
index 78d440ac..c99c7552 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -6,12 +6,11 @@ import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
+import { App } from '@app/App';
+import { ReloadPrompt } from '@components/pwa/ReloadPrompt';
import { RouteProvider } from '@core/router';
import { store } from '@core/store';
-import App from './App';
-import ReloadPrompt from './components/pwa/ReloadPrompt';
-
ReactDOM.render(
diff --git a/src/pages/Messages.tsx b/src/pages/Messages.tsx
index b775207b..e0396996 100644
--- a/src/pages/Messages.tsx
+++ b/src/pages/Messages.tsx
@@ -1,4 +1,4 @@
-import type React from 'react';
+import React from 'react';
import { FiHash } from 'react-icons/fi';
@@ -10,9 +10,9 @@ import { Protobuf } from '@meshtastic/meshtasticjs';
import { useAppSelector } from '../hooks/redux';
export const Messages = (): JSX.Element => {
- const messages = useAppSelector((state) => state.meshtastic.messages);
- const users = useAppSelector((state) => state.meshtastic.users);
- const channels = useAppSelector((state) => state.meshtastic.channels);
+ const nodes = useAppSelector((state) => state.meshtastic.nodes);
+ const channels = useAppSelector((state) => state.meshtastic.radio.channels);
+ const [channelIndex, setChannelIndex] = React.useState(0);
return (
@@ -23,25 +23,28 @@ export const Messages = (): JSX.Element => {
options={channels
.filter(
(channel) =>
- channel.role !== Protobuf.Channel_Role.DISABLED &&
- channel.settings?.name !== 'admin',
+ channel.channel.role !== Protobuf.Channel_Role.DISABLED &&
+ channel.channel.settings?.name !== 'admin',
)
.map((channel) => {
return {
- name: channel.settings?.name.length
- ? channel.settings.name
- : channel.role === Protobuf.Channel_Role.PRIMARY
+ name: channel.channel.settings?.name.length
+ ? channel.channel.settings.name
+ : channel.channel.role === Protobuf.Channel_Role.PRIMARY
? 'Primary'
- : `CH: ${channel.index}`,
- value: channel.index,
+ : `CH: ${channel.channel.index}`,
+ value: channel.channel.index,
};
})}
+ onChange={(e): void => {
+ setChannelIndex(parseInt(e.target.value));
+ }}
small
/>
- {messages.map((message, index) => (
+ {channels[channelIndex]?.messages.map((message, index) => (
{
ack={message.ack}
rxTime={new Date()}
senderName={
- users.find(
- (user) => user.packet.from === message.message.packet.from,
- )?.data.longName ?? 'UNK'
+ nodes.find((node) => node.number === message.message.packet.from)
+ ?.user?.longName ?? 'UNK'
}
/>
))}
-
+
);
};
diff --git a/src/pages/Nodes/Index.tsx b/src/pages/Nodes/Index.tsx
index ffb8ee89..46c8c110 100644
--- a/src/pages/Nodes/Index.tsx
+++ b/src/pages/Nodes/Index.tsx
@@ -9,23 +9,26 @@ import { Protobuf } from '@meshtastic/meshtasticjs';
import { Node } from './Node';
export const Nodes = (): JSX.Element => {
- const nodes = useAppSelector((state) => state.meshtastic.nodes);
- const users = useAppSelector((state) => state.meshtastic.users);
+ const myNodeNum = useAppSelector(
+ (state) => state.meshtastic.radio.hardware,
+ ).myNodeNum;
+ const nodes = useAppSelector((state) => state.meshtastic.nodes).filter(
+ (node) => node.number !== myNodeNum,
+ );
return (
{
- const user = users.find((user) => user.packet.from === node.num)?.data;
return {
- title: user ? user.longName : node.num.toString(),
- description: user
- ? Protobuf.HardwareModel[user.hwModel]
+ title: node.user?.longName ?? node.number.toString(),
+ description: node.user
+ ? Protobuf.HardwareModel[node.user.hwModel]
: 'Unknown Hardware',
icon: (
diff --git a/src/pages/Nodes/Node.tsx b/src/pages/Nodes/Node.tsx
index f399d53f..936fecc7 100644
--- a/src/pages/Nodes/Node.tsx
+++ b/src/pages/Nodes/Node.tsx
@@ -6,33 +6,24 @@ import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
import TimeAgo from 'timeago-react';
-import { Cover } from '@app/components/generic/Cover';
-import { useAppSelector } from '@app/hooks/redux';
import { Card } from '@components/generic/Card';
-import { Checkbox } from '@components/generic/form/Checkbox';
-import { Input } from '@components/generic/form/Input';
+import { Cover } from '@components/generic/Cover';
import { IconButton } from '@components/generic/IconButton';
import { StatCard } from '@components/generic/StatCard';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
-import type { Protobuf } from '@meshtastic/meshtasticjs';
+import type { Node as NodeType } from '@core/slices/meshtasticSlice';
export interface NodeProps {
navOpen?: boolean;
setNavOpen?: React.Dispatch>;
- node: Protobuf.NodeInfo;
+ node: NodeType;
}
export const Node = ({ navOpen, setNavOpen, node }: NodeProps): JSX.Element => {
- const user = useAppSelector((state) => state.meshtastic.users).find(
- (user) => user.packet.from === node.num,
- )?.data;
- const position = useAppSelector(
- (state) => state.meshtastic.positionPackets,
- ).find((position) => position.packet.from === node.num)?.data;
const [debug, setDebug] = React.useState(false);
return (
{
}}
/>
}
- footer={<>>}
>
- ) : (
- 'Never'
- )
+ node.lastHeard ? : 'Never'
}
/>
-
+
} />
-
-
-
-
-
-
+
diff --git a/src/pages/Plugins/ExternalNotification.tsx b/src/pages/Plugins/ExternalNotification.tsx
index f42bf053..8422ca28 100644
--- a/src/pages/Plugins/ExternalNotification.tsx
+++ b/src/pages/Plugins/ExternalNotification.tsx
@@ -1,16 +1,16 @@
-import type React from 'react';
+import React from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { FiMenu } from 'react-icons/fi';
import { FormFooter } from '@app/components/FormFooter';
-import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { Card } from '@components/generic/Card';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Input } from '@components/generic/form/Input';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
+import { connection } from '@core/connection';
import type { RadioConfig_UserPreferences } from '@meshtastic/meshtasticjs/dist/generated';
export interface ExternalNotificationProps {
@@ -22,7 +22,9 @@ export const ExternalNotification = ({
navOpen,
setNavOpen,
}: ExternalNotificationProps): JSX.Element => {
- const preferences = useAppSelector((state) => state.meshtastic.preferences);
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
const { register, handleSubmit, formState, reset, control } =
useForm({
@@ -39,6 +41,19 @@ export const ExternalNotification = ({
},
});
+ React.useEffect(() => {
+ reset({
+ extNotificationPluginActive: preferences.extNotificationPluginActive,
+ extNotificationPluginAlertBell:
+ preferences.extNotificationPluginAlertBell,
+ extNotificationPluginAlertMessage:
+ preferences.extNotificationPluginAlertMessage,
+ extNotificationPluginEnabled: preferences.extNotificationPluginEnabled,
+ extNotificationPluginOutput: preferences.extNotificationPluginOutput,
+ extNotificationPluginOutputMs: preferences.extNotificationPluginOutputMs,
+ });
+ }, [reset, preferences]);
+
const onSubmit = handleSubmit((data) => {
void connection.setPreferences(data);
});
diff --git a/src/pages/Plugins/Files.tsx b/src/pages/Plugins/Files.tsx
index 01504592..6ceb0da8 100644
--- a/src/pages/Plugins/Files.tsx
+++ b/src/pages/Plugins/Files.tsx
@@ -4,11 +4,11 @@ import type React from 'react';
import { FiMenu, FiTrash, FiUploadCloud } from 'react-icons/fi';
import useSWR from 'swr';
-import fetcher from '@app/core/utils/fetcher';
-import { useAppSelector } from '@app/hooks/redux';
import { Card } from '@components/generic/Card';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
+import { connectionUrl } from '@core/connection';
+import fetcher from '@core/utils/fetcher';
export interface RangeTestProps {
navOpen?: boolean;
@@ -33,20 +33,8 @@ interface IFiles {
}
export const Files = ({ navOpen, setNavOpen }: RangeTestProps): JSX.Element => {
- const hostOverrideEnabled = useAppSelector(
- (state) => state.meshtastic.hostOverrideEnabled,
- );
- const hostOverride = useAppSelector((state) => state.meshtastic.hostOverride);
-
- const connectionURL = hostOverrideEnabled
- ? hostOverride
- : import.meta.env.PROD
- ? window.location.hostname
- : (import.meta.env.VITE_PUBLIC_DEVICE_IP as string) ??
- 'http://meshtastic.local';
-
const { data } = useSWR(
- `http://${connectionURL}/json/spiffs/browse/static`,
+ `http://${connectionUrl}/json/spiffs/browse/static`,
fetcher,
);
@@ -107,7 +95,7 @@ export const Files = ({ navOpen, setNavOpen }: RangeTestProps): JSX.Element => {
/> */}
{
className="mx-2 my-auto"
// confirmAction={async (): Promise => {
// await fetch(
- // `http://${connectionURL}/json/spiffs/delete/static?remove=${file.name}`,
+ // `http://${connectionUrl}/json/spiffs/delete/static?remove=${file.name}`,
// {
// method: 'DELETE',
// },
diff --git a/src/pages/Plugins/RangeTest.tsx b/src/pages/Plugins/RangeTest.tsx
index 2ceb88b8..0824442a 100644
--- a/src/pages/Plugins/RangeTest.tsx
+++ b/src/pages/Plugins/RangeTest.tsx
@@ -1,16 +1,16 @@
-import type React from 'react';
+import React from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { FiMenu } from 'react-icons/fi';
-import { FormFooter } from '@app/components/FormFooter';
-import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
+import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Input } from '@components/generic/form/Input';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
+import { connection } from '@core/connection';
import type { RadioConfig_UserPreferences } from '@meshtastic/meshtasticjs/dist/generated';
export interface RangeTestProps {
@@ -22,7 +22,9 @@ export const RangeTest = ({
navOpen,
setNavOpen,
}: RangeTestProps): JSX.Element => {
- const preferences = useAppSelector((state) => state.meshtastic.preferences);
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
const { register, handleSubmit, formState, reset, control } =
useForm({
@@ -33,6 +35,14 @@ export const RangeTest = ({
},
});
+ React.useEffect(() => {
+ reset({
+ rangeTestPluginEnabled: preferences.rangeTestPluginEnabled,
+ rangeTestPluginSave: preferences.rangeTestPluginSave,
+ rangeTestPluginSender: preferences.rangeTestPluginSender,
+ });
+ }, [reset, preferences]);
+
const onSubmit = handleSubmit((data) => {
void connection.setPreferences(data);
});
diff --git a/src/pages/Plugins/Serial.tsx b/src/pages/Plugins/Serial.tsx
index ca528b14..84f44f5e 100644
--- a/src/pages/Plugins/Serial.tsx
+++ b/src/pages/Plugins/Serial.tsx
@@ -1,16 +1,16 @@
-import type React from 'react';
+import React from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { FiMenu } from 'react-icons/fi';
-import { FormFooter } from '@app/components/FormFooter';
-import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
+import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Input } from '@components/generic/form/Input';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
+import { connection } from '@core/connection';
import type { RadioConfig_UserPreferences } from '@meshtastic/meshtasticjs/dist/generated';
export interface SerialProps {
@@ -19,7 +19,9 @@ export interface SerialProps {
}
export const Serial = ({ navOpen, setNavOpen }: SerialProps): JSX.Element => {
- const preferences = useAppSelector((state) => state.meshtastic.preferences);
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
const { register, handleSubmit, formState, reset, control } =
useForm({
@@ -33,6 +35,17 @@ export const Serial = ({ navOpen, setNavOpen }: SerialProps): JSX.Element => {
},
});
+ React.useEffect(() => {
+ reset({
+ serialpluginEnabled: preferences.serialpluginEnabled,
+ serialpluginEcho: preferences.serialpluginEcho,
+ serialpluginMode: preferences.serialpluginMode,
+ serialpluginRxd: preferences.serialpluginRxd,
+ serialpluginTimeout: preferences.serialpluginTimeout,
+ serialpluginTxd: preferences.serialpluginTxd,
+ });
+ }, [reset, preferences]);
+
const onSubmit = handleSubmit((data) => {
void connection.setPreferences(data);
});
diff --git a/src/pages/settings/Channels.tsx b/src/pages/settings/Channels.tsx
index fe96ea47..f12760c8 100644
--- a/src/pages/settings/Channels.tsx
+++ b/src/pages/settings/Channels.tsx
@@ -3,15 +3,15 @@ import React from 'react';
import { FiCode, FiMenu, FiSave } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
-import { LoraConfig } from '@app/components/LoraConfig';
-import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { Channel } from '@components/Channel';
import { Button } from '@components/generic/Button';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { IconButton } from '@components/generic/IconButton';
+import { LoraConfig } from '@components/LoraConfig';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
+import { connection } from '@core/connection';
export interface ChannelsProps {
navOpen?: boolean;
@@ -22,7 +22,7 @@ export const Channels = ({
navOpen,
setNavOpen,
}: ChannelsProps): JSX.Element => {
- const channels = useAppSelector((state) => state.meshtastic.channels);
+ const channels = useAppSelector((state) => state.meshtastic.radio.channels);
const [debug, setDebug] = React.useState(false);
return (
@@ -58,15 +58,15 @@ export const Channels = ({
}
>
- {channels[0] &&
}
+ {channels[0] &&
}
} />
{channels.map((channel) => (
))}
diff --git a/src/pages/settings/Connection.tsx b/src/pages/settings/Connection.tsx
deleted file mode 100644
index b40e6a78..00000000
--- a/src/pages/settings/Connection.tsx
+++ /dev/null
@@ -1,271 +0,0 @@
-import React from 'react';
-
-import { useForm } from 'react-hook-form';
-import { FiCheck, FiMenu } from 'react-icons/fi';
-import JSONPretty from 'react-json-pretty';
-
-import { FormFooter } from '@app/components/FormFooter';
-import { ble, connection, serial, setConnection } from '@app/core/connection';
-import { useAppSelector } from '@app/hooks/redux';
-import { Button } from '@components/generic/Button';
-import { Card } from '@components/generic/Card';
-import { Checkbox } from '@components/generic/form/Checkbox';
-import { Input } from '@components/generic/form/Input';
-import { Select } from '@components/generic/form/Select';
-import { IconButton } from '@components/generic/IconButton';
-import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
-import {
- IBLEConnection,
- IHTTPConnection,
- ISerialConnection,
-} from '@meshtastic/meshtasticjs';
-import type {
- BLEConnectionParameters,
- HTTPConnectionParameters,
- SerialConnectionParameters,
-} from '@meshtastic/meshtasticjs/dist/types';
-
-export interface ConnectionProps {
- navOpen?: boolean;
- setNavOpen?: React.Dispatch
>;
-}
-
-enum connType {
- HTTP,
- BLE,
- SERIAL,
-}
-
-export const Connection = ({
- navOpen,
- setNavOpen,
-}: ConnectionProps): JSX.Element => {
- const [selectedConnType, setSelectedConnType] = React.useState(connType.HTTP);
- const [bleDevices, setBleDevices] = React.useState([]);
- const [serialDevices, setSerialDevices] = React.useState([]);
- const [httpIpSource, setHttpIpSource] = React.useState<'local' | 'remote'>(
- 'local',
- );
- const hostOverrideEnabled = useAppSelector(
- (state) => state.meshtastic.hostOverrideEnabled,
- );
- const hostOverride = useAppSelector((state) => state.meshtastic.hostOverride);
-
- const { formState, reset } = useForm<{
- method: connType;
- }>({
- defaultValues: {
- method: connType.HTTP,
- },
- });
-
- const connect = async (
- connectionType: connType,
- params:
- | HTTPConnectionParameters
- | SerialConnectionParameters
- | BLEConnectionParameters,
- ): Promise => {
- connection.complete();
- connection.disconnect();
-
- if (connectionType === connType.BLE) {
- setConnection(new IBLEConnection());
- } else if (connectionType === connType.HTTP) {
- setConnection(new IHTTPConnection());
- } else {
- setConnection(new ISerialConnection());
- }
-
- // @ts-ignore tmp
- await connection.connect(params);
- };
-
- const updateBleDeviceList = React.useCallback(async (): Promise => {
- const devices = await ble.getDevices();
- setBleDevices(devices);
- }, []);
-
- const updateSerialDeviceList = React.useCallback(async (): Promise => {
- const devices = await serial.getPorts();
- console.log(devices);
-
- setSerialDevices(devices);
- }, []);
-
- React.useEffect(() => {
- if (selectedConnType === connType.BLE) {
- void updateBleDeviceList();
- }
- if (selectedConnType === connType.SERIAL) {
- void updateSerialDeviceList();
- }
- }, [selectedConnType, updateBleDeviceList, updateSerialDeviceList]);
-
- const connectionURL: string = hostOverrideEnabled
- ? hostOverride
- : import.meta.env.PROD
- ? window.location.hostname
- : (import.meta.env.VITE_PUBLIC_DEVICE_IP as string) ??
- 'http://meshtastic.local';
-
- return (
- }
- onClick={(): void => {
- setNavOpen && setNavOpen(!navOpen);
- }}
- />
- }
- footer={
- {
- return;
- }}
- clearAction={reset}
- />
- }
- >
-
-
-
-
-
-
-
- );
-};
diff --git a/src/pages/settings/Index.tsx b/src/pages/settings/Index.tsx
index 2f6c07a8..c4658561 100644
--- a/src/pages/settings/Index.tsx
+++ b/src/pages/settings/Index.tsx
@@ -3,7 +3,6 @@ import type React from 'react';
import {
FiLayers,
FiLayout,
- FiLink2,
FiMapPin,
FiRadio,
FiUser,
@@ -14,7 +13,6 @@ import {
import { PageLayout } from '@components/templates/PageLayout';
import { Channels } from './Channels';
-import { Connection } from './Connection';
import { Interface } from './Interface';
import { Position } from './Position';
import { Power } from './Power';
@@ -24,11 +22,6 @@ import { WiFi } from './WiFi';
export const Settings = (): JSX.Element => {
const sidebarItems = [
- {
- title: 'Connection',
- description: 'Connection method and parameters',
- icon: ,
- },
{
title: 'WiFi',
description: 'WiFi credentials and mode',
@@ -70,7 +63,6 @@ export const Settings = (): JSX.Element => {
title="Settings"
sidebarItems={sidebarItems}
panels={[
- ,
,
,
,
diff --git a/src/pages/settings/Interface.tsx b/src/pages/settings/Interface.tsx
index d89921e1..0c774baa 100644
--- a/src/pages/settings/Interface.tsx
+++ b/src/pages/settings/Interface.tsx
@@ -3,11 +3,11 @@ import type React from 'react';
import { useTranslation } from 'react-i18next';
import { FiMenu, FiSave } from 'react-icons/fi';
-import i18n from '@app/core/translation';
import { Button } from '@components/generic/Button';
import { Card } from '@components/generic/Card';
import { Select } from '@components/generic/form/Select';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
+import i18n from '@core/translation';
export interface InterfaceProps {
navOpen?: boolean;
diff --git a/src/pages/settings/Position.tsx b/src/pages/settings/Position.tsx
index 69466bad..657257d4 100644
--- a/src/pages/settings/Position.tsx
+++ b/src/pages/settings/Position.tsx
@@ -4,9 +4,8 @@ import { useForm } from 'react-hook-form';
import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
-import { FormFooter } from '@app/components/FormFooter';
-import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
+import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { Checkbox } from '@components/generic/form/Checkbox';
@@ -14,6 +13,7 @@ import { Input } from '@components/generic/form/Input';
import { Select } from '@components/generic/form/Select';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
+import { connection } from '@core/connection';
import { Protobuf } from '@meshtastic/meshtasticjs';
export interface PositionProps {
@@ -25,7 +25,9 @@ export const Position = ({
navOpen,
setNavOpen,
}: PositionProps): JSX.Element => {
- const preferences = useAppSelector((state) => state.meshtastic.preferences);
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
const [debug, setDebug] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const { register, handleSubmit, formState, reset } =
@@ -41,6 +43,10 @@ export const Position = ({
},
});
+ React.useEffect(() => {
+ reset(preferences);
+ }, [reset, preferences]);
+
const onSubmit = handleSubmit((data) => {
setLoading(true);
void connection.setPreferences(data, async () => {
diff --git a/src/pages/settings/Power.tsx b/src/pages/settings/Power.tsx
index 65ee9986..f18d5587 100644
--- a/src/pages/settings/Power.tsx
+++ b/src/pages/settings/Power.tsx
@@ -4,15 +4,15 @@ import { useForm } from 'react-hook-form';
import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
-import { FormFooter } from '@app/components/FormFooter';
-import { Select } from '@app/components/generic/form/Select';
-import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
+import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { Checkbox } from '@components/generic/form/Checkbox';
+import { Select } from '@components/generic/form/Select';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
+import { connection } from '@core/connection';
import { Protobuf } from '@meshtastic/meshtasticjs';
export interface PowerProps {
@@ -21,7 +21,9 @@ export interface PowerProps {
}
export const Power = ({ navOpen, setNavOpen }: PowerProps): JSX.Element => {
- const preferences = useAppSelector((state) => state.meshtastic.preferences);
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
const [debug, setDebug] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const { register, handleSubmit, formState, reset } =
@@ -32,6 +34,10 @@ export const Power = ({ navOpen, setNavOpen }: PowerProps): JSX.Element => {
},
});
+ React.useEffect(() => {
+ reset(preferences);
+ }, [reset, preferences]);
+
const onSubmit = handleSubmit((data) => {
setLoading(true);
void connection.setPreferences(data, async () => {
diff --git a/src/pages/settings/Radio.tsx b/src/pages/settings/Radio.tsx
index 9f213b72..c3f64078 100644
--- a/src/pages/settings/Radio.tsx
+++ b/src/pages/settings/Radio.tsx
@@ -4,15 +4,15 @@ import { useForm } from 'react-hook-form';
import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
-import { FormFooter } from '@app/components/FormFooter';
-import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
+import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Select } from '@components/generic/form/Select';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
+import { connection } from '@core/connection';
import { Protobuf } from '@meshtastic/meshtasticjs';
export interface RadioProps {
@@ -21,7 +21,9 @@ export interface RadioProps {
}
export const Radio = ({ navOpen, setNavOpen }: RadioProps): JSX.Element => {
- const preferences = useAppSelector((state) => state.meshtastic.preferences);
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
const [debug, setDebug] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const { register, handleSubmit, formState, reset } =
@@ -29,6 +31,10 @@ export const Radio = ({ navOpen, setNavOpen }: RadioProps): JSX.Element => {
defaultValues: preferences,
});
+ React.useEffect(() => {
+ reset(preferences);
+ }, [reset, preferences]);
+
const onSubmit = handleSubmit((data) => {
setLoading(true);
void connection.setPreferences(data, async () => {
diff --git a/src/pages/settings/User.tsx b/src/pages/settings/User.tsx
index 9a7ec3d2..e5a60eb3 100644
--- a/src/pages/settings/User.tsx
+++ b/src/pages/settings/User.tsx
@@ -5,8 +5,8 @@ import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
import { base16 } from 'rfc4648';
-import { FormFooter } from '@app/components/FormFooter';
-import { useAppDispatch, useAppSelector } from '@app/hooks/redux';
+import { useAppSelector } from '@app/hooks/redux';
+import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { Checkbox } from '@components/generic/form/Checkbox';
@@ -15,7 +15,6 @@ import { Select } from '@components/generic/form/Select';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
-import { addUser } from '@core/slices/meshtasticSlice';
import { Protobuf } from '@meshtastic/meshtasticjs';
export interface UserProps {
@@ -26,10 +25,11 @@ export interface UserProps {
export const User = ({ navOpen, setNavOpen }: UserProps): JSX.Element => {
const [debug, setDebug] = React.useState(false);
const [loading, setLoading] = React.useState(false);
- const dispatch = useAppDispatch();
- const myNodeInfo = useAppSelector((state) => state.meshtastic.myNodeInfo);
- const user = useAppSelector((state) => state.meshtastic.users).find(
- (user) => user.packet.from === myNodeInfo.myNodeNum,
+ const myNodeNum = useAppSelector(
+ (state) => state.meshtastic.radio.hardware,
+ ).myNodeNum;
+ const node = useAppSelector((state) => state.meshtastic.nodes).find(
+ (node) => node.number === myNodeNum,
);
const { register, handleSubmit, formState, reset } = useForm<{
longName: string;
@@ -38,22 +38,34 @@ export const User = ({ navOpen, setNavOpen }: UserProps): JSX.Element => {
team: Protobuf.Team;
}>({
defaultValues: {
- longName: user?.data.longName,
- shortName: user?.data.shortName,
- isLicensed: user?.data.isLicensed,
- team: user?.data.team,
+ longName: node?.user?.longName,
+ shortName: node?.user?.shortName,
+ isLicensed: node?.user?.isLicensed,
+ team: node?.user?.team,
},
});
+ React.useEffect(() => {
+ reset({
+ longName: node?.user?.longName,
+ shortName: node?.user?.shortName,
+ isLicensed: node?.user?.isLicensed,
+ team: node?.user?.team,
+ });
+ }, [reset, node]);
+
const onSubmit = handleSubmit((data) => {
setLoading(true);
- // TODO: can be removed once getUser is implemented
- if (user) {
- void connection.setOwner({ ...user.data, ...data }, async () => {
+
+ if (node?.user) {
+ void connection.setOwner({ ...node.user, ...data }, async () => {
await Promise.resolve();
setLoading(false);
});
- dispatch(addUser({ ...user, ...{ data: { ...user.data, ...data } } }));
+ // TODO: can be removed once getUser is implemented
+ // dispatch(
+ // addUser({ ...node.user, ...{ data: { ...node.user.data, ...data } } }),
+ // );
}
});
@@ -87,15 +99,15 @@ export const User = ({ navOpen, setNavOpen }: UserProps): JSX.Element => {
}
>
- } />
+ } />