diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f322b3a..f6a7d2e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,10 +10,10 @@ importers: dependencies: '@ant-design/charts': specifier: ^2.6.1 - version: 2.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9)) + version: 2.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6))) '@astrojs/preact': specifier: ^4.1.1 - version: 4.1.1(@babel/core@7.28.0)(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(preact@10.26.9)(terser@5.43.1)(yaml@2.8.0) + version: 4.1.1(@babel/core@7.28.0)(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(preact@10.26.9)(terser@5.48.0)(yaml@2.8.0) '@astrojs/ts-plugin': specifier: ^1.10.5 version: 1.10.5 @@ -22,7 +22,7 @@ importers: version: 1.0.0(nanostores@1.0.1)(preact@10.26.9) '@playform/compress': specifier: ^0.1.9 - version: 0.1.9(@types/node@24.1.0)(jiti@1.21.7)(rollup@4.45.1)(typescript@5.8.3)(yaml@2.8.0) + version: 0.1.9(@types/node@25.9.1)(jiti@1.21.7)(rollup@4.45.1)(typescript@5.8.3)(yaml@2.8.0) '@tabler/icons-preact': specifier: ^3.34.1 version: 3.34.1(preact@10.26.9) @@ -31,13 +31,13 @@ importers: version: 1.0.10 astro: specifier: ^5.14.7 - version: 5.14.7(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.43.1)(typescript@5.8.3)(yaml@2.8.0) + version: 5.14.7(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.48.0)(typescript@5.8.3)(yaml@2.8.0) astro-compressor: specifier: ^1.0.0 version: 1.0.0 astro-min: specifier: ^1.3.1 - version: 1.3.1(astro@5.14.7(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.43.1)(typescript@5.8.3)(yaml@2.8.0)) + version: 1.3.1(astro@5.14.7(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.48.0)(typescript@5.8.3)(yaml@2.8.0)) chart.js: specifier: ^4.5.0 version: 4.5.0 @@ -59,7 +59,7 @@ importers: devDependencies: '@astrojs/tailwind': specifier: ^6.0.2 - version: 6.0.2(astro@5.14.7(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.43.1)(typescript@5.8.3)(yaml@2.8.0))(tailwindcss@3.4.17) + version: 6.0.2(astro@5.14.7(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.48.0)(typescript@5.8.3)(yaml@2.8.0))(tailwindcss@3.4.17) daisyui: specifier: ^4.12.24 version: 4.12.24(postcss@8.5.6) @@ -764,6 +764,9 @@ packages: '@jridgewell/gen-mapping@0.3.12': resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -771,6 +774,9 @@ packages: '@jridgewell/source-map@0.3.10': resolution: {integrity: sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/sourcemap-codec@1.5.4': resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} @@ -780,6 +786,9 @@ packages: '@jridgewell/trace-mapping@0.3.29': resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@kurkle/color@0.3.4': resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} @@ -1095,6 +1104,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/fontkit@2.0.8': resolution: {integrity: sha512-wN+8bYxIpJf+5oZdrdtaX04qUuWHcKxcDEgRS9Qm9ZClSHjzEn13SxUC+5eRM+4yXIeTYk8mTzLAWGF64847ew==} @@ -1125,6 +1137,9 @@ packages: '@types/node@24.1.0': resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==} + '@types/node@25.9.1': + resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==} + '@types/stylis@4.2.5': resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} @@ -1205,6 +1220,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -1218,8 +1238,8 @@ packages: peerDependencies: ajv: ^8.8.2 - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -1301,6 +1321,11 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.10.32: + resolution: {integrity: sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==} + engines: {node: '>=6.0.0'} + hasBin: true + big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -1330,6 +1355,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + bubblesets-js@2.3.4: resolution: {integrity: sha512-DyMjHmpkS2+xcFNtyN00apJYL3ESdp9fTrkDr5+9Qg/GPqFmcWgGsK1akZnttE1XFxJ/VMy4DNNGMGYtmFp1Sg==} @@ -1361,6 +1391,9 @@ packages: caniuse-lite@1.0.30001727: resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==} + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1733,6 +1766,9 @@ packages: electron-to-chromium@1.5.190: resolution: {integrity: sha512-k4McmnB2091YIsdCgkS0fMVMPOJgxl93ltFzaryXqwip1AaxeDqKCGLxkXODDA5Ab/D+tV5EL5+aTx76RvLRxw==} + electron-to-chromium@1.5.361: + resolution: {integrity: sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==} + emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -1746,8 +1782,8 @@ packages: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} - enhanced-resolve@5.18.2: - resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==} + enhanced-resolve@5.22.0: + resolution: {integrity: sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==} engines: {node: '>=10.13.0'} entities@4.5.0: @@ -1834,8 +1870,8 @@ packages: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} - fast-uri@3.0.6: - resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} fastparse@1.1.2: resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==} @@ -2165,8 +2201,8 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - loader-runner@4.3.0: - resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + loader-runner@4.3.2: + resolution: {integrity: sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==} engines: {node: '>=6.11.5'} loader-utils@2.0.4: @@ -2433,6 +2469,10 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-releases@2.0.46: + resolution: {integrity: sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==} + engines: {node: '>=18'} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -2613,9 +2653,6 @@ packages: radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - rbush@3.0.1: resolution: {integrity: sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==} @@ -2723,17 +2760,14 @@ packages: rw@1.3.3: resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} - schema-utils@4.3.2: - resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} semver@6.3.1: @@ -2745,9 +2779,6 @@ packages: engines: {node: '>=10'} hasBin: true - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - shallowequal@1.1.0: resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} @@ -2872,23 +2903,50 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - tapable@2.2.2: - resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - terser-webpack-plugin@5.3.14: - resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + terser-webpack-plugin@5.6.0: + resolution: {integrity: sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==} engines: {node: '>= 10.13.0'} peerDependencies: + '@minify-html/node': '*' '@swc/core': '*' + '@swc/css': '*' + '@swc/html': '*' + clean-css: '*' + cssnano: '*' + csso: '*' esbuild: '*' + html-minifier-terser: '*' + lightningcss: '*' + postcss: '*' uglify-js: '*' webpack: ^5.1.0 peerDependenciesMeta: + '@minify-html/node': + optional: true '@swc/core': optional: true + '@swc/css': + optional: true + '@swc/html': + optional: true + clean-css: + optional: true + cssnano: + optional: true + csso: + optional: true esbuild: optional: true + html-minifier-terser: + optional: true + lightningcss: + optional: true + postcss: + optional: true uglify-js: optional: true @@ -2897,8 +2955,8 @@ packages: engines: {node: '>=10'} hasBin: true - terser@5.43.1: - resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==} + terser@5.48.0: + resolution: {integrity: sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==} engines: {node: '>=10'} hasBin: true @@ -2975,6 +3033,9 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + undici-types@7.8.0: resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} @@ -3085,6 +3146,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + utf-8-validate@5.0.10: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} @@ -3160,15 +3227,15 @@ packages: vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} - watchpack@2.4.4: - resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - webpack-sources@3.3.3: - resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} + webpack-sources@3.5.0: + resolution: {integrity: sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==} engines: {node: '>=10.13.0'} webpack@5.99.9: @@ -3289,9 +3356,9 @@ snapshots: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - '@ant-design/charts@2.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9))': + '@ant-design/charts@2.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6)))': dependencies: - '@ant-design/graphs': 2.1.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9)) + '@ant-design/graphs': 2.1.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6))) '@ant-design/plots': 2.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) lodash: 4.17.21 react: 19.1.0 @@ -3299,12 +3366,12 @@ snapshots: transitivePeerDependencies: - workerize-loader - '@ant-design/graphs@2.1.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9))': + '@ant-design/graphs@2.1.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6)))': dependencies: '@ant-design/charts-util': 0.0.1-alpha.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@antv/g6': 5.0.49(workerize-loader@2.0.2(webpack@5.99.9)) - '@antv/g6-extension-react': 0.2.4(@antv/g6@5.0.49(workerize-loader@2.0.2(webpack@5.99.9)))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@antv/graphin': 3.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9)) + '@antv/g6': 5.0.49(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6))) + '@antv/g6-extension-react': 0.2.4(@antv/g6@5.0.49(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6))))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@antv/graphin': 3.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6))) lodash: 4.17.21 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) @@ -3501,15 +3568,15 @@ snapshots: flru: 1.0.2 pdfast: 0.2.0 - '@antv/g6-extension-react@0.2.4(@antv/g6@5.0.49(workerize-loader@2.0.2(webpack@5.99.9)))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@antv/g6-extension-react@0.2.4(@antv/g6@5.0.49(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6))))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@antv/g': 6.1.27 '@antv/g-svg': 2.0.41 - '@antv/g6': 5.0.49(workerize-loader@2.0.2(webpack@5.99.9)) + '@antv/g6': 5.0.49(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6))) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - '@antv/g6@5.0.49(workerize-loader@2.0.2(webpack@5.99.9))': + '@antv/g6@5.0.49(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6)))': dependencies: '@antv/algorithm': 0.1.26 '@antv/component': 2.1.5 @@ -3519,7 +3586,7 @@ snapshots: '@antv/g-plugin-dragndrop': 2.0.37 '@antv/graphlib': 2.0.4 '@antv/hierarchy': 0.6.14 - '@antv/layout': 1.2.14-beta.9(workerize-loader@2.0.2(webpack@5.99.9)) + '@antv/layout': 1.2.14-beta.9(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6))) '@antv/util': 3.3.11 bubblesets-js: 2.3.4 transitivePeerDependencies: @@ -3533,9 +3600,9 @@ snapshots: '@antv/g-web-animations-api': 2.1.27 '@babel/runtime': 7.27.6 - '@antv/graphin@3.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9))': + '@antv/graphin@3.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6)))': dependencies: - '@antv/g6': 5.0.49(workerize-loader@2.0.2(webpack@5.99.9)) + '@antv/g6': 5.0.49(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6))) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) transitivePeerDependencies: @@ -3547,12 +3614,12 @@ snapshots: '@antv/hierarchy@0.6.14': {} - '@antv/layout@1.2.14-beta.9(workerize-loader@2.0.2(webpack@5.99.9))': + '@antv/layout@1.2.14-beta.9(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6)))': dependencies: '@antv/event-emitter': 0.1.3 '@antv/graphlib': 2.0.4 '@antv/util': 3.3.11 - '@naoak/workerize-transferable': 0.1.0(workerize-loader@2.0.2(webpack@5.99.9)) + '@naoak/workerize-transferable': 0.1.0(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6))) comlink: 4.4.2 d3-force: 3.0.0 d3-force-3d: 3.0.6 @@ -3655,13 +3722,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/preact@4.1.1(@babel/core@7.28.0)(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(preact@10.26.9)(terser@5.43.1)(yaml@2.8.0)': + '@astrojs/preact@4.1.1(@babel/core@7.28.0)(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(preact@10.26.9)(terser@5.48.0)(yaml@2.8.0)': dependencies: - '@preact/preset-vite': 2.10.2(@babel/core@7.28.0)(preact@10.26.9)(vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0)) + '@preact/preset-vite': 2.10.2(@babel/core@7.28.0)(preact@10.26.9)(vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0)) '@preact/signals': 2.3.2(preact@10.26.9) preact: 10.26.9 preact-render-to-string: 6.6.2(preact@10.26.9) - vite: 6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0) + vite: 6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0) transitivePeerDependencies: - '@babel/core' - '@types/node' @@ -3681,9 +3748,9 @@ snapshots: dependencies: prismjs: 1.30.0 - '@astrojs/tailwind@6.0.2(astro@5.14.7(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.43.1)(typescript@5.8.3)(yaml@2.8.0))(tailwindcss@3.4.17)': + '@astrojs/tailwind@6.0.2(astro@5.14.7(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.48.0)(typescript@5.8.3)(yaml@2.8.0))(tailwindcss@3.4.17)': dependencies: - astro: 5.14.7(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.43.1)(typescript@5.8.3)(yaml@2.8.0) + astro: 5.14.7(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.48.0)(typescript@5.8.3)(yaml@2.8.0) autoprefixer: 10.4.21(postcss@8.5.6) postcss: 8.5.6 postcss-load-config: 4.0.2(postcss@8.5.6) @@ -4126,6 +4193,11 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.4 '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/source-map@0.3.10': @@ -4133,6 +4205,11 @@ snapshots: '@jridgewell/gen-mapping': 0.3.12 '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/sourcemap-codec@1.5.4': {} '@jridgewell/sourcemap-codec@1.5.5': {} @@ -4142,6 +4219,11 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@kurkle/color@0.3.4': {} '@minify-html/node-darwin-x64@0.15.0': @@ -4158,9 +4240,9 @@ snapshots: nanostores: 1.0.1 preact: 10.26.9 - '@naoak/workerize-transferable@0.1.0(workerize-loader@2.0.2(webpack@5.99.9))': + '@naoak/workerize-transferable@0.1.0(workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6)))': dependencies: - workerize-loader: 2.0.2(webpack@5.99.9) + workerize-loader: 2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6)) '@nodelib/fs.scandir@2.1.5': dependencies: @@ -4179,12 +4261,12 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@playform/compress@0.1.9(@types/node@24.1.0)(jiti@1.21.7)(rollup@4.45.1)(typescript@5.8.3)(yaml@2.8.0)': + '@playform/compress@0.1.9(@types/node@25.9.1)(jiti@1.21.7)(rollup@4.45.1)(typescript@5.8.3)(yaml@2.8.0)': dependencies: '@playform/pipe': 0.1.3 '@types/csso': 5.0.4 '@types/html-minifier-terser': 7.0.2 - astro: 5.14.7(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.39.0)(typescript@5.8.3)(yaml@2.8.0) + astro: 5.14.7(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.39.0)(typescript@5.8.3)(yaml@2.8.0) commander: 13.1.0 csso: 5.0.5 deepmerge-ts: 7.1.5 @@ -4234,18 +4316,18 @@ snapshots: deepmerge-ts: 7.1.5 fast-glob: 3.3.3 - '@preact/preset-vite@2.10.2(@babel/core@7.28.0)(preact@10.26.9)(vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0))': + '@preact/preset-vite@2.10.2(@babel/core@7.28.0)(preact@10.26.9)(vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.0) '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.0) - '@prefresh/vite': 2.4.8(preact@10.26.9)(vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0)) + '@prefresh/vite': 2.4.8(preact@10.26.9)(vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0)) '@rollup/pluginutils': 4.2.1 babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.28.0) debug: 4.4.1 picocolors: 1.1.1 - vite: 6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0) - vite-prerender-plugin: 0.5.11(vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0)) + vite: 6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0) + vite-prerender-plugin: 0.5.11(vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0)) transitivePeerDependencies: - preact - supports-color @@ -4265,7 +4347,7 @@ snapshots: '@prefresh/utils@1.2.1': {} - '@prefresh/vite@2.4.8(preact@10.26.9)(vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0))': + '@prefresh/vite@2.4.8(preact@10.26.9)(vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0))': dependencies: '@babel/core': 7.28.0 '@prefresh/babel-plugin': 0.5.2 @@ -4273,7 +4355,7 @@ snapshots: '@prefresh/utils': 1.2.1 '@rollup/pluginutils': 4.2.1 preact: 10.26.9 - vite: 6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0) + vite: 6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0) transitivePeerDependencies: - supports-color @@ -4463,15 +4545,17 @@ snapshots: '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/eslint@9.6.1': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} + '@types/fontkit@2.0.8': dependencies: '@types/node': 24.1.0 @@ -4504,6 +4588,10 @@ snapshots: dependencies: undici-types: 7.8.0 + '@types/node@25.9.1': + dependencies: + undici-types: 7.24.6 + '@types/stylis@4.2.5': {} '@types/trusted-types@2.0.7': @@ -4611,19 +4699,21 @@ snapshots: acorn@8.15.0: {} - ajv-formats@2.1.1(ajv@8.17.1): + acorn@8.16.0: {} + + ajv-formats@2.1.1(ajv@8.20.0): optionalDependencies: - ajv: 8.17.1 + ajv: 8.20.0 - ajv-keywords@5.1.0(ajv@8.17.1): + ajv-keywords@5.1.0(ajv@8.20.0): dependencies: - ajv: 8.17.1 + ajv: 8.20.0 fast-deep-equal: 3.1.3 - ajv@8.17.1: + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.0.6 + fast-uri: 3.1.2 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -4658,13 +4748,13 @@ snapshots: astro-compressor@1.0.0: {} - astro-min@1.3.1(astro@5.14.7(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.43.1)(typescript@5.8.3)(yaml@2.8.0)): + astro-min@1.3.1(astro@5.14.7(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.48.0)(typescript@5.8.3)(yaml@2.8.0)): dependencies: '@redwerkz/html-min': 0.15.1 - astro: 5.14.7(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.43.1)(typescript@5.8.3)(yaml@2.8.0) + astro: 5.14.7(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.48.0)(typescript@5.8.3)(yaml@2.8.0) svgo: 3.3.2 - astro@5.14.7(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.39.0)(typescript@5.8.3)(yaml@2.8.0): + astro@5.14.7(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.39.0)(typescript@5.8.3)(yaml@2.8.0): dependencies: '@astrojs/compiler': 2.12.2 '@astrojs/internal-helpers': 0.7.4 @@ -4720,8 +4810,8 @@ snapshots: unist-util-visit: 5.0.0 unstorage: 1.17.1 vfile: 6.0.3 - vite: 6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.39.0)(yaml@2.8.0) - vitefu: 1.1.1(vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0)) + vite: 6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.39.0)(yaml@2.8.0) + vitefu: 1.1.1(vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0)) xxhash-wasm: 1.1.0 yargs-parser: 21.1.1 yocto-spinner: 0.2.3 @@ -4765,7 +4855,7 @@ snapshots: - uploadthing - yaml - astro@5.14.7(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.43.1)(typescript@5.8.3)(yaml@2.8.0): + astro@5.14.7(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@4.45.1)(terser@5.48.0)(typescript@5.8.3)(yaml@2.8.0): dependencies: '@astrojs/compiler': 2.12.2 '@astrojs/internal-helpers': 0.7.4 @@ -4821,8 +4911,8 @@ snapshots: unist-util-visit: 5.0.0 unstorage: 1.17.1 vfile: 6.0.3 - vite: 6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0) - vitefu: 1.1.1(vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0)) + vite: 6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0) + vitefu: 1.1.1(vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0)) xxhash-wasm: 1.1.0 yargs-parser: 21.1.1 yocto-spinner: 0.2.3 @@ -4890,6 +4980,8 @@ snapshots: base64-js@1.5.1: {} + baseline-browser-mapping@2.10.32: {} + big.js@5.2.2: {} binary-extensions@2.3.0: {} @@ -4926,6 +5018,14 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.1) + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.32 + caniuse-lite: 1.0.30001793 + electron-to-chromium: 1.5.361 + node-releases: 2.0.46 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + bubblesets-js@2.3.4: {} buffer-from@1.1.2: {} @@ -4951,6 +5051,8 @@ snapshots: caniuse-lite@1.0.30001727: {} + caniuse-lite@1.0.30001793: {} + ccount@2.0.1: {} chalk@5.4.1: {} @@ -5286,6 +5388,8 @@ snapshots: electron-to-chromium@1.5.190: {} + electron-to-chromium@1.5.361: {} + emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} @@ -5294,10 +5398,10 @@ snapshots: emojis-list@3.0.0: {} - enhanced-resolve@5.18.2: + enhanced-resolve@5.22.0: dependencies: graceful-fs: 4.2.11 - tapable: 2.2.2 + tapable: 2.3.3 entities@4.5.0: {} @@ -5407,7 +5511,7 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fast-uri@3.0.6: {} + fast-uri@3.1.2: {} fastparse@1.1.2: {} @@ -5670,7 +5774,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 24.1.0 + '@types/node': 25.9.1 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -5745,7 +5849,7 @@ snapshots: lines-and-columns@1.2.4: {} - loader-runner@4.3.0: {} + loader-runner@4.3.2: {} loader-utils@2.0.4: dependencies: @@ -6188,6 +6292,8 @@ snapshots: node-releases@2.0.19: {} + node-releases@2.0.46: {} + normalize-path@3.0.0: {} normalize-range@0.1.2: {} @@ -6352,10 +6458,6 @@ snapshots: radix3@1.1.2: {} - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - rbush@3.0.1: dependencies: quickselect: 2.0.0 @@ -6526,27 +6628,21 @@ snapshots: rw@1.3.3: {} - safe-buffer@5.2.1: {} - safer-buffer@2.1.2: {} scheduler@0.26.0: {} - schema-utils@4.3.2: + schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) + ajv: 8.20.0 + ajv-formats: 2.1.1(ajv@8.20.0) + ajv-keywords: 5.1.0(ajv@8.20.0) semver@6.3.1: {} semver@7.7.2: {} - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 - shallowequal@1.1.0: {} sharp@0.33.5: @@ -6759,16 +6855,18 @@ snapshots: transitivePeerDependencies: - ts-node - tapable@2.2.2: {} + tapable@2.3.3: {} - terser-webpack-plugin@5.3.14(webpack@5.99.9): + terser-webpack-plugin@5.6.0(lightningcss@1.29.3)(postcss@8.5.6)(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6)): dependencies: - '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 - schema-utils: 4.3.2 - serialize-javascript: 6.0.2 - terser: 5.43.1 - webpack: 5.99.9 + schema-utils: 4.3.3 + terser: 5.48.0 + webpack: 5.99.9(lightningcss@1.29.3)(postcss@8.5.6) + optionalDependencies: + lightningcss: 1.29.3 + postcss: 8.5.6 terser@5.39.0: dependencies: @@ -6777,10 +6875,10 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - terser@5.43.1: + terser@5.48.0: dependencies: - '@jridgewell/source-map': 0.3.10 - acorn: 8.15.0 + '@jridgewell/source-map': 0.3.11 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -6837,6 +6935,8 @@ snapshots: undici-types@6.20.0: {} + undici-types@7.24.6: {} + undici-types@7.8.0: {} unicode-properties@1.4.1: @@ -6924,6 +7024,12 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + utf-8-validate@5.0.10: dependencies: node-gyp-build: 4.8.4 @@ -6945,7 +7051,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-prerender-plugin@0.5.11(vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0)): + vite-prerender-plugin@0.5.11(vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0)): dependencies: kolorist: 1.8.0 magic-string: 0.30.17 @@ -6953,9 +7059,9 @@ snapshots: simple-code-frame: 1.3.0 source-map: 0.7.4 stack-trace: 1.0.0-pre2 - vite: 6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0) + vite: 6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0) - vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.39.0)(yaml@2.8.0): + vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.39.0)(yaml@2.8.0): dependencies: esbuild: 0.25.8 fdir: 6.4.6(picomatch@4.0.3) @@ -6964,14 +7070,14 @@ snapshots: rollup: 4.45.1 tinyglobby: 0.2.14 optionalDependencies: - '@types/node': 24.1.0 + '@types/node': 25.9.1 fsevents: 2.3.3 jiti: 1.21.7 lightningcss: 1.29.3 terser: 5.39.0 yaml: 2.8.0 - vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0): + vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0): dependencies: esbuild: 0.25.8 fdir: 6.4.6(picomatch@4.0.3) @@ -6980,59 +7086,68 @@ snapshots: rollup: 4.45.1 tinyglobby: 0.2.14 optionalDependencies: - '@types/node': 24.1.0 + '@types/node': 25.9.1 fsevents: 2.3.3 jiti: 1.21.7 lightningcss: 1.29.3 - terser: 5.43.1 + terser: 5.48.0 yaml: 2.8.0 - vitefu@1.1.1(vite@6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0)): + vitefu@1.1.1(vite@6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0)): optionalDependencies: - vite: 6.4.1(@types/node@24.1.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.43.1)(yaml@2.8.0) + vite: 6.4.1(@types/node@25.9.1)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.48.0)(yaml@2.8.0) vscode-languageserver-textdocument@1.0.12: {} vscode-uri@3.1.0: {} - watchpack@2.4.4: + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 web-namespaces@2.0.1: {} - webpack-sources@3.3.3: {} + webpack-sources@3.5.0: {} - webpack@5.99.9: + webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6): dependencies: '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - browserslist: 4.25.1 + acorn: 8.16.0 + browserslist: 4.28.2 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.2 + enhanced-resolve: 5.22.0 es-module-lexer: 1.7.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 + loader-runner: 4.3.2 mime-types: 2.1.35 neo-async: 2.6.2 - schema-utils: 4.3.2 - tapable: 2.2.2 - terser-webpack-plugin: 5.3.14(webpack@5.99.9) - watchpack: 2.4.4 - webpack-sources: 3.3.3 + schema-utils: 4.3.3 + tapable: 2.3.3 + terser-webpack-plugin: 5.6.0(lightningcss@1.29.3)(postcss@8.5.6)(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6)) + watchpack: 2.5.1 + webpack-sources: 3.5.0 transitivePeerDependencies: + - '@minify-html/node' - '@swc/core' + - '@swc/css' + - '@swc/html' + - clean-css + - cssnano + - csso - esbuild + - html-minifier-terser + - lightningcss + - postcss - uglify-js websocket@1.0.35: @@ -7056,10 +7171,10 @@ snapshots: dependencies: string-width: 7.2.0 - workerize-loader@2.0.2(webpack@5.99.9): + workerize-loader@2.0.2(webpack@5.99.9(lightningcss@1.29.3)(postcss@8.5.6)): dependencies: loader-utils: 2.0.4 - webpack: 5.99.9 + webpack: 5.99.9(lightningcss@1.29.3)(postcss@8.5.6) wrap-ansi@7.0.0: dependencies: diff --git a/src/components/AccessPointConfigModal.astro b/src/components/AccessPointConfigModal.astro new file mode 100644 index 0000000..91dc15f --- /dev/null +++ b/src/components/AccessPointConfigModal.astro @@ -0,0 +1,209 @@ +--- +import IconEye from "../icons/IconEye.astro"; +import IconEyeClosed from "../icons/IconEyeClosed.astro"; +--- + + + + + + diff --git a/src/components/AppProviderStore.tsx b/src/components/AppProviderStore.tsx index 3c267ed..574b4b0 100644 --- a/src/components/AppProviderStore.tsx +++ b/src/components/AppProviderStore.tsx @@ -1,689 +1,13 @@ -import { atom } from 'nanostores'; -import pkg from "websocket"; -const { w3cwebsocket } = pkg; +import { atom } from "nanostores"; -// Update Status Enum - matches backend enum in update_notifier.h -export enum UpdateStatus { - ERROR = -1, - STARTED = 0, - IN_PROGRESS = 1, - SUCCESS = 2, - NO_UPDATE = 3 -} - -export const $websocket = atom(null); -export const $activePage = atom('dashboard'); -export const $freeInternalHeap = atom(375 * 1024); -export const $totalInternalHeap = atom(375 * 1024); // ESP32-P4 has 375KB internal heap (heap_caps_get_info mit MALLOC_CAP_INTERNAL) -export const $modulationInput = atom(0); -export const $inputVoltage = atom(0); -export const $driverTemp = atom(0); -export const $counter = atom(0); -export const $ref = atom(0); -export const $dcdcState = atom(0); -export const $dcdc_errorStatus = atom('--'); -export const $idCountDashboard = atom(2); -export const $wsConnectionStatus = atom('Disconnected'); -export const $modulationInputMethod = atom('--'); -export const $gpioState = atom<{ [key: number]: boolean }>({ - 4: false, - 5: false, - 6: false, - 7: false, - 8: false, - 9: false, -}); -export const $validGpioKeys = atom([4, 5, 6, 7, 8, 9]); -/* DCDC */ -export const $dcdc_state = atom(0); -export const $dcdc_state_string = atom('--'); -export const $dcdc_state_desc_string = atom('--'); -export const $dcdc_error_flag = atom(0); -export const $POWERGOOD = atom(0); -export const $POWERGOOD_string = atom('--'); -export const $ref_value = atom(0); -/* LASER */ -export const $laser_state = atom(2); // LASER_STOP -export const $laser_state_string = atom('--'); -export const $laser_state_desc_string = atom('--'); -export const $is_REF_calibrated = atom(0); -export const $has_duty_lookup_table = atom(0); -export const $laser_error_flag = atom(0); -export const $laser_error_flag_string = atom('--'); -export const $LASERGOOD = atom(0); -export const $LASERGOOD_string = atom('--'); -export const $laser_set_temp = atom(0); -export const $laser_max_temp = atom(0); -export const $interlock = atom(0); -export const $set_current = atom(0); -export const $max_current = atom(0); -export const $threshold_current = atom(0); -export const $current_reading = atom(0); -export const $current_reading_string = atom('--'); -export const $laser_temp = atom(0); -export const $laser_temp_string = atom('--'); - -/* TEMPERATURE CHART DATA */ -export const $temperature_chart_data = atom<{ - timestamps: string[]; - driverTemps: number[]; - laserTemps: number[]; -}>({ - timestamps: [], - driverTemps: [], - laserTemps: [] -}); - -/* DRIVER */ -export const $driver_temp = atom(0); -export const $driver_temp_string = atom('--'); -export const $driver_max_temp = atom(0); -export const $driver_max_temp_string = atom('--'); -export const $vcc_voltage = atom(0); -export const $vcc_voltage_string = atom('--'); -export const $pd_voltage = atom(0); -export const $pd_voltage_string = atom('--'); -/* CALIBRATION TABLE */ -export const $calibration_table_data = atom<{ - values: number[]; - min_duty: number; - max_duty: number; - points_count: number; -}> - ({ - values: [], - min_duty: 0, - max_duty: 0, - points_count: 0, - }); - -/* UPDATE SYSTEM */ -export interface UpdateInfo { - core: string; - currentVersion: string; - newVersion: string; - icon: string; - hasProgressBar: boolean; - updateAvailable: boolean; -} - -// Neue Status-Definitionen -export enum TargetUpdateStatus { - WAITING = 'waiting', - IN_PROGRESS = 'in_progress', - COMPLETED = 'completed', - ERROR = 'error', - NO_UPDATE = 'no_update' -} - -export enum TotalUpdateStatus { - INITIAL = 'initial', - STARTED = 'started', - UPDATING = 'updating', - SUCCESS = 'success', - ERROR = 'error', - RESTARTING = 'restarting' -} - -export const $availableUpdates = atom([]); -export const $updateChangelog = atom(''); -export const $updateInProgress = atom(false); - -// Separate progress stores for each update type -// [progress, status] where status uses UpdateStatus enum -export const $p4FirmwareProgress = atom<[number, TargetUpdateStatus]>([0, TargetUpdateStatus.NO_UPDATE]); // [progress, TargetUpdateStatus] -export const $p4WebinterfaceProgress = atom<[number, TargetUpdateStatus]>([0, TargetUpdateStatus.NO_UPDATE]); // [progress, TargetUpdateStatus] -export const $stm32FirmwareProgress = atom<[number, TargetUpdateStatus]>([0, TargetUpdateStatus.NO_UPDATE]); // [progress, TargetUpdateStatus] -export const $c6FirmwareProgress = atom<[number, TargetUpdateStatus]>([0, TargetUpdateStatus.NO_UPDATE]); // [progress, TargetUpdateStatus] - -// Neuer Store fΓΌr den Gesamt-Update-Status -export const $totalUpdateStatus = atom(TotalUpdateStatus.INITIAL); - -export const $currentUpdateTargetIndex = atom(0); -export const $updateErrorMessages = atom<{ [key: number]: string }>({}); -export const $updatedTargets = atom([false, false, false, false]); - -// Add update state to global store -export const $updateState = atom<'initial' | 'updating' | 'success' | 'error' | 'reloading' | 'restarting'>('initial'); -// Global modal state -export const $isUpdaterModalOpen = atom(false); -export const $isSuccessPopupOpen = atom(false); -export const $isErrorPopupOpen = atom(false); - -export const getDcdcStateString = (state: number): string => { - switch (state) { - case 0: return "IDLE"; - case 1: return "INIT"; - case 2: return "START"; - case 3: return "RUN"; - case 4: return "STOP"; - case 5: return "ERROR"; - default: return "UNKNOWN"; - } -}; - -export const getDcdcStateDescString = (state: number): string => { - - switch (state) { - case 0: return "DCDC is idle"; - case 1: return "Initializing Voltage ramping"; - case 2: return "Ramping to target voltage"; - case 3: return "DCDC is running"; - case 4: return "DCDC is stopped"; - case 5: return "DCDC is in error state"; // TODO: add error description - default: return "UNKNOWN"; - } -}; - -export const getLaserStateString = (state: number): string => { - switch (state) { - case 0: return "INTERNAL MODULATION"; - case 1: return "EXTERNAL MODULATION"; - case 2: return "STOP"; - case 3: return "ERROR"; - case 4: return "REF CALIBRATION"; - case 5: return "LASER CALIBRATION"; - default: return "UNKNOWN"; - } -}; - -export const getLaserStateDescString = (state: number): string => { - switch (state) { - case 0: return "Internal laser modulation running"; - case 1: return "External laser modulation running"; - case 2: return "Laser stopped"; - case 3: return "Laser in error state"; // TODO: add error description - case 4: return "Calibrating REF valie"; - case 5: return "Calibrating laser"; - default: return "Unknown laser state"; - } -}; - -const setDCDCState = (state: number) => { - $dcdc_state.set(state); - $dcdc_state_string.set(getDcdcStateString(state)); - $dcdc_state_desc_string.set(getDcdcStateDescString(state)); -} - -const setLaserState = (state: number) => { - $laser_state.set(state); - $laser_state_string.set(getLaserStateString(state)); - $laser_state_desc_string.set(getLaserStateDescString(state)); -} - -const setPOWERGOOD = (state: number) => { - $POWERGOOD.set(state); - $POWERGOOD_string.set(state ? "Yes" : "No"); -} - -const setLASERGOOD = (state: number) => { - $LASERGOOD.set(state); - $LASERGOOD_string.set(state ? "Yes" : "No"); -} - - -const setDcdcErrorStatus = (state: number) => { - $dcdc_error_flag.set(state); - $dcdc_errorStatus.set(state ? "Error" : "No Errors"); -} -const setLaserErrorStatus = (state: number) => { - $laser_error_flag.set(state); - $laser_error_flag_string.set(state ? "Error" : "No Errors"); -} - -const setREF_value = (state: number) => { - $ref_value.set(state); -} - -const setModulationInputMethod = (state: number) => { - $modulationInputMethod.set(state === 0 ? "INTERNAL MODULATION" : state === 1 ? "EXTERNAL MODULATION" : "---"); -} - -const setREF_calibrated = (state: number) => { - $is_REF_calibrated.set(state); -} -const setHAS_DUTY_LOOKUP_TABLE = (state: number) => { - $has_duty_lookup_table.set(state); -} - -const setLaserSetTemp = (state: number) => { - $laser_set_temp.set(state); -} -const setLaserMaxTemp = (state: number) => { - $laser_max_temp.set(state); -} -const setInterlock = (state: number) => { - $interlock.set(state); -} - -const setModulationInput = (state: number) => { - $modulationInput.set(state); -} -const setSetCurrent = (state: number) => { - $set_current.set(state); -} -const setMaxCurrent = (state: number) => { - $max_current.set(state); -} - -const setThresholdCurrent = (state: number) => { - $threshold_current.set(state); -} -const setCurrentReading = (state: number) => { - $current_reading.set(state); - $current_reading_string.set(state + " mA"); -} -const setLaserTemp = (state: number) => { - $laser_temp.set(state); - $laser_temp_string.set(state + " Β°C"); -} - -const setDriverTemp = (state: number) => { - $driver_temp.set(state); - $driver_temp_string.set(state + " Β°C"); -} -const setDriverMaxTemp = (state: number) => { - $driver_max_temp.set(state); - $driver_max_temp_string.set(state + " Β°C"); -} - -// Temperature chart data management -const maxTemperatureDataPoints = 300; // 5 minutes worth of data at 1 second intervals - -export const addTemperatureDataPoint = (driverTemp: number, laserTemp: number) => { - const currentData = $temperature_chart_data.get(); - const now = new Date(); - const timeString = now.toLocaleTimeString(); - - const newData = { - timestamps: [...currentData.timestamps, timeString], - driverTemps: [...currentData.driverTemps, driverTemp], - laserTemps: [...currentData.laserTemps, laserTemp] - }; - - // Remove old data points to maintain 5-minute window - if (newData.timestamps.length > maxTemperatureDataPoints) { - newData.timestamps = newData.timestamps.slice(-maxTemperatureDataPoints); - newData.driverTemps = newData.driverTemps.slice(-maxTemperatureDataPoints); - newData.laserTemps = newData.laserTemps.slice(-maxTemperatureDataPoints); - } - - $temperature_chart_data.set(newData); -} - -export const clearTemperatureData = () => { - $temperature_chart_data.set({ - timestamps: [], - driverTemps: [], - laserTemps: [] - }); -} -const setVccVoltage = (state: number) => { - $vcc_voltage.set(state); - $vcc_voltage_string.set(state + " V"); -} -const setPdVoltage = (state: number) => { - $pd_voltage.set(state); - $pd_voltage_string.set(state + " V"); -} - -const setCalibrationTableData = (values: number[], min_duty: number, max_duty: number, points_count: number) => { - $calibration_table_data.set({ - values: values, - min_duty: min_duty, - max_duty: max_duty, - points_count: points_count - }); -} - -const setAvailableUpdates = (updates: UpdateInfo[]) => { - $availableUpdates.set(updates); -} -const setUpdateChangelog = (changelog: string) => { - $updateChangelog.set(changelog); -} -const setUpdateInProgress = (inProgress: boolean) => { - $updateInProgress.set(inProgress); -} - -const setP4FirmwareProgress = (progress: number, status: TargetUpdateStatus = TargetUpdateStatus.NO_UPDATE) => { - $p4FirmwareProgress.set([progress, status]); -} - -const setP4WebinterfaceProgress = (progress: number, status: TargetUpdateStatus = TargetUpdateStatus.NO_UPDATE) => { - $p4WebinterfaceProgress.set([progress, status]); -} - -const setStm32FirmwareProgress = (progress: number, status: TargetUpdateStatus = TargetUpdateStatus.NO_UPDATE) => { - $stm32FirmwareProgress.set([progress, status]); -} - -const setC6FirmwareProgress = (progress: number, status: TargetUpdateStatus = TargetUpdateStatus.NO_UPDATE) => { - $c6FirmwareProgress.set([progress, status]); -} - -const setTotalUpdateStatus = (status: TotalUpdateStatus) => { - console.log(`🎯 Total update status change: ${$totalUpdateStatus.get()} β†’ ${status}`); - $totalUpdateStatus.set(status); -} - -const startUpdate = () => { - console.log(`πŸš€ Starting update process`); - setTotalUpdateStatus(TotalUpdateStatus.STARTED); -} - -const setCurrentUpdateTargetIndex = (index: number) => { - $currentUpdateTargetIndex.set(index); -} - -const setUpdateErrorMessages = (errorMessages: { [key: number]: string }) => { - $updateErrorMessages.set(errorMessages); -} - -const setUpdateState = (state: 'initial' | 'updating' | 'success' | 'error' | 'restarting') => { - console.log(`🎯 State change: ${$updateState.get()} β†’ ${state}`); - $updateState.set(state); - - // Synchronize with total update status - switch (state) { - case 'initial': - setTotalUpdateStatus(TotalUpdateStatus.INITIAL); - break; - case 'updating': - setTotalUpdateStatus(TotalUpdateStatus.UPDATING); - break; - case 'success': - setTotalUpdateStatus(TotalUpdateStatus.SUCCESS); - break; - case 'error': - setTotalUpdateStatus(TotalUpdateStatus.ERROR); - break; - - case 'restarting': - setTotalUpdateStatus(TotalUpdateStatus.UPDATING); - break; - } -} - -const setUpdaterModalOpen = (open: boolean) => { - console.log(`πŸš€ Setting updater modal: ${open ? 'OPEN' : 'CLOSED'}`); - $isUpdaterModalOpen.set(open); -} -// reset all states to offiline states, when websocket is disconnected -const setWebSocketConnectionStatus = (status: string) => { - $wsConnectionStatus.set(status); - // set states to offline states! But do not reset calibration table/update states etc. - if (status === "Disconnected") { - $modulationInput.set(0); - $inputVoltage.set(0); - $driverTemp.set(0); - $counter.set(0); - $ref.set(0); - $dcdcState.set(0); - $dcdc_errorStatus.set('--'); - $modulationInputMethod.set('--'); - $gpioState.set({ - 4: false, - 5: false, - 6: false, - 7: false, - 8: false, - 9: false, - }); - /* DCDC */ - $dcdc_state.set(0); - $dcdc_state_string.set('--'); - $dcdc_state_desc_string.set('--'); - $dcdc_error_flag.set(0); - $POWERGOOD.set(0); - $POWERGOOD_string.set('--'); - $ref_value.set(0); - /* LASER */ - $laser_state.set(2); // LASER_STOP - $laser_state_string.set('--'); - $laser_state_desc_string.set('--'); - $is_REF_calibrated.set(0); - $has_duty_lookup_table.set(0); - $laser_error_flag.set(0); - $laser_error_flag_string.set('--'); - $LASERGOOD.set(0); - $LASERGOOD_string.set('--'); - $laser_set_temp.set(0); - $laser_max_temp.set(0); - $interlock.set(0); - $set_current.set(0); - $max_current.set(0); - $threshold_current.set(0); - $current_reading.set(0); - $current_reading_string.set('--'); - $laser_temp.set(0); - $laser_temp_string.set('--'); - /* TEMPERATURE CHART DATA */ - clearTemperatureData(); - /* DRIVER */ - $driver_temp.set(0); - $driver_temp_string.set('--'); - $driver_max_temp.set(0); - $driver_max_temp_string.set('--'); - $vcc_voltage.set(0); - $vcc_voltage_string.set('--'); - $pd_voltage.set(0); - $pd_voltage_string.set('--'); - } -} - -const resetUpdateStatus = () => { - console.log("Resetting update status"); - $updateState.set('initial'); - $updateInProgress.set(false); - $updateErrorMessages.set({}); - $currentUpdateTargetIndex.set(0); - $p4FirmwareProgress.set([0, TargetUpdateStatus.NO_UPDATE]); - $p4WebinterfaceProgress.set([0, TargetUpdateStatus.NO_UPDATE]); - $stm32FirmwareProgress.set([0, TargetUpdateStatus.NO_UPDATE]); - $c6FirmwareProgress.set([0, TargetUpdateStatus.NO_UPDATE]); - $availableUpdates.set([]); - $updateChangelog.set(''); - $updatedTargets.set([false, false, false, false]); -} - -const setErrorPopupOpen = (isOpen: boolean) => { - console.log(`❌ Setting error popup: ${isOpen ? 'OPEN' : 'CLOSED'}`); - $isErrorPopupOpen.set(isOpen); -} - -const setSuccessPopupOpen = (isOpen: boolean) => { - console.log(`πŸŽ‰ Setting success popup: ${isOpen ? 'OPEN' : 'CLOSED'}`); - $isSuccessPopupOpen.set(isOpen); -} - -const setFreeInternalHeap = (heap: number) => { - $freeInternalHeap.set(heap); -} - -const setUpdatedTargets = (targets: boolean[]) => { - console.log("🎯 Setting updated targets:", targets); - $updatedTargets.set(targets); -} +// WebSocket connection state β€” set by WebSocketProvider on open/close/error. +// Consumers can subscribe to react to connectivity (e.g. show a toast, gate UI actions). +export const $wsConnectionStatus = atom("Disconnected"); +// Centralised mutators so WebSocketProvider doesn't need to know about every atom. +// More setters can be added here as the app gains state beyond the WiFi config UI. export const stateSetters = { - setWebSocketConnectionStatus, - setDCDCState, - setLaserState, - setPOWERGOOD, - setLASERGOOD, - setDcdcErrorStatus, - setLaserErrorStatus, - setREF_value, - setModulationInputMethod, - setREF_calibrated, - setHAS_DUTY_LOOKUP_TABLE, - setLaserSetTemp, - setLaserMaxTemp, - setInterlock, - setModulationInput, - setSetCurrent, - setMaxCurrent, - setThresholdCurrent, - setCurrentReading, - setLaserTemp, - setDriverTemp, - setDriverMaxTemp, - setVccVoltage, - setPdVoltage, - setCalibrationTableData, - setAvailableUpdates, - setUpdateChangelog, - setUpdateInProgress, - setP4FirmwareProgress, - setP4WebinterfaceProgress, - setStm32FirmwareProgress, - setC6FirmwareProgress, - setTotalUpdateStatus, - startUpdate, - setCurrentUpdateTargetIndex, - setUpdateErrorMessages, - setUpdateState, - setUpdaterModalOpen, - setSuccessPopupOpen, - setErrorPopupOpen, - resetUpdateStatus, - setFreeInternalHeap, - setUpdatedTargets + setWebSocketConnectionStatus: (status: string) => { + $wsConnectionStatus.set(status); + }, }; - -const send_uart_cmd_without_data = (command: number) => { - if ($websocket.get() !== null && $websocket.get()?.readyState === $websocket.get()?.OPEN) { - const buffer = new Uint8Array([0xAB, command]); - $websocket.get()?.send(buffer); - } else { - console.error("WebSocket ist nicht verbunden"); - } -}; - -const send_uart_cmd_with_data = (command: number, data: number) => { - if ($websocket.get() !== null && $websocket.get()?.readyState === $websocket.get()?.OPEN) { - const buffer = new Uint8Array(6); - buffer[0] = 0xAA; - buffer[1] = command; - buffer[2] = (data >> 24) & 0xFF; - buffer[3] = (data >> 16) & 0xFF; - buffer[4] = (data >> 8) & 0xFF; - buffer[5] = data & 0xFF; - $websocket.get()?.send(buffer); - } -}; - -const send_network_cmd = (command: number) => { - if ($websocket.get() !== null && $websocket.get()?.readyState === $websocket.get()?.OPEN) { - const buffer = new Uint8Array([0xBA, command]); - $websocket.get()?.send(buffer); - } else { - console.error("WebSocket ist nicht verbunden"); - } -}; - -const send_firmware_update_cmd = (command: number) => { - if ($websocket.get() !== null && $websocket.get()?.readyState === $websocket.get()?.OPEN) { - const buffer = new Uint8Array([0xBB, command]); - $websocket.get()?.send(buffer); - } else { - console.error("WebSocket ist nicht verbunden"); - } -} - -export const start_DCDC = () => { - send_uart_cmd_without_data(0x00); -} - -export const stop_DCDC = () => { - send_uart_cmd_without_data(0x01); -} - -export const reset_DCDC = () => { - send_uart_cmd_without_data(0x02); -} - -export const run_Laser_External = () => { - send_uart_cmd_without_data(0x03); -} - -export const run_Laser_Internal = () => { - send_uart_cmd_without_data(0x04); -} - -export const stop_Laser = () => { - send_uart_cmd_without_data(0x05); -} - -export const reset_Laser = () => { - send_uart_cmd_without_data(0x06); -} - -export const start_REF_Calibration = () => { - send_uart_cmd_without_data(0x07); -} - -export const start_Laser_Calibration = () => { - send_uart_cmd_without_data(0x08); -} - -export const set_Laser_Threshold = (threshold: number) => { - send_uart_cmd_with_data(0x09, threshold); -} - -export const set_Laser_MAX_Current = (current: number) => { - send_uart_cmd_with_data(0x0A, current); -} - -export const set_Laser_Set_Current = (current: number) => { - send_uart_cmd_with_data(0x0B, current); -} - -export const set_Laser_Set_Temp = (temp: number) => { - send_uart_cmd_with_data(0x0C, temp); -} -export const set_Laser_Max_Temp = (temp: number) => { - send_uart_cmd_with_data(0x0D, temp); -} -export const set_Driver_Max_Temp = (temp: number) => { - send_uart_cmd_with_data(0x0E, temp); -} -export const get_calibration_table = () => { - console.log("Getting calibration table"); - send_uart_cmd_without_data(0x0F); -} -export const set_REF_value = (value: number) => { - send_uart_cmd_with_data(0x10, value); -} -export const set_Overcurrent_Protection_Value = (value: number) => { - send_uart_cmd_with_data(0x11, value); -} - -// UPDATE SYSTEM COMMANDS -export const request_available_updates = () => { - console.log("Requesting available updates"); - send_firmware_update_cmd(0x00); -} - - -export const start_firmware_update_p4_fw = () => { - console.log("Starting P4 Firmware update"); - send_firmware_update_cmd(0x02); -} -export const start_firmware_update_p4_web = () => { - console.log("Starting P4 Webinterface update"); - send_firmware_update_cmd(0x03); -} -export const start_firmware_update_stm32_fw = () => { - console.log("Starting STM32 Firmware update"); - send_firmware_update_cmd(0x04); -} -export const start_firmware_update_c6_fw = () => { - console.log("Starting C6 Firmware update"); - send_firmware_update_cmd(0x05); -} -export const request_update_progress = () => { - console.log("Requesting update progress"); - -} \ No newline at end of file diff --git a/src/components/ConnectionStatusBadge.tsx b/src/components/ConnectionStatusBadge.tsx deleted file mode 100644 index b3fc514..0000000 --- a/src/components/ConnectionStatusBadge.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useStore } from '@nanostores/preact'; -import { $wsConnectionStatus } from './AppProviderStore'; - -export default function ConnectionStatusBadge() { - const status = useStore($wsConnectionStatus); - - let colorClass = 'bg-gray-400 text-white'; - if (status.startsWith('Connected')) colorClass = 'bg-green-500 text-white'; - else if (status.startsWith('Connecting')) colorClass = 'bg-yellow-400 text-black'; - else if ( - status.startsWith('Error') || - status.startsWith('Failed') || - status.startsWith('Disconnected') - ) - colorClass = 'bg-red-500 text-white'; - - // Passe die Breite ggf. an den lΓ€ngsten Status an! - const maxText = 'Connecting ...'; - - return ( - - {/* Unsichtbarer Platzhalter fΓΌr feste Breite und Position */} - - {maxText} - - {/* Sichtbarer Status absolut darΓΌber */} - - {status} - - - ); -} \ No newline at end of file diff --git a/src/components/ControlPage.astro b/src/components/ControlPage.astro deleted file mode 100644 index c6da9c2..0000000 --- a/src/components/ControlPage.astro +++ /dev/null @@ -1,234 +0,0 @@ ---- -const pageTitle = "Laser Control"; ---- - -
-

