Browse Source

WIP config overhaul

pull/82/head
Sacha Weatherstone 3 years ago
parent
commit
6340809ab3
No known key found for this signature in database GPG Key ID: 7AB2D7E206124B31
  1. 10
      package.json
  2. 214
      pnpm-lock.yaml
  3. 41
      src/components/PageComponents/Config/Bluetooth.tsx
  4. 41
      src/components/PageComponents/Config/Device.tsx
  5. 51
      src/components/PageComponents/Config/Display.tsx
  6. 41
      src/components/PageComponents/Config/LoRa.tsx
  7. 47
      src/components/PageComponents/Config/Network.tsx
  8. 106
      src/components/PageComponents/Config/Position.tsx
  9. 41
      src/components/PageComponents/Config/Power.tsx
  10. 1
      src/components/Sidebar.tsx
  11. 3
      src/components/form/Form.tsx
  12. 58
      src/core/stores/deviceStore.ts
  13. 18
      src/pages/Config/DeviceConfig.tsx
  14. 3
      src/validation/config/lora.ts
  15. 2
      src/validation/config/network.ts

10
package.json

@ -20,11 +20,11 @@
"homepage": "https://meshtastic.org",
"dependencies": {
"@emeraldpay/hashicon-react": "^0.5.2",
"@headlessui/react": "^1.7.7",
"@headlessui/react": "^1.7.8",
"@heroicons/react": "^2.0.14",
"@hookform/error-message": "^2.0.1",
"@hookform/resolvers": "^2.9.10",
"@meshtastic/meshtasticjs": "2.0.13-5",
"@meshtastic/meshtasticjs": "2.0.15-0",
"@primer/octicons-react": "^17.11.1",
"@tailwindcss/typography": "^0.5.9",
"@turf/turf": "^6.5.0",
@ -36,7 +36,7 @@
"date-fns": "^2.29.3",
"geodesy": "^2.4.0",
"i18next": "^22.4.9",
"immer": "^9.0.18",
"immer": "^9.0.19",
"mapbox-gl": "npm:empty-npm-package@^1.0.0",
"maplibre-gl": "2.4.0",
"pretty-ms": "^8.0.0",
@ -66,7 +66,7 @@
"@typescript-eslint/parser": "^5.49.0",
"@vitejs/plugin-react": "^3.0.1",
"autoprefixer": "^10.4.13",
"eslint": "^8.32.0",
"eslint": "^8.33.0",
"eslint-config-prettier": "^8.6.0",
"eslint-import-resolver-typescript": "^3.5.3",
"eslint-plugin-import": "^2.27.5",
@ -79,7 +79,7 @@
"rollup-plugin-visualizer": "^5.9.0",
"tailwindcss": "^3.2.4",
"tar": "^6.1.13",
"tslib": "^2.4.1",
"tslib": "^2.5.0",
"typescript": "^4.9.4",
"vite": "^4.0.4",
"vite-plugin-environment": "^1.1.3",

214
pnpm-lock.yaml

@ -2,11 +2,11 @@ lockfileVersion: 5.4
specifiers:
'@emeraldpay/hashicon-react': ^0.5.2
'@headlessui/react': ^1.7.7
'@headlessui/react': ^1.7.8
'@heroicons/react': ^2.0.14
'@hookform/error-message': ^2.0.1
'@hookform/resolvers': ^2.9.10
'@meshtastic/meshtasticjs': 2.0.13-5
'@meshtastic/meshtasticjs': 2.0.15-0
'@primer/octicons-react': ^17.11.1
'@tailwindcss/forms': ^0.5.3
'@tailwindcss/typography': ^0.5.9
@ -28,7 +28,7 @@ specifiers:
class-transformer: ^0.5.1
class-validator: ^0.14.0
date-fns: ^2.29.3
eslint: ^8.32.0
eslint: ^8.33.0
eslint-config-prettier: ^8.6.0
eslint-import-resolver-typescript: ^3.5.3
eslint-plugin-import: ^2.27.5
@ -37,7 +37,7 @@ specifiers:
geodesy: ^2.4.0
gzipper: ^7.2.0
i18next: ^22.4.9
immer: ^9.0.18
immer: ^9.0.19
mapbox-gl: npm:empty-npm-package@^1.0.0
maplibre-gl: 2.4.0
postcss: ^8.4.21
@ -58,7 +58,7 @@ specifiers:
tailwindcss: ^3.2.4
tar: ^6.1.13
timeago-react: ^3.0.5
tslib: ^2.4.1
tslib: ^2.5.0
typescript: ^4.9.4
vite: ^4.0.4
vite-plugin-environment: ^1.1.3
@ -67,11 +67,11 @@ specifiers:
dependencies:
'@emeraldpay/hashicon-react': 0.5.2
'@headlessui/react': 1.7.7_biqbaboplfbrettd7655fr4n2y
'@headlessui/react': 1.7.8_biqbaboplfbrettd7655fr4n2y
'@heroicons/react': 2.0[email protected]
'@hookform/error-message': 2.0.1_uno7536xd2i6xn2dtvbywz2sva
'@hookform/resolvers': 2.9[email protected]
'@meshtastic/meshtasticjs': 2.0.13-5
'@meshtastic/meshtasticjs': 2.0.15-0
'@primer/octicons-react': 17.11[email protected]
'@tailwindcss/typography': 0.5[email protected]
'@turf/turf': 6.5.0
@ -83,7 +83,7 @@ dependencies:
date-fns: 2.29.3
geodesy: 2.4.0
i18next: 22.4.9
immer: 9.0.18
immer: 9.0.19
mapbox-gl: /empty-npm-package/1.0.0
maplibre-gl: 2.4.0
pretty-ms: 8.0.0
@ -98,7 +98,7 @@ dependencies:
react-qrcode-logo: 2.8.0_biqbaboplfbrettd7655fr4n2y
rfc4648: 1.5.2
timeago-react: 3.0[email protected]
zustand: 4.3[email protected]8[email protected]
zustand: 4.3[email protected]9[email protected]
devDependencies:
'@tailwindcss/forms': 0.5[email protected]
@ -109,16 +109,16 @@ devDependencies:
'@types/react-dom': 18.0.10
'@types/w3c-web-serial': 1.0.3
'@types/web-bluetooth': 0.0.16
'@typescript-eslint/eslint-plugin': 5.49.0_iu322prlnwsygkcra5kbpy22si
'@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje
'@typescript-eslint/eslint-plugin': 5.49.0_rsaczafy73x3xqauzesvzbsgzy
'@typescript-eslint/parser': 5.49.0_zkdaqh7it7uc4cvz2haft7rc6u
'@vitejs/plugin-react': 3.0[email protected]
autoprefixer: 10.4[email protected]
eslint: 8.32.0
eslint-config-prettier: 8.6[email protected]2.0
eslint-import-resolver-typescript: 3.5.3_ps7hf4l2dvbuxvtusmrfhmzsba
eslint-plugin-import: 2.27.5_tto3jvfrcbe7ndbi56p7uxhaki
eslint-plugin-react: 7.32[email protected]2.0
eslint-plugin-react-hooks: 4.6[email protected]2.0
eslint: 8.33.0
eslint-config-prettier: 8.6[email protected]3.0
eslint-import-resolver-typescript: 3.5.3_ohdts44xlqyeyrlje4qnefqeay
eslint-plugin-import: 2.27.5_c6pjvta7aysubsdnhvgec47vxe
eslint-plugin-react: 7.32[email protected]3.0
eslint-plugin-react-hooks: 4.6[email protected]3.0
gzipper: 7.2.0
postcss: 8.4.21
prettier: 2.8.3
@ -126,7 +126,7 @@ devDependencies:
rollup-plugin-visualizer: 5.9.0
tailwindcss: 3.2[email protected]
tar: 6.1.13
tslib: 2.4.1
tslib: 2.5.0
typescript: 4.9.4
vite: 4.0.4_@[email protected]
vite-plugin-environment: 1.1[email protected]
@ -161,8 +161,8 @@ packages:
'@babel/highlight': 7.18.6
dev: true
/@babel/compat-data/7.20.10:
resolution: {integrity: sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==}
/@babel/compat-data/7.20.14:
resolution: {integrity: sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==}
engines: {node: '>=6.9.0'}
dev: true
@ -172,7 +172,7 @@ packages:
dependencies:
'@ampproject/remapping': 2.2.0
'@babel/code-frame': 7.18.6
'@babel/generator': 7.20.7
'@babel/generator': 7.20.14
'@babel/helper-compilation-targets': 7.20.7_@[email protected]
'@babel/helper-module-transforms': 7.20.11
'@babel/helpers': 7.20.13
@ -189,8 +189,8 @@ packages:
- supports-color
dev: true
/@babel/generator/7.20.7:
resolution: {integrity: sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==}
/@babel/generator/7.20.14:
resolution: {integrity: sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.20.7
@ -219,7 +219,7 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0
dependencies:
'@babel/compat-data': 7.20.10
'@babel/compat-data': 7.20.14
'@babel/core': 7.20.12
'@babel/helper-validator-option': 7.18.6
browserslist: 4.21.4
@ -583,7 +583,7 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/compat-data': 7.20.10
'@babel/compat-data': 7.20.14
'@babel/core': 7.20.12
'@babel/helper-compilation-targets': 7.20.7_@[email protected]
'@babel/helper-plugin-utils': 7.20.2
@ -826,8 +826,8 @@ packages:
'@babel/helper-plugin-utils': 7.20.2
dev: true
/@babel/plugin-transform-block-scoping/7.20.11_@[email protected]:
resolution: {integrity: sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==}
/@babel/plugin-transform-block-scoping/7.20.14_@[email protected]:
resolution: {integrity: sha512-sMPepQtsOs5fM1bwNvuJJHvaCfOEQfmc01FGw0ELlTpTJj5Ql/zuNRRldYhAPys4ghXdBIQJbRVYi44/7QflQQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@ -1179,7 +1179,7 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/compat-data': 7.20.10
'@babel/compat-data': 7.20.14
'@babel/core': 7.20.12
'@babel/helper-compilation-targets': 7.20.7_@[email protected]
'@babel/helper-plugin-utils': 7.20.2
@ -1219,7 +1219,7 @@ packages:
'@babel/plugin-transform-arrow-functions': 7.20.7_@[email protected]
'@babel/plugin-transform-async-to-generator': 7.20.7_@[email protected]
'@babel/plugin-transform-block-scoped-functions': 7.18.6_@[email protected]
'@babel/plugin-transform-block-scoping': 7.20.11_@[email protected]
'@babel/plugin-transform-block-scoping': 7.20.14_@[email protected]
'@babel/plugin-transform-classes': 7.20.7_@[email protected]
'@babel/plugin-transform-computed-properties': 7.20.7_@[email protected]
'@babel/plugin-transform-destructuring': 7.20.7_@[email protected]
@ -1292,7 +1292,7 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
'@babel/code-frame': 7.18.6
'@babel/generator': 7.20.7
'@babel/generator': 7.20.14
'@babel/helper-environment-visitor': 7.18.9
'@babel/helper-function-name': 7.19.0
'@babel/helper-hoist-variables': 7.18.6
@ -1314,8 +1314,8 @@ packages:
to-fast-properties: 2.0.0
dev: true
/@buf/meshtastic_protobufs.bufbuild_es/1.0.0-20230114035636-d95aa4c6a33c.1_@[email protected]:
resolution: {registry: https://buf.build/gen/npm/v1, tarball: https://buf.build/gen/npm/v1/@buf/meshtastic_protobufs.bufbuild_es/1.0.0-20230114035636-d95aa4c6a33c.1/tarball}
/@buf/meshtastic_protobufs.bufbuild_es/1.0.0-20230129055417-f11f156e79a6.1_@[email protected]:
resolution: {registry: https://buf.build/gen/npm/v1, tarball: https://buf.build/gen/npm/v1/@buf/meshtastic_protobufs.bufbuild_es/1.0.0-20230129055417-f11f156e79a6.1/tarball}
peerDependencies:
'@bufbuild/protobuf': ^1.0.0
dependencies:
@ -1547,7 +1547,7 @@ packages:
ajv: 6.12.6
debug: 4.3.4
espree: 9.4.1
globals: 13.19.0
globals: 13.20.0
ignore: 5.2.4
import-fresh: 3.3.0
js-yaml: 4.1.0
@ -1564,8 +1564,8 @@ packages:
base64-js: 1.5.1
dev: true
/@headlessui/react/1.7.7_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-BqDOd/tB9u2tA0T3Z0fn18ktw+KbVwMnkxxsGPIH2hzssrQhKB5n/6StZOyvLYP/FsYtvuXfi9I0YowKPv2c1w==}
/@headlessui/react/1.7.8_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-zcwb0kd7L05hxmoAMIioEaOn235Dg0fUO+iGbLPgLVSjzl/l39V6DTpC2Df49PE5aG5/f5q0PZ9ZHZ78ENNV+A==}
engines: {node: '>=10'}
peerDependencies:
react: ^16 || ^17 || ^18
@ -1713,13 +1713,16 @@ packages:
engines: {node: '>=6.0.0'}
dev: false
/@meshtastic/meshtasticjs/2.0.13-5:
resolution: {integrity: sha512-4nddyKCPvujgwZa0Y+Bz4m7MFkOq7D2q5iuDqXbnE8xq2sqAjQde9DzK+ihnFe89enf7a5hz5d2bxZBqmMDYmg==}
/@meshtastic/meshtasticjs/2.0.15-0:
resolution: {integrity: sha512-CEfLP/PQWsQoUoFkQ2FVSNUKhjH+6J3QaTgvaRcP8YWq269SA8/A4ZFIIdg28DMKkPNcGPfVv/6PX7y98C6zmA==}
dependencies:
'@buf/meshtastic_protobufs.bufbuild_es': 1.0.0-20230114035636-d95aa4c6a33c.1_@[email protected]
'@buf/meshtastic_protobufs.bufbuild_es': 1.0.0-20230129055417-f11f156e79a6.1_@[email protected]
'@bufbuild/protobuf': 1.0.0
crc: 4.3.1
sub-events: 1.9.0
tslog: 4.7.1
transitivePeerDependencies:
- buffer
dev: false
/@nodelib/fs.scandir/2.1.5:
@ -1749,7 +1752,7 @@ packages:
open: 8.4.0
picocolors: 1.0.0
tiny-glob: 0.2.9
tslib: 2.4.1
tslib: 2.5.0
dev: true
/@primer/octicons-react/[email protected]:
@ -1803,7 +1806,7 @@ packages:
rollup: 2.79.1
dev: true
/@rollup/plugin-replace/[email protected]0.1:
/@rollup/plugin-replace/[email protected]2.0:
resolution: {integrity: sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==}
engines: {node: '>=14.0.0'}
peerDependencies:
@ -1812,9 +1815,9 @@ packages:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 5.0[email protected]0.1
'@rollup/pluginutils': 5.0[email protected]2.0
magic-string: 0.27.0
rollup: 3.10.1
rollup: 3.12.0
dev: true
/@rollup/pluginutils/[email protected]:
@ -1829,7 +1832,7 @@ packages:
rollup: 2.79.1
dev: true
/@rollup/pluginutils/[email protected]0.1:
/@rollup/pluginutils/[email protected]2.0:
resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==}
engines: {node: '>=14.0.0'}
peerDependencies:
@ -1841,7 +1844,7 @@ packages:
'@types/estree': 1.0.0
estree-walker: 2.0.2
picomatch: 2.3.1
rollup: 3.10.1
rollup: 3.12.0
dev: true
/@stablelib/binary/1.0.1:
@ -3058,7 +3061,7 @@ packages:
resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
dev: true
/@typescript-eslint/eslint-plugin/5.49.0_iu322prlnwsygkcra5kbpy22si:
/@typescript-eslint/eslint-plugin/5.49.0_rsaczafy73x3xqauzesvzbsgzy:
resolution: {integrity: sha512-IhxabIpcf++TBaBa1h7jtOWyon80SXPRLDq0dVz5SLFC/eW6tofkw/O7Ar3lkx5z5U6wzbKDrl2larprp5kk5Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -3069,12 +3072,12 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje
'@typescript-eslint/parser': 5.49.0_zkdaqh7it7uc4cvz2haft7rc6u
'@typescript-eslint/scope-manager': 5.49.0
'@typescript-eslint/type-utils': 5.49.0_7uibuqfxkfaozanbtbziikiqje
'@typescript-eslint/utils': 5.49.0_7uibuqfxkfaozanbtbziikiqje
'@typescript-eslint/type-utils': 5.49.0_zkdaqh7it7uc4cvz2haft7rc6u
'@typescript-eslint/utils': 5.49.0_zkdaqh7it7uc4cvz2haft7rc6u
debug: 4.3.4
eslint: 8.32.0
eslint: 8.33.0
ignore: 5.2.4
natural-compare-lite: 1.4.0
regexpp: 3.2.0
@ -3085,7 +3088,7 @@ packages:
- supports-color
dev: true
/@typescript-eslint/parser/5.49.0_7uibuqfxkfaozanbtbziikiqje:
/@typescript-eslint/parser/5.49.0_zkdaqh7it7uc4cvz2haft7rc6u:
resolution: {integrity: sha512-veDlZN9mUhGqU31Qiv2qEp+XrJj5fgZpJ8PW30sHU+j/8/e5ruAhLaVDAeznS7A7i4ucb/s8IozpDtt9NqCkZg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -3099,7 +3102,7 @@ packages:
'@typescript-eslint/types': 5.49.0
'@typescript-eslint/typescript-estree': 5.49[email protected]
debug: 4.3.4
eslint: 8.32.0
eslint: 8.33.0
typescript: 4.9.4
transitivePeerDependencies:
- supports-color
@ -3113,7 +3116,7 @@ packages:
'@typescript-eslint/visitor-keys': 5.49.0
dev: true
/@typescript-eslint/type-utils/5.49.0_7uibuqfxkfaozanbtbziikiqje:
/@typescript-eslint/type-utils/5.49.0_zkdaqh7it7uc4cvz2haft7rc6u:
resolution: {integrity: sha512-eUgLTYq0tR0FGU5g1YHm4rt5H/+V2IPVkP0cBmbhRyEmyGe4XvJ2YJ6sYTmONfjmdMqyMLad7SB8GvblbeESZA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -3124,9 +3127,9 @@ packages:
optional: true
dependencies:
'@typescript-eslint/typescript-estree': 5.49[email protected]
'@typescript-eslint/utils': 5.49.0_7uibuqfxkfaozanbtbziikiqje
'@typescript-eslint/utils': 5.49.0_zkdaqh7it7uc4cvz2haft7rc6u
debug: 4.3.4
eslint: 8.32.0
eslint: 8.33.0
tsutils: 3.21[email protected]
typescript: 4.9.4
transitivePeerDependencies:
@ -3159,7 +3162,7 @@ packages:
- supports-color
dev: true
/@typescript-eslint/utils/5.49.0_7uibuqfxkfaozanbtbziikiqje:
/@typescript-eslint/utils/5.49.0_zkdaqh7it7uc4cvz2haft7rc6u:
resolution: {integrity: sha512-cPJue/4Si25FViIb74sHCLtM4nTSBXtLx1d3/QT6mirQ/c65bV8arBEebBJJizfq8W2YyMoPI/WWPFWitmNqnQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -3170,9 +3173,9 @@ packages:
'@typescript-eslint/scope-manager': 5.49.0
'@typescript-eslint/types': 5.49.0
'@typescript-eslint/typescript-estree': 5.49[email protected]
eslint: 8.32.0
eslint: 8.33.0
eslint-scope: 5.1.1
eslint-utils: 3.0[email protected]2.0
eslint-utils: 3.0[email protected]3.0
semver: 7.3.8
transitivePeerDependencies:
- supports-color
@ -3347,7 +3350,7 @@ packages:
postcss: ^8.1.0
dependencies:
browserslist: 4.21.4
caniuse-lite: 1.0.30001448
caniuse-lite: 1.0.30001449
fraction.js: 4.2.0
normalize-range: 0.1.2
picocolors: 1.0.0
@ -3365,7 +3368,7 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/compat-data': 7.20.10
'@babel/compat-data': 7.20.14
'@babel/core': 7.20.12
'@babel/helper-define-polyfill-provider': 0.3.3_@[email protected]
semver: 6.3.0
@ -3435,7 +3438,7 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001448
caniuse-lite: 1.0.30001449
electron-to-chromium: 1.4.284
node-releases: 2.0.8
update-browserslist-db: 1.0[email protected]
@ -3465,8 +3468,8 @@ packages:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
/caniuse-lite/1.0.30001448:
resolution: {integrity: sha512-tq2YI+MJnooG96XpbTRYkBxLxklZPOdLmNIOdIhvf7SNJan6u5vCKum8iT7ZfCt70m1GPkuC7P3TtX6UuhupuA==}
/caniuse-lite/1.0.30001449:
resolution: {integrity: sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw==}
dev: true
/chalk/2.4.2:
@ -3619,6 +3622,13 @@ packages:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
dev: true
/crc/4.3.1:
resolution: {integrity: sha512-xj9aHWoSZ3QjIrfhaDjWFObTOuCKgI4PDuzORvgzCIJ3qDw9Z3dOVK/Oj++N0kWdFLWBbOjSi+/0SLleiy/4OQ==}
engines: {node: '>=12'}
peerDependencies:
buffer: '>=6.0.3'
dev: false
/cross-spawn/7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@ -3957,13 +3967,13 @@ packages:
engines: {node: '>=10'}
dev: true
/eslint-config-prettier/[email protected]2.0:
/eslint-config-prettier/[email protected]3.0:
resolution: {integrity: sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==}
hasBin: true
peerDependencies:
eslint: '>=7.0.0'
dependencies:
eslint: 8.32.0
eslint: 8.33.0
dev: true
/eslint-import-resolver-node/0.3.7:
@ -3976,7 +3986,7 @@ packages:
- supports-color
dev: true
/eslint-import-resolver-typescript/3.5.3_ps7hf4l2dvbuxvtusmrfhmzsba:
/eslint-import-resolver-typescript/3.5.3_ohdts44xlqyeyrlje4qnefqeay:
resolution: {integrity: sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
@ -3985,18 +3995,18 @@ packages:
dependencies:
debug: 4.3.4
enhanced-resolve: 5.12.0
eslint: 8.32.0
eslint-plugin-import: 2.27.5_tto3jvfrcbe7ndbi56p7uxhaki
eslint: 8.33.0
eslint-plugin-import: 2.27.5_c6pjvta7aysubsdnhvgec47vxe
get-tsconfig: 4.3.0
globby: 13.1.3
is-core-module: 2.11.0
is-glob: 4.0.3
synckit: 0.8.4
synckit: 0.8.5
transitivePeerDependencies:
- supports-color
dev: true
/eslint-module-utils/2.7.4_xoxtsypck35xtelm3fn5dkquvy:
/eslint-module-utils/2.7.4_5hqjyc62h4cn6t4zslmr6l4rke:
resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==}
engines: {node: '>=4'}
peerDependencies:
@ -4017,16 +4027,16 @@ packages:
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje
'@typescript-eslint/parser': 5.49.0_zkdaqh7it7uc4cvz2haft7rc6u
debug: 3.2.7
eslint: 8.32.0
eslint: 8.33.0
eslint-import-resolver-node: 0.3.7
eslint-import-resolver-typescript: 3.5.3_ps7hf4l2dvbuxvtusmrfhmzsba
eslint-import-resolver-typescript: 3.5.3_ohdts44xlqyeyrlje4qnefqeay
transitivePeerDependencies:
- supports-color
dev: true
/eslint-plugin-import/2.27.5_tto3jvfrcbe7ndbi56p7uxhaki:
/eslint-plugin-import/2.27.5_c6pjvta7aysubsdnhvgec47vxe:
resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==}
engines: {node: '>=4'}
peerDependencies:
@ -4036,15 +4046,15 @@ packages:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje
'@typescript-eslint/parser': 5.49.0_zkdaqh7it7uc4cvz2haft7rc6u
array-includes: 3.1.6
array.prototype.flat: 1.3.1
array.prototype.flatmap: 1.3.1
debug: 3.2.7
doctrine: 2.1.0
eslint: 8.32.0
eslint: 8.33.0
eslint-import-resolver-node: 0.3.7
eslint-module-utils: 2.7.4_xoxtsypck35xtelm3fn5dkquvy
eslint-module-utils: 2.7.4_5hqjyc62h4cn6t4zslmr6l4rke
has: 1.0.3
is-core-module: 2.11.0
is-glob: 4.0.3
@ -4059,16 +4069,16 @@ packages:
- supports-color
dev: true
/eslint-plugin-react-hooks/[email protected]2.0:
/eslint-plugin-react-hooks/[email protected]3.0:
resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==}
engines: {node: '>=10'}
peerDependencies:
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
dependencies:
eslint: 8.32.0
eslint: 8.33.0
dev: true
/eslint-plugin-react/[email protected]2.0:
/eslint-plugin-react/[email protected]3.0:
resolution: {integrity: sha512-vOjdgyd0ZHBXNsmvU+785xY8Bfe57EFbTYYk8XrROzWpr9QBvpjITvAXt9xqcE6+8cjR/g1+mfumPToxsl1www==}
engines: {node: '>=4'}
peerDependencies:
@ -4078,7 +4088,7 @@ packages:
array.prototype.flatmap: 1.3.1
array.prototype.tosorted: 1.1.1
doctrine: 2.1.0
eslint: 8.32.0
eslint: 8.33.0
estraverse: 5.3.0
jsx-ast-utils: 3.3.3
minimatch: 3.1.2
@ -4108,13 +4118,13 @@ packages:
estraverse: 5.3.0
dev: true
/eslint-utils/[email protected]2.0:
/eslint-utils/[email protected]3.0:
resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
peerDependencies:
eslint: '>=5'
dependencies:
eslint: 8.32.0
eslint: 8.33.0
eslint-visitor-keys: 2.1.0
dev: true
@ -4128,8 +4138,8 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/eslint/8.32.0:
resolution: {integrity: sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==}
/eslint/8.33.0:
resolution: {integrity: sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
@ -4144,7 +4154,7 @@ packages:
doctrine: 3.0.0
escape-string-regexp: 4.0.0
eslint-scope: 7.1.1
eslint-utils: 3.0[email protected]2.0
eslint-utils: 3.0[email protected]3.0
eslint-visitor-keys: 3.3.0
espree: 9.4.1
esquery: 1.4.0
@ -4153,7 +4163,7 @@ packages:
file-entry-cache: 6.0.1
find-up: 5.0.0
glob-parent: 6.0.2
globals: 13.19.0
globals: 13.20.0
grapheme-splitter: 1.0.4
ignore: 5.2.4
import-fresh: 3.3.0
@ -4446,8 +4456,8 @@ packages:
engines: {node: '>=4'}
dev: true
/globals/13.19.0:
resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==}
/globals/13.20.0:
resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==}
engines: {node: '>=8'}
dependencies:
type-fest: 0.20.2
@ -4588,8 +4598,8 @@ packages:
engines: {node: '>= 4'}
dev: true
/immer/9.0.18:
resolution: {integrity: sha512-eAPNpsj7Ax1q6Y/3lm2PmlwRcFzpON7HSNQ3ru5WQH1/PSpnyed/HpNOELl2CxLKoj4r+bAHgdyKqW5gc2Se1A==}
/immer/9.0.19:
resolution: {integrity: sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==}
dev: false
/import-fresh/3.3.0:
@ -5887,8 +5897,8 @@ packages:
fsevents: 2.3.2
dev: true
/rollup/3.10.1:
resolution: {integrity: sha512-3Er+yel3bZbZX1g2kjVM+FW+RUWDxbG87fcqFM5/9HbPCTpbVp6JOLn7jlxnNlbu7s/N/uDA4EV/91E2gWnxzw==}
/rollup/3.12.0:
resolution: {integrity: sha512-4MZ8kA2HNYahIjz63rzrMMRvDqQDeS9LoriJvMuV0V6zIGysP36e9t4yObUfwdT9h/szXoHQideICftcdZklWg==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
hasBin: true
optionalDependencies:
@ -6148,12 +6158,12 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
/synckit/0.8.4:
resolution: {integrity: sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==}
/synckit/0.8.5:
resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==}
engines: {node: ^14.18.0 || >=16.0.0}
dependencies:
'@pkgr/utils': 2.3.1
tslib: 2.4.1
tslib: 2.5.0
dev: true
/tailwindcss/[email protected]:
@ -6325,8 +6335,8 @@ packages:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
dev: true
/tslib/2.4.1:
resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==}
/tslib/2.5.0:
resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==}
dev: true
/tslog/4.7.1:
@ -6484,11 +6494,11 @@ packages:
peerDependencies:
vite: ^3.1.0 || ^4.0.0
dependencies:
'@rollup/plugin-replace': 5.0[email protected]0.1
'@rollup/plugin-replace': 5.0[email protected]2.0
debug: 4.3.4
fast-glob: 3.2.12
pretty-bytes: 6.0.0
rollup: 3.10.1
rollup: 3.12.0
vite: 4.0.4_@[email protected]
workbox-build: 6.5.4
workbox-window: 6.5.4
@ -6526,7 +6536,7 @@ packages:
esbuild: 0.16.17
postcss: 8.4.21
resolve: 1.22.1
rollup: 3.10.1
rollup: 3.12.0
optionalDependencies:
fsevents: 2.3.2
dev: true
@ -6810,7 +6820,7 @@ packages:
engines: {node: '>=10'}
dev: true
/zustand/[email protected]8[email protected]:
/zustand/[email protected]9[email protected]:
resolution: {integrity: sha512-rd4haDmlwMTVWVqwvgy00ny8rtti/klRoZjFbL/MAcDnmD5qSw/RZc+Vddstdv90M5Lv6RPgWvm1Hivyn0QgJw==}
engines: {node: '>=12.7.0'}
peerDependencies:
@ -6822,7 +6832,7 @@ packages:
react:
optional: true
dependencies:
immer: 9.0.18
immer: 9.0.19
react: 18.2.0
use-sync-external-store: 1.2[email protected]
dev: false

41
src/components/PageComponents/Config/Bluetooth.tsx

@ -15,7 +15,7 @@ import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const Bluetooth = (): JSX.Element => {
const { config, connection, setConfig } = useDevice();
const { config, setWorkingConfig } = useDevice();
const {
register,
@ -24,6 +24,7 @@ export const Bluetooth = (): JSX.Element => {
control,
reset
} = useForm<BluetoothValidation>({
mode: "onChange",
defaultValues: config.bluetooth,
resolver: classValidatorResolver(BluetoothValidation)
});
@ -33,34 +34,14 @@ export const Bluetooth = (): JSX.Element => {
}, [reset, config.bluetooth]);
const onSubmit = handleSubmit((data) => {
if (connection) {
void toast.promise(
connection
.setConfig(
new Protobuf.Config({
payloadVariant: {
case: "bluetooth",
value: data
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "bluetooth",
value: data
}
})
)
),
{
loading: "Saving...",
success: "Saved Bluetooth Config, Restarting Node",
error: "No response received"
setWorkingConfig(
new Protobuf.Config({
payloadVariant: {
case: "bluetooth",
value: data
}
);
}
})
);
});
const pairingMode = useWatch({
@ -70,9 +51,7 @@ export const Bluetooth = (): JSX.Element => {
});
return (
<Form
onSubmit={onSubmit}
>
<Form onSubmit={onSubmit}>
<Controller
name="enabled"
control={control}

41
src/components/PageComponents/Config/Device.tsx

@ -15,7 +15,7 @@ import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const Device = (): JSX.Element => {
const { config, connection, setConfig } = useDevice();
const { config, setWorkingConfig } = useDevice();
const {
register,
handleSubmit,
@ -23,6 +23,7 @@ export const Device = (): JSX.Element => {
control,
reset
} = useForm<DeviceValidation>({
mode: "onChange",
defaultValues: config.device,
resolver: classValidatorResolver(DeviceValidation)
});
@ -32,40 +33,18 @@ export const Device = (): JSX.Element => {
}, [reset, config.device]);
const onSubmit = handleSubmit((data) => {
if (connection) {
void toast.promise(
connection
.setConfig(
new Protobuf.Config({
payloadVariant: {
case: "device",
value: data
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "device",
value: data
}
})
)
),
{
loading: "Saving...",
success: "Saved Device Config, Restarting Node",
error: "No response received"
setWorkingConfig(
new Protobuf.Config({
payloadVariant: {
case: "device",
value: data
}
);
}
})
);
});
return (
<Form
onSubmit={onSubmit}
>
<Form onSubmit={onSubmit}>
<Select
label="Role"
description="What role the device performs on the mesh"

51
src/components/PageComponents/Config/Display.tsx

@ -7,7 +7,7 @@ import { toast } from "react-hot-toast";
import { Input } from "@app/components/form/Input.js";
import { Select } from "@app/components/form/Select.js";
import { Toggle } from "@app/components/form/Toggle.js";
import type { DisplayValidation } from "@app/validation/config/display.js";
import { DisplayValidation } from "@app/validation/config/display.js";
import { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js";
import { renderOptions } from "@core/utils/selectEnumOptions.js";
@ -15,7 +15,7 @@ import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const Display = (): JSX.Element => {
const { config, connection, setConfig } = useDevice();
const { config, setWorkingConfig } = useDevice();
const {
register,
handleSubmit,
@ -23,43 +23,24 @@ export const Display = (): JSX.Element => {
reset,
control
} = useForm<DisplayValidation>({
defaultValues: config.display
// resolver: classValidatorResolver(DisplayValidation)
mode: "onChange",
defaultValues: config.display,
resolver: classValidatorResolver(DisplayValidation)
});
// useEffect(() => {
// reset(config.display);
// }, [reset, config.display]);
useEffect(() => {
reset(config.display);
}, [reset, config.display]);
const onSubmit = handleSubmit((data) => {
// if (connection) {
// void toast.promise(
// connection
// .setConfig(
// new Protobuf.Config({
// payloadVariant: {
// case: "display",
// value: data
// }
// })
// )
// .then(() =>
// setConfig(
// new Protobuf.Config({
// payloadVariant: {
// case: "display",
// value: data
// }
// })
// )
// ),
// {
// loading: "Saving...",
// success: "Saved Display Config, Restarting Node",
// error: "No response received"
// }
// );
// }
setWorkingConfig(
new Protobuf.Config({
payloadVariant: {
case: "display",
value: data
}
})
);
});
return (

41
src/components/PageComponents/Config/LoRa.tsx

@ -16,7 +16,7 @@ import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const LoRa = (): JSX.Element => {
const { config, connection, setConfig } = useDevice();
const { config, setWorkingConfig } = useDevice();
const {
register,
@ -25,6 +25,7 @@ export const LoRa = (): JSX.Element => {
control,
reset
} = useForm<LoRaValidation>({
mode: "onChange",
defaultValues: config.lora,
resolver: classValidatorResolver(LoRaValidation)
});
@ -40,40 +41,18 @@ export const LoRa = (): JSX.Element => {
}, [reset, config.lora]);
const onSubmit = handleSubmit((data) => {
if (connection) {
void toast.promise(
connection
.setConfig(
new Protobuf.Config({
payloadVariant: {
case: "lora",
value: data
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "lora",
value: data
}
})
)
),
{
loading: "Saving...",
success: "Saved LoRa Config, Restarting Node",
error: "No response received"
setWorkingConfig(
new Protobuf.Config({
payloadVariant: {
case: "lora",
value: data
}
);
}
})
);
});
return (
<Form
onSubmit={onSubmit}
>
<Form onSubmit={onSubmit}>
<FormSection title="Modem Settings">
<Controller
name="usePreset"

47
src/components/PageComponents/Config/Network.tsx

@ -18,7 +18,7 @@ import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const Network = (): JSX.Element => {
const { config, connection, setConfig } = useDevice();
const { config, setWorkingConfig } = useDevice();
const {
register,
handleSubmit,
@ -26,6 +26,7 @@ export const Network = (): JSX.Element => {
control,
reset
} = useForm<NetworkValidation>({
mode: "onChange",
defaultValues: config.network,
resolver: classValidatorResolver(NetworkValidation)
});
@ -53,40 +54,18 @@ export const Network = (): JSX.Element => {
}, [reset, config.network]);
const onSubmit = handleSubmit((data) => {
if (connection) {
void toast.promise(
connection
.setConfig(
new Protobuf.Config({
payloadVariant: {
case: "network",
value: new Protobuf.Config_NetworkConfig(data)
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "network",
value: data
}
})
)
),
{
loading: "Saving...",
success: "Saved Network Config, Restarting Node",
error: "No response received"
setWorkingConfig(
new Protobuf.Config({
payloadVariant: {
case: "network",
value: data
}
);
}
})
);
});
return (
<Form
onSubmit={onSubmit}
>
<Form onSubmit={onSubmit}>
<ErrorMessage errors={errors} name="wifiEnabled" />
<ErrorMessage errors={errors} name="wifiMode" />
<ErrorMessage errors={errors} name="wifiSsid" />
@ -190,6 +169,12 @@ export const Network = (): JSX.Element => {
error={errors.ntpServer?.message}
{...register("ntpServer")}
/>
<Input
label="Rsyslog Server"
description="Rsyslog server for external logging"
error={errors.rsyslogServer?.message}
{...register("rsyslogServer")}
/>
</Form>
);
};

106
src/components/PageComponents/Config/Position.tsx

@ -15,7 +15,7 @@ import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const Position = (): JSX.Element => {
const { config, connection, nodes, hardware, setConfig } = useDevice();
const { config, nodes, hardware, setWorkingConfig } = useDevice();
const myNode = nodes.find((n) => n.data.num === hardware.myNodeNum);
@ -26,6 +26,7 @@ export const Position = (): JSX.Element => {
reset,
control
} = useForm<PositionValidation>({
mode: "onChange",
defaultValues: {
fixedAlt: myNode?.data.position?.altitude,
fixedLat: (myNode?.data.position?.latitudeI ?? 0) / 1e7,
@ -58,58 +59,65 @@ export const Position = (): JSX.Element => {
new Protobuf.Config_PositionConfig(rest)
);
if (connection) {
void toast.promise(
connection
.setPosition(
new Protobuf.Position({
altitude: fixedAlt,
latitudeI: fixedLat * 1e7,
longitudeI: fixedLng * 1e7
})
)
.then(() => reset({ ...data })),
{
loading: "Saving...",
success: "Saved Position Config, Restarting Node",
error: "No response received"
setWorkingConfig(
new Protobuf.Config({
payloadVariant: {
case: "position",
value: rest
}
);
if (configHasChanged) {
void toast.promise(
connection
.setConfig(
new Protobuf.Config({
payloadVariant: {
case: "position",
value: rest
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "position",
value: rest
}
})
)
),
{
loading: "Saving...",
success: "Saved Position Config, Restarting Node",
error: "No response received"
}
);
}
}
})
);
// if (connection) {
// void toast.promise(
// connection
// .setPosition(
// new Protobuf.Position({
// altitude: fixedAlt,
// latitudeI: fixedLat * 1e7,
// longitudeI: fixedLng * 1e7
// })
// )
// .then(() => reset({ ...data })),
// {
// loading: "Saving...",
// success: "Saved Position Config, Restarting Node",
// error: "No response received"
// }
// );
// if (configHasChanged) {
// void toast.promise(
// connection
// .setConfig(
// new Protobuf.Config({
// payloadVariant: {
// case: "position",
// value: rest
// }
// })
// )
// .then(() =>
// setConfig(
// new Protobuf.Config({
// payloadVariant: {
// case: "position",
// value: rest
// }
// })
// )
// ),
// {
// loading: "Saving...",
// success: "Saved Position Config, Restarting Node",
// error: "No response received"
// }
// );
// }
// }
});
return (
<Form
onSubmit={onSubmit}
>
<Form onSubmit={onSubmit}>
<Controller
name="gpsEnabled"
control={control}

41
src/components/PageComponents/Config/Power.tsx

@ -14,7 +14,7 @@ import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const Power = (): JSX.Element => {
const { config, connection, setConfig } = useDevice();
const { config, setWorkingConfig } = useDevice();
const {
register,
handleSubmit,
@ -22,6 +22,7 @@ export const Power = (): JSX.Element => {
reset,
control
} = useForm<PowerValidation>({
mode: "onChange",
defaultValues: config.power,
resolver: classValidatorResolver(PowerValidation)
});
@ -31,40 +32,18 @@ export const Power = (): JSX.Element => {
}, [reset, config.power]);
const onSubmit = handleSubmit((data) => {
if (connection) {
void toast.promise(
connection
.setConfig(
new Protobuf.Config({
payloadVariant: {
case: "power",
value: data
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "power",
value: data
}
})
)
),
{
loading: "Saving...",
success: "Saved Power Config, Restarting Node",
error: "No response received"
setWorkingConfig(
new Protobuf.Config({
payloadVariant: {
case: "power",
value: data
}
);
}
})
);
});
return (
<Form
onSubmit={onSubmit}
>
<Form onSubmit={onSubmit}>
<Input
label="Shutdown on battery delay"
description="Automatically shutdown node after this long when on battery, 0 for indefinite"

1
src/components/Sidebar.tsx

@ -12,6 +12,7 @@ import { CommandLineIcon } from "@heroicons/react/24/outline";
import { Types } from "@meshtastic/meshtasticjs";
import { Input } from "./form/Input.js";
import { Button } from "./form/Button.js";
export const Sidebar = (): JSX.Element => {
const { removeDevice } = useDeviceStore();

3
src/components/form/Form.tsx

@ -2,7 +2,7 @@ import type React from "react";
import type { HTMLProps } from "react";
export interface FormProps extends HTMLProps<HTMLFormElement> {
onSubmit: (event: React.FormEvent<HTMLFormElement>) => Promise<void>;
onSubmit?: (event: React.FormEvent<HTMLFormElement>) => Promise<void>;
}
export const Form = ({
@ -14,6 +14,7 @@ export const Form = ({
<form
className="mr-2 w-full rounded-md bg-backgroundSecondary px-2"
onSubmit={onSubmit}
onChange={onSubmit}
{...props}
>
<div className="flex flex-col gap-3 p-4">{children}</div>

58
src/core/stores/deviceStore.ts

@ -52,16 +52,6 @@ export interface processPacketParams {
time: number;
}
export type WorkingConfig = [
Protobuf.Config_DeviceConfig?,
Protobuf.Config_PositionConfig?,
Protobuf.Config_PowerConfig?,
Protobuf.Config_NetworkConfig?,
Protobuf.Config_DisplayConfig?,
Protobuf.Config_LoRaConfig?,
Protobuf.Config_BluetoothConfig?
];
export type DialogVariant = "import" | "QR" | "shutdown" | "reboot";
export interface Device {
@ -71,6 +61,8 @@ export interface Device {
channels: Channel[];
config: Protobuf.LocalConfig;
moduleConfig: Protobuf.LocalModuleConfig;
workingConfig: Protobuf.Config[];
workingModuleConfig: Protobuf.ModuleConfig[];
hardware: Protobuf.MyNodeInfo;
nodes: Node[];
connection?: Types.ConnectionType;
@ -82,7 +74,6 @@ export interface Device {
currentMetrics: Protobuf.DeviceMetrics;
pendingSettingsChanges: boolean;
messageDraft: string;
workingConfig: WorkingConfig;
dialog: {
import: boolean;
QR: boolean;
@ -94,6 +85,8 @@ export interface Device {
setStatus: (status: Types.DeviceStatusEnum) => void;
setConfig: (config: Protobuf.Config) => void;
setModuleConfig: (config: Protobuf.ModuleConfig) => void;
setWorkingConfig: (config: Protobuf.Config) => void;
setWorkingModuleConfig: (config: Protobuf.ModuleConfig) => void;
setHardware: (hardware: Protobuf.MyNodeInfo) => void;
setMetrics: (metrics: Types.PacketMetadata<Protobuf.Telemetry>) => void;
setActivePage: (page: Page) => void;
@ -145,6 +138,8 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
channels: [],
config: new Protobuf.LocalConfig(),
moduleConfig: new Protobuf.LocalModuleConfig(),
workingConfig: [],
workingModuleConfig: [],
hardware: new Protobuf.MyNodeInfo(),
nodes: [],
connection: undefined,
@ -162,7 +157,6 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
},
pendingSettingsChanges: false,
messageDraft: "",
workingConfig: [],
setReady: (ready: boolean) => {
set(
@ -260,6 +254,46 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
})
);
},
setWorkingConfig: (config: Protobuf.Config) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (!device) {
return;
}
const workingConfigIndex = device?.workingConfig.findIndex(
(wc) => wc.payloadVariant.case === config.payloadVariant.case
);
if (workingConfigIndex !== -1) {
device.workingConfig[workingConfigIndex] = config;
} else {
device?.workingConfig.push(config);
}
})
);
},
setWorkingModuleConfig: (moduleConfig: Protobuf.ModuleConfig) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (!device) {
return;
}
const workingModuleConfigIndex =
device?.workingModuleConfig.findIndex(
(wmc) =>
wmc.payloadVariant.case ===
moduleConfig.payloadVariant.case
);
if (workingModuleConfigIndex !== -1) {
device.workingModuleConfig[workingModuleConfigIndex] =
moduleConfig;
} else {
device?.workingModuleConfig.push(moduleConfig);
}
})
);
},
setHardware: (hardware: Protobuf.MyNodeInfo) => {
set(
produce<DeviceState>((draft) => {

18
src/pages/Config/DeviceConfig.tsx

@ -16,7 +16,7 @@ import { Button } from "@app/components/form/Button.js";
import { CheckIcon } from "@primer/octicons-react";
export const DeviceConfig = (): JSX.Element => {
const { hardware } = useDevice();
const { hardware, workingConfig, connection } = useDevice();
const configSections = [
{
@ -71,7 +71,17 @@ export const DeviceConfig = (): JSX.Element => {
))}
</ol>
<div className="ml-auto">
<Button iconBefore={<CheckIcon className="w-4" />}>Save</Button>
<Button
onClick={async () => {
workingConfig.map(async (config) => {
await connection?.setConfig(config);
});
await connection?.commitEditSettings();
}}
iconBefore={<CheckIcon className="w-4" />}
>
Apply & Reboot
</Button>
</div>
</div>
@ -88,7 +98,9 @@ export const DeviceConfig = (): JSX.Element => {
}`}
>
{Config.label}
<span className="ml-auto bg-accent rounded-full px-3 text-textPrimary">3</span>
<span className="ml-auto rounded-full bg-accent px-3 text-textPrimary">
3
</span>
</div>
)}
</Tab>

3
src/validation/config/lora.ts

@ -48,6 +48,9 @@ export class LoRaValidation
@IsBoolean()
overrideDutyCycle: boolean;
@IsBoolean()
sx126xRxBoostedGain: boolean;
@IsArray()
ignoreIncoming: number[];
}

2
src/validation/config/network.ts

@ -30,6 +30,8 @@ export class NetworkValidation
addressMode: Protobuf.Config_NetworkConfig_AddressMode;
ipv4Config: NetworkValidation_IpV4Config;
rsyslogServer: string;
}
export class NetworkValidation_IpV4Config

Loading…
Cancel
Save