Browse Source

fix: resolved issue with being unable to scroll up in the input field

pull/487/head
Dan Ditomaso 1 year ago
parent
commit
d379769672
  1. 1
      .gitignore
  2. 566
      deno.lock
  3. 7
      package.json
  4. 32
      src/components/PageComponents/Connect/HTTP.test.tsx
  5. 53
      src/components/PageComponents/Messages/ChannelChat.tsx
  6. 148
      src/components/PageComponents/Messages/MessageInput.test.tsx
  7. 29
      src/components/PageComponents/Messages/MessageInput.tsx
  8. 3
      src/components/PageLayout.tsx
  9. 2
      src/components/Sidebar.tsx
  10. 32
      src/core/stores/deviceStore.ts
  11. 15
      src/index.css
  12. 83
      src/pages/Messages.tsx
  13. 16
      src/tests/setupTests.ts
  14. 22
      vite.config.ts
  15. 24
      vitest.config.ts

1
.gitignore

@ -4,3 +4,4 @@ stats.html
.vercel
.vite/deps
dev-dist
__screenshots__*

566
deno.lock

@ -24,6 +24,7 @@
"npm:@tailwindcss/postcss@^4.0.9": "4.0.9",
"npm:@testing-library/jest-dom@^6.6.3": "6.6.3",
"npm:@testing-library/react@^16.2.0": "16.2.0_@[email protected]_@[email protected]_@[email protected]__@[email protected][email protected][email protected][email protected]",
"npm:@testing-library/user-event@^14.6.1": "14.6.1_@[email protected]",
"npm:@turf/turf@^7.2.0": "7.2.0",
"npm:@types/chrome@^0.0.307": "0.0.307",
"npm:@types/js-cookie@^3.0.6": "3.0.6",
@ -49,6 +50,7 @@
"npm:jsdom@26": "26.0.0",
"npm:[email protected]": "[email protected]",
"npm:[email protected]": "5.1.1",
"npm:playwright@^1.50.1": "1.50.1",
"npm:postcss@^8.5.3": "8.5.3",
"npm:react-dom@19": "[email protected]",
"npm:react-error-boundary@5": "[email protected]",
@ -71,6 +73,8 @@
"npm:vite-plugin-pwa@~0.21.1": "[email protected]__@[email protected][email protected][email protected]__@[email protected][email protected][email protected]_@[email protected]",
"npm:vite@*": "6.2.0_@[email protected]",
"npm:vite@^6.2.0": "6.2.0_@[email protected]",
"npm:vitest-browser-react@~0.1.1": "0.1.1_@[email protected]_@[email protected]__@[email protected]_@[email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected][email protected][email protected][email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]__@[email protected][email protected]____@[email protected][email protected][email protected]_____@[email protected]___@[email protected][email protected][email protected]____@[email protected][email protected]____@[email protected][email protected]___@[email protected][email protected][email protected][email protected]_@[email protected]_@[email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]___@[email protected][email protected][email protected][email protected]__@[email protected][email protected]",
"npm:vitest@^3.0.7": "3.0.7_@[email protected][email protected][email protected]__@[email protected]",
"npm:[email protected]": "5.0.3_@[email protected][email protected][email protected]"
},
"npm": {
@ -871,6 +875,25 @@
"@bufbuild/[email protected]": {
"integrity": "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg=="
},
"@bundled-es-modules/[email protected]": {
"integrity": "sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==",
"dependencies": [
"cookie"
]
},
"@bundled-es-modules/[email protected]": {
"integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==",
"dependencies": [
"statuses"
]
},
"@bundled-es-modules/[email protected]": {
"integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==",
"dependencies": [
"@types/tough-cookie",
"[email protected]"
]
},
"@clack/[email protected]": {
"integrity": "sha512-5cfhQNH+1VQ2xLQlmzXMqUoiaH0lRBq9/CLW9lTyMbuKLC3+xEK01tHVvyut++mLOn5urSHmkm6I0Lg9MaJSTQ==",
"dependencies": [
@ -1094,6 +1117,37 @@
"base64-js"
]
},
"@inquirer/[email protected]_@[email protected]": {
"integrity": "sha512-6ZXYK3M1XmaVBZX6FCfChgtponnL0R6I7k8Nu+kaoNkT828FVZTcca1MqmWQipaW2oNREQl5AaPCUOOCVNdRMw==",
"dependencies": [
"@inquirer/core",
"@inquirer/type",
"@types/[email protected]"
]
},
"@inquirer/[email protected]_@[email protected]": {
"integrity": "sha512-AA9CQhlrt6ZgiSy6qoAigiA1izOa751ugX6ioSjqgJ+/Gd+tEN/TORk5sUYNjXuHWfW0r1n/a6ak4u/NqHHrtA==",
"dependencies": [
"@inquirer/figures",
"@inquirer/type",
"@types/[email protected]",
"ansi-escapes",
"cli-width",
"mute-stream",
"signal-exit",
"[email protected]",
"yoctocolors-cjs"
]
},
"@inquirer/[email protected]": {
"integrity": "sha512-Ey6176gZmeqZuY/W/nZiUyvmb1/qInjcpiZjXWi6nON+nxJpD1bxtSoBxNliGISae32n6OwbY+TSXPZ1CfS4bw=="
},
"@inquirer/[email protected]_@[email protected]": {
"integrity": "sha512-2MNFrDY8jkFYc9Il9DgLsHhMzuHnOYM1+CUYVWbzu9oT0hC7V7EcYvdCKeoll/Fcci04A+ERZ9wcc7cQ8lTkIA==",
"dependencies": [
"@types/[email protected]"
]
},
"@isaacs/[email protected]": {
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"dependencies": [
@ -1241,6 +1295,17 @@
"[email protected]"
]
},
"@mswjs/[email protected]": {
"integrity": "sha512-wK+5pLK5XFmgtH3aQ2YVvA3HohS3xqV/OxuVOdNx9Wpnz7VE/fnC+e1A7ln6LFYeck7gOJ/dsZV6OLplOtAJ2w==",
"dependencies": [
"@open-draft/deferred-promise",
"@open-draft/logger",
"@open-draft/until",
"is-node-process",
"outvariant",
"strict-event-emitter"
]
},
"@noble/[email protected]": {
"integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==",
"dependencies": [
@ -1250,6 +1315,19 @@
"@noble/[email protected]": {
"integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="
},
"@open-draft/[email protected]": {
"integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA=="
},
"@open-draft/[email protected]": {
"integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==",
"dependencies": [
"is-node-process",
"outvariant"
]
},
"@open-draft/[email protected]": {
"integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="
},
"@pivanov/[email protected][email protected][email protected][email protected]": {
"integrity": "sha512-JQ/pXeG9/Yq3UuwH2Xp4F6bSAIDGzbxT0Vrg/82tMi3Yp+Ps9AYzjSDE+zfvBRqc7J11V6MMonUrWj4+2dYgrg==",
"dependencies": [
@ -1260,6 +1338,9 @@
"@pkgjs/[email protected]": {
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="
},
"@polka/[email protected]": {
"integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw=="
},
"@preact/[email protected]": {
"integrity": "sha512-OBvUsRZqNmjzCZXWLxkZfhcgT+Fk8DDcT/8vD6a1xhDemodyy87UJRJfASMuSD8FaAIeGgGm85ydXhm7lr4fyA=="
},
@ -2041,6 +2122,12 @@
"react-dom"
]
},
"@testing-library/[email protected]_@[email protected]": {
"integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==",
"dependencies": [
"@testing-library/dom"
]
},
"@turf/[email protected]": {
"integrity": "sha512-Cf+d2LozABdb0TJoIcJwFKB+qisJY4nMUW9z6PAuZ9UCH7AR//hy2Z06vwYCKFZKP4a7DRPkOMBadQABCyoYuw==",
"dependencies": [
@ -3420,6 +3507,9 @@
"@types/har-format"
]
},
"@types/[email protected]": {
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
},
"@types/[email protected]": {
"integrity": "sha512-DauBl25PKZZ0WVJr42a6CNvI6efsdzofl9sajqZr2Gf5Gu733WkDdUGiPkUHXiUvYGzNNlFQde2wdZdfQPG+yw=="
},
@ -3503,12 +3593,18 @@
"@types/[email protected]": {
"integrity": "sha512-c6ynzmpJwqKTkMHDLonE+EStBqTHJqiR+1RsDd40K3YjglABm/C6mZO7xn25g5WldsgxfGHGaKa3IXRnig9c0A=="
},
"@types/[email protected]": {
"integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A=="
},
"@types/[email protected]": {
"integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==",
"dependencies": [
"@types/geojson"
]
},
"@types/[email protected]": {
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA=="
},
"@types/[email protected]": {
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="
},
@ -3545,7 +3641,120 @@
"@babel/plugin-transform-react-jsx-source",
"@types/babel__core",
"react-refresh",
"vite"
"[email protected]_@[email protected]"
]
},
"@vitest/[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]_@[email protected][email protected][email protected]__@[email protected][email protected]__@[email protected][email protected]_@[email protected][email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]__@[email protected][email protected]____@[email protected][email protected][email protected]_____@[email protected]___@[email protected][email protected][email protected]____@[email protected][email protected]____@[email protected][email protected]___@[email protected][email protected][email protected][email protected][email protected]__@[email protected]": {
"integrity": "sha512-TDzZtnbe37KZLSLhvlO1pUkeRSRzW3rOhPLsshX8agGoPELMlG7EvS4z9GfsdaCxsP7oWLBJpFjNJwLS458Bzg==",
"dependencies": [
"@testing-library/dom",
"@testing-library/user-event",
"@vitest/[email protected][email protected][email protected]__@[email protected][email protected]__@[email protected][email protected]_@[email protected][email protected]__@[email protected]",
"@vitest/utils",
"[email protected]",
"msw",
"sirv",
"tinyrainbow",
"[email protected]_@[email protected][email protected][email protected]__@[email protected]_@[email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected][email protected]",
"ws"
]
},
"@vitest/[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]_@[email protected][email protected][email protected]__@[email protected][email protected]__@[email protected][email protected]_@[email protected][email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]__@[email protected][email protected]": {
"integrity": "sha512-TDzZtnbe37KZLSLhvlO1pUkeRSRzW3rOhPLsshX8agGoPELMlG7EvS4z9GfsdaCxsP7oWLBJpFjNJwLS458Bzg==",
"dependencies": [
"@testing-library/dom",
"@testing-library/user-event",
"@vitest/[email protected][email protected][email protected]__@[email protected][email protected]__@[email protected][email protected]_@[email protected]",
"@vitest/utils",
"[email protected]",
"msw",
"sirv",
"tinyrainbow",
"[email protected]_@[email protected][email protected][email protected]__@[email protected]_@[email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]___@[email protected][email protected][email protected][email protected]__@[email protected][email protected]",
"ws"
]
},
"@vitest/[email protected]": {
"integrity": "sha512-QP25f+YJhzPfHrHfYHtvRn+uvkCFCqFtW9CktfBxmB+25QqWsx7VB2As6f4GmwllHLDhXNHvqedwhvMmSnNmjw==",
"dependencies": [
"@vitest/spy",
"@vitest/utils",
"chai",
"tinyrainbow"
]
},
"@vitest/[email protected][email protected][email protected]__@[email protected][email protected]__@[email protected][email protected]_@[email protected]": {
"integrity": "sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w==",
"dependencies": [
"@vitest/spy",
"[email protected]",
"[email protected]",
"msw",
"[email protected]_@[email protected]_@[email protected]"
]
},
"@vitest/[email protected][email protected][email protected]__@[email protected][email protected]__@[email protected][email protected]_@[email protected][email protected]__@[email protected]": {
"integrity": "sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w==",
"dependencies": [
"@vitest/spy",
"[email protected]",
"[email protected]",
"msw",
"[email protected]_@[email protected]"
]
},
"@vitest/[email protected][email protected]__@[email protected]_@[email protected]": {
"integrity": "sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w==",
"dependencies": [
"@vitest/spy",
"[email protected]",
"[email protected]",
"[email protected]_@[email protected]"
]
},
"@vitest/[email protected][email protected]__@[email protected]_@[email protected][email protected][email protected]__@[email protected][email protected]": {
"integrity": "sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w==",
"dependencies": [
"@vitest/spy",
"[email protected]",
"[email protected]",
"msw",
"[email protected]_@[email protected]"
]
},
"@vitest/[email protected]": {
"integrity": "sha512-CiRY0BViD/V8uwuEzz9Yapyao+M9M008/9oMOSQydwbwb+CMokEq3XVaF3XK/VWaOK0Jm9z7ENhybg70Gtxsmg==",
"dependencies": [
"tinyrainbow"
]
},
"@vitest/[email protected]": {
"integrity": "sha512-WeEl38Z0S2ZcuRTeyYqaZtm4e26tq6ZFqh5y8YD9YxfWuu0OFiGFUbnxNynwLjNRHPsXyee2M9tV7YxOTPZl2g==",
"dependencies": [
"@vitest/utils",
"pathe"
]
},
"@vitest/[email protected]": {
"integrity": "sha512-eqTUryJWQN0Rtf5yqCGTQWsCFOQe4eNz5Twsu21xYEcnFJtMU5XvmG0vgebhdLlrHQTSq5p8vWHJIeJQV8ovsA==",
"dependencies": [
"@vitest/pretty-format",
"[email protected]",
"pathe"
]
},
"@vitest/[email protected]": {
"integrity": "sha512-4T4WcsibB0B6hrKdAZTM37ekuyFZt2cGbEGd2+L0P8ov15J1/HUsUaqkXEQPNAWr4BtPPe1gI+FYfMHhEKfR8w==",
"dependencies": [
"tinyspy"
]
},
"@vitest/[email protected]": {
"integrity": "sha512-xePVpCRfooFX3rANQjwoditoXgWb1MaFbzmGuPP59MK6i13mrnDw/yEIyJudLeW6/38mCNcwCiJIGmpDPibAIg==",
"dependencies": [
"@vitest/pretty-format",
"loupe",
"tinyrainbow"
]
},
"[email protected]": {
@ -3563,6 +3772,12 @@
"require-from-string"
]
},
"[email protected]": {
"integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
"dependencies": [
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
},
@ -3633,6 +3848,9 @@
"util"
]
},
"[email protected]": {
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="
},
"[email protected]": {
"integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw=="
},
@ -3825,6 +4043,9 @@
"typewise"
]
},
"[email protected]": {
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="
},
"[email protected]": {
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dependencies": [
@ -3851,6 +4072,16 @@
"[email protected]": {
"integrity": "sha512-faRs/AW3jA9nTwmJBSO1PQ6L/EOgsB5HMQQq4iCu5zhPgVVgO/pZRHlmatwijZKetFw8/Pr4q6dEN8sJuq8qTw=="
},
"[email protected]": {
"integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
"dependencies": [
"assertion-error",
"check-error",
"deep-eql",
"loupe",
"pathval"
]
},
"[email protected]": {
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
"dependencies": [
@ -3865,6 +4096,9 @@
"supports-color"
]
},
"[email protected]": {
"integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw=="
},
"[email protected]": {
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="
},
@ -3889,6 +4123,17 @@
"clsx"
]
},
"[email protected]": {
"integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ=="
},
"[email protected]": {
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dependencies": [
"[email protected]",
"[email protected]",
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="
},
@ -3948,6 +4193,9 @@
"[email protected]": {
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
},
"[email protected]": {
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="
},
"[email protected]": {
"integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==",
"dependencies": [
@ -4090,6 +4338,9 @@
"[email protected]": {
"integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="
},
"[email protected]": {
"integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="
},
"[email protected]": {
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="
},
@ -4279,6 +4530,9 @@
"[email protected]": {
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="
},
"[email protected]": {
"integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ=="
},
"[email protected]": {
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dependencies": [
@ -4390,6 +4644,9 @@
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA=="
},
"[email protected]": {
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"dependencies": [
@ -4462,7 +4719,7 @@
"at-least-node",
"graceful-fs",
"jsonfile",
"universalify"
"universalify@2.0.1"
]
},
"[email protected]": {
@ -4509,6 +4766,9 @@
"[email protected]": {
"integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A=="
},
"[email protected]": {
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"[email protected]": {
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dependencies": [
@ -4606,6 +4866,9 @@
"[email protected]": {
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"[email protected]": {
"integrity": "sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ=="
},
"[email protected]": {
"integrity": "sha512-JUvhzo8dHQWJp1eyYy1ShaPfcowsPbRc2rvwkD4LRyou/80UUz96bn+EOOYLWO4PG0Y5f3+UlUX9Gmu8RZhrtw==",
"dependencies": [
@ -4661,6 +4924,9 @@
"function-bind"
]
},
"[email protected]": {
"integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ=="
},
"[email protected]": {
"integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
"dependencies": [
@ -4833,6 +5099,9 @@
"define-properties"
]
},
"[email protected]": {
"integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw=="
},
"[email protected]": {
"integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
"dependencies": [
@ -4975,7 +5244,7 @@
"rrweb-cssom",
"saxes",
"symbol-tree",
"tough-cookie",
"tough-cookie@5.1.2",
"w3c-xmlserializer",
"[email protected]",
"whatwg-encoding",
@ -5010,7 +5279,7 @@
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dependencies": [
"graceful-fs",
"universalify"
"universalify@2.0.1"
]
},
"[email protected]": {
@ -5098,6 +5367,9 @@
"[email protected]": {
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"[email protected]": {
"integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug=="
},
"[email protected]": {
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
},
@ -5235,12 +5507,42 @@
"[email protected]": {
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="
},
"[email protected]": {
"integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="
},
"[email protected]": {
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"[email protected][email protected]_@[email protected]": {
"integrity": "sha512-+mycXv8l2fEAjFZ5sjrtjJDmm2ceKGjrNbBr1durRg6VkU9fNUE/gsmQ51hWbHqs+l35W1iM+ZsmOD9Fd6lspw==",
"dependencies": [
"@bundled-es-modules/cookie",
"@bundled-es-modules/statuses",
"@bundled-es-modules/tough-cookie",
"@inquirer/confirm",
"@mswjs/interceptors",
"@open-draft/deferred-promise",
"@open-draft/until",
"@types/cookie",
"@types/statuses",
"graphql",
"headers-polyfill",
"is-node-process",
"outvariant",
"path-to-regexp",
"picocolors",
"strict-event-emitter",
"[email protected]",
"typescript",
"yargs"
]
},
"[email protected]": {
"integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw=="
},
"[email protected]": {
"integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA=="
},
"[email protected]": {
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="
},
@ -5318,6 +5620,9 @@
"[email protected]": {
"integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A=="
},
"[email protected]": {
"integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA=="
},
"[email protected]": {
"integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
"dependencies": [
@ -5383,6 +5688,15 @@
"minipass"
]
},
"[email protected]": {
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="
},
"[email protected]": {
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="
},
"[email protected]": {
"integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA=="
},
"[email protected]": {
"integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==",
"dependencies": [
@ -5498,6 +5812,9 @@
"[email protected]": {
"integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw=="
},
"[email protected]": {
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
},
"[email protected]": {
"integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
"dependencies": [
@ -5527,6 +5844,9 @@
"[email protected]": {
"integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA=="
},
"[email protected]": {
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
},
"[email protected]": {
"integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ=="
},
@ -5753,9 +6073,15 @@
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
},
"[email protected]": {
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
},
"[email protected]": {
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
},
"[email protected]": {
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="
},
@ -5977,6 +6303,9 @@
"side-channel-weakmap"
]
},
"[email protected]": {
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="
},
"[email protected]": {
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="
},
@ -5992,6 +6321,14 @@
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==",
"dependencies": [
"@polka/url",
"mrmime",
"totalist"
]
},
"[email protected]": {
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
},
@ -6049,6 +6386,15 @@
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="
},
"[email protected]": {
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
},
"[email protected]": {
"integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w=="
},
"[email protected]": {
"integrity": "sha512-ivkRENMh0mdGoPlZ4xVcEaC8rXQfTEfvonRw5m8VDKV7kgcbZbaNd1TnKl08wXbcLdT7okSc63HNP8cVhy95zg=="
},
@ -6077,6 +6423,9 @@
"[email protected]": {
"integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="
},
"[email protected]": {
"integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ=="
},
"[email protected]": {
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dependencies": [
@ -6271,6 +6620,12 @@
"setimmediate"
]
},
"[email protected]": {
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="
},
"[email protected]": {
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="
},
"[email protected][email protected]": {
"integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
"dependencies": [
@ -6278,12 +6633,21 @@
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA=="
},
"[email protected]": {
"integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA=="
},
"[email protected]": {
"integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g=="
},
"[email protected]": {
"integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="
},
"[email protected]": {
"integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q=="
},
"[email protected]": {
"integrity": "sha512-Jabl32m21tt/d/PbDO88R43F8aY98Piiz6BVH9ShUlOAiiAELhEqwrAmBocjAqnCfoUeIsRU+h3IEzZd318F3w=="
},
@ -6305,6 +6669,18 @@
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="
},
"[email protected]": {
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
"dependencies": [
"psl",
"[email protected]",
"[email protected]",
"url-parse"
]
},
"[email protected]": {
"integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==",
"dependencies": [
@ -6343,9 +6719,15 @@
"[email protected]": {
"integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg=="
},
"[email protected]": {
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="
},
"[email protected]": {
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="
},
"[email protected]": {
"integrity": "sha512-3T/PUdKTCnkUmhQU6FFJEHsLwadsRegktX3TNHk+2JJB9HlA8gp1/VXblXVDI93kSnXF2rdPx0GMbHtJIV2LPg=="
},
"[email protected]": {
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"dependencies": [
@ -6445,6 +6827,9 @@
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="
},
"[email protected]": {
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="
},
@ -6466,6 +6851,13 @@
"picocolors"
]
},
"[email protected]": {
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dependencies": [
"querystringify",
"requires-port"
]
},
"[email protected]": {
"integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==",
"dependencies": [
@ -6512,12 +6904,22 @@
"[email protected]": {
"integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg=="
},
"[email protected]_@[email protected]": {
"integrity": "sha512-2fX0QwX4GkkkpULXdT1Pf4q0tC1i1lFOyseKoonavXUNlQ77KpW2XqBGGNIm/J4Ows4KxgGJzDguYVPKwG/n5A==",
"dependencies": [
"cac",
"debug",
"es-module-lexer",
"pathe",
"[email protected]_@[email protected]"
]
},
"[email protected][email protected]__@[email protected]_@[email protected]": {
"integrity": "sha512-4n+Ys+2bKHQohPBKigFlndwWQ5fFKwaGY6muNDMTb0fSQLyBzS+jjUNRZG9sKF0S/Go4ApG6LFnUGopjkILg3w==",
"dependencies": [
"@rollup/plugin-inject",
"node-stdlib-browser",
"vite"
"vite@6.2.0_@[email protected]"
]
},
"[email protected][email protected]__@[email protected][email protected][email protected]__@[email protected][email protected][email protected]_@[email protected]": {
@ -6526,11 +6928,21 @@
"debug",
"[email protected]",
"tinyglobby",
"vite",
"vite@6.2.0_@[email protected]",
"workbox-build",
"workbox-window"
]
},
"[email protected]_@[email protected]": {
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==",
"dependencies": [
"@types/[email protected]",
"[email protected]",
"[email protected]",
"postcss",
"[email protected]"
]
},
"[email protected]_@[email protected]": {
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==",
"dependencies": [
@ -6541,6 +6953,110 @@
"[email protected]"
]
},
"[email protected]_@[email protected]_@[email protected]": {
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==",
"dependencies": [
"@types/[email protected]",
"[email protected]",
"[email protected]",
"postcss",
"[email protected]"
]
},
"[email protected]_@[email protected]_@[email protected]__@[email protected]_@[email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected][email protected][email protected][email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]__@[email protected][email protected]____@[email protected][email protected][email protected]_____@[email protected]___@[email protected][email protected][email protected]____@[email protected][email protected]____@[email protected][email protected]___@[email protected][email protected][email protected][email protected]_@[email protected]_@[email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]___@[email protected][email protected][email protected][email protected]__@[email protected][email protected]": {
"integrity": "sha512-n9l+sIAexKqqfBuEkjVGdfZ4xAn1Gn/+wc4Mo8KsUSUOVoM9evSY0rVXdMIzCQqloT/zvmFGAtziFINkqu+t7g==",
"dependencies": [
"@types/react",
"@types/react-dom",
"@vitest/[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]_@[email protected][email protected][email protected]__@[email protected][email protected]__@[email protected][email protected]_@[email protected][email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]__@[email protected][email protected]",
"react",
"react-dom",
"[email protected]_@[email protected][email protected][email protected]__@[email protected]_@[email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected][email protected]"
]
},
"[email protected]_@[email protected][email protected][email protected]__@[email protected]": {
"integrity": "sha512-IP7gPK3LS3Fvn44x30X1dM9vtawm0aesAa2yBIZ9vQf+qB69NXC5776+Qmcr7ohUXIQuLhk7xQR0aSUIDPqavg==",
"dependencies": [
"@types/[email protected]",
"@vitest/expect",
"@vitest/[email protected][email protected]__@[email protected]_@[email protected]",
"@vitest/pretty-format",
"@vitest/runner",
"@vitest/snapshot",
"@vitest/spy",
"@vitest/utils",
"chai",
"debug",
"expect-type",
"jsdom",
"[email protected]",
"pathe",
"std-env",
"tinybench",
"tinyexec",
"tinypool",
"tinyrainbow",
"[email protected]_@[email protected]",
"vite-node",
"why-is-node-running"
]
},
"[email protected]_@[email protected][email protected][email protected]__@[email protected]_@[email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]___@[email protected][email protected][email protected][email protected]__@[email protected][email protected]": {
"integrity": "sha512-IP7gPK3LS3Fvn44x30X1dM9vtawm0aesAa2yBIZ9vQf+qB69NXC5776+Qmcr7ohUXIQuLhk7xQR0aSUIDPqavg==",
"dependencies": [
"@types/[email protected]",
"@vitest/[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]_@[email protected][email protected][email protected]__@[email protected][email protected]__@[email protected][email protected]_@[email protected][email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]__@[email protected][email protected]",
"@vitest/expect",
"@vitest/[email protected][email protected]__@[email protected]_@[email protected][email protected][email protected]__@[email protected][email protected]",
"@vitest/pretty-format",
"@vitest/runner",
"@vitest/snapshot",
"@vitest/spy",
"@vitest/utils",
"chai",
"debug",
"expect-type",
"jsdom",
"[email protected]",
"pathe",
"std-env",
"tinybench",
"tinyexec",
"tinypool",
"tinyrainbow",
"[email protected]_@[email protected]",
"vite-node",
"why-is-node-running"
]
},
"[email protected]_@[email protected][email protected][email protected]__@[email protected]_@[email protected][email protected]___@[email protected][email protected][email protected]____@[email protected]__@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected]__@[email protected][email protected][email protected][email protected]": {
"integrity": "sha512-IP7gPK3LS3Fvn44x30X1dM9vtawm0aesAa2yBIZ9vQf+qB69NXC5776+Qmcr7ohUXIQuLhk7xQR0aSUIDPqavg==",
"dependencies": [
"@types/[email protected]",
"@vitest/[email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]_@[email protected][email protected][email protected]__@[email protected][email protected]__@[email protected][email protected]_@[email protected][email protected][email protected]__@[email protected][email protected][email protected]___@[email protected]__@[email protected][email protected]____@[email protected][email protected][email protected]_____@[email protected]___@[email protected][email protected][email protected]____@[email protected][email protected]____@[email protected][email protected]___@[email protected][email protected][email protected][email protected][email protected]__@[email protected]",
"@vitest/expect",
"@vitest/[email protected][email protected]__@[email protected]_@[email protected][email protected][email protected]__@[email protected][email protected]",
"@vitest/pretty-format",
"@vitest/runner",
"@vitest/snapshot",
"@vitest/spy",
"@vitest/utils",
"chai",
"debug",
"expect-type",
"jsdom",
"[email protected]",
"pathe",
"std-env",
"tinybench",
"tinyexec",
"tinypool",
"tinyrainbow",
"[email protected]_@[email protected]",
"vite-node",
"why-is-node-running"
]
},
"[email protected]": {
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
},
@ -6651,6 +7167,13 @@
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
"dependencies": [
"siginfo",
"stackback"
]
},
"[email protected]": {
"integrity": "sha512-PCSk3eK7Mxeuyatb22pcSx9dlgWNv3+M8PqPaYDokks8Y5/FX4soaOqj3yhAZr5k6Q5JWTOMYgaJBpbw11G9Eg==",
"dependencies": [
@ -6791,6 +7314,14 @@
"workbox-core"
]
},
"[email protected]": {
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"dependencies": [
"[email protected]",
"[email protected]",
"[email protected]"
]
},
"[email protected]": {
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dependencies": [
@ -6822,15 +7353,36 @@
"[email protected]": {
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
"[email protected]": {
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
},
"[email protected]": {
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
},
"[email protected]": {
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="
},
"[email protected]": {
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
},
"[email protected]": {
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dependencies": [
"cliui",
"escalade",
"get-caller-file",
"require-directory",
"[email protected]",
"y18n",
"yargs-parser"
]
},
"[email protected]": {
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
},
"[email protected]": {
"integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA=="
},
"[email protected]_@[email protected][email protected][email protected]": {
"integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==",
"dependencies": [
@ -6889,6 +7441,7 @@
"npm:jsdom@26",
"npm:[email protected]",
"npm:[email protected]",
"npm:playwright@^1.50.1",
"npm:postcss@^8.5.3",
"npm:react-dom@19",
"npm:react-error-boundary@5",
@ -6907,6 +7460,7 @@
"npm:[email protected]",
"npm:vite-plugin-pwa@~0.21.1",
"npm:vite@^6.2.0",
"npm:vitest-browser-react@~0.1.1",
"npm:vitest@^3.0.7",
"npm:[email protected]"
]

7
package.json

@ -14,7 +14,6 @@
"dev:ui": "deno run -A npm:vite dev",
"dev:scan": "VITE_DEBUG_SCAN=true deno task dev:ui",
"test": "deno run -A npm:vitest",
"test:ui": "deno task test --ui",
"preview": "deno run -A npm:vite preview",
"package": "gzipper c -i html,js,css,png,ico,svg,webmanifest,txt dist dist/output && tar -cvf dist/build.tar -C ./dist/output/ ."
},
@ -67,6 +66,7 @@
"js-cookie": "^3.0.5",
"lucide-react": "^0.477.0",
"maplibre-gl": "5.1.1",
"playwright": "^1.50.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-error-boundary": "^5.0.0",
@ -76,6 +76,8 @@
"react-scan": "^0.2.8",
"rfc4648": "^1.5.4",
"vite-plugin-node-polyfills": "^0.23.0",
"vitest": "^3.0.7",
"vitest-browser-react": "^0.1.1",
"zustand": "5.0.3"
},
"devDependencies": {
@ -102,7 +104,6 @@
"tar": "^7.4.3",
"typescript": "^5.8.2",
"vite": "^6.2.0",
"vite-plugin-pwa": "^0.21.1",
"vitest": "^3.0.7"
"vite-plugin-pwa": "^0.21.1"
}
}

32
src/components/PageComponents/Connect/HTTP.test.tsx

@ -1,8 +1,8 @@
import { describe, it, vi, expect } from "vitest";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { HTTP } from "@components/PageComponents/Connect/HTTP.tsx";
import { TransportHTTP } from "@meshtastic/transport-http";
import { MeshDevice } from "@meshtastic/core";
import { TransportHTTP } from "@meshtastic/transport-http";
import { vi, describe, it, expect } from "vitest";
vi.mock("@core/stores/appStore.ts", () => ({
useAppStore: vi.fn(() => ({ setSelectedDevice: vi.fn() })),
@ -41,25 +41,27 @@ describe("HTTP Component", () => {
it("allows input field to be updated", () => {
render(<HTTP closeDialog={vi.fn()} />);
const input = screen.getByRole("textbox");
fireEvent.change(input, { target: { value: "meshtastic.local" } });
expect(input).toHaveValue("meshtastic.local");
const inputField = screen.getByRole("textbox");
fireEvent.change(inputField, { target: { value: 'meshtastic.local' } })
expect(screen.getByPlaceholderText("000.000.000.000 / meshtastic.local")).toBeInTheDocument();
});
it("toggles HTTPS switch and updates prefix", () => {
render(<HTTP closeDialog={vi.fn()} />);
const switchInput = screen.getByRole("switch");
expect(screen.getByText("http://")).toBeInTheDocument();
fireEvent.click(switchInput);
fireEvent.click(switchInput)
expect(screen.getByText("https://")).toBeInTheDocument();
fireEvent.click(switchInput);
fireEvent.click(switchInput)
expect(switchInput).not.toBeChecked();
expect(screen.getByText("http://")).toBeInTheDocument();
});
it("enables HTTPS toggle when location protocol is https", () => {
Object.defineProperty(globalThis, "location", {
Object.defineProperty(window, "location", {
value: { protocol: "https:" },
writable: true,
});
@ -70,21 +72,19 @@ describe("HTTP Component", () => {
expect(switchInput).toBeChecked();
});
it.skip("submits form and triggers connection process", () => {
// This will need further work to test, as it involves a lot of other plumbing mocking
it("submits form and triggers connection process", async () => {
const closeDialog = vi.fn();
render(<HTTP closeDialog={closeDialog} />);
const button = screen.getByRole("button", { name: "Connect" });
expect(button).not.toBeDisabled();
fireEvent.click(button);
waitFor(() => {
await waitFor(() => {
expect(button).toBeDisabled();
expect(closeDialog).toHaveBeenCalled();
expect(TransportHTTP.create).toHaveBeenCalled();
expect(MeshDevice).toHaveBeenCalled();
expect(closeDialog).toBeCalled();
expect(TransportHTTP.create).toBeCalled();
expect(MeshDevice).toBeCalled();
});
});
});

53
src/components/PageComponents/Messages/ChannelChat.tsx

@ -1,14 +1,10 @@
import { type MessageWithState, useDevice } from "@core/stores/deviceStore.ts";
import { Message } from "@components/PageComponents/Messages/Message.tsx";
import { MessageInput } from "@components/PageComponents/Messages/MessageInput.tsx";
import type { Types } from "@meshtastic/core";
import { InboxIcon } from "lucide-react";
import { useCallback, useEffect, useRef } from "react";
export interface ChannelChatProps {
messages?: MessageWithState[];
channel: Types.ChannelNumber;
to: Types.Destination;
}
const EmptyState = () => (
@ -20,8 +16,6 @@ const EmptyState = () => (
export const ChannelChat = ({
messages,
channel,
to,
}: ChannelChatProps) => {
const { nodes } = useDevice();
const messagesEndRef = useRef<HTMLDivElement>(null);
@ -30,10 +24,12 @@ export const ChannelChat = ({
const scrollToBottom = useCallback(() => {
const scrollContainer = scrollContainerRef.current;
if (scrollContainer) {
const isNearBottom = scrollContainer.scrollHeight -
scrollContainer.scrollTop -
scrollContainer.clientHeight <
const isNearBottom =
scrollContainer.scrollHeight -
scrollContainer.scrollTop -
scrollContainer.clientHeight <
100;
if (isNearBottom) {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}
@ -42,7 +38,7 @@ export const ChannelChat = ({
useEffect(() => {
scrollToBottom();
}, [scrollToBottom]);
}, [scrollToBottom, messages]);
if (!messages?.length) {
return (
@ -50,34 +46,31 @@ export const ChannelChat = ({
<div className="flex-1 flex items-center justify-center">
<EmptyState />
</div>
<div className="shrink-0 p-4 w-full dark:bg-slate-900">
<MessageInput to={to} channel={channel} maxBytes={200} />
</div>
</div>
);
}
return (
<div className="flex flex-col h-full container mx-auto">
<div className="flex-1 overflow-y-auto" ref={scrollContainerRef}>
<div className="w-full h-full flex flex-col justify-end pl-4 pr-44">
{messages.map((message, index) => {
return (
<Message
key={message.id}
message={message}
sender={nodes.get(message.from)}
lastMsgSameUser={index > 0 &&
messages[index - 1].from === message.from}
/>
);
})}
<div
ref={scrollContainerRef}
className="flex-1 overflow-y-auto pl-4 pr-4 md:pr-44"
>
<div className="flex flex-col justify-end min-h-full">
{messages.map((message, index) => (
<Message
key={message.id}
message={message}
sender={nodes.get(message.from)}
lastMsgSameUser={
index > 0 && messages[index - 1].from === message.from
}
/>
))}
<div ref={messagesEndRef} className="w-full" />
</div>
</div>
<div className="shrink-0 mt-2 p-4 w-full dark:bg-slate-900">
<MessageInput to={to} channel={channel} maxBytes={200} />
</div>
</div>
);
};
};

148
src/components/PageComponents/Messages/MessageInput.test.tsx

@ -0,0 +1,148 @@
import { MessageInput } from '@components/PageComponents/Messages/MessageInput.tsx';
import { useDevice } from "@core/stores/deviceStore.ts";
import { vi, describe, it, expect, beforeEach, Mock } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
vi.mock("@core/stores/deviceStore.ts", () => ({
useDevice: vi.fn(),
}));
vi.mock("@core/utils/debounce.ts", () => ({
debounce: (fn: () => void) => fn,
}));
vi.mock("@components/UI/Button.tsx", () => ({
Button: ({ children, ...props }: { children: React.ReactNode }) => <button {...props}>{children}</button>
}));
vi.mock("@components/UI/Input.tsx", () => ({
Input: (props: any) => <input {...props} />
}));
vi.mock("lucide-react", () => ({
SendIcon: () => <div data-testid="send-icon">Send</div>
}));
// TODO: getting an error with this test
describe.skip('MessageInput Component', () => {
const mockProps = {
to: "broadcast" as const,
channel: 0 as const,
maxBytes: 100,
};
const mockSetMessageDraft = vi.fn();
const mockSetMessageState = vi.fn();
const mockSendText = vi.fn().mockResolvedValue(123); // mock ID returned from sendText
beforeEach(() => {
vi.clearAllMocks();
// Setup the mock implementation for useDevice
(useDevice as Mock).mockReturnValue({
connection: {
sendText: mockSendText,
},
setMessageState: mockSetMessageState,
messageDraft: "",
setMessageDraft: mockSetMessageDraft,
hardware: {
myNodeNum: 1234567890,
},
});
});
it('renders correctly with initial state', () => {
render(<MessageInput {...mockProps} />);
expect(screen.getByPlaceholderText('Enter Message')).toBeInTheDocument();
expect(screen.getByTestId('send-icon')).toBeInTheDocument();
expect(screen.getByText('0/100')).toBeInTheDocument();
});
it('updates local draft and byte count when typing', () => {
render(<MessageInput {...mockProps} />);
const inputField = screen.getByPlaceholderText('Enter Message');
fireEvent.change(inputField, { target: { value: 'Hello' } })
expect(screen.getByText('5/100')).toBeInTheDocument();
expect(inputField).toHaveValue('Hello');
expect(mockSetMessageDraft).toHaveBeenCalledWith('Hello');
});
it('does not allow input exceeding max bytes', () => {
render(<MessageInput {...mockProps} maxBytes={5} />);
const inputField = screen.getByPlaceholderText('Enter Message');
expect(screen.getByText('5/5')).toBeInTheDocument();
fireEvent.change(inputField, { target: { value: 'Hello' } })
expect(inputField).toHaveValue('Hello');
expect(screen.getByText('5/5')).toBeInTheDocument();
});
it('sends message and resets form when submitting', async () => {
render(<MessageInput {...mockProps} />);
const inputField = screen.getByPlaceholderText('Enter Message');
const submitButton = screen.getByText('Send');
fireEvent.change(inputField, { target: { value: 'Test Message' } });
fireEvent.click(submitButton);
const form = screen.getByRole('form');
fireEvent.submit(form);
expect(mockSendText).toHaveBeenCalledWith('Test message', 'broadcast', true, 0);
await waitFor(() => {
expect(mockSetMessageState).toHaveBeenCalledWith(
'broadcast',
0,
'broadcast',
1234567890,
123,
'ack'
);
});
expect(inputField).toHaveValue('');
expect(screen.getByText('0/100')).toBeInTheDocument();
expect(mockSetMessageDraft).toHaveBeenCalledWith('');
});
it('prevents sending empty messages', () => {
render(<MessageInput {...mockProps} />);
const form = screen.getByPlaceholderText('Enter Message')
fireEvent.submit(form);
expect(mockSendText).not.toHaveBeenCalled();
});
it('initializes with existing message draft', () => {
(useDevice as Mock).mockReturnValue({
connection: {
sendText: mockSendText,
},
setMessageState: mockSetMessageState,
messageDraft: "Existing draft",
setMessageDraft: mockSetMessageDraft,
isQueueingMessages: false,
queueStatus: { free: 10 },
hardware: {
myNodeNum: 1234567890,
},
});
render(<MessageInput {...mockProps} />);
const inputField = screen.getByRole('label');
expect(inputField).toHaveValue('Existing draft');
expect(screen.getByText('14/100')).toBeInTheDocument();
});
});

29
src/components/PageComponents/Messages/MessageInput.tsx

@ -1,4 +1,4 @@
import { debounce } from "../../../core/utils/debounce.ts";
import { debounce } from "@core/utils/debounce.ts";
import { Button } from "@components/UI/Button.tsx";
import { Input } from "@components/UI/Input.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
@ -22,6 +22,8 @@ export const MessageInput = ({
setMessageState,
messageDraft,
setMessageDraft,
isQueueingMessages,
queueStatus,
hardware,
} = useDevice();
const myNodeNum = hardware.myNodeNum;
@ -33,8 +35,12 @@ export const MessageInput = ({
[setMessageDraft],
);
// sends the message to the selected destination
const sendText = useCallback(
async (message: string) => {
console.log('queueStatus', queueStatus.free)
await connection
?.sendText(message, to, true, channel)
.then((id: number) =>
@ -58,7 +64,7 @@ export const MessageInput = ({
)
);
},
[channel, connection, myNodeNum, setMessageState, to],
[channel, connection, myNodeNum, setMessageState, to, queueStatus],
);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@ -81,14 +87,17 @@ export const MessageInput = ({
if (localDraft === "") return;
const message = formData.get("messageInput") as string;
startTransition(() => {
sendText(message);
setLocalDraft("");
setMessageDraft("");
setMessageBytes(0);
if (!isQueueingMessages) {
sendText(message);
setLocalDraft("");
setMessageDraft("");
setMessageBytes(0);
}
});
}}
>
<div className="flex grow gap-2">
<div className="flex grow gap-2 ">
<span className="w-full">
<Input
autoFocus
@ -99,11 +108,11 @@ export const MessageInput = ({
onChange={handleInputChange}
/>
</span>
<div className="flex items-center w-24 p-2 place-content-end">
<label className="flex items-center w-24 p-2 place-content-end">
{messageBytes}/{maxBytes}
</div>
</label>
<Button type="submit">
<Button type="submit" className="dark:bg-white dark:text-slate-900 dark:hover:bg-slate-400 dark:hover:text-slate-700">
<SendIcon size={16} />
</Button>
</div>

3
src/components/PageLayout.tsx

@ -10,6 +10,7 @@ export interface PageLayoutProps {
label: string;
noPadding?: boolean;
children: React.ReactNode;
className?: string;
actions?: {
icon: LucideIcon;
iconClasses?: string;
@ -23,6 +24,7 @@ export const PageLayout = ({
label,
noPadding,
actions,
className,
children,
}: PageLayoutProps) => {
return (
@ -63,6 +65,7 @@ export const PageLayout = ({
className={cn(
"flex h-full w-full flex-col overflow-y-auto",
!noPadding && "pl-3 pr-3 ",
className
)}
>
{children}

2
src/components/Sidebar.tsx

@ -66,7 +66,7 @@ export const Sidebar = ({ children }: SidebarProps) => {
return showSidebar
? (
<div className="min-w-[280px] max-w-min flex-col overflow-y-auto border-r-[0.5px] bg-background-primary border-slate-300 dark:border-slate-700">
<div className="min-w-[280px] max-w-min flex-col overflow-y-auto border-r-[0.5px] bg-background-primary border-slate-300 dark:border-slate-400">
<div className="flex justify-between px-8 pt-6">
<div>
<span className="text-lg font-medium">

32
src/core/stores/deviceStore.ts

@ -1,5 +1,5 @@
import { create } from "@bufbuild/protobuf";
import { Protobuf, Types } from "@meshtastic/core";
import { MeshDevice, Protobuf, Types } from "@meshtastic/core";
import { produce } from "immer";
import { createContext, useContext } from "react";
import { create as createStore } from "zustand";
@ -28,6 +28,10 @@ export type DialogVariant =
| "pkiBackup"
| "nodeDetails";
type QueueStatus = {
res: number, free: number, maxlen: number
}
export interface Device {
id: number;
status: Types.DeviceStatusEnum;
@ -47,13 +51,15 @@ export interface Device {
number,
Types.PacketMetadata<Protobuf.Mesh.RouteDiscovery>[]
>;
connection?: Types.ConnectionType;
connection?: MeshDevice;
activePage: Page;
activeNode: number;
waypoints: Protobuf.Mesh.Waypoint[];
// currentMetrics: Protobuf.DeviceMetrics;
pendingSettingsChanges: boolean;
messageDraft: string;
queueStatus: QueueStatus,
isQueueingMessages: boolean,
dialog: {
import: boolean;
QR: boolean;
@ -65,6 +71,7 @@ export interface Device {
nodeDetails: boolean;
};
setStatus: (status: Types.DeviceStatusEnum) => void;
setConfig: (config: Protobuf.Config.Config) => void;
setModuleConfig: (config: Protobuf.ModuleConfig.ModuleConfig) => void;
@ -80,7 +87,7 @@ export interface Device {
addNodeInfo: (nodeInfo: Protobuf.Mesh.NodeInfo) => void;
addUser: (user: Types.PacketMetadata<Protobuf.Mesh.User>) => void;
addPosition: (position: Types.PacketMetadata<Protobuf.Mesh.Position>) => void;
addConnection: (connection: Types.ConnectionType) => void;
addConnection: (connection: MeshDevice) => void;
addMessage: (message: MessageWithState) => void;
addTraceRoute: (
traceroute: Types.PacketMetadata<Protobuf.Mesh.RouteDiscovery>,
@ -98,6 +105,7 @@ export interface Device {
setDialogOpen: (dialog: DialogVariant, open: boolean) => void;
processPacket: (data: ProcessPacketParams) => void;
setMessageDraft: (message: string) => void;
setQueueStatus: (status: QueueStatus) => void;
}
export interface DeviceState {
@ -137,6 +145,10 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
activePage: "messages",
activeNode: 0,
waypoints: [],
queueStatus: {
res: 0, free: 0, maxlen: 0
},
isQueueingMessages: false,
dialog: {
import: false,
QR: false,
@ -303,7 +315,7 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
.findIndex(
(wmc) =>
wmc.payloadVariant.case ===
moduleConfig.payloadVariant.case,
moduleConfig.payloadVariant.case,
);
if (workingModuleConfigIndex !== -1) {
device.workingModuleConfig[workingModuleConfigIndex] =
@ -516,7 +528,6 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
set(
produce<DeviceState>((draft) => {
console.log("addTraceRoute called");
console.log(traceroute);
const device = draft.devices.get(id);
if (!device) {
return;
@ -631,6 +642,17 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
}),
);
},
setQueueStatus: (status: QueueStatus) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
device.queueStatus = status;
device.queueStatus.free >= 10 ? true : false
}
}),
);
}
});
}),
);

15
src/index.css

@ -71,6 +71,7 @@
}
@layer base {
*,
::after,
::before,
@ -96,11 +97,23 @@
}
}
@layer utilities {
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
}
/* Prevent image dragging */
img {
-webkit-user-drag: none;
}
@keyframes spin-slower {
to {
transform: rotate(360deg);
@ -109,4 +122,4 @@ img {
.animate-spin-slow {
animation: spin-slower 2s linear infinite;
}
}

83
src/pages/Messages.tsx

@ -12,6 +12,7 @@ import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import { getChannelName } from "@pages/Channels.tsx";
import { HashIcon, LockIcon, LockOpenIcon } from "lucide-react";
import { useState } from "react";
import { MessageInput } from "@components/PageComponents/Messages/MessageInput.tsx";
export const MessagesPage = () => {
const { channels, nodes, hardware, messages } = useDevice();
@ -31,6 +32,11 @@ export const MessagesPage = () => {
const node = nodes.get(activeChat);
const nodeHex = node?.num ? numberToHexUnpadded(node.num) : "Unknown";
const messageDestination = chatType === "direct" ? activeChat : "broadcast";
const messageChannel = chatType === "direct"
? Types.ChannelNumber.Primary
: activeChat;
return (
<>
<Sidebar>
@ -41,9 +47,9 @@ export const MessagesPage = () => {
label={channel.settings?.name.length
? channel.settings?.name
: channel.index === 0
? "Primary"
: `Ch ${channel.index}`}
active={activeChat === channel.index}
? "Primary"
: `Ch ${channel.index}`}
active={activeChat === channel.index && chatType === "broadcast"}
onClick={() => {
setChatType("broadcast");
setActiveChat(channel.index);
@ -68,7 +74,7 @@ export const MessagesPage = () => {
key={node.num}
label={node.user?.longName ??
`!${numberToHexUnpadded(node.num)}`}
active={activeChat === node.num}
active={activeChat === node.num && chatType === "direct"}
onClick={() => {
setChatType("direct");
setActiveChat(node.num);
@ -84,15 +90,15 @@ export const MessagesPage = () => {
</div>
</SidebarSection>
</Sidebar>
<div className="flex flex-col grow">
<div className="flex flex-col w-full h-full">
<PageLayout
label={`Messages: ${
chatType === "broadcast" && currentChannel
? getChannelName(currentChannel)
: chatType === "direct" && nodes.get(activeChat)
className="flex flex-col h-full"
label={`Messages: ${chatType === "broadcast" && currentChannel
? getChannelName(currentChannel)
: chatType === "direct" && nodes.get(activeChat)
? (nodes.get(activeChat)?.user?.longName ?? nodeHex)
: "Loading..."
}`}
}`}
actions={chatType === "direct"
? [
{
@ -115,32 +121,43 @@ export const MessagesPage = () => {
]
: []}
>
{allChannels.map(
(channel) =>
activeChat === channel.index && (
<ChannelChat
key={channel.index}
to="broadcast"
messages={messages.broadcast.get(channel.index)}
channel={channel.index}
/>
),
)}
{filteredNodes.map(
(node) =>
activeChat === node.num && (
<ChannelChat
key={node.num}
to={activeChat}
messages={messages.direct.get(node.num)}
channel={Types.ChannelNumber.Primary}
/>
),
)}
<div className="flex-1 overflow-y-auto">
{chatType === "broadcast" && currentChannel && (
<div className="flex flex-col h-full">
<div className="flex-1 overflow-y-auto">
<ChannelChat
key={currentChannel.index}
to="broadcast"
messages={messages.broadcast.get(currentChannel.index)}
channel={currentChannel.index}
/>
</div>
</div>
)}
{chatType === "direct" && node && (
<div className="flex flex-col h-full">
<div className="flex-1 overflow-y-auto">
<ChannelChat
key={node.num}
messages={messages.direct.get(node.num)} channel={ChannelNumber.Primary} to={0} />
</div>
</div>
)}
</div>
{/* Single message input for both chat types */}
<div className="shrink-0 p-4 w-full dark:bg-slate-900">
<MessageInput
to={messageDestination}
channel={messageChannel}
maxBytes={200}
/>
</div>
</PageLayout>
</div>
</>
);
};
export default MessagesPage;
export default MessagesPage;

16
src/tests/setupTests.ts

@ -1,7 +1,17 @@
import "@testing-library/jest-dom";
import { expect, afterEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import * as matchers from "@testing-library/jest-dom/matchers";
globalThis.ResizeObserver = class {
class ResizeObserver {
observe() { }
unobserve() { }
disconnect() { }
};
}
globalThis.ResizeObserver = ResizeObserver;
expect.extend(matchers);
afterEach(() => {
cleanup();
});

22
vite.config.ts

@ -1,7 +1,6 @@
import { defineConfig } from 'vite';
import { defineConfig } from "vite";
import react from '@vitejs/plugin-react';
import { VitePWA } from 'vite-plugin-pwa';
import path from 'node:path';
import { execSync } from 'node:child_process';
let hash = '';
@ -19,7 +18,7 @@ export default defineConfig({
registerType: 'autoUpdate',
strategies: 'generateSW',
devOptions: {
enabled: true
enabled: false
},
workbox: {
cleanupOutdatedCaches: true,
@ -30,27 +29,10 @@ export default defineConfig({
define: {
'import.meta.env.VITE_COMMIT_HASH': JSON.stringify(hash),
},
resolve: {
alias: {
// Using Node's path and process.cwd() instead of Deno.cwd()
'@app': path.resolve(process.cwd(), './src'),
'@pages': path.resolve(process.cwd(), './src/pages'),
'@components': path.resolve(process.cwd(), './src/components'),
'@core': path.resolve(process.cwd(), './src/core'),
'@layouts': path.resolve(process.cwd(), './src/layouts'),
},
},
server: {
port: 3000
},
optimizeDeps: {
exclude: ['react-scan']
},
test: {
environment: 'jsdom',
globals: true,
include: ['**/*.{test,spec}.{ts,tsx}'],
setupFiles: ["./src/tests/setupTests.ts"],
}
});

24
vitest.config.ts

@ -0,0 +1,24 @@
import path from "node:path";
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vitest/config'
export default defineConfig({
plugins: [
react(),
],
resolve: {
alias: {
'@app': path.resolve(process.cwd(), './src'),
'@pages': path.resolve(process.cwd(), './src/pages'),
'@components': path.resolve(process.cwd(), './src/components'),
'@core': path.resolve(process.cwd(), './src/core'),
'@layouts': path.resolve(process.cwd(), './src/layouts'),
},
},
test: {
globals: true,
include: ['src/**/*.test.tsx', 'src/**/*.test.ts'],
setupFiles: ['src/tests/setupTests.ts'],
environment: 'jsdom',
},
})
Loading…
Cancel
Save