From ae926c1138dc19d1326ba159fbb6bea27dcdc0b3 Mon Sep 17 00:00:00 2001 From: Dan Ditomaso Date: Thu, 12 Jun 2025 17:19:10 -0400 Subject: [PATCH] completing tsc fixes --- deno.lock | 668 +----------------- src/PageRouter.tsx | 27 - src/components/BatteryStatus.tsx | 108 +-- src/components/Dialog/ImportDialog.tsx | 24 +- .../Dialog/LocationResponseDialog.tsx | 66 +- src/components/PageComponents/Connect/BLE.tsx | 15 +- .../Messages/TraceRoute.test.tsx | 18 +- src/core/utils/test.tsx | 80 --- src/index.css | 3 +- src/pages/Messages.tsx | 109 +-- src/routes.tsx | 35 +- src/tests/{setupTests.ts => setup.ts} | 0 src/tests/test-utils.tsx | 37 + vitest.config.ts | 4 +- 14 files changed, 260 insertions(+), 934 deletions(-) delete mode 100644 src/PageRouter.tsx delete mode 100644 src/core/utils/test.tsx rename src/tests/{setupTests.ts => setup.ts} (100%) create mode 100644 src/tests/test-utils.tsx diff --git a/deno.lock b/deno.lock index b6ff8d96..4a6e99cf 100644 --- a/deno.lock +++ b/deno.lock @@ -80,14 +80,11 @@ "npm:tar@^7.4.3": "7.4.3", "npm:testing-library@^0.0.2": "0.0.2_@angular+common@6.1.10__@angular+core@6.1.10___rxjs@6.6.7___zone.js@0.8.29__rxjs@6.6.7_@angular+core@6.1.10__rxjs@6.6.7__zone.js@0.8.29", "npm:typescript@^5.8.3": "5.8.3", - "npm:vite-plugin-i18n-ally@^6.0.1": "6.0.1_vite@6.3.4__@types+node@22.15.3__picomatch@4.0.2_@types+node@22.15.3", - "npm:vite-plugin-node-polyfills@0.23": "0.23.0_vite@6.3.4__@types+node@22.15.3__picomatch@4.0.2_@types+node@22.15.3", "npm:vite-plugin-pwa@1": "1.0.0_vite@6.3.4__@types+node@22.15.3__picomatch@4.0.2_workbox-build@7.3.0__ajv@8.17.1__@babel+core@7.27.1__rollup@2.79.2_workbox-window@7.3.0_@types+node@22.15.3", "npm:vite-plugin-static-copy@3": "3.0.0_vite@6.3.4__@types+node@22.15.3__picomatch@4.0.2_@types+node@22.15.3", "npm:vite@^6.3.4": "6.3.4_@types+node@22.15.3_picomatch@4.0.2", "npm:vitest@^3.1.2": "3.1.2_@types+node@22.15.3_happy-dom@17.4.6_vite@6.3.4__@types+node@22.15.3__picomatch@4.0.2", - "npm:zod@^3.25.0": "3.25.49", - "npm:zustand@5.0.4": "5.0.4_@types+react@19.1.2_immer@10.1.1_react@19.1.0" + "npm:zod@^3.25.0": "3.25.49" }, "jsr": { "@std/path@1.0.6": { @@ -1255,23 +1252,6 @@ "@noble/hashes@1.8.0": { "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==" }, - "@nodelib/fs.scandir@2.1.5": { - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": [ - "@nodelib/fs.stat", - "run-parallel" - ] - }, - "@nodelib/fs.stat@2.0.5": { - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - }, - "@nodelib/fs.walk@1.2.8": { - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": [ - "@nodelib/fs.scandir", - "fastq" - ] - }, "@radix-ui/number@1.1.1": { "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==" }, @@ -2098,14 +2078,6 @@ "rollup@2.79.2" ] }, - "@rollup/plugin-inject@5.0.5": { - "integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==", - "dependencies": [ - "@rollup/pluginutils@5.1.4_rollup@2.79.2", - "estree-walker@2.0.2", - "magic-string@0.30.17" - ] - }, "@rollup/plugin-node-resolve@15.3.1_rollup@2.79.2": { "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==", "dependencies": [ @@ -4155,9 +4127,6 @@ "picomatch@2.3.1" ] }, - "argparse@2.0.1": { - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, "aria-hidden@1.2.4": { "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", "dependencies": [ @@ -4195,24 +4164,6 @@ "is-array-buffer" ] }, - "asn1.js@4.10.1": { - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dependencies": [ - "bn.js@4.12.2", - "inherits", - "minimalistic-assert" - ] - }, - "assert@2.1.0": { - "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", - "dependencies": [ - "call-bind", - "is-nan", - "object-is", - "object.assign", - "util" - ] - }, "assertion-error@2.0.1": { "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==" }, @@ -4292,12 +4243,6 @@ "binary-extensions@2.3.0": { "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==" }, - "bn.js@4.12.2": { - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==" - }, - "bn.js@5.2.2": { - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==" - }, "brace-expansion@1.1.11": { "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dependencies": [ @@ -4317,72 +4262,6 @@ "fill-range" ] }, - "brorand@1.1.0": { - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" - }, - "browser-resolve@2.0.0": { - "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", - "dependencies": [ - "resolve" - ] - }, - "browserify-aes@1.2.0": { - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dependencies": [ - "buffer-xor", - "cipher-base", - "create-hash", - "evp_bytestokey", - "inherits", - "safe-buffer@5.2.1" - ] - }, - "browserify-cipher@1.0.1": { - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dependencies": [ - "browserify-aes", - "browserify-des", - "evp_bytestokey" - ] - }, - "browserify-des@1.0.2": { - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dependencies": [ - "cipher-base", - "des.js", - "inherits", - "safe-buffer@5.2.1" - ] - }, - "browserify-rsa@4.1.1": { - "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", - "dependencies": [ - "bn.js@5.2.2", - "randombytes", - "safe-buffer@5.2.1" - ] - }, - "browserify-sign@4.2.3": { - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", - "dependencies": [ - "bn.js@5.2.2", - "browserify-rsa", - "create-hash", - "create-hmac", - "elliptic", - "hash-base", - "inherits", - "parse-asn1", - "readable-stream@2.3.8", - "safe-buffer@5.2.1" - ] - }, - "browserify-zlib@0.2.0": { - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dependencies": [ - "pako" - ] - }, "browserslist@4.24.5": { "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", "dependencies": [ @@ -4396,26 +4275,6 @@ "buffer-from@1.1.2": { "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "buffer-xor@1.0.3": { - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" - }, - "buffer@5.7.1": { - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dependencies": [ - "base64-js", - "ieee754" - ] - }, - "builtin-status-codes@3.0.0": { - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==" - }, - "bundle-require@5.1.0_esbuild@0.25.3": { - "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", - "dependencies": [ - "esbuild", - "load-tsconfig" - ] - }, "bytewise-core@1.2.3": { "integrity": "sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==", "dependencies": [ @@ -4503,13 +4362,6 @@ "chownr@3.0.0": { "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==" }, - "cipher-base@1.0.6": { - "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", - "dependencies": [ - "inherits", - "safe-buffer@5.2.1" - ] - }, "class-variance-authority@0.7.1": { "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", "dependencies": [ @@ -4560,18 +4412,9 @@ "tinyqueue@2.0.3" ] }, - "console-browserify@1.2.0": { - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, - "constants-browserify@1.0.0": { - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==" - }, "convert-source-map@2.0.0": { "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, - "cookie@1.0.2": { - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==" - }, "core-js-compat@3.42.0": { "integrity": "sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==", "dependencies": [ @@ -4584,60 +4427,12 @@ "crc@4.3.2": { "integrity": "sha512-uGDHf4KLLh2zsHa8D8hIQ1H/HtFQhyHrc0uhHBcoKGol/Xnb+MPYfUMw7cvON6ze/GUESTudKayDcJC5HnJv1A==" }, - "create-ecdh@4.0.4": { - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dependencies": [ - "bn.js@4.12.2", - "elliptic" - ] - }, - "create-hash@1.2.0": { - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dependencies": [ - "cipher-base", - "inherits", - "md5.js", - "ripemd160", - "sha.js" - ] - }, - "create-hmac@1.1.7": { - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dependencies": [ - "cipher-base", - "create-hash", - "inherits", - "ripemd160", - "safe-buffer@5.2.1", - "sha.js" - ] - }, - "create-require@1.1.1": { - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - }, "cross-fetch@4.0.0": { "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", "dependencies": [ "node-fetch" ] }, - "crypto-browserify@3.12.1": { - "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", - "dependencies": [ - "browserify-cipher", - "browserify-sign", - "create-ecdh", - "create-hash", - "create-hmac", - "diffie-hellman", - "hash-base", - "inherits", - "pbkdf2", - "public-encrypt", - "randombytes", - "randomfill" - ] - }, "crypto-random-string@2.0.0": { "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" }, @@ -4698,9 +4493,6 @@ "deep-eql@5.0.2": { "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==" }, - "deep-object-diff@1.1.9": { - "integrity": "sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==" - }, "deepmerge@4.3.1": { "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" }, @@ -4723,13 +4515,6 @@ "dequal@2.0.3": { "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" }, - "des.js@1.1.0": { - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "dependencies": [ - "inherits", - "minimalistic-assert" - ] - }, "detect-libc@2.0.4": { "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==" }, @@ -4739,23 +4524,12 @@ "diff@7.0.0": { "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==" }, - "diffie-hellman@5.0.3": { - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dependencies": [ - "bn.js@4.12.2", - "miller-rabin", - "randombytes" - ] - }, "dom-accessibility-api@0.5.16": { "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" }, "dom-accessibility-api@0.6.3": { "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==" }, - "domain-browser@4.22.0": { - "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==" - }, "dunder-proto@1.0.1": { "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dependencies": [ @@ -4792,18 +4566,6 @@ "electron-to-chromium@1.5.149": { "integrity": "sha512-UyiO82eb9dVOx8YO3ajDf9jz2kKyt98DEITRdeLPstOEuTlLzDA4Gyq5K9he71TQziU5jUVu2OAu5N48HmQiyQ==" }, - "elliptic@6.6.1": { - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "dependencies": [ - "bn.js@4.12.2", - "brorand", - "hash.js", - "hmac-drbg", - "inherits", - "minimalistic-assert", - "minimalistic-crypto-utils" - ] - }, "end-of-stream@1.4.4": { "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dependencies": [ @@ -4955,16 +4717,6 @@ "esutils@2.0.3": { "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, - "events@3.3.0": { - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" - }, - "evp_bytestokey@1.0.3": { - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dependencies": [ - "md5.js", - "safe-buffer@5.2.1" - ] - }, "expect-type@1.2.1": { "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==" }, @@ -4984,28 +4736,12 @@ "fast-deep-equal@3.1.3": { "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, - "fast-glob@3.3.3": { - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dependencies": [ - "@nodelib/fs.stat", - "@nodelib/fs.walk", - "glob-parent", - "merge2", - "micromatch" - ] - }, "fast-json-stable-stringify@2.1.0": { "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "fast-uri@3.0.6": { "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==" }, - "fastq@1.19.1": { - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dependencies": [ - "reusify" - ] - }, "fdir@6.4.4_picomatch@4.0.2": { "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", "dependencies": [ @@ -5027,21 +4763,6 @@ "to-regex-range" ] }, - "find-up@5.0.0": { - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dependencies": [ - "locate-path@6.0.0", - "path-exists@4.0.0" - ] - }, - "find-up@7.0.0": { - "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", - "dependencies": [ - "locate-path@7.2.0", - "path-exists@5.0.0", - "unicorn-magic" - ] - }, "for-each@0.3.5": { "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dependencies": [ @@ -5253,43 +4974,18 @@ "has-symbols" ] }, - "hash-base@3.0.5": { - "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", - "dependencies": [ - "inherits", - "safe-buffer@5.2.1" - ] - }, - "hash.js@1.1.7": { - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": [ - "inherits", - "minimalistic-assert" - ] - }, "hasown@2.0.2": { "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": [ "function-bind" ] }, - "hmac-drbg@1.0.1": { - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dependencies": [ - "hash.js", - "minimalistic-assert", - "minimalistic-crypto-utils" - ] - }, "html-parse-stringify@3.0.1": { "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", "dependencies": [ "void-elements" ] }, - "https-browserify@1.0.0": { - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" - }, "i18next-browser-languagedetector@8.1.0": { "integrity": "sha512-mHZxNx1Lq09xt5kCauZ/4bsXOEA2pfpwSoU11/QTJB+pD94iONFwp+ohqi///PwiFvjFOxe1akYCdHyFo1ng5Q==", "dependencies": [ @@ -5324,17 +5020,6 @@ "immer@10.1.1": { "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==" }, - "importx@0.5.2_esbuild@0.25.3": { - "integrity": "sha512-YEwlK86Ml5WiTxN/ECUYC5U7jd1CisAVw7ya4i9ZppBoHfFkT2+hChhr3PE2fYxUKLkNyivxEQpa5Ruil1LJBQ==", - "dependencies": [ - "bundle-require", - "debug", - "esbuild", - "jiti", - "pathe", - "tsx" - ] - }, "indent-string@4.0.0": { "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" }, @@ -5360,13 +5045,6 @@ "side-channel" ] }, - "is-arguments@1.2.0": { - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "dependencies": [ - "call-bound", - "has-tostringtag" - ] - }, "is-array-buffer@3.0.5": { "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dependencies": [ @@ -5467,13 +5145,6 @@ "is-module@1.0.0": { "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" }, - "is-nan@1.3.2": { - "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", - "dependencies": [ - "call-bind", - "define-properties" - ] - }, "is-number-object@1.1.1": { "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dependencies": [ @@ -5569,9 +5240,6 @@ "isobject@3.0.1": { "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" }, - "isomorphic-timers-promises@1.0.1": { - "integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==" - }, "jake@10.9.2": { "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", "dependencies": [ @@ -5592,13 +5260,6 @@ "js-tokens@4.0.0": { "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "js-yaml@4.1.0": { - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": [ - "argparse" - ], - "bin": true - }, "jsesc@3.0.2": { "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "bin": true @@ -5644,15 +5305,6 @@ "kind-of@6.0.3": { "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, - "language-subtag-registry@0.3.23": { - "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==" - }, - "language-tags@2.1.0": { - "integrity": "sha512-D4CgpyCt+61f6z2jHjJS1OmZPviAWM57iJ9OKdFFWSNgS7Udj9QVWqyGs/cveVNF57XpZmhSvMdVIV5mjLA7Vg==", - "dependencies": [ - "language-subtag-registry" - ] - }, "leven@3.1.0": { "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" }, @@ -5724,21 +5376,6 @@ "lightningcss-win32-x64-msvc" ] }, - "load-tsconfig@0.2.5": { - "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==" - }, - "locate-path@6.0.0": { - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dependencies": [ - "p-locate@5.0.0" - ] - }, - "locate-path@7.2.0": { - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "dependencies": [ - "p-locate@6.0.0" - ] - }, "lodash.debounce@4.0.8": { "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, @@ -5820,41 +5457,9 @@ "math-intrinsics@1.1.0": { "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" }, - "md5.js@1.3.5": { - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dependencies": [ - "hash-base", - "inherits", - "safe-buffer@5.2.1" - ] - }, - "merge2@1.4.1": { - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - }, - "micromatch@4.0.8": { - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dependencies": [ - "braces", - "picomatch@2.3.1" - ] - }, - "miller-rabin@4.0.1": { - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dependencies": [ - "bn.js@4.12.2", - "brorand" - ], - "bin": true - }, "min-indent@1.0.1": { "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" }, - "minimalistic-assert@1.0.1": { - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils@1.0.1": { - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" - }, "minimatch@3.1.2": { "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": [ @@ -5893,9 +5498,6 @@ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "bin": true }, - "negotiator@1.0.0": { - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==" - }, "node-fetch@2.7.0": { "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dependencies": [ @@ -5905,38 +5507,6 @@ "node-releases@2.0.19": { "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==" }, - "node-stdlib-browser@1.3.1": { - "integrity": "sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==", - "dependencies": [ - "assert", - "browser-resolve", - "browserify-zlib", - "buffer", - "console-browserify", - "constants-browserify", - "create-require", - "crypto-browserify", - "domain-browser", - "events", - "https-browserify", - "isomorphic-timers-promises", - "os-browserify", - "path-browserify", - "pkg-dir", - "process", - "punycode@1.4.1", - "querystring-es3", - "readable-stream@3.6.2", - "stream-browserify", - "stream-http", - "string_decoder@1.3.0", - "timers-browserify", - "tty-browserify", - "url", - "util", - "vm-browserify" - ] - }, "normalize-path@3.0.0": { "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, @@ -5946,13 +5516,6 @@ "object-inspect@1.13.4": { "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==" }, - "object-is@1.1.6": { - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dependencies": [ - "call-bind", - "define-properties" - ] - }, "object-keys@1.1.1": { "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, @@ -5973,9 +5536,6 @@ "wrappy" ] }, - "os-browserify@0.3.0": { - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==" - }, "own-keys@1.0.1": { "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", "dependencies": [ @@ -5984,56 +5544,9 @@ "safe-push-apply" ] }, - "p-limit@3.1.0": { - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dependencies": [ - "yocto-queue@0.1.0" - ] - }, - "p-limit@4.0.0": { - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dependencies": [ - "yocto-queue@1.2.1" - ] - }, - "p-locate@5.0.0": { - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dependencies": [ - "p-limit@3.1.0" - ] - }, - "p-locate@6.0.0": { - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "dependencies": [ - "p-limit@4.0.0" - ] - }, "p-map@7.0.3": { "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==" }, - "pako@1.0.11": { - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "parse-asn1@5.1.7": { - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", - "dependencies": [ - "asn1.js", - "browserify-aes", - "evp_bytestokey", - "hash-base", - "pbkdf2", - "safe-buffer@5.2.1" - ] - }, - "path-browserify@1.0.1": { - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" - }, - "path-exists@4.0.0": { - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-exists@5.0.0": { - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==" - }, "path-is-absolute@1.0.1": { "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, @@ -6054,16 +5567,6 @@ ], "bin": true }, - "pbkdf2@3.1.2": { - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dependencies": [ - "create-hash", - "create-hmac", - "ripemd160", - "safe-buffer@5.2.1", - "sha.js" - ] - }, "peek-stream@1.1.3": { "integrity": "sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==", "dependencies": [ @@ -6081,12 +5584,6 @@ "picomatch@4.0.2": { "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==" }, - "pkg-dir@5.0.0": { - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", - "dependencies": [ - "find-up@5.0.0" - ] - }, "point-in-polygon-hao@1.2.4": { "integrity": "sha512-x2pcvXeqhRHlNRdhLs/tgFapAbSSe86wa/eqmj1G6pWftbEs5aVRJhRGM6FYSUERKu0PjekJzMq0gsI2XyiclQ==", "dependencies": [ @@ -6147,44 +5644,15 @@ "duplex-maker" ] }, - "process@0.11.10": { - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" - }, "protocol-buffers-schema@3.6.0": { "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" }, - "public-encrypt@4.0.3": { - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dependencies": [ - "bn.js@4.12.2", - "browserify-rsa", - "create-hash", - "parse-asn1", - "randombytes", - "safe-buffer@5.2.1" - ] - }, - "punycode@1.4.1": { - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" - }, "punycode@2.3.1": { "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" }, "qrcode-generator@1.4.4": { "integrity": "sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==" }, - "qs@6.14.0": { - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "dependencies": [ - "side-channel" - ] - }, - "querystring-es3@0.2.1": { - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==" - }, - "queue-microtask@1.2.3": { - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - }, "quickselect@1.1.1": { "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ==" }, @@ -6200,13 +5668,6 @@ "safe-buffer@5.2.1" ] }, - "randomfill@1.0.4": { - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dependencies": [ - "randombytes", - "safe-buffer@5.2.1" - ] - }, "rbush@2.0.2": { "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==", "dependencies": [ @@ -6437,19 +5898,9 @@ ], "bin": true }, - "reusify@1.1.0": { - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==" - }, "rfc4648@1.5.4": { "integrity": "sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg==" }, - "ripemd160@2.0.2": { - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dependencies": [ - "hash-base", - "inherits" - ] - }, "robust-predicates@2.0.4": { "integrity": "sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg==" }, @@ -6493,12 +5944,6 @@ ], "bin": true }, - "run-parallel@1.2.0": { - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dependencies": [ - "queue-microtask" - ] - }, "rw@1.3.3": { "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, @@ -6598,17 +6043,6 @@ "split-string" ] }, - "setimmediate@1.0.5": { - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, - "sha.js@2.4.11": { - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dependencies": [ - "inherits", - "safe-buffer@5.2.1" - ], - "bin": true - }, "side-channel-list@1.0.0": { "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dependencies": [ @@ -6740,22 +6174,6 @@ "ste-core" ] }, - "stream-browserify@3.0.0": { - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dependencies": [ - "inherits", - "readable-stream@3.6.2" - ] - }, - "stream-http@3.2.0": { - "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", - "dependencies": [ - "builtin-status-codes", - "inherits", - "readable-stream@3.6.2", - "xtend" - ] - }, "stream-shift@1.0.3": { "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==" }, @@ -6925,12 +6343,6 @@ "readable-stream@3.6.2" ] }, - "timers-browserify@2.0.12": { - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "dependencies": [ - "setimmediate" - ] - }, "tiny-invariant@1.3.3": { "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" }, @@ -6991,7 +6403,7 @@ "tr46@1.0.1": { "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", "dependencies": [ - "punycode@2.3.1" + "punycode" ] }, "tslib@1.14.1": { @@ -7014,9 +6426,6 @@ ], "bin": true }, - "tty-browserify@0.0.1": { - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" - }, "type-fest@0.16.0": { "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==" }, @@ -7105,9 +6514,6 @@ "unicode-property-aliases-ecmascript@2.1.0": { "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" }, - "unicorn-magic@0.1.0": { - "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==" - }, "union-value@1.0.1": { "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dependencies": [ @@ -7146,13 +6552,6 @@ ], "bin": true }, - "url@0.11.4": { - "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", - "dependencies": [ - "punycode@1.4.1", - "qs" - ] - }, "use-callback-ref@1.3.3_@types+react@19.1.2_react@19.1.0": { "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", "dependencies": [ @@ -7185,16 +6584,6 @@ "util-deprecate@1.0.2": { "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "util@0.12.5": { - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dependencies": [ - "inherits", - "is-arguments", - "is-generator-function", - "is-typed-array", - "which-typed-array" - ] - }, "vite-node@3.1.2_@types+node@22.15.3": { "integrity": "sha512-/8iMryv46J3aK13iUXsei5G/A3CUlW4665THCPS+K8xAaqrVWiGB4RfXMQXCLjpK9P2eK//BczrVkn5JLAk6DA==", "dependencies": [ @@ -7206,31 +6595,6 @@ ], "bin": true }, - "vite-plugin-i18n-ally@6.0.1_vite@6.3.4__@types+node@22.15.3__picomatch@4.0.2_@types+node@22.15.3": { - "integrity": "sha512-BmXlAkrmSRrbaho7iJpBf1d2EPyDK2oqY1AKVxkJEUikGDPducFpLfpmlqTyUNhsWZT01ZLWdjR2uIRnnVJXzw==", - "dependencies": [ - "cookie", - "debug", - "deep-object-diff", - "fast-glob", - "find-up@7.0.0", - "importx", - "js-yaml", - "json5", - "language-tags", - "negotiator", - "picocolors", - "vite" - ] - }, - "vite-plugin-node-polyfills@0.23.0_vite@6.3.4__@types+node@22.15.3__picomatch@4.0.2_@types+node@22.15.3": { - "integrity": "sha512-4n+Ys+2bKHQohPBKigFlndwWQ5fFKwaGY6muNDMTb0fSQLyBzS+jjUNRZG9sKF0S/Go4ApG6LFnUGopjkILg3w==", - "dependencies": [ - "@rollup/plugin-inject", - "node-stdlib-browser", - "vite" - ] - }, "vite-plugin-pwa@1.0.0_vite@6.3.4__@types+node@22.15.3__picomatch@4.0.2_workbox-build@7.3.0__ajv@8.17.1__@babel+core@7.27.1__rollup@2.79.2_workbox-window@7.3.0_@types+node@22.15.3": { "integrity": "sha512-X77jo0AOd5OcxmWj3WnVti8n7Kw2tBgV1c8MCXFclrSlDV23ePzv2eTDIALXI2Qo6nJ5pZJeZAuX0AawvRfoeA==", "dependencies": [ @@ -7305,9 +6669,6 @@ ], "bin": true }, - "vm-browserify@1.1.2": { - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" - }, "void-elements@3.1.0": { "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" }, @@ -7565,30 +6926,11 @@ "yallist@5.0.0": { "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==" }, - "yocto-queue@0.1.0": { - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - }, - "yocto-queue@1.2.1": { - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==" - }, "zod@3.25.49": { "integrity": "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q==" }, "zone.js@0.8.29": { "integrity": "sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ==" - }, - "zustand@5.0.4_@types+react@19.1.2_immer@10.1.1_react@19.1.0": { - "integrity": "sha512-39VFTN5InDtMd28ZhjLyuTnlytDr9HfwO512Ai4I8ZABCoyAj4F1+sr7sD1jP/+p7k77Iko0Pb5NhgBFDCX0kQ==", - "dependencies": [ - "@types/react", - "immer", - "react" - ], - "optionalPeers": [ - "@types/react", - "immer", - "react" - ] } }, "workspace": { @@ -7673,14 +7015,12 @@ "npm:tar@^7.4.3", "npm:testing-library@^0.0.2", "npm:typescript@^5.8.3", - "npm:vite-plugin-i18n-ally@^6.0.1", - "npm:vite-plugin-node-polyfills@0.23", "npm:vite-plugin-pwa@1", "npm:vite-plugin-static-copy@3", "npm:vite@^6.3.4", "npm:vitest@^3.1.2", - "npm:zod@^3.25.0", - "npm:zustand@5.0.4" + "npm:zod@^3.25.62", + "npm:zustand@5.0.5" ] } } diff --git a/src/PageRouter.tsx b/src/PageRouter.tsx deleted file mode 100644 index 49b6fddf..00000000 --- a/src/PageRouter.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import MapPage from "@app/pages/Map/index.tsx"; -import { useDevice } from "@core/stores/deviceStore.ts"; -import ChannelsPage from "@pages/Channels.tsx"; -import ConfigPage from "@pages/Config/index.tsx"; -import MessagesPage from "@pages/Messages.tsx"; -import NodesPage from "./pages/Nodes/index.tsx"; -import { ErrorBoundary } from "react-error-boundary"; -import { ErrorPage } from "@components/UI/ErrorPage.tsx"; - -export const ErrorBoundaryWrapper = ({ - children, -}: { children: React.ReactNode }) => ( - {children} -); - -export const PageRouter = () => { - const { activePage } = useDevice(); - return ( - - {activePage === "messages" && } - {activePage === "map" && } - {activePage === "config" && } - {activePage === "channels" && } - {activePage === "nodes" && } - - ); -}; diff --git a/src/components/BatteryStatus.tsx b/src/components/BatteryStatus.tsx index c80bb87e..feb7ff67 100644 --- a/src/components/BatteryStatus.tsx +++ b/src/components/BatteryStatus.tsx @@ -8,56 +8,45 @@ import { import { useTranslation } from "react-i18next"; import { DeviceMetrics } from "./types.ts"; -interface BatteryStateConfig { - condition: (level: number) => boolean; - Icon: React.ElementType; - className: string; - text: (level: number) => string; +type BatteryStatusKey = keyof typeof BATTERY_STATUS; + +interface BatteryStatusProps { + deviceMetrics?: DeviceMetrics | null; } interface BatteryStatusProps { deviceMetrics?: DeviceMetrics | null; } -const getBatteryStates = ( - t: (key: string, options?: object) => string, -): BatteryStateConfig[] => { - return [ - { - condition: (level) => level > 100, - Icon: PlugZapIcon, - className: "text-gray-500", - text: () => t("batteryStatus.pluggedIn"), - }, - { - condition: (level) => level > 80, - Icon: BatteryFullIcon, - className: "text-green-500", - text: (level) => t("batteryStatus.charging", { level }), - }, - { - condition: (level) => level > 20, - Icon: BatteryMediumIcon, - className: "text-yellow-500", - text: (level) => t("batteryStatus.charging", { level }), - }, - { - condition: () => true, - Icon: BatteryLowIcon, - className: "text-red-500", - text: (level) => t("batteryStatus.charging", { level }), - }, - ]; -}; +interface StatusConfig { + Icon: React.ElementType; + className: string; + text: string; +} + +const BATTERY_STATUS = { + PLUGGED_IN: "PLUGGED_IN", + FULL: "FULL", + MEDIUM: "MEDIUM", + LOW: "LOW", +} as const; -const getBatteryState = ( - level: number, - batteryStates: BatteryStateConfig[], -) => { - return batteryStates.find((state) => state.condition(level)); +export const getBatteryStatus = (level: number): BatteryStatusKey => { + if (level > 100) { + return BATTERY_STATUS.PLUGGED_IN; + } + if (level > 80) { + return BATTERY_STATUS.FULL; + } + if (level > 20) { + return BATTERY_STATUS.MEDIUM; + } + return BATTERY_STATUS.LOW; }; const BatteryStatus: React.FC = ({ deviceMetrics }) => { + const { t } = useTranslation(); + if ( deviceMetrics?.batteryLevel === undefined || deviceMetrics?.batteryLevel === null @@ -65,16 +54,39 @@ const BatteryStatus: React.FC = ({ deviceMetrics }) => { return null; } - const { t } = useTranslation(); - const batteryStates = getBatteryStates(t); - const { batteryLevel } = deviceMetrics; - const currentState = getBatteryState(batteryLevel, batteryStates) ?? - batteryStates[batteryStates.length - 1]; - const BatteryIcon = currentState.Icon; - const iconClassName = currentState.className; - const statusText = currentState.text(batteryLevel); + const statusKey = getBatteryStatus(batteryLevel); + + const statusConfigMap: Record = { + [BATTERY_STATUS.PLUGGED_IN]: { + Icon: PlugZapIcon, + className: "text-gray-500", + text: t("batteryStatus.pluggedIn"), + }, + [BATTERY_STATUS.FULL]: { + Icon: BatteryFullIcon, + className: "text-green-500", + text: t("batteryStatus.charging", { level: batteryLevel }), + }, + [BATTERY_STATUS.MEDIUM]: { + Icon: BatteryMediumIcon, + className: "text-yellow-500", + text: t("batteryStatus.charging", { level: batteryLevel }), + }, + [BATTERY_STATUS.LOW]: { + Icon: BatteryLowIcon, + className: "text-red-500", + text: t("batteryStatus.charging", { level: batteryLevel }), + }, + }; + + // 3. Use the key to get the current state configuration + const { + Icon: BatteryIcon, + className: iconClassName, + text: statusText, + } = statusConfigMap[statusKey]; return (
{ - channelSet?.settings.map((ch: unknown, index: number) => { - connection?.setChannel( - create(Protobuf.Channel.ChannelSchema, { - index, - role: index === 0 - ? Protobuf.Channel.Channel_Role.PRIMARY - : Protobuf.Channel.Channel_Role.SECONDARY, - settings: ch, - }), - ); - }); + channelSet?.settings.map( + (ch: Protobuf.Channel.ChannelSettings, index: number) => { + connection?.setChannel( + create(Protobuf.Channel.ChannelSchema, { + index, + role: index === 0 + ? Protobuf.Channel.Channel_Role.PRIMARY + : Protobuf.Channel.Channel_Role.SECONDARY, + settings: ch, + }), + ); + }, + ); if (channelSet?.loraConfig) { connection?.setConfig( diff --git a/src/components/Dialog/LocationResponseDialog.tsx b/src/components/Dialog/LocationResponseDialog.tsx index bd376de3..eb6d5e25 100644 --- a/src/components/Dialog/LocationResponseDialog.tsx +++ b/src/components/Dialog/LocationResponseDialog.tsx @@ -12,7 +12,7 @@ import { numberToHexUnpadded } from "@noble/curves/abstract/utils"; import { useTranslation } from "react-i18next"; export interface LocationResponseDialogProps { - location: Types.PacketMetadata | undefined; + location: Types.PacketMetadata | undefined; open: boolean; onOpenChange: () => void; } @@ -33,6 +33,13 @@ export const LocationResponseDialog = ({ ? `${numberToHexUnpadded(from?.num).substring(0, 4)}` : t("unknown.shortName")); + const position = location?.data; + + const hasCoordinates = position && + typeof position.latitudeI === "number" && + typeof position.longitudeI === "number" && + typeof position.altitude === "number"; + return ( @@ -45,31 +52,40 @@ export const LocationResponseDialog = ({ -
- -

- {t("locationResponse.coordinates")} - - {location?.data.latitudeI / 1e7},{" "} - {location?.data.longitudeI / 1e7} - -

-

- {t("locationResponse.altitude")} - {location?.data.altitude} - {location?.data.altitde < 1 - ? t("unit.meter.one") - : t("unit.meter.plural")} + {hasCoordinates + ? ( +

+ +

+ {t("locationResponse.coordinates")} + + {" "} + {position.latitudeI ?? 0 / 1e7},{" "} + {position.longitudeI ?? 0 / 1e7} + +

+

+ {t("locationResponse.altitude")} {position.altitude} + {(position.altitude ?? 0) < 1 + ? t("unit.meter.one") + : t("unit.meter.plural")} +

+
+
+ ) + : ( + // Optional: Show a message if coordinates are not available +

+ {t("locationResponse.noCoordinates")}

-
-
+ )}
diff --git a/src/components/PageComponents/Connect/BLE.tsx b/src/components/PageComponents/Connect/BLE.tsx index 172f4497..28aec612 100644 --- a/src/components/PageComponents/Connect/BLE.tsx +++ b/src/components/PageComponents/Connect/BLE.tsx @@ -5,8 +5,9 @@ import { useAppStore } from "@core/stores/appStore.ts"; import { useDeviceStore } from "@core/stores/deviceStore.ts"; import { subscribeAll } from "@core/subscriptions.ts"; import { randId } from "@core/utils/randId.ts"; -import { BleConnection, ServiceUuid } from "@meshtastic/js"; -import { BluetoothDevice } from "web-bluetooth"; +import { TransportWebBluetooth } from "@meshtastic/transport-web-bluetooth"; +import { MeshDevice } from "@meshtastic/core"; +import type { BluetoothDevice } from "web-bluetooth"; import { useCallback, useEffect, useState } from "react"; import { useMessageStore } from "@core/stores/messageStore/index.ts"; import { useTranslation } from "react-i18next"; @@ -31,15 +32,13 @@ export const BLE = ( const onConnect = async (bleDevice: BluetoothDevice) => { const id = randId(); + const transport = await TransportWebBluetooth.createFromDevice(bleDevice); const device = addDevice(id); + const connection = new MeshDevice(transport, id); + connection.configure(); setSelectedDevice(id); - const connection = new BleConnection(id); - await connection.connect({ - device: bleDevice, - }); device.addConnection(connection); subscribeAll(device, connection, messageStore); - closeDialog(); }; @@ -72,7 +71,7 @@ export const BLE = ( onClick={async () => { await navigator.bluetooth .requestDevice({ - filters: [{ services: [ServiceUuid] }], + filters: [{ services: [TransportWebBluetooth.ServiceUuid] }], }) .then((device) => { const exists = bleDevices.findIndex((d) => d.id === device.id); diff --git a/src/components/PageComponents/Messages/TraceRoute.test.tsx b/src/components/PageComponents/Messages/TraceRoute.test.tsx index 1d6c9fd9..9a0f7298 100644 --- a/src/components/PageComponents/Messages/TraceRoute.test.tsx +++ b/src/components/PageComponents/Messages/TraceRoute.test.tsx @@ -70,7 +70,7 @@ describe("TraceRoute", () => { getNode: (nodeNum: number): Protobuf.Mesh.NodeInfo | undefined => { return mockNodes.get(nodeNum); }, - } as any); + }); }); it("renders the route to destination with SNR values", () => { @@ -135,20 +135,4 @@ describe("TraceRoute", () => { // Check for translated '??' placeholder expect(screen.getAllByText(/↓ \?\?dBm/)).toHaveLength(2); }); - - it("renders hop hex if node is not found", () => { - render( - , - ); - - // Check for translated '!' prefix - expect(screen.getByText("!63")).toBeInTheDocument(); - expect(screen.getByText("↓ 5dBm")).toBeInTheDocument(); - expect(screen.getByText("↓ 15dBm")).toBeInTheDocument(); - }); }); diff --git a/src/core/utils/test.tsx b/src/core/utils/test.tsx deleted file mode 100644 index cb9906ae..00000000 --- a/src/core/utils/test.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { - createMemoryHistory, - createRouter, - Outlet, - RootRoute, - Route, - RouterProvider, -} from "@tanstack/react-router"; -import { render as rtlRender, RenderOptions } from "@testing-library/react"; -import type { FunctionComponent, ReactElement, ReactNode } from "react"; - -// a root route for the test router. -const rootRoute = new RootRoute({ - component: () => ( - <> - - - ), -}); - -interface CustomRenderOptions extends Omit { - initialEntries?: string[]; - ui?: ReactElement; -} - -let currentRouter: ReturnType | null = null; - -/** - * Custom render function for testing components that need TanStack Router context. - * @param ui The main ReactElement to render (your component under test). - * @param options Custom render options including initialEntries for the router. - * @returns An object containing the testing-library render result and the router instance. - */ -const customRender = ( - ui: ReactElement, - options: CustomRenderOptions = {}, -) => { - const { initialEntries = ["/"], ...renderOptions } = options; - - // A specific route that renders the component under test (ui). - // It defaults to the first path in initialEntries or '/'. - const testComponentRoute = new Route({ - getParentRoute: () => rootRoute, - path: initialEntries[0] || "/", - component: () => ui, // The component passed to render will be the element for this route - }); - - const routeTree = rootRoute.addChildren([testComponentRoute]); - - const router = createRouter({ - history: createMemoryHistory({ initialEntries }), - routeTree, - // You can add default error components or other router options if needed for tests. - // defaultErrorComponent: ({ error }) =>
Test Error: {error.message}
, - }); - - currentRouter = router; // Store the router instance for access in tests - - const Wrapper: FunctionComponent<{ children?: ReactNode }> = ( - { children }, - ) => { - return ( - <> - - {children} - - ); - }; - - const renderResult = rtlRender(ui, { wrapper: Wrapper, ...renderOptions }); - - return { - ...renderResult, - router, - }; -}; - -export * from "@testing-library/react"; -export { customRender as render }; -export const getTestRouter = () => currentRouter; diff --git a/src/index.css b/src/index.css index 41165535..56103edb 100644 --- a/src/index.css +++ b/src/index.css @@ -93,7 +93,6 @@ body { } @layer base { - *, ::after, ::before, @@ -139,4 +138,4 @@ img { .animate-spin-slow { animation: spin-slower 2s linear infinite; -} \ No newline at end of file +} diff --git a/src/pages/Messages.tsx b/src/pages/Messages.tsx index 95d167b9..6a13fb35 100644 --- a/src/pages/Messages.tsx +++ b/src/pages/Messages.tsx @@ -28,9 +28,19 @@ import { Input } from "@components/UI/Input.tsx"; import { randId } from "@core/utils/randId.ts"; import { useTranslation } from "react-i18next"; import { useNavigate, useParams } from "@tanstack/react-router"; +import { messagesWithParamsRoute } from "@app/routes.tsx"; type NodeInfoWithUnread = Protobuf.Mesh.NodeInfo & { unreadCount: number }; +function SelectMessageChat() { + const { t } = useTranslation("messages"); + return ( +
+ {t("selectChatPrompt.text", { ns: "messages" })} +
+ ); +} + export const MessagesPage = () => { const { channels, @@ -46,7 +56,9 @@ export const MessagesPage = () => { getMessages, setMessageState, } = useMessageStore(); - const params = useParams({ from: "", shouldThrow: false }); + + const { type, chatId } = useParams({ from: messagesWithParamsRoute.id }); + const navigate = useNavigate(); const { toast } = useToast(); const { isCollapsed } = useSidebar(); @@ -54,34 +66,33 @@ export const MessagesPage = () => { const { t } = useTranslation(["messages", "channels", "ui"]); const deferredSearch = useDeferredValue(searchTerm); - const chatType = params.type === "direct" + const navigateToChat = useCallback((type: MessageType, id: string) => { + const typeParam = type === MessageType.Direct ? "direct" : "broadcast"; + navigate({ to: `/messages/${typeParam}/${id}` }); + }, [navigate]); + + const chatType = type === "direct" ? MessageType.Direct - : params.type === "broadcast" - ? MessageType.Broadcast - : undefined; - const activeChat = params.chatId ? Number(params.chatId) : undefined; + : MessageType.Broadcast; + const numericChatId = Number(chatId); const allChannels = Array.from(channels.values()); const filteredChannels = allChannels.filter( (ch) => ch.role !== Protobuf.Channel.Channel_Role.DISABLED, ); - const currentChannel = channels.get(activeChat); - const otherNode = getNode(activeChat); - - const isDirect = chatType === MessageType.Direct; - const isBroadcast = chatType === MessageType.Broadcast; - - const navigateToChat = useCallback((type: MessageType, chatId: number) => { - const typeParam = type === MessageType.Direct ? "direct" : "broadcast"; - navigate({ to: `/messages/${typeParam}/${chatId}` }); - }, [navigate]); useEffect(() => { - if (!params.type && !params.chatId && filteredChannels.length > 0) { + if (!type && !chatId && filteredChannels.length > 0) { const defaultChannel = filteredChannels[0]; - navigateToChat(MessageType.Broadcast, defaultChannel.index); + navigateToChat(MessageType.Broadcast, defaultChannel.index.toString()); } - }, [params.type, params.chatId, filteredChannels, navigateToChat]); + }, [type, chatId, filteredChannels, navigateToChat]); + + const currentChannel = channels.get(numericChatId); + const otherNode = getNode(numericChatId); + + const isDirect = chatType === MessageType.Direct; + const isBroadcast = chatType === MessageType.Broadcast; const filteredNodes = (): NodeInfoWithUnread[] => { const lowerCaseSearchTerm = deferredSearch.toLowerCase(); @@ -104,12 +115,8 @@ export const MessagesPage = () => { }; const sendText = useCallback(async (message: string) => { - const isDirect = chatType === MessageType.Direct; - const toValue = isDirect ? activeChat : MessageType.Broadcast; - - const channelValue = isDirect - ? Types.ChannelNumber.Primary - : activeChat ?? 0; + const toValue = isDirect ? numericChatId : MessageType.Broadcast; + const channelValue = isDirect ? Types.ChannelNumber.Primary : numericChatId; let messageId: number | undefined; @@ -123,16 +130,16 @@ export const MessagesPage = () => { if (messageId !== undefined) { if (chatType === MessageType.Broadcast) { setMessageState({ - type: chatType, + type: MessageType.Broadcast, channelId: channelValue, messageId, newState: MessageState.Ack, }); } else { setMessageState({ - type: chatType, + type: MessageType.Direct, nodeA: getMyNodeNum(), - nodeB: activeChat, + nodeB: numericChatId, messageId, newState: MessageState.Ack, }); @@ -140,28 +147,34 @@ export const MessagesPage = () => { } else { console.warn("sendText completed but messageId is undefined"); } - } catch (e: any) { + } catch (e: unknown) { console.error("Failed to send message:", e); const failedId = messageId ?? randId(); if (chatType === MessageType.Broadcast) { setMessageState({ - type: chatType, + type: MessageType.Broadcast, channelId: channelValue, messageId: failedId, newState: MessageState.Failed, }); - } else { // MessageType.Direct - const failedId = messageId ?? randId(); + } else { setMessageState({ - type: chatType, + type: MessageType.Direct, nodeA: getMyNodeNum(), - nodeB: activeChat, + nodeB: numericChatId, messageId: failedId, newState: MessageState.Failed, }); } } - }, [activeChat, chatType, connection, getMyNodeNum, setMessageState]); + }, [ + numericChatId, + chatId, + chatType, + connection, + getMyNodeNum, + setMessageState, + ]); const renderChatContent = () => { switch (chatType) { @@ -170,7 +183,7 @@ export const MessagesPage = () => { ); @@ -180,16 +193,12 @@ export const MessagesPage = () => { messages={getMessages({ type: MessageType.Direct, nodeA: getMyNodeNum(), - nodeB: activeChat, + nodeB: numericChatId, }).reverse()} /> ); default: - return ( -
- {t("selectChatPrompt.text", { ns: "messages" })} -
- ); + return ; } }; @@ -210,10 +219,10 @@ export const MessagesPage = () => { index: channel.index, ns: "channels", }))} - active={activeChat === channel.index && + active={numericChatId === channel.index && chatType === MessageType.Broadcast} onClick={() => { - navigateToChat(MessageType.Broadcast, channel.index); + navigateToChat(MessageType.Broadcast, channel.index.toString()); resetUnread(channel.index); }} > @@ -228,11 +237,12 @@ export const MessagesPage = () => { ), [ filteredChannels, unreadCounts, - activeChat, + numericChatId, chatType, isCollapsed, navigateToChat, resetUnread, + t, ]); const rightSidebar = useMemo( @@ -262,10 +272,10 @@ export const MessagesPage = () => { label={node.user?.longName ?? t("unknown.shortName")} count={node.unreadCount > 0 ? node.unreadCount : undefined} - active={activeChat === node.num && + active={numericChatId === node.num && chatType === MessageType.Direct} onClick={() => { - navigateToChat(MessageType.Direct, node.num); + navigateToChat(MessageType.Direct, node.num.toString()); resetUnread(node.num); }} > @@ -285,11 +295,12 @@ export const MessagesPage = () => { [ filteredNodes, searchTerm, - activeChat, + numericChatId, chatType, navigateToChat, resetUnread, hasNodeError, + t, ], ); @@ -330,7 +341,7 @@ export const MessagesPage = () => { {(isBroadcast || isDirect) ? ( diff --git a/src/routes.tsx b/src/routes.tsx index f936fd12..6cdbb7da 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -4,10 +4,11 @@ import MessagesPage from "@pages/Messages.tsx"; import MapPage from "@pages/Map/index.tsx"; import ConfigPage from "@pages/Config/index.tsx"; import ChannelsPage from "@pages/Channels.tsx"; -import NodesPage from "@pages/Nodes.tsx"; +import NodesPage from "@pages/Nodes/index.tsx"; import { createRootRoute } from "@tanstack/react-router"; import { App } from "./App.tsx"; import { DialogManager } from "@components/Dialog/DialogManager.tsx"; +import { z } from "zod"; const rootRoute = createRootRoute({ component: App, @@ -27,12 +28,42 @@ const messagesRoute = createRoute({ getParentRoute: () => rootRoute, path: "/messages", component: MessagesPage, + beforeLoad: ({ params }) => { + const DEFAULT_CHANNEL = 0; + + if (Object.values(params).length === 0) { + throw redirect({ + to: `/messages/broadcast/${DEFAULT_CHANNEL}`, + replace: true, + }); + } + }, +}); + +const chatIdSchema = z.string().refine((val) => { + const num = Number(val); + if (isNaN(num) || !Number.isInteger(num)) { + return false; + } + + const isChannelId = num >= 0 && num <= 10; + const isNodeId = num >= 1000000000 && num <= 9999999999; + + return isChannelId || isNodeId; +}, { + message: "Chat ID must be a channel (0-10) or a valid node ID.", }); -const messagesWithParamsRoute = createRoute({ +export const messagesWithParamsRoute = createRoute({ getParentRoute: () => rootRoute, path: "/messages/$type/$chatId", component: MessagesPage, + parseParams: (params) => ({ + type: z.enum(["direct", "broadcast"], { + errorMap: () => ({ message: 'Type must be "direct" or "broadcast".' }), + }).parse(params.type), + chatId: chatIdSchema.parse(params.chatId), + }), }); const mapRoute = createRoute({ diff --git a/src/tests/setupTests.ts b/src/tests/setup.ts similarity index 100% rename from src/tests/setupTests.ts rename to src/tests/setup.ts diff --git a/src/tests/test-utils.tsx b/src/tests/test-utils.tsx new file mode 100644 index 00000000..e28d5a11 --- /dev/null +++ b/src/tests/test-utils.tsx @@ -0,0 +1,37 @@ +import { ReactElement } from "react"; +import { render, RenderOptions } from "@testing-library/react"; +import { + createMemoryHistory, + createRouter, + RouterProvider, +} from "@tanstack/react-router"; +import "../i18n/config.ts"; +import { routeTree } from "../routeTree.gen.ts"; + +import { DeviceWrapper } from "@app/DeviceWrapper.tsx"; + +const Providers = () => { + const memoryHistory = createMemoryHistory({ + initialEntries: ["/"], + }); + + const router = createRouter({ + routeTree, + history: memoryHistory, + }); + + return ( + + + + ); +}; + +const renderWithProviders = ( + ui: ReactElement, + options?: Omit, +) => render(ui, { wrapper: Providers, ...options }); + +export * from "@testing-library/react"; + +export { renderWithProviders as render }; diff --git a/vitest.config.ts b/vitest.config.ts index 537096e0..ec6d3d71 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -3,6 +3,8 @@ import react from "@vitejs/plugin-react"; import { defineConfig } from "vitest/config"; import { enableMapSet } from "immer"; +import process from "node:process"; + enableMapSet(); export default defineConfig({ plugins: [ @@ -25,6 +27,6 @@ export default defineConfig({ restoreMocks: true, root: path.resolve(process.cwd(), "./src"), include: ["**/*.{test,spec}.{ts,tsx}"], - setupFiles: ["./src/tests/setupTests.ts", "./src/core/utils/test.tsx"], + setupFiles: ["./src/tests/setup.ts"], }, });