diff --git a/webui/jsconfig.json b/webui/jsconfig.json new file mode 100644 index 0000000..babf8fb --- /dev/null +++ b/webui/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} \ No newline at end of file diff --git a/webui/package.json b/webui/package.json index 782b0f9..0f1631e 100644 --- a/webui/package.json +++ b/webui/package.json @@ -10,8 +10,11 @@ "preview": "vite preview" }, "dependencies": { + "@phosphor-icons/react": "^2.1.10", "react": "^19.1.1", - "react-dom": "^19.1.1" + "react-dom": "^19.1.1", + "react-router-dom": "^7.8.2", + "sass-embedded": "^1.92.1" }, "devDependencies": { "@eslint/js": "^9.33.0", diff --git a/webui/pnpm-lock.yaml b/webui/pnpm-lock.yaml index 16d27ea..a26bbd0 100644 --- a/webui/pnpm-lock.yaml +++ b/webui/pnpm-lock.yaml @@ -8,12 +8,21 @@ importers: .: dependencies: + '@phosphor-icons/react': + specifier: ^2.1.10 + version: 2.1.10(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react: specifier: ^19.1.1 version: 19.1.1 react-dom: specifier: ^19.1.1 version: 19.1.1(react@19.1.1) + react-router-dom: + specifier: ^7.8.2 + version: 7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + sass-embedded: + specifier: ^1.92.1 + version: 1.92.1 devDependencies: '@eslint/js': specifier: ^9.33.0 @@ -26,7 +35,7 @@ importers: version: 19.1.9(@types/react@19.1.12) '@vitejs/plugin-react': specifier: ^5.0.0 - version: 5.0.2(vite@7.1.5) + version: 5.0.2(vite@7.1.5(sass-embedded@1.92.1)(sass@1.92.1)) eslint: specifier: ^9.33.0 version: 9.35.0 @@ -41,7 +50,7 @@ importers: version: 16.3.0 vite: specifier: ^7.1.2 - version: 7.1.5 + version: 7.1.5(sass-embedded@1.92.1)(sass@1.92.1) packages: @@ -128,6 +137,9 @@ packages: resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} + '@bufbuild/protobuf@2.7.0': + resolution: {integrity: sha512-qn6tAIZEw5i/wiESBF4nQxZkl86aY4KoO0IkUa2Lh+rya64oTOdJQFlZuMwI1Qz9VBJQrQC4QlSA2DNek5gCOA==} + '@esbuild/aix-ppc64@0.25.9': resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} engines: {node: '>=18'} @@ -354,6 +366,95 @@ packages: '@jridgewell/trace-mapping@0.3.30': resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + '@parcel/watcher-android-arm64@2.5.1': + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.1': + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.1': + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.1': + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.1': + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.1': + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.1': + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.1': + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.1': + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.1': + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.1': + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.1': + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.1': + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} + + '@phosphor-icons/react@2.1.10': + resolution: {integrity: sha512-vt8Tvq8GLjheAZZYa+YG/pW7HDbov8El/MANW8pOAz4eGxrwhnbfrQZq0Cp4q8zBEu8NIhHdnr+r8thnfRSNYA==} + engines: {node: '>=10'} + peerDependencies: + react: '>= 16.8' + react-dom: '>= 16.8' + '@rolldown/pluginutils@1.0.0-beta.34': resolution: {integrity: sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA==} @@ -520,11 +621,18 @@ packages: brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + browserslist@4.25.4: resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-builder@0.2.0: + resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -536,6 +644,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -543,12 +655,19 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorjs.io@0.5.2: + resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -568,6 +687,11 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + electron-to-chromium@1.5.215: resolution: {integrity: sha512-TIvGp57UpeNetj/wV/xpFNpWGb0b/ROw372lHPx5Aafx02gjTBtWnEEcaSX3W2dLM3OSdGGyHX/cHl01JQsLaQ==} @@ -659,6 +783,10 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -699,6 +827,9 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + immutable@5.1.3: + resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -715,6 +846,10 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -761,6 +896,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -775,6 +914,9 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-releases@2.0.20: resolution: {integrity: sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA==} @@ -805,6 +947,10 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} @@ -830,10 +976,31 @@ packages: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} + react-router-dom@7.8.2: + resolution: {integrity: sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.8.2: + resolution: {integrity: sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react@19.1.1: resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} engines: {node: '>=0.10.0'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -843,6 +1010,123 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + sass-embedded-all-unknown@1.92.1: + resolution: {integrity: sha512-5t6/YZf+vhO3OY/49h8RCL6Cwo78luva0M+TnTM9gu9ASffRXAuOVLNKciSXa3loptyemDDS6IU5/dVH5w0KmA==} + cpu: ['!arm', '!arm64', '!riscv64', '!x64'] + + sass-embedded-android-arm64@1.92.1: + resolution: {integrity: sha512-Q+UruGb7yKawHagVmVDRRKsnc4mJZvWMBnuRCu2coJo2FofyqBmXohVGXbxko97sYceA9TJTrUEx3WVKQUNCbQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + + sass-embedded-android-arm@1.92.1: + resolution: {integrity: sha512-4EjpVVzuksERdgAd4BqeSXFnWtWN3DSRyEIUPJ7BhcS9sfDh2Gf6miI2kNTvIQLJ2XIJynDDcEQ8a1U9KwKUTQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + + sass-embedded-android-riscv64@1.92.1: + resolution: {integrity: sha512-nCY5btLlX7W7Jc6cCL6D2Yklpiu540EJ2G08YVGu12DrAMCBzqM347CSRf2ojp1H8jyhvmLkaFwnrJWzh+6S+w==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [android] + + sass-embedded-android-x64@1.92.1: + resolution: {integrity: sha512-qYWR3bftJ77aLYwYDFuzDI4dcwVVixxqQxlIQWNGkHRCexj614qGSSHemr18C2eVj3mjXAQxTQxU68U7pkGPAA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + + sass-embedded-darwin-arm64@1.92.1: + resolution: {integrity: sha512-g2yQ3txjMYLKMjL2cW1xRO9nnV3ijf95NbX/QShtV6tiVUETZNWDsRMDEwBNGYY6PTE/UZerjJL1R/2xpQg6WA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + + sass-embedded-darwin-x64@1.92.1: + resolution: {integrity: sha512-eH+fgxLQhTEPjZPCgPAVuX5e514Qp/4DMAUMtlNShv4cr4TD5qOp1XlsPYR/b7uE7p2cKFkUpUn/bHNqJ2ay4A==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + + sass-embedded-linux-arm64@1.92.1: + resolution: {integrity: sha512-dNmlpGeZkry1BofhAdGFBXrpM69y9LlYuNnncf+HfsOOUtj8j0q1RwS+zb5asknhKFUOAG8GCGRY1df7Rwu35g==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-arm@1.92.1: + resolution: {integrity: sha512-cT3w8yoQTqrtZvWLJeutEGmawITDTY4J6oSVQjeDcPnnoPt0gOFxem8YMznraACXvahw/2+KJDH33BTNgiPo0A==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-musl-arm64@1.92.1: + resolution: {integrity: sha512-TfiEBkCyNzVoOhjHXUT+vZ6+p0ueDbvRw6f4jHdkvljZzXdXMby4wh7BU1odl69rgRTkSvYKhgbErRLDR/F7pQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-musl-arm@1.92.1: + resolution: {integrity: sha512-nPBos6lI31ef2zQhqTZhFOU7ar4impJbLIax0XsqS269YsiCwjhk11VmUloJTpFlJuKMiVXNo7dPx+katxhD/Q==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-musl-riscv64@1.92.1: + resolution: {integrity: sha512-R+RcJA4EYpJDE9JM1GgPYgZo7x94FlxZ6jPodOQkEaZ1S9kvXVCuP5X/0PXRPhu08KJOfeMsAElzfdAjUf7KJg==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + sass-embedded-linux-musl-x64@1.92.1: + resolution: {integrity: sha512-/HolYRGXJjx8nLw6oj5ZrkR7PFM7X/5kE4MYZaFMpDIPIcw3bqB2fUXLo/MYlRLsw7gBAT6hJAMBrNdKuTphfw==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-linux-riscv64@1.92.1: + resolution: {integrity: sha512-b9bxe0CMsbSsLx3nrR0cq8xpIkoAC6X36o4DGMITF3m2v3KsojC7ru9X0Gz+zUFr6rwpq/0lTNzFLNu6sPNo3w==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + sass-embedded-linux-x64@1.92.1: + resolution: {integrity: sha512-xuiK5Jp5NldW4bvlC7AuX1Wf7o0gLZ3md/hNg+bkTvxtCDgnUHtfdo8Q+xWP11bD9QX31xXFWpmUB8UDLi6XQQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-unknown-all@1.92.1: + resolution: {integrity: sha512-AT9oXvtNY4N+Nd0wvoWqq9A5HjdH/X3aUH4boQUtXyaJ/9DUwnQmBpP5Gtn028ZS8exOGBdobmmWAuigv0k/OA==} + os: ['!android', '!darwin', '!linux', '!win32'] + + sass-embedded-win32-arm64@1.92.1: + resolution: {integrity: sha512-KvmpQjY9yTBMtTYz4WBqetlv9bGaDW1aStcu7MSTbH7YiSybX/9fnxlCAEQv1WlIidQhcJAiyk0Eae+LGK7cIQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + + sass-embedded-win32-x64@1.92.1: + resolution: {integrity: sha512-B6Nz/GbH7Vkpb2TkQHsGcczWM5t+70VWopWF1x5V5yxLpA8ZzVQ7NTKKi+jDoVY2Efu6ZyzgT9n5KgG2kWliXA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + + sass-embedded@1.92.1: + resolution: {integrity: sha512-28YwLnF5atAhogt3E4hXzz/NB9dwKffyw08a7DEasLh94P7+aELkG3ENSHYCWB9QFN14hYNLfwr9ozUsPDhcDQ==} + engines: {node: '>=16.0.0'} + hasBin: true + + sass@1.92.1: + resolution: {integrity: sha512-ffmsdbwqb3XeyR8jJR6KelIXARM9bFQe8A6Q3W4Klmwy5Ckd5gz7jgUNHo4UOqutU5Sk1DtKLbpDP0nLCg1xqQ==} + engines: {node: '>=14.0.0'} + hasBin: true + scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} @@ -850,6 +1134,9 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -870,10 +1157,29 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + sync-child-process@1.0.2: + resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} + engines: {node: '>=16.0.0'} + + sync-message-port@1.1.3: + resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} + engines: {node: '>=16.0.0'} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -887,6 +1193,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + vite@7.1.5: resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1057,6 +1366,8 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@bufbuild/protobuf@2.7.0': {} + '@esbuild/aix-ppc64@0.25.9': optional: true @@ -1209,6 +1520,72 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@parcel/watcher-android-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-x64@2.5.1': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.1': + optional: true + + '@parcel/watcher-win32-arm64@2.5.1': + optional: true + + '@parcel/watcher-win32-ia32@2.5.1': + optional: true + + '@parcel/watcher-win32-x64@2.5.1': + optional: true + + '@parcel/watcher@2.5.1': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 + optional: true + + '@phosphor-icons/react@2.1.10(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + '@rolldown/pluginutils@1.0.0-beta.34': {} '@rollup/rollup-android-arm-eabi@4.50.1': @@ -1307,7 +1684,7 @@ snapshots: dependencies: csstype: 3.1.3 - '@vitejs/plugin-react@5.0.2(vite@7.1.5)': + '@vitejs/plugin-react@5.0.2(vite@7.1.5(sass-embedded@1.92.1)(sass@1.92.1))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) @@ -1315,7 +1692,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.34 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.1.5 + vite: 7.1.5(sass-embedded@1.92.1)(sass@1.92.1) transitivePeerDependencies: - supports-color @@ -1345,6 +1722,11 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + optional: true + browserslist@4.25.4: dependencies: caniuse-lite: 1.0.30001741 @@ -1352,6 +1734,8 @@ snapshots: node-releases: 2.0.20 update-browserslist-db: 1.1.3(browserslist@4.25.4) + buffer-builder@0.2.0: {} + callsites@3.1.0: {} caniuse-lite@1.0.30001741: {} @@ -1361,16 +1745,25 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + optional: true + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + colorjs.io@0.5.2: {} + concat-map@0.0.1: {} convert-source-map@2.0.0: {} + cookie@1.0.2: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -1385,6 +1778,9 @@ snapshots: deep-is@0.1.4: {} + detect-libc@1.0.3: + optional: true + electron-to-chromium@1.5.215: {} esbuild@0.25.9: @@ -1509,6 +1905,11 @@ snapshots: dependencies: flat-cache: 4.0.1 + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + optional: true + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -1538,6 +1939,8 @@ snapshots: ignore@5.3.2: {} + immutable@5.1.3: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -1551,6 +1954,9 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-number@7.0.0: + optional: true + isexe@2.0.0: {} js-tokens@4.0.0: {} @@ -1588,6 +1994,12 @@ snapshots: dependencies: yallist: 3.1.1 + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + optional: true + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -1598,6 +2010,9 @@ snapshots: natural-compare@1.4.0: {} + node-addon-api@7.1.1: + optional: true + node-releases@2.0.20: {} optionator@0.9.4: @@ -1627,6 +2042,9 @@ snapshots: picocolors@1.1.1: {} + picomatch@2.3.1: + optional: true + picomatch@4.0.3: {} postcss@8.5.6: @@ -1646,8 +2064,25 @@ snapshots: react-refresh@0.17.0: {} + react-router-dom@7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-router: 7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + + react-router@7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + cookie: 1.0.2 + react: 19.1.1 + set-cookie-parser: 2.7.1 + optionalDependencies: + react-dom: 19.1.1(react@19.1.1) + react@19.1.1: {} + readdirp@4.1.2: + optional: true + resolve-from@4.0.0: {} rollup@4.50.1: @@ -1677,10 +2112,113 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.50.1 fsevents: 2.3.3 + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + + sass-embedded-all-unknown@1.92.1: + dependencies: + sass: 1.92.1 + optional: true + + sass-embedded-android-arm64@1.92.1: + optional: true + + sass-embedded-android-arm@1.92.1: + optional: true + + sass-embedded-android-riscv64@1.92.1: + optional: true + + sass-embedded-android-x64@1.92.1: + optional: true + + sass-embedded-darwin-arm64@1.92.1: + optional: true + + sass-embedded-darwin-x64@1.92.1: + optional: true + + sass-embedded-linux-arm64@1.92.1: + optional: true + + sass-embedded-linux-arm@1.92.1: + optional: true + + sass-embedded-linux-musl-arm64@1.92.1: + optional: true + + sass-embedded-linux-musl-arm@1.92.1: + optional: true + + sass-embedded-linux-musl-riscv64@1.92.1: + optional: true + + sass-embedded-linux-musl-x64@1.92.1: + optional: true + + sass-embedded-linux-riscv64@1.92.1: + optional: true + + sass-embedded-linux-x64@1.92.1: + optional: true + + sass-embedded-unknown-all@1.92.1: + dependencies: + sass: 1.92.1 + optional: true + + sass-embedded-win32-arm64@1.92.1: + optional: true + + sass-embedded-win32-x64@1.92.1: + optional: true + + sass-embedded@1.92.1: + dependencies: + '@bufbuild/protobuf': 2.7.0 + buffer-builder: 0.2.0 + colorjs.io: 0.5.2 + immutable: 5.1.3 + rxjs: 7.8.2 + supports-color: 8.1.1 + sync-child-process: 1.0.2 + varint: 6.0.0 + optionalDependencies: + sass-embedded-all-unknown: 1.92.1 + sass-embedded-android-arm: 1.92.1 + sass-embedded-android-arm64: 1.92.1 + sass-embedded-android-riscv64: 1.92.1 + sass-embedded-android-x64: 1.92.1 + sass-embedded-darwin-arm64: 1.92.1 + sass-embedded-darwin-x64: 1.92.1 + sass-embedded-linux-arm: 1.92.1 + sass-embedded-linux-arm64: 1.92.1 + sass-embedded-linux-musl-arm: 1.92.1 + sass-embedded-linux-musl-arm64: 1.92.1 + sass-embedded-linux-musl-riscv64: 1.92.1 + sass-embedded-linux-musl-x64: 1.92.1 + sass-embedded-linux-riscv64: 1.92.1 + sass-embedded-linux-x64: 1.92.1 + sass-embedded-unknown-all: 1.92.1 + sass-embedded-win32-arm64: 1.92.1 + sass-embedded-win32-x64: 1.92.1 + + sass@1.92.1: + dependencies: + chokidar: 4.0.3 + immutable: 5.1.3 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.1 + optional: true + scheduler@0.26.0: {} semver@6.3.1: {} + set-cookie-parser@2.7.1: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -1695,11 +2233,28 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + sync-child-process@1.0.2: + dependencies: + sync-message-port: 1.1.3 + + sync-message-port@1.1.3: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + optional: true + + tslib@2.8.1: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -1714,7 +2269,9 @@ snapshots: dependencies: punycode: 2.3.1 - vite@7.1.5: + varint@6.0.0: {} + + vite@7.1.5(sass-embedded@1.92.1)(sass@1.92.1): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) @@ -1724,6 +2281,8 @@ snapshots: tinyglobby: 0.2.15 optionalDependencies: fsevents: 2.3.3 + sass: 1.92.1 + sass-embedded: 1.92.1 which@2.0.2: dependencies: diff --git a/webui/src/App.jsx b/webui/src/App.jsx index b5d6288..6e62a88 100644 --- a/webui/src/App.jsx +++ b/webui/src/App.jsx @@ -1,10 +1,18 @@ +import { createBrowserRouter, Navigate, RouterProvider } from "react-router-dom"; +import "@/common/styles/main.sass"; +import Root from "@/common/layouts/Root.jsx"; const App = () => { + const router = createBrowserRouter([ + { + path: "/", + element: , + children: [ + { path: "/", element: }, + ], + }, + ]); - return ( - <> -

vite init

- - ) -} + return ; +}; export default App; \ No newline at end of file diff --git a/webui/src/common/contexts/UserContext.jsx b/webui/src/common/contexts/UserContext.jsx new file mode 100644 index 0000000..2f9fa6b --- /dev/null +++ b/webui/src/common/contexts/UserContext.jsx @@ -0,0 +1,68 @@ +import { createContext, useEffect, useState } from "react"; +import { getRequest, postRequest } from "@/common/utils/RequestUtil.js"; +import Login from "@/pages/Login/index.js"; + +export const UserContext = createContext({}); + +export const UserProvider = ({ children }) => { + + const [sessionToken, setSessionToken] = useState(localStorage.getItem("sessionToken")); + const [firstTimeSetup, setFirstTimeSetup] = useState(false); + const [user, setUser] = useState(null); + + const updateSessionToken = (sessionToken) => { + setSessionToken(sessionToken); + localStorage.setItem("sessionToken", sessionToken); + login(); + }; + + const checkFirstTimeSetup = async () => { + try { + const response = await getRequest("setup/status"); + setFirstTimeSetup(response?.first_user_exists); + } catch (error) { + console.error(error); + } + }; + + const login = async () => { + try { + const userObj = await getRequest("accounts/me"); + setUser(userObj); + } catch (error) { + if (error.message === "Unauthorized") { + setSessionToken(null); + localStorage.removeItem("sessionToken"); + } + } + }; + + const logout = async () => { + await postRequest("auth/logout", { token: sessionToken }); + + window.location.reload(); + }; + + useEffect(() => { + const searchParams = new URLSearchParams(location.search); + const tokenFromUrl = searchParams.get('token'); + const error = searchParams.get('error'); + + if (tokenFromUrl) { + updateSessionToken(tokenFromUrl); + } else if (error) { + console.log(error) + } + }, [location]); + + useEffect(() => { + sessionToken ? login() : checkFirstTimeSetup(); + }, []); + + return ( + + {user == null && } + {user !== null && children} + + ); +}; \ No newline at end of file diff --git a/webui/src/common/layouts/Root.jsx b/webui/src/common/layouts/Root.jsx new file mode 100644 index 0000000..29da720 --- /dev/null +++ b/webui/src/common/layouts/Root.jsx @@ -0,0 +1,7 @@ +export default () => { + return ( + <> + Root + + ) +} \ No newline at end of file diff --git a/webui/src/common/styles/main.sass b/webui/src/common/styles/main.sass new file mode 100644 index 0000000..e69de29 diff --git a/webui/src/common/utils/RequestUtil.js b/webui/src/common/utils/RequestUtil.js new file mode 100644 index 0000000..00d46d6 --- /dev/null +++ b/webui/src/common/utils/RequestUtil.js @@ -0,0 +1,48 @@ +export const request = async (url, method, body, headers) => { + url = url.startsWith("/") ? url.substring(1) : url; + + const response = await fetch(`/api/${url}`, { + method: method, + headers: {...headers, "Content-Type": "application/json"}, + body: JSON.stringify(body) + }); + + if (response.status === 401) throw new Error("Unauthorized"); + + const rawData = await response.text(); + const data = rawData ? JSON.parse(rawData) : rawData.toString(); + + if (data.code >= 300) throw data; + + if (!response.ok) throw data; + + return data; +} + +const getToken = () => { + return localStorage.getItem("sessionToken"); +} + +export const sessionRequest = (url, method, token, body) => { + return request(url, method, body, {"Authorization": `Bearer ${token}`}); +} + +export const getRequest = (url) => { + return sessionRequest(url, "GET", getToken()); +} + +export const postRequest = (url, body) => { + return sessionRequest(url, "POST", getToken(), body); +} + +export const putRequest = (url, body) => { + return sessionRequest(url, "PUT", getToken(), body); +} + +export const deleteRequest = (url) => { + return sessionRequest(url, "DELETE", getToken()); +} + +export const patchRequest = (url, body) => { + return sessionRequest(url, "PATCH", getToken(), body); +} \ No newline at end of file diff --git a/webui/src/main.jsx b/webui/src/main.jsx index 3d9da8a..d5251d8 100644 --- a/webui/src/main.jsx +++ b/webui/src/main.jsx @@ -1,9 +1,12 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import App from './App.jsx' +import {UserProvider} from "@/common/contexts/UserContext.jsx"; createRoot(document.getElementById('root')).render( - + + + , ) diff --git a/webui/src/pages/Login/Login.jsx b/webui/src/pages/Login/Login.jsx new file mode 100644 index 0000000..87d316e --- /dev/null +++ b/webui/src/pages/Login/Login.jsx @@ -0,0 +1,6 @@ +import "./styles.sass"; +export const Login = () => { + return ( +
Login Page
+ ) +} \ No newline at end of file diff --git a/webui/src/pages/Login/index.js b/webui/src/pages/Login/index.js new file mode 100644 index 0000000..e39a6fc --- /dev/null +++ b/webui/src/pages/Login/index.js @@ -0,0 +1 @@ +export {Login as default} from "./Login"; \ No newline at end of file diff --git a/webui/src/pages/Login/styles.sass b/webui/src/pages/Login/styles.sass new file mode 100644 index 0000000..e69de29 diff --git a/webui/vite.config.js b/webui/vite.config.js index 149c314..cdd5f9c 100644 --- a/webui/vite.config.js +++ b/webui/vite.config.js @@ -1,6 +1,20 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import {defineConfig} from "vite" +import react from "@vitejs/plugin-react" +import * as path from "path"; + export default defineConfig({ - plugins: [react()], + plugins: [react()], + server: { + proxy: { + "/api": { + target: "http://localhost:8379" + } + } + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "src"), + } + }, }); \ No newline at end of file