{pageTitle}

- - -
- -
-
-

DCDC Control

- - -
- - - - -
- -
- -
- - -
- 10V - 20V - 30V - 40V - 50V -
-
- -
-
- Input Voltage: 24.5V -
-
- PD: 3.2V -
-
- -
- - -
-
-
- - -
-
-

Laser Control

- -
- - - - -
- -
- -
- Interlock Status: -
- - - - Unlocked -
-
- -
- - -
- -
- -
- - - -
-
- -
- - - - The laser mode is dependent on the DCDC status and safety settings. -
-
-
-
- - -
-
-

Safety Settings

- - -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - - - Disabling safety features may damage your hardware or create hazardous conditions. -
-
-
-
-
- - diff --git a/src/components/DashboardPage.astro b/src/components/DashboardPage.astro deleted file mode 100644 index 315c0de..0000000 --- a/src/components/DashboardPage.astro +++ /dev/null @@ -1,549 +0,0 @@ ---- -import { - $wsConnectionStatus, - $dcdc_state_string, - $dcdc_state_desc_string, - $laser_state_string, - $laser_state_desc_string, - $laser_temp, - $laser_temp_string, - $driver_temp, - $driver_temp_string, - $driver_max_temp, - $driver_max_temp_string, - $temperature_chart_data, - addTemperatureDataPoint, -} from "./AppProviderStore"; -const pageTitle = "Dashboard"; ---- - -
-

