committed by
GitHub
32 changed files with 1064 additions and 733 deletions
@ -56,7 +56,6 @@ |
|||||
"npm:react-hook-form@^7.54.2": "[email protected]", |
"npm:react-hook-form@^7.54.2": "[email protected]", |
||||
"npm:[email protected]": "[email protected][email protected][email protected][email protected]", |
"npm:[email protected]": "[email protected][email protected][email protected][email protected]", |
||||
"npm:react-qrcode-logo@3": "[email protected][email protected][email protected]", |
"npm:react-qrcode-logo@3": "[email protected][email protected][email protected]", |
||||
"npm:react-scan@~0.2.8": "[email protected][email protected][email protected][email protected]", |
|
||||
"npm:react@19": "19.0.0", |
"npm:react@19": "19.0.0", |
||||
"npm:rfc4648@^1.5.4": "1.5.4", |
"npm:rfc4648@^1.5.4": "1.5.4", |
||||
"npm:simple-git-hooks@^2.11.1": "2.11.1", |
"npm:simple-git-hooks@^2.11.1": "2.11.1", |
||||
@ -899,168 +898,78 @@ |
|||||
"tough-cookie" |
"tough-cookie" |
||||
] |
] |
||||
}, |
}, |
||||
"@clack/[email protected]": { |
|
||||
"integrity": "sha512-5cfhQNH+1VQ2xLQlmzXMqUoiaH0lRBq9/CLW9lTyMbuKLC3+xEK01tHVvyut++mLOn5urSHmkm6I0Lg9MaJSTQ==", |
|
||||
"dependencies": [ |
|
||||
"picocolors", |
|
||||
"sisteransi" |
|
||||
] |
|
||||
}, |
|
||||
"@clack/[email protected]": { |
|
||||
"integrity": "sha512-6b9Ab2UiZwJYA9iMyboYyW9yJvAO9V753ZhS+DHKEjZRKAxPPOb7MXXu84lsPFG+vZt6FRFniZ8rXi+zCIw4yQ==", |
|
||||
"dependencies": [ |
|
||||
"@clack/core", |
|
||||
"picocolors", |
|
||||
"sisteransi" |
|
||||
] |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==" |
"integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==" |
"integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==" |
"integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==" |
"integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==" |
"integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==" |
"integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==" |
"integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==" |
"integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==" |
"integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==" |
"integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==" |
"integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==" |
"integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==" |
"integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==" |
"integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==" |
"integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==" |
"integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==" |
"integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==" |
"integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==" |
"integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==" |
"integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==" |
"integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==" |
"integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==" |
"integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==" |
"integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==" |
||||
}, |
}, |
||||
"@esbuild/[email protected]": { |
|
||||
"integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==" |
|
||||
}, |
|
||||
"@esbuild/[email protected]": { |
"@esbuild/[email protected]": { |
||||
"integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==" |
"integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==" |
||||
}, |
}, |
||||
@ -1099,7 +1008,7 @@ |
|||||
"dependencies": [ |
"dependencies": [ |
||||
"@inquirer/core", |
"@inquirer/core", |
||||
"@inquirer/type", |
"@inquirer/type", |
||||
"@types/node@22.13.8" |
"@types/node" |
||||
] |
] |
||||
}, |
}, |
||||
"@inquirer/[email protected]_@[email protected]": { |
"@inquirer/[email protected]_@[email protected]": { |
||||
@ -1107,7 +1016,7 @@ |
|||||
"dependencies": [ |
"dependencies": [ |
||||
"@inquirer/figures", |
"@inquirer/figures", |
||||
"@inquirer/type", |
"@inquirer/type", |
||||
"@types/node@22.13.8", |
"@types/node", |
||||
"ansi-escapes", |
"ansi-escapes", |
||||
"cli-width", |
"cli-width", |
||||
"mute-stream", |
"mute-stream", |
||||
@ -1122,7 +1031,7 @@ |
|||||
"@inquirer/[email protected]_@[email protected]": { |
"@inquirer/[email protected]_@[email protected]": { |
||||
"integrity": "sha512-2MNFrDY8jkFYc9Il9DgLsHhMzuHnOYM1+CUYVWbzu9oT0hC7V7EcYvdCKeoll/Fcci04A+ERZ9wcc7cQ8lTkIA==", |
"integrity": "sha512-2MNFrDY8jkFYc9Il9DgLsHhMzuHnOYM1+CUYVWbzu9oT0hC7V7EcYvdCKeoll/Fcci04A+ERZ9wcc7cQ8lTkIA==", |
||||
"dependencies": [ |
"dependencies": [ |
||||
"@types/node@22.13.8" |
"@types/node" |
||||
] |
] |
||||
}, |
}, |
||||
"@isaacs/[email protected]": { |
"@isaacs/[email protected]": { |
||||
@ -1305,29 +1214,12 @@ |
|||||
"@open-draft/[email protected]": { |
"@open-draft/[email protected]": { |
||||
"integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==" |
"integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==" |
||||
}, |
}, |
||||
"@pivanov/[email protected][email protected][email protected][email protected]": { |
|
||||
"integrity": "sha512-JQ/pXeG9/Yq3UuwH2Xp4F6bSAIDGzbxT0Vrg/82tMi3Yp+Ps9AYzjSDE+zfvBRqc7J11V6MMonUrWj4+2dYgrg==", |
|
||||
"dependencies": [ |
|
||||
"react", |
|
||||
"react-dom" |
|
||||
] |
|
||||
}, |
|
||||
"@pkgjs/[email protected]": { |
"@pkgjs/[email protected]": { |
||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==" |
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==" |
||||
}, |
}, |
||||
"@polka/[email protected]": { |
"@polka/[email protected]": { |
||||
"integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==" |
"integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==" |
||||
}, |
}, |
||||
"@preact/[email protected]": { |
|
||||
"integrity": "sha512-OBvUsRZqNmjzCZXWLxkZfhcgT+Fk8DDcT/8vD6a1xhDemodyy87UJRJfASMuSD8FaAIeGgGm85ydXhm7lr4fyA==" |
|
||||
}, |
|
||||
"@preact/[email protected][email protected]": { |
|
||||
"integrity": "sha512-naxcJgUJ6BTOROJ7C3QML7KvwKwCXQJYTc5L/b0eEsdYgPB6SxwoQ1vDGcS0Q7GVjAenVq/tXrybVdFShHYZWg==", |
|
||||
"dependencies": [ |
|
||||
"@preact/signals-core", |
|
||||
"preact" |
|
||||
] |
|
||||
}, |
|
||||
"@radix-ui/[email protected]": { |
"@radix-ui/[email protected]": { |
||||
"integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==" |
"integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==" |
||||
}, |
}, |
||||
@ -3531,16 +3423,10 @@ |
|||||
"@types/pbf" |
"@types/pbf" |
||||
] |
] |
||||
}, |
}, |
||||
"@types/[email protected]": { |
|
||||
"integrity": "sha512-9RV2zST+0s3EhfrMZIhrz2bhuhBwxgkbHEwP2gtGWPjBzVQjifMzJ9exw7aDZhR1wbpj8zBrfp3bo8oJcGiUUw==", |
|
||||
"dependencies": [ |
|
||||
"[email protected]" |
|
||||
] |
|
||||
}, |
|
||||
"@types/[email protected]": { |
"@types/[email protected]": { |
||||
"integrity": "sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==", |
"integrity": "sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==", |
||||
"dependencies": [ |
"dependencies": [ |
||||
"undici-types@6.20.0" |
"undici-types" |
||||
] |
] |
||||
}, |
}, |
||||
"@types/[email protected]": { |
"@types/[email protected]": { |
||||
@ -3848,9 +3734,6 @@ |
|||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==" |
"integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==" |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-LTCos3SmOJHrag0qF91tLUZMMw6wA+i15ESRBp71pvfNlTMYcxYoJHJ/pvFhd+29Wm5vfgVxBHV7kP5OKUUipg==" |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" |
"integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" |
||||
}, |
}, |
||||
@ -4458,64 +4341,34 @@ |
|||||
"is-symbol" |
"is-symbol" |
||||
] |
] |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", |
|
||||
"dependencies": [ |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]", |
|
||||
"@esbuild/[email protected]" |
|
||||
] |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", |
"integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", |
||||
"dependencies": [ |
"dependencies": [ |
||||
"@esbuild/aix-ppc64@0.25.0", |
"@esbuild/aix-ppc64", |
||||
"@esbuild/android-arm@0.25.0", |
"@esbuild/android-arm", |
||||
"@esbuild/android-arm64@0.25.0", |
"@esbuild/android-arm64", |
||||
"@esbuild/android-x64@0.25.0", |
"@esbuild/android-x64", |
||||
"@esbuild/darwin-arm64@0.25.0", |
"@esbuild/darwin-arm64", |
||||
"@esbuild/darwin-x64@0.25.0", |
"@esbuild/darwin-x64", |
||||
"@esbuild/freebsd-arm64@0.25.0", |
"@esbuild/freebsd-arm64", |
||||
"@esbuild/freebsd-x64@0.25.0", |
"@esbuild/freebsd-x64", |
||||
"@esbuild/linux-arm@0.25.0", |
"@esbuild/linux-arm", |
||||
"@esbuild/linux-arm64@0.25.0", |
"@esbuild/linux-arm64", |
||||
"@esbuild/linux-ia32@0.25.0", |
"@esbuild/linux-ia32", |
||||
"@esbuild/linux-loong64@0.25.0", |
"@esbuild/linux-loong64", |
||||
"@esbuild/linux-mips64el@0.25.0", |
"@esbuild/linux-mips64el", |
||||
"@esbuild/linux-ppc64@0.25.0", |
"@esbuild/linux-ppc64", |
||||
"@esbuild/linux-riscv64@0.25.0", |
"@esbuild/linux-riscv64", |
||||
"@esbuild/linux-s390x@0.25.0", |
"@esbuild/linux-s390x", |
||||
"@esbuild/linux-x64@0.25.0", |
"@esbuild/linux-x64", |
||||
"@esbuild/netbsd-arm64@0.25.0", |
"@esbuild/netbsd-arm64", |
||||
"@esbuild/netbsd-x64@0.25.0", |
"@esbuild/netbsd-x64", |
||||
"@esbuild/openbsd-arm64@0.25.0", |
"@esbuild/openbsd-arm64", |
||||
"@esbuild/openbsd-x64@0.25.0", |
"@esbuild/openbsd-x64", |
||||
"@esbuild/sunos-x64@0.25.0", |
"@esbuild/sunos-x64", |
||||
"@esbuild/win32-arm64@0.25.0", |
"@esbuild/win32-arm64", |
||||
"@esbuild/win32-ia32@0.25.0", |
"@esbuild/win32-ia32", |
||||
"@esbuild/win32-x64@0.25.0" |
"@esbuild/win32-x64" |
||||
] |
] |
||||
}, |
}, |
||||
"[email protected]": { |
"[email protected]": { |
||||
@ -4701,12 +4554,6 @@ |
|||||
"get-intrinsic" |
"get-intrinsic" |
||||
] |
] |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", |
|
||||
"dependencies": [ |
|
||||
"resolve-pkg-maps" |
|
||||
] |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==" |
"integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==" |
||||
}, |
}, |
||||
@ -5139,9 +4986,6 @@ |
|||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" |
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" |
"integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" |
||||
}, |
}, |
||||
@ -5340,9 +5184,6 @@ |
|||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==" |
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==" |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==" |
"integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==" |
||||
}, |
}, |
||||
@ -5607,9 +5448,6 @@ |
|||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==" |
"integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==" |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w==" |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==" |
"integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==" |
||||
}, |
}, |
||||
@ -5777,31 +5615,6 @@ |
|||||
"use-sidecar" |
"use-sidecar" |
||||
] |
] |
||||
}, |
}, |
||||
"[email protected][email protected][email protected][email protected][email protected]": { |
|
||||
"integrity": "sha512-+6Gvu9b0UMmzV0JkigA7Y2YcjQABiNrweP9l9j8nrutN5OAYLRe4JgfwiUohPFngMD+Y6I5N0kW+okXhvVLGUw==", |
|
||||
"dependencies": [ |
|
||||
"@babel/core", |
|
||||
"@babel/generator", |
|
||||
"@babel/types", |
|
||||
"@clack/core", |
|
||||
"@clack/prompts", |
|
||||
"@pivanov/utils", |
|
||||
"@preact/signals", |
|
||||
"@rollup/[email protected][email protected]", |
|
||||
"@types/[email protected]", |
|
||||
"bippy", |
|
||||
"[email protected]", |
|
||||
"[email protected]", |
|
||||
"kleur", |
|
||||
"mri", |
|
||||
"playwright", |
|
||||
"preact", |
|
||||
"react", |
|
||||
"react-dom", |
|
||||
"tsx", |
|
||||
"unplugin" |
|
||||
] |
|
||||
}, |
|
||||
"[email protected]_@[email protected][email protected]": { |
"[email protected]_@[email protected][email protected]": { |
||||
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", |
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", |
||||
"dependencies": [ |
"dependencies": [ |
||||
@ -5912,9 +5725,6 @@ |
|||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" |
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==" |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", |
"integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", |
||||
"dependencies": [ |
"dependencies": [ |
||||
@ -6153,9 +5963,6 @@ |
|||||
"totalist" |
"totalist" |
||||
] |
] |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-hNj1/oZ7ygsfmPZ7ZfN5MUBRoGg1gtpnImuJBgLO0ljQ67DtJuiQaiYdS4lUA6s0KCwnPhGivtC/WRwIZLkHyg==" |
"integrity": "sha512-hNj1/oZ7ygsfmPZ7ZfN5MUBRoGg1gtpnImuJBgLO0ljQ67DtJuiQaiYdS4lUA6s0KCwnPhGivtC/WRwIZLkHyg==" |
||||
}, |
}, |
||||
@ -6516,14 +6323,6 @@ |
|||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-oDWuGVONxhVEBtschLf2cs/Jy8i7h1T+CpdkTNWQgdAF7DhRo2G8vMCgILKe7ojdEkLhICWgI1LYSSKaJsRgcw==" |
"integrity": "sha512-oDWuGVONxhVEBtschLf2cs/Jy8i7h1T+CpdkTNWQgdAF7DhRo2G8vMCgILKe7ojdEkLhICWgI1LYSSKaJsRgcw==" |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", |
|
||||
"dependencies": [ |
|
||||
"[email protected]", |
|
||||
"[email protected]", |
|
||||
"get-tsconfig" |
|
||||
] |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" |
"integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" |
||||
}, |
}, |
||||
@ -6601,9 +6400,6 @@ |
|||||
"which-boxed-primitive" |
"which-boxed-primitive" |
||||
] |
] |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" |
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" |
||||
}, |
}, |
||||
@ -6644,13 +6440,6 @@ |
|||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==" |
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==" |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-us4j03/499KhbGP8BU7Hrzrgseo+KdfJYWcbcajCOqsAyb8Gk0Yn2kiUIcZISYCb1JFaZfIuG3b42HmguVOKCQ==", |
|
||||
"dependencies": [ |
|
||||
"acorn", |
|
||||
"webpack-virtual-modules" |
|
||||
] |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" |
"integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" |
||||
}, |
}, |
||||
@ -6747,8 +6536,8 @@ |
|||||
"[email protected]_@[email protected]": { |
"[email protected]_@[email protected]": { |
||||
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", |
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", |
||||
"dependencies": [ |
"dependencies": [ |
||||
"@types/node@22.13.8", |
"@types/node", |
||||
"esbuild@0.25.0", |
"esbuild", |
||||
"[email protected]", |
"[email protected]", |
||||
"postcss", |
"postcss", |
||||
"[email protected]" |
"[email protected]" |
||||
@ -6757,7 +6546,7 @@ |
|||||
"[email protected]_@[email protected][email protected][email protected]__@[email protected]_@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected][email protected][email protected][email protected]_____@[email protected][email protected]_____@[email protected][email protected]____@[email protected][email protected][email protected][email protected]____@[email protected][email protected][email protected][email protected][email protected][email protected]___@[email protected][email protected]___@[email protected]__@[email protected][email protected][email protected]": { |
"[email protected]_@[email protected][email protected][email protected]__@[email protected]_@[email protected][email protected][email protected]___@[email protected][email protected]___@[email protected][email protected][email protected][email protected][email protected]_____@[email protected][email protected]_____@[email protected][email protected]____@[email protected][email protected][email protected][email protected]____@[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-dfqAsNqRGUc8hB9OVR2P0w8PZPEckti2+5rdZip0WIz9WW0MnImJ8XiR61QhqLa92EQzKP2uPkzenKOAHyEIbA==", |
"integrity": "sha512-dfqAsNqRGUc8hB9OVR2P0w8PZPEckti2+5rdZip0WIz9WW0MnImJ8XiR61QhqLa92EQzKP2uPkzenKOAHyEIbA==", |
||||
"dependencies": [ |
"dependencies": [ |
||||
"@types/node@22.13.8", |
"@types/node", |
||||
"@vitest/browser", |
"@vitest/browser", |
||||
"@vitest/expect", |
"@vitest/expect", |
||||
"@vitest/[email protected][email protected]__@[email protected]_@[email protected][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]", |
||||
@ -6799,9 +6588,6 @@ |
|||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" |
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" |
||||
}, |
}, |
||||
"[email protected]": { |
|
||||
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==" |
|
||||
}, |
|
||||
"[email protected]": { |
"[email protected]": { |
||||
"integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==" |
"integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==" |
||||
}, |
}, |
||||
@ -7151,7 +6937,6 @@ |
|||||
"npm:react-hook-form@^7.54.2", |
"npm:react-hook-form@^7.54.2", |
||||
"npm:[email protected]", |
"npm:[email protected]", |
||||
"npm:react-qrcode-logo@3", |
"npm:react-qrcode-logo@3", |
||||
"npm:react-scan@~0.2.8", |
|
||||
"npm:react@19", |
"npm:react@19", |
||||
"npm:rfc4648@^1.5.4", |
"npm:rfc4648@^1.5.4", |
||||
"npm:simple-git-hooks@^2.11.1", |
"npm:simple-git-hooks@^2.11.1", |
||||
|
|||||
@ -1,190 +0,0 @@ |
|||||
import { useAppStore } from "../../core/stores/appStore.ts"; |
|
||||
import { useDevice } from "../../core/stores/deviceStore.ts"; |
|
||||
import { |
|
||||
Accordion, |
|
||||
AccordionContent, |
|
||||
AccordionItem, |
|
||||
AccordionTrigger, |
|
||||
} from "../UI/Accordion.tsx"; |
|
||||
import { |
|
||||
Dialog, |
|
||||
DialogClose, |
|
||||
DialogContent, |
|
||||
DialogFooter, |
|
||||
DialogHeader, |
|
||||
DialogTitle, |
|
||||
} from "../UI/Dialog.tsx"; |
|
||||
import { Protobuf } from "@meshtastic/core"; |
|
||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils"; |
|
||||
import { DeviceImage } from "../generic/DeviceImage.tsx"; |
|
||||
import { TimeAgo } from "../generic/TimeAgo.tsx"; |
|
||||
import { Uptime } from "../generic/Uptime.tsx"; |
|
||||
|
|
||||
export interface NodeDetailsDialogProps { |
|
||||
open: boolean; |
|
||||
onOpenChange: (open: boolean) => void; |
|
||||
} |
|
||||
|
|
||||
export const NodeDetailsDialog = ({ |
|
||||
open, |
|
||||
onOpenChange, |
|
||||
}: NodeDetailsDialogProps) => { |
|
||||
const { nodes } = useDevice(); |
|
||||
const { nodeNumDetails } = useAppStore(); |
|
||||
const device: Protobuf.Mesh.NodeInfo = nodes.get(nodeNumDetails); |
|
||||
|
|
||||
return device |
|
||||
? ( |
|
||||
<Dialog open={open} onOpenChange={onOpenChange}> |
|
||||
<DialogContent> |
|
||||
<DialogClose /> |
|
||||
<DialogHeader> |
|
||||
<DialogTitle> |
|
||||
Node Details for {device.user?.longName ?? "UNKNOWN"} ( |
|
||||
{device.user?.shortName ?? "UNK"}) |
|
||||
</DialogTitle> |
|
||||
</DialogHeader> |
|
||||
<DialogFooter> |
|
||||
<div className="w-full"> |
|
||||
<DeviceImage |
|
||||
className="w-32 h-32 mx-auto rounded-lg border-4 border-slate-200 dark:border-slate-800" |
|
||||
deviceType={Protobuf.Mesh |
|
||||
.HardwareModel[device.user?.hwModel ?? 0]} |
|
||||
/> |
|
||||
<div className="bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3"> |
|
||||
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50"> |
|
||||
Details: |
|
||||
</p> |
|
||||
<p> |
|
||||
Hardware:{" "} |
|
||||
{Protobuf.Mesh.HardwareModel[device.user?.hwModel ?? 0]} |
|
||||
</p> |
|
||||
<p>Node Number: {device.num}</p> |
|
||||
<p>Node HEX: !{numberToHexUnpadded(device.num)}</p> |
|
||||
<p> |
|
||||
Role: {Protobuf.Config.Config_DeviceConfig_Role[ |
|
||||
device.user?.role ?? 0 |
|
||||
]} |
|
||||
</p> |
|
||||
<p> |
|
||||
Last Heard: {device.lastHeard === 0 |
|
||||
? ( |
|
||||
"Never" |
|
||||
) |
|
||||
: <TimeAgo timestamp={device.lastHeard * 1000} />} |
|
||||
</p> |
|
||||
</div> |
|
||||
|
|
||||
{device.position |
|
||||
? ( |
|
||||
<div className="mt-5 bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3"> |
|
||||
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50"> |
|
||||
Position: |
|
||||
</p> |
|
||||
{device.position.latitudeI && device.position.longitudeI |
|
||||
? ( |
|
||||
<p> |
|
||||
Coordinates:{" "} |
|
||||
<a |
|
||||
className="text-blue-500 dark:text-blue-400" |
|
||||
href={`https://www.openstreetmap.org/?mlat=${device.position.latitudeI / 1e7 |
|
||||
}&mlon=${device.position.longitudeI / 1e7 |
|
||||
}&layers=N`}
|
|
||||
target="_blank" |
|
||||
rel="noreferrer" |
|
||||
> |
|
||||
{device.position.latitudeI / 1e7},{" "} |
|
||||
{device.position.longitudeI / 1e7} |
|
||||
</a> |
|
||||
</p> |
|
||||
) |
|
||||
: null} |
|
||||
{device.position.altitude |
|
||||
? <p>Altitude: {device.position.altitude}m</p> |
|
||||
: null} |
|
||||
</div> |
|
||||
) |
|
||||
: null} |
|
||||
|
|
||||
{device.deviceMetrics |
|
||||
? ( |
|
||||
<div className="mt-5 bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3"> |
|
||||
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50"> |
|
||||
Device Metrics: |
|
||||
</p> |
|
||||
{device.deviceMetrics.airUtilTx |
|
||||
? ( |
|
||||
<p> |
|
||||
Air TX utilization:{" "} |
|
||||
{device.deviceMetrics.airUtilTx.toFixed(2)}% |
|
||||
</p> |
|
||||
) |
|
||||
: null} |
|
||||
{device.deviceMetrics.channelUtilization |
|
||||
? ( |
|
||||
<p> |
|
||||
Channel utilization:{" "} |
|
||||
{device.deviceMetrics.channelUtilization.toFixed(2)}% |
|
||||
</p> |
|
||||
) |
|
||||
: null} |
|
||||
{device.deviceMetrics.batteryLevel |
|
||||
? ( |
|
||||
<p> |
|
||||
Battery level:{" "} |
|
||||
{device.deviceMetrics.batteryLevel.toFixed(2)}% |
|
||||
</p> |
|
||||
) |
|
||||
: null} |
|
||||
{device.deviceMetrics.voltage |
|
||||
? ( |
|
||||
<p> |
|
||||
Voltage: {device.deviceMetrics.voltage.toFixed(2)}V |
|
||||
</p> |
|
||||
) |
|
||||
: null} |
|
||||
{device.deviceMetrics.uptimeSeconds |
|
||||
? ( |
|
||||
<p> |
|
||||
Uptime:{" "} |
|
||||
<Uptime |
|
||||
seconds={device.deviceMetrics.uptimeSeconds} |
|
||||
/> |
|
||||
</p> |
|
||||
) |
|
||||
: null} |
|
||||
</div> |
|
||||
) |
|
||||
: null} |
|
||||
|
|
||||
{device |
|
||||
? ( |
|
||||
<div className="mt-5 w-full max-w-[464px] bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3"> |
|
||||
<Accordion |
|
||||
className="AccordionRoot" |
|
||||
type="single" |
|
||||
collapsible |
|
||||
> |
|
||||
<AccordionItem className="AccordionItem" value="item-1"> |
|
||||
<AccordionTrigger> |
|
||||
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50"> |
|
||||
All Raw Metrics: |
|
||||
</p> |
|
||||
</AccordionTrigger> |
|
||||
<AccordionContent className="overflow-x-scroll"> |
|
||||
<pre className="text-xs w-full"> |
|
||||
{JSON.stringify(device, null, 2)} |
|
||||
</pre> |
|
||||
</AccordionContent> |
|
||||
</AccordionItem> |
|
||||
</Accordion> |
|
||||
</div> |
|
||||
) |
|
||||
: null} |
|
||||
</div> |
|
||||
</DialogFooter> |
|
||||
</DialogContent> |
|
||||
</Dialog> |
|
||||
) |
|
||||
: null; |
|
||||
}; |
|
||||
@ -0,0 +1,73 @@ |
|||||
|
import { describe, it, vi, expect, beforeEach, Mock } from "vitest"; |
||||
|
import { render, screen } from "@testing-library/react"; |
||||
|
import { NodeDetailsDialog } from "@components/Dialog/NodeDetailsDialog/NodeDetailsDialog.tsx"; |
||||
|
import { useDevice } from "@core/stores/deviceStore.ts"; |
||||
|
import { useAppStore } from "@core/stores/appStore.ts"; |
||||
|
|
||||
|
vi.mock("@core/stores/deviceStore"); |
||||
|
vi.mock("@core/stores/appStore"); |
||||
|
|
||||
|
describe("NodeDetailsDialog", () => { |
||||
|
const mockDevice = { |
||||
|
num: 1234, |
||||
|
user: { |
||||
|
longName: "Test Node", |
||||
|
shortName: "TN", |
||||
|
hwModel: 1, |
||||
|
role: 1, |
||||
|
}, |
||||
|
lastHeard: 1697500000, |
||||
|
position: { |
||||
|
latitudeI: 450000000, |
||||
|
longitudeI: -750000000, |
||||
|
altitude: 200, |
||||
|
}, |
||||
|
deviceMetrics: { |
||||
|
airUtilTx: 50.123, |
||||
|
channelUtilization: 75.456, |
||||
|
batteryLevel: 88.789, |
||||
|
voltage: 4.2, |
||||
|
uptimeSeconds: 3600, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
// Reset mocks before each test
|
||||
|
vi.resetAllMocks(); |
||||
|
|
||||
|
(useDevice as Mock).mockReturnValue({ |
||||
|
nodes: new Map([[1234, mockDevice]]), |
||||
|
}); |
||||
|
|
||||
|
(useAppStore as unknown as Mock).mockReturnValue({ |
||||
|
nodeNumDetails: 1234, |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
it("renders node details correctly", () => { |
||||
|
render(<NodeDetailsDialog open={true} onOpenChange={() => { }} />); |
||||
|
|
||||
|
expect(screen.getByText(/Node Details for Test Node/i)).toBeInTheDocument(); |
||||
|
|
||||
|
expect(screen.getByText("Node Number: 1234")).toBeInTheDocument(); |
||||
|
|
||||
|
expect(screen.getByText(/Air TX utilization: 50.12%/i)).toBeInTheDocument(); |
||||
|
expect(screen.getByText(/Channel utilization: 75.46%/i)).toBeInTheDocument(); |
||||
|
expect(screen.getByText(/Battery level: 88.79%/i)).toBeInTheDocument(); |
||||
|
expect(screen.getByText(/Voltage: 4.20V/i)).toBeInTheDocument(); |
||||
|
expect(screen.getByText(/Uptime:/i)).toBeInTheDocument(); |
||||
|
expect(screen.getByText(/Coordinates:/i)).toBeInTheDocument(); |
||||
|
expect(screen.getByText("45, -75")).toBeInTheDocument(); |
||||
|
expect(screen.getByText(/Altitude: 200m/i)).toBeInTheDocument(); |
||||
|
expect(screen.getByText(/Role:/i)).toBeInTheDocument(); |
||||
|
}); |
||||
|
|
||||
|
it("renders null if device is not found", () => { |
||||
|
(useDevice as Mock).mockReturnValue({ |
||||
|
nodes: new Map(), |
||||
|
}); |
||||
|
|
||||
|
render(<NodeDetailsDialog open={true} onOpenChange={() => { }} />); |
||||
|
expect(screen.queryByText(/Node Details for/i)).not.toBeInTheDocument(); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,177 @@ |
|||||
|
import { useAppStore } from "@core/stores/appStore.ts"; |
||||
|
import { useDevice } from "@core/stores/deviceStore.ts"; |
||||
|
import { |
||||
|
Accordion, |
||||
|
AccordionContent, |
||||
|
AccordionItem, |
||||
|
AccordionTrigger, |
||||
|
} from "@components/UI/Accordion.tsx"; |
||||
|
import { |
||||
|
Dialog, |
||||
|
DialogClose, |
||||
|
DialogContent, |
||||
|
DialogFooter, |
||||
|
DialogHeader, |
||||
|
DialogTitle, |
||||
|
} from "@components/UI/Dialog.tsx"; |
||||
|
import { Protobuf } from "@meshtastic/core"; |
||||
|
import { numberToHexUnpadded } from "@noble/curves/abstract/utils"; |
||||
|
import { DeviceImage } from "@components/generic/DeviceImage.tsx"; |
||||
|
import { TimeAgo } from "@components/generic/TimeAgo.tsx"; |
||||
|
import { Uptime } from "@components/generic/Uptime.tsx"; |
||||
|
|
||||
|
export interface NodeDetailsDialogProps { |
||||
|
open: boolean; |
||||
|
onOpenChange: (open: boolean) => void; |
||||
|
} |
||||
|
|
||||
|
export const NodeDetailsDialog = ({ |
||||
|
open, |
||||
|
onOpenChange, |
||||
|
}: NodeDetailsDialogProps) => { |
||||
|
const { nodes } = useDevice(); |
||||
|
const { nodeNumDetails } = useAppStore(); |
||||
|
|
||||
|
const device = nodes.get(nodeNumDetails); |
||||
|
|
||||
|
if (!device) return null; |
||||
|
|
||||
|
const deviceMetricsMap = [ |
||||
|
{ |
||||
|
key: "airUtilTx", |
||||
|
label: "Air TX utilization", |
||||
|
value: device.deviceMetrics?.airUtilTx, |
||||
|
format: (val: number) => `${val.toFixed(2)}%`, |
||||
|
}, |
||||
|
{ |
||||
|
key: "channelUtilization", |
||||
|
label: "Channel utilization", |
||||
|
value: device.deviceMetrics?.channelUtilization, |
||||
|
format: (val: number) => `${val.toFixed(2)}%`, |
||||
|
}, |
||||
|
{ |
||||
|
key: "batteryLevel", |
||||
|
label: "Battery level", |
||||
|
value: device.deviceMetrics?.batteryLevel, |
||||
|
format: (val: number) => `${val.toFixed(2)}%`, |
||||
|
}, |
||||
|
{ |
||||
|
key: "voltage", |
||||
|
label: "Voltage", |
||||
|
value: device.deviceMetrics?.voltage, |
||||
|
format: (val: number) => `${val.toFixed(2)}V`, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
return ( |
||||
|
<Dialog open={open} onOpenChange={onOpenChange}> |
||||
|
<DialogContent > |
||||
|
<DialogClose /> |
||||
|
<DialogHeader> |
||||
|
<DialogTitle> |
||||
|
Node Details for {device.user?.longName ?? "UNKNOWN"} ( |
||||
|
{device.user?.shortName ?? "UNK"}) |
||||
|
</DialogTitle> |
||||
|
</DialogHeader> |
||||
|
<DialogFooter> |
||||
|
<div className="w-full"> |
||||
|
<div className="flex flex-col"> |
||||
|
<DeviceImage |
||||
|
className="w-32 h-32 mx-auto rounded-lg border-4 border-slate-200 dark:border-slate-800" |
||||
|
deviceType={ |
||||
|
Protobuf.Mesh.HardwareModel[device.user?.hwModel ?? 0] |
||||
|
} |
||||
|
/> |
||||
|
<div className="bg-slate-100 text-slate-900 dark:text-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3"> |
||||
|
<p className="text-lg font-semibold">Details:</p> |
||||
|
<p> |
||||
|
Hardware:{" "} |
||||
|
{Protobuf.Mesh.HardwareModel[device.user?.hwModel ?? 0]} |
||||
|
</p> |
||||
|
<p>Node Number: {device.num}</p> |
||||
|
<p>Node Hex: !{numberToHexUnpadded(device.num)}</p> |
||||
|
<p> |
||||
|
Role:{" "} |
||||
|
{ |
||||
|
Protobuf.Config.Config_DeviceConfig_Role[ |
||||
|
device.user?.role ?? 0 |
||||
|
] |
||||
|
} |
||||
|
</p> |
||||
|
<p> |
||||
|
Last Heard:{" "} |
||||
|
{device.lastHeard === 0 ? "Never" : <TimeAgo timestamp={device.lastHeard * 1000} />} |
||||
|
</p> |
||||
|
</div> |
||||
|
|
||||
|
{device.position && ( |
||||
|
<div className="text-slate-900 dark:text-slate-100 bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3"> |
||||
|
<p className="text-lg font-semibold">Position:</p> |
||||
|
{device.position.latitudeI && device.position.longitudeI && ( |
||||
|
<p> |
||||
|
Coordinates:{" "} |
||||
|
<a |
||||
|
className="text-blue-500 dark:text-blue-400" |
||||
|
href={`https://www.openstreetmap.org/?mlat=${device.position.latitudeI / 1e7 |
||||
|
}&mlon=${device.position.longitudeI / 1e7 |
||||
|
}&layers=N`}
|
||||
|
target="_blank" |
||||
|
rel="noreferrer" |
||||
|
> |
||||
|
{device.position.latitudeI / 1e7},{" "} |
||||
|
{device.position.longitudeI / 1e7} |
||||
|
</a> |
||||
|
</p> |
||||
|
)} |
||||
|
{device.position.altitude && ( |
||||
|
<p>Altitude: {device.position.altitude}m</p> |
||||
|
)} |
||||
|
</div> |
||||
|
)} |
||||
|
|
||||
|
{device.deviceMetrics && ( |
||||
|
<div className="text-slate-900 dark:text-slate-100 bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3"> |
||||
|
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50"> |
||||
|
Device Metrics: |
||||
|
</p> |
||||
|
{deviceMetricsMap.map( |
||||
|
(metric) => |
||||
|
metric.value !== undefined && ( |
||||
|
<p key={metric.key}> |
||||
|
{metric.label}: {metric.format(metric.value)} |
||||
|
</p> |
||||
|
) |
||||
|
)} |
||||
|
{device.deviceMetrics.uptimeSeconds && ( |
||||
|
<p> |
||||
|
Uptime:{" "} |
||||
|
<Uptime seconds={device.deviceMetrics.uptimeSeconds} /> |
||||
|
</p> |
||||
|
)} |
||||
|
</div> |
||||
|
)} |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
<div className="text-slate-900 dark:text-slate-100 w-full max-w-[464px] bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3"> |
||||
|
<Accordion className="AccordionRoot" type="single" collapsible> |
||||
|
<AccordionItem className="AccordionItem" value="item-1"> |
||||
|
<AccordionTrigger> |
||||
|
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50"> |
||||
|
All Raw Metrics: |
||||
|
</p> |
||||
|
</AccordionTrigger> |
||||
|
<AccordionContent className="overflow-x-scroll"> |
||||
|
<pre className="text-xs w-full"> |
||||
|
{JSON.stringify(device, null, 2)} |
||||
|
</pre> |
||||
|
</AccordionContent> |
||||
|
</AccordionItem> |
||||
|
</Accordion> |
||||
|
</div> |
||||
|
</div> |
||||
|
</DialogFooter> |
||||
|
</DialogContent> |
||||
|
</Dialog> |
||||
|
); |
||||
|
}; |
||||
@ -0,0 +1,55 @@ |
|||||
|
import { render, screen, fireEvent } from "@testing-library/react"; |
||||
|
import { beforeEach, describe, expect, it, Mock, vi } from "vitest"; |
||||
|
import { RefreshKeysDialog } from "./RefreshKeysDialog"; |
||||
|
import { useRefreshKeysDialog } from "./useRefreshKeysDialog.ts"; |
||||
|
|
||||
|
vi.mock("./useRefreshKeysDialog.ts", () => ({ |
||||
|
useRefreshKeysDialog: vi.fn(), |
||||
|
})); |
||||
|
|
||||
|
describe("RefreshKeysDialog Component", () => { |
||||
|
let handleCloseDialogMock: Mock; |
||||
|
let handleNodeRemoveMock: Mock; |
||||
|
let onOpenChangeMock: Mock; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
handleCloseDialogMock = vi.fn(); |
||||
|
handleNodeRemoveMock = vi.fn(); |
||||
|
onOpenChangeMock = vi.fn(); |
||||
|
|
||||
|
(useRefreshKeysDialog as Mock).mockReturnValue({ |
||||
|
handleCloseDialog: handleCloseDialogMock, |
||||
|
handleNodeRemove: handleNodeRemoveMock, |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
it("renders the dialog with correct content", () => { |
||||
|
render(<RefreshKeysDialog open={true} onOpenChange={onOpenChangeMock} />); |
||||
|
expect(screen.getByText("Keys Mismatch")).toBeInTheDocument(); |
||||
|
expect(screen.getByText("Request New Keys")).toBeInTheDocument(); |
||||
|
expect(screen.getByText("Dismiss")).toBeInTheDocument(); |
||||
|
}); |
||||
|
|
||||
|
it("calls handleNodeRemove when 'Request New Keys' button is clicked", () => { |
||||
|
render(<RefreshKeysDialog open={true} onOpenChange={onOpenChangeMock} />); |
||||
|
fireEvent.click(screen.getByText("Request New Keys")); |
||||
|
expect(handleNodeRemoveMock).toHaveBeenCalled(); |
||||
|
}); |
||||
|
|
||||
|
it("calls handleCloseDialog when 'Dismiss' button is clicked", () => { |
||||
|
render(<RefreshKeysDialog open={true} onOpenChange={onOpenChangeMock} />); |
||||
|
fireEvent.click(screen.getByText("Dismiss")); |
||||
|
expect(handleCloseDialogMock).toHaveBeenCalled(); |
||||
|
}); |
||||
|
|
||||
|
it("calls onOpenChange when dialog close button is clicked", () => { |
||||
|
render(<RefreshKeysDialog open={true} onOpenChange={onOpenChangeMock} />); |
||||
|
fireEvent.click(screen.getByRole("button", { name: /close/i })); |
||||
|
expect(handleCloseDialogMock).toHaveBeenCalled(); |
||||
|
}); |
||||
|
|
||||
|
it("does not render when open is false", () => { |
||||
|
render(<RefreshKeysDialog open={false} onOpenChange={onOpenChangeMock} />); |
||||
|
expect(screen.queryByText("Keys Mismatch")).not.toBeInTheDocument(); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,61 @@ |
|||||
|
import { |
||||
|
Dialog, |
||||
|
DialogClose, |
||||
|
DialogContent, |
||||
|
DialogHeader, |
||||
|
DialogTitle, |
||||
|
} from "@components/UI/Dialog.tsx"; |
||||
|
import { Button } from "@components/UI/Button.tsx"; |
||||
|
import { LockKeyholeOpenIcon } from "lucide-react"; |
||||
|
import { useRefreshKeysDialog } from "./useRefreshKeysDialog.ts"; |
||||
|
|
||||
|
export interface RefreshKeysDialogProps { |
||||
|
open: boolean; |
||||
|
onOpenChange: (open: boolean) => void; |
||||
|
} |
||||
|
|
||||
|
export const RefreshKeysDialog = ({ open, onOpenChange }: RefreshKeysDialogProps) => { |
||||
|
|
||||
|
const { handleCloseDialog, handleNodeRemove } = useRefreshKeysDialog(); |
||||
|
return ( |
||||
|
<Dialog open={open} onOpenChange={onOpenChange}> |
||||
|
<DialogContent className="max-w-8 flex flex-col gap-2"> |
||||
|
<DialogClose onClick={handleCloseDialog} /> |
||||
|
<DialogHeader> |
||||
|
<DialogTitle>Keys Mismatch</DialogTitle> |
||||
|
</DialogHeader> |
||||
|
Your node is unable to send a direct message to this node. This is due to the remote node's current public key not matching the previously stored key for this node. |
||||
|
<ul className="mt-2"> |
||||
|
<li className="flex place-items-center gap-2 items-start"> |
||||
|
<div className="p-2 bg-slate-500 rounded-lg mt-1"> |
||||
|
<LockKeyholeOpenIcon size={30} className="text-white justify-center" /> |
||||
|
</div> |
||||
|
<div className="flex flex-col gap-2"> |
||||
|
<div> |
||||
|
<p className="font-bold mb-0.5">Accept New Keys</p> |
||||
|
<p> |
||||
|
This will remove the node from device and request new keys. |
||||
|
</p> |
||||
|
</div> |
||||
|
<Button |
||||
|
variant="default" |
||||
|
onClick={handleNodeRemove} |
||||
|
className="" |
||||
|
> |
||||
|
Request New Keys |
||||
|
</Button> |
||||
|
<Button |
||||
|
variant="outline" |
||||
|
onClick={handleCloseDialog} |
||||
|
className="" |
||||
|
> |
||||
|
Dismiss |
||||
|
</Button> |
||||
|
</div> |
||||
|
</li> |
||||
|
</ul> |
||||
|
{/* </DialogDescription> */} |
||||
|
</DialogContent> |
||||
|
</Dialog > |
||||
|
); |
||||
|
}; |
||||
@ -0,0 +1,77 @@ |
|||||
|
import { renderHook, act } from "@testing-library/react"; |
||||
|
import { useRefreshKeysDialog } from "./useRefreshKeysDialog.ts"; |
||||
|
import { beforeEach, describe, expect, it, Mock, vi } from "vitest"; |
||||
|
import { useDevice } from "@core/stores/deviceStore.ts"; |
||||
|
|
||||
|
vi.mock("@core/stores/appStore.ts", () => ({ |
||||
|
useAppStore: vi.fn(() => ({ activeChat: "chat-123" })), |
||||
|
})); |
||||
|
|
||||
|
vi.mock("@core/stores/deviceStore.ts", () => ({ |
||||
|
useDevice: vi.fn(() => ({ |
||||
|
removeNode: vi.fn(), |
||||
|
setDialogOpen: vi.fn(), |
||||
|
getNodeError: vi.fn(), |
||||
|
clearNodeError: vi.fn(), |
||||
|
})), |
||||
|
})); |
||||
|
|
||||
|
describe("useRefreshKeysDialog Hook", () => { |
||||
|
let removeNodeMock: Mock; |
||||
|
let setDialogOpenMock: Mock; |
||||
|
let getNodeErrorMock: Mock; |
||||
|
let clearNodeErrorMock: Mock; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
removeNodeMock = vi.fn(); |
||||
|
setDialogOpenMock = vi.fn(); |
||||
|
getNodeErrorMock = vi.fn(); |
||||
|
clearNodeErrorMock = vi.fn(); |
||||
|
|
||||
|
(useDevice as Mock).mockReturnValue({ |
||||
|
removeNode: removeNodeMock, |
||||
|
setDialogOpen: setDialogOpenMock, |
||||
|
getNodeError: getNodeErrorMock, |
||||
|
clearNodeError: clearNodeErrorMock, |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
it("handleNodeRemove should remove the node and update dialog if there is an error", () => { |
||||
|
getNodeErrorMock.mockReturnValue({ node: "node-abc" }); |
||||
|
|
||||
|
const { result } = renderHook(() => useRefreshKeysDialog()); |
||||
|
|
||||
|
act(() => { |
||||
|
result.current.handleNodeRemove(); |
||||
|
}); |
||||
|
|
||||
|
expect(getNodeErrorMock).toHaveBeenCalledWith("chat-123"); |
||||
|
expect(clearNodeErrorMock).toHaveBeenCalledWith("chat-123"); |
||||
|
expect(removeNodeMock).toHaveBeenCalledWith("node-abc"); |
||||
|
expect(setDialogOpenMock).toHaveBeenCalledWith("refreshKeys", false); |
||||
|
}); |
||||
|
|
||||
|
it("handleNodeRemove should do nothing if there is no error", () => { |
||||
|
getNodeErrorMock.mockReturnValue(undefined); |
||||
|
|
||||
|
const { result } = renderHook(() => useRefreshKeysDialog()); |
||||
|
|
||||
|
act(() => { |
||||
|
result.current.handleNodeRemove(); |
||||
|
}); |
||||
|
|
||||
|
expect(removeNodeMock).not.toHaveBeenCalled(); |
||||
|
expect(setDialogOpenMock).not.toHaveBeenCalled(); |
||||
|
expect(clearNodeErrorMock).not.toHaveBeenCalled(); |
||||
|
}); |
||||
|
|
||||
|
it("handleCloseDialog should close the dialog", () => { |
||||
|
const { result } = renderHook(() => useRefreshKeysDialog()); |
||||
|
|
||||
|
act(() => { |
||||
|
result.current.handleCloseDialog(); |
||||
|
}); |
||||
|
|
||||
|
expect(setDialogOpenMock).toHaveBeenCalledWith("refreshKeys", false); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,28 @@ |
|||||
|
import { useCallback } from "react"; |
||||
|
import { useAppStore } from "@core/stores/appStore.ts"; |
||||
|
import { useDevice } from "@core/stores/deviceStore.ts"; |
||||
|
|
||||
|
export function useRefreshKeysDialog() { |
||||
|
const { removeNode, setDialogOpen, clearNodeError, getNodeError } = useDevice(); |
||||
|
const { activeChat } = useAppStore(); |
||||
|
|
||||
|
const handleNodeRemove = useCallback(() => { |
||||
|
const nodeWithError = getNodeError(activeChat); |
||||
|
if (!nodeWithError) { |
||||
|
return; |
||||
|
} |
||||
|
clearNodeError(activeChat); |
||||
|
handleCloseDialog();; |
||||
|
return removeNode(nodeWithError?.node); |
||||
|
}, [activeChat, clearNodeError, setDialogOpen, removeNode]); |
||||
|
|
||||
|
const handleCloseDialog = useCallback(() => { |
||||
|
setDialogOpen('refreshKeys', false); |
||||
|
}, [setDialogOpen]) |
||||
|
|
||||
|
return { |
||||
|
handleCloseDialog, |
||||
|
handleNodeRemove |
||||
|
}; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,126 @@ |
|||||
|
import { |
||||
|
Tooltip, |
||||
|
TooltipArrow, |
||||
|
TooltipContent, |
||||
|
TooltipProvider, |
||||
|
TooltipTrigger, |
||||
|
} from "@components/UI/Tooltip.tsx"; |
||||
|
import { useDeviceStore } from "@core/stores/deviceStore.ts"; |
||||
|
import { cn } from "@core/utils/cn.ts"; |
||||
|
import { Avatar } from "@components/UI/Avatar.tsx"; |
||||
|
import { AlertCircle, CheckCircle2, CircleEllipsis } from "lucide-react"; |
||||
|
import type { LucideIcon } from "lucide-react"; |
||||
|
import { ReactNode, useMemo } from "react"; |
||||
|
import { Message, MessageState } from "@core/services/types.ts"; |
||||
|
|
||||
|
interface MessageProps { |
||||
|
lastMsgSameUser: boolean; |
||||
|
message: Message; |
||||
|
} |
||||
|
|
||||
|
interface MessageStatus { |
||||
|
state: MessageState; |
||||
|
displayText: string; |
||||
|
icon: LucideIcon; |
||||
|
} |
||||
|
|
||||
|
const MESSAGE_STATUS: Record<MessageState, MessageStatus> = { |
||||
|
ack: { state: "ack", displayText: "Message delivered", icon: CheckCircle2 }, |
||||
|
waiting: { state: "waiting", displayText: "Waiting for delivery", icon: CircleEllipsis }, |
||||
|
failed: { state: "failed", displayText: "Delivery failed", icon: AlertCircle }, |
||||
|
}; |
||||
|
|
||||
|
const getMessageStatus = (state: MessageState): MessageStatus => |
||||
|
MESSAGE_STATUS[state] || { state: "failed", displayText: "Unknown error", icon: AlertCircle }; |
||||
|
|
||||
|
const StatusTooltip = ({ status, children }: { status: MessageStatus; children: ReactNode }) => ( |
||||
|
<TooltipProvider> |
||||
|
<Tooltip> |
||||
|
<TooltipTrigger asChild>{children}</TooltipTrigger> |
||||
|
<TooltipContent |
||||
|
className="rounded-md bg-slate-800 px-3 py-1.5 text-sm text-white shadow-md animate-in fade-in-0 zoom-in-95" |
||||
|
side="top" |
||||
|
align="center" |
||||
|
sideOffset={5} |
||||
|
> |
||||
|
{status.displayText} |
||||
|
<TooltipArrow className="fill-slate-800" /> |
||||
|
</TooltipContent> |
||||
|
</Tooltip> |
||||
|
</TooltipProvider> |
||||
|
); |
||||
|
|
||||
|
const StatusIcon = ({ status, className, ...otherProps }: { status: MessageStatus; className?: string }) => { |
||||
|
const isFailed = status.state === "failed"; |
||||
|
const iconClass = cn("text-slate-500 dark:text-slate-400 w-4 h-4 shrink-0", className); |
||||
|
const Icon = status.icon; |
||||
|
|
||||
|
return ( |
||||
|
<StatusTooltip status={status}> |
||||
|
<Icon className={iconClass} {...otherProps} color={isFailed ? "red" : "currentColor"} /> |
||||
|
</StatusTooltip> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
const getMessageTextStyles = (status: MessageStatus) => { |
||||
|
const isAcknowledged = status.state === "ack"; |
||||
|
const isFailed = status.state === "failed"; |
||||
|
|
||||
|
return cn( |
||||
|
"break-words overflow-hidden", |
||||
|
isAcknowledged ? "text-slate-900 dark:text-white" : "text-slate-900 dark:text-slate-400", |
||||
|
isFailed && "text-red-500 dark:text-red-500", |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
const TimeDisplay = ({ date, className }: { date: Date; className?: string }) => ( |
||||
|
<div className={cn("flex items-center gap-2 shrink-0", className)}> |
||||
|
<span className="text-xs text-slate-500 dark:text-slate-400 font-mono">{date.toLocaleDateString()}</span> |
||||
|
<span className="text-xs text-slate-500 dark:text-slate-400 font-mono"> |
||||
|
{date.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" })} |
||||
|
</span> |
||||
|
</div> |
||||
|
); |
||||
|
|
||||
|
export const MessageItem = ({ lastMsgSameUser, message }: MessageProps) => { |
||||
|
const { getDevices } = useDeviceStore(); |
||||
|
|
||||
|
const isDeviceUser = useMemo( |
||||
|
() => |
||||
|
getDevices() |
||||
|
.map((device) => device.nodes.get(device.hardware.myNodeNum)?.num) |
||||
|
.includes(message.from), |
||||
|
[getDevices, message.from], |
||||
|
); |
||||
|
|
||||
|
const messageUser = message?.from |
||||
|
? getDevices().find((device) => device.nodes.has(message.from))?.nodes.get(message.from) |
||||
|
: null; |
||||
|
|
||||
|
const messageStatus = getMessageStatus(message.state); |
||||
|
const messageTextClass = getMessageTextStyles(messageStatus); |
||||
|
|
||||
|
return ( |
||||
|
<div className="flex flex-col w-full px-4 justify-start"> |
||||
|
<div className={cn("flex flex-col flex-wrap items-start py-1", messageTextClass, isDeviceUser && "items-end")}> |
||||
|
<div className="flex items-center gap-2 mb-2"> |
||||
|
{!lastMsgSameUser && ( |
||||
|
<div className="flex place-items-center gap-2 mb-1"> |
||||
|
<Avatar text={messageUser?.user?.shortName ?? "UNK"} /> |
||||
|
<div className="flex flex-col"> |
||||
|
<span className="font-medium text-slate-900 dark:text-white truncate"> |
||||
|
{messageUser?.user?.longName} |
||||
|
</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
)} |
||||
|
</div> |
||||
|
<TimeDisplay date={message.date} /> |
||||
|
<div className="flex place-items-center gap-2 pb-2"> |
||||
|
<div className={cn(isDeviceUser && "pl-11", messageTextClass)}>{message.message}</div> |
||||
|
<StatusIcon status={messageStatus} /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
||||
@ -0,0 +1,95 @@ |
|||||
|
import { describe, it, expect, vi, beforeEach, Mock } from "vitest"; |
||||
|
import { render, screen } from "@testing-library/react"; |
||||
|
import { TraceRoute } from "@components/PageComponents/Messages/TraceRoute.tsx"; |
||||
|
import { useDevice } from "@core/stores/deviceStore.ts"; |
||||
|
|
||||
|
vi.mock("@core/stores/deviceStore"); |
||||
|
|
||||
|
describe("TraceRoute", () => { |
||||
|
const mockNodes = new Map([ |
||||
|
[ |
||||
|
1, |
||||
|
{ num: 1, user: { longName: "Node A" } }, |
||||
|
], |
||||
|
[ |
||||
|
2, |
||||
|
{ num: 2, user: { longName: "Node B" } }, |
||||
|
], |
||||
|
[ |
||||
|
3, |
||||
|
{ num: 3, user: { longName: "Node C" } }, |
||||
|
], |
||||
|
]); |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
vi.resetAllMocks(); |
||||
|
(useDevice as Mock).mockReturnValue({ |
||||
|
nodes: mockNodes, |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
it("renders the route to destination with SNR values", () => { |
||||
|
render( |
||||
|
<TraceRoute |
||||
|
from={{ user: { longName: "Source Node" } } as any} |
||||
|
to={{ user: { longName: "Destination Node" } } as any} |
||||
|
route={[1, 2]} |
||||
|
snrTowards={[10, 20, 30]} |
||||
|
/> |
||||
|
); |
||||
|
|
||||
|
expect(screen.getByText("Route to destination:")).toBeInTheDocument(); |
||||
|
expect(screen.getByText("Destination Node")).toBeInTheDocument(); |
||||
|
|
||||
|
expect(screen.getByText("Node A")).toBeInTheDocument(); |
||||
|
expect(screen.getByText("Node B")).toBeInTheDocument(); |
||||
|
|
||||
|
expect(screen.getAllByText(/↓/)).toHaveLength(3); // startNode + 2 hops
|
||||
|
expect(screen.getByText("↓ 10dB")).toBeInTheDocument(); |
||||
|
expect(screen.getByText("↓ 20dB")).toBeInTheDocument(); |
||||
|
expect(screen.getByText("↓ 30dB")).toBeInTheDocument(); |
||||
|
expect(screen.getByText("Source Node")).toBeInTheDocument(); |
||||
|
}); |
||||
|
|
||||
|
it("renders the route back when provided", () => { |
||||
|
render( |
||||
|
<TraceRoute |
||||
|
from={{ user: { longName: "Source Node" } } as any} |
||||
|
to={{ user: { longName: "Destination Node" } } as any} |
||||
|
route={[1]} |
||||
|
snrTowards={[15, 25]} |
||||
|
routeBack={[3]} |
||||
|
snrBack={[35, 45]} |
||||
|
/> |
||||
|
); |
||||
|
|
||||
|
expect(screen.getByText("Route back:")).toBeInTheDocument(); |
||||
|
expect(screen.getByText("Node C")).toBeInTheDocument(); |
||||
|
expect(screen.getByText("↓ 35dB")).toBeInTheDocument(); |
||||
|
expect(screen.getByText("↓ 45dB")).toBeInTheDocument(); |
||||
|
}); |
||||
|
|
||||
|
it("renders '??' for missing SNR values", () => { |
||||
|
render( |
||||
|
<TraceRoute |
||||
|
from={{ user: { longName: "Source" } } as any} |
||||
|
to={{ user: { longName: "Dest" } } as any} |
||||
|
route={[1]} |
||||
|
/> |
||||
|
); |
||||
|
|
||||
|
expect(screen.getAllByText("↓ ??dB").length).toBeGreaterThan(0); |
||||
|
}); |
||||
|
|
||||
|
it("renders hop hex if node is not found", () => { |
||||
|
render( |
||||
|
<TraceRoute |
||||
|
from={{ user: { longName: "Source" } } as any} |
||||
|
to={{ user: { longName: "Dest" } } as any} |
||||
|
route={[99]} |
||||
|
/> |
||||
|
); |
||||
|
|
||||
|
expect(screen.getByText(/^!63$/)).toBeInTheDocument(); // 99 in hex
|
||||
|
}); |
||||
|
}); |
||||
Loading…
Reference in new issue