diff --git a/.gitignore b/.gitignore index 4108b33..c3419e6 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.env + # Logs logs *.log diff --git a/package-lock.json b/package-lock.json index 8afc87b..670e391 100755 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@mantine/notifications": "^8.3.1", "@tabler/icons-react": "^3.34.1", "axios": "^1.13.2", + "dotenv": "^17.4.2", "immer": "^11.1.4", "keycloak-js": "^26.2.3", "miew-react": "^0.11.0", @@ -26,6 +27,7 @@ }, "devDependencies": { "@eslint/js": "^9.33.0", + "@types/node": "^25.6.0", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@types/react-helmet": "^6.1.11", @@ -331,9 +333,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", "cpu": [ "ppc64" ], @@ -347,9 +349,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", "cpu": [ "arm" ], @@ -363,9 +365,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", "cpu": [ "arm64" ], @@ -379,9 +381,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", "cpu": [ "x64" ], @@ -395,9 +397,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", "cpu": [ "arm64" ], @@ -411,9 +413,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", "cpu": [ "x64" ], @@ -427,9 +429,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", "cpu": [ "arm64" ], @@ -443,9 +445,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", "cpu": [ "x64" ], @@ -459,9 +461,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", "cpu": [ "arm" ], @@ -475,9 +477,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", "cpu": [ "arm64" ], @@ -491,9 +493,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", "cpu": [ "ia32" ], @@ -507,9 +509,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", "cpu": [ "loong64" ], @@ -523,9 +525,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", "cpu": [ "mips64el" ], @@ -539,9 +541,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", "cpu": [ "ppc64" ], @@ -555,9 +557,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", "cpu": [ "riscv64" ], @@ -571,9 +573,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", "cpu": [ "s390x" ], @@ -587,9 +589,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", "cpu": [ "x64" ], @@ -603,9 +605,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", "cpu": [ "arm64" ], @@ -619,9 +621,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", "cpu": [ "x64" ], @@ -635,9 +637,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", "cpu": [ "arm64" ], @@ -651,9 +653,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", "cpu": [ "x64" ], @@ -667,9 +669,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", "cpu": [ "arm64" ], @@ -683,9 +685,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", "cpu": [ "x64" ], @@ -699,9 +701,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", "cpu": [ "arm64" ], @@ -715,9 +717,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", "cpu": [ "ia32" ], @@ -731,9 +733,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", "cpu": [ "x64" ], @@ -1566,6 +1568,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } + }, "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", @@ -1795,9 +1807,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -1966,14 +1978,14 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", - "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.2.tgz", + "integrity": "sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "proxy-from-env": "^2.1.0" } }, "node_modules/balanced-match": { @@ -1994,9 +2006,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -2246,6 +2258,18 @@ "csstype": "^3.0.2" } }, + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2313,9 +2337,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "devOptional": true, "hasInstallScript": true, "license": "MIT", @@ -2326,32 +2350,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" } }, "node_modules/escalade": { @@ -2673,16 +2697,16 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "funding": [ { "type": "individual", @@ -3097,9 +3121,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.merge": { @@ -3360,9 +3384,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -3373,9 +3397,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "devOptional": true, "funding": [ { @@ -3423,10 +3447,13 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/punycode": { "version": "2.3.1", @@ -3896,9 +3923,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "devOptional": true, "license": "MIT", "engines": { @@ -4023,6 +4050,13 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "devOptional": true, + "license": "MIT" + }, "node_modules/update-browserslist-db": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", @@ -4153,13 +4187,13 @@ } }, "node_modules/vite": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz", - "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "devOptional": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", + "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", @@ -4265,9 +4299,9 @@ } }, "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "devOptional": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index a71f788..a822a1e 100755 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@mantine/notifications": "^8.3.1", "@tabler/icons-react": "^3.34.1", "axios": "^1.13.2", + "dotenv": "^17.4.2", "immer": "^11.1.4", "keycloak-js": "^26.2.3", "miew-react": "^0.11.0", @@ -28,6 +29,7 @@ }, "devDependencies": { "@eslint/js": "^9.33.0", + "@types/node": "^25.6.0", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@types/react-helmet": "^6.1.11", diff --git a/src/Api/ConvertBackendCalls.tsx b/src/Api/ConvertBackendCalls.tsx index da9185f..8504068 100755 --- a/src/Api/ConvertBackendCalls.tsx +++ b/src/Api/ConvertBackendCalls.tsx @@ -1,19 +1,20 @@ import axios, { AxiosError } from "axios"; import type { ConvertSchema } from "Types/ApiCalls/ConvertBackendCallsTypes"; -const openbableBackendRoot = "http://localhost:1654"; - export async function ConvertMoleculeToStandart( data: ConvertSchema, ): Promise { try { - const response = await axios.post(openbableBackendRoot + "/convert", { - text: data.inputText, - format: data.inputFormat, - convert_3d: data.make_3d, - add_hydrogen: data.add_h, - optimize_geometry: data.optimize, - }); + const response = await axios.post( + import.meta.env.VITE_MOLECULAR_BACKEND_URL + "/convert", + { + text: data.inputText, + format: data.inputFormat, + convert_3d: data.make_3d, + add_hydrogen: data.add_h, + optimize_geometry: data.optimize, + }, + ); // Response from the FastAPI JSONResponse return response.data.molfile; @@ -32,7 +33,9 @@ export async function GetInFormats(): Promise< { [key: string]: string } | AxiosError > { try { - const response = await axios.get(openbableBackendRoot + "/informats"); + const response = await axios.get( + import.meta.env.VITE_MOLECULAR_BACKEND_URL + "/informats", + ); return response.data; } catch (error) { //Error handling diff --git a/src/Api/Keycloak/Keycloak.tsx b/src/Api/Keycloak/Keycloak.tsx index 6e8eae9..57691e5 100644 --- a/src/Api/Keycloak/Keycloak.tsx +++ b/src/Api/Keycloak/Keycloak.tsx @@ -1,28 +1,97 @@ import axios from "axios"; -import { keycloakURI } from "GlobalVars"; -import Keycloak from "keycloak-js"; +import Keycloak, { type KeycloakProfile } from "keycloak-js"; +import { routes } from "Routes/Routes"; const keycloak = new Keycloak({ - url: keycloakURI, - realm: "dev-realm", + url: import.meta.env.VITE_KEYCLOAK_URL + ? import.meta.env.VITE_KEYCLOAK_URL + : "", + realm: "quant_sim-realm", clientId: "react-frontend", }); -const api = axios.create({ - baseURL: `${keycloak.authServerUrl}/realms/${keycloak.realm}`, -}); - export default keycloak; export async function getProfile(keycloak: Keycloak) { return keycloak.loadUserProfile(); } -export const handleSubmit = async (profile) => { +export const updateUserData = async ( + profile: KeycloakProfile, +): Promise => { try { - await api.put("/account", profile); - alert("Profile updated!"); + await keycloak.updateToken(30); + const response = await axios.post( + `${keycloak.authServerUrl}/realms/${keycloak.realm}/account/`, + { + firstName: profile.firstName, + lastName: profile.lastName, + email: profile.email, + username: profile.username, + attributes: profile.attributes || {}, + }, + { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${keycloak.token}`, + }, + withCredentials: true, // Important: allows credentials in CORS + }, + ); + if (response.status === 204) { + // Refresh the local profile after successful update + const updatedProfile = await keycloak.loadUserProfile(); + return updatedProfile; + } } catch (err) { console.error(err); } }; + +export const updatePasswordWithRedirect = async ( + successRedirectUrl?: string, +) => { + try { + await keycloak.updateToken(30); + + // Trigger the UPDATE_PASSWORD required action + // This will redirect the user to Keycloak's password change page + return keycloak.login({ + action: "UPDATE_PASSWORD", + redirectUri: + successRedirectUrl || + window.location.origin + + "/" + + import.meta.env.VITE_BASE_PATH + + "/" + + routes.SettingsPage.path + + "?password_updated=true", + // Optional: Force re-authentication + prompt: "login", + }); + } catch (error) { + console.error("Failed to initiate password update:", error); + throw error; + } +}; + +export const SendEmailVerification = async () => { + try { + await keycloak.updateToken(30); + + // Trigger the UPDATE_PASSWORD required action + // This will redirect the user to Keycloak's password change page + return keycloak.login({ + action: "VERIFY_EMAIL", + redirectUri: + window.location.origin + + import.meta.env.VITE_BASE_PATH + + "/" + + routes.SettingsPage.path + + "?email_sent=true", + }); + } catch (error) { + console.error("Failed to initiate password update:", error); + throw error; + } +}; diff --git a/src/Api/QuantumBackend/UserManagement.tsx b/src/Api/QuantumBackend/UserManagement.tsx new file mode 100644 index 0000000..50f59fd --- /dev/null +++ b/src/Api/QuantumBackend/UserManagement.tsx @@ -0,0 +1,52 @@ +import keycloak from "Api/Keycloak/Keycloak"; +import axios from "axios"; +import type { UserData } from "Types/User/User"; + +export const GetCurrentUserInfo = async (): Promise => { + try { + // Trigger the UPDATE_PASSWORD required action + // This will redirect the user to Keycloak's password change page + const response = await axios.get( + `${import.meta.env.VITE_QUANTUM_BACKEND_URL}/user`, + { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${keycloak.token}`, + }, + withCredentials: true, // Important: allows credentials in CORS + }, + ); + if (response.status === 200) { + return response.data; + } + } catch (error) { + console.error("Error Getting User Data", error); + throw error; + } +}; + +export const UpdateCurrentUserInfo = async ( + profile_picture_path: string, +): Promise => { + try { + // Trigger the UPDATE_PASSWORD required action + // This will redirect the user to Keycloak's password change page + const response = await axios.put( + `${import.meta.env.VITE_QUANTUM_BACKEND_URL}/user`, + { profile_picture_path: profile_picture_path }, + { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${keycloak.token}`, + }, + withCredentials: true, // Important: allows credentials in CORS + }, + ); + if (response.status === 200) { + return response.data; + } + } catch (error) { + console.error("Error Getting User Data", error); + throw error; + } +}; diff --git a/src/App.tsx b/src/App.tsx index 0b47732..536333b 100755 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,27 +7,17 @@ import "@mantine/notifications/styles.css"; import "@mantine/core/styles.css"; import { Notifications } from "@mantine/notifications"; import { useLayoutStore } from "Stores/LayoutStore"; -import { - defaultAnimationDuration, - headerHeight, - sideMenuWidth, -} from "GlobalVars"; import Sidebar from "Components/Layout/Sidebar/Sidebar"; import { Outlet, useLocation } from "react-router"; import { Helmet } from "react-helmet"; import { useEffect } from "react"; import { useMediaQuery } from "@mantine/hooks"; import BreadCrumbs from "Routes/Breadcrumbs/Breadcrumbs"; -import keycloak, { getProfile } from "Api/Keycloak/Keycloak"; +import keycloak from "Api/Keycloak/Keycloak"; import { AuthenticationStore } from "Stores/AuthenticationStore"; -import type { KeycloakProfile } from "keycloak-js"; -import { useNavigate } from "react-router"; - function App() { const { is_navbar_open, set_navbar_open } = useLayoutStore(); - const { set_token, set_profile } = AuthenticationStore(); - const navigate = useNavigate(); - + const { set_token } = AuthenticationStore(); const theme = useMantineTheme(); const location = useLocation(); @@ -70,9 +60,9 @@ function App() {
diff --git a/src/Components/CardWithButton/CardWithButton.tsx b/src/Components/CardWithButton/CardWithButton.tsx index 01652bc..e166851 100755 --- a/src/Components/CardWithButton/CardWithButton.tsx +++ b/src/Components/CardWithButton/CardWithButton.tsx @@ -1,4 +1,4 @@ -import { Card, Text, Button, Title, Space } from "@mantine/core"; +import { Card, Text, Space } from "@mantine/core"; import "./CardWithButton.css"; import { Link } from "react-router"; import CustomButton from "Components/CustomButton/CustomButton"; diff --git a/src/Components/CustomButton/CustomButton.css b/src/Components/CustomButton/CustomButton.css index ecb625a..dd1a3be 100644 --- a/src/Components/CustomButton/CustomButton.css +++ b/src/Components/CustomButton/CustomButton.css @@ -35,10 +35,11 @@ border-color: var(--color); background: transparent; color: var(--color); + --hover_color: color-mix(in srgb, var(--hovercolor) 20%, transparent); } .outline:hover { - background: color-mix(in srgb, var(--hovercolor) 20%, transparent); + background: var(--hover_color); } /* ###################### */ @@ -46,10 +47,11 @@ .color { background: var(--color); color: var(--textcolor); + --hover_color: var(--hovercolor); } .color:hover { - background-color: var(--hovercolor); + background-color: var(--hover_color); } .primary { @@ -98,8 +100,14 @@ .subtle { color: var(--color); + --hover_color: color-mix(in srgb, var(--color) 20%, transparent); } .subtle:hover { - background-color: color-mix(in srgb, var(--color) 20%, transparent); + background-color: --hover_color; +} + +.button-Disabled { + background-color: var(--hover_color); + cursor: inherit; } diff --git a/src/Components/CustomButton/CustomButton.tsx b/src/Components/CustomButton/CustomButton.tsx index 4df1d38..63297a9 100644 --- a/src/Components/CustomButton/CustomButton.tsx +++ b/src/Components/CustomButton/CustomButton.tsx @@ -34,7 +34,10 @@ function CustomButton({ console.log(color); return ( QMolSim diff --git a/src/Components/Layout/Sidebar/Sidebar.tsx b/src/Components/Layout/Sidebar/Sidebar.tsx index ed82bd3..806022a 100755 --- a/src/Components/Layout/Sidebar/Sidebar.tsx +++ b/src/Components/Layout/Sidebar/Sidebar.tsx @@ -1,6 +1,5 @@ import { Avatar, - Button, Divider, Modal, Stack, @@ -25,7 +24,6 @@ import { useState, type ForwardRefExoticComponent } from "react"; import { routes } from "Routes/Routes"; import keycloak from "Api/Keycloak/Keycloak"; import { AuthenticationStore } from "Stores/AuthenticationStore"; -import { baseUri, baseUrl } from "GlobalVars"; import CustomButton from "Components/CustomButton/CustomButton"; interface SubtleLinkButtonProps { @@ -69,7 +67,12 @@ function Sidebar() {
keycloak.logout({ redirectUri: baseUri + baseUrl })} + onClick={() => + keycloak.logout({ + redirectUri: + window.location.origin + "/" + import.meta.env.VITE_BASE_PATH, + }) + } textSize="lg" color="contrast" > diff --git a/src/Components/PaginationContainer/PaginationContainer.tsx b/src/Components/PaginationContainer/PaginationContainer.tsx index c1231bb..aa02010 100644 --- a/src/Components/PaginationContainer/PaginationContainer.tsx +++ b/src/Components/PaginationContainer/PaginationContainer.tsx @@ -2,11 +2,17 @@ import { Pagination } from "@mantine/core"; import "./PaginationContainer.css"; import type { PropsWithChildren } from "react"; -export function PaginationContainer(a: PropsWithChildren) { +interface PaginationContainerProps extends PropsWithChildren { + numberOfPages: number; +} + +export function PaginationContainer(a: PaginationContainerProps) { return (
{a.children}
- + {a.numberOfPages > 1 && ( + + )}
); } diff --git a/src/GlobalVars.ts b/src/GlobalVars.ts deleted file mode 100755 index e5a4244..0000000 --- a/src/GlobalVars.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const baseUrl = "/quantum"; -export const baseDomain = "localhost"; -export const basePort = 8001; -export const keycloakURI = "http://auth.localhost"; -export const baseUri = `http://${baseDomain}:${basePort}`; -//AppShell vars -export const headerHeight = 50; -export const sideMenuWidth = 280; - -// Global Style vars -export const defaultAnimationDuration = 100; diff --git a/src/Modals/NewExperiment/NewExperiment.css b/src/Modals/NewExperiment/NewExperiment.css index e69de29..19f9ceb 100755 --- a/src/Modals/NewExperiment/NewExperiment.css +++ b/src/Modals/NewExperiment/NewExperiment.css @@ -0,0 +1,4 @@ +.MantineInput { + background-color: var(--mantine-color-secondary-filled); + color: var(--mantine-color-contrast-filled) !important; +} diff --git a/src/Modals/NewExperiment/NewExperiment.tsx b/src/Modals/NewExperiment/NewExperiment.tsx index f6e0013..d150c77 100755 --- a/src/Modals/NewExperiment/NewExperiment.tsx +++ b/src/Modals/NewExperiment/NewExperiment.tsx @@ -1,5 +1,4 @@ import { - Button, Center, Modal, Select, @@ -7,9 +6,8 @@ import { Textarea, TextInput, Title, - UnstyledButton, } from "@mantine/core"; -import { useEffect, useState, type ChangeEvent } from "react"; +import { useEffect, useState } from "react"; import "./NewExperiment.css"; import { useExperimentStore } from "Stores/ExperimentStore"; import CustomButton from "Components/CustomButton/CustomButton"; @@ -68,6 +66,7 @@ export function NewExperimentModal(props: NewExperimentModalProps) { label="Имя эксперимента" placeholder="Введите имя эксперимента" required + classNames={{ input: "MantineInput" }} onChange={(event) => { setName(event.currentTarget.value); }} @@ -80,6 +79,7 @@ export function NewExperimentModal(props: NewExperimentModalProps) { minRows={4} maxRows={10} autosize + classNames={{ input: "MantineInput" }} onChange={(event) => { setDescription(event.currentTarget.value); }} @@ -91,6 +91,7 @@ export function NewExperimentModal(props: NewExperimentModalProps) { placeholder="Выберите команду эксперимента" searchable data={[]} + classNames={{ input: "MantineInput" }} onChange={() => {}} /> diff --git a/src/Pages/DevicesPage/DevicesPage.css b/src/Pages/DevicesPage/DevicesPage.css new file mode 100644 index 0000000..e69de29 diff --git a/src/Pages/DevicesPage/DevicesPage.tsx b/src/Pages/DevicesPage/DevicesPage.tsx new file mode 100644 index 0000000..18eacb4 --- /dev/null +++ b/src/Pages/DevicesPage/DevicesPage.tsx @@ -0,0 +1,31 @@ +import { Helmet } from "react-helmet"; +import "./DevicesPage.css"; +import { PaginationContainer } from "Components/PaginationContainer/PaginationContainer"; +import { Alert } from "@mantine/core"; +import { Link } from "react-router"; + +function DevicesPage() { + return ( + <> + + Device Page | QMolSim + + +
+ + + Для того, чтобы добавить устройство, простмотрите{" "} + + документацию + + + +
+ + ); +} + +export default DevicesPage; diff --git a/src/Pages/DocumentationPage/DocumentationPage.css b/src/Pages/DocumentationPage/DocumentationPage.css index 539770c..867e2b3 100755 --- a/src/Pages/DocumentationPage/DocumentationPage.css +++ b/src/Pages/DocumentationPage/DocumentationPage.css @@ -1,26 +1,26 @@ -.DocumentationPage { - display: flex; - flex-direction: row-reverse; - justify-content: space-between; - padding-top: 25px; -} - -.contents { - flex-grow: 1; -} - -.tableOfContents { - position: sticky; - top: 60px; - width: 150px; - height: min-content; -} - -.docTitle { - padding-bottom: 50px; -} - -.hoverCard { - position: fixed; - bottom: 10px; -} +.DocumentationPage { + display: flex; + flex-direction: row-reverse; + justify-content: space-between; + padding-top: 25px; +} + +.contents { + flex-grow: 1; +} + +.tableOfContents { + position: sticky; + top: 60px; + width: 190px; + height: min-content; +} + +.docTitle { + padding-bottom: 50px; +} + +.hoverCard { + position: fixed; + bottom: 10px; +} diff --git a/src/Pages/DocumentationPage/DocumentationPage.tsx b/src/Pages/DocumentationPage/DocumentationPage.tsx index b1a452d..a65dcb2 100755 --- a/src/Pages/DocumentationPage/DocumentationPage.tsx +++ b/src/Pages/DocumentationPage/DocumentationPage.tsx @@ -1,13 +1,5 @@ -import { - ActionIcon, - Box, - Divider, - Menu, - TableOfContents, - Title, -} from "@mantine/core"; +import { Box, Divider, TableOfContents, Title } from "@mantine/core"; import "./DocumentationPage.css"; -import { IconMenu2 } from "@tabler/icons-react"; import { Helmet } from "react-helmet"; function DocumentationPage() { @@ -31,9 +23,12 @@ function DocumentationPage() { color="accent" size="sm" radius="sm" + minDepthToOffset={0} + depthOffset={20} scrollSpyOptions={{ - selector: "section h2", + selector: "section h1, h2", }} + className="" getControlProps={({ data }) => ({ onClick: () => data @@ -43,56 +38,12 @@ function DocumentationPage() { })} /> - - - - - - - - - ({ - onClick: () => - data - .getNode() - .scrollIntoView({ behavior: "smooth", block: "center" }), - children: data.value, - })} - /> - - -
- Introduction + 1. Введение
-
- features -
-
- Conslusion +
+ 1.1 Быстрое начало
diff --git a/src/Pages/ExperimentsPage/ExperimentPage.tsx b/src/Pages/ExperimentsPage/ExperimentPage.tsx index c395437..0a3b9f6 100644 --- a/src/Pages/ExperimentsPage/ExperimentPage.tsx +++ b/src/Pages/ExperimentsPage/ExperimentPage.tsx @@ -74,9 +74,9 @@ function ExperimentPage() { {experiment.tasks_ids.length > 0 && ( - - {experiment.tasks_ids.map((task: ExperimentTask) => { - return
{task.data.name}
; + + {experiment.tasks_ids.map((task: number) => { + return
{task}
; })}
)} @@ -95,7 +95,7 @@ function ExperimentPage() {
{" "} - + Ошибка. Эксперимент не найден {" "}
diff --git a/src/Pages/ExperimentsPage/ExperimentsPage.tsx b/src/Pages/ExperimentsPage/ExperimentsPage.tsx index 43b6182..4f3076d 100644 --- a/src/Pages/ExperimentsPage/ExperimentsPage.tsx +++ b/src/Pages/ExperimentsPage/ExperimentsPage.tsx @@ -8,10 +8,11 @@ import ExperimentsListCard from "Components/ListCard/ExperimentsListCard"; import { useExperimentStore } from "Stores/ExperimentStore"; import type { Experiment } from "Types/Experiment/Experiment"; import CustomButton from "Components/CustomButton/CustomButton"; +import { Alert } from "@mantine/core"; function ExperimentsPage() { const [isOpen, setIsOpen] = useState(false); - const { experiments, teams, tasks } = useExperimentStore(); + const { experiments, teams } = useExperimentStore(); return ( <> @@ -32,18 +33,20 @@ function ExperimentsPage() { marginBottom: "20px", }} > -
- { - setIsOpen(true); - }} - icon={} - text="Создать эксперимент" - /> -
+ {teams.length > 0 && ( +
+ { + setIsOpen(true); + }} + icon={} + text="Создать эксперимент" + /> +
+ )} - + {experiments.map((exp: Experiment) => { return ( ); })} + {teams.length == 0 && ( + + Создайте или войдите в команду чтобы начать работу с + экспериментами + + )} diff --git a/src/Pages/TeamsPage/TeamsPage.css b/src/Pages/TeamsPage/TeamsPage.css index 6bea27a..c5247d8 100644 --- a/src/Pages/TeamsPage/TeamsPage.css +++ b/src/Pages/TeamsPage/TeamsPage.css @@ -1,4 +1,6 @@ .TeamsPage { flex-grow: 1; display: flex; + flex-direction: column; + gap: 10px; } diff --git a/src/Pages/TeamsPage/TeamsPage.tsx b/src/Pages/TeamsPage/TeamsPage.tsx index 2f753a5..1a10fde 100644 --- a/src/Pages/TeamsPage/TeamsPage.tsx +++ b/src/Pages/TeamsPage/TeamsPage.tsx @@ -1,8 +1,14 @@ import { Helmet } from "react-helmet"; import "./TeamsPage.css"; import { PaginationContainer } from "Components/PaginationContainer/PaginationContainer"; +import CustomButton from "Components/CustomButton/CustomButton"; +import { IconUsersGroup } from "@tabler/icons-react"; +import { useState } from "react"; +import { Alert } from "@mantine/core"; function TeamsPage() { + const [, setIsOpen] = useState(false); + return ( <> @@ -13,7 +19,21 @@ function TeamsPage() { />
- +
+ { + setIsOpen(true); + }} + icon={} + text="Создать эксперимент" + /> +
+ + + Создайте или войдите в команду чтобы начать работу с экспериментами + +
); diff --git a/src/Pages/UserPage/UserPage.tsx b/src/Pages/UserPage/UserPage.tsx index aee6641..f45db61 100644 --- a/src/Pages/UserPage/UserPage.tsx +++ b/src/Pages/UserPage/UserPage.tsx @@ -1,13 +1,12 @@ import { - Button, Title, Tabs, TextInput, SimpleGrid, - Chip, - Text, Divider, Switch, + LoadingOverlay, + Space, } from "@mantine/core"; import { IconChartCandle, @@ -17,20 +16,98 @@ import { IconSun, IconMoonStars, } from "@tabler/icons-react"; -import keycloak from "Api/Keycloak/Keycloak"; -import { useEffect } from "react"; +import keycloak, { + SendEmailVerification, + updatePasswordWithRedirect, + updateUserData, +} from "Api/Keycloak/Keycloak"; +import { useEffect, useState } from "react"; import { Helmet } from "react-helmet"; import { AuthenticationStore } from "Stores/AuthenticationStore"; import "./UserPage.css"; import { useUserPreferencesStore } from "Stores/PreferencesStore"; import CustomButton from "Components/CustomButton/CustomButton"; +import { notifications } from "@mantine/notifications"; +import { useSearchParams } from "react-router"; +import { + GetCurrentUserInfo, + UpdateCurrentUserInfo, +} from "Api/QuantumBackend/UserManagement"; +import type { UserData } from "Types/User/User"; function UserPage() { - const { profile, token } = AuthenticationStore(); + const { profile, is_loading, profile_picture_path } = AuthenticationStore(); const { theme, set_theme } = useUserPreferencesStore(); + const [username, set_username] = useState(""); + const [email, set_email] = useState(""); + const [pfp_path, set_pfp_path] = useState(""); + const [is_editing_path, set_is_editing_path] = useState(false); + const [searchParams] = useSearchParams(); + + const updateData = () => { + if ( + profile && + ((profile.username && profile.username != username) || + (profile.email && profile.email != email)) + ) { + console.log("A"); + const prof_1 = profile; + prof_1.email = email; + prof_1.username = username; + AuthenticationStore.setState({ + is_loading: true, + }); + updateUserData(prof_1).then((data) => { + console.log(data); + if (data) { + notifications.show({ + radius: "md", + title: "Данные успешно изменены", + message: "", + icon: , + style: { paddingLeft: "5px" }, + }); + keycloak.loadUserProfile().then((profile) => { + AuthenticationStore.setState({ + is_loading: false, + profile: profile, + }); + }); + } + }); + } + }; + + const update_pfp = async () => { + UpdateCurrentUserInfo(pfp_path).then(() => { + GetCurrentUserInfo().then((info: UserData | undefined) => { + if (info && info.profile_picture_path) + AuthenticationStore.setState({ + profile_picture_path: info.profile_picture_path, + }); + }); + }); + }; useEffect(() => { - console.log(token); - }, []); + if (profile) { + if (profile.username) set_username(profile.username); + if (profile.email) set_email(profile.email); + if (searchParams.get("password_updated")) { + notifications.show({ + radius: "md", + title: "Пароль изменен успешно", + message: "", + icon: , + style: { paddingLeft: "5px" }, + }); + } + } + }, [profile, searchParams]); + + useEffect(() => { + if (profile_picture_path) set_pfp_path(profile_picture_path); + }, [profile_picture_path]); + return ( <> @@ -68,92 +145,223 @@ function UserPage() { - - Имя пользователя: - - Почта: - - - - - - - - Почта верифицирована:{" "} - <Chip mx="lg" size="auto" checked={profile?.emailVerified}> - {profile?.emailVerified ? ( - <div - style={{ - display: "flex", - justifyContent: "center", - alignItems: "center", - }} - > - <IconCheck - size={25} - color={"green"} - style={{ verticalAlign: "center", margin: "5px" }} - /> - </div> - ) : ( - <div - style={{ - display: "flex", - justifyContent: "center", - alignItems: "center", - }} - > - <IconCancel - size={25} - color="red" + <div + style={{ position: "relative", padding: "5px", height: "100%" }} + > + <LoadingOverlay + visible={is_loading} + zIndex={1000} + overlayProps={{ radius: "sm", blur: 2 }} + loaderProps={{ size: 50, type: "dots" }} + /> + <SimpleGrid verticalSpacing="lg" cols={2}> + <Title size="lg">Имя пользователя: + set_username(e.currentTarget.value)} + /> + Почта: + set_email(e.currentTarget.value)} + /> + + + + + + + + Почта верифицирована:{" "} + <div> + {profile?.emailVerified ? ( + <div style={{ - verticalAlign: "center", - margin: "5px", + display: "flex", + justifyContent: "center", + alignItems: "center", + }} + > + <IconCheck + size={25} + color={"white"} + style={{ verticalAlign: "center", margin: "5px" }} + /> + </div> + ) : ( + <div + style={{ + display: "flex", + justifyContent: "center", + alignItems: "center", + }} + > + <IconCancel + size={25} + color="red" + style={{ + verticalAlign: "center", + margin: "5px", + }} + /> + </div> + )} + </div> + + {!profile?.emailVerified && ( +
+ SendEmailVerification()} + /> +
+ )} + {profile?.emailVerified && ( +
+ )} + Пароль: +
+ { + updatePasswordWithRedirect(); + }} + /> +
+
+ +
+ Фотография профиля + + + {!is_editing_path ? ( + + ) : ( + set_pfp_path(e.currentTarget.value)} + /> + )} + +
+ {!is_editing_path ? ( + { + set_is_editing_path(true); + }} + /> + ) : ( + <> + { + update_pfp(); + set_is_editing_path(false); }} /> -
+ + { + set_is_editing_path(false); + set_pfp_path(profile_picture_path); + }} + /> + )} - - - {!profile?.emailVerified && ( - - )} - {profile?.emailVerified &&
} - Пароль: - - +
+ +
set_theme(!event.currentTarget.checked ? "dark" : "light") } onLabel={ - +
+ + Светлая +
} offLabel={ - +
+ Темная + +
} />
diff --git a/src/Routes/Breadcrumbs/Breadcrumbs.tsx b/src/Routes/Breadcrumbs/Breadcrumbs.tsx index 97d6845..b6d97ed 100755 --- a/src/Routes/Breadcrumbs/Breadcrumbs.tsx +++ b/src/Routes/Breadcrumbs/Breadcrumbs.tsx @@ -1,6 +1,6 @@ import { Breadcrumbs } from "@mantine/core"; import { type ReactElement } from "react"; -import { Link, type UIMatch } from "react-router"; +import { Link } from "react-router"; import "./Breadcrumbs.css"; import { routes } from "Routes/Routes"; import { useLocation } from "react-router"; diff --git a/src/Routes/RouterAuhGuard.tsx b/src/Routes/RouterAuhGuard.tsx index 664937c..ba93263 100644 --- a/src/Routes/RouterAuhGuard.tsx +++ b/src/Routes/RouterAuhGuard.tsx @@ -10,7 +10,7 @@ export default function AuthGuard() { loginStarted.current = true; keycloak.login({ - redirectUri: window.location.href, + redirectUri: window.location.origin, }); } }, []); diff --git a/src/Routes/Routes.tsx b/src/Routes/Routes.tsx index 1ff4f0d..8b76df7 100755 --- a/src/Routes/Routes.tsx +++ b/src/Routes/Routes.tsx @@ -1,6 +1,5 @@ import { createBrowserRouter } from "react-router"; import MainPage from "Pages/MainPage/MainPage"; -import { baseUrl } from "../GlobalVars"; import App from "../App"; import ErrorPage from "./ErrorPage"; import DocumentationPage from "Pages/DocumentationPage/DocumentationPage"; @@ -12,6 +11,7 @@ import UserPage from "Pages/UserPage/UserPage"; import ExperimentPage from "Pages/ExperimentsPage/ExperimentPage"; import ExperimentsPage from "Pages/ExperimentsPage/ExperimentsPage"; import AuthGuard from "./RouterAuhGuard"; +import DevicesPage from "Pages/DevicesPage/DevicesPage"; export const routes: { [id: string]: { path: string; breadcrumbs: (path: string) => ReactElement[] }; @@ -66,7 +66,7 @@ const router = createBrowserRouter( }, { - element: , // 🔒 everything below requires auth + element: , children: [ { path: routes.ExperimentsPage.path, @@ -84,6 +84,10 @@ const router = createBrowserRouter( path: routes.TeamsPage.path, Component: TeamsPage, }, + { + path: routes.MachinesPage.path, + Component: DevicesPage, + }, ], }, @@ -94,6 +98,6 @@ const router = createBrowserRouter( ], }, ], - { basename: baseUrl }, + { basename: import.meta.env.VITE_BASE_PATH }, ); export default router; diff --git a/src/Stores/AuthenticationStore.tsx b/src/Stores/AuthenticationStore.tsx index c81a3a4..4e74022 100644 --- a/src/Stores/AuthenticationStore.tsx +++ b/src/Stores/AuthenticationStore.tsx @@ -2,18 +2,24 @@ import type { KeycloakProfile } from "keycloak-js"; import { create } from "zustand"; interface AuthernticationStoreState { - token: string | undefined; + is_loading: boolean; profile: KeycloakProfile | null; + profile_picture_path: string; set_profile: (profile: KeycloakProfile | null) => void; - set_token: (token: string | undefined) => void; + set_profile_picture_path: (path: string) => void; + set_is_loading: (is_loading: boolean) => void; } export const AuthenticationStore = create()( (set) => ({ - token: undefined, + is_loading: true, profile: null, + profile_picture_path: "", set_profile: (profile: KeycloakProfile | null) => set(() => ({ profile: profile })), - set_token: (token: string | undefined) => set(() => ({ token: token })), + set_is_loading: (is_loading: boolean) => + set(() => ({ is_loading: is_loading })), + set_profile_picture_path: (path: string) => + set(() => ({ profile_picture_path: path })), }), ); diff --git a/src/Types/Experiment/Experiment.tsx b/src/Types/Experiment/Experiment.tsx index 0581dd6..3ebe111 100755 --- a/src/Types/Experiment/Experiment.tsx +++ b/src/Types/Experiment/Experiment.tsx @@ -1,7 +1,3 @@ -//export interface Experiment {} - -import type { Team } from "Types/User/User"; - export type ExperimentStatus = | "DRAFT" | "QUEUE" diff --git a/src/Types/User/User.tsx b/src/Types/User/User.tsx index 9137ff5..8022158 100644 --- a/src/Types/User/User.tsx +++ b/src/Types/User/User.tsx @@ -18,3 +18,11 @@ export interface Permission { id: number; name: string; } + +export interface UserData { + keycloak_id: string; + email: string; + username: string; + profile_picture_path: string | null; + created_at: Date; +} diff --git a/src/main.tsx b/src/main.tsx index 249d635..d3c0679 100755 --- a/src/main.tsx +++ b/src/main.tsx @@ -13,6 +13,9 @@ import { import keycloak from "Api/Keycloak/Keycloak"; import { AuthenticationStore } from "Stores/AuthenticationStore"; import { useUserPreferencesStore } from "Stores/PreferencesStore"; +import type { KeycloakProfile } from "keycloak-js"; +import { GetCurrentUserInfo } from "Api/QuantumBackend/UserManagement"; +import type { UserData } from "Types/User/User"; const colorSchemeManager = localStorageColorSchemeManager({ key: "my-app-color-scheme", @@ -60,18 +63,39 @@ const theme = createTheme({ }); async function bootstrap() { - const authenticated = await keycloak.init({ - onLoad: "check-sso", - pkceMethod: "S256", - silentCheckSsoRedirectUri: - "http://localhost:8001/quantum/silent-check-sso.html", - }); - - if (authenticated) { - const profile = await keycloak.loadUserProfile(); - - AuthenticationStore.setState({ token: keycloak.token, profile: profile }); - } + AuthenticationStore.setState({ is_loading: true }); + keycloak + .init({ + onLoad: "check-sso", + pkceMethod: "S256", + silentCheckSsoRedirectUri: + window.location.origin + + "/" + + import.meta.env.VITE_BASE_PATH + + "/silent-check-sso.html", + silentCheckSsoFallback: false, + }) + .then((authenticated: boolean) => { + if (authenticated) { + keycloak.loadUserProfile().then((profile: KeycloakProfile) => { + AuthenticationStore.setState({ + is_loading: false, + profile: profile, + }); + GetCurrentUserInfo().then((info: UserData | undefined) => { + if (info && info.profile_picture_path) + AuthenticationStore.setState({ + profile_picture_path: info.profile_picture_path, + }); + }); + }); + } else { + console.log("Keycloak authentication failed."); + AuthenticationStore.setState({ + is_loading: false, + }); + } + }); useUserPreferencesStore.setState({ theme: checkIsDarkSchemePreferred() ? "dark" : "light", @@ -80,7 +104,7 @@ async function bootstrap() { createRoot(document.getElementById("root")!).render(); } -function AppProviders() { +export function AppProviders() { const themePreference = useUserPreferencesStore((state) => state.theme); return ( diff --git a/vite.config.ts b/vite.config.ts index c8998d3..6ab8980 100755 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,14 +1,33 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import tsconfigPaths from "vite-tsconfig-paths"; -import { baseDomain, basePort, baseUrl } from "./src/GlobalVars"; +import dotenv from "dotenv"; +dotenv.config(); // https://vite.dev/config/ export default defineConfig({ plugins: [react(), tsconfigPaths()], server: { - host: baseDomain, - port: basePort, + host: process.env.VITE_HOSTNAME, + port: Number(process.env.VITE_PORT), + }, + preview: { + port: Number(process.env.VITE_PORT), + }, + base: "/" + process.env.VITE_BASE_PATH, + build: { + rollupOptions: { + output: { + manualChunks(id) { + if (id.includes("node_modules")) { + return id + .toString() + .split("node_modules/")[1] + .split("/")[0] + .toString(); + } + }, + }, + }, }, - base: baseUrl, });