{pageTitle}

- - -
-
-
-
DCDC State
-
- {$dcdc_state_string.get()} -
-
- ● - {$dcdc_state_desc_string.get()} -
-
-
- -
-
-
Laser State
-
- {$laser_state_string.get()} -
-
- ● - {$laser_state_desc_string.get()} -
-
-
- -
-
-
Driver Temperature
-
{$driver_temp_string.get()}
-
- ● - Maximal allowed: {$driver_max_temp_string.get()} -
-
-
- -
-
-
WebSocket
-
- {$wsConnectionStatus.get()} -
-
- ● - Connection status -
-
-
-
- - -
- -
-
-

DCDC Control

-
- - - -
-
- Power Good: -- -
-
-
- - -
-
-

Laser Control

-
-
- - -
-
- - -
- - -
-
- Laser Good: -- -
-
-
- - -
-
-

System Status

-
-
- Driver Temp: - --Β°C -
-
- VCC Voltage: - --V -
-
- PD Voltage: - --V -
-
- Laser Current: - --mA -
-
-
-
-
- -
- -
-
-

Calibration Table

- - -
- -
-
- - - -
No Calibration Data
-
Click the button below to request data from device
-
-
- - - -
- - - -
-
- - -
-
-

Temperature Monitor

- - -
- - -
- - -
-
-
-
- Driver Temp: --Β°C -
-
-
- Laser Temp: --Β°C -
-
-
- Last 5 minutes -
-
-
-
-
-
- - - diff --git a/src/components/DcdcPage.astro b/src/components/DcdcPage.astro deleted file mode 100644 index 729d87a..0000000 --- a/src/components/DcdcPage.astro +++ /dev/null @@ -1,283 +0,0 @@ ---- -const pageTitle = "DCDC Control"; ---- - -
-

