diff --git a/package.json b/package.json
index dbb56e6d..cbd85f99 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"dependencies": {
"@floating-ui/react-dom": "^0.4.3",
"@headlessui/react": "^1.4.3",
- "@meshtastic/components": "^1.0.17",
+ "@meshtastic/components": "^1.0.19",
"@meshtastic/meshtasticjs": "^0.6.38",
"@reduxjs/toolkit": "^1.7.1",
"@tippyjs/react": "^4.2.6",
@@ -65,7 +65,7 @@
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
- "gzipper": "^6.2.1",
+ "gzipper": "^7.0.0",
"postcss": "^8.4.5",
"prettier": "^2.5.1",
"tailwindcss": "^3.0.15",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b976e8be..14176e7a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3,7 +3,7 @@ lockfileVersion: 5.3
specifiers:
'@floating-ui/react-dom': ^0.4.3
'@headlessui/react': ^1.4.3
- '@meshtastic/components': ^1.0.17
+ '@meshtastic/components': ^1.0.19
'@meshtastic/meshtasticjs': ^0.6.38
'@reduxjs/toolkit': ^1.7.1
'@tippyjs/react': ^4.2.6
@@ -30,7 +30,7 @@ specifiers:
eslint-plugin-react: ^7.28.0
eslint-plugin-react-hooks: ^4.3.0
graphql-request: ^3.7.0
- gzipper: ^6.2.1
+ gzipper: ^7.0.0
i18next: ^21.6.6
i18next-browser-languagedetector: ^6.1.2
mapbox-gl: ^2.6.1
@@ -66,7 +66,7 @@ specifiers:
dependencies:
'@floating-ui/react-dom': 0.4.3_b3482aaf5744fc7c2aeb7941b0e0a78f
'@headlessui/react': 1.4.3_react-dom@17.0.2+react@17.0.2
- '@meshtastic/components': 1.0.17_@types+react@17.0.38
+ '@meshtastic/components': 1.0.19_@types+react@17.0.38
'@meshtastic/meshtasticjs': 0.6.38
'@reduxjs/toolkit': 1.7.1_react-redux@7.2.6+react@17.0.2
'@tippyjs/react': 4.2.6_react-dom@17.0.2+react@17.0.2
@@ -117,7 +117,7 @@ devDependencies:
eslint-plugin-import: 2.25.4_eslint@8.7.0
eslint-plugin-react: 7.28.0_eslint@8.7.0
eslint-plugin-react-hooks: 4.3.0_eslint@8.7.0
- gzipper: 6.2.1
+ gzipper: 7.0.0
postcss: 8.4.5
prettier: 2.5.1
tailwindcss: 3.0.15_ef48b3b8837f8a23677bffe8f9cd866d
@@ -1451,6 +1451,13 @@ packages:
- '@types/react'
dev: false
+ /@gfx/zopfli/1.0.15:
+ resolution: {integrity: sha512-7mBgpi7UD82fsff5ThQKet0uBTl4BYerQuc+/qA1ELTwWEiIedRTcD3JgiUu9wwZ2kytW8JOb165rSdAt8PfcQ==}
+ engines: {node: '>= 8'}
+ dependencies:
+ base64-js: 1.5.1
+ dev: true
+
/@headlessui/react/1.4.3_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-n2IQkaaw0aAAlQS5MEXsM4uRK+w18CrM72EqnGRl/UBOQeQajad8oiKXR9Nk15jOzTFQjpxzrZMf1NxHidFBiw==}
engines: {node: '>=10'}
@@ -1532,8 +1539,8 @@ packages:
engines: {node: '>=6.0.0'}
dev: false
- /@meshtastic/components/1.0.17_@types+react@17.0.38:
- resolution: {integrity: sha512-e9ETFrzQUtpxVHc6NiiYMCkr7Ml4v7xlbILWK3LV48ALMDojBAFKLHdxuClpt0Rszo91ORACSSVpUkJNfWnp1A==}
+ /@meshtastic/components/1.0.19_@types+react@17.0.38:
+ resolution: {integrity: sha512-Uls4JpJFrxi86MlxRNTPRHFBW5m/3VVFaz1anvam1vHXpJZz/ikcEmW5Xgu+f7lkBO6JGtEgvdXSbJFCkr5gqQ==}
dependencies:
inter-ui: 3.19.3
react: 17.0.2
@@ -1715,8 +1722,8 @@ packages:
'@types/geojson': 7946.0.8
dev: true
- /@types/node/17.0.8:
- resolution: {integrity: sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==}
+ /@types/node/17.0.9:
+ resolution: {integrity: sha512-5dNBXu/FOER+EXnyah7rn8xlNrfMOQb/qXnw4NQgLkCygKBKhdmF/CA5oXVOKZLBEahw8s2WP9LxIcN/oDDRgQ==}
dev: true
/@types/parse-json/4.0.0:
@@ -1763,7 +1770,7 @@ packages:
/@types/resolve/1.17.1:
resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
dependencies:
- '@types/node': 17.0.8
+ '@types/node': 17.0.9
dev: true
/@types/scheduler/0.16.2:
@@ -2113,11 +2120,6 @@ packages:
engines: {node: '>=6'}
dev: true
- /ansi-regex/2.1.1:
- resolution: {integrity: sha1-w7M6te42DYbg5ijwRorn7yfWVN8=}
- engines: {node: '>=0.10.0'}
- dev: true
-
/ansi-regex/5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
@@ -2145,17 +2147,6 @@ packages:
picomatch: 2.3.1
dev: true
- /aproba/1.2.0:
- resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==}
- dev: true
-
- /are-we-there-yet/1.1.7:
- resolution: {integrity: sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==}
- dependencies:
- delegates: 1.0.0
- readable-stream: 2.3.7
- dev: true
-
/arg/5.0.1:
resolution: {integrity: sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==}
dev: true
@@ -2230,7 +2221,7 @@ packages:
postcss: ^8.1.0
dependencies:
browserslist: 4.19.1
- caniuse-lite: 1.0.30001299
+ caniuse-lite: 1.0.30001300
fraction.js: 4.1.2
normalize-range: 0.1.2
picocolors: 1.0.0
@@ -2308,14 +2299,6 @@ packages:
engines: {node: '>=8'}
dev: true
- /bl/4.1.0:
- resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
- dependencies:
- buffer: 5.7.1
- inherits: 2.0.4
- readable-stream: 3.6.0
- dev: true
-
/boring-avatars/1.6.1:
resolution: {integrity: sha512-P7BZRz1DEdx61iW7q8EoB10rDLGGH4ec8uwQsMKOCag8TznC5A/efd5OBuL9Su3HjMEDHN3X8/JRRQNsVZMl4Q==}
dev: false
@@ -2339,7 +2322,7 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
- caniuse-lite: 1.0.30001299
+ caniuse-lite: 1.0.30001300
electron-to-chromium: 1.4.46
escalade: 3.1.1
node-releases: 2.0.1
@@ -2350,13 +2333,6 @@ packages:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
- /buffer/5.7.1:
- resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
- dependencies:
- base64-js: 1.5.1
- ieee754: 1.2.1
- dev: true
-
/builtin-modules/3.2.0:
resolution: {integrity: sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==}
engines: {node: '>=6'}
@@ -2379,8 +2355,8 @@ packages:
engines: {node: '>= 6'}
dev: true
- /caniuse-lite/1.0.30001299:
- resolution: {integrity: sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw==}
+ /caniuse-lite/1.0.30001300:
+ resolution: {integrity: sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==}
dev: true
/chalk/2.4.2:
@@ -2415,25 +2391,11 @@ packages:
fsevents: 2.3.2
dev: true
- /chownr/1.1.4:
- resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
- dev: true
-
/chownr/2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'}
dev: true
- /clone/1.0.4:
- resolution: {integrity: sha1-2jCcwmPfFZlMaIypAheco8fNfH4=}
- engines: {node: '>=0.8'}
- dev: true
-
- /code-point-at/1.1.0:
- resolution: {integrity: sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=}
- engines: {node: '>=0.10.0'}
- dev: true
-
/color-convert/1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies:
@@ -2466,10 +2428,6 @@ packages:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
dev: true
- /commander/3.0.2:
- resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==}
- dev: true
-
/commander/7.2.0:
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
engines: {node: '>= 10'}
@@ -2484,10 +2442,6 @@ packages:
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
dev: true
- /console-control-strings/1.1.0:
- resolution: {integrity: sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=}
- dev: true
-
/convert-source-map/1.8.0:
resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==}
dependencies:
@@ -2579,13 +2533,6 @@ packages:
ms: 2.1.2
dev: true
- /decompress-response/4.2.1:
- resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==}
- engines: {node: '>=8'}
- dependencies:
- mimic-response: 2.1.0
- dev: true
-
/deep-equal/2.0.5:
resolution: {integrity: sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==}
dependencies:
@@ -2606,11 +2553,6 @@ packages:
which-typed-array: 1.1.7
dev: true
- /deep-extend/0.6.0:
- resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
- engines: {node: '>=4.0.0'}
- dev: true
-
/deep-is/0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
@@ -2620,12 +2562,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
- /defaults/1.0.3:
- resolution: {integrity: sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=}
- dependencies:
- clone: 1.0.4
- dev: true
-
/define-properties/1.1.3:
resolution: {integrity: sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==}
engines: {node: '>= 0.4'}
@@ -2642,16 +2578,6 @@ packages:
engines: {node: '>=0.4.0'}
dev: false
- /delegates/1.0.0:
- resolution: {integrity: sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=}
- dev: true
-
- /detect-libc/1.0.3:
- resolution: {integrity: sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=}
- engines: {node: '>=0.10'}
- hasBin: true
- dev: true
-
/detective/5.2.0:
resolution: {integrity: sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==}
engines: {node: '>=0.8.0'}
@@ -3383,11 +3309,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
- /expand-template/2.0.3:
- resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
- engines: {node: '>=6'}
- dev: true
-
/extract-files/9.0.0:
resolution: {integrity: sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==}
engines: {node: ^10.17.0 || ^12.0.0 || >= 13.7.0}
@@ -3493,10 +3414,6 @@ packages:
resolution: {integrity: sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==}
dev: true
- /fs-constants/1.0.0:
- resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
- dev: true
-
/fs-extra/9.1.0:
resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
engines: {node: '>=10'}
@@ -3534,19 +3451,6 @@ packages:
resolution: {integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=}
dev: true
- /gauge/2.7.4:
- resolution: {integrity: sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=}
- dependencies:
- aproba: 1.2.0
- console-control-strings: 1.1.0
- has-unicode: 2.0.1
- object-assign: 4.1.1
- signal-exit: 3.0.6
- string-width: 1.0.2
- strip-ansi: 3.0.1
- wide-align: 1.1.5
- dev: true
-
/gensync/1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
@@ -3581,10 +3485,6 @@ packages:
get-intrinsic: 1.1.1
dev: true
- /github-from-package/0.0.0:
- resolution: {integrity: sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=}
- dev: true
-
/gl-matrix/3.4.3:
resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==}
dev: false
@@ -3656,14 +3556,14 @@ packages:
resolution: {integrity: sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==}
dev: false
- /gzipper/6.2.1:
- resolution: {integrity: sha512-HGCFv3hZy87B+AHRuDpbyRbvOdaJllyGB+OTqDqKy54e8M1RDgF64QN/buyqpqhvSXWePNIE0jqbHpcjCWG6YQ==}
+ /gzipper/7.0.0:
+ resolution: {integrity: sha512-Pfr8FXg4JOQ9hwWWS+d5KDOokRlfjkuNuK7HVJsiXwQhYTugKMHXAnAeEuKr5ILtxX0cAzJBtR6g3Wclze8+LA==}
engines: {node: '>=14'}
hasBin: true
dependencies:
+ '@gfx/zopfli': 1.0.15
commander: 7.2.0
deep-equal: 2.0.5
- node-zopfli: 2.1.4
simple-zstd: 1.4.0
uuid: 8.3.2
dev: true
@@ -3694,10 +3594,6 @@ packages:
has-symbols: 1.0.2
dev: true
- /has-unicode/2.0.1:
- resolution: {integrity: sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=}
- dev: true
-
/has/1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
@@ -3745,6 +3641,7 @@ packages:
/ieee754/1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+ dev: false
/ignore/4.0.6:
resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
@@ -3784,10 +3681,6 @@ packages:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
- /ini/1.3.8:
- resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
- dev: true
-
/inter-ui/3.19.3:
resolution: {integrity: sha512-5FG9fjuYOXocIfjzcCBhICL5cpvwEetseL3FU6tP3d6Bn7g8wODhB+I9RNGRTizCT7CUG4GOK54OPxqq3msQgg==}
dev: false
@@ -3857,13 +3750,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
- /is-fullwidth-code-point/1.0.0:
- resolution: {integrity: sha1-754xOG8DGn8NZDr4L95QxFfvAMs=}
- engines: {node: '>=0.10.0'}
- dependencies:
- number-is-nan: 1.0.1
- dev: true
-
/is-fullwidth-code-point/3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
@@ -4010,7 +3896,7 @@ packages:
resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==}
engines: {node: '>= 10.13.0'}
dependencies:
- '@types/node': 17.0.8
+ '@types/node': 17.0.9
merge-stream: 2.0.0
supports-color: 7.2.0
dev: true
@@ -4251,11 +4137,6 @@ packages:
mime-db: 1.51.0
dev: false
- /mimic-response/2.1.0:
- resolution: {integrity: sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==}
- engines: {node: '>=8'}
- dev: true
-
/minimatch/3.0.4:
resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==}
dependencies:
@@ -4280,10 +4161,6 @@ packages:
yallist: 4.0.0
dev: true
- /mkdirp-classic/0.5.3:
- resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
- dev: true
-
/mkdirp/1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
@@ -4306,30 +4183,16 @@ packages:
resolution: {integrity: sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E=}
dev: false
- /nanoid/3.1.32:
- resolution: {integrity: sha512-F8mf7R3iT9bvThBoW4tGXhXFHCctyCiUUPrWF8WaTqa3h96d9QybkSeba43XVOOE3oiLfkVDe4bT8MeGmkrTxw==}
+ /nanoid/3.2.0:
+ resolution: {integrity: sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
dev: true
- /napi-build-utils/1.0.2:
- resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
- dev: true
-
/natural-compare/1.4.0:
resolution: {integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=}
dev: true
- /node-abi/2.30.1:
- resolution: {integrity: sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==}
- dependencies:
- semver: 5.7.1
- dev: true
-
- /node-addon-api/1.7.2:
- resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==}
- dev: true
-
/node-fetch/2.6.1:
resolution: {integrity: sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==}
engines: {node: 4.x || >=6.0.0}
@@ -4339,22 +4202,6 @@ packages:
resolution: {integrity: sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==}
dev: true
- /node-zopfli/2.1.4:
- resolution: {integrity: sha512-5kxbPxNQHbORFBNNf083V7h0dTFy6+C1W4ZA4qTXjpCQqEMzxAQFAOfi6BlCmXAkC/+Vr8d6h0XOmdjvp+9FNw==}
- engines: {node: '>=8'}
- hasBin: true
- requiresBuild: true
- dependencies:
- commander: 3.0.2
- defaults: 1.0.3
- node-addon-api: 1.7.2
- prebuild-install: 5.3.6
- dev: true
-
- /noop-logger/0.1.1:
- resolution: {integrity: sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=}
- dev: true
-
/normalize-path/3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
@@ -4365,20 +4212,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
- /npmlog/4.1.2:
- resolution: {integrity: sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==}
- dependencies:
- are-we-there-yet: 1.1.7
- console-control-strings: 1.1.0
- gauge: 2.7.4
- set-blocking: 2.0.0
- dev: true
-
- /number-is-nan/1.0.1:
- resolution: {integrity: sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=}
- engines: {node: '>=0.10.0'}
- dev: true
-
/object-assign/4.1.1:
resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=}
engines: {node: '>=0.10.0'}
@@ -4632,7 +4465,7 @@ packages:
resolution: {integrity: sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
- nanoid: 3.1.32
+ nanoid: 3.2.0
picocolors: 1.0.0
source-map-js: 1.0.1
dev: true
@@ -4641,28 +4474,6 @@ packages:
resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==}
dev: false
- /prebuild-install/5.3.6:
- resolution: {integrity: sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==}
- engines: {node: '>=6'}
- hasBin: true
- dependencies:
- detect-libc: 1.0.3
- expand-template: 2.0.3
- github-from-package: 0.0.0
- minimist: 1.2.5
- mkdirp-classic: 0.5.3
- napi-build-utils: 1.0.2
- node-abi: 2.30.1
- noop-logger: 0.1.1
- npmlog: 4.1.2
- pump: 3.0.0
- rc: 1.2.8
- simple-get: 3.1.0
- tar-fs: 2.1.1
- tunnel-agent: 0.6.0
- which-pm-runs: 1.0.0
- dev: true
-
/prelude-ls/1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@@ -4707,13 +4518,6 @@ packages:
resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==}
dev: false
- /pump/3.0.0:
- resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
- dependencies:
- end-of-stream: 1.4.4
- once: 1.4.0
- dev: true
-
/punycode/2.1.1:
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
engines: {node: '>=6'}
@@ -4746,16 +4550,6 @@ packages:
safe-buffer: 5.2.1
dev: true
- /rc/1.2.8:
- resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
- hasBin: true
- dependencies:
- deep-extend: 0.6.0
- ini: 1.3.8
- minimist: 1.2.5
- strip-json-comments: 2.0.1
- dev: true
-
/react-dom/17.0.2_react@17.0.2:
resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==}
peerDependencies:
@@ -5144,11 +4938,6 @@ packages:
object-assign: 4.1.1
dev: false
- /semver/5.7.1:
- resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
- hasBin: true
- dev: true
-
/semver/6.3.0:
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
hasBin: true
@@ -5173,10 +4962,6 @@ packages:
randombytes: 2.1.0
dev: true
- /set-blocking/2.0.0:
- resolution: {integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=}
- dev: true
-
/shebang-command/2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -5197,22 +4982,6 @@ packages:
object-inspect: 1.12.0
dev: true
- /signal-exit/3.0.6:
- resolution: {integrity: sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==}
- dev: true
-
- /simple-concat/1.0.1:
- resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
- dev: true
-
- /simple-get/3.1.0:
- resolution: {integrity: sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==}
- dependencies:
- decompress-response: 4.2.1
- once: 1.4.0
- simple-concat: 1.0.1
- dev: true
-
/simple-zstd/1.4.0:
resolution: {integrity: sha512-9zBNnu7MkwRiZm7voFUX7ehCcLO2d1FmJ2RWEVsN8Exw2tVYK9k/0/8WjPUmSmtoHOyoFTkHHaOLuPSwkgFmrA==}
dependencies:
@@ -5287,15 +5056,6 @@ packages:
resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==}
dev: true
- /string-width/1.0.2:
- resolution: {integrity: sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=}
- engines: {node: '>=0.10.0'}
- dependencies:
- code-point-at: 1.1.0
- is-fullwidth-code-point: 1.0.0
- strip-ansi: 3.0.1
- dev: true
-
/string-width/4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@@ -5353,13 +5113,6 @@ packages:
is-regexp: 1.0.0
dev: true
- /strip-ansi/3.0.1:
- resolution: {integrity: sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=}
- engines: {node: '>=0.10.0'}
- dependencies:
- ansi-regex: 2.1.1
- dev: true
-
/strip-ansi/6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
@@ -5377,11 +5130,6 @@ packages:
engines: {node: '>=10'}
dev: true
- /strip-json-comments/2.0.1:
- resolution: {integrity: sha1-PFMZQukIwml8DsNEhYwobHygpgo=}
- engines: {node: '>=0.10.0'}
- dev: true
-
/strip-json-comments/3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@@ -5474,26 +5222,6 @@ packages:
- ts-node
dev: true
- /tar-fs/2.1.1:
- resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
- dependencies:
- chownr: 1.1.4
- mkdirp-classic: 0.5.3
- pump: 3.0.0
- tar-stream: 2.2.0
- dev: true
-
- /tar-stream/2.2.0:
- resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
- engines: {node: '>=6'}
- dependencies:
- bl: 4.1.0
- end-of-stream: 1.4.4
- fs-constants: 1.0.0
- inherits: 2.0.4
- readable-stream: 3.6.0
- dev: true
-
/tar/6.1.11:
resolution: {integrity: sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==}
engines: {node: '>= 10'}
@@ -5633,12 +5361,6 @@ packages:
typescript: 4.5.4
dev: true
- /tunnel-agent/0.6.0:
- resolution: {integrity: sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=}
- dependencies:
- safe-buffer: 5.2.1
- dev: true
-
/type-check/0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -5867,10 +5589,6 @@ packages:
is-weakset: 2.0.2
dev: true
- /which-pm-runs/1.0.0:
- resolution: {integrity: sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=}
- dev: true
-
/which-typed-array/1.1.7:
resolution: {integrity: sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==}
engines: {node: '>= 0.4'}
@@ -5891,12 +5609,6 @@ packages:
isexe: 2.0.0
dev: true
- /wide-align/1.1.5:
- resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
- dependencies:
- string-width: 1.0.2
- dev: true
-
/word-wrap/1.2.3:
resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
engines: {node: '>=0.10.0'}
diff --git a/src/App.tsx b/src/App.tsx
index 5424a962..f11f98ea 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -13,7 +13,6 @@ import { useAppSelector } from '@hooks/useAppSelector';
import { Messages } from '@pages/Messages';
import { Nodes } from '@pages/Nodes';
import { NotFound } from '@pages/NotFound';
-import { Plugins } from '@pages/Plugins/Index';
import { Settings } from '@pages/settings/Index';
import { ErrorFallback } from './components/ErrorFallback';
@@ -67,7 +66,7 @@ export const App = (): JSX.Element => {
-
+
@@ -81,7 +80,6 @@ export const App = (): JSX.Element => {
)}
- {route.name === 'plugins' && }
{route.name === 'settings' && }
{route.name === false && }
diff --git a/src/components/generic/Loading.tsx b/src/components/generic/Loading.tsx
deleted file mode 100644
index 5778d4bc..00000000
--- a/src/components/generic/Loading.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import type React from 'react';
-
-export const Loading = (): JSX.Element => {
- return (
-
- );
-};
diff --git a/src/components/generic/Sidebar.tsx b/src/components/generic/Sidebar.tsx
index 2b415504..8564a43c 100644
--- a/src/components/generic/Sidebar.tsx
+++ b/src/components/generic/Sidebar.tsx
@@ -37,7 +37,7 @@ export const Sidebar = ({
{children ?? (
-
+
)}
diff --git a/src/components/generic/form/Form.tsx b/src/components/generic/form/Form.tsx
new file mode 100644
index 00000000..1003fb72
--- /dev/null
+++ b/src/components/generic/form/Form.tsx
@@ -0,0 +1,22 @@
+import type React from 'react';
+
+import { Loading } from '@meshtastic/components';
+
+export interface FormProps {
+ loading?: boolean;
+ children: React.ReactNode;
+}
+
+export const Form = ({ loading, children }: FormProps): JSX.Element => {
+ return (
+
+ );
+};
diff --git a/src/components/menu/BottomNav.tsx b/src/components/menu/BottomNav.tsx
index 7cbba3cf..f63b217d 100644
--- a/src/components/menu/BottomNav.tsx
+++ b/src/components/menu/BottomNav.tsx
@@ -26,6 +26,7 @@ import { useAppSelector } from '@hooks/useAppSelector';
import { Protobuf, Types } from '@meshtastic/meshtasticjs';
import { Tooltip } from '../generic/Tooltip';
+import { VersionInfo } from '../modals/VersionInfo';
// export interface BottomNavProps {
@@ -99,6 +100,12 @@ export const BottomNav = (): JSX.Element => {
+
{
+ setShowVersionInfo(false);
+ }}
+ />
{
diff --git a/src/components/menu/Navigation.tsx b/src/components/menu/Navigation.tsx
index c014b15c..00ef2258 100644
--- a/src/components/menu/Navigation.tsx
+++ b/src/components/menu/Navigation.tsx
@@ -1,19 +1,11 @@
import type React from 'react';
-import { FiGrid, FiMessageSquare, FiPackage, FiSettings } from 'react-icons/fi';
+import { FiGrid, FiMessageSquare, FiSettings } from 'react-icons/fi';
import type { Link } from 'type-route';
import { routes, useRoute } from '@core/router';
-type DefaultDivProps = JSX.IntrinsicElements['div'];
-
-export type NavigationProps = DefaultDivProps;
-
-export const Navigation = ({
- onClick,
- className,
- ...props
-}: NavigationProps): JSX.Element => {
+export const Navigation = (): JSX.Element => {
const route = useRoute();
return (
@@ -34,13 +26,6 @@ export const Navigation = ({
link={routes.nodes().link}
/>
-
}
- active={route.name === 'plugins'}
- link={routes.plugins().link}
- />
-
}
diff --git a/src/components/modals/VersionInfo.tsx b/src/components/modals/VersionInfo.tsx
new file mode 100644
index 00000000..c1615877
--- /dev/null
+++ b/src/components/modals/VersionInfo.tsx
@@ -0,0 +1,56 @@
+import React from 'react';
+
+import { Modal } from '@components/generic/Modal';
+import { Card } from '@meshtastic/components';
+
+export interface VersionInfoProps {
+ visible: boolean;
+ onclose: () => void;
+}
+
+export const VersionInfo = ({
+ visible,
+ onclose,
+}: VersionInfoProps): JSX.Element => {
+ // const { data } = useSWR
(
+ // `query {
+ // repository(owner: "meshtastic", name: "meshtastic-web") {
+ // ref(qualifiedName: "master") {
+ // name
+ // target {
+ // ... on Commit {
+ // history(first: 4) {
+ // edges {
+ // node {
+ // abbreviatedOid
+ // message
+ // author {
+ // avatarUrl
+ // name
+ // }
+ // }
+ // }
+ // }
+ // }
+ // }
+ // }
+ // }
+ // }`,
+ // fetcher,
+ // );
+ // console.log(data);
+
+ return (
+ {
+ onclose();
+ }}
+ >
+
+ Version Info
+ {/* {data?.sha} */}
+
+
+ );
+};
diff --git a/src/components/pages/settings/plugins/PluginsSidebar.tsx b/src/components/pages/settings/plugins/PluginsSidebar.tsx
new file mode 100644
index 00000000..73ea39c7
--- /dev/null
+++ b/src/components/pages/settings/plugins/PluginsSidebar.tsx
@@ -0,0 +1,76 @@
+import type React from 'react';
+
+import { FiCode, FiSliders } from 'react-icons/fi';
+
+import { TabButton } from '@app/components/TabButton';
+import type { Plugin } from '@app/pages/settings/Plugins';
+import { Sidebar } from '@components/generic/Sidebar';
+import { Tab } from '@headlessui/react';
+
+import { ExternalNotificationsDebugPanel } from './panels/ExternalNotifications/DebugPanel';
+import { ExternalNotificationsSettingsPlanel } from './panels/ExternalNotifications/SettingsPlanel';
+import { RangeTestDebugPanel } from './panels/RangeTest/DebugPanel';
+import { RangeTestSettingsPanel } from './panels/RangeTest/SettingsPanel';
+import { SerialDebugPanel } from './panels/Serial/DebugPanel';
+import { SerialSettingsPanel } from './panels/Serial/SettingsPanel';
+import { StoreForwardDebugPanel } from './panels/StoreForward/DebugPanel';
+import { StoreForwardSettingsPanel } from './panels/StoreForward/SettingsPanel';
+
+export interface PluginsSidebarProps {
+ plugin?: Plugin;
+ closeSidebar: () => void;
+}
+
+export const PluginsSidebar = ({
+ plugin,
+ closeSidebar,
+}: PluginsSidebarProps): JSX.Element => {
+ return (
+
+ {plugin && (
+
+
+
+
+
+
+
+
+
+
+
+
+ {plugin === 'Range Test' && (
+ <>
+
+
+ >
+ )}
+ {plugin === 'External Notifications' && (
+ <>
+
+
+ >
+ )}
+ {plugin === 'Serial' && (
+ <>
+
+
+ >
+ )}
+ {plugin === 'Store & Forward' && (
+ <>
+
+
+ >
+ )}
+
+
+ )}
+
+ );
+};
diff --git a/src/components/pages/settings/plugins/panels/ExternalNotifications/DebugPanel.tsx b/src/components/pages/settings/plugins/panels/ExternalNotifications/DebugPanel.tsx
new file mode 100644
index 00000000..95dba259
--- /dev/null
+++ b/src/components/pages/settings/plugins/panels/ExternalNotifications/DebugPanel.tsx
@@ -0,0 +1,32 @@
+import type React from 'react';
+
+import JSONPretty from 'react-json-pretty';
+
+import { useAppSelector } from '@app/hooks/useAppSelector';
+import { CopyButton } from '@components/menu/buttons/CopyButton';
+import { Tab } from '@headlessui/react';
+
+export const ExternalNotificationsDebugPanel = (): JSX.Element => {
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
+
+ const debugData = {
+ extNotificationPluginActive: preferences.extNotificationPluginActive,
+ extNotificationPluginAlertBell: preferences.extNotificationPluginAlertBell,
+ extNotificationPluginAlertMessage:
+ preferences.extNotificationPluginAlertMessage,
+ extNotificationPluginEnabled: preferences.extNotificationPluginEnabled,
+ extNotificationPluginOutput: preferences.extNotificationPluginOutput,
+ extNotificationPluginOutputMs: preferences.extNotificationPluginOutputMs,
+ };
+
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/src/components/pages/settings/plugins/panels/ExternalNotifications/SettingsPlanel.tsx b/src/components/pages/settings/plugins/panels/ExternalNotifications/SettingsPlanel.tsx
new file mode 100644
index 00000000..781bab8e
--- /dev/null
+++ b/src/components/pages/settings/plugins/panels/ExternalNotifications/SettingsPlanel.tsx
@@ -0,0 +1,97 @@
+import React from 'react';
+
+import { useForm, useWatch } from 'react-hook-form';
+import { FiSave } from 'react-icons/fi';
+
+import { Form } from '@app/components/generic/form/Form';
+import { connection } from '@app/core/connection';
+import { useAppSelector } from '@app/hooks/useAppSelector';
+import { Tab } from '@headlessui/react';
+import { Checkbox, IconButton, Input } from '@meshtastic/components';
+import type { Protobuf } from '@meshtastic/meshtasticjs';
+
+export const ExternalNotificationsSettingsPlanel = (): JSX.Element => {
+ const [loading, setLoading] = React.useState(false);
+
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
+
+ const { register, handleSubmit, formState, reset, control } =
+ useForm({
+ defaultValues: preferences,
+ });
+
+ React.useEffect(() => {
+ reset(preferences);
+ }, [reset, preferences]);
+
+ const onSubmit = handleSubmit(async (data) => {
+ setLoading(true);
+ await connection.setPreferences(data, async (): Promise => {
+ reset({ ...data });
+ setLoading(false);
+ await Promise.resolve();
+ });
+ });
+
+ const pluginEnabled = useWatch({
+ control,
+ name: 'extNotificationPluginEnabled',
+ defaultValue: false,
+ });
+
+ return (
+
+
+
+
+ => {
+ await onSubmit();
+ }}
+ icon={}
+ />
+
+
+
+ );
+};
diff --git a/src/components/pages/settings/plugins/panels/RangeTest/DebugPanel.tsx b/src/components/pages/settings/plugins/panels/RangeTest/DebugPanel.tsx
new file mode 100644
index 00000000..a877979a
--- /dev/null
+++ b/src/components/pages/settings/plugins/panels/RangeTest/DebugPanel.tsx
@@ -0,0 +1,28 @@
+import type React from 'react';
+
+import JSONPretty from 'react-json-pretty';
+
+import { useAppSelector } from '@app/hooks/useAppSelector';
+import { CopyButton } from '@components/menu/buttons/CopyButton';
+import { Tab } from '@headlessui/react';
+
+export const RangeTestDebugPanel = (): JSX.Element => {
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
+
+ const debugData = {
+ rangeTestPluginEnabled: preferences.rangeTestPluginEnabled,
+ rangeTestPluginSave: preferences.rangeTestPluginSave,
+ rangeTestPluginSender: preferences.rangeTestPluginSender,
+ };
+
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/src/components/pages/settings/plugins/panels/RangeTest/SettingsPanel.tsx b/src/components/pages/settings/plugins/panels/RangeTest/SettingsPanel.tsx
new file mode 100644
index 00000000..ec5c4c2a
--- /dev/null
+++ b/src/components/pages/settings/plugins/panels/RangeTest/SettingsPanel.tsx
@@ -0,0 +1,79 @@
+import React from 'react';
+
+import { useForm, useWatch } from 'react-hook-form';
+import { FiSave } from 'react-icons/fi';
+
+import { Form } from '@app/components/generic/form/Form';
+import { connection } from '@app/core/connection';
+import { useAppSelector } from '@app/hooks/useAppSelector';
+import { Tab } from '@headlessui/react';
+import { Checkbox, IconButton, Input } from '@meshtastic/components';
+import type { Protobuf } from '@meshtastic/meshtasticjs';
+
+export const RangeTestSettingsPanel = (): JSX.Element => {
+ const [loading, setLoading] = React.useState(false);
+
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
+
+ const { register, handleSubmit, formState, reset, control } =
+ useForm({
+ defaultValues: preferences,
+ });
+
+ React.useEffect(() => {
+ reset(preferences);
+ }, [reset, preferences]);
+
+ const onSubmit = handleSubmit(async (data) => {
+ setLoading(true);
+ await connection.setPreferences(data, async (): Promise => {
+ reset({ ...data });
+ setLoading(false);
+ await Promise.resolve();
+ });
+ });
+
+ const pluginEnabled = useWatch({
+ control,
+ name: 'rangeTestPluginEnabled',
+ defaultValue: false,
+ });
+
+ return (
+
+
+
+
+ => {
+ await onSubmit();
+ }}
+ icon={}
+ />
+
+
+
+ );
+};
diff --git a/src/components/pages/settings/plugins/panels/Serial/DebugPanel.tsx b/src/components/pages/settings/plugins/panels/Serial/DebugPanel.tsx
new file mode 100644
index 00000000..87127823
--- /dev/null
+++ b/src/components/pages/settings/plugins/panels/Serial/DebugPanel.tsx
@@ -0,0 +1,31 @@
+import type React from 'react';
+
+import JSONPretty from 'react-json-pretty';
+
+import { useAppSelector } from '@app/hooks/useAppSelector';
+import { CopyButton } from '@components/menu/buttons/CopyButton';
+import { Tab } from '@headlessui/react';
+
+export const SerialDebugPanel = (): JSX.Element => {
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
+
+ const debugData = {
+ serialpluginEnabled: preferences.serialpluginEnabled,
+ serialpluginEcho: preferences.serialpluginEcho,
+ serialpluginMode: preferences.serialpluginMode,
+ serialpluginRxd: preferences.serialpluginRxd,
+ serialpluginTxd: preferences.serialpluginTxd,
+ serialpluginTimeout: preferences.serialpluginTimeout,
+ };
+
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/src/components/pages/settings/plugins/panels/Serial/SettingsPanel.tsx b/src/components/pages/settings/plugins/panels/Serial/SettingsPanel.tsx
new file mode 100644
index 00000000..e5afb96b
--- /dev/null
+++ b/src/components/pages/settings/plugins/panels/Serial/SettingsPanel.tsx
@@ -0,0 +1,100 @@
+import React from 'react';
+
+import { useForm, useWatch } from 'react-hook-form';
+import { FiSave } from 'react-icons/fi';
+
+import { Form } from '@app/components/generic/form/Form';
+import { connection } from '@app/core/connection';
+import { useAppSelector } from '@app/hooks/useAppSelector';
+import { Tab } from '@headlessui/react';
+import { Checkbox, IconButton, Input } from '@meshtastic/components';
+import type { Protobuf } from '@meshtastic/meshtasticjs';
+
+export const SerialSettingsPanel = (): JSX.Element => {
+ const [loading, setLoading] = React.useState(false);
+
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
+
+ const { register, handleSubmit, formState, reset, control } =
+ useForm({
+ defaultValues: preferences,
+ });
+
+ React.useEffect(() => {
+ reset(preferences);
+ }, [reset, preferences]);
+
+ const onSubmit = handleSubmit(async (data) => {
+ setLoading(true);
+ await connection.setPreferences(data, async (): Promise => {
+ reset({ ...data });
+ setLoading(false);
+ await Promise.resolve();
+ });
+ });
+
+ const pluginEnabled = useWatch({
+ control,
+ name: 'serialpluginEnabled',
+ defaultValue: false,
+ });
+
+ return (
+
+
+
+
+ => {
+ await onSubmit();
+ }}
+ icon={}
+ />
+
+
+
+ );
+};
diff --git a/src/components/pages/settings/plugins/panels/StoreForward/DebugPanel.tsx b/src/components/pages/settings/plugins/panels/StoreForward/DebugPanel.tsx
new file mode 100644
index 00000000..b9dbc5c3
--- /dev/null
+++ b/src/components/pages/settings/plugins/panels/StoreForward/DebugPanel.tsx
@@ -0,0 +1,32 @@
+import type React from 'react';
+
+import JSONPretty from 'react-json-pretty';
+
+import { useAppSelector } from '@app/hooks/useAppSelector';
+import { CopyButton } from '@components/menu/buttons/CopyButton';
+import { Tab } from '@headlessui/react';
+
+export const StoreForwardDebugPanel = (): JSX.Element => {
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
+
+ const debugData = {
+ storeForwardPluginEnabled: preferences.storeForwardPluginEnabled,
+ storeForwardPluginHeartbeat: preferences.storeForwardPluginHeartbeat,
+ storeForwardPluginRecords: preferences.storeForwardPluginRecords,
+ storeForwardPluginHistoryReturnMax:
+ preferences.storeForwardPluginHistoryReturnMax,
+ storeForwardPluginHistoryReturnWindow:
+ preferences.storeForwardPluginHistoryReturnWindow,
+ };
+
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/src/components/pages/settings/plugins/panels/StoreForward/SettingsPanel.tsx b/src/components/pages/settings/plugins/panels/StoreForward/SettingsPanel.tsx
new file mode 100644
index 00000000..b5150693
--- /dev/null
+++ b/src/components/pages/settings/plugins/panels/StoreForward/SettingsPanel.tsx
@@ -0,0 +1,95 @@
+import React from 'react';
+
+import { useForm, useWatch } from 'react-hook-form';
+import { FiSave } from 'react-icons/fi';
+
+import { Form } from '@app/components/generic/form/Form';
+import { connection } from '@app/core/connection';
+import { useAppSelector } from '@app/hooks/useAppSelector';
+import { Tab } from '@headlessui/react';
+import { Checkbox, IconButton, Input } from '@meshtastic/components';
+import type { Protobuf } from '@meshtastic/meshtasticjs';
+
+export const StoreForwardSettingsPanel = (): JSX.Element => {
+ const [loading, setLoading] = React.useState(false);
+
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
+
+ const { register, handleSubmit, formState, reset, control } =
+ useForm({
+ defaultValues: preferences,
+ });
+
+ React.useEffect(() => {
+ reset(preferences);
+ }, [reset, preferences]);
+
+ const onSubmit = handleSubmit(async (data) => {
+ setLoading(true);
+ await connection.setPreferences(data, async (): Promise => {
+ reset({ ...data });
+ setLoading(false);
+ await Promise.resolve();
+ });
+ });
+
+ const pluginEnabled = useWatch({
+ control,
+ name: 'storeForwardPluginEnabled',
+ defaultValue: false,
+ });
+
+ return (
+
+
+
+
+ => {
+ await onSubmit();
+ }}
+ icon={}
+ />
+
+
+
+ );
+};
diff --git a/src/components/pages/settings/channels/ChannelsSidebar.tsx b/src/components/pages/settings/radio/channels/ChannelsSidebar.tsx
similarity index 100%
rename from src/components/pages/settings/channels/ChannelsSidebar.tsx
rename to src/components/pages/settings/radio/channels/ChannelsSidebar.tsx
diff --git a/src/components/pages/settings/channels/panels/DebugPanel.tsx b/src/components/pages/settings/radio/channels/panels/DebugPanel.tsx
similarity index 100%
rename from src/components/pages/settings/channels/panels/DebugPanel.tsx
rename to src/components/pages/settings/radio/channels/panels/DebugPanel.tsx
diff --git a/src/components/pages/settings/channels/panels/QRCodePanel.tsx b/src/components/pages/settings/radio/channels/panels/QRCodePanel.tsx
similarity index 100%
rename from src/components/pages/settings/channels/panels/QRCodePanel.tsx
rename to src/components/pages/settings/radio/channels/panels/QRCodePanel.tsx
diff --git a/src/components/pages/settings/channels/panels/SettingsPanel.tsx b/src/components/pages/settings/radio/channels/panels/SettingsPanel.tsx
similarity index 96%
rename from src/components/pages/settings/channels/panels/SettingsPanel.tsx
rename to src/components/pages/settings/radio/channels/panels/SettingsPanel.tsx
index 677f3999..e0676bcf 100644
--- a/src/components/pages/settings/channels/panels/SettingsPanel.tsx
+++ b/src/components/pages/settings/radio/channels/panels/SettingsPanel.tsx
@@ -5,7 +5,7 @@ import { useForm } from 'react-hook-form';
import { FiSave } from 'react-icons/fi';
import { MdRefresh, MdVisibility, MdVisibilityOff } from 'react-icons/md';
-import { Loading } from '@app/components/generic/Loading';
+import { Form } from '@app/components/generic/form/Form';
import { connection } from '@app/core/connection';
import { Tab } from '@headlessui/react';
import { Checkbox, IconButton, Input, Select } from '@meshtastic/components';
@@ -73,8 +73,7 @@ export const SettingsPanel = ({ channel }: SettingsPanelProps): JSX.Element => {
return (
- {loading && }
-
+
>;
-}
-
-export const ExternalNotification = ({
- navOpen,
- setNavOpen,
-}: ExternalNotificationProps): JSX.Element => {
- const preferences = useAppSelector(
- (state) => state.meshtastic.radio.preferences,
- );
-
- const { register, handleSubmit, formState, reset, control } =
- useForm({
- defaultValues: {
- extNotificationPluginActive: preferences.extNotificationPluginActive,
- extNotificationPluginAlertBell:
- preferences.extNotificationPluginAlertBell,
- extNotificationPluginAlertMessage:
- preferences.extNotificationPluginAlertMessage,
- extNotificationPluginEnabled: preferences.extNotificationPluginEnabled,
- extNotificationPluginOutput: preferences.extNotificationPluginOutput,
- extNotificationPluginOutputMs:
- preferences.extNotificationPluginOutputMs,
- },
- });
-
- 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, async (): Promise => {
- //add loading indicator
- reset({ ...data });
- await Promise.resolve();
- });
- });
-
- //todo, add loading indicator
-
- const watchExternalNotificationPluginEnabled = useWatch({
- control,
- name: 'extNotificationPluginEnabled',
- defaultValue: false,
- });
-
- return (
- }
- onClick={(): void => {
- setNavOpen && setNavOpen(!navOpen);
- }}
- />
- }
- footer={
-
- }
- >
-
-
- );
-};
diff --git a/src/pages/Plugins/Files.tsx b/src/pages/Plugins/Files.tsx
deleted file mode 100644
index ccf0b5c4..00000000
--- a/src/pages/Plugins/Files.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-import type React from 'react';
-
-// import { DefaultExtensionType, defaultStyles, FileIcon } from 'react-file-icon';
-import { FiMenu, FiTrash, FiUploadCloud } from 'react-icons/fi';
-import useSWR from 'swr';
-
-import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
-import { connectionUrl } from '@core/connection';
-import fetcher from '@core/utils/fetcher';
-import { Card, IconButton } from '@meshtastic/components';
-
-export interface RangeTestProps {
- navOpen?: boolean;
- setNavOpen?: React.Dispatch>;
-}
-interface IFile {
- name: string;
- nameModified: string;
- size: number;
-}
-interface IFiles {
- data: {
- files: IFile[];
- filesystem: {
- free: number;
- total: number;
- used: number;
- };
- };
-
- status: boolean;
-}
-
-export const Files = ({ navOpen, setNavOpen }: RangeTestProps): JSX.Element => {
- const { data } = useSWR(
- `http://${connectionUrl}/json/spiffs/browse/static`,
- fetcher,
- );
-
- return (
- }
- onClick={(): void => {
- setNavOpen && setNavOpen(!navOpen);
- }}
- />
- }
- >
-
-
- {data ? (
-
-
-
- {JSON.stringify(data.data.filesystem.used)} bytes total
-
-
- ) : (
- Loading...
- )}
-
-
} />}
- className="md:w-1/3"
- >
- {data ? (
-
- {data.data.files.map((file: IFile) => (
-
-
-
=> {
- // await fetch(
- // `http://${connectionUrl}/json/spiffs/delete/static?remove=${file.name}`,
- // {
- // method: 'DELETE',
- // },
- // );
- // }}
- icon={}
- />
-
- ))}
-
- ) : (
-
Loading...
- )}
-
-
-
- );
-};
diff --git a/src/pages/Plugins/Index.tsx b/src/pages/Plugins/Index.tsx
deleted file mode 100644
index 2f93530b..00000000
--- a/src/pages/Plugins/Index.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import type React from 'react';
-
-import {
- FiAlignLeft,
- FiBell,
- FiFastForward,
- FiFileText,
- FiRss,
-} from 'react-icons/fi';
-
-import { PageLayout } from '@components/templates/PageLayout';
-
-import { ExternalNotification } from './ExternalNotification';
-import { Files } from './Files';
-import { RangeTest } from './RangeTest';
-import { Serial } from './Serial';
-import { StoreAndForward } from './StoreAndForward';
-
-export const Plugins = (): JSX.Element => {
- return (
- ,
- },
- {
- title: 'File Browser',
- description: 'HTTP only file browser',
- icon: ,
- },
- {
- title: 'External Notification',
- description: 'External hardware alerts',
- icon: ,
- },
- {
- title: 'Serial',
- description: 'Send serial data over the mesh',
- icon: ,
- },
- {
- title: 'Store & Forward',
- description: 'Retrive message history',
- icon: ,
- },
- ]}
- panels={[
- ,
- ,
- ,
- ,
- ,
- ]}
- />
- );
-};
diff --git a/src/pages/Plugins/RangeTest.tsx b/src/pages/Plugins/RangeTest.tsx
deleted file mode 100644
index 8a13849c..00000000
--- a/src/pages/Plugins/RangeTest.tsx
+++ /dev/null
@@ -1,106 +0,0 @@
-import React from 'react';
-
-import { useForm, useWatch } from 'react-hook-form';
-import { FiMenu } from 'react-icons/fi';
-
-import { FormFooter } from '@components/FormFooter';
-import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
-import { connection } from '@core/connection';
-import { useAppSelector } from '@hooks/useAppSelector';
-import { Card, Checkbox, IconButton, Input } from '@meshtastic/components';
-import type { RadioConfig_UserPreferences } from '@meshtastic/meshtasticjs/dist/generated';
-
-export interface RangeTestProps {
- navOpen?: boolean;
- setNavOpen?: React.Dispatch>;
-}
-
-export const RangeTest = ({
- navOpen,
- setNavOpen,
-}: RangeTestProps): JSX.Element => {
- const preferences = useAppSelector(
- (state) => state.meshtastic.radio.preferences,
- );
-
- const { register, handleSubmit, formState, reset, control } =
- useForm({
- defaultValues: {
- rangeTestPluginEnabled: preferences.rangeTestPluginEnabled,
- rangeTestPluginSave: preferences.rangeTestPluginSave,
- rangeTestPluginSender: preferences.rangeTestPluginSender,
- },
- });
-
- React.useEffect(() => {
- reset({
- rangeTestPluginEnabled: preferences.rangeTestPluginEnabled,
- rangeTestPluginSave: preferences.rangeTestPluginSave,
- rangeTestPluginSender: preferences.rangeTestPluginSender,
- });
- }, [reset, preferences]);
-
- const onSubmit = handleSubmit((data) => {
- void connection.setPreferences(data, async (): Promise => {
- //add loading indicator
- reset({ ...data });
- await Promise.resolve();
- });
- });
-
- //todo, add loading indicator
-
- const watchRangeTestPluginEnabled = useWatch({
- control,
- name: 'rangeTestPluginEnabled',
- defaultValue: false,
- });
-
- return (
- }
- onClick={(): void => {
- setNavOpen && setNavOpen(!navOpen);
- }}
- />
- }
- footer={
-
- }
- >
-
-
- );
-};
diff --git a/src/pages/Plugins/Serial.tsx b/src/pages/Plugins/Serial.tsx
deleted file mode 100644
index b176a8b1..00000000
--- a/src/pages/Plugins/Serial.tsx
+++ /dev/null
@@ -1,133 +0,0 @@
-import React from 'react';
-
-import { useForm, useWatch } from 'react-hook-form';
-import { FiMenu } from 'react-icons/fi';
-
-import { FormFooter } from '@components/FormFooter';
-import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
-import { connection } from '@core/connection';
-import { useAppSelector } from '@hooks/useAppSelector';
-import { Card, Checkbox, IconButton, Input } from '@meshtastic/components';
-import type { RadioConfig_UserPreferences } from '@meshtastic/meshtasticjs/dist/generated';
-
-export interface SerialProps {
- navOpen?: boolean;
- setNavOpen?: React.Dispatch>;
-}
-
-export const Serial = ({ navOpen, setNavOpen }: SerialProps): JSX.Element => {
- const preferences = useAppSelector(
- (state) => state.meshtastic.radio.preferences,
- );
-
- const { register, handleSubmit, formState, reset, control } =
- useForm({
- defaultValues: {
- serialpluginEnabled: preferences.serialpluginEnabled,
- serialpluginEcho: preferences.serialpluginEcho,
- serialpluginMode: preferences.serialpluginMode,
- serialpluginRxd: preferences.serialpluginRxd,
- serialpluginTimeout: preferences.serialpluginTimeout,
- serialpluginTxd: preferences.serialpluginTxd,
- },
- });
-
- 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, async (): Promise => {
- //add loading indicator
- reset({ ...data });
- await Promise.resolve();
- });
- });
- //todo, add loading indicator
-
- const watchSerialPluginEnabled = useWatch({
- control,
- name: 'serialpluginEnabled',
- defaultValue: false,
- });
-
- return (
- }
- onClick={(): void => {
- setNavOpen && setNavOpen(!navOpen);
- }}
- />
- }
- footer={
-
- }
- >
-
-
- );
-};
diff --git a/src/pages/Plugins/StoreAndForward.tsx b/src/pages/Plugins/StoreAndForward.tsx
deleted file mode 100644
index 8379abde..00000000
--- a/src/pages/Plugins/StoreAndForward.tsx
+++ /dev/null
@@ -1,98 +0,0 @@
-import React from 'react';
-
-import { useForm, useWatch } from 'react-hook-form';
-import { FiMenu } from 'react-icons/fi';
-
-import { FormFooter } from '@components/FormFooter';
-import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
-import { connection } from '@core/connection';
-import { useAppSelector } from '@hooks/useAppSelector';
-import { Card, Checkbox, IconButton, Input } from '@meshtastic/components';
-import type { RadioConfig_UserPreferences } from '@meshtastic/meshtasticjs/dist/generated';
-
-export interface StoreAndForwardProps {
- navOpen?: boolean;
- setNavOpen?: React.Dispatch>;
-}
-
-export const StoreAndForward = ({
- navOpen,
- setNavOpen,
-}: StoreAndForwardProps): JSX.Element => {
- const preferences = useAppSelector(
- (state) => state.meshtastic.radio.preferences,
- );
-
- const { register, handleSubmit, formState, reset, control } =
- useForm({
- defaultValues: {
- storeForwardPluginEnabled: preferences.storeForwardPluginEnabled,
- storeForwardPluginRecords: preferences.storeForwardPluginRecords,
- },
- });
-
- React.useEffect(() => {
- reset({
- storeForwardPluginEnabled: preferences.storeForwardPluginEnabled,
- storeForwardPluginRecords: preferences.storeForwardPluginRecords,
- });
- }, [reset, preferences]);
-
- const onSubmit = handleSubmit((data) => {
- void connection.setPreferences(data, async (): Promise => {
- //add loading indicator
- reset({ ...data });
- await Promise.resolve();
- });
- });
- //todo, add loading indicator
-
- const watchStoreForwardPluginEnabled = useWatch({
- control,
- name: 'storeForwardPluginEnabled',
- defaultValue: false,
- });
-
- return (
- }
- onClick={(): void => {
- setNavOpen && setNavOpen(!navOpen);
- }}
- />
- }
- footer={
-
- }
- >
-
-
- );
-};
diff --git a/src/pages/settings/Channels.tsx b/src/pages/settings/Channels.tsx
index d0222ecc..14df0bd5 100644
--- a/src/pages/settings/Channels.tsx
+++ b/src/pages/settings/Channels.tsx
@@ -11,7 +11,6 @@ import {
import { Tooltip } from '@app/components/generic/Tooltip';
import type { ChannelData } from '@app/core/slices/meshtasticSlice';
import { FormFooter } from '@components/FormFooter';
-import { Loading } from '@components/generic/Loading';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
import { useAppSelector } from '@hooks/useAppSelector';
@@ -21,11 +20,12 @@ import {
Checkbox,
IconButton,
Input,
+ Loading,
Select,
} from '@meshtastic/components';
import { Protobuf } from '@meshtastic/meshtasticjs';
-import { ChannelsSidebar } from '../../components/pages/settings/channels/ChannelsSidebar';
+import { ChannelsSidebar } from '../../components/pages/settings/radio/channels/ChannelsSidebar';
export interface ChannelsProps {
navOpen?: boolean;
diff --git a/src/pages/settings/Index.tsx b/src/pages/settings/Index.tsx
index 40c3f407..c9c68518 100644
--- a/src/pages/settings/Index.tsx
+++ b/src/pages/settings/Index.tsx
@@ -4,6 +4,7 @@ import {
FiLayers,
FiLayout,
FiMapPin,
+ FiPackage,
FiRadio,
FiUser,
FiWifi,
@@ -15,6 +16,7 @@ import { PageLayout } from '@components/templates/PageLayout';
import { Channels } from './Channels';
import { Interface } from './Interface';
+import { Plugins } from './Plugins';
import { Position } from './Position';
import { Power } from './Power';
import { Radio } from './Radio';
@@ -31,8 +33,9 @@ export const Settings = (): JSX.Element => {
,
,
,
- ,
- ,
+ ,
+ ,
+ ,
];
const sidebarItems: SidebarItemProps[] = [
@@ -56,6 +59,11 @@ export const Settings = (): JSX.Element => {
description: 'Manage channels',
icon: ,
},
+ {
+ title: 'Plugins',
+ description: 'Plugins',
+ icon: ,
+ },
{
title: 'Interface',
description: 'Language and UI settings',
diff --git a/src/pages/settings/Plugins.tsx b/src/pages/settings/Plugins.tsx
new file mode 100644
index 00000000..67afdc11
--- /dev/null
+++ b/src/pages/settings/Plugins.tsx
@@ -0,0 +1,130 @@
+import React from 'react';
+
+import {
+ FiAlignLeft,
+ FiBell,
+ FiExternalLink,
+ FiFastForward,
+ FiMenu,
+ FiRss,
+} from 'react-icons/fi';
+
+import { PluginsSidebar } from '@app/components/pages/settings/plugins/PluginsSidebar';
+import { useAppSelector } from '@app/hooks/useAppSelector';
+import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
+import { Button, Card, IconButton } from '@meshtastic/components';
+
+export type Plugin =
+ | 'Range Test'
+ | 'External Notifications'
+ | 'Serial'
+ | 'Store & Forward';
+
+export interface PluginsProps {
+ navOpen?: boolean;
+ setNavOpen?: React.Dispatch>;
+}
+
+export const Plugins = ({ navOpen, setNavOpen }: PluginsProps): JSX.Element => {
+ const [sidebarOpen, setSidebarOpen] = React.useState(false);
+ const [selectedPlugin, setSelectedPlugin] = React.useState<
+ Plugin | undefined
+ >();
+ const preferences = useAppSelector(
+ (state) => state.meshtastic.radio.preferences,
+ );
+
+ const plugins: {
+ name: Plugin;
+ description: string;
+ enabled: boolean;
+ icon: JSX.Element;
+ }[] = [
+ {
+ name: 'Range Test',
+ description: 'Test the range of your Meshtastic node',
+ enabled: preferences.rangeTestPluginEnabled,
+ icon: ,
+ },
+ {
+ name: 'External Notifications',
+ description: 'External hardware alerts',
+ enabled: preferences.extNotificationPluginEnabled,
+ icon: ,
+ },
+ {
+ name: 'Serial',
+ description: 'Send serial data over the mesh',
+ enabled: preferences.serialpluginEnabled,
+ icon: ,
+ },
+ {
+ name: 'Store & Forward',
+ description: 'Retrive message history',
+ enabled: preferences.storeForwardPluginEnabled,
+ icon: ,
+ },
+ ];
+
+ return (
+ <>
+ }
+ onClick={(): void => {
+ setNavOpen && setNavOpen(!navOpen);
+ }}
+ />
+ }
+ >
+
+
+ {plugins.map((plugin, index) => (
+
{
+ setSelectedPlugin(plugin.name);
+ setSidebarOpen(true);
+ }}
+ className={`flex justify-between p-2 border border-gray-300 dark:border-gray-600 bg-gray-100 rounded-md dark:bg-secondaryDark shadow-md ${
+ selectedPlugin === plugin.name
+ ? 'border-primary dark:border-primary'
+ : ''
+ }`}
+ >
+
+
+
+
{plugin.icon}
+ {plugin.name}
+
+
+
+ } />
+
+
+ ))}
+
+
+
+ {sidebarOpen && (
+ {
+ setSidebarOpen(false);
+ }}
+ plugin={selectedPlugin}
+ />
+ )}
+ >
+ );
+};