Move plugins to settings page
This commit is contained in:
+2
-2
@@ -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",
|
||||
|
||||
Generated
+28
-316
@@ -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'}
|
||||
|
||||
+1
-3
@@ -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 => {
|
||||
<div className="flex">
|
||||
<Logo />
|
||||
</div>
|
||||
<Navigation className="flex" />
|
||||
<Navigation />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,7 +80,6 @@ export const App = (): JSX.Element => {
|
||||
<Nodes />
|
||||
</MapboxProvider>
|
||||
)}
|
||||
{route.name === 'plugins' && <Plugins />}
|
||||
{route.name === 'settings' && <Settings />}
|
||||
{route.name === false && <NotFound />}
|
||||
</ErrorBoundary>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import type React from 'react';
|
||||
|
||||
export const Loading = (): JSX.Element => {
|
||||
return (
|
||||
<div className="absolute top-0 bottom-0 left-0 right-0 z-10 flex rounded-md backdrop-filter backdrop-blur-sm">
|
||||
<div className="m-auto text-lg font-medium text-gray-400">Loading</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -37,7 +37,7 @@ export const Sidebar = ({
|
||||
</div>
|
||||
</div>
|
||||
{children ?? (
|
||||
<div className="flex flex-grow bg-gray-100 dark:bg-primaryDark">
|
||||
<div className="flex flex-grow bg-gray-50 dark:bg-primaryDark">
|
||||
<div className="m-auto text-lg font-medium">Please select item</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -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 (
|
||||
<form
|
||||
onSubmit={(e): void => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
className="relative flex-grow gap-3 p-2"
|
||||
>
|
||||
{loading && <Loading />}
|
||||
{children}
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -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 => {
|
||||
</div>
|
||||
|
||||
<div className="flex">
|
||||
<VersionInfo
|
||||
visible={showVersionInfo}
|
||||
onclose={(): void => {
|
||||
setShowVersionInfo(false);
|
||||
}}
|
||||
/>
|
||||
<Tooltip contents={`Current Commit`}>
|
||||
<div
|
||||
onClick={(): void => {
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
<NavLink
|
||||
name="Plugins"
|
||||
icon={<FiPackage className="w-5 h-5 my-auto group-active:scale-90" />}
|
||||
active={route.name === 'plugins'}
|
||||
link={routes.plugins().link}
|
||||
/>
|
||||
|
||||
<NavLink
|
||||
name="Settings"
|
||||
icon={<FiSettings className="w-5 h-5 my-auto group-active:scale-90" />}
|
||||
|
||||
@@ -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<CommitHistory>(
|
||||
// `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 (
|
||||
<Modal
|
||||
open={visible}
|
||||
onClose={(): void => {
|
||||
onclose();
|
||||
}}
|
||||
>
|
||||
<Card>
|
||||
<div className="w-full max-w-3xl p-10">Version Info</div>
|
||||
{/* {data?.sha} */}
|
||||
</Card>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<Sidebar
|
||||
title={plugin ?? 'Please select plugin'}
|
||||
tagline={plugin ? 'settings' : '...'}
|
||||
closeSidebar={closeSidebar}
|
||||
>
|
||||
{plugin && (
|
||||
<Tab.Group>
|
||||
<div className="shadow-md">
|
||||
<Tab.List className="flex justify-between border-b border-gray-300 dark:border-gray-600">
|
||||
<TabButton>
|
||||
<FiSliders />
|
||||
</TabButton>
|
||||
<TabButton>
|
||||
<FiCode />
|
||||
</TabButton>
|
||||
</Tab.List>
|
||||
</div>
|
||||
<Tab.Panels className="flex flex-grow overflow-y-auto bg-gray-100 dark:bg-primaryDark">
|
||||
{plugin === 'Range Test' && (
|
||||
<>
|
||||
<RangeTestSettingsPanel />
|
||||
<RangeTestDebugPanel />
|
||||
</>
|
||||
)}
|
||||
{plugin === 'External Notifications' && (
|
||||
<>
|
||||
<ExternalNotificationsSettingsPlanel />
|
||||
<ExternalNotificationsDebugPanel />
|
||||
</>
|
||||
)}
|
||||
{plugin === 'Serial' && (
|
||||
<>
|
||||
<SerialSettingsPanel />
|
||||
<SerialDebugPanel />
|
||||
</>
|
||||
)}
|
||||
{plugin === 'Store & Forward' && (
|
||||
<>
|
||||
<StoreForwardSettingsPanel />
|
||||
<StoreForwardDebugPanel />
|
||||
</>
|
||||
)}
|
||||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
)}
|
||||
</Sidebar>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<Tab.Panel className="relative">
|
||||
<div className="fixed right-0 m-2">
|
||||
<CopyButton data={JSON.stringify(debugData)} />
|
||||
</div>
|
||||
<JSONPretty className="max-w-sm" data={debugData} />
|
||||
</Tab.Panel>
|
||||
);
|
||||
};
|
||||
@@ -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<Protobuf.RadioConfig_UserPreferences>({
|
||||
defaultValues: preferences,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
reset(preferences);
|
||||
}, [reset, preferences]);
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
setLoading(true);
|
||||
await connection.setPreferences(data, async (): Promise<void> => {
|
||||
reset({ ...data });
|
||||
setLoading(false);
|
||||
await Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const pluginEnabled = useWatch({
|
||||
control,
|
||||
name: 'extNotificationPluginEnabled',
|
||||
defaultValue: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<Tab.Panel className="flex flex-col w-full">
|
||||
<Form loading={loading}>
|
||||
<Checkbox
|
||||
label="Plugin Enabled"
|
||||
{...register('extNotificationPluginEnabled')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Active"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('extNotificationPluginActive')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Bell"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('extNotificationPluginAlertBell')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Message"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('extNotificationPluginAlertMessage')}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Output"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('extNotificationPluginOutput', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Output MS"
|
||||
suffix="ms"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('extNotificationPluginOutputMs', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
</Form>
|
||||
<div className="flex w-full bg-white dark:bg-secondaryDark">
|
||||
<div className="p-2 ml-auto">
|
||||
<IconButton
|
||||
disabled={!formState.isDirty}
|
||||
onClick={async (): Promise<void> => {
|
||||
await onSubmit();
|
||||
}}
|
||||
icon={<FiSave />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Tab.Panel>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<Tab.Panel className="relative">
|
||||
<div className="fixed right-0 m-2">
|
||||
<CopyButton data={JSON.stringify(debugData)} />
|
||||
</div>
|
||||
<JSONPretty className="max-w-sm" data={debugData} />
|
||||
</Tab.Panel>
|
||||
);
|
||||
};
|
||||
@@ -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<Protobuf.RadioConfig_UserPreferences>({
|
||||
defaultValues: preferences,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
reset(preferences);
|
||||
}, [reset, preferences]);
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
setLoading(true);
|
||||
await connection.setPreferences(data, async (): Promise<void> => {
|
||||
reset({ ...data });
|
||||
setLoading(false);
|
||||
await Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const pluginEnabled = useWatch({
|
||||
control,
|
||||
name: 'rangeTestPluginEnabled',
|
||||
defaultValue: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<Tab.Panel className="flex flex-col w-full">
|
||||
<Form loading={loading}>
|
||||
<Checkbox
|
||||
label="Range Test Plugin Enabled?"
|
||||
{...register('rangeTestPluginEnabled')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Range Test Plugin Save?"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('rangeTestPluginSave')}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Message Interval"
|
||||
disabled={!pluginEnabled}
|
||||
suffix="Seconds"
|
||||
{...register('rangeTestPluginSender', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
</Form>
|
||||
<div className="flex w-full bg-white dark:bg-secondaryDark">
|
||||
<div className="p-2 ml-auto">
|
||||
<IconButton
|
||||
disabled={!formState.isDirty}
|
||||
onClick={async (): Promise<void> => {
|
||||
await onSubmit();
|
||||
}}
|
||||
icon={<FiSave />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Tab.Panel>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<Tab.Panel className="relative">
|
||||
<div className="fixed right-0 m-2">
|
||||
<CopyButton data={JSON.stringify(debugData)} />
|
||||
</div>
|
||||
<JSONPretty className="max-w-sm" data={debugData} />
|
||||
</Tab.Panel>
|
||||
);
|
||||
};
|
||||
@@ -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<Protobuf.RadioConfig_UserPreferences>({
|
||||
defaultValues: preferences,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
reset(preferences);
|
||||
}, [reset, preferences]);
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
setLoading(true);
|
||||
await connection.setPreferences(data, async (): Promise<void> => {
|
||||
reset({ ...data });
|
||||
setLoading(false);
|
||||
await Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const pluginEnabled = useWatch({
|
||||
control,
|
||||
name: 'serialpluginEnabled',
|
||||
defaultValue: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<Tab.Panel className="flex flex-col w-full">
|
||||
<Form loading={loading}>
|
||||
<Checkbox label="Plugin Enabled" {...register('serialpluginEnabled')} />
|
||||
<Checkbox
|
||||
label="Echo"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('serialpluginEcho')}
|
||||
/>
|
||||
|
||||
<Input
|
||||
type="number"
|
||||
label="RX"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('serialpluginRxd', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="TX"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('serialpluginTxd', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Mode"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('serialpluginMode', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Timeout"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('serialpluginTimeout', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
</Form>
|
||||
<div className="flex w-full bg-white dark:bg-secondaryDark">
|
||||
<div className="p-2 ml-auto">
|
||||
<IconButton
|
||||
disabled={!formState.isDirty}
|
||||
onClick={async (): Promise<void> => {
|
||||
await onSubmit();
|
||||
}}
|
||||
icon={<FiSave />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Tab.Panel>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<Tab.Panel className="relative">
|
||||
<div className="fixed right-0 m-2">
|
||||
<CopyButton data={JSON.stringify(debugData)} />
|
||||
</div>
|
||||
<JSONPretty className="max-w-sm" data={debugData} />
|
||||
</Tab.Panel>
|
||||
);
|
||||
};
|
||||
@@ -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<Protobuf.RadioConfig_UserPreferences>({
|
||||
defaultValues: preferences,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
reset(preferences);
|
||||
}, [reset, preferences]);
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
setLoading(true);
|
||||
await connection.setPreferences(data, async (): Promise<void> => {
|
||||
reset({ ...data });
|
||||
setLoading(false);
|
||||
await Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const pluginEnabled = useWatch({
|
||||
control,
|
||||
name: 'storeForwardPluginEnabled',
|
||||
defaultValue: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<Tab.Panel className="flex flex-col w-full">
|
||||
<Form loading={loading}>
|
||||
<Checkbox
|
||||
label="Plugin Enabled"
|
||||
{...register('storeForwardPluginEnabled')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Heartbeat Enabled"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('storeForwardPluginHeartbeat')}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Number of records"
|
||||
suffix="Records"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('storeForwardPluginRecords', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="History return max"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('storeForwardPluginHistoryReturnMax', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="History return window"
|
||||
disabled={!pluginEnabled}
|
||||
{...register('storeForwardPluginHistoryReturnWindow', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
</Form>
|
||||
<div className="flex w-full bg-white dark:bg-secondaryDark">
|
||||
<div className="p-2 ml-auto">
|
||||
<IconButton
|
||||
disabled={!formState.isDirty}
|
||||
onClick={async (): Promise<void> => {
|
||||
await onSubmit();
|
||||
}}
|
||||
icon={<FiSave />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Tab.Panel>
|
||||
);
|
||||
};
|
||||
+3
-4
@@ -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 (
|
||||
<Tab.Panel className="flex flex-col w-full">
|
||||
{loading && <Loading />}
|
||||
<form className="flex-grow gap-3 p-2">
|
||||
<Form loading={loading}>
|
||||
{channel?.index !== 0 && (
|
||||
<>
|
||||
<Checkbox
|
||||
@@ -122,7 +121,7 @@ export const SettingsPanel = ({ channel }: SettingsPanelProps): JSX.Element => {
|
||||
/>
|
||||
<Checkbox label="Uplink Enabled" {...register('uplinkEnabled')} />
|
||||
<Checkbox label="Downlink Enabled" {...register('downlinkEnabled')} />
|
||||
</form>
|
||||
</Form>
|
||||
<div className="flex w-full bg-white dark:bg-secondaryDark">
|
||||
<div className="p-2 ml-auto">
|
||||
<IconButton
|
||||
@@ -3,6 +3,5 @@ import { createRouter, defineRoute } from 'type-route';
|
||||
export const { RouteProvider, useRoute, routes } = createRouter({
|
||||
messages: defineRoute('/'),
|
||||
nodes: defineRoute('/nodes'),
|
||||
plugins: defineRoute('/plugins'),
|
||||
settings: defineRoute('/settings'),
|
||||
});
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import { FiMenu } from 'react-icons/fi';
|
||||
|
||||
import { FormFooter } from '@app/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 ExternalNotificationProps {
|
||||
navOpen?: boolean;
|
||||
setNavOpen?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
export const ExternalNotification = ({
|
||||
navOpen,
|
||||
setNavOpen,
|
||||
}: ExternalNotificationProps): JSX.Element => {
|
||||
const preferences = useAppSelector(
|
||||
(state) => state.meshtastic.radio.preferences,
|
||||
);
|
||||
|
||||
const { register, handleSubmit, formState, reset, control } =
|
||||
useForm<RadioConfig_UserPreferences>({
|
||||
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<void> => {
|
||||
//add loading indicator
|
||||
reset({ ...data });
|
||||
await Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
//todo, add loading indicator
|
||||
|
||||
const watchExternalNotificationPluginEnabled = useWatch({
|
||||
control,
|
||||
name: 'extNotificationPluginEnabled',
|
||||
defaultValue: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<PrimaryTemplate
|
||||
title="External Notification"
|
||||
tagline="Plugin"
|
||||
leftButton={
|
||||
<IconButton
|
||||
icon={<FiMenu className="w-5 h-5" />}
|
||||
onClick={(): void => {
|
||||
setNavOpen && setNavOpen(!navOpen);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<FormFooter
|
||||
dirty={formState.isDirty}
|
||||
saveAction={onSubmit}
|
||||
clearAction={reset}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className="w-full space-y-4">
|
||||
<Card>
|
||||
<div className="w-full max-w-3xl p-10 md:max-w-xl">
|
||||
<form onSubmit={onSubmit}>
|
||||
<Checkbox
|
||||
label="Plugin Enabled"
|
||||
{...register('extNotificationPluginEnabled')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Active"
|
||||
disabled={!watchExternalNotificationPluginEnabled}
|
||||
{...register('extNotificationPluginActive')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Bell"
|
||||
disabled={!watchExternalNotificationPluginEnabled}
|
||||
{...register('extNotificationPluginAlertBell')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Message"
|
||||
disabled={!watchExternalNotificationPluginEnabled}
|
||||
{...register('extNotificationPluginAlertMessage')}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Output"
|
||||
disabled={!watchExternalNotificationPluginEnabled}
|
||||
{...register('extNotificationPluginOutput', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Output MS"
|
||||
disabled={!watchExternalNotificationPluginEnabled}
|
||||
{...register('extNotificationPluginOutputMs', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</PrimaryTemplate>
|
||||
);
|
||||
};
|
||||
@@ -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<React.SetStateAction<boolean>>;
|
||||
}
|
||||
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<IFiles>(
|
||||
`http://${connectionUrl}/json/spiffs/browse/static`,
|
||||
fetcher,
|
||||
);
|
||||
|
||||
return (
|
||||
<PrimaryTemplate
|
||||
title="File Browser"
|
||||
tagline="Plugin"
|
||||
leftButton={
|
||||
<IconButton
|
||||
icon={<FiMenu className="w-5 h-5" />}
|
||||
onClick={(): void => {
|
||||
setNavOpen && setNavOpen(!navOpen);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col justify-between w-full gap-4 md:flex-row-reverse">
|
||||
<Card title="SPIFFS" description="Statistics">
|
||||
{data ? (
|
||||
<div className="flex">
|
||||
<div className="mx-auto my-4 bg-gray-500 rounded-3xl">
|
||||
<div></div>
|
||||
{JSON.stringify(data.data.filesystem.used)} bytes total
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>Loading...</div>
|
||||
)}
|
||||
</Card>
|
||||
<Card
|
||||
title="Files"
|
||||
description="SPIFFS Contents"
|
||||
buttons={<IconButton icon={<FiUploadCloud className="w-8 h-8" />} />}
|
||||
className="md:w-1/3"
|
||||
>
|
||||
{data ? (
|
||||
<div className="flex flex-col my-4 space-y-2">
|
||||
{data.data.files.map((file: IFile) => (
|
||||
<div
|
||||
key={file.name}
|
||||
className="flex justify-between mx-4 bg-gray-300 rounded-md dark:bg-secondaryDark "
|
||||
>
|
||||
<div className="flex p-2 max-h-12">
|
||||
<div className="flex w-12">
|
||||
{/* <FileIcon
|
||||
extension={
|
||||
(file.nameModified ?? file.name).split('.')[
|
||||
(file.nameModified ?? file.name).split('.').length -
|
||||
1
|
||||
]
|
||||
}
|
||||
{...defaultStyles[
|
||||
(file.nameModified ?? file.name).split('.')[
|
||||
(file.nameModified ?? file.name).split('.').length -
|
||||
1
|
||||
] as DefaultExtensionType
|
||||
]}
|
||||
/> */}
|
||||
</div>
|
||||
<a
|
||||
href={`http://${connectionUrl}/${file.name.replace(
|
||||
'static/',
|
||||
'',
|
||||
)}`}
|
||||
className="my-auto font-semibold"
|
||||
>
|
||||
{file.nameModified ?? file.name}
|
||||
</a>
|
||||
</div>
|
||||
<IconButton
|
||||
className="mx-2 my-auto"
|
||||
// confirmAction={async (): Promise<void> => {
|
||||
// await fetch(
|
||||
// `http://${connectionUrl}/json/spiffs/delete/static?remove=${file.name}`,
|
||||
// {
|
||||
// method: 'DELETE',
|
||||
// },
|
||||
// );
|
||||
// }}
|
||||
icon={<FiTrash className="w-5 h-5" />}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div>Loading...</div>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</PrimaryTemplate>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<PageLayout
|
||||
title="Plugins"
|
||||
sidebarItems={[
|
||||
{
|
||||
title: 'Range Test',
|
||||
description: 'Test the range of your Meshtastic node',
|
||||
icon: <FiRss className="flex-shrink-0 w-6 h-6" />,
|
||||
},
|
||||
{
|
||||
title: 'File Browser',
|
||||
description: 'HTTP only file browser',
|
||||
icon: <FiFileText className="flex-shrink-0 w-6 h-6" />,
|
||||
},
|
||||
{
|
||||
title: 'External Notification',
|
||||
description: 'External hardware alerts',
|
||||
icon: <FiBell className="flex-shrink-0 w-6 h-6" />,
|
||||
},
|
||||
{
|
||||
title: 'Serial',
|
||||
description: 'Send serial data over the mesh',
|
||||
icon: <FiAlignLeft className="flex-shrink-0 w-6 h-6" />,
|
||||
},
|
||||
{
|
||||
title: 'Store & Forward',
|
||||
description: 'Retrive message history',
|
||||
icon: <FiFastForward className="flex-shrink-0 w-6 h-6" />,
|
||||
},
|
||||
]}
|
||||
panels={[
|
||||
<RangeTest key={1} />,
|
||||
<Files key={2} />,
|
||||
<ExternalNotification key={3} />,
|
||||
<Serial key={4} />,
|
||||
<StoreAndForward key={5} />,
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -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<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
export const RangeTest = ({
|
||||
navOpen,
|
||||
setNavOpen,
|
||||
}: RangeTestProps): JSX.Element => {
|
||||
const preferences = useAppSelector(
|
||||
(state) => state.meshtastic.radio.preferences,
|
||||
);
|
||||
|
||||
const { register, handleSubmit, formState, reset, control } =
|
||||
useForm<RadioConfig_UserPreferences>({
|
||||
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<void> => {
|
||||
//add loading indicator
|
||||
reset({ ...data });
|
||||
await Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
//todo, add loading indicator
|
||||
|
||||
const watchRangeTestPluginEnabled = useWatch({
|
||||
control,
|
||||
name: 'rangeTestPluginEnabled',
|
||||
defaultValue: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<PrimaryTemplate
|
||||
title="Range Test"
|
||||
tagline="Plugin"
|
||||
leftButton={
|
||||
<IconButton
|
||||
icon={<FiMenu className="w-5 h-5" />}
|
||||
onClick={(): void => {
|
||||
setNavOpen && setNavOpen(!navOpen);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<FormFooter
|
||||
dirty={formState.isDirty}
|
||||
saveAction={onSubmit}
|
||||
clearAction={reset}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className="w-full space-y-4">
|
||||
<Card>
|
||||
<div className="w-full max-w-3xl p-10 md:max-w-xl">
|
||||
<form onSubmit={onSubmit}>
|
||||
<Checkbox
|
||||
label="Range Test Plugin Enabled?"
|
||||
{...register('rangeTestPluginEnabled')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Range Test Plugin Save?"
|
||||
disabled={!watchRangeTestPluginEnabled}
|
||||
{...register('rangeTestPluginSave')}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Message Interval"
|
||||
disabled={!watchRangeTestPluginEnabled}
|
||||
{...register('rangeTestPluginSender', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</PrimaryTemplate>
|
||||
);
|
||||
};
|
||||
@@ -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<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
export const Serial = ({ navOpen, setNavOpen }: SerialProps): JSX.Element => {
|
||||
const preferences = useAppSelector(
|
||||
(state) => state.meshtastic.radio.preferences,
|
||||
);
|
||||
|
||||
const { register, handleSubmit, formState, reset, control } =
|
||||
useForm<RadioConfig_UserPreferences>({
|
||||
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<void> => {
|
||||
//add loading indicator
|
||||
reset({ ...data });
|
||||
await Promise.resolve();
|
||||
});
|
||||
});
|
||||
//todo, add loading indicator
|
||||
|
||||
const watchSerialPluginEnabled = useWatch({
|
||||
control,
|
||||
name: 'serialpluginEnabled',
|
||||
defaultValue: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<PrimaryTemplate
|
||||
title="Serial"
|
||||
tagline="Plugin"
|
||||
leftButton={
|
||||
<IconButton
|
||||
icon={<FiMenu className="w-5 h-5" />}
|
||||
onClick={(): void => {
|
||||
setNavOpen && setNavOpen(!navOpen);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<FormFooter
|
||||
dirty={formState.isDirty}
|
||||
saveAction={onSubmit}
|
||||
clearAction={reset}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className="w-full space-y-4">
|
||||
<Card>
|
||||
<div className="w-full max-w-3xl p-10 md:max-w-xl">
|
||||
<form onSubmit={onSubmit}>
|
||||
<Checkbox
|
||||
label="Plugin Enabled"
|
||||
{...register('serialpluginEnabled')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Echo"
|
||||
disabled={!watchSerialPluginEnabled}
|
||||
{...register('serialpluginEcho')}
|
||||
/>
|
||||
|
||||
<Input
|
||||
type="number"
|
||||
label="RX"
|
||||
disabled={!watchSerialPluginEnabled}
|
||||
{...register('serialpluginRxd', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="TX"
|
||||
disabled={!watchSerialPluginEnabled}
|
||||
{...register('serialpluginTxd', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Mode"
|
||||
disabled={!watchSerialPluginEnabled}
|
||||
{...register('serialpluginMode', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Timeout"
|
||||
disabled={!watchSerialPluginEnabled}
|
||||
{...register('serialpluginTimeout', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</PrimaryTemplate>
|
||||
);
|
||||
};
|
||||
@@ -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<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
export const StoreAndForward = ({
|
||||
navOpen,
|
||||
setNavOpen,
|
||||
}: StoreAndForwardProps): JSX.Element => {
|
||||
const preferences = useAppSelector(
|
||||
(state) => state.meshtastic.radio.preferences,
|
||||
);
|
||||
|
||||
const { register, handleSubmit, formState, reset, control } =
|
||||
useForm<RadioConfig_UserPreferences>({
|
||||
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<void> => {
|
||||
//add loading indicator
|
||||
reset({ ...data });
|
||||
await Promise.resolve();
|
||||
});
|
||||
});
|
||||
//todo, add loading indicator
|
||||
|
||||
const watchStoreForwardPluginEnabled = useWatch({
|
||||
control,
|
||||
name: 'storeForwardPluginEnabled',
|
||||
defaultValue: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<PrimaryTemplate
|
||||
title="Serial"
|
||||
tagline="Plugin"
|
||||
leftButton={
|
||||
<IconButton
|
||||
icon={<FiMenu className="w-5 h-5" />}
|
||||
onClick={(): void => {
|
||||
setNavOpen && setNavOpen(!navOpen);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<FormFooter
|
||||
dirty={formState.isDirty}
|
||||
saveAction={onSubmit}
|
||||
clearAction={reset}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className="w-full space-y-4">
|
||||
<Card>
|
||||
<div className="w-full max-w-3xl p-10 md:max-w-xl">
|
||||
<form onSubmit={onSubmit}>
|
||||
<Checkbox
|
||||
label="Plugin Enabled"
|
||||
{...register('storeForwardPluginEnabled')}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Number of records"
|
||||
disabled={!watchStoreForwardPluginEnabled}
|
||||
{...register('storeForwardPluginRecords', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</PrimaryTemplate>
|
||||
);
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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 => {
|
||||
<User key={4} />,
|
||||
<Power key={5} />,
|
||||
<Radio key={6} />,
|
||||
<Channels key={8} />,
|
||||
<Interface key={7} />,
|
||||
<Channels key={7} />,
|
||||
<Plugins key={8} />,
|
||||
<Interface key={9} />,
|
||||
];
|
||||
|
||||
const sidebarItems: SidebarItemProps[] = [
|
||||
@@ -56,6 +59,11 @@ export const Settings = (): JSX.Element => {
|
||||
description: 'Manage channels',
|
||||
icon: <FiLayers className="flex-shrink-0 w-6 h-6" />,
|
||||
},
|
||||
{
|
||||
title: 'Plugins',
|
||||
description: 'Plugins',
|
||||
icon: <FiPackage className="flex-shrink-0 w-6 h-6" />,
|
||||
},
|
||||
{
|
||||
title: 'Interface',
|
||||
description: 'Language and UI settings',
|
||||
|
||||
@@ -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<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
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: <FiRss />,
|
||||
},
|
||||
{
|
||||
name: 'External Notifications',
|
||||
description: 'External hardware alerts',
|
||||
enabled: preferences.extNotificationPluginEnabled,
|
||||
icon: <FiBell />,
|
||||
},
|
||||
{
|
||||
name: 'Serial',
|
||||
description: 'Send serial data over the mesh',
|
||||
enabled: preferences.serialpluginEnabled,
|
||||
icon: <FiAlignLeft />,
|
||||
},
|
||||
{
|
||||
name: 'Store & Forward',
|
||||
description: 'Retrive message history',
|
||||
enabled: preferences.storeForwardPluginEnabled,
|
||||
icon: <FiFastForward />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<PrimaryTemplate
|
||||
title="Plugins"
|
||||
tagline="Settings"
|
||||
leftButton={
|
||||
<Button
|
||||
icon={<FiMenu className="w-5 h-5" />}
|
||||
onClick={(): void => {
|
||||
setNavOpen && setNavOpen(!navOpen);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Card
|
||||
title="Basic settings"
|
||||
description="Device name and user parameters"
|
||||
>
|
||||
<div className="w-full max-w-3xl p-10 space-y-2 md:max-w-xl">
|
||||
{plugins.map((plugin, index) => (
|
||||
<div
|
||||
key={index}
|
||||
onClick={(): void => {
|
||||
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'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
<div className="flex my-auto space-x-2">
|
||||
<div
|
||||
className={`h-3 my-auto w-3 rounded-full ${
|
||||
plugin.enabled ? 'bg-green-500' : 'bg-gray-400'
|
||||
}`}
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<div className="my-auto">{plugin.icon}</div>
|
||||
{plugin.name}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<IconButton active icon={<FiExternalLink />} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</PrimaryTemplate>
|
||||
{sidebarOpen && (
|
||||
<PluginsSidebar
|
||||
closeSidebar={(): void => {
|
||||
setSidebarOpen(false);
|
||||
}}
|
||||
plugin={selectedPlugin}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user