{pageTitle}

- - -
-
-

Mode Control

-
- - - - -
-
-
- - -
-
-
-

Voltage Control

- -
- - -
- 10V - 20V - 30V - 40V - 50V -
-
- -
-
-
Input Voltage
-
24.5V
-
Range: 18-28V
-
-
-
Output Voltage
-
25.0V
-
Β±0.1V
-
-
- -
- - -
-
-
- -
-
-

Current & Power

- -
-
-
Current
-
2.1A
-
Max: 5.0A
-
-
-
Power
-
52.5W
-
Max: 150W
-
-
- -
-
- Efficiency - 92.5% -
- -
- -
-
- Temperature - 45.2Β°C -
- -
Warning at 85Β°C
-
-
-
-
- - -
-
-

Protection Settings

- -
-
- - -
- 1A - 3A - 6A -
-
- 5.0A -
-
- -
- - -
- 60Β°C - 80Β°C - 100Β°C -
-
- 85Β°C -
-
- -
- - -
- 15V - 18V - 22V -
-
- 18.0V -
-
-
- -
-
- -
-
- -
-
-
-
- - -
-
-

Status & Diagnostics

- -
-
-

Operating Status

-
-
- PWM Frequency: - 100kHz -
-
- Duty Cycle: - 65.2% -
-
- Switching Losses: - 2.1W -
-
- Uptime: - 2h 45m -
-
-
- -
-

