diff --git a/.github/workflows/build-and-push.yaml b/.github/workflows/build-and-push.yaml index 77b69afb..3a4632fe 100644 --- a/.github/workflows/build-and-push.yaml +++ b/.github/workflows/build-and-push.yaml @@ -75,6 +75,4 @@ jobs: context: . file: ./Dockerfile push: true - tags: ${{ steps.metadata.outputs.tags }} - build-args: | - BASE_IMAGE=${{ env.REGISTRY }}/base-image:latest \ No newline at end of file + tags: ${{ steps.metadata.outputs.tags }} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 10d7844c..9769d216 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,12 +11,14 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", - "@mui/material": "^5.15.12", + "@mui/material": "^5.15.14", "@statisticsnorway/ssb-component-library": "^2.0.98", "dotenv": "^16.4.5", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "express": "4.18.3", + "express": "4.19.1", + "express-http-proxy": "^2.0.0", + "http-proxy-middleware": "^2.0.6", "http-status-codes": "^2.3.0", "jsonwebtoken": "^9.0.2", "jwks-rsa": "^3.1.0", @@ -27,20 +29,20 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-responsive": "^9.0.2", - "react-router-dom": "^6.22.2", + "react-router-dom": "^6.22.3", "vite-express": "0.15.0" }, "devDependencies": { - "@types/react": "^18.2.64", - "@types/react-dom": "^18.2.20", - "@typescript-eslint/eslint-plugin": "^7.0.0", - "@typescript-eslint/parser": "^6.21.0", + "@types/react": "^18.2.69", + "@types/react-dom": "^18.2.22", + "@typescript-eslint/eslint-plugin": "^7.3.1", + "@typescript-eslint/parser": "^7.3.1", "@vitejs/plugin-react-swc": "^3.6.0", "eslint": "^8.57.0", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.5", - "typescript": "^5.2.2", - "vite": "^5.1.5" + "eslint-plugin-react-refresh": "^0.4.6", + "typescript": "^5.4.3", + "vite": "^5.2.6" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -397,9 +399,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz", - "integrity": "sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", "cpu": [ "ppc64" ], @@ -412,9 +414,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.11.tgz", - "integrity": "sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", "cpu": [ "arm" ], @@ -427,9 +429,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz", - "integrity": "sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", "cpu": [ "arm64" ], @@ -442,9 +444,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.11.tgz", - "integrity": "sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", "cpu": [ "x64" ], @@ -457,9 +459,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz", - "integrity": "sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", "cpu": [ "arm64" ], @@ -472,9 +474,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz", - "integrity": "sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", "cpu": [ "x64" ], @@ -487,9 +489,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz", - "integrity": "sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", "cpu": [ "arm64" ], @@ -502,9 +504,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz", - "integrity": "sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", "cpu": [ "x64" ], @@ -517,9 +519,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz", - "integrity": "sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", "cpu": [ "arm" ], @@ -532,9 +534,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz", - "integrity": "sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", "cpu": [ "arm64" ], @@ -547,9 +549,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz", - "integrity": "sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", "cpu": [ "ia32" ], @@ -562,9 +564,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz", - "integrity": "sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", "cpu": [ "loong64" ], @@ -577,9 +579,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz", - "integrity": "sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", "cpu": [ "mips64el" ], @@ -592,9 +594,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz", - "integrity": "sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", "cpu": [ "ppc64" ], @@ -607,9 +609,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz", - "integrity": "sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", "cpu": [ "riscv64" ], @@ -622,9 +624,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz", - "integrity": "sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", "cpu": [ "s390x" ], @@ -637,9 +639,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz", - "integrity": "sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", "cpu": [ "x64" ], @@ -652,9 +654,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz", - "integrity": "sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", "cpu": [ "x64" ], @@ -667,9 +669,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz", - "integrity": "sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", "cpu": [ "x64" ], @@ -682,9 +684,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz", - "integrity": "sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", "cpu": [ "x64" ], @@ -697,9 +699,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz", - "integrity": "sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", "cpu": [ "arm64" ], @@ -712,9 +714,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz", - "integrity": "sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", "cpu": [ "ia32" ], @@ -727,9 +729,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz", - "integrity": "sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", "cpu": [ "x64" ], @@ -946,14 +948,14 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==" }, "node_modules/@mui/base": { - "version": "5.0.0-beta.38", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.38.tgz", - "integrity": "sha512-AsjD6Y1X5A1qndxz8xCcR8LDqv31aiwlgWMPxFAX/kCKiIGKlK65yMeVZ62iQr/6LBz+9hSKLiD1i4TZdAHKcQ==", + "version": "5.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", + "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", "dependencies": { "@babel/runtime": "^7.23.9", "@floating-ui/react-dom": "^2.0.8", - "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.12", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", "@popperjs/core": "^2.11.8", "clsx": "^2.1.0", "prop-types": "^15.8.1" @@ -977,25 +979,25 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.15.12", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.12.tgz", - "integrity": "sha512-brRO+tMFLpGyjEYHrX97bzqeF6jZmKpqqe1rY0LyIHAwP6xRVzh++zSecOQorDOCaZJg4XkGT9xfD+RWOWxZBA==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.14.tgz", + "integrity": "sha512-on75VMd0XqZfaQW+9pGjSNiqW+ghc5E2ZSLRBXwcXl/C4YzjfyjrLPhrEpKnR9Uym9KXBvxrhoHfPcczYHweyA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/material": { - "version": "5.15.12", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.12.tgz", - "integrity": "sha512-vXJGg6KNKucsvbW6l7w9zafnpOp0CWc0Wx4mDykuABTpQ5QQBnZxP7+oB4yAS1hDZQ1WobbeIl0CjxK4EEahkA==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.14.tgz", + "integrity": "sha512-kEbRw6fASdQ1SQ7LVdWR5OlWV3y7Y54ZxkLzd6LV5tmz+NpO3MJKZXSfgR0LHMP7meKsPiMm4AuzV0pXDpk/BQ==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/base": "5.0.0-beta.38", - "@mui/core-downloads-tracker": "^5.15.12", - "@mui/system": "^5.15.12", - "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.12", + "@mui/base": "5.0.0-beta.40", + "@mui/core-downloads-tracker": "^5.15.14", + "@mui/system": "^5.15.14", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "csstype": "^3.1.3", @@ -1035,12 +1037,12 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/@mui/private-theming": { - "version": "5.15.12", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.12.tgz", - "integrity": "sha512-cqoSo9sgA5HE+8vZClbLrq9EkyOnYysooepi5eKaKvJ41lReT2c5wOZAeDDM1+xknrMDos+0mT2zr3sZmUiRRA==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz", + "integrity": "sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.15.12", + "@mui/utils": "^5.15.14", "prop-types": "^15.8.1" }, "engines": { @@ -1061,9 +1063,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.15.11", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.11.tgz", - "integrity": "sha512-So21AhAngqo07ces4S/JpX5UaMU2RHXpEA6hNzI6IQjd/1usMPxpgK8wkGgTe3JKmC2KDmH8cvoycq5H3Ii7/w==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz", + "integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==", "dependencies": { "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", @@ -1092,15 +1094,15 @@ } }, "node_modules/@mui/system": { - "version": "5.15.12", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.12.tgz", - "integrity": "sha512-/pq+GO6yN3X7r3hAwFTrzkAh7K1bTF5r8IzS79B9eyKJg7v6B/t4/zZYMR6OT9qEPtwf6rYN2Utg1e6Z7F1OgQ==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.14.tgz", + "integrity": "sha512-auXLXzUaCSSOLqJXmsAaq7P96VPRXg2Rrz6OHNV7lr+kB8lobUF+/N84Vd9C4G/wvCXYPs5TYuuGBRhcGbiBGg==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.15.12", - "@mui/styled-engine": "^5.15.11", - "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.12", + "@mui/private-theming": "^5.15.14", + "@mui/styled-engine": "^5.15.14", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1131,9 +1133,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.13", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz", - "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==", + "version": "7.2.14", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz", + "integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" }, @@ -1144,9 +1146,9 @@ } }, "node_modules/@mui/utils": { - "version": "5.15.12", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.12.tgz", - "integrity": "sha512-8SDGCnO2DY9Yy+5bGzu00NZowSDtuyHP4H8gunhHGQoIlhlY2Z3w64wBzAOLpYw/ZhJNzksDTnS/i8qdJvxuow==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz", + "integrity": "sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==", "dependencies": { "@babel/runtime": "^7.23.9", "@types/prop-types": "^15.7.11", @@ -1228,17 +1230,17 @@ } }, "node_modules/@remix-run/router": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz", - "integrity": "sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q==", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz", + "integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==", "engines": { "node": ">=14.0.0" } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.4.tgz", - "integrity": "sha512-ub/SN3yWqIv5CWiAZPHVS1DloyZsJbtXmX4HxUTIpS0BHm9pW5iYBo2mIZi+hE3AeiTzHz33blwSnhdUo+9NpA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", + "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", "cpu": [ "arm" ], @@ -1249,9 +1251,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.4.tgz", - "integrity": "sha512-ehcBrOR5XTl0W0t2WxfTyHCR/3Cq2jfb+I4W+Ch8Y9b5G+vbAecVv0Fx/J1QKktOrgUYsIKxWAKgIpvw56IFNA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", + "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", "cpu": [ "arm64" ], @@ -1262,9 +1264,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.4.tgz", - "integrity": "sha512-1fzh1lWExwSTWy8vJPnNbNM02WZDS8AW3McEOb7wW+nPChLKf3WG2aG7fhaUmfX5FKw9zhsF5+MBwArGyNM7NA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", + "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", "cpu": [ "arm64" ], @@ -1275,9 +1277,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.4.tgz", - "integrity": "sha512-Gc6cukkF38RcYQ6uPdiXi70JB0f29CwcQ7+r4QpfNpQFVHXRd0DfWFidoGxjSx1DwOETM97JPz1RXL5ISSB0pA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", + "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", "cpu": [ "x64" ], @@ -1288,9 +1290,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.4.tgz", - "integrity": "sha512-g21RTeFzoTl8GxosHbnQZ0/JkuFIB13C3T7Y0HtKzOXmoHhewLbVTFBQZu+z5m9STH6FZ7L/oPgU4Nm5ErN2fw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", + "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", "cpu": [ "arm" ], @@ -1301,9 +1303,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.4.tgz", - "integrity": "sha512-TVYVWD/SYwWzGGnbfTkrNpdE4HON46orgMNHCivlXmlsSGQOx/OHHYiQcMIOx38/GWgwr/po2LBn7wypkWw/Mg==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", + "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", "cpu": [ "arm64" ], @@ -1314,9 +1316,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.4.tgz", - "integrity": "sha512-XcKvuendwizYYhFxpvQ3xVpzje2HHImzg33wL9zvxtj77HvPStbSGI9czrdbfrf8DGMcNNReH9pVZv8qejAQ5A==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", + "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", "cpu": [ "arm64" ], @@ -1327,9 +1329,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.4.tgz", - "integrity": "sha512-LFHS/8Q+I9YA0yVETyjonMJ3UA+DczeBd/MqNEzsGSTdNvSJa1OJZcSH8GiXLvcizgp9AlHs2walqRcqzjOi3A==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", + "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", "cpu": [ "riscv64" ], @@ -1340,9 +1342,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.4.tgz", - "integrity": "sha512-dIYgo+j1+yfy81i0YVU5KnQrIJZE8ERomx17ReU4GREjGtDW4X+nvkBak2xAUpyqLs4eleDSj3RrV72fQos7zw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", + "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", "cpu": [ "x64" ], @@ -1353,9 +1355,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.4.tgz", - "integrity": "sha512-RoaYxjdHQ5TPjaPrLsfKqR3pakMr3JGqZ+jZM0zP2IkDtsGa4CqYaWSfQmZVgFUCgLrTnzX+cnHS3nfl+kB6ZQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", + "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", "cpu": [ "x64" ], @@ -1366,9 +1368,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.4.tgz", - "integrity": "sha512-T8Q3XHV+Jjf5e49B4EAaLKV74BbX7/qYBRQ8Wop/+TyyU0k+vSjiLVSHNWdVd1goMjZcbhDmYZUYW5RFqkBNHQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", + "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", "cpu": [ "arm64" ], @@ -1379,9 +1381,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.4.tgz", - "integrity": "sha512-z+JQ7JirDUHAsMecVydnBPWLwJjbppU+7LZjffGf+Jvrxq+dVjIE7By163Sc9DKc3ADSU50qPVw0KonBS+a+HQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", + "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", "cpu": [ "ia32" ], @@ -1392,9 +1394,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.4.tgz", - "integrity": "sha512-LfdGXCV9rdEify1oxlN9eamvDSjv9md9ZVMAbNHA87xqIfFCxImxan9qZ8+Un54iK2nnqPlbnSi4R54ONtbWBw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", "cpu": [ "x64" ], @@ -1678,6 +1680,14 @@ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1726,9 +1736,9 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, "node_modules/@types/react": { - "version": "18.2.64", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.64.tgz", - "integrity": "sha512-MlmPvHgjj2p3vZaxbQgFUQFvD8QiZwACfGqEdDSWou5yISWxDQ4/74nCAwsUiX7UFLKZz3BbVSPj+YxeoGGCfg==", + "version": "18.2.69", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.69.tgz", + "integrity": "sha512-W1HOMUWY/1Yyw0ba5TkCV+oqynRjG7BnteBB+B7JmAK7iw3l2SW+VGOxL+akPweix6jk2NNJtyJKpn4TkpfK3Q==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1736,9 +1746,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.21", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.21.tgz", - "integrity": "sha512-gnvBA/21SA4xxqNXEwNiVcP0xSGHh/gi1VhWv9Bl46a0ItbTT5nFY+G9VSQpaG/8N/qdJpJ+vftQ4zflTtnjLw==", + "version": "18.2.22", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz", + "integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==", "dev": true, "dependencies": { "@types/react": "*" @@ -1783,16 +1793,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.0.tgz", - "integrity": "sha512-M72SJ0DkcQVmmsbqlzc6EJgb/3Oz2Wdm6AyESB4YkGgCxP8u5jt5jn4/OBMPK3HLOxcttZq5xbBBU7e2By4SZQ==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.3.1.tgz", + "integrity": "sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.0.0", - "@typescript-eslint/type-utils": "7.0.0", - "@typescript-eslint/utils": "7.0.0", - "@typescript-eslint/visitor-keys": "7.0.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/type-utils": "7.3.1", + "@typescript-eslint/utils": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1801,14 +1811,14 @@ "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "@typescript-eslint/parser": "^7.0.0", "eslint": "^8.56.0" }, "peerDependenciesMeta": { @@ -1817,74 +1827,27 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.0.tgz", - "integrity": "sha512-IxTStwhNDPO07CCrYuAqjuJ3Xf5MrMaNgbAZPxFXAUpAtwqFxiuItxUaVtP/SJQeCdJjwDGh9/lMOluAndkKeg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.0.0", - "@typescript-eslint/visitor-keys": "7.0.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.0.tgz", - "integrity": "sha512-9ZIJDqagK1TTs4W9IyeB2sH/s1fFhN9958ycW8NRTg1vXGzzH5PQNzq6KbsbVGMT+oyyfa17DfchHDidcmf5cg==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.0.tgz", - "integrity": "sha512-JZP0uw59PRHp7sHQl3aF/lFgwOW2rgNVnXUksj1d932PMita9wFBd3621vHQRDvHwPsSY9FMAAHVc8gTvLYY4w==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.0.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.3.1.tgz", + "integrity": "sha512-Rq49+pq7viTRCH48XAbTA+wdLRrB/3sRq4Lpk0oGDm0VmnjBrAOVXH/Laalmwsv2VpekiEfVFwJYVk6/e8uvQw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -1893,16 +1856,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.3.1.tgz", + "integrity": "sha512-fVS6fPxldsKY2nFvyT7IP78UO1/I2huG+AYu5AMjCT9wtl6JFiDnsv4uad4jQ0GTFzcUV5HShVeN96/17bTBag==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1910,18 +1873,18 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.0.tgz", - "integrity": "sha512-FIM8HPxj1P2G7qfrpiXvbHeHypgo2mFpFGoh5I73ZlqmJOsloSa1x0ZyXCer43++P1doxCgNqIOLqmZR6SOT8g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.3.1.tgz", + "integrity": "sha512-iFhaysxFsMDQlzJn+vr3OrxN8NmdQkHks4WaqD4QBnt5hsq234wcYdyQ9uquzJJIDAj5W4wQne3yEsYA6OmXGw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.0.0", - "@typescript-eslint/utils": "7.0.0", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/utils": "7.3.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1936,71 +1899,13 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.0.tgz", - "integrity": "sha512-9ZIJDqagK1TTs4W9IyeB2sH/s1fFhN9958ycW8NRTg1vXGzzH5PQNzq6KbsbVGMT+oyyfa17DfchHDidcmf5cg==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.0.tgz", - "integrity": "sha512-JzsOzhJJm74aQ3c9um/aDryHgSHfaX8SHFIu9x4Gpik/+qxLvxUylhTsO9abcNu39JIdhY2LgYrFxTii3IajLA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.0.0", - "@typescript-eslint/visitor-keys": "7.0.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.0.tgz", - "integrity": "sha512-JZP0uw59PRHp7sHQl3aF/lFgwOW2rgNVnXUksj1d932PMita9wFBd3621vHQRDvHwPsSY9FMAAHVc8gTvLYY4w==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.0.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.3.1.tgz", + "integrity": "sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2008,13 +1913,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.3.1.tgz", + "integrity": "sha512-tLpuqM46LVkduWP7JO7yVoWshpJuJzxDOPYIVWUUZbW+4dBpgGeUdl/fQkhuV0A8eGnphYw3pp8d2EnvPOfxmQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2023,7 +1928,7 @@ "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2036,21 +1941,21 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.0.tgz", - "integrity": "sha512-kuPZcPAdGcDBAyqDn/JVeJVhySvpkxzfXjJq1X1BFSTYo1TTuo4iyb937u457q4K0In84p6u2VHQGaFnv7VYqg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.3.1.tgz", + "integrity": "sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.0.0", - "@typescript-eslint/types": "7.0.0", - "@typescript-eslint/typescript-estree": "7.0.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", "semver": "^7.5.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2060,92 +1965,17 @@ "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.0.tgz", - "integrity": "sha512-IxTStwhNDPO07CCrYuAqjuJ3Xf5MrMaNgbAZPxFXAUpAtwqFxiuItxUaVtP/SJQeCdJjwDGh9/lMOluAndkKeg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.0.0", - "@typescript-eslint/visitor-keys": "7.0.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.0.tgz", - "integrity": "sha512-9ZIJDqagK1TTs4W9IyeB2sH/s1fFhN9958ycW8NRTg1vXGzzH5PQNzq6KbsbVGMT+oyyfa17DfchHDidcmf5cg==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.0.tgz", - "integrity": "sha512-JzsOzhJJm74aQ3c9um/aDryHgSHfaX8SHFIu9x4Gpik/+qxLvxUylhTsO9abcNu39JIdhY2LgYrFxTii3IajLA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.0.0", - "@typescript-eslint/visitor-keys": "7.0.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.0.tgz", - "integrity": "sha512-JZP0uw59PRHp7sHQl3aF/lFgwOW2rgNVnXUksj1d932PMita9wFBd3621vHQRDvHwPsSY9FMAAHVc8gTvLYY4w==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.0.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.1.tgz", + "integrity": "sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/types": "7.3.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2829,10 +2659,15 @@ "node": ">= 0.4" } }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, "node_modules/esbuild": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.11.tgz", - "integrity": "sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -2841,29 +2676,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.11", - "@esbuild/android-arm": "0.19.11", - "@esbuild/android-arm64": "0.19.11", - "@esbuild/android-x64": "0.19.11", - "@esbuild/darwin-arm64": "0.19.11", - "@esbuild/darwin-x64": "0.19.11", - "@esbuild/freebsd-arm64": "0.19.11", - "@esbuild/freebsd-x64": "0.19.11", - "@esbuild/linux-arm": "0.19.11", - "@esbuild/linux-arm64": "0.19.11", - "@esbuild/linux-ia32": "0.19.11", - "@esbuild/linux-loong64": "0.19.11", - "@esbuild/linux-mips64el": "0.19.11", - "@esbuild/linux-ppc64": "0.19.11", - "@esbuild/linux-riscv64": "0.19.11", - "@esbuild/linux-s390x": "0.19.11", - "@esbuild/linux-x64": "0.19.11", - "@esbuild/netbsd-x64": "0.19.11", - "@esbuild/openbsd-x64": "0.19.11", - "@esbuild/sunos-x64": "0.19.11", - "@esbuild/win32-arm64": "0.19.11", - "@esbuild/win32-ia32": "0.19.11", - "@esbuild/win32-x64": "0.19.11" + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" } }, "node_modules/escape-html": { @@ -2989,9 +2824,9 @@ } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.5.tgz", - "integrity": "sha512-D53FYKJa+fDmZMtriODxvhwrO+IOqrxoEo21gMA0sjHdU6dPVH4OhyFip9ypl8HOF5RV5KdTo+rBQLvnY2cO8w==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.6.tgz", + "integrity": "sha512-NjGXdm7zgcKRkKMua34qVO9doI7VOxZ6ancSvBELJSSoX97jyndXcSoa8XBh69JoB31dNz3EEzlMcizZl7LaMA==", "dev": true, "peerDependencies": { "eslint": ">=7" @@ -3113,6 +2948,11 @@ "node": ">=6" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -3122,16 +2962,16 @@ } }, "node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.1.tgz", + "integrity": "sha512-K4w1/Bp7y8iSiVObmCrtq8Cs79XjJc/RU2YYkZQ7wpUu5ZyZ7MtPHkqoMz4pf+mgXfNvo2qft8D9OnrH2ABk9w==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -3162,6 +3002,35 @@ "node": ">= 0.10.0" } }, + "node_modules/express-http-proxy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/express-http-proxy/-/express-http-proxy-2.0.0.tgz", + "integrity": "sha512-TXxcPFTWVUMSEmyM6iX2sT/JtmqhqngTq29P+eXTVFdtxZrTmM8THUYK59rUXiln0FfPGvxEpGRnVrgvHksXDw==", + "dependencies": { + "debug": "^3.0.1", + "es6-promise": "^4.1.1", + "raw-body": "^2.3.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/express-http-proxy/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -3433,6 +3302,25 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3668,6 +3556,42 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, "node_modules/http-status-codes": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", @@ -3833,15 +3757,26 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/jose": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", - "integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==", + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", + "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==", "funding": { "url": "https://github.com/sponsors/panva" } @@ -4156,7 +4091,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -4551,9 +4485,9 @@ "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==" }, "node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "dev": true, "funding": [ { @@ -4572,7 +4506,7 @@ "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -4789,11 +4723,11 @@ } }, "node_modules/react-router": { - "version": "6.22.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.2.tgz", - "integrity": "sha512-YD3Dzprzpcq+tBMHBS822tCjnWD3iIZbTeSXMY9LPSG541EfoBGyZ3bS25KEnaZjLcmQpw2AVLkFyfgXY8uvcw==", + "version": "6.22.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz", + "integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==", "dependencies": { - "@remix-run/router": "1.15.2" + "@remix-run/router": "1.15.3" }, "engines": { "node": ">=14.0.0" @@ -4803,12 +4737,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.22.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.2.tgz", - "integrity": "sha512-WgqxD2qySEIBPZ3w0sHH+PUAiamDeszls9tzqMPBDA1YYVucTBXLU7+gtRfcSnhe92A3glPnvSxK2dhNoAVOIQ==", + "version": "6.22.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz", + "integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==", "dependencies": { - "@remix-run/router": "1.15.2", - "react-router": "6.22.2" + "@remix-run/router": "1.15.3", + "react-router": "6.22.3" }, "engines": { "node": ">=14.0.0" @@ -4880,6 +4814,11 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -4954,9 +4893,9 @@ } }, "node_modules/rollup": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.4.tgz", - "integrity": "sha512-2ztU7pY/lrQyXSCnnoU4ICjT/tCG9cdH3/G25ERqE3Lst6vl2BCM5hL2Nw+sslAvAf+ccKsAq1SkKQALyqhR7g==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -4969,19 +4908,19 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.4", - "@rollup/rollup-android-arm64": "4.9.4", - "@rollup/rollup-darwin-arm64": "4.9.4", - "@rollup/rollup-darwin-x64": "4.9.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.4", - "@rollup/rollup-linux-arm64-gnu": "4.9.4", - "@rollup/rollup-linux-arm64-musl": "4.9.4", - "@rollup/rollup-linux-riscv64-gnu": "4.9.4", - "@rollup/rollup-linux-x64-gnu": "4.9.4", - "@rollup/rollup-linux-x64-musl": "4.9.4", - "@rollup/rollup-win32-arm64-msvc": "4.9.4", - "@rollup/rollup-win32-ia32-msvc": "4.9.4", - "@rollup/rollup-win32-x64-msvc": "4.9.4", + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", "fsevents": "~2.3.2" } }, @@ -5279,9 +5218,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "engines": { "node": ">=0.10.0" } @@ -5485,9 +5424,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5552,14 +5491,14 @@ } }, "node_modules/vite": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz", - "integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==", + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", + "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==", "dev": true, "dependencies": { - "esbuild": "^0.19.3", - "postcss": "^8.4.35", - "rollup": "^4.2.0" + "esbuild": "^0.20.1", + "postcss": "^8.4.36", + "rollup": "^4.13.0" }, "bin": { "vite": "bin/vite.js" @@ -5942,141 +5881,141 @@ "requires": {} }, "@esbuild/aix-ppc64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz", - "integrity": "sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", "optional": true }, "@esbuild/android-arm": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.11.tgz", - "integrity": "sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", "optional": true }, "@esbuild/android-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz", - "integrity": "sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", "optional": true }, "@esbuild/android-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.11.tgz", - "integrity": "sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz", - "integrity": "sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", "optional": true }, "@esbuild/darwin-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz", - "integrity": "sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz", - "integrity": "sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz", - "integrity": "sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", "optional": true }, "@esbuild/linux-arm": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz", - "integrity": "sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", "optional": true }, "@esbuild/linux-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz", - "integrity": "sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", "optional": true }, "@esbuild/linux-ia32": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz", - "integrity": "sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", "optional": true }, "@esbuild/linux-loong64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz", - "integrity": "sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz", - "integrity": "sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz", - "integrity": "sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz", - "integrity": "sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", "optional": true }, "@esbuild/linux-s390x": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz", - "integrity": "sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", "optional": true }, "@esbuild/linux-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz", - "integrity": "sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz", - "integrity": "sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz", - "integrity": "sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", "optional": true }, "@esbuild/sunos-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz", - "integrity": "sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", "optional": true }, "@esbuild/win32-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz", - "integrity": "sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", "optional": true }, "@esbuild/win32-ia32": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz", - "integrity": "sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", "optional": true }, "@esbuild/win32-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz", - "integrity": "sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", "optional": true }, "@eslint-community/eslint-utils": { @@ -6248,35 +6187,35 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==" }, "@mui/base": { - "version": "5.0.0-beta.38", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.38.tgz", - "integrity": "sha512-AsjD6Y1X5A1qndxz8xCcR8LDqv31aiwlgWMPxFAX/kCKiIGKlK65yMeVZ62iQr/6LBz+9hSKLiD1i4TZdAHKcQ==", + "version": "5.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", + "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", "requires": { "@babel/runtime": "^7.23.9", "@floating-ui/react-dom": "^2.0.8", - "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.12", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", "@popperjs/core": "^2.11.8", "clsx": "^2.1.0", "prop-types": "^15.8.1" } }, "@mui/core-downloads-tracker": { - "version": "5.15.12", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.12.tgz", - "integrity": "sha512-brRO+tMFLpGyjEYHrX97bzqeF6jZmKpqqe1rY0LyIHAwP6xRVzh++zSecOQorDOCaZJg4XkGT9xfD+RWOWxZBA==" + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.14.tgz", + "integrity": "sha512-on75VMd0XqZfaQW+9pGjSNiqW+ghc5E2ZSLRBXwcXl/C4YzjfyjrLPhrEpKnR9Uym9KXBvxrhoHfPcczYHweyA==" }, "@mui/material": { - "version": "5.15.12", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.12.tgz", - "integrity": "sha512-vXJGg6KNKucsvbW6l7w9zafnpOp0CWc0Wx4mDykuABTpQ5QQBnZxP7+oB4yAS1hDZQ1WobbeIl0CjxK4EEahkA==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.14.tgz", + "integrity": "sha512-kEbRw6fASdQ1SQ7LVdWR5OlWV3y7Y54ZxkLzd6LV5tmz+NpO3MJKZXSfgR0LHMP7meKsPiMm4AuzV0pXDpk/BQ==", "requires": { "@babel/runtime": "^7.23.9", - "@mui/base": "5.0.0-beta.38", - "@mui/core-downloads-tracker": "^5.15.12", - "@mui/system": "^5.15.12", - "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.12", + "@mui/base": "5.0.0-beta.40", + "@mui/core-downloads-tracker": "^5.15.14", + "@mui/system": "^5.15.14", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "csstype": "^3.1.3", @@ -6293,19 +6232,19 @@ } }, "@mui/private-theming": { - "version": "5.15.12", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.12.tgz", - "integrity": "sha512-cqoSo9sgA5HE+8vZClbLrq9EkyOnYysooepi5eKaKvJ41lReT2c5wOZAeDDM1+xknrMDos+0mT2zr3sZmUiRRA==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz", + "integrity": "sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==", "requires": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.15.12", + "@mui/utils": "^5.15.14", "prop-types": "^15.8.1" } }, "@mui/styled-engine": { - "version": "5.15.11", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.11.tgz", - "integrity": "sha512-So21AhAngqo07ces4S/JpX5UaMU2RHXpEA6hNzI6IQjd/1usMPxpgK8wkGgTe3JKmC2KDmH8cvoycq5H3Ii7/w==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz", + "integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==", "requires": { "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", @@ -6314,30 +6253,30 @@ } }, "@mui/system": { - "version": "5.15.12", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.12.tgz", - "integrity": "sha512-/pq+GO6yN3X7r3hAwFTrzkAh7K1bTF5r8IzS79B9eyKJg7v6B/t4/zZYMR6OT9qEPtwf6rYN2Utg1e6Z7F1OgQ==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.14.tgz", + "integrity": "sha512-auXLXzUaCSSOLqJXmsAaq7P96VPRXg2Rrz6OHNV7lr+kB8lobUF+/N84Vd9C4G/wvCXYPs5TYuuGBRhcGbiBGg==", "requires": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.15.12", - "@mui/styled-engine": "^5.15.11", - "@mui/types": "^7.2.13", - "@mui/utils": "^5.15.12", + "@mui/private-theming": "^5.15.14", + "@mui/styled-engine": "^5.15.14", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" } }, "@mui/types": { - "version": "7.2.13", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz", - "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==", + "version": "7.2.14", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz", + "integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==", "requires": {} }, "@mui/utils": { - "version": "5.15.12", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.12.tgz", - "integrity": "sha512-8SDGCnO2DY9Yy+5bGzu00NZowSDtuyHP4H8gunhHGQoIlhlY2Z3w64wBzAOLpYw/ZhJNzksDTnS/i8qdJvxuow==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz", + "integrity": "sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==", "requires": { "@babel/runtime": "^7.23.9", "@types/prop-types": "^15.7.11", @@ -6386,98 +6325,98 @@ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, "@remix-run/router": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz", - "integrity": "sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q==" + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz", + "integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==" }, "@rollup/rollup-android-arm-eabi": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.4.tgz", - "integrity": "sha512-ub/SN3yWqIv5CWiAZPHVS1DloyZsJbtXmX4HxUTIpS0BHm9pW5iYBo2mIZi+hE3AeiTzHz33blwSnhdUo+9NpA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", + "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", "dev": true, "optional": true }, "@rollup/rollup-android-arm64": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.4.tgz", - "integrity": "sha512-ehcBrOR5XTl0W0t2WxfTyHCR/3Cq2jfb+I4W+Ch8Y9b5G+vbAecVv0Fx/J1QKktOrgUYsIKxWAKgIpvw56IFNA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", + "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", "dev": true, "optional": true }, "@rollup/rollup-darwin-arm64": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.4.tgz", - "integrity": "sha512-1fzh1lWExwSTWy8vJPnNbNM02WZDS8AW3McEOb7wW+nPChLKf3WG2aG7fhaUmfX5FKw9zhsF5+MBwArGyNM7NA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", + "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", "dev": true, "optional": true }, "@rollup/rollup-darwin-x64": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.4.tgz", - "integrity": "sha512-Gc6cukkF38RcYQ6uPdiXi70JB0f29CwcQ7+r4QpfNpQFVHXRd0DfWFidoGxjSx1DwOETM97JPz1RXL5ISSB0pA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", + "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", "dev": true, "optional": true }, "@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.4.tgz", - "integrity": "sha512-g21RTeFzoTl8GxosHbnQZ0/JkuFIB13C3T7Y0HtKzOXmoHhewLbVTFBQZu+z5m9STH6FZ7L/oPgU4Nm5ErN2fw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", + "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", "dev": true, "optional": true }, "@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.4.tgz", - "integrity": "sha512-TVYVWD/SYwWzGGnbfTkrNpdE4HON46orgMNHCivlXmlsSGQOx/OHHYiQcMIOx38/GWgwr/po2LBn7wypkWw/Mg==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", + "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", "dev": true, "optional": true }, "@rollup/rollup-linux-arm64-musl": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.4.tgz", - "integrity": "sha512-XcKvuendwizYYhFxpvQ3xVpzje2HHImzg33wL9zvxtj77HvPStbSGI9czrdbfrf8DGMcNNReH9pVZv8qejAQ5A==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", + "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", "dev": true, "optional": true }, "@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.4.tgz", - "integrity": "sha512-LFHS/8Q+I9YA0yVETyjonMJ3UA+DczeBd/MqNEzsGSTdNvSJa1OJZcSH8GiXLvcizgp9AlHs2walqRcqzjOi3A==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", + "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", "dev": true, "optional": true }, "@rollup/rollup-linux-x64-gnu": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.4.tgz", - "integrity": "sha512-dIYgo+j1+yfy81i0YVU5KnQrIJZE8ERomx17ReU4GREjGtDW4X+nvkBak2xAUpyqLs4eleDSj3RrV72fQos7zw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", + "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", "dev": true, "optional": true }, "@rollup/rollup-linux-x64-musl": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.4.tgz", - "integrity": "sha512-RoaYxjdHQ5TPjaPrLsfKqR3pakMr3JGqZ+jZM0zP2IkDtsGa4CqYaWSfQmZVgFUCgLrTnzX+cnHS3nfl+kB6ZQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", + "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", "dev": true, "optional": true }, "@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.4.tgz", - "integrity": "sha512-T8Q3XHV+Jjf5e49B4EAaLKV74BbX7/qYBRQ8Wop/+TyyU0k+vSjiLVSHNWdVd1goMjZcbhDmYZUYW5RFqkBNHQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", + "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", "dev": true, "optional": true }, "@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.4.tgz", - "integrity": "sha512-z+JQ7JirDUHAsMecVydnBPWLwJjbppU+7LZjffGf+Jvrxq+dVjIE7By163Sc9DKc3ADSU50qPVw0KonBS+a+HQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", + "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", "dev": true, "optional": true }, "@rollup/rollup-win32-x64-msvc": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.4.tgz", - "integrity": "sha512-LfdGXCV9rdEify1oxlN9eamvDSjv9md9ZVMAbNHA87xqIfFCxImxan9qZ8+Un54iK2nnqPlbnSi4R54ONtbWBw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", "dev": true, "optional": true }, @@ -6644,6 +6583,14 @@ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" }, + "@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "requires": { + "@types/node": "*" + } + }, "@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -6692,9 +6639,9 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, "@types/react": { - "version": "18.2.64", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.64.tgz", - "integrity": "sha512-MlmPvHgjj2p3vZaxbQgFUQFvD8QiZwACfGqEdDSWou5yISWxDQ4/74nCAwsUiX7UFLKZz3BbVSPj+YxeoGGCfg==", + "version": "18.2.69", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.69.tgz", + "integrity": "sha512-W1HOMUWY/1Yyw0ba5TkCV+oqynRjG7BnteBB+B7JmAK7iw3l2SW+VGOxL+akPweix6jk2NNJtyJKpn4TkpfK3Q==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -6702,9 +6649,9 @@ } }, "@types/react-dom": { - "version": "18.2.21", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.21.tgz", - "integrity": "sha512-gnvBA/21SA4xxqNXEwNiVcP0xSGHh/gi1VhWv9Bl46a0ItbTT5nFY+G9VSQpaG/8N/qdJpJ+vftQ4zflTtnjLw==", + "version": "18.2.22", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz", + "integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==", "dev": true, "requires": { "@types/react": "*" @@ -6749,135 +6696,73 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.0.tgz", - "integrity": "sha512-M72SJ0DkcQVmmsbqlzc6EJgb/3Oz2Wdm6AyESB4YkGgCxP8u5jt5jn4/OBMPK3HLOxcttZq5xbBBU7e2By4SZQ==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.3.1.tgz", + "integrity": "sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.0.0", - "@typescript-eslint/type-utils": "7.0.0", - "@typescript-eslint/utils": "7.0.0", - "@typescript-eslint/visitor-keys": "7.0.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/type-utils": "7.3.1", + "@typescript-eslint/utils": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", "natural-compare": "^1.4.0", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" - }, - "dependencies": { - "@typescript-eslint/scope-manager": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.0.tgz", - "integrity": "sha512-IxTStwhNDPO07CCrYuAqjuJ3Xf5MrMaNgbAZPxFXAUpAtwqFxiuItxUaVtP/SJQeCdJjwDGh9/lMOluAndkKeg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "7.0.0", - "@typescript-eslint/visitor-keys": "7.0.0" - } - }, - "@typescript-eslint/types": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.0.tgz", - "integrity": "sha512-9ZIJDqagK1TTs4W9IyeB2sH/s1fFhN9958ycW8NRTg1vXGzzH5PQNzq6KbsbVGMT+oyyfa17DfchHDidcmf5cg==", - "dev": true - }, - "@typescript-eslint/visitor-keys": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.0.tgz", - "integrity": "sha512-JZP0uw59PRHp7sHQl3aF/lFgwOW2rgNVnXUksj1d932PMita9wFBd3621vHQRDvHwPsSY9FMAAHVc8gTvLYY4w==", - "dev": true, - "requires": { - "@typescript-eslint/types": "7.0.0", - "eslint-visitor-keys": "^3.4.1" - } - } } }, "@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.3.1.tgz", + "integrity": "sha512-Rq49+pq7viTRCH48XAbTA+wdLRrB/3sRq4Lpk0oGDm0VmnjBrAOVXH/Laalmwsv2VpekiEfVFwJYVk6/e8uvQw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.3.1.tgz", + "integrity": "sha512-fVS6fPxldsKY2nFvyT7IP78UO1/I2huG+AYu5AMjCT9wtl6JFiDnsv4uad4jQ0GTFzcUV5HShVeN96/17bTBag==", "dev": true, "requires": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1" } }, "@typescript-eslint/type-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.0.tgz", - "integrity": "sha512-FIM8HPxj1P2G7qfrpiXvbHeHypgo2mFpFGoh5I73ZlqmJOsloSa1x0ZyXCer43++P1doxCgNqIOLqmZR6SOT8g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.3.1.tgz", + "integrity": "sha512-iFhaysxFsMDQlzJn+vr3OrxN8NmdQkHks4WaqD4QBnt5hsq234wcYdyQ9uquzJJIDAj5W4wQne3yEsYA6OmXGw==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "7.0.0", - "@typescript-eslint/utils": "7.0.0", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/utils": "7.3.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" - }, - "dependencies": { - "@typescript-eslint/types": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.0.tgz", - "integrity": "sha512-9ZIJDqagK1TTs4W9IyeB2sH/s1fFhN9958ycW8NRTg1vXGzzH5PQNzq6KbsbVGMT+oyyfa17DfchHDidcmf5cg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.0.tgz", - "integrity": "sha512-JzsOzhJJm74aQ3c9um/aDryHgSHfaX8SHFIu9x4Gpik/+qxLvxUylhTsO9abcNu39JIdhY2LgYrFxTii3IajLA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "7.0.0", - "@typescript-eslint/visitor-keys": "7.0.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.0.tgz", - "integrity": "sha512-JZP0uw59PRHp7sHQl3aF/lFgwOW2rgNVnXUksj1d932PMita9wFBd3621vHQRDvHwPsSY9FMAAHVc8gTvLYY4w==", - "dev": true, - "requires": { - "@typescript-eslint/types": "7.0.0", - "eslint-visitor-keys": "^3.4.1" - } - } } }, "@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.3.1.tgz", + "integrity": "sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.3.1.tgz", + "integrity": "sha512-tLpuqM46LVkduWP7JO7yVoWshpJuJzxDOPYIVWUUZbW+4dBpgGeUdl/fQkhuV0A8eGnphYw3pp8d2EnvPOfxmQ==", "dev": true, "requires": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6887,71 +6772,27 @@ } }, "@typescript-eslint/utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.0.tgz", - "integrity": "sha512-kuPZcPAdGcDBAyqDn/JVeJVhySvpkxzfXjJq1X1BFSTYo1TTuo4iyb937u457q4K0In84p6u2VHQGaFnv7VYqg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.3.1.tgz", + "integrity": "sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.0.0", - "@typescript-eslint/types": "7.0.0", - "@typescript-eslint/typescript-estree": "7.0.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", "semver": "^7.5.4" - }, - "dependencies": { - "@typescript-eslint/scope-manager": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.0.tgz", - "integrity": "sha512-IxTStwhNDPO07CCrYuAqjuJ3Xf5MrMaNgbAZPxFXAUpAtwqFxiuItxUaVtP/SJQeCdJjwDGh9/lMOluAndkKeg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "7.0.0", - "@typescript-eslint/visitor-keys": "7.0.0" - } - }, - "@typescript-eslint/types": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.0.tgz", - "integrity": "sha512-9ZIJDqagK1TTs4W9IyeB2sH/s1fFhN9958ycW8NRTg1vXGzzH5PQNzq6KbsbVGMT+oyyfa17DfchHDidcmf5cg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.0.tgz", - "integrity": "sha512-JzsOzhJJm74aQ3c9um/aDryHgSHfaX8SHFIu9x4Gpik/+qxLvxUylhTsO9abcNu39JIdhY2LgYrFxTii3IajLA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "7.0.0", - "@typescript-eslint/visitor-keys": "7.0.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.0.tgz", - "integrity": "sha512-JZP0uw59PRHp7sHQl3aF/lFgwOW2rgNVnXUksj1d932PMita9wFBd3621vHQRDvHwPsSY9FMAAHVc8gTvLYY4w==", - "dev": true, - "requires": { - "@typescript-eslint/types": "7.0.0", - "eslint-visitor-keys": "^3.4.1" - } - } } }, "@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.1.tgz", + "integrity": "sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==", "dev": true, "requires": { - "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/types": "7.3.1", "eslint-visitor-keys": "^3.4.1" } }, @@ -7444,34 +7285,39 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, "esbuild": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.11.tgz", - "integrity": "sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==", - "requires": { - "@esbuild/aix-ppc64": "0.19.11", - "@esbuild/android-arm": "0.19.11", - "@esbuild/android-arm64": "0.19.11", - "@esbuild/android-x64": "0.19.11", - "@esbuild/darwin-arm64": "0.19.11", - "@esbuild/darwin-x64": "0.19.11", - "@esbuild/freebsd-arm64": "0.19.11", - "@esbuild/freebsd-x64": "0.19.11", - "@esbuild/linux-arm": "0.19.11", - "@esbuild/linux-arm64": "0.19.11", - "@esbuild/linux-ia32": "0.19.11", - "@esbuild/linux-loong64": "0.19.11", - "@esbuild/linux-mips64el": "0.19.11", - "@esbuild/linux-ppc64": "0.19.11", - "@esbuild/linux-riscv64": "0.19.11", - "@esbuild/linux-s390x": "0.19.11", - "@esbuild/linux-x64": "0.19.11", - "@esbuild/netbsd-x64": "0.19.11", - "@esbuild/openbsd-x64": "0.19.11", - "@esbuild/sunos-x64": "0.19.11", - "@esbuild/win32-arm64": "0.19.11", - "@esbuild/win32-ia32": "0.19.11", - "@esbuild/win32-x64": "0.19.11" + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "requires": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" } }, "escape-html": { @@ -7571,9 +7417,9 @@ "requires": {} }, "eslint-plugin-react-refresh": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.5.tgz", - "integrity": "sha512-D53FYKJa+fDmZMtriODxvhwrO+IOqrxoEo21gMA0sjHdU6dPVH4OhyFip9ypl8HOF5RV5KdTo+rBQLvnY2cO8w==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.6.tgz", + "integrity": "sha512-NjGXdm7zgcKRkKMua34qVO9doI7VOxZ6ancSvBELJSSoX97jyndXcSoa8XBh69JoB31dNz3EEzlMcizZl7LaMA==", "dev": true, "requires": {} }, @@ -7637,22 +7483,27 @@ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, "express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.1.tgz", + "integrity": "sha512-K4w1/Bp7y8iSiVObmCrtq8Cs79XjJc/RU2YYkZQ7wpUu5ZyZ7MtPHkqoMz4pf+mgXfNvo2qft8D9OnrH2ABk9w==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -7680,6 +7531,11 @@ "vary": "~1.1.2" }, "dependencies": { + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -7695,6 +7551,26 @@ } } }, + "express-http-proxy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/express-http-proxy/-/express-http-proxy-2.0.0.tgz", + "integrity": "sha512-TXxcPFTWVUMSEmyM6iX2sT/JtmqhqngTq29P+eXTVFdtxZrTmM8THUYK59rUXiln0FfPGvxEpGRnVrgvHksXDw==", + "requires": { + "debug": "^3.0.1", + "es6-promise": "^4.1.1", + "raw-body": "^2.3.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, "fast-content-type-parse": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", @@ -7922,6 +7798,11 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" }, + "follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -8086,6 +7967,28 @@ "toidentifier": "1.0.1" } }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, "http-status-codes": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", @@ -8201,15 +8104,20 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "jose": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", - "integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==" + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", + "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==" }, "js-tokens": { "version": "4.0.0", @@ -8488,7 +8396,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "requires": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -8761,14 +8668,14 @@ "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==" }, "postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "dev": true, "requires": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" } }, "prelude-ls": { @@ -8914,20 +8821,20 @@ } }, "react-router": { - "version": "6.22.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.2.tgz", - "integrity": "sha512-YD3Dzprzpcq+tBMHBS822tCjnWD3iIZbTeSXMY9LPSG541EfoBGyZ3bS25KEnaZjLcmQpw2AVLkFyfgXY8uvcw==", + "version": "6.22.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz", + "integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==", "requires": { - "@remix-run/router": "1.15.2" + "@remix-run/router": "1.15.3" } }, "react-router-dom": { - "version": "6.22.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.2.tgz", - "integrity": "sha512-WgqxD2qySEIBPZ3w0sHH+PUAiamDeszls9tzqMPBDA1YYVucTBXLU7+gtRfcSnhe92A3glPnvSxK2dhNoAVOIQ==", + "version": "6.22.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz", + "integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==", "requires": { - "@remix-run/router": "1.15.2", - "react-router": "6.22.2" + "@remix-run/router": "1.15.3", + "react-router": "6.22.3" } }, "react-transition-group": { @@ -8976,6 +8883,11 @@ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, "resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -9025,24 +8937,24 @@ } }, "rollup": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.4.tgz", - "integrity": "sha512-2ztU7pY/lrQyXSCnnoU4ICjT/tCG9cdH3/G25ERqE3Lst6vl2BCM5hL2Nw+sslAvAf+ccKsAq1SkKQALyqhR7g==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", "dev": true, "requires": { - "@rollup/rollup-android-arm-eabi": "4.9.4", - "@rollup/rollup-android-arm64": "4.9.4", - "@rollup/rollup-darwin-arm64": "4.9.4", - "@rollup/rollup-darwin-x64": "4.9.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.4", - "@rollup/rollup-linux-arm64-gnu": "4.9.4", - "@rollup/rollup-linux-arm64-musl": "4.9.4", - "@rollup/rollup-linux-riscv64-gnu": "4.9.4", - "@rollup/rollup-linux-x64-gnu": "4.9.4", - "@rollup/rollup-linux-x64-musl": "4.9.4", - "@rollup/rollup-win32-arm64-msvc": "4.9.4", - "@rollup/rollup-win32-ia32-msvc": "4.9.4", - "@rollup/rollup-win32-x64-msvc": "4.9.4", + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", "@types/estree": "1.0.5", "fsevents": "~2.3.2" } @@ -9262,9 +9174,9 @@ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" }, "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==" }, "split2": { "version": "4.2.0", @@ -9403,9 +9315,9 @@ } }, "typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", "dev": true }, "undefsafe": { @@ -9447,15 +9359,15 @@ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "vite": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz", - "integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==", + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", + "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==", "dev": true, "requires": { - "esbuild": "^0.19.3", + "esbuild": "^0.20.1", "fsevents": "~2.3.3", - "postcss": "^8.4.35", - "rollup": "^4.2.0" + "postcss": "^8.4.36", + "rollup": "^4.13.0" } }, "vite-express": { diff --git a/package.json b/package.json index 8c895e2c..1f444683 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,14 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", - "@mui/material": "^5.15.12", + "@mui/material": "^5.15.14", "@statisticsnorway/ssb-component-library": "^2.0.98", "dotenv": "^16.4.5", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "express": "4.18.3", + "express": "4.19.1", + "express-http-proxy": "^2.0.0", + "http-proxy-middleware": "^2.0.6", "http-status-codes": "^2.3.0", "jsonwebtoken": "^9.0.2", "jwks-rsa": "^3.1.0", @@ -32,19 +34,19 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-responsive": "^9.0.2", - "react-router-dom": "^6.22.2", + "react-router-dom": "^6.22.3", "vite-express": "0.15.0" }, "devDependencies": { - "@types/react": "^18.2.64", - "@types/react-dom": "^18.2.20", - "@typescript-eslint/eslint-plugin": "^7.0.0", - "@typescript-eslint/parser": "^6.21.0", + "@types/react": "^18.2.69", + "@types/react-dom": "^18.2.22", + "@typescript-eslint/eslint-plugin": "^7.3.1", + "@typescript-eslint/parser": "^7.3.1", "@vitejs/plugin-react-swc": "^3.6.0", "eslint": "^8.57.0", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.5", - "typescript": "^5.2.2", - "vite": "^5.1.5" + "eslint-plugin-react-refresh": "^0.4.6", + "typescript": "^5.4.3", + "vite": "^5.2.6" } } diff --git a/server.js b/server.js index 9626da63..9e26caf1 100644 --- a/server.js +++ b/server.js @@ -2,21 +2,53 @@ import ViteExpress from 'vite-express' import { createLightship } from 'lightship' import express from 'express' import { getReasonPhrase } from 'http-status-codes' +import proxy from 'express-http-proxy' import dotenv from 'dotenv' +import cache from 'memory-cache' -if (!process.env.VITE_DAPLA_TEAM_API_URL) { +if (!process.env.DAPLA_TEAM_API_URL) { dotenv.config({ path: './.env.local' }) } -const DAPLA_TEAM_API_URL = process.env.VITE_DAPLA_TEAM_API_URL - const app = express() const PORT = process.env.PORT || 3000 +const DAPLA_TEAM_API_URL = process.env.DAPLA_TEAM_API_URL || 'https://dapla-team-api-v2.staging-bip-app.ssb.no' + +app.use( + '/api', + proxy(DAPLA_TEAM_API_URL, { + proxyReqBodyDecorator: function (bodyContent, srcReq) { + console.log(`Request Body: ${bodyContent}`) + return bodyContent + }, + proxyReqOptDecorator: function (proxyReqOpts, srcReq) { + console.log(`Request Headers:`, srcReq.headers) + if (srcReq.body) { + console.log(`Request Body:`, srcReq.body) + } + return proxyReqOpts + }, + proxyReqPathResolver: function (req) { + const newPath = req.originalUrl.replace(/^\/api/, '') + console.log(`Forwarding to: ${DAPLA_TEAM_API_URL}${newPath}`) + return newPath + }, + userResDecorator: function (proxyRes, proxyResData, userReq, userRes) { + console.log(`Response Status: ${proxyRes.statusCode}`) + console.log(`Response Headers:`, proxyRes.headers) + return proxyResData + }, + proxyErrorHandler: function (err, res) { + console.error('Proxy Error:', err) + res.status(500).send('Proxy Error') + }, + }) +) app.use(express.json()) // DO NOT REMOVE, NECCESSARY FOR FRONTEND -app.get('/api/photo/:principalName', async (req, res, next) => { +app.get('/localApi/photo/:principalName', async (req, res, next) => { const accessToken = req.headers.authorization.split(' ')[1] const principalName = req.params.principalName const userPhotoUrl = `${DAPLA_TEAM_API_URL}/users/${principalName}/photo` @@ -30,6 +62,43 @@ app.get('/api/photo/:principalName', async (req, res, next) => { } }) +app.get('/localApi/users', async (req, res) => { + const cacheKey = 'usersForSearch' + const cachedData = cache.get(cacheKey) + + const token = req.headers.authorization + const usersUrl = new URL(`${DAPLA_TEAM_API_URL}/users`) + const selects = ['display_name', 'principal_name', 'section_name'] + + usersUrl.searchParams.append('select', selects.join(',')) + if (cachedData) { + res.json(cachedData) + } else { + try { + const response = await fetch(usersUrl.toString(), { + method: 'GET', + headers: { + Accept: '*/*', + 'Content-Type': 'application/json', + Authorization: token, + }, + }) + + if (!response.ok) { + const err = await response.text() + res.status(response.status).send(err) + } else { + const data = await response.json() + cache.put(cacheKey, data, 3600000) + res.status(response.status).send(data) + } + } catch (error) { + console.log(error) + res.status(500).send('Internal Server Error') + } + } +}) + async function fetchPhoto(accessToken, url, fallbackErrorMessage) { const response = await fetch(url, getFetchOptions(accessToken)) @@ -42,7 +111,40 @@ async function fetchPhoto(accessToken, url, fallbackErrorMessage) { return photoBuffer.toString('base64') } -app.get('/api/fetch-token', (req, res) => { +//TODO: Remove me once DELETE with proxy is fixed +app.delete('/localApi/groups/:groupUniformName/:userPrincipalName', async (req, res) => { + const token = req.headers.authorization + const groupUniformName = req.params.groupUniformName + const userPrincipalName = req.params.userPrincipalName + const groupsUrl = `${DAPLA_TEAM_API_URL}/groups/${groupUniformName}/users` + + try { + const response = await fetch(groupsUrl, { + method: 'DELETE', + headers: { + Accept: '*/*', + 'Content-Type': 'application/json', + Authorization: token, + }, + body: JSON.stringify({ + users: [userPrincipalName], + }), + }) + + if (!response.ok) { + const err = await response.text() + res.status(response.status).send(err) + } else { + const data = await response.json() + res.status(response.status).send(data) + } + } catch (error) { + console.log(error) + res.status(500).send('Internal Server Error') + } +}) + +app.get('/localApi/fetch-token', (req, res) => { if (!req.headers.authorization || !req.headers.authorization.startsWith('Bearer')) { return res.status(401).json({ message: 'No token provided' }) } @@ -75,7 +177,6 @@ app.use((err, req, res, next) => { }) }) - const lightship = await createLightship() ViteExpress.listen(app, PORT, () => { diff --git a/src/@types/pageTypes.ts b/src/@types/pageTypes.ts index b2d4a6a9..29a88cef 100644 --- a/src/@types/pageTypes.ts +++ b/src/@types/pageTypes.ts @@ -2,3 +2,8 @@ export interface TabProps { title: string path: string } + +export interface DropdownItems { + id: string + title: string +} diff --git a/src/components/Avatar/avatar.module.scss b/src/components/Avatar/avatar.module.scss index 8dd71631..28365151 100644 --- a/src/components/Avatar/avatar.module.scss +++ b/src/components/Avatar/avatar.module.scss @@ -1,9 +1,8 @@ @use '@statisticsnorway/ssb-component-library/src/style/variables' as variables; .avatar { - width: 50px; - height: 50px; - margin: 0 1.5rem 0 0; + width: 40px; + height: 40px; border: 1px solid variables.$ssb-dark-2; border-radius: 50%; display: flex; @@ -20,8 +19,8 @@ } img { - width: 50px; - height: 50px; + width: 40px; + height: 40px; border-radius: 50%; object-fit: cover; } diff --git a/src/components/DeleteLink/DeleteLink.tsx b/src/components/DeleteLink/DeleteLink.tsx new file mode 100644 index 00000000..5eff9f80 --- /dev/null +++ b/src/components/DeleteLink/DeleteLink.tsx @@ -0,0 +1,21 @@ +import styles from './deletelink.module.scss' + +import { Trash2 } from 'react-feather' + +interface DeleteLink { + children: string + tabIndex?: number + icon?: boolean + handleDeleteUser: CallableFunction +} + +const DeleteLink = ({ children, tabIndex, icon, handleDeleteUser }: DeleteLink) => { + return ( + handleDeleteUser()}> + {icon && } + {children} + + ) +} + +export default DeleteLink diff --git a/src/components/DeleteLink/deletelink.module.scss b/src/components/DeleteLink/deletelink.module.scss new file mode 100644 index 00000000..7ff82185 --- /dev/null +++ b/src/components/DeleteLink/deletelink.module.scss @@ -0,0 +1,22 @@ +@use '@statisticsnorway/ssb-component-library/src/style/variables' as variables; + +.deleteLinkWrapper { + display: inline-flex; + align-items: center; + color: variables.$ssb-red-3; + padding: .5rem; + line-height: 1.7; + cursor: pointer; + + svg { + margin-right: .5rem; + } + + span { + border-bottom: 1px solid; + } + + &:focus { + @include variables.focus-marker; + } +} \ No newline at end of file diff --git a/src/components/FormattedTableColumn.tsx b/src/components/FormattedTableColumn/FormattedTableColumn.tsx similarity index 63% rename from src/components/FormattedTableColumn.tsx rename to src/components/FormattedTableColumn/FormattedTableColumn.tsx index 9beb1a38..52a6a021 100644 --- a/src/components/FormattedTableColumn.tsx +++ b/src/components/FormattedTableColumn/FormattedTableColumn.tsx @@ -1,4 +1,6 @@ -import { Text, Link } from '@statisticsnorway/ssb-component-library' +import styles from './formattedtablecolumn.module.scss' + +import { Link } from '@statisticsnorway/ssb-component-library' interface FormattedTableColumnProps { href?: string @@ -11,14 +13,14 @@ const FormattedTableColumn = (props: FormattedTableColumnProps) => { return ( <> - + {href && linkText && ( {linkText} )} - {text && {text}} + {text && {text}} ) } diff --git a/src/components/FormattedTableColumn/formattedtablecolumn.module.scss b/src/components/FormattedTableColumn/formattedtablecolumn.module.scss new file mode 100644 index 00000000..27db7313 --- /dev/null +++ b/src/components/FormattedTableColumn/formattedtablecolumn.module.scss @@ -0,0 +1,19 @@ +@use '@statisticsnorway/ssb-component-library/src/style/variables' as variables; + +.linkTextWrapper { + margin-bottom: .75em; +} + +.textWrapper { + margin-top: .75em; +} + +@media #{variables.$mobile} { + .linkTextWrapper { + margin-bottom: 2px; + } + + .textWrapper { + margin-top: 2px; + } +} \ No newline at end of file diff --git a/src/components/Header/header.module.scss b/src/components/Header/header.module.scss index 7905437c..8b255e2d 100644 --- a/src/components/Header/header.module.scss +++ b/src/components/Header/header.module.scss @@ -7,8 +7,8 @@ border-bottom: 1px solid variables.$ssb-dark-2; color: variables.$ssb-dark-5; align-items: center; - padding: 1rem; - padding-left: 4rem; + padding: 0 4rem; + height: 80px; margin: 0; font-family: 'Roboto Condensed', sans-serif !important; font-stretch: condensed; diff --git a/src/components/PageLayout/PageLayout.tsx b/src/components/PageLayout/PageLayout.tsx index 1d186676..23331cbc 100644 --- a/src/components/PageLayout/PageLayout.tsx +++ b/src/components/PageLayout/PageLayout.tsx @@ -16,9 +16,13 @@ const PageLayout = ({ title, button, content }: PageLayoutProps) => {
-
- {title && {title}} - {button} +
+ {title && ( + + {title} + + )} + {button &&
{button}
}
{content}
diff --git a/src/components/PageLayout/pagelayout.module.scss b/src/components/PageLayout/pagelayout.module.scss index 47d208fb..89c6c9d4 100644 --- a/src/components/PageLayout/pagelayout.module.scss +++ b/src/components/PageLayout/pagelayout.module.scss @@ -8,15 +8,26 @@ } } -.title { +.titleContainer { display: flex; flex-direction: row; justify-content: space-between; + align-items: center; margin-top: 1.5rem; @media #{variables.$mobile} { flex-direction: column; + align-items: start; + margin-bottom: 1rem; + + .title { + margin: 0; + } + + .button { + margin: 1.5rem 0 1rem; + } } } @@ -24,7 +35,11 @@ display: flex; flex-direction: column; margin-top: -2rem; - gap: 0.5rem; + gap: .25rem; + + @media #{variables.$mobile} { + margin-top: 0; + } } .descriptionSpacing { diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx index 698a1af1..0937b273 100644 --- a/src/components/ProtectedRoute.tsx +++ b/src/components/ProtectedRoute.tsx @@ -21,6 +21,7 @@ const ProtectedRoute = () => { setIsAuthenticated(true) } catch (error) { console.error('Error occurred when updating userProfile data') + console.error(error) } } setData() diff --git a/src/components/SidebarModal/SidebarModal.tsx b/src/components/SidebarModal/SidebarModal.tsx index 3fbf60bf..db4049fc 100644 --- a/src/components/SidebarModal/SidebarModal.tsx +++ b/src/components/SidebarModal/SidebarModal.tsx @@ -1,34 +1,51 @@ import styles from './sidebar.module.scss' -import { Link, Button } from '@statisticsnorway/ssb-component-library' +import { useRef, useEffect } from 'react' +import { Title, Link, Button } from '@statisticsnorway/ssb-component-library' import { X } from 'react-feather' interface SidebarHeader { - modalType: string + modalType?: string modalTitle: string - modalDescription: string + modalDescription?: string +} + +interface SidebarBody { + modalBodyTitle: string + modalBody: JSX.Element +} + +interface SidebarFooter { + submitButtonText: string + onClose?: () => void + handleSubmit?: () => void +} + +interface SidebarModal { + open: boolean + onClose: () => void + header: SidebarHeader + body: SidebarBody + footer: SidebarFooter } const SidebarModalHeader = ({ modalType, modalTitle, modalDescription }: SidebarHeader): JSX.Element => { return (
-
- {modalType} -
-
-

{modalTitle}

-
-
-

{modalDescription}

-
+ {modalType && {modalType}} + {{modalTitle}} + {modalDescription &&

{modalDescription}

}
) } -interface SidebarFooter { - submitButtonText: string - onClose?: () => void - handleSubmit?: () => void +const SidebarModalBody = ({ modalBodyTitle, modalBody }: SidebarBody): JSX.Element => { + return ( +
+ {modalBodyTitle} + {modalBody} +
+ ) } const SidebarModalFooter = ({ submitButtonText, onClose, handleSubmit }: SidebarFooter): JSX.Element => { @@ -44,47 +61,30 @@ const SidebarModalFooter = ({ submitButtonText, onClose, handleSubmit }: Sidebar ) } -interface SidebarModal { - open: boolean - onClose: () => void - header: SidebarHeader - body: JSX.Element - footer: SidebarFooter -} - const SidebarModal = ({ open, onClose, header, footer, body }: SidebarModal) => { - /* - const [showScrollIndicator, setShowScrollIndicator] = useState(false); - const contentRef = useRef(null); + const sidebarModalRef = useRef(null) - const checkForOverflow = () => { - const element = contentRef.current; - if (!element) return + useEffect(() => { + const handleBackdropOnClick = (e: Event) => { + if (sidebarModalRef.current && !sidebarModalRef?.current?.contains(e.target as Node)) onClose() + } - // Check if the content is overflowing in the vertical direction - const hasOverflow = element.scrollHeight > element.clientHeight; - setShowScrollIndicator(hasOverflow); - }; + window.addEventListener('mousedown', handleBackdropOnClick) + return () => { + window.removeEventListener('mousedown', handleBackdropOnClick) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) - useEffect(() => { - if (!open) return - - checkForOverflow(); - }, [open]); - */ return ( -
-
-
- {/*
*/} -
- {/* showScrollIndicator &&
↓ Scroll for å vise mer innhold
*/} - {body} -
+
) diff --git a/src/components/SidebarModal/sidebar.module.scss b/src/components/SidebarModal/sidebar.module.scss index cf5c0f8f..e9b6263a 100644 --- a/src/components/SidebarModal/sidebar.module.scss +++ b/src/components/SidebarModal/sidebar.module.scss @@ -1,8 +1,7 @@ @use '@statisticsnorway/ssb-component-library/src/style/variables' as variables; - .container { - width: 20%; + width: 375px; height: 100%; position: fixed; display: flex; @@ -16,95 +15,49 @@ transition: transform 0.3s ease; transform: translateX(100%); - button { - background: none; - color: inherit; - border: none; - padding: 0; - font: inherit; - cursor: pointer; - outline: inherit; - float: right; + @media #{variables.$mobile} { + width: 100%; } +} - .xIcon { - color: variables.$ssb-green-4; - } +.closeButton { + background: none; + border: none; + cursor: pointer; + float: right; + padding: 1rem; +} - .body { - background-color: variables.$ssb-green-1; - border-bottom: 1px solid #d4d4d4; - height: 80%; - overflow-y: auto; - > * { - padding: 1rem; - } - .scroll { - color: red; - position: fixed; - left: 50%; - width: 100%; - text-align: center; - transform: translateX(-50%); - z-index: 1000; - } - } +.xIcon { + color: variables.$ssb-green-4; +} - .modalHeader { - width: 100%; - display: flex; - flex-direction: column; - justify-content: center; - margin-left: 1rem; - margin-bottom: 2rem; - - button { - margin: 0; - padding: 0; - float: right; - } - - > * > * { - padding: 0; - margin: 0; - } - - .modalType {} - .modalTitle {} - .modalDescription {} - } - - .modalFooter { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - margin-left: 2.5rem; - margin-right: 2.5rem; - padding-top: 1rem; - padding-bottom: 1rem; - height: auto; - - .modalFooterButtonText {} - } +.modalBody { + background-color: variables.$ssb-green-1; + border-bottom: 1px solid #d4d4d4; + height: 80%; + padding: 2rem 1.5rem 0; + overflow-y: auto; +} - @media (max-width: 1500px) { - width: 30%; - .modalFooter { - flex-direction: column; - gap: 20px; - padding: 1rem; - } +.modalHeader { + display: flex; + flex-direction: column; + justify-content: center; + margin: 0 0 2rem 1.5rem; + + > * { + padding: 0; + margin: 0; } +} - @media (max-width: 1050px) { - width: 100%; - .modalFooter { - flex-direction: column; - margin: 1rem 0; - gap: 1rem; - } - } +.modalFooter { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + margin: 1rem 2.5rem; } .open { diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index 763a1a99..7a94a790 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -1,6 +1,6 @@ import styles from './table.module.scss' -import { useEffect, useState } from 'react' +import React, { useEffect, useState, useMemo } from 'react' import { useMediaQuery } from 'react-responsive' import { Title, Dropdown, Input, Text } from '@statisticsnorway/ssb-component-library' import { ArrowUp, ArrowDown } from 'react-feather' @@ -14,11 +14,13 @@ interface TableProps extends TableData { interface TableDesktopViewProps extends TableData { activeTab?: string } + export interface TableData { columns: { id: string label: string unsortable?: boolean + align?: string }[] data: { id: string @@ -27,12 +29,28 @@ export interface TableData { } const conditionalStyling = (index: number) => { - // Add conditional styling for the first element, then third etc return (index + 1) % 2 !== 0 ? styles.greenBackground : undefined } const NoResultText = () =>

Fant ingen resultater

+// eslint-disable-next-line @typescript-eslint/no-explicit-any +type MixedElement = string | number | React.ReactElement + +const extractStringValue = (child: MixedElement): string | number => { + if (typeof child === 'string' || typeof child === 'number') { + return child + } else if (React.isValidElement(child)) { + const props = child.props as { children?: MixedElement; linkText?: MixedElement } + if (props.children) { + return extractStringValue(props.children) + } else if (props.linkText) { + return extractStringValue(props.linkText) + } + } + return '' +} + const TableMobileView = ({ columns, data }: TableData) => (
{data.length ? ( @@ -68,13 +86,14 @@ const TableDesktopView = ({ columns, data, activeTab }: TableDesktopViewProps) = // eslint-disable-next-line react-hooks/exhaustive-deps }, [activeTab]) - const sortTableData = (id: string) => { - data.sort((a, b) => { - // Sort by id for the first column; - const valueA = typeof a[id] === 'object' ? a['id'] : a[id] - const valueB = typeof b[id] === 'object' ? b['id'] : b[id] + const sortedData = useMemo(() => { + const sorted = [...data] + sorted.sort((a, b) => { + // Sort by id for the first column + const valueA = extractStringValue(a[sortBy] as MixedElement) + const valueB = extractStringValue(b[sortBy] as MixedElement) - // Sort by number + // sort by number if (typeof valueA === 'number' && typeof valueB === 'number') return sortByDirection === 'asc' ? valueA - valueB : valueB - valueA @@ -83,16 +102,17 @@ const TableDesktopView = ({ columns, data, activeTab }: TableDesktopViewProps) = if (valueA.toLowerCase() < valueB.toLowerCase()) return sortByDirection === 'asc' ? -1 : 1 if (valueA.toLowerCase() > valueB.toLowerCase()) return sortByDirection === 'asc' ? 1 : -1 } + return 0 // TODO: Sort by date }) - } + return sorted + }, [data, sortBy, sortByDirection]) const handleSortBy = (id: string) => { setSortBy(id) setSortByDirection((prevState) => (prevState === 'asc' ? 'desc' : 'asc')) - sortTableData(id) } const renderSortByArrow = (selectedColumn: boolean, sortByDirection: string) => { @@ -128,12 +148,14 @@ const TableDesktopView = ({ columns, data, activeTab }: TableDesktopViewProps) = - {data.length ? ( - data.map((row, index) => { + {sortedData.length ? ( + sortedData.map((row, index) => { return ( {columns.map((column) => ( - {row[column.id]} + + {row[column.id]} + ))} ) diff --git a/src/components/Table/table.module.scss b/src/components/Table/table.module.scss index e66ad532..e246e26d 100644 --- a/src/components/Table/table.module.scss +++ b/src/components/Table/table.module.scss @@ -72,28 +72,32 @@ } .sortableColumn { + position: relative; cursor: pointer; - - svg { - display: none; - color: variables.$ssb-green-4; - margin-left: .25rem; - } - + span { - display: flex; - align-items: center; + display: inline-block; + position: relative; + padding-right: 30px; + white-space: nowrap; + + svg { + position: absolute; + top: 50%; + right: 5px; + transform: translateY(-50%); + display: none; + } } .displayArrowOnSelectedColumn { display: initial; + color: variables.$ssb-green-4; } - - &:hover { - span { - color: variables.$ssb-green-4; - } + &:hover span { + color: variables.$ssb-green-4; + svg { display: initial; } @@ -134,4 +138,11 @@ @media #{variables.$mobile} { display: flex; } +} + +.centerText { + span { + display: flex; + justify-content: center; + } } \ No newline at end of file diff --git a/src/pages/SharedBucketDetail/SharedBucketDetail.tsx b/src/pages/SharedBucketDetail/SharedBucketDetail.tsx index 8b230e46..730f6100 100644 --- a/src/pages/SharedBucketDetail/SharedBucketDetail.tsx +++ b/src/pages/SharedBucketDetail/SharedBucketDetail.tsx @@ -3,34 +3,78 @@ import styles from '../../components/PageLayout/pagelayout.module.scss' import PageLayout from '../../components/PageLayout/PageLayout' import PageSkeleton from '../../components/PageSkeleton/PageSkeleton' -import FormattedTableColumn from '../../components/FormattedTableColumn' +import FormattedTableColumn from '../../components/FormattedTableColumn/FormattedTableColumn' import Table, { TableData } from '../../components/Table/Table' import { ApiError } from '../../utils/services' -import { Team, SharedBucket, SharedBucketDetail, getSharedBucketDetailData } from '../../services/sharedBucketDetail' +import { + Team, + SharedBucket, + SharedBucketDetail as SharedBucketDetailType, + getSharedBucketDetailData, +} from '../../services/sharedBucketDetail' import { DaplaCtrlContext } from '../../provider/DaplaCtrlProvider' import { useState, useEffect, useContext } from 'react' import { useParams } from 'react-router-dom' -import { Dialog, LeadParagraph, Text } from '@statisticsnorway/ssb-component-library' +import { Dialog, LeadParagraph, Text, Link } from '@statisticsnorway/ssb-component-library' +import { formatDisplayName, getGroupType, stripSuffixes } from '../../utils/utils' const SharedBucketDetail = () => { const { setBreadcrumbTeamDetailDisplayName, setBreadcrumbBucketDetailDisplayName } = useContext(DaplaCtrlContext) const [error, setError] = useState() const [loadingSharedBucketsData, setLoadingSharedBucketsData] = useState(true) - const [sharedBucketData, setSharedBucketData] = useState() + const [sharedBucketData, setSharedBucketData] = useState() const [sharedBucketTableData, setSharedBucketTableData] = useState() const { teamId } = useParams<{ teamId: string }>() const { shortName } = useParams<{ shortName: string }>() - const prepSharedBucketTableData = (response: SharedBucketDetail): TableData['data'] => { - return (response['sharedBucket'] as SharedBucket).teams.map(({ display_name, uniform_name, section_name }) => { - return { - id: display_name ?? '', - team: , + const prepSharedBucketTableData = (response: SharedBucketDetailType): TableData['data'] => { + const usersMap: { + [principalName: string]: { + id: string + navn: JSX.Element + seksjon: string + principal_name: string + gruppe: string[] + team: JSX.Element + team_navn: string } + } = {} + + ;((response['sharedBucket'] as SharedBucket).groups ?? []).forEach(({ uniform_name, users }) => { + ;(users ?? []).forEach((user) => { + const key = `${user.principal_name}-${stripSuffixes(uniform_name)}` + if (!usersMap[key]) { + usersMap[key] = { + id: formatDisplayName(user.display_name), + navn: ( + + ), + seksjon: user.section_name, + principal_name: user.principal_name, + team_navn: stripSuffixes(uniform_name), + gruppe: [getGroupType(uniform_name)], + team: ( + + {stripSuffixes(uniform_name)} + + ), + } + } else { + usersMap[key].gruppe.push(getGroupType(uniform_name)) + } + }) }) + return Object.values(usersMap).map((user) => ({ + ...user, + gruppe: user.gruppe.join(', '), + })) } useEffect(() => { @@ -66,10 +110,18 @@ const SharedBucketDetail = () => { if (sharedBucketData) { const sharedBucketsTableHeaderColumns = [ + { + id: 'navn', + label: 'Navn', + }, { id: 'team', label: 'Team', }, + { + id: 'gruppe', + label: 'Gruppe', + }, ] return ( diff --git a/src/pages/TeamDetail/TeamDetail.tsx b/src/pages/TeamDetail/TeamDetail.tsx index e76c1e74..02ed0915 100644 --- a/src/pages/TeamDetail/TeamDetail.tsx +++ b/src/pages/TeamDetail/TeamDetail.tsx @@ -1,47 +1,157 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import styles from '../../components/PageLayout/pagelayout.module.scss' +import pageStyles from '../../components/PageLayout/pagelayout.module.scss' +import styles from './teamDetail.module.scss' -import { TabProps } from '../../@types/pageTypes' +import { DropdownItems, TabProps } from '../../@types/pageTypes' -import { useCallback, useContext, useEffect, useState } from 'react' +import { ReactElement, useCallback, useContext, useEffect, useState } from 'react' import PageLayout from '../../components/PageLayout/PageLayout' -import { TeamDetailData, getTeamDetail, Team, SharedBuckets } from '../../services/teamDetail' +import { + TeamDetailData, + getTeamDetail, + Team, + SharedBuckets, + addUserToGroups, + removeUserFromGroups, + Group, + JobResponse, +} from '../../services/teamDetail' import { useParams } from 'react-router-dom' -import { ApiError } from '../../utils/services' +import { ApiError, TokenData, fetchUserInformationFromAuthToken } from '../../utils/services' import { DaplaCtrlContext } from '../../provider/DaplaCtrlProvider' import Table, { TableData } from '../../components/Table/Table' import { formatDisplayName, getGroupType } from '../../utils/utils' -import { Text, Dialog, LeadParagraph, Divider, Tabs } from '@statisticsnorway/ssb-component-library' +import { + Text, + Dialog, + LeadParagraph, + Divider, + Tabs, + Button, + Dropdown, + Tag, + Link, +} from '@statisticsnorway/ssb-component-library' import PageSkeleton from '../../components/PageSkeleton/PageSkeleton' -import { Skeleton } from '@mui/material' -import FormattedTableColumn from '../../components/FormattedTableColumn' +import { Skeleton, CircularProgress } from '@mui/material' +import { XCircle } from 'react-feather' +import FormattedTableColumn from '../../components/FormattedTableColumn/FormattedTableColumn' +import SidebarModal from '../../components/SidebarModal/SidebarModal' +import DeleteLink from '../../components/DeleteLink/DeleteLink' +import { fetchUserSearchData, User } from '../../services/teamMembers' + +interface UserInfo { + name?: string + email?: string + groups?: Group[] +} + +interface EditUserStates { + [key: string]: boolean | Array +} const TEAM_USERS_TAB = { title: 'Teammedlemmer', path: 'team', + columns: [ + { + id: 'navn', + label: 'Navn', + }, + { + id: 'gruppe', + label: 'Gruppe', + }, + { + id: 'epost', + label: 'E-post', + }, + ], } const SHARED_BUCKETS_TAB = { title: 'Delte data', path: 'sharedBuckets', + columns: [ + { + id: 'navn', + label: 'Navn', + }, + { + id: 'tilgang', + label: 'Tilgang', + }, + // { id: 'delte_data', label: 'Delte data' }, + { id: 'antall_personer', label: 'Antall personer' }, + ], +} + +const defaultSelectedUserDropdown = { + key: 'add-selected-user', + error: false, + errorMessage: `Ugyldig navn`, +} +const defaultSelectedUser = { + id: 'search', + title: 'Søk ...', +} + +const defaultAddUserKey = 'add-user-selected-group' +const defaultEditUserKey = 'edit-user-selected-group' +const defaultSelectedGroup = { + id: 'velg', + title: 'Velg ...', } const TeamDetail = () => { const [activeTab, setActiveTab] = useState(TEAM_USERS_TAB) + const [tokenData, setTokenData] = useState() const { setBreadcrumbTeamDetailDisplayName } = useContext(DaplaCtrlContext) const [error, setError] = useState() const [loadingTeamData, setLoadingTeamData] = useState(true) + const [loadingUsers, setLoadingUsers] = useState(false) const [teamDetailData, setTeamDetailData] = useState() + const [userData, setUserData] = useState() const [teamDetailTableTitle, setTeamDetailTableTitle] = useState(TEAM_USERS_TAB.title) + const [teamDetailTableHeaderColumns, setTeamDetailTableHeaderColumns] = useState( + TEAM_USERS_TAB.columns + ) const [teamDetailTableData, setTeamDetailTableData] = useState() + // Add users to team + const [openAddUserSidebarModal, setOpenAddUserSidebarModal] = useState(false) + const [selectedUserDropdown, setSelectedUserDropdown] = useState(defaultSelectedUserDropdown) + const [selectedUser, setSelectedUser] = useState(defaultSelectedUser) + const [selectedGroupAddUser, setSelectedGroupAddUser] = useState({ + ...defaultSelectedGroup, + key: defaultAddUserKey, + }) + const [teamGroupTags, setTeamGroupTags] = useState([]) + const [teamGroupTagsError, setTeamGroupTagsError] = useState({ + error: false, + errorMessage: 'Velg minst én tilgangsgruppe', + }) + const [addUserToTeamErrors, setAddUserToTeamErrors] = useState>([]) + const [showAddUserSpinner, setShowAddUserSpinner] = useState(false) + + // Edit users in team + const [openEditUserSidebarModal, setOpenEditUserSidebarModal] = useState(false) + const [editUserInfo, setEditUserInfo] = useState({ name: '', email: '', groups: [] }) + const [selectedGroupEditUser, setSelectedGroupEditUser] = useState({ + ...defaultSelectedGroup, + key: defaultEditUserKey, + }) + const [userGroupTags, setUserGroupTags] = useState([]) + const [editUserErrors, setEditUserErrors] = useState({}) + const [showEditUserSpinner, setShowEditUserSpinner] = useState({}) + const { teamId } = useParams<{ teamId: string }>() + const teamDetailTab = (activeTab as TabProps)?.path ?? activeTab const prepTeamData = useCallback( (response: TeamDetailData): TableData['data'] => { - const teamDetailTab = (activeTab as TabProps)?.path ?? activeTab const sharedBucketsTab = SHARED_BUCKETS_TAB.path if (teamDetailTab === sharedBucketsTab) { const sharedBuckets = (response[sharedBucketsTab] as SharedBuckets).items @@ -53,7 +163,7 @@ const TeamDetail = () => { id: short_name, navn: , tilgang: typeof teams_count === 'number' ? `${teams_count} team` : teams_count, - delte_data: metrics?.groups_count, + // delte_data: '-', // To be implemented; data does not exist in the API yet. antall_personer: metrics?.users_count, } }) @@ -62,21 +172,58 @@ const TeamDetail = () => { if (!teamUsers) return [] return teamUsers.map(({ display_name, principal_name, section_name, groups }) => { + const userFullName = formatDisplayName(display_name) + const userGroups = groups?.filter((group) => + group.uniform_name.startsWith((response.team as Team).uniform_name) + ) as Group[] return { - id: formatDisplayName(display_name), + id: userFullName, navn: ( ), seksjon: section_name, // Makes section name searchable and sortable in table by including the field gruppe: groups - ?.filter((group) => group.uniform_name.startsWith((response.team as Team).uniform_name)) + ?.filter((group) => { + const baseUniformName = (response.team as Team).uniform_name + const allowedSuffixes = ['-managers', '-developers', '-data-admins', '-support', '-consumers'] + if (group.uniform_name.startsWith(baseUniformName)) { + const suffix = group.uniform_name.slice(baseUniformName.length) + return allowedSuffixes.some((allowedSuffix) => suffix.startsWith(allowedSuffix)) + } + return false + }) .map((group) => getGroupType(group.uniform_name)) .join(', '), epost: principal_name, + editUser: ( + + { + setOpenEditUserSidebarModal(true) + setEditUserInfo({ + name: formatDisplayName(display_name), + email: principal_name, + groups: userGroups, + }) + setSelectedGroupEditUser({ + ...defaultSelectedGroup, + key: `${defaultEditUserKey}-${principal_name}`, + }) + setUserGroupTags( + userGroups.map(({ uniform_name }) => { + return { id: uniform_name, title: getGroupType(uniform_name) } + }) + ) + }} + > + Endre + + + ), } }) } @@ -84,8 +231,16 @@ const TeamDetail = () => { [activeTab] ) + const isTeamManager = useCallback(() => { + const teamManagers = (teamDetailData && (teamDetailData.team as Team).managers) ?? [] + return teamManagers?.some((manager) => manager.principal_name === tokenData?.email) + }, [tokenData, teamDetailData]) + useEffect(() => { if (!teamId) return + fetchUserInformationFromAuthToken() + .then((tokenData) => setTokenData(tokenData)) + .catch((error) => setError(error as ApiError)) getTeamDetail(teamId) .then((response) => { const formattedResponse = response as TeamDetailData @@ -102,18 +257,71 @@ const TeamDetail = () => { }, []) useEffect(() => { - if (teamDetailData) setTeamDetailTableData(prepTeamData(teamDetailData)) - }, [prepTeamData]) + if (isTeamManager()) { + setTeamDetailTableHeaderColumns([ + ...TEAM_USERS_TAB.columns, + { + id: 'editUser', + label: '', + unsortable: true, + align: 'center', + }, + ]) + } + }, [isTeamManager]) - const handleTabClick = (tab: string) => { - setActiveTab(tab) - if (tab === TEAM_USERS_TAB.path) { - setTeamDetailTableTitle(TEAM_USERS_TAB.title) - } else { - setTeamDetailTableTitle(SHARED_BUCKETS_TAB.title) + useEffect(() => { + if (teamDetailData) { + if (teamDetailTab === SHARED_BUCKETS_TAB.path) { + setTeamDetailTableTitle(SHARED_BUCKETS_TAB.title) + setTeamDetailTableHeaderColumns(SHARED_BUCKETS_TAB.columns) + } else { + setTeamDetailTableTitle(TEAM_USERS_TAB.title) + if (isTeamManager()) { + setTeamDetailTableHeaderColumns([ + ...TEAM_USERS_TAB.columns, + { + id: 'editUser', + label: '', + unsortable: true, + align: 'center', + }, + ]) + } else { + setTeamDetailTableHeaderColumns(TEAM_USERS_TAB.columns) + } + } + setTeamDetailTableData(prepTeamData(teamDetailData)) } + }, [prepTeamData]) + + const getUsersAutoCompleteData = () => { + if (userData) return + setLoadingUsers(true) + fetchUserSearchData() + .then((users) => { + const filteredUsers = users.filter( + (allUsers) => + !(teamDetailData?.team as Team).users?.some( + (teamUsers) => allUsers.principal_name === teamUsers.principal_name + ) + ) + setUserData(filteredUsers) + }) + .catch((error) => { + setError(error as ApiError) + }) + .finally(() => setLoadingUsers(false)) } + useEffect(() => { + if (openAddUserSidebarModal) { + getUsersAutoCompleteData() + } + }, [openAddUserSidebarModal]) + + const handleTabClick = (tab: string) => setActiveTab(tab) + const renderErrorAlert = () => { return ( @@ -126,43 +334,14 @@ const TeamDetail = () => { if (error) return renderErrorAlert() if (loadingTeamData) return - if (teamDetailData && teamDetailTableData) { - const teamOverviewTableHeaderColumns = - activeTab === SHARED_BUCKETS_TAB.path - ? [ - { - id: 'navn', - label: 'Navn', - }, - { - id: 'tilgang', - label: 'Tilgang', - }, - { id: 'delte_data', label: 'Delte data' }, - { id: 'antall_personer', label: 'Antall personer' }, - ] - : [ - { - id: 'navn', - label: 'Navn', - }, - { - id: 'gruppe', - label: 'Gruppe', - }, - { - id: 'epost', - label: 'Epost ?', - }, - ] - + if (teamDetailData && teamDetailTableHeaderColumns && teamDetailTableData) { return ( <> - - + + {(teamDetailData.team as Team).uniform_name ?? ''} - {formatDisplayName((teamDetailData.team as Team).manager?.display_name ?? '')} + {formatDisplayName((teamDetailData.team as Team).section_manager.display_name ?? '')} {(teamDetailData.team as Team).section_name ?? ''} { @@ -190,17 +369,397 @@ const TeamDetail = () => { } } - return ( - - ) + const handleAddUser = (item: DropdownItems) => { + setSelectedUserDropdown({ ...selectedUserDropdown, key: `${defaultSelectedUserDropdown.key}-${item.id}` }) + setSelectedUser(item) + } + + const removeDuplicateDropdownItems = (items: DropdownItems[]) => { + return items.reduce((acc: DropdownItems[], dropdownItem: DropdownItems) => { + const ids = acc.map((obj) => obj.id) + if (!ids.includes(dropdownItem.id)) { + acc.push(dropdownItem) + } + return acc + }, []) + } + + const handleAddGroupTag = (item: DropdownItems) => { + if (openAddUserSidebarModal) { + const teamGroupsTags = removeDuplicateDropdownItems([...teamGroupTags, item]) + setTeamGroupTags(teamGroupsTags) + setTeamGroupTagsError({ ...teamGroupTagsError, error: false }) + setSelectedGroupAddUser({ ...item, key: `${defaultAddUserKey}-${item.id}` }) + } + + if (openEditUserSidebarModal) { + const userGroupsTagsList = removeDuplicateDropdownItems([...userGroupTags, item]) + setUserGroupTags(userGroupsTagsList) + setSelectedGroupEditUser({ ...item, key: `${defaultEditUserKey}-${item.id}` }) + } + } + + const handleDeleteGroupTag = (item: DropdownItems) => { + if (openAddUserSidebarModal) { + const teamGroupsTags = teamGroupTags.filter((items) => items !== item) + setTeamGroupTags(teamGroupsTags) + } + + if (openEditUserSidebarModal) { + const userGroupsTags = userGroupTags.filter((items) => items !== item) + setUserGroupTags(userGroupsTags) + } + } + + const getErrorList = (response: JobResponse[]) => { + return response + .map(({ status, detail }) => { + if ((detail && status === 'ERROR') || (detail && status === 'IGNORED')) { + return detail + } + return '' + }) + .filter((str) => str !== '') + } + + const handleAddUserOnSubmit = () => { + const isSelectedUserValid = selectedUser.id !== 'search' + if (!isSelectedUserValid) setSelectedUserDropdown({ ...selectedUserDropdown, error: true }) + if (!teamGroupTags.length) + setTeamGroupTagsError({ + ...teamGroupTagsError, + error: true, + }) + + if (isSelectedUserValid && teamGroupTags.length) { + setAddUserToTeamErrors([]) + setShowAddUserSpinner(true) + addUserToGroups( + teamGroupTags.map((group) => group.id), + selectedUser.id + ) + .then((response) => { + const errorsList = getErrorList(response) + if (errorsList.length) { + setAddUserToTeamErrors(errorsList) + } else { + setOpenAddUserSidebarModal(false) + setTeamGroupTags([]) + // Reset fields with their respective keys; re-initializes component + setSelectedUserDropdown({ ...defaultSelectedUserDropdown }) + setSelectedGroupAddUser({ ...defaultSelectedGroup, key: defaultAddUserKey }) + } + }) + .catch((e) => setAddUserToTeamErrors(e.message)) + .finally(() => setShowAddUserSpinner(false)) + } + } + + const resetEditUserValues = () => { + setEditUserErrors({ ...editUserErrors, [`${editUserInfo.email}`]: [] }) + setShowEditUserSpinner({ ...showEditUserSpinner, [`${editUserInfo.email}`]: true }) + } + + const handleEditUserOnSubmit = () => { + const addedGroups = + userGroupTags?.filter((groupTag) => !editUserInfo.groups?.some((group) => groupTag.id === group.uniform_name)) ?? + [] + const removedGroups = + editUserInfo.groups?.filter((group) => !userGroupTags?.some((groupTag) => groupTag.id === group.uniform_name)) ?? + [] + + if ((addedGroups.length && removedGroups.length) || addedGroups.length || removedGroups.length) { + resetEditUserValues() + } + + if (addedGroups.length && removedGroups.length) { + Promise.all([ + addUserToGroups( + addedGroups.map((group) => group.id), + editUserInfo?.email as string + ), + removeUserFromGroups( + removedGroups.map((group) => group.uniform_name), + editUserInfo?.email as string + ), + ]) + .then((response) => { + const flattenedResponse = [...response[0], ...response[1]] + const errorsList = getErrorList(flattenedResponse) + if (errorsList.length) { + setEditUserErrors({ ...editUserErrors, [`${editUserInfo.email}`]: errorsList }) + } else { + setOpenEditUserSidebarModal(false) + // Reset fields with their respective keys; re-initializes component + setSelectedGroupEditUser({ ...defaultSelectedGroup, key: defaultEditUserKey }) + } + }) + .catch((e) => setEditUserErrors({ ...editUserErrors, [`${editUserInfo.email}`]: e.message })) + .finally(() => setShowEditUserSpinner({ ...showEditUserSpinner, [`${editUserInfo.email}`]: false })) + + return + } + + if (addedGroups.length) { + addUserToGroups( + addedGroups.map((group) => group.id), + editUserInfo?.email as string + ) + .then((response) => { + const errorsList = getErrorList(response) + if (errorsList.length) { + setEditUserErrors({ ...editUserErrors, [`${editUserInfo.email}`]: errorsList }) + } else { + setOpenEditUserSidebarModal(false) + // Reset fields with their respective keys; re-initializes component + setSelectedGroupEditUser({ ...defaultSelectedGroup, key: defaultEditUserKey }) + } + }) + .catch((e) => setEditUserErrors({ ...editUserErrors, [`${editUserInfo.email}`]: e.message })) + .finally(() => setShowEditUserSpinner({ ...showEditUserSpinner, [`${editUserInfo.email}`]: false })) + + return + } + + if (removedGroups.length) { + removeUserFromGroups( + removedGroups?.map((group) => group.uniform_name), + editUserInfo.email as string + ) + .then((response) => { + const errorsList = getErrorList(response) + if (errorsList.length) { + setEditUserErrors({ ...editUserErrors, [`${editUserInfo.email}`]: errorsList }) + } else { + setOpenEditUserSidebarModal(false) + // Reset fields with their respective keys; re-initializes component + setSelectedGroupEditUser({ ...defaultSelectedGroup, key: defaultEditUserKey }) + } + }) + .catch((e) => setEditUserErrors({ ...editUserErrors, [`${editUserInfo.email}`]: e.message })) + .finally(() => setShowEditUserSpinner({ ...showEditUserSpinner, [`${editUserInfo.email}`]: false })) + + return + } + } + + const handleDeleteUser = () => { + if (editUserInfo.groups && editUserInfo.groups.length) { + resetEditUserValues() + + removeUserFromGroups( + editUserInfo.groups.map(({ uniform_name }) => uniform_name), + editUserInfo.email as string + ) + .then((response) => { + const errorsList = getErrorList(response) + if (errorsList.length) { + setEditUserErrors({ ...editUserErrors, [`${editUserInfo.email}`]: errorsList }) + } else { + setOpenEditUserSidebarModal(false) + // Reset fields with their respective keys; re-initializes component + setSelectedGroupEditUser({ ...defaultSelectedGroup, key: defaultEditUserKey }) + } + }) + .catch((e) => setEditUserErrors({ ...editUserErrors, [`${editUserInfo.email}`]: e.message })) + .finally(() => setShowEditUserSpinner({ ...showEditUserSpinner, [`${editUserInfo.email}`]: false })) + + return + } + } + + const renderSidebarModalInfo = (children: ReactElement) => { + return ( +
+ Det kan ta opp til 45 minutter før personen kan bruke tilgangen + {children} +
+ ) + } + + const renderSidebarModalWarning = (errorList: string[]) => { + if (errorList.length) { + return ( + + {typeof errorList === 'string' ? ( + errorList + ) : ( +
    + {errorList.map((errors) => ( +
  • {errors}
  • + ))} +
+ )} +
+ ) + } + } + + const teamModalHeader = teamDetailData + ? { + modalType: 'Medlem', + modalTitle: `${(teamDetailData?.team as Team).display_name}`, + modalDescription: `${(teamDetailData?.team as Team).uniform_name}`, } - content={renderContent()} - /> + : { + modalTitle: '', + } + const teamGroups = teamDetailData ? ((teamDetailData.team as Team).groups as Group[]) : [] + const renderAddUserSidebarModal = () => { + if (teamDetailData) { + return ( + setOpenAddUserSidebarModal(false)} + header={teamModalHeader} + footer={{ + submitButtonText: 'Legg til medlem', + handleSubmit: handleAddUserOnSubmit, + }} + body={{ + modalBodyTitle: 'Legg person til teamet', + modalBody: ( + <> + {!loadingUsers ? ( + { + return { + id: principal_name, + title: `${formatDisplayName(display_name)} (${principal_name})`, + } + })} + onSelect={(item: DropdownItems) => handleAddUser(item)} + error={selectedUserDropdown.error} + errorMessage={selectedUserDropdown.errorMessage} + searchable + /> + ) : ( +
+ +
+ )} + ({ + id: uniform_name, + title: getGroupType(uniform_name), + }))} + onSelect={(item: DropdownItems) => handleAddGroupTag(item)} + error={teamGroupTagsError.error} + errorMessage={teamGroupTagsError.errorMessage} + /> +
+ {teamGroupTags && + teamGroupTags.map((group) => ( + } + onClick={() => handleDeleteGroupTag(group)} + > + {group.title} + + ))} +
+
+ {renderSidebarModalInfo( + <> + {addUserToTeamErrors.length ? renderSidebarModalWarning(addUserToTeamErrors) : null} + {showAddUserSpinner && } + + )} +
+ + ), + }} + /> + ) + } + } + + const renderEditUserSidebarModal = () => { + if (teamDetailData && editUserInfo) { + return ( + setOpenEditUserSidebarModal(false)} + header={teamModalHeader} + footer={{ + submitButtonText: 'Oppdater Tilgang', + handleSubmit: handleEditUserOnSubmit, + }} + body={{ + modalBodyTitle: `Endre tilgang til "${editUserInfo.name}"`, + modalBody: ( + <> + ({ + id: uniform_name, + title: getGroupType(uniform_name), + }))} + onSelect={(item: DropdownItems) => handleAddGroupTag(item)} + /> +
+ {userGroupTags && + userGroupTags.map((group) => ( + } + onClick={() => handleDeleteGroupTag(group)} + > + {group.title} + + ))} +
+
+ + Fjern fra teamet + + {renderSidebarModalInfo( + <> + {editUserErrors?.[editUserInfo.email as string] + ? renderSidebarModalWarning(editUserErrors?.[editUserInfo.email as string] as string[]) + : null} + {showEditUserSpinner?.[editUserInfo.email as string] && } + + )} +
+ + ), + }} + /> + ) + } + } + + return ( + <> + {renderAddUserSidebarModal()} + {renderEditUserSidebarModal()} + + ) + } + content={renderContent()} + button={ + isTeamManager() ? : undefined + } + /> + ) } diff --git a/src/pages/TeamDetail/teamDetail.module.scss b/src/pages/TeamDetail/teamDetail.module.scss index 24cbd24e..1a548320 100644 --- a/src/pages/TeamDetail/teamDetail.module.scss +++ b/src/pages/TeamDetail/teamDetail.module.scss @@ -1 +1,34 @@ -@use '@statisticsnorway/ssb-component-library/src/style/variables' as variables; \ No newline at end of file +@use '@statisticsnorway/ssb-component-library/src/style/variables' as variables; + +.modalBodyDialog { + display: flex; + flex-direction: column; + align-items: center; + + > * { + margin-bottom: 1.5rem; + } + + @media #{variables.$mobile} { + height: auto; + } +} + +.inputSpacing, .dropdownSpacing { + min-width: 100%; +} + +.inputSpacing { + margin-bottom: 2.5rem; +} + +.dropdownSpacing { + margin-bottom: 1.5rem; +} + +.tagsContainer { + display: flex; + flex-wrap: wrap; + gap: .5rem; + margin-bottom: 2.5rem; +} \ No newline at end of file diff --git a/src/pages/TeamMembers/TeamMembers.tsx b/src/pages/TeamMembers/TeamMembers.tsx index 76483dea..b37d2769 100644 --- a/src/pages/TeamMembers/TeamMembers.tsx +++ b/src/pages/TeamMembers/TeamMembers.tsx @@ -10,7 +10,7 @@ import PageSkeleton from '../../components/PageSkeleton/PageSkeleton' import { fetchAllTeamMembersData, TeamMembersData } from '../../services/teamMembers' import { formatDisplayName } from '../../utils/utils' import { ApiError, fetchUserInformationFromAuthToken } from '../../utils/services' -import FormattedTableColumn from '../../components/FormattedTableColumn' +import FormattedTableColumn from '../../components/FormattedTableColumn/FormattedTableColumn' const MY_USERS_TAB = { title: 'Mine teammedlemmer', @@ -30,11 +30,11 @@ const TeamMembers = () => { const [error, setError] = useState() const [loading, setLoading] = useState(true) + const teamMembersTab = (activeTab as TabProps).path ?? activeTab + const prepUserData = useCallback( (response: TeamMembersData): TableData['data'] => { - const teamMember = (activeTab as TabProps)?.path ?? activeTab - - return response[teamMember].users.map( + return response[teamMembersTab].users.map( ({ display_name, principal_name, section_name, section_manager, teams, groups }) => ({ id: formatDisplayName(display_name), navn: ( @@ -46,7 +46,7 @@ const TeamMembers = () => { ), team: teams.length, epost: principal_name, - data_admin_roller: groups.filter((group) => group.uniform_name.endsWith('data-admins')).length, + data_admins: groups.filter((group) => group.uniform_name.endsWith('data-admins')).length, seksjon: section_name, // Makes section name searchable and sortable in table by including the field seksjonsleder: formatDisplayName( section_manager && section_manager.length > 0 @@ -74,24 +74,21 @@ const TeamMembers = () => { setLoading(false) } } - fetchData() }, []) useEffect(() => { if (teamMembersData) { + if (teamMembersTab === MY_USERS_TAB.path) { + setTeamMembersTableTitle(MY_USERS_TAB.title) + } else { + setTeamMembersTableTitle(ALL_USERS_TAB.title) + } setTeamMembersTableData(prepUserData(teamMembersData)) // Update Table view on Tab onClick } }, [prepUserData]) - const handleTabClick = (tab: string) => { - setActiveTab(tab) - if (tab === MY_USERS_TAB.path) { - setTeamMembersTableTitle(MY_USERS_TAB.title) - } else { - setTeamMembersTableTitle(ALL_USERS_TAB.title) - } - } + const handleTabClick = (tab: string) => setActiveTab(tab) const renderErrorAlert = () => { return ( @@ -116,8 +113,8 @@ const TeamMembers = () => { label: 'Team', }, { - id: 'data_admin_roller', - label: 'Data-admin-roller', + id: 'data_admins', + label: 'Som data-admin', }, { id: 'seksjonsleder', diff --git a/src/pages/TeamOverview/TeamOverview.tsx b/src/pages/TeamOverview/TeamOverview.tsx index 6daacfc8..11fb704a 100644 --- a/src/pages/TeamOverview/TeamOverview.tsx +++ b/src/pages/TeamOverview/TeamOverview.tsx @@ -10,7 +10,7 @@ import PageSkeleton from '../../components/PageSkeleton/PageSkeleton' import { fetchTeamOverviewData, TeamOverviewData } from '../../services/teamOverview' import { formatDisplayName } from '../../utils/utils' import { ApiError, fetchUserInformationFromAuthToken } from '../../utils/services' -import FormattedTableColumn from '../../components/FormattedTableColumn' +import FormattedTableColumn from '../../components/FormattedTableColumn/FormattedTableColumn' const MY_TEAMS_TAB = { title: 'Mine team', @@ -30,15 +30,16 @@ const TeamOverview = () => { const [error, setError] = useState() const [loading, setLoading] = useState(true) + const teamTab = (activeTab as TabProps)?.path ?? activeTab + const prepTeamData = useCallback( (response: TeamOverviewData): TableData['data'] => { - const teamTab = (activeTab as TabProps)?.path ?? activeTab - return response[teamTab].teams.map(({ uniform_name, section_name, users, manager }) => ({ + return response[teamTab].teams.map(({ uniform_name, section_name, users, managers }) => ({ id: uniform_name, seksjon: section_name, // Makes section name searchable and sortable in table by including the field navn: , teammedlemmer: users.length, - ansvarlig: formatDisplayName(manager.display_name), + managers: managers ? managers.map((managerObj) => formatDisplayName(managerObj.display_name)).join(', ') : '', })) }, [activeTab] @@ -65,18 +66,16 @@ const TeamOverview = () => { useEffect(() => { if (teamOverviewData) { + if (teamTab === MY_TEAMS_TAB.path) { + setTeamOverviewTableTitle(MY_TEAMS_TAB.title) + } else { + setTeamOverviewTableTitle(ALL_TEAMS_TAB.title) + } setTeamOverviewTableData(prepTeamData(teamOverviewData)) // Update Table view on Tab onClick } }, [prepTeamData]) - const handleTabClick = (tab: string) => { - setActiveTab(tab) - if (tab === MY_TEAMS_TAB.path) { - setTeamOverviewTableTitle(MY_TEAMS_TAB.title) - } else { - setTeamOverviewTableTitle(ALL_TEAMS_TAB.title) - } - } + const handleTabClick = (tab: string) => setActiveTab(tab) const renderErrorAlert = () => { return ( @@ -101,8 +100,8 @@ const TeamOverview = () => { label: 'Teammedlemmer', }, { - id: 'ansvarlig', - label: 'Ansvarlig', + id: 'managers', + label: 'Managers', }, ] diff --git a/src/pages/UserProfile/UserProfile.tsx b/src/pages/UserProfile/UserProfile.tsx index 5598d5fc..140ee446 100644 --- a/src/pages/UserProfile/UserProfile.tsx +++ b/src/pages/UserProfile/UserProfile.tsx @@ -9,14 +9,14 @@ import PageSkeleton from '../../components/PageSkeleton/PageSkeleton' import { useCallback, useContext, useEffect, useState } from 'react' import { DaplaCtrlContext } from '../../provider/DaplaCtrlProvider' -import { getGroupType, formatDisplayName } from '../../utils/utils' +import { getGroupType, formatDisplayName, stripSuffixes } from '../../utils/utils' import { getUserProfileTeamData, TeamsData } from '../../services/userProfile' import { useParams } from 'react-router-dom' import { Skeleton } from '@mui/material' import { ApiError } from '../../utils/services' -import FormattedTableColumn from '../../components/FormattedTableColumn' +import FormattedTableColumn from '../../components/FormattedTableColumn/FormattedTableColumn' const UserProfile = () => { const { setBreadcrumbUserProfileDisplayName } = useContext(DaplaCtrlContext) @@ -28,20 +28,26 @@ const UserProfile = () => { const prepTeamData = useCallback( (response: TeamsData): TableData['data'] => { - return response.teams.map(({ uniform_name, section_name, groups, manager }) => ({ + return response.teams.map(({ uniform_name, section_name, groups, managers }) => ({ id: uniform_name, seksjon: section_name, // Makes section name searchable and sortable in table by including the field navn: , gruppe: principalName ? groups - ?.filter((group) => group.users.some((user) => user.principal_name === principalName)) // Filter groups based on principalName presence + ?.filter( + (group) => + group.users.some((user) => user.principal_name === principalName) && + // making sure uniform name of the group and uniform name of the team are same + // this is to combat this issue: https://github.com/statisticsnorway/dapla-team-api-redux/issues/63 + stripSuffixes(group.uniform_name) === uniform_name + ) // Filter groups based on principalName presence .map((group) => getGroupType(group.uniform_name)) .join(', ') : 'INGEN FUNNET', - ansvarlig: formatDisplayName(manager.display_name), + managers: managers.map((managerObj) => formatDisplayName(managerObj.display_name)).join(', '), })) }, - [userProfileData] + [principalName, userProfileData] ) useEffect(() => { @@ -83,8 +89,8 @@ const UserProfile = () => { label: 'Gruppe', }, { - id: 'ansvarlig', - label: 'Ansvarlig', + id: 'managers', + label: 'Managers', }, ] return ( diff --git a/src/services/sharedBucketDetail.ts b/src/services/sharedBucketDetail.ts index 21c38367..90b9cf35 100644 --- a/src/services/sharedBucketDetail.ts +++ b/src/services/sharedBucketDetail.ts @@ -1,7 +1,6 @@ import { ApiError, fetchAPIData } from '../utils/services' -import { flattenEmbedded } from '../utils/utils' +import { flattenEmbedded, DAPLA_TEAM_API_URL } from '../utils/utils' -const DAPLA_TEAM_API_URL = import.meta.env.VITE_DAPLA_TEAM_API_URL const TEAMS_URL = `${DAPLA_TEAM_API_URL}/teams` export interface SharedBucketDetail { @@ -11,7 +10,7 @@ export interface SharedBucketDetail { export interface SharedBucket { short_name: string bucket_name: string - teams: Team[] + groups: Group[] } export interface Team { @@ -20,8 +19,19 @@ export interface Team { section_name: string } +export interface User { + display_name: string + principal_name: string + section_name: string +} + +export interface Group { + uniform_name: string + users?: User[] +} + const fetchTeamDetail = async (teamId: string): Promise => { - const teamUrl = new URL(`${TEAMS_URL}/${teamId}`) + const teamUrl = new URL(`${TEAMS_URL}/${teamId}`, window.location.origin) const selects = ['uniform_name', 'section_name'] @@ -47,10 +57,15 @@ const fetchTeamDetail = async (teamId: string): Promise => { } export const fetchSharedBucketDetailData = async (teamId: string, shortName: string): Promise => { - const sharedBucketUrl = new URL(`${TEAMS_URL}/${teamId}/shared/buckets/${shortName}`) - - const embeds = ['teams'] - const selects = ['teams.uniform_name', 'teams.display_name', 'teams.section_name'] + const sharedBucketUrl = new URL(`${TEAMS_URL}/${teamId}/shared/buckets/${shortName}`, window.location.origin) + + const embeds = ['groups', 'groups.users'] + const selects = [ + 'groups.uniform_name', + 'groups.users.principal_name', + 'groups.users.display_name', + 'groups.users.section_name', + ] sharedBucketUrl.searchParams.set('embed', embeds.join(',')) sharedBucketUrl.searchParams.set('selects', selects.join(',')) diff --git a/src/services/teamDetail.ts b/src/services/teamDetail.ts index 5564a6fb..5450809a 100644 --- a/src/services/teamDetail.ts +++ b/src/services/teamDetail.ts @@ -1,8 +1,8 @@ import { ApiError, fetchAPIData } from '../utils/services' -import { flattenEmbedded } from '../utils/utils' +import { flattenEmbedded, DAPLA_TEAM_API_URL } from '../utils/utils' -const DAPLA_TEAM_API_URL = import.meta.env.VITE_DAPLA_TEAM_API_URL const TEAMS_URL = `${DAPLA_TEAM_API_URL}/teams` +const GROUPS_URL = `${DAPLA_TEAM_API_URL}/groups` export interface TeamDetailData { [key: string]: Team | SharedBuckets // teamUsers, sharedBuckets @@ -14,7 +14,8 @@ export interface Team { display_name: string section_name: string section_code?: string - manager?: TeamManager + section_manager: User + managers?: TeamManager[] users?: User[] groups?: Group[] // eslint-disable-next-line @@ -30,10 +31,10 @@ export interface User { display_name: string principal_name: string section_name: string - groups: Group[] + groups?: Group[] } -interface Group { +export interface Group { uniform_name: string display_name: string } @@ -41,7 +42,7 @@ interface Group { export interface SharedBuckets { items: SharedBucket[] // eslint-disable-next-line - _embedded?: any + _embedded?: any } export interface SharedBucket { @@ -56,9 +57,16 @@ export interface Metrics { users_count?: number | string } +export interface JobResponse { + status: string + detail?: string +} + +type Method = 'POST' | 'DELETE' // POST = ADD, DELETE = REMOVE + export const fetchTeamInfo = async (teamId: string): Promise => { - const teamsUrl = new URL(`${TEAMS_URL}/${teamId}`) - const embeds = ['users', 'users.groups', 'managers'] + const teamsUrl = new URL(`${TEAMS_URL}/${teamId}`, window.location.origin) + const embeds = ['users', 'users.groups', 'managers', 'groups'] const selects = [ 'uniform_name', 'display_name', @@ -70,6 +78,7 @@ export const fetchTeamInfo = async (teamId: string): Promise => 'users.display_name', 'users.section_name', 'users.groups.uniform_name', + 'groups.uniform_name', ] teamsUrl.searchParams.set('embed', embeds.join(',')) @@ -80,16 +89,25 @@ export const fetchTeamInfo = async (teamId: string): Promise => const flattendTeams = flattenEmbedded(teamDetailData) if (!flattendTeams) return {} as Team if (!flattendTeams.users) flattendTeams.users = [] + flattendTeams.users.forEach((user: User) => { + if (!user.section_name || user.section_name === '') user.section_name = 'Mangler seksjon' + }) + if (!flattendTeams.groups) flattendTeams.groups = [] if (!flattendTeams.managers || flattendTeams.managers.length === 0) { flattendTeams.manager = { display_name: 'Ikke funnet', principal_name: 'Ikke funnet', section_name: 'Ikke funnet', } + } + + if (flattendTeams._links && flattendTeams._links.section_manager) { + const sectionManagerUrl = new URL(flattendTeams._links.section_manager.href) + const path = sectionManagerUrl.pathname + flattendTeams.section_manager = await fetchTeamSectionManager(`${DAPLA_TEAM_API_URL}${path}`) } else { - flattendTeams.manager = flattendTeams.managers[0] + flattendTeams.section_manager = { display_name: 'Seksjonsleder ikke funnet', principal_name: 'Ikkefunnet@ssb.no' } } - delete flattendTeams.managers return flattendTeams } catch (error) { @@ -105,7 +123,7 @@ export const fetchTeamInfo = async (teamId: string): Promise => } export const fetchSharedBuckets = async (teamId: string): Promise => { - const sharedBucketsUrl = new URL(`${TEAMS_URL}/${teamId}/shared/buckets`) + const sharedBucketsUrl = new URL(`${TEAMS_URL}/${teamId}/shared/buckets`, window.location.origin) const embeds = ['metrics'] const selects = ['short_name', 'bucket_name', 'metrics.teams_count', 'metrics.groups_count', 'metrics.users_count'] @@ -144,6 +162,23 @@ export const fetchSharedBuckets = async (teamId: string): Promise { + try { + const response = await fetchAPIData(url) + + return response + } catch (error) { + if (error instanceof ApiError) { + console.error('Failed to fetch team section manager:', error) + throw error + } else { + const apiError = new ApiError(500, 'An unexpected error occurred') + console.error('Failed to fetch team section manager:', apiError) + throw apiError + } + } +} + export const getTeamDetail = async (teamId: string): Promise => { try { const [teamInfo, sharedBuckets] = await Promise.all([fetchTeamInfo(teamId), fetchSharedBuckets(teamId)]) @@ -155,7 +190,92 @@ export const getTeamDetail = async (teamId: string): Promise => throw error } else { const apiError = new ApiError(500, 'An unexpected error occurred') - console.error('FFailed to fetch data for teamDetail page:', apiError) + console.error('Failed to fetch data for teamDetail page:', apiError) + throw apiError + } + } +} + +export const addUserToGroups = async (groupIds: string[], userPrincipalName: string): Promise => { + try { + const jobResponses = await Promise.all( + groupIds.map((groupId) => updateGroupMembership(groupId, userPrincipalName, 'POST')) + ) + return jobResponses + } catch (error) { + if (error instanceof ApiError) { + console.error('Failed to add user to groups: ', error) + throw error + } else { + const apiError = new ApiError(500, 'An unexpected error occurred') + console.error('Failed to add user to groups: ', apiError) + throw apiError + } + } +} + +export const removeUserFromGroups = async (groupIds: string[], userPrincipalName: string): Promise => { + try { + const jobResponses = await Promise.all( + groupIds.map((groupId) => updateGroupMembership(groupId, userPrincipalName, 'DELETE')) + ) + return jobResponses + } catch (error) { + if (error instanceof ApiError) { + console.error('Failed to remove user from groups: ', error) + throw error + } else { + const apiError = new ApiError(500, 'An unexpected error occurred') + console.error('Failed to remove user from groups: ', apiError) + throw apiError + } + } +} + +const updateGroupMembership = async ( + groupId: string, + userPrincipalName: string, + method: Method +): Promise => { + let groupsUrl = `${GROUPS_URL}/${groupId}/users` + const fetchOptions: RequestInit = { + method: method, + headers: { + Accept: '*/*', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + users: [userPrincipalName], + }), + } + + // TODO: Remove me once DELETE with proxy is fixed + if (method === 'DELETE') { + groupsUrl = `/localApi/groups/${groupId}/${userPrincipalName}` + // Don't include body in fetch options for DELETE method + delete fetchOptions.body + } + + try { + const response = await fetch(groupsUrl, fetchOptions) + + if (!response.ok) { + const errorMessage = (await response.text()) || 'An error occurred' + const { detail, status } = JSON.parse(errorMessage) + throw new ApiError(status, detail) + } + + const responseJson = await response.json() + const flattenedResponse = { ...responseJson._embedded.results[0] } + + return flattenedResponse + } catch (error) { + if (error instanceof ApiError) { + console.error('Failed to update group membership: ', error) + throw error + } else { + const apiError = new ApiError(500, 'An unexpected error occurred') + console.error('Failed to update group membership: ', apiError) throw apiError } } diff --git a/src/services/teamMembers.ts b/src/services/teamMembers.ts index 3637a0c2..3d02cd7e 100644 --- a/src/services/teamMembers.ts +++ b/src/services/teamMembers.ts @@ -1,13 +1,13 @@ import { ApiError, fetchAPIData } from '../utils/services' +import { DAPLA_TEAM_API_URL } from '../utils/utils' -const DAPLA_TEAM_API_URL = import.meta.env.VITE_DAPLA_TEAM_API_URL const USERS_URL = `${DAPLA_TEAM_API_URL}/users` export interface TeamMembersData { [key: string]: UsersData // myUsers, allUsers } -interface UsersData { +export interface UsersData { users: User[] } @@ -36,7 +36,7 @@ interface Group { } const fetchManagedUsers = async (principalName: string): Promise => { - const usersUrl = new URL(`${USERS_URL}/${principalName}`) + const usersUrl = new URL(`${USERS_URL}/${principalName}`, window.location.origin) const embeds = ['managed_users'] const selects = ['managed_users.principal_name'] @@ -68,7 +68,7 @@ export const fetchManagedUsersManagers = async (principalName: string): Promise< const prepUsers = await Promise.all( users.map(async (user): Promise => { - const usersUrl = new URL(`${USERS_URL}/${user.principal_name}`) + const usersUrl = new URL(`${USERS_URL}/${user.principal_name}`, window.location.origin) const embeds = ['teams', 'groups', 'section_manager'] const selects = [ @@ -110,7 +110,7 @@ export const fetchManagedUsersManagers = async (principalName: string): Promise< } export const fetchAllUsers = async (): Promise => { - const usersUrl = new URL(`${USERS_URL}`) + const usersUrl = new URL(`${USERS_URL}`, window.location.origin) const embeds = ['section_manager', 'teams', 'groups'] const selects = [ @@ -171,3 +171,35 @@ export const fetchAllTeamMembersData = async (principalName: string): Promise => { + const usersUrl = '/localApi/users' + + try { + const allUsersData = await fetchAPIData(usersUrl) + + if (!allUsersData) throw new ApiError(500, 'No json data returned') + if (!allUsersData._embedded || !allUsersData._embedded.users) throw new ApiError(500, 'Did not receive users data') + + const prepData = allUsersData._embedded.users.map((user: User) => { + const prepUserData = { + ...user, + ...user._embedded, + } + delete prepUserData._embedded + return prepUserData + }) + delete prepData._embedded + + return prepData + } catch (error) { + if (error instanceof ApiError) { + console.error('Failed to fetch user search data:', error) + throw error + } else { + const apiError = new ApiError(500, 'An unexpected error occurred') + console.error('Failed to fetch user search data:', apiError) + throw apiError + } + } +} diff --git a/src/services/teamOverview.ts b/src/services/teamOverview.ts index e4dcc822..66309b83 100644 --- a/src/services/teamOverview.ts +++ b/src/services/teamOverview.ts @@ -1,6 +1,6 @@ import { ApiError, fetchAPIData } from '../utils/services' -import { flattenEmbedded } from '../utils/utils' -const DAPLA_TEAM_API_URL = import.meta.env.VITE_DAPLA_TEAM_API_URL +import { flattenEmbedded, DAPLA_TEAM_API_URL } from '../utils/utils' + const USERS_URL = `${DAPLA_TEAM_API_URL}/users` const TEAMS_URL = `${DAPLA_TEAM_API_URL}/teams` @@ -18,7 +18,7 @@ export interface Team { display_name: string section_name: string section_code: string - manager: TeamManager + managers: TeamManager[] users: User[] groups: Group[] // eslint-disable-next-line @@ -42,7 +42,7 @@ interface Group { } const fetchAllTeams = async (): Promise => { - const teamsUrl = new URL(`${TEAMS_URL}`) + const teamsUrl = new URL(`${TEAMS_URL}`, window.location.origin) const embeds = ['users', 'groups.users'] const selects = [ @@ -75,13 +75,24 @@ const fetchAllTeams = async (): Promise => { }) const flattedTeamsWithManager = flattedTeams.teams.map((team: Team) => { - const managers = team.groups.find((group) => group.uniform_name === `${team.uniform_name}-managers`) + const managersGroup = team.groups.find((group) => group.uniform_name === `${team.uniform_name}-managers`) + + const managers = + managersGroup && managersGroup.users && managersGroup.users.length > 0 + ? managersGroup.users.map((manager) => ({ + display_name: manager.display_name, + principal_name: manager.principal_name, + })) + : [ + { + display_name: 'Mangler managers', + principal_name: 'ManglerManagers@ssb.no', + }, + ] + return { ...team, - manager: - managers && managers.users && managers.users.length > 0 - ? { display_name: managers.users[0].display_name, principal_name: managers.users[0].principal_name } - : { display_name: 'Mangler manager', principal_name: 'ManglerManager@ssb.no' }, + managers: managers, } }) @@ -99,7 +110,7 @@ const fetchAllTeams = async (): Promise => { } const fetchTeamsForPrincipalName = async (principalName: string): Promise => { - const usersUrl = new URL(`${USERS_URL}/${principalName}`) + const usersUrl = new URL(`${USERS_URL}/${principalName}`, window.location.origin) const embeds = ['teams', 'teams.users', 'teams.groups.users'] const selects = [ @@ -129,13 +140,24 @@ const fetchTeamsForPrincipalName = async (principalName: string): Promise { - const managers = team.groups.find((group) => group.uniform_name === `${team.uniform_name}-managers`) + const managersGroup = team.groups.find((group) => group.uniform_name === `${team.uniform_name}-managers`) + + const managers = + managersGroup && managersGroup.users && managersGroup.users.length > 0 + ? managersGroup.users.map((manager) => ({ + display_name: manager.display_name, + principal_name: manager.principal_name, + })) + : [ + { + display_name: 'Mangler manager', + principal_name: 'ManglerManagers@ssb.no', + }, + ] + return { ...team, - manager: - managers && managers.users && managers.users.length > 0 - ? { display_name: managers.users[0].display_name, principal_name: managers.users[0].principal_name } - : { display_name: 'Mangler ansvarlig', principal_name: 'ManglerAnsvarlig@ssb.no' }, + managers: managers, } }) diff --git a/src/services/userProfile.ts b/src/services/userProfile.ts index b198d571..e0cebaaf 100644 --- a/src/services/userProfile.ts +++ b/src/services/userProfile.ts @@ -1,7 +1,6 @@ import { ApiError, fetchAPIData } from '../utils/services' -import { flattenEmbedded } from '../utils/utils' +import { flattenEmbedded, DAPLA_TEAM_API_URL } from '../utils/utils' -const DAPLA_TEAM_API_URL = import.meta.env.VITE_DAPLA_TEAM_API_URL const USERS_URL = `${DAPLA_TEAM_API_URL}/users` export interface UserProfileTeamData { @@ -19,7 +18,7 @@ export interface Team { display_name: string section_name: string section_code: string - manager: TeamManager + managers: TeamManager[] users: User[] groups: Group[] // eslint-disable-next-line @@ -48,8 +47,7 @@ interface Group { } export const getUserProfile = async (principalName: string): Promise => { - const usersUrl = new URL(`${USERS_URL}/${principalName}`) - + const usersUrl = new URL(`${USERS_URL}/${principalName}`, window.location.origin) const embeds = ['section_manager'] const selects = [ 'principal_name', @@ -85,7 +83,7 @@ export const getUserProfile = async (principalName: string): Promise => { - const usersUrl = new URL(`${USERS_URL}/${principalName}`) + const usersUrl = new URL(`${USERS_URL}/${principalName}`, window.location.origin) const embeds = ['teams', 'teams.groups', 'teams.groups.users'] const selects = [ @@ -94,7 +92,7 @@ export const getUserProfileTeamData = async (principalName: string): Promise { - const managers = team.groups.find((group) => group.uniform_name === `${team.uniform_name}-managers`) + const managersGroup = team.groups.find((group) => group.uniform_name === `${team.uniform_name}-managers`) + + const managers = + managersGroup && managersGroup.users && managersGroup.users.length > 0 + ? managersGroup.users.map((manager) => ({ + display_name: manager.display_name, + principal_name: manager.principal_name, + })) + : [ + { + display_name: 'Mangler managers', + principal_name: 'ManglerManagers@ssb.no', + }, + ] + return { ...team, - manager: - managers && managers.users && managers.users.length > 0 - ? { display_name: managers.users[0].display_name, principal_name: managers.users[0].principal_name } - : { display_name: 'Mangler ansvarlig', principal_name: 'ManglerAnsvarlig@ssb.no' }, + managers: managers, } }) @@ -144,7 +153,7 @@ export const getUserProfileTeamData = async (principalName: string): Promise { - const response = await fetch(`/api/photo/${principalName}`) + const response = await fetch(`/localApi/photo/${principalName}`) if (!response.ok) { throw new ApiError(500, 'could not fetch photo') diff --git a/src/utils/services.ts b/src/utils/services.ts index 6655da12..dd66fff4 100644 --- a/src/utils/services.ts +++ b/src/utils/services.ts @@ -11,7 +11,7 @@ export const fetchAPIData = async (url: string): Promise => { return response.json() } -interface TokenData { +export interface TokenData { name: string given_name: string family_name: string @@ -19,7 +19,7 @@ interface TokenData { } export const fetchUserInformationFromAuthToken = async (): Promise => { - const response = await fetch('/api/fetch-token') + const response = await fetch('/localApi/fetch-token') const tokenData = await response.json() const jwt = JSON.parse(atob(tokenData.token.split('.')[1])) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index e9a0f171..ea21fae2 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,22 +1,35 @@ +// https://vitejs.dev/config/server-options.html +// https://github.com/garronej/vite-envs + +export const DAPLA_TEAM_API_URL = `/api` + export const getGroupType = (groupName: string) => { const match = groupName.match(/(managers|developers|data-admins|support|consumers)$/) const role = match ? match[0] : null switch (role) { case 'managers': - return 'Manager' + return 'managers' case 'developers': - return 'Developers' + return 'developers' case 'data-admins': - return 'Data-admins' + return 'data-admins' case 'support': - return 'Support' + return 'support' case 'consumers': - return 'Consumers' + return 'consumers' default: return groupName } } +export const stripSuffixes = (inputString: string) => { + // Regular expression to match the specified suffixes + const suffixesPattern = /-(data-admins|managers|developers|consumers|support)$/ + + // Replace matched suffix with an empty string + return inputString.replace(suffixesPattern, '') +} + export const formatDisplayName = (displayName: string) => { return displayName.split(', ').reverse().join(' ') }