Error Log

-
-
-
14:32 - System started
-
14:33 - Voltage ramped to 25V
-
14:35 - Temp spike to 60Β°C
-
14:36 - Normal operation
-
-
-
-
-
-
-
- - - - diff --git a/src/components/GlobalModals.tsx b/src/components/GlobalModals.tsx deleted file mode 100644 index f8ed7dc..0000000 --- a/src/components/GlobalModals.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import { useState, useEffect } from 'preact/hooks'; -import { useStore } from '@nanostores/preact'; -import { $wsConnectionStatus, $updateState } from './AppProviderStore'; -import UpdaterModal from './UpdaterModal'; -import UpdateSuccessPopup from './UpdateSuccessPopup'; -import UpdateErrorPopup from './UpdateErrorPopup'; -import { $isUpdaterModalOpen, $isSuccessPopupOpen, $isErrorPopupOpen, stateSetters } from './AppProviderStore'; - -// Extend window interface -declare global { - interface Window { - openStatusModal?: () => void; - openFirmwareModal?: () => void; - openUpdaterModal?: () => void; - } -} - -export default function GlobalModals() { - const [isStatusModalOpen, setIsStatusModalOpen] = useState(false); - const [isFirmwareModalOpen, setIsFirmwareModalOpen] = useState(false); - - const updateState = useStore($updateState); - const isUpdaterModalOpen = useStore($isUpdaterModalOpen); - const isSuccessPopupOpen = useStore($isSuccessPopupOpen); - const isErrorPopupOpen = useStore($isErrorPopupOpen); - - // Auto-open success/error popups when update state changes - useEffect(() => { - console.log("🎭 GlobalModals useEffect triggered:", { - updateState, - isSuccessPopupOpen, - isErrorPopupOpen, - isUpdaterModalOpen - }); - - if (updateState === 'success' && !isSuccessPopupOpen) { - console.log("🟒 Opening SUCCESS popup - update completed"); - stateSetters.setSuccessPopupOpen(true); - } else if (updateState === 'restarting') { - console.log("πŸ”„ RESTARTING state - ensuring SUCCESS popup stays open for countdown"); - // Ensure success popup is open for restarting state (it will show restart UI) - if (!isSuccessPopupOpen) { - console.log("πŸ”„ Opening SUCCESS popup for RESTARTING state - will show countdown"); - stateSetters.setSuccessPopupOpen(true); - } else { - console.log("πŸ”„ SUCCESS popup already open - countdown should be visible"); - } - } else if (updateState === 'error' && !isErrorPopupOpen) { - console.log("❌ Opening ERROR popup - update failed"); - stateSetters.setErrorPopupOpen(true); - } else { - console.log("🎭 No modal action needed - conditions not met"); - } - }, [updateState, isSuccessPopupOpen, isErrorPopupOpen]); - - // Listen for global modal events - if (typeof window !== 'undefined') { - window.openStatusModal = () => setIsStatusModalOpen(true); - window.openFirmwareModal = () => setIsFirmwareModalOpen(true); - window.openUpdaterModal = () => { - if (!$isUpdaterModalOpen.get()) { - stateSetters.setUpdaterModalOpen(true); - } - }; - } - - return ( - <> - {/* Status Modal */} - {isStatusModalOpen && ( - - - - - )} - - {/* Firmware Update Modal */} - {isFirmwareModalOpen && ( - - - - - )} - - {/* Updater Modal */} - { stateSetters.setUpdaterModalOpen(false); }} - /> - - {/* Update Success Popup */} - { - stateSetters.setSuccessPopupOpen(false); - // Reset update state after popup is closed - stateSetters.setUpdateState('initial'); - }} - /> - - {/* Update Error Popup */} - { - stateSetters.setErrorPopupOpen(false); - // Reset update state after popup is closed - stateSetters.setUpdateState('initial'); - }} - /> - - ); -} \ No newline at end of file diff --git a/src/components/HostnameChangedModal.astro b/src/components/HostnameChangedModal.astro new file mode 100644 index 0000000..ae505d7 --- /dev/null +++ b/src/components/HostnameChangedModal.astro @@ -0,0 +1,43 @@ + + + diff --git a/src/components/LogsPage.astro b/src/components/LogsPage.astro deleted file mode 100644 index ea841a6..0000000 --- a/src/components/LogsPage.astro +++ /dev/null @@ -1,144 +0,0 @@ ---- -const pageTitle = "Logs"; ---- -
-
-

System Logs

-
- - -
-
- - -
-
-

Filters

- -
-
- -
- - - - -
-
- -
- - -
- -
- -
- - -
-
- -
- -
-
-
-
- - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimestampLevelComponentMessageActions
2025-03-15 14:32:45
ERROR
DriverFailed to initialize temperature sensor
2025-03-15 14:30:12
WARN
ModulatorPWM frequency outside optimal range
2025-03-15 14:28:05
INFO
SystemUser authentication successful
2025-03-15 14:25:59
DEBUG
ControlPID controller parameters updated
2025-03-15 14:20:33
INFO
SystemLaser driver initialization complete
2025-03-15 14:18:22
SUCCESS
HardwareAll hardware components detected
2025-03-15 14:15:07
INFO
SystemSystem boot initiated
-
- - -
-
- Showing 1-7 of 42 entries -
-
- - - - - -
-
-
-
-
\ No newline at end of file diff --git a/src/components/MemoryProgressBar.tsx b/src/components/MemoryProgressBar.tsx deleted file mode 100644 index e8c9d01..0000000 --- a/src/components/MemoryProgressBar.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { useStore } from '@nanostores/preact'; -import { $freeInternalHeap, $totalInternalHeap } from './AppProviderStore'; - -interface MemoryProgressBarProps { - showDetails?: boolean; - className?: string; -} - -export default function MemoryProgressBar({ showDetails = true, className = "" }: MemoryProgressBarProps) { - const freeInternalHeap = useStore($freeInternalHeap); - const totalInternalHeap = useStore($totalInternalHeap); - - // Calculate used and percentage - const usedInternalHeap = totalInternalHeap - freeInternalHeap; - const usagePercentage = totalInternalHeap > 0 ? (usedInternalHeap / totalInternalHeap) * 100 : 0; - const freePercentage = 100 - usagePercentage; - - // Determine color based on usage - const getProgressColor = (percentage: number) => { - if (percentage < 50) return 'bg-green-500'; - if (percentage < 75) return 'bg-yellow-500'; - if (percentage < 90) return 'bg-orange-500'; - return 'bg-red-500'; - }; - - const getTextColor = (percentage: number) => { - if (percentage < 50) return 'text-green-600'; - if (percentage < 75) return 'text-yellow-600'; - if (percentage < 90) return 'text-orange-600'; - return 'text-red-600'; - }; - - const formatBytes = (bytes: number) => { - if (bytes === 0) return '0 B'; - const k = 1024; - const sizes = ['B', 'KB', 'MB']; - const i = Math.floor(Math.log(bytes) / Math.log(k)); - return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; - }; - - // Create segments for the memory bar (like Linux htop) - const totalSegments = 20; - const usedSegments = Math.round((usagePercentage / 100) * totalSegments); - - const getSegmentColor = (segmentIndex: number) => { - if (segmentIndex >= usedSegments) return 'bg-gray-300'; // Empty - - const percentageAtSegment = (segmentIndex / totalSegments) * 100; - if (percentageAtSegment < 50) return 'bg-green-500'; - if (percentageAtSegment < 75) return 'bg-yellow-500'; - if (percentageAtSegment < 90) return 'bg-orange-500'; - return 'bg-red-500'; - }; - - return ( -
- {/* Linux-style Memory Bar with segments */} -
-
-
- Internal Heap -
- - {usagePercentage.toFixed(1)}% - -
- {formatBytes(usedInternalHeap)}/{formatBytes(totalInternalHeap)} -
-
-
- {/* Memory segments */} -
- {Array.from({ length: totalSegments }, (_, i) => ( -
- ))} -
-
-
- - {/* Memory Stats */} - {showDetails && ( -
-
- Used: - {formatBytes(usedInternalHeap)} -
-
- Free: - {formatBytes(freeInternalHeap)} -
-
- Total: - {formatBytes(totalInternalHeap)} -
-
- )} -
- ); -} diff --git a/src/components/ModulationPage.astro b/src/components/ModulationPage.astro deleted file mode 100644 index 064063f..0000000 --- a/src/components/ModulationPage.astro +++ /dev/null @@ -1,505 +0,0 @@ ---- -// This is server-side - runs at build time -const pageTitle = "Modulation"; ---- -
-

Laser Modulation

- - -
-
-

Modulation Mode

- - -
- - -
- - -
-

Internal Modulation Modes

-
- - - - -
-
- - - -
-
- - -
- - -
-
-

- - - - Constant Current Mode -

- -
- - -
- 0A - 2.5A - 5.0A - 7.5A - 10.0A -
-
- -
- -
- -
- - - - Constant Current mode provides stable current output regardless of load changes. -
-
-
- - - - - - - - - - - - - - - - - - - - - -
-
-

- - - - - - - - - - - - - - - - - Advanced Parameters -

- -
- - -
- -
- -
- - - -
-
- -
- - -
-
-
-
-
- - diff --git a/src/components/MonitoringPage.astro b/src/components/MonitoringPage.astro deleted file mode 100644 index 2fdddb0..0000000 --- a/src/components/MonitoringPage.astro +++ /dev/null @@ -1,193 +0,0 @@ ---- -// This is server-side - runs at build time -const pageTitle = "Monitoring"; ---- - -
-

{pageTitle}

- - -
-
-
-

Temperature

-
-
-
65%
-
25.6Β°C
-
-
-
- Min: 22.1Β°C - Max: 28.3Β°C -
-
-
- -
-
-

Current

-
-
-
42%
-
125mA
-
-
-
- Min: 0mA - Max: 300mA -
-
-
- -
-
-

Output Power

-
-
-
50%
-
500mW
-
-
-
- Min: 0mW - Max: 1000mW -
-
-
-
- - -
-
-

System Health

-
- - - - - - - - - - - - - - - -
CPU Temperature -
-
-
- 0Β°C - 30Β°C - 60Β°C - 90Β°C - 120Β°C -
-
-
-
- 42.3Β°C -
-
GaN Temperature -
-
-
- 0Β°C - 30Β°C - 60Β°C - 90Β°C - 120Β°C -
-
-
-
- 65.8Β°C -
-
WiFi Signal Strength -
-
-
- -120dBm - -90dBm - -60dBm - -30dBm - 0dBm -
-
-
-
- -42dBm -
-
-
-
-
- - -
-
-
-

Temperature History

-
-

Temperature Chart Placeholder

-
-
-
- -
-
-

Power Output History

-
-

Power Chart Placeholder

-
-
-
-
-
- - \ No newline at end of file diff --git a/src/components/NetworkManagerStore.tsx b/src/components/NetworkManagerStore.tsx new file mode 100644 index 0000000..f65fe90 --- /dev/null +++ b/src/components/NetworkManagerStore.tsx @@ -0,0 +1,234 @@ +import { atom } from "nanostores"; +import { $websocket } from "./WebSocketAtom"; + +// Mirrors network_config_command_id in components/types_and_commands/inc/command_interface.h. +// UI only uses APPLY_CONFIG, SET_MDNS_HOSTNAME, and GET_WIFI_NETWORKS β€” the rest are legacy single-purpose +// commands that APPLY_CONFIG supersedes. +export enum NetworkManagerCommands { + NETWORK_CMD_SET_WIFI_STATION_MODE = 0, // legacy: configure WiFi Station mode + NETWORK_CMD_SET_WIFI_AP_MODE = 1, // legacy: configure WiFi Access Point mode + NETWORK_CMD_SET_STATIC_IP_STATION_MODE = 2, // legacy: set static IP for Station mode + NETWORK_CMD_SET_MDNS_HOSTNAME = 3, // Set MDNS hostname + NETWORK_CMD_GET_WIFI_NETWORKS = 4, // Scan and return available WiFi networks + NETWORK_CMD_APPLY_CONFIG = 5, // Apply full network configuration (mode + IPs + credentials) + NETWORK_CMD_UNKNOWN = 6, // Unknown Command +} + +// Mirrors connection_mode_t in components/types_and_commands/inc/data_types.h. +// No ethernet on this board β€” only WiFi APSTA or WiFi station. +export enum ConnectionMode { + CONNECTION_MODE_UNKNOWN = 0, // Not yet configured; firmware defaults to APSTA on boot + CONNECTION_MODE_APSTA = 1, // WiFi APSTA (default before user configures STA) + CONNECTION_MODE_STA_DHCP = 2, // WiFi station, DHCP + CONNECTION_MODE_STA_STATIC = 3, // WiFi station, static IP +} + +// Mirrors network_config_nvs in components/nvs_management/inc/nvs_management.h. +export type NetworkConfigNVS = { + Connection_Mode: ConnectionMode; + DHCP_Mode_Station: boolean; // true = DHCP, false = Static IP (DHCP off) + AP_Channel: number; // AP Channel, if AP is configured + IP_Address_Station: string; // actual Station IP Address + Gateway_IP_Address_Station: string; // actual Gateway IP Address for Station Mode + Netmask_Station: string; // actual Netmask for Station Mode + Static_Cfg_IP_Address_Station: string; // saved configuration static IP Address for Station Mode + Static_Cfg_Gateway_IP_Address_Station: string; // saved configuration Gateway IP Address for Station Mode + Static_Cfg_Netmask_Station: string; // saved configuration Netmask for Station Mode + SSID_Station: string; // Station SSID saved + Password_Station: string; // Station Password saved + SSID_AP: string; // AP SSID saved + Password_AP: string; // AP Password saved + MDNS_Hostname: string; // MDNS Hostname saved +}; + +export const $current_network_configuration = atom({ + Connection_Mode: ConnectionMode.CONNECTION_MODE_UNKNOWN, + DHCP_Mode_Station: true, + AP_Channel: 0, + IP_Address_Station: "", + Gateway_IP_Address_Station: "", + Netmask_Station: "", + Static_Cfg_IP_Address_Station: "", + Static_Cfg_Gateway_IP_Address_Station: "", + Static_Cfg_Netmask_Station: "", + SSID_Station: "", + Password_Station: "", + SSID_AP: "", + Password_AP: "", + MDNS_Hostname: "hydrobuddy", +}); + +export type WiFiNetwork = { + SSID: string; // SSID of the network + RSSI: number; // Signal strength in dBm + Channel: number; // Channel number + SecurityType: string; // Security type (WPA, WPA2, WEP, etc.) +}; + +export function authmodeToSecurity(mode: number): string { + switch (mode) { + case 0: + return "Open"; + case 1: + return "WEP"; + case 2: + return "WPA"; + case 3: + return "WPA2"; + case 4: + return "WPA/WPA2"; + case 5: + return "WPA3"; + case 6: + return "WPA2-Enterprise"; + case 7: + return "WPA3-Enterprise"; + default: + return "Unknown"; + } +} + +export const $scanned_wifi_networks = atom([]); + +// Live status emitted by network_manager_task ~every 500 ms via "network_status_update". +// Fields with no ethernet equivalent and no ws_connected_clients (intentionally dropped β€” single-purpose web UI). +export type NetworkStatusDisplay = { + Connection_Mode: ConnectionMode; + AP_Channel: number; + IP_Address_Station: string; + Gateway_IP_Address_Station: string; + Netmask_Station: string; + MDNS_Hostname: string; + MAC_Address_WiFi: string; + rssi: number | null; // null when WiFi STA not connected +}; + +export const $network_status_display = atom({ + Connection_Mode: ConnectionMode.CONNECTION_MODE_UNKNOWN, + AP_Channel: 0, + IP_Address_Station: "", + Gateway_IP_Address_Station: "", + Netmask_Station: "", + MDNS_Hostname: "", + MAC_Address_WiFi: "", + rssi: null, +}); + +/* StationConfigModal / wizard helper nanostores */ + +// depending on radio button in modal or on current network configuration, the toggle shall be set/unset. Used for state saving/retrieval. +export const $wifi_static_ip_config_enabled = atom(false); +export const $selected_ssid = atom(""); +export const $wifi_network_pw = atom(""); +export const $temporary_static_ip_address = atom(""); +export const $temporary_static_ip_subnet_mask = atom(""); +export const $temporary_static_ip_gateway_ip_address = atom(""); + +export const $hostname_input_field = atom(""); + +function wsOpen(): WebSocket | null { + const ws = $websocket.get(); + return ws && (ws as WebSocket).readyState === WebSocket.OPEN ? (ws as WebSocket) : null; +} + +export function send_new_network_configuration_to_alpha(network_config: NetworkConfigNVS): boolean { + // send the network configuration to the device + const ws = wsOpen(); + if (!ws) { + console.error("WebSocket not connected, cannot send new network configuration!"); + return false; + } + console.log("Sending new network configuration!"); + console.log("Current configuration: ", $current_network_configuration.get()); + console.log("New configuration: ", network_config); + + const mode = network_config.Connection_Mode; + const hasApsta = mode === ConnectionMode.CONNECTION_MODE_APSTA; + const hasSta = mode === ConnectionMode.CONNECTION_MODE_STA_DHCP || mode === ConnectionMode.CONNECTION_MODE_STA_STATIC; + const hasStaticSta = mode === ConnectionMode.CONNECTION_MODE_STA_STATIC; + + if (mode === ConnectionMode.CONNECTION_MODE_UNKNOWN) { + console.error("Cannot send config with UNKNOWN connection mode!"); + return false; + } + if (hasApsta && (network_config.SSID_AP === "" || network_config.SSID_AP.length >= 32 || network_config.Password_AP.length >= 32)) { + console.error("APSTA AP SSID/password invalid!"); + return false; + } + if (hasSta && (network_config.SSID_Station === "" || network_config.SSID_Station.length >= 32 || network_config.Password_Station.length >= 32)) { + console.error("STA SSID/password invalid!"); + return false; + } + if ( + hasStaticSta && + (network_config.Static_Cfg_IP_Address_Station === "" || + network_config.Static_Cfg_Netmask_Station === "" || + network_config.Static_Cfg_Gateway_IP_Address_Station === "") + ) { + console.error("Static STA IP fields missing!"); + return false; + } + + ws.send( + JSON.stringify({ + message_type: "network_cmd", + network_command: NetworkManagerCommands.NETWORK_CMD_APPLY_CONFIG, + network_config: network_config, + }), + ); + return true; +} + +// Request the firmware to broadcast its current network_config (mode + saved SSID etc.). +// Called on WebSocket open so the UI knows whether to show the wizard or the overview. +export const request_network_config = (): void => { + wsOpen()?.send(JSON.stringify({ message_type: "request_network_config" })); +}; + +export const scan_wifi_networks = (): void => { + $scanned_wifi_networks.set([]); + wsOpen()?.send( + JSON.stringify({ + message_type: "network_cmd", + network_command: NetworkManagerCommands.NETWORK_CMD_GET_WIFI_NETWORKS, + }), + ); +}; + +export const set_hostname = (hostname: string): boolean => { + const ws = wsOpen(); + if (!ws) { + console.error("WebSocket not connected, cannot set hostname!"); + return false; + } + + if (!hostname || hostname.length === 0 || hostname.length > 31) { + console.error("Invalid hostname! Must be 1-31 characters."); + return false; + } else if (hostname === $current_network_configuration.get().MDNS_Hostname) { + return false; + } + console.log("Setting MDNS hostname:", hostname); + + ws.send( + JSON.stringify({ + message_type: "set_network_hostname", + network_command: NetworkManagerCommands.NETWORK_CMD_SET_MDNS_HOSTNAME, + hostname: hostname, + }), + ); + + return true; +}; + +export const clear_scanned_wifi_networks = (): void => { + $scanned_wifi_networks.set([]); +}; + +export type NetworkConfigError = { + reason: string; + failed_ssid: string; + connection_mode: ConnectionMode; +}; + +export const $network_config_error = atom(null); diff --git a/src/components/NetworkOverview.astro b/src/components/NetworkOverview.astro new file mode 100644 index 0000000..d9347a8 --- /dev/null +++ b/src/components/NetworkOverview.astro @@ -0,0 +1,543 @@ +--- +import { IconPlant } from "@tabler/icons-preact"; +--- + +
+ +
+
+
+ +
+

HydroBuddy is online

+

Loading mode…

+
+
+ +
+
+ + +
+ +
+
+

Connection Mode

+
β€”
+
β€”
+
+
+ + +
+
+

WiFi

+
β€”
+ +
RSSI: β€”
+
β€”
+
+
+ + +
+
+

Station IP

+
β€”
+
GW: β€”
+
Mask: β€”
+
MAC: β€”
+
+
+ + +
+
+

Hostname

+
β€”
+ + http://hydrobuddy.local + +
+
+
+ + +
+
+

Device name

+

Reach the web interface at this name.local from any device on the same network.

+
+ + +
+ +
+
+ + +
+
+

IP Address Assignment

+

DHCP is the safe default. Static IP only if your network requires it.

+ +
+ + +
+ + +
+
+ + +
+
+

WiFi Mode

+

Choose how the device connects.

+ +
+ + +
+ + + +
+
+
+ + + + + + + + diff --git a/src/components/NetworkPage.astro b/src/components/NetworkPage.astro index 6191cc9..6d5e302 100644 --- a/src/components/NetworkPage.astro +++ b/src/components/NetworkPage.astro @@ -1,530 +1,684 @@ --- +import StationConfigModal from "../components/modals/StationConfigModal.astro"; +import AccessPointConfigModal from "../components/modals/AccessPointConfigModal.astro"; +import WifiDisableWarningModal from "../components/modals/WifiDisableWarningModal.astro"; +import HostnameChangedModal from "../components/modals/HostnameChangedModal.astro"; +import IconEye from "../components/icons/IconEye.astro"; +import IconEyeClosed from "../components/icons/IconEyeClosed.astro"; + const pageTitle = "Network Configuration"; --- -
-

{pageTitle}

- - -
-

Connection Status

- -
-
-
-
- Network Status +
+

{pageTitle}

+ +
+ +
+
+

Connection Mode

+
Loading...
+
+
+ + +
+
+

Ethernet

+
-
+
GW: -
+
Mask: -
+
MAC: -
+
+
+ + +
+
+
+
+

WiFi

+
-
+ -
Connected over WiFi
-
Station Mode
+
RSSI:
+
Not connected
+
+
+ + + + + + +
-
-
-
- - - - - IP Address -
-
192.168.1.158
-
DHCP Assigned
+
+
+ + +
+
+

WiFi Station

+
-
+
GW: -
+
Mask: -
+
MAC: -
+
+
+ + +
+
+

Hostname

+
-
+ + http://hostname.local + +
+
+ + +
+
+
+
+

Connected Clients

+
0
+
No clients
+ + + + + +
-
-
-
- - - +
+
+
+ +
+ +
+
+
+ +
+

+ + + + - Hostname + Network Interface Name +

+ + +
+ +
-
hydrobuddy.local
-
mDNS Active
+ +
-
-
-
-
- - - - - - - - Signal Strength + +
+ + +
+

Ethernet IP Address Configuration

+ + +
+ +
-
-42dBm
-
- -
- -100dBm - -10dBm + +
-
-
-
- - - - - - - Client Count +
+
+ + +
+
+ +
+
+ +
+

+ + + + + + + + WiFi Configuration +

-
2
-
Connected Devices
+ +
+
+
+ +
+ + + + +
-
-
- -
- -
-
-

Network Info

- -
-
- Hostname - hydrobuddy.local -
-
- IP Address - 192.168.1.158 -
-
- Subnet - 255.255.255.0 -
-
- Gateway - 192.168.1.1 -
-
- MAC Address - AA:BB:CC:DD:EE:FF -
-
- Connection Method - WiFi -
- -
- +
+
+
-

Connected Devices

-
-
-
- πŸ’» -
-
laptop-office
-
192.168.1.102
-
-
- -
-
-
- πŸ“± -
-
smartphone-dev
-
192.168.1.103
-
+
WiFi Station
+
Connect to a WiFi network
- -
-
-
- πŸ’» -
-
tablet-main
-
192.168.1.104
-
+ + + -
+
- - -
-
-

WiFi Settings

- - -
- -
- - -
-
- - -
- -
- - - - -
-
- - -
- -
- - -
-
- - - - - -
-
- - -
- -
- - - -
- -
- - -
- -
- - -
-
-
-
-
- - -
-
-

General Network Settings

- -
-
-
- -
- - -
-
- - - - -
- - -
- Only letters, numbers, and hyphens allowed -
-
-
- -
-
- -
- -
- -
-
-
-
- - -