From ead8f43b7ff941b50a3d4b487157e33483886e3e Mon Sep 17 00:00:00 2001 From: hugolxt <87241914+hugolxt@users.noreply.github.com> Date: Wed, 15 Mar 2023 14:40:23 +0100 Subject: [PATCH] Staging implementation (#9) The creation of a single repository is no longer relevant. Therefore, we have to separate the front and back repo into two distinct repositories. This PR allows to repatriate the work on dev branch --- .vscode/settings.json | 5 +- package-lock.json | 1430 ++++++++++++++++- package.json | 7 +- src/api/controllers/ProjectController.ts | 15 +- .../config/{ => database}/IDatabaseConfig.ts | 0 src/common/config/variables/Variables.ts | 85 + src/common/cron/Cron.ts | 67 + src/common/cron/IConfig.ts | 12 + src/common/cron/index.ts | 4 + src/common/databases/database.ts | 5 +- .../migration.sql | 56 +- .../migration.sql | 2 + .../migration.sql | 2 + .../migration.sql | 32 + src/common/helpers/FunctionBinder.ts | 42 + src/common/helpers/ObjectHydrate.ts | 12 +- src/common/helpers/ProxyHelpers.ts | 13 + src/common/repositories/BaseRepository.ts | 4 + src/common/repositories/MetricsRepository.ts | 190 --- src/common/repositories/ProjectRepository.ts | 62 - .../repositories/metrics/MetricsRepository.ts | 220 +++ .../projects/ProjectsRepository.ts | 63 + src/common/ressources/MetricEntity.ts | 35 +- src/common/ressources/ProjectEntity.ts | 20 +- src/common/services/BaseService.ts | 11 +- src/common/services/metric/MetricService.ts | 88 - src/common/services/metric/MetricsService.ts | 76 + src/common/services/project/ProjectService.ts | 39 - .../services/project/ProjectsService.ts | 37 + src/common/services/proxy/ProxyService.ts | 119 ++ .../proxy/validators/IsRpcPathAllowed.ts | 31 + .../proxy/validators/IsValidProject.ts | 24 + src/common/system/database/DbProvider.ts | 14 +- src/common/system/database/index.ts | 2 +- src/common/system/interfaces/Interfaces.ts | 9 + src/entries/Api.ts | 46 +- src/entries/Web.ts | 32 +- .../DesignSystem/CheckBox/classes.module.scss | 4 +- .../Elements/InputField/classes.module.scss | 18 +- .../Form/Elements/InputField/index.tsx | 4 +- .../NotificationModal/classes.module.scss | 10 + .../Profile/ProfileModal/classes.module.scss | 11 + .../DesignSystem/Modal/classes.module.scss | 20 + .../DesignSystem/RadioBox/classes.module.scss | 4 +- .../ToastElement/classes.module.scss | 2 +- .../Components/DesignSystem/ToolTip/index.tsx | 50 +- .../LayoutTemplates/DefaultLayout.tsx | 1 - .../Components/Layouts/DesignSystem/index.tsx | 2 +- src/front/Config/VariablesFront.ts | 37 + src/front/Themes/variables.scss | 26 +- src/front/index.scss | 1 + 51 files changed, 2540 insertions(+), 561 deletions(-) rename src/common/config/{ => database}/IDatabaseConfig.ts (100%) create mode 100644 src/common/config/variables/Variables.ts create mode 100644 src/common/cron/Cron.ts create mode 100644 src/common/cron/IConfig.ts create mode 100644 src/common/cron/index.ts create mode 100644 src/common/databases/migrations/20230224095135_remove_metrics_uuid_uniqueness/migration.sql create mode 100644 src/common/databases/migrations/20230227152159_remove_requested_date_format/migration.sql create mode 100644 src/common/databases/migrations/20230301110217_remove_ids_projects_metrics/migration.sql create mode 100644 src/common/helpers/FunctionBinder.ts create mode 100644 src/common/helpers/ProxyHelpers.ts create mode 100644 src/common/repositories/BaseRepository.ts delete mode 100644 src/common/repositories/MetricsRepository.ts delete mode 100644 src/common/repositories/ProjectRepository.ts create mode 100644 src/common/repositories/metrics/MetricsRepository.ts create mode 100644 src/common/repositories/projects/ProjectsRepository.ts delete mode 100644 src/common/services/metric/MetricService.ts create mode 100644 src/common/services/metric/MetricsService.ts delete mode 100644 src/common/services/project/ProjectService.ts create mode 100644 src/common/services/project/ProjectsService.ts create mode 100644 src/common/services/proxy/ProxyService.ts create mode 100644 src/common/services/proxy/validators/IsRpcPathAllowed.ts create mode 100644 src/common/services/proxy/validators/IsValidProject.ts create mode 100644 src/common/system/interfaces/Interfaces.ts create mode 100644 src/front/Config/VariablesFront.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 4b5c7184..5937d2ba 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -37,5 +37,8 @@ "rust-client.rustupPath": "${env:HOME}/elrondsdk/vendor-rust/bin/rustup", "rust-client.rlsPath": "${env:HOME}/elrondsdk/vendor-rust/bin/rls", "rust-client.disableRustup": true, - "rust-client.autoStartRls": false + "rust-client.autoStartRls": false, + "[prisma]": { + "editor.defaultFormatter": "Prisma.prisma" + } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 50dda645..c77d3229 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,9 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@mui/material": "^5.11.12", "@prisma/client": "^4.9.0", "apexcharts": "^3.36.3", "axios": "^1.3.3", @@ -20,6 +23,7 @@ "express": "^4.18.2", "module-alias": "^2.2.2", "next": "^13.1.5", + "node-schedule": "^2.1.1", "prisma": "^4.9.0", "prisma-query": "^2.0.0", "react": "^18.2.0", @@ -39,6 +43,7 @@ "@types/cors": "^2.8.13", "@types/express": "^4.17.16", "@types/node": "^18.11.18", + "@types/node-schedule": "^2.1.0", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "@types/uuid": "^9.0.0", @@ -46,6 +51,81 @@ "prettier": "2.8.4" } }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.2.tgz", + "integrity": "sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==", + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -57,6 +137,139 @@ "node": ">=12" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", + "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.1", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.1.3" + } + }, + "node_modules/@emotion/cache": { + "version": "11.10.5", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", + "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", + "dependencies": { + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.1", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "stylis": "4.1.3" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "dependencies": { + "@emotion/memoize": "^0.8.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + }, + "node_modules/@emotion/react": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz", + "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/cache": "^11.10.5", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", + "dependencies": { + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", + "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" + }, + "node_modules/@emotion/styled": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz", + "integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/is-prop-valid": "^1.2.0", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", + "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", + "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", @@ -79,6 +292,237 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@mui/base": { + "version": "5.0.0-alpha.119", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.119.tgz", + "integrity": "sha512-XA5zhlYfXi67u613eIF0xRmktkatx6ERy3h+PwrMN5IcWFbgiL1guz8VpdXON+GWb8+G7B8t5oqTFIaCqaSAeA==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@emotion/is-prop-valid": "^1.2.0", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.11", + "@popperjs/core": "^2.11.6", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/base/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.11.12", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.12.tgz", + "integrity": "sha512-LHh8HZQ5nPVcW5QnyLwkAZ40txc/S2bzKMQ3bTO+5mjuwAJ2AzQrjZINLVy1geY7ei1pHXVqO1hcWHg/QdT44w==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + } + }, + "node_modules/@mui/material": { + "version": "5.11.12", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.12.tgz", + "integrity": "sha512-M6BiIeJjySeEzWeiFJQ9pIjJy6mx5mHPWeMT99wjQdAmA2GxCQhE9A0fh6jQP4jMmYzxhOIhjsGcp0vSdpseXg==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/base": "5.0.0-alpha.119", + "@mui/core-downloads-tracker": "^5.11.12", + "@mui/system": "^5.11.12", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.12", + "@types/react-transition-group": "^4.4.5", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/@mui/private-theming": { + "version": "5.11.12", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.12.tgz", + "integrity": "sha512-hnJ0svNI1TPeWZ18E6DvES8PB4NyMLwal6EyXf69rTrYqT6wZPLjB+HiCYfSOCqU/fwArhupSqIIkQpDs8CkAw==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/utils": "^5.11.12", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.11.tgz", + "integrity": "sha512-wV0UgW4lN5FkDBXefN8eTYeuE9sjyQdg5h94vtwZCUamGQEzmCOtir4AakgmbWMy0x8OLjdEUESn9wnf5J9MOg==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@emotion/cache": "^11.10.5", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.11.12", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.12.tgz", + "integrity": "sha512-sYjsXkiwKpZDC3aS6O/6KTjji0jGINLQcrD5EJ5NTkIDiLf19I4HJhnufgKqlTWNfoDBlRohuTf3TzfM06c4ug==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@mui/private-theming": "^5.11.12", + "@mui/styled-engine": "^5.11.11", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.12", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz", + "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.11.12", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.12.tgz", + "integrity": "sha512-5vH9B/v8pzkpEPO2HvGM54ToXV6cFdAn8UrvdN8TMEEwpn/ycW0jLiyBcgUlPsQ+xha7hqXCPQYHaYFDIcwaiw==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@types/prop-types": "^15.7.5", + "@types/react-is": "^16.7.1 || ^17.0.0", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/@next/env": { "version": "13.1.5", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.1.5.tgz", @@ -279,6 +723,15 @@ "node": ">= 10" } }, + "node_modules/@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@prisma/client": { "version": "4.9.0", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.9.0.tgz", @@ -400,11 +853,24 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" }, + "node_modules/@types/node-schedule": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/node-schedule/-/node-schedule-2.1.0.tgz", + "integrity": "sha512-NiTwl8YN3v/1YCKrDFSmCTkVxFDylueEqsOFdgF+vPsm+AlyJKGAo5yzX1FiOxPsZiN6/r8gJitYx2EaSuBmmg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -422,7 +888,6 @@ "version": "18.0.27", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", - "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -438,11 +903,26 @@ "@types/react": "*" } }, + "node_modules/@types/react-is": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", + "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "node_modules/@types/serve-static": { "version": "1.15.0", @@ -502,6 +982,17 @@ "node": ">=0.4.0" } }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -552,6 +1043,20 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -630,6 +1135,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001449", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001449.tgz", @@ -645,6 +1158,27 @@ } ] }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -696,6 +1230,27 @@ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -732,6 +1287,11 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, "node_modules/cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -757,16 +1317,41 @@ "node": ">= 0.10" } }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, + "node_modules/cron-parser": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.8.1.tgz", + "integrity": "sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ==", + "dependencies": { + "luxon": "^3.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/csstype": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", - "dev": true + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "node_modules/debug": { "version": "2.6.9", @@ -809,6 +1394,15 @@ "node": ">=0.3.1" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dotenv": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", @@ -830,11 +1424,30 @@ "node": ">= 0.8" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -917,6 +1530,11 @@ "node": ">= 0.8" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -1022,7 +1640,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -1038,6 +1655,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -1075,6 +1700,21 @@ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz", "integrity": "sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==" }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -1088,6 +1728,11 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1099,6 +1744,17 @@ "node": ">=8" } }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1131,11 +1787,26 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, "node_modules/libphonenumber-js": { "version": "1.10.18", "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.18.tgz", "integrity": "sha512-NS4ZEgNhwbcPz1gfSXCGFnQm0xEiyTSPRthIuWytDzOiEG9xnZ2FbLyfJC4tI2BMAAXpoWbNxHYH75pa3Dq9og==" }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/long-timeout": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", + "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -1147,6 +1818,14 @@ "loose-envify": "cli.js" } }, + "node_modules/luxon": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz", + "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==", + "engines": { + "node": ">=12" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -1295,6 +1974,19 @@ } } }, + "node_modules/node-schedule": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", + "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", + "dependencies": { + "cron-parser": "^4.2.0", + "long-timeout": "0.1.1", + "sorted-array-functions": "^1.3.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/nodemon": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", @@ -1388,6 +2080,34 @@ "node": ">= 0.8" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1396,11 +2116,24 @@ "node": ">= 0.8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -1585,6 +2318,21 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/react-tsparticles": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/react-tsparticles/-/react-tsparticles-2.8.0.tgz", @@ -1624,6 +2372,35 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1762,6 +2539,19 @@ "semver": "bin/semver.js" } }, + "node_modules/sorted-array-functions": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz", + "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==" + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -1800,11 +2590,15 @@ } } }, + "node_modules/stylis": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", + "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -1812,6 +2606,17 @@ "node": ">=4" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/svg.draggable.js": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz", @@ -1895,6 +2700,14 @@ "node": ">= 0.8.0" } }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2459,6 +3272,14 @@ "node": ">= 0.8" } }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -2469,6 +3290,60 @@ } }, "dependencies": { + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, + "@babel/types": { + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.2.tgz", + "integrity": "sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==", + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, "@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -2477,6 +3352,120 @@ "@jridgewell/trace-mapping": "0.3.9" } }, + "@emotion/babel-plugin": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", + "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.1", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.1.3" + } + }, + "@emotion/cache": { + "version": "11.10.5", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", + "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", + "requires": { + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.1", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "stylis": "4.1.3" + } + }, + "@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + }, + "@emotion/is-prop-valid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "requires": { + "@emotion/memoize": "^0.8.0" + } + }, + "@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + }, + "@emotion/react": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz", + "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/cache": "^11.10.5", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "hoist-non-react-statics": "^3.3.1" + } + }, + "@emotion/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", + "requires": { + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", + "csstype": "^3.0.2" + } + }, + "@emotion/sheet": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", + "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" + }, + "@emotion/styled": { + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz", + "integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/is-prop-valid": "^1.2.0", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0" + } + }, + "@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, + "@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "requires": {} + }, + "@emotion/utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", + "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + }, + "@emotion/weak-memoize": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", + "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + }, "@jridgewell/resolve-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", @@ -2496,6 +3485,120 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@mui/base": { + "version": "5.0.0-alpha.119", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.119.tgz", + "integrity": "sha512-XA5zhlYfXi67u613eIF0xRmktkatx6ERy3h+PwrMN5IcWFbgiL1guz8VpdXON+GWb8+G7B8t5oqTFIaCqaSAeA==", + "requires": { + "@babel/runtime": "^7.21.0", + "@emotion/is-prop-valid": "^1.2.0", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.11", + "@popperjs/core": "^2.11.6", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, + "@mui/core-downloads-tracker": { + "version": "5.11.12", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.12.tgz", + "integrity": "sha512-LHh8HZQ5nPVcW5QnyLwkAZ40txc/S2bzKMQ3bTO+5mjuwAJ2AzQrjZINLVy1geY7ei1pHXVqO1hcWHg/QdT44w==" + }, + "@mui/material": { + "version": "5.11.12", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.12.tgz", + "integrity": "sha512-M6BiIeJjySeEzWeiFJQ9pIjJy6mx5mHPWeMT99wjQdAmA2GxCQhE9A0fh6jQP4jMmYzxhOIhjsGcp0vSdpseXg==", + "requires": { + "@babel/runtime": "^7.21.0", + "@mui/base": "5.0.0-alpha.119", + "@mui/core-downloads-tracker": "^5.11.12", + "@mui/system": "^5.11.12", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.12", + "@types/react-transition-group": "^4.4.5", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, + "@mui/private-theming": { + "version": "5.11.12", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.12.tgz", + "integrity": "sha512-hnJ0svNI1TPeWZ18E6DvES8PB4NyMLwal6EyXf69rTrYqT6wZPLjB+HiCYfSOCqU/fwArhupSqIIkQpDs8CkAw==", + "requires": { + "@babel/runtime": "^7.21.0", + "@mui/utils": "^5.11.12", + "prop-types": "^15.8.1" + } + }, + "@mui/styled-engine": { + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.11.tgz", + "integrity": "sha512-wV0UgW4lN5FkDBXefN8eTYeuE9sjyQdg5h94vtwZCUamGQEzmCOtir4AakgmbWMy0x8OLjdEUESn9wnf5J9MOg==", + "requires": { + "@babel/runtime": "^7.21.0", + "@emotion/cache": "^11.10.5", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + } + }, + "@mui/system": { + "version": "5.11.12", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.12.tgz", + "integrity": "sha512-sYjsXkiwKpZDC3aS6O/6KTjji0jGINLQcrD5EJ5NTkIDiLf19I4HJhnufgKqlTWNfoDBlRohuTf3TzfM06c4ug==", + "requires": { + "@babel/runtime": "^7.21.0", + "@mui/private-theming": "^5.11.12", + "@mui/styled-engine": "^5.11.11", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.12", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + } + }, + "@mui/types": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz", + "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==", + "requires": {} + }, + "@mui/utils": { + "version": "5.11.12", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.12.tgz", + "integrity": "sha512-5vH9B/v8pzkpEPO2HvGM54ToXV6cFdAn8UrvdN8TMEEwpn/ycW0jLiyBcgUlPsQ+xha7hqXCPQYHaYFDIcwaiw==", + "requires": { + "@babel/runtime": "^7.21.0", + "@types/prop-types": "^15.7.5", + "@types/react-is": "^16.7.1 || ^17.0.0", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, "@next/env": { "version": "13.1.5", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.1.5.tgz", @@ -2579,6 +3682,11 @@ "integrity": "sha512-IZHwvd649ccbWyLCfu92IXEpR250NpmBkaRelPV+WVm4jrd62FKRFCNdqdCXq6TrEg9wN8cK4YG8tm44uEZqLA==", "optional": true }, + "@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" + }, "@prisma/client": { "version": "4.9.0", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.9.0.tgz", @@ -2687,11 +3795,24 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" }, + "@types/node-schedule": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/node-schedule/-/node-schedule-2.1.0.tgz", + "integrity": "sha512-NiTwl8YN3v/1YCKrDFSmCTkVxFDylueEqsOFdgF+vPsm+AlyJKGAo5yzX1FiOxPsZiN6/r8gJitYx2EaSuBmmg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, "@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "@types/qs": { "version": "6.9.7", @@ -2709,7 +3830,6 @@ "version": "18.0.27", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", - "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2725,11 +3845,26 @@ "@types/react": "*" } }, + "@types/react-is": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", + "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "requires": { + "@types/react": "*" + } + }, + "@types/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "requires": { + "@types/react": "*" + } + }, "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "@types/serve-static": { "version": "1.15.0", @@ -2777,6 +3912,14 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, "anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -2824,6 +3967,16 @@ "proxy-from-env": "^1.1.0" } }, + "babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "requires": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2886,11 +4039,33 @@ "get-intrinsic": "^1.0.2" } }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, "caniuse-lite": { "version": "1.0.30001449", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001449.tgz", "integrity": "sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw==" }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + } + } + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -2931,6 +4106,24 @@ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2958,6 +4151,11 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, "cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -2977,16 +4175,35 @@ "vary": "^1" } }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, + "cron-parser": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.8.1.tgz", + "integrity": "sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ==", + "requires": { + "luxon": "^3.2.1" + } + }, "csstype": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", - "dev": true + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "debug": { "version": "2.6.9", @@ -3016,6 +4233,15 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "dotenv": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", @@ -3031,11 +4257,24 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -3106,6 +4345,11 @@ "unpipe": "~1.0.0" } }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -3171,14 +4415,21 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -3210,6 +4461,15 @@ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz", "integrity": "sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==" }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -3220,6 +4480,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3228,6 +4493,14 @@ "binary-extensions": "^2.0.0" } }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "requires": { + "has": "^1.0.3" + } + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3251,11 +4524,26 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, "libphonenumber-js": { "version": "1.10.18", "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.18.tgz", "integrity": "sha512-NS4ZEgNhwbcPz1gfSXCGFnQm0xEiyTSPRthIuWytDzOiEG9xnZ2FbLyfJC4tI2BMAAXpoWbNxHYH75pa3Dq9og==" }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "long-timeout": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", + "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -3264,6 +4552,11 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "luxon": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz", + "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==" + }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -3356,6 +4649,16 @@ "styled-jsx": "5.1.1" } }, + "node-schedule": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", + "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", + "requires": { + "cron-parser": "^4.2.0", + "long-timeout": "0.1.1", + "sorted-array-functions": "^1.3.0" + } + }, "nodemon": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", @@ -3423,16 +4726,45 @@ "ee-first": "1.1.1" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -3556,6 +4888,17 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, "react-tsparticles": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/react-tsparticles/-/react-tsparticles-2.8.0.tgz", @@ -3578,6 +4921,26 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -3682,6 +5045,16 @@ } } }, + "sorted-array-functions": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz", + "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "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", @@ -3700,15 +5073,24 @@ "client-only": "0.0.1" } }, + "stylis": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", + "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, "svg.draggable.js": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz", @@ -3773,6 +5155,11 @@ "svg.js": "^2.6.5" } }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4248,6 +5635,11 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 9b47a0ce..1b653b6f 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "tezosLink project", "_moduleAliases": { "@Api": "./dist/api", - "@Front": "./dist/front/*", + "@Front": "./dist/front", "@Assets": "./dist/front/Assets/*", "@Components": "./dist/front/Components/*", "@Themes": "./dist/front/Themes/*", @@ -41,6 +41,9 @@ }, "homepage": "https://github.com/smart-chain-fr/tezosLink#readme", "dependencies": { + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@mui/material": "^5.11.12", "@prisma/client": "^4.9.0", "apexcharts": "^3.36.3", "axios": "^1.3.3", @@ -52,6 +55,7 @@ "express": "^4.18.2", "module-alias": "^2.2.2", "next": "^13.1.5", + "node-schedule": "^2.1.1", "prisma": "^4.9.0", "prisma-query": "^2.0.0", "react": "^18.2.0", @@ -71,6 +75,7 @@ "@types/cors": "^2.8.13", "@types/express": "^4.17.16", "@types/node": "^18.11.18", + "@types/node-schedule": "^2.1.0", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "@types/uuid": "^9.0.0", diff --git a/src/api/controllers/ProjectController.ts b/src/api/controllers/ProjectController.ts index 7987d438..631ddbde 100644 --- a/src/api/controllers/ProjectController.ts +++ b/src/api/controllers/ProjectController.ts @@ -3,9 +3,8 @@ import { Controller, Get, Post } from "@ControllerPattern/index"; import { Service } from "typedi"; import { ProjectEntity } from "@Common/ressources"; import { IsNotEmpty, IsString, IsUUID, validateOrReject } from "class-validator"; -import ProjectService from "@Services/project/ProjectService"; +import ProjectService from "@Services/project/ProjectsService"; import ObjectHydrate from "@Common/helpers/ObjectHydrate"; -import { processFindManyQuery } from "prisma-query"; import ApiController from "@Common/system/controller-pattern/ApiController"; class Params { @@ -24,8 +23,8 @@ export default class ProjectController extends ApiController { @Get("/projects") protected async get(req: Request, res: Response) { - const query = processFindManyQuery(req.query); - this.httpSuccess(res, await this.projectService.getByCriterias(query)); + // const query = processFindManyQuery(req.query); + // this.httpSuccess(res, await this.projectService.getByCriterias(query)); } @Get("/projects/:uuid") @@ -41,10 +40,10 @@ export default class ProjectController extends ApiController { } const project = await this.projectService.getByUUID(params); - if (!project) { - this.httpNotFoundRequest(res); - return; - } + // if (!project) { + // this.httpNotFoundRequest(res); + // return; + // } this.httpSuccess(res, project); } diff --git a/src/common/config/IDatabaseConfig.ts b/src/common/config/database/IDatabaseConfig.ts similarity index 100% rename from src/common/config/IDatabaseConfig.ts rename to src/common/config/database/IDatabaseConfig.ts diff --git a/src/common/config/variables/Variables.ts b/src/common/config/variables/Variables.ts new file mode 100644 index 00000000..5e41cb57 --- /dev/null +++ b/src/common/config/variables/Variables.ts @@ -0,0 +1,85 @@ +import { Service } from "typedi"; +import { validateOrReject, IsNotEmpty, IsOptional } from "class-validator"; +import dotenv from "dotenv"; + +@Service() +export class BackendVariables { + @IsNotEmpty() + public readonly DATABASE_PORT!: string; + + @IsNotEmpty() + public readonly DATABASE_HOSTNAME!: string; + + @IsNotEmpty() + public readonly DATABASE_USER!: string; + + @IsNotEmpty() + public readonly DATABASE_PASSWORD!: string; + + @IsNotEmpty() + public readonly DATABASE_NAME!: string; + + @IsNotEmpty() + public readonly API_HOSTNAME!: string; + + @IsOptional() + public readonly API_LABEL!: string; + + @IsNotEmpty() + public readonly API_PORT!: string; + + @IsNotEmpty() + public readonly API_ROOT_URL!: string; + + @IsOptional() + public readonly RPC_GATEWAY_LABEL!: string; + + @IsNotEmpty() + public readonly RPC_GATEWAY_PORT!: string; + + @IsNotEmpty() + public readonly RPC_GATEWAY_ROOT_URL!: string; + + @IsNotEmpty() + public readonly ARCHIVE_NODES_URL!: string; + + @IsNotEmpty() + public readonly ARCHIVE_NODES_PORT!: string; + + @IsNotEmpty() + public readonly ROLLING_NODES_URL!: string; + + @IsNotEmpty() + public readonly ROLLING_NODES_PORT!: string; + + @IsNotEmpty() + public readonly TEZOS_NETWORK!: string; + + public readonly NODE_ENV = process.env.NODE_ENV; + + public constructor() { + dotenv.config(); + this.DATABASE_PORT = process.env["DATABASE_PORT"]!; + this.DATABASE_HOSTNAME = process.env["DATABASE_HOSTNAME"]!; + this.DATABASE_USER = process.env["DATABASE_USER"]!; + this.DATABASE_PASSWORD = process.env["DATABASE_PASSWORD"]!; + this.DATABASE_NAME = process.env["DATABASE_NAME"]!; + this.API_HOSTNAME = process.env["API_HOSTNAME"]!; + this.API_LABEL = process.env["API_LABEL"]!; + this.API_PORT = process.env["API_PORT"]!; + this.API_ROOT_URL = process.env["API_ROOT_URL"]!; + this.RPC_GATEWAY_LABEL = process.env["RPC_GATEWAY_LABEL"]!; + this.RPC_GATEWAY_PORT = process.env["RPC_GATEWAY_PORT"]!; + this.RPC_GATEWAY_ROOT_URL = process.env["RPC_GATEWAY_ROOT_URL"]!; + this.ARCHIVE_NODES_URL = process.env["ARCHIVE_NODES_URL"]!; + this.ARCHIVE_NODES_PORT = process.env["ARCHIVE_NODES_PORT"]!; + this.ROLLING_NODES_URL = process.env["ROLLING_NODES_URL"]!; + this.ROLLING_NODES_PORT = process.env["ROLLING_NODES_PORT"]!; + this.TEZOS_NETWORK = process.env["TEZOS_NETWORK"]!; + } + public async validate() { + await validateOrReject(this); + return this; + } +} + diff --git a/src/common/cron/Cron.ts b/src/common/cron/Cron.ts new file mode 100644 index 00000000..c87f9a8d --- /dev/null +++ b/src/common/cron/Cron.ts @@ -0,0 +1,67 @@ +import { Service } from "typedi"; +import IConfig from "./IConfig"; +import schedule from "node-schedule"; +import FunctionBinder, { IFunctionBinder } from "@Common/helpers/FunctionBinder"; + +type ICronTimer = { + second?: string | "*" | null; + minute?: string | "*" | null; + hour?: string | "*" | null; + dayMonth?: string | "*" | null; + month?: string | "*" | null; + dayWeek?: string | "*" | null; +}; + +@Service() +export default class Cron { + private readonly cronJobs: schedule.Job[] = []; + private static readonly runningJobs: boolean[] = []; + public async run(CronConfig: IConfig) { + this.cronJobs.splice(0); + this.cancel(); + this.cronJobs.push(...CronConfig.jobs.filter((job) => job.enabled).map((job, index) => this.buildCronJob(job, index, CronConfig.binders))); + return this; + } + + public cancel() { + this.cronJobs.forEach((job) => job.cancel()); + return this; + } + + public static createTimer(cronTimer: ICronTimer) { + return [cronTimer.second ?? "*", cronTimer.minute ?? "*", cronTimer.hour ?? "*", cronTimer.dayMonth ?? "*", cronTimer.month ?? "*", cronTimer.dayWeek ?? "*"].join(" "); + } + + private buildCronJob(job: IConfig["jobs"][number], index: number, binders: IFunctionBinder[]) { + return schedule.scheduleJob(job.cronTime, () => Cron.scheduleJob(job, job.onTick, index, binders)); + } + + /** + * @description Prevent same jobs superposition + */ + private static async scheduleJob(jobConfig: IConfig["jobs"][number], cronCommand: () => Promise, index: number, binders: IFunctionBinder[]) { + if (Cron.runningJobs[index]) return; + Cron.runningJobs[index] = true; + + try { + console.info(`${Cron.getDate()} CronJob: ${jobConfig.cronTime} ${jobConfig.name}: started`); + + if (binders.length) { + await FunctionBinder.bind(cronCommand, binders); + } else { + await cronCommand(); + } + + console.info(`${Cron.getDate()} CronJob: ${jobConfig.name}: end success`); + } catch (e) { + console.info(`${Cron.getDate()} CronJob: ${jobConfig.name}: end with error`); + console.error(e); + } + Cron.runningJobs[index] = false; + } + + private static getDate() { + const d = new Date(); + return `${d.getDate()}/${d.getMonth() + 1}/${d.getFullYear()} ${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}`; + } +} diff --git a/src/common/cron/IConfig.ts b/src/common/cron/IConfig.ts new file mode 100644 index 00000000..dec74272 --- /dev/null +++ b/src/common/cron/IConfig.ts @@ -0,0 +1,12 @@ +import { IFunctionBinder } from "@Common/helpers/FunctionBinder"; + +export default interface IConfig { + binders: IFunctionBinder[]; + jobs: { + name: string; + description?: string; + cronTime: string | Date; + onTick: () => Promise; + enabled?: boolean; + }[]; +} diff --git a/src/common/cron/index.ts b/src/common/cron/index.ts new file mode 100644 index 00000000..ac7e8d31 --- /dev/null +++ b/src/common/cron/index.ts @@ -0,0 +1,4 @@ +import IConfig from "@Common/cron/IConfig"; +import Cron from "@Common/cron/Cron"; +export type { IConfig }; +export default Cron; diff --git a/src/common/databases/database.ts b/src/common/databases/database.ts index 26a6feff..ecd8b810 100644 --- a/src/common/databases/database.ts +++ b/src/common/databases/database.ts @@ -1,13 +1,14 @@ import { Service } from "typedi"; import DbProvider from "@Common/system/database"; import dotenv from "dotenv"; +import { BackendVariables } from "@Common/config/variables/Variables"; dotenv.config(); @Service() export default class Database { protected readonly dbProvider: DbProvider; - constructor() { + constructor(private variables: BackendVariables) { this.dbProvider = new DbProvider({ name: this.getDatabaseName(), }); @@ -21,7 +22,7 @@ export default class Database { } private getDatabaseName(): string { - const name = process.env["DATABASE_NAME"]; + const name = this.variables.DATABASE_NAME; if (!name) throw new Error("Database name is undefined!. Add name of db in the url."); return name; } diff --git a/src/common/databases/migrations/20230119175343_v1_20230119_create_app_application/migration.sql b/src/common/databases/migrations/20230119175343_v1_20230119_create_app_application/migration.sql index 731404fc..1f482e09 100644 --- a/src/common/databases/migrations/20230119175343_v1_20230119_create_app_application/migration.sql +++ b/src/common/databases/migrations/20230119175343_v1_20230119_create_app_application/migration.sql @@ -1,34 +1,34 @@ --- -- CreateTable --- CREATE TABLE "app_projects" ( --- "id" SERIAL NOT NULL, --- "title" VARCHAR(255) NOT NULL, --- "uuid" VARCHAR(255) NOT NULL, --- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, --- "updatedAt" TIMESTAMP(3) NOT NULL, --- "network" VARCHAR(255) NOT NULL, +-- CreateTable +CREATE TABLE "app_projects" ( + "id" SERIAL NOT NULL, + "title" VARCHAR(255) NOT NULL, + "uuid" VARCHAR(255) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "network" VARCHAR(255) NOT NULL, --- CONSTRAINT "app_projects_pkey" PRIMARY KEY ("id") --- ); + CONSTRAINT "app_projects_pkey" PRIMARY KEY ("id") +); --- -- CreateTable --- CREATE TABLE "app_metrics" ( --- "id" SERIAL NOT NULL, --- "path" VARCHAR(255) NOT NULL, --- "uuid" VARCHAR(255) NOT NULL, --- "remote_address" VARCHAR(255) NOT NULL, --- "date_requested" TIMESTAMP(3) NOT NULL, --- "projectId" INTEGER NOT NULL, --- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, --- "updatedAt" TIMESTAMP(3) NOT NULL, +-- CreateTable +CREATE TABLE "app_metrics" ( + "id" SERIAL NOT NULL, + "path" VARCHAR(255) NOT NULL, + "uuid" VARCHAR(255) NOT NULL, + "remote_address" VARCHAR(255) NOT NULL, + "date_requested" TIMESTAMP(3) NOT NULL, + "projectId" INTEGER NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, --- CONSTRAINT "app_metrics_pkey" PRIMARY KEY ("id") --- ); + CONSTRAINT "app_metrics_pkey" PRIMARY KEY ("id") +); --- -- CreateIndex --- CREATE UNIQUE INDEX "app_projects_uuid_key" ON "app_projects"("uuid"); +-- CreateIndex +CREATE UNIQUE INDEX "app_projects_uuid_key" ON "app_projects"("uuid"); --- -- CreateIndex --- CREATE UNIQUE INDEX "app_metrics_uuid_key" ON "app_metrics"("uuid"); +-- CreateIndex +CREATE UNIQUE INDEX "app_metrics_uuid_key" ON "app_metrics"("uuid"); --- -- AddForeignKey --- ALTER TABLE "app_metrics" ADD CONSTRAINT "app_metrics_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "app_projects"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +-- AddForeignKey +ALTER TABLE "app_metrics" ADD CONSTRAINT "app_metrics_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "app_projects"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/src/common/databases/migrations/20230224095135_remove_metrics_uuid_uniqueness/migration.sql b/src/common/databases/migrations/20230224095135_remove_metrics_uuid_uniqueness/migration.sql new file mode 100644 index 00000000..e535fa33 --- /dev/null +++ b/src/common/databases/migrations/20230224095135_remove_metrics_uuid_uniqueness/migration.sql @@ -0,0 +1,2 @@ +-- DropIndex +DROP INDEX "app_metrics_uuid_key"; diff --git a/src/common/databases/migrations/20230227152159_remove_requested_date_format/migration.sql b/src/common/databases/migrations/20230227152159_remove_requested_date_format/migration.sql new file mode 100644 index 00000000..1363f00b --- /dev/null +++ b/src/common/databases/migrations/20230227152159_remove_requested_date_format/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "app_metrics" ALTER COLUMN "date_requested" SET DATA TYPE DATE; diff --git a/src/common/databases/migrations/20230301110217_remove_ids_projects_metrics/migration.sql b/src/common/databases/migrations/20230301110217_remove_ids_projects_metrics/migration.sql new file mode 100644 index 00000000..70bab1e9 --- /dev/null +++ b/src/common/databases/migrations/20230301110217_remove_ids_projects_metrics/migration.sql @@ -0,0 +1,32 @@ +/* + Warnings: + + - The primary key for the `app_metrics` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `id` on the `app_metrics` table. All the data in the column will be lost. + - You are about to drop the column `projectId` on the `app_metrics` table. All the data in the column will be lost. + - The primary key for the `app_projects` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `id` on the `app_projects` table. All the data in the column will be lost. + - A unique constraint covering the columns `[uuid]` on the table `app_metrics` will be added. If there are existing duplicate values, this will fail. + - Added the required column `projectUuid` to the `app_metrics` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropForeignKey +ALTER TABLE "app_metrics" DROP CONSTRAINT "app_metrics_projectId_fkey"; + +-- AlterTable +ALTER TABLE "app_metrics" DROP CONSTRAINT "app_metrics_pkey", +DROP COLUMN "id", +DROP COLUMN "projectId", +ADD COLUMN "projectUuid" TEXT NOT NULL, +ADD CONSTRAINT "app_metrics_pkey" PRIMARY KEY ("uuid"); + +-- AlterTable +ALTER TABLE "app_projects" DROP CONSTRAINT "app_projects_pkey", +DROP COLUMN "id", +ADD CONSTRAINT "app_projects_pkey" PRIMARY KEY ("uuid"); + +-- CreateIndex +CREATE UNIQUE INDEX "app_metrics_uuid_key" ON "app_metrics"("uuid"); + +-- AddForeignKey +ALTER TABLE "app_metrics" ADD CONSTRAINT "app_metrics_projectUuid_fkey" FOREIGN KEY ("projectUuid") REFERENCES "app_projects"("uuid") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/src/common/helpers/FunctionBinder.ts b/src/common/helpers/FunctionBinder.ts new file mode 100644 index 00000000..1db4629f --- /dev/null +++ b/src/common/helpers/FunctionBinder.ts @@ -0,0 +1,42 @@ +export type IFunctionBinder = (next?: IFunctionBinder) => Promise; +/** + * @description execute functions on body of another function + * @example ` + * const binders = [fooA, fooB, fooC]; + * + * //Will be something like + * function fooA(fooB, fooC, next) { + * //code... + * fooB(fooC, next); + * //code... + * } + * function fooB(fooC, next) { + * //code... + * fooC(next); + * //code... + * } + * + * function fooC(next) { + * //code... + * next(); + * //code... + * } + * ` + * fooC will be executed in body of fooB and fooB in body of fooA + */ +export default abstract class FunctionBinder { + public static async bind(next: () => Promise, binders: IFunctionBinder[]) { + let currentBinder = async function () { + await next(); + }; + + let index = binders.length; + while (index--) { + const localIndex = index; + const nextBinder = currentBinder; + currentBinder = async () => binders[localIndex]!(nextBinder); + } + + await currentBinder(); + } +} diff --git a/src/common/helpers/ObjectHydrate.ts b/src/common/helpers/ObjectHydrate.ts index 880d1cef..5e220bd0 100644 --- a/src/common/helpers/ObjectHydrate.ts +++ b/src/common/helpers/ObjectHydrate.ts @@ -1,7 +1,13 @@ -import { plainToClassFromExist } from "class-transformer"; +import { type ClassTransformOptions, plainToClass, plainToClassFromExist } from "class-transformer"; export default abstract class ObjectHydrate { - public static hydrate(object: { [key: string]: any }, from: { [key: string]: any }): T { - return plainToClassFromExist(object, from) as T; + public static hydrate(object: T, from: Partial, options?: ClassTransformOptions): T { + return plainToClassFromExist(object, from, options); + } + + public static map(ClassEntity: { new (): T }, fromArray: Partial[], options?: ClassTransformOptions): T[] { + return fromArray.map((from) => { + return plainToClass(ClassEntity, from, options); + }); } } diff --git a/src/common/helpers/ProxyHelpers.ts b/src/common/helpers/ProxyHelpers.ts new file mode 100644 index 00000000..0bb76139 --- /dev/null +++ b/src/common/helpers/ProxyHelpers.ts @@ -0,0 +1,13 @@ +export function getUUIDFromPath(path: string, re: RegExp): string { + let uuid = ""; + const matches = path.match(re); + if (matches !== null) { + uuid = matches[matches.length - 1]!; + } + return uuid; +} + +export function getRPCFromPath(basePath: string, path: string, re: RegExp): string { + return path.replace("/" + basePath + getUUIDFromPath(path, re), ""); +} + diff --git a/src/common/repositories/BaseRepository.ts b/src/common/repositories/BaseRepository.ts new file mode 100644 index 00000000..45e050b6 --- /dev/null +++ b/src/common/repositories/BaseRepository.ts @@ -0,0 +1,4 @@ +export default abstract class BaseRepository { + protected readonly maxFetchRows = 100; + protected readonly defaultFetchRows = 50; +} diff --git a/src/common/repositories/MetricsRepository.ts b/src/common/repositories/MetricsRepository.ts deleted file mode 100644 index 9f5bbb9d..00000000 --- a/src/common/repositories/MetricsRepository.ts +++ /dev/null @@ -1,190 +0,0 @@ -import TezosLink from "@Common/databases/TezosLink"; -import { MetricEntity } from "@Common/ressources"; -import { ORMBadQueryError } from "@Common/system/database/exceptions/ORMBadQueryError"; -import { type Prisma } from "@prisma/client"; -import { Service } from "typedi"; - -type RequestsByDayMetrics = { - date_requested: Date; - count: number; -}; - -@Service() -export default class MetricRepository { - constructor(private database: TezosLink) {} - protected get model() { - return this.database.getClient().metric; - } - protected get instanceDb() { - return this.database.getClient(); - } - - public async findMany(query: any): Promise { - try { - return this.model.findMany(query) as Promise; - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } - - public async findOne(metricEntity: Partial): Promise | null> { - try { - const data = { ...metricEntity }; - return this.model.findUnique({ where: data }); - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } - - public async create(metricEntity: Partial): Promise { - try { - const data = { ...metricEntity }; - - return this.model.create({ - data: { - path: data.path!, - uuid: data.uuid!, - remote_address: data.remote_address!, - date_requested: data.date_requested!, - project: { - connect: { - id: data.id!, - }, - }, - }, - }) as Promise; - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } - - // Create many metrics in bulk - public async createMany(metricEntity: Partial): Promise { - try { - const data = { ...metricEntity }; - const result: MetricEntity[] = []; - - this.instanceDb.$transaction(async(transaction: Prisma.TransactionClient) => { - for (const item of data) { - if (!item) continue; - result.push( - await transaction.metric.create({ - data: { - path: item.path!, - uuid: item.uuid!, - remote_address: item.remote_address!, - date_requested: item.date_requested!, - project: { - connect: { - id: item.id!, - }, - }, - }, - }), - ); - } - }); - return result; - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } - - // Count Rpc path usage for a specific project - public async countRpcPathUsage(projectId: number, from: Date, to: Date): Promise { - try { - return this.model.groupBy({ - by: ["path"], - _count: { - path: true, - }, - where: { - projectId: projectId, - date_requested: { - gte: from, - lte: to, - }, - }, - }); - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } - - // Last requests for a specific project - public async findLastRequests(projectId: number, limit: number): Promise { - try { - return this.model.findMany({ - where: { - projectId: projectId, - }, - take: limit, - orderBy: { - date_requested: "desc", - }, - }); - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } - - // Find Requests by Day for a specific project - public async findRequestsByDay(projectId: number, from: Date, to: Date): Promise { - try { - const result: RequestsByDayMetrics[] = []; - const response = this.model.groupBy({ - by: ["date_requested"], - _count: { - date_requested: true, - }, - where: { - projectId: projectId, - date_requested: { - gte: from, - lte: to, - }, - }, - }); - for (const item of response as Array<{ date_requested: Date; _count: { date_requested: number } }> | any) { - result.push({ - date_requested: item.date_requested, - count: item._count.date_requested, - }); - } - return result; - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } - - // Count all metrics by criterias for a specific project - public async countAll(projectId: number): Promise { - try { - return this.model.count({ - where: { - projectId: projectId, - }, - }); - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } - - // Remove Three months old metrics - public async removeOldMetricsBymonths(months: number): Promise { - try { - const date = new Date(); - date.setMonth(date.getMonth() - months); - this.model.deleteMany({ - where: { - date_requested: { - lte: date, - }, - }, - }); - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } -} - diff --git a/src/common/repositories/ProjectRepository.ts b/src/common/repositories/ProjectRepository.ts deleted file mode 100644 index 1b2b610f..00000000 --- a/src/common/repositories/ProjectRepository.ts +++ /dev/null @@ -1,62 +0,0 @@ -import TezosLink from "@Common/databases/TezosLink"; -import { ProjectEntity } from "@Common/ressources"; -import { ORMBadQueryError } from "@Common/system/database/exceptions/ORMBadQueryError"; -import { Service } from "typedi"; -import { v4 as uuidv4 } from "uuid"; - -@Service() -export default class ProjectRepository { - constructor(private database: TezosLink) {} - protected get model() { - return this.database.getClient().project; - } - - public async findMany(query: any): Promise { - try { - return this.model.findMany(query) as Promise; - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } - - public async findOne(projectEntity: Partial): Promise | null> { - try { - const data = { ...projectEntity }; - return this.model.findUnique({ - where: data, - - include: { - // Include metrics & count - Metrics: true, - _count: { - select: { Metrics: true }, - }, - - }, - }); - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } - - public async create(projectEntity: Partial): Promise { - try { - const data = { ...projectEntity }; - data.uuid = uuidv4(); - return this.model.create({ - data: { - uuid: data.uuid, - title: data.title!, - network: data.network!, - }, - include: { - // Include metrics - Metrics: true, - }, - }) as Promise; - } catch (error) { - throw new ORMBadQueryError((error as Error).message, error as Error); - } - } -} - diff --git a/src/common/repositories/metrics/MetricsRepository.ts b/src/common/repositories/metrics/MetricsRepository.ts new file mode 100644 index 00000000..6207c48d --- /dev/null +++ b/src/common/repositories/metrics/MetricsRepository.ts @@ -0,0 +1,220 @@ +// import TezosLink from "@Common/databases/TezosLink"; +// import ObjectHydrate from "@Common/helpers/ObjectHydrate"; +// import { MetricEntity } from "@Common/ressources"; +// import { ORMBadQueryError } from "@Common/system/database/exceptions/ORMBadQueryError"; +// import { type Prisma } from "@prisma/client"; + +import { Service } from "typedi"; +// import { v4 as uuidv4 } from "uuid"; +import BaseRepository from "../BaseRepository"; + +export class RequestsByDayMetrics { + date_requested!: Date; + count!: number; +} + +export class CountRpcPathUsage { + path!: string; + count!: number; +} + +@Service() +export default class MetricsRepository extends BaseRepository { + // constructor(private database: TezosLink) { + // super(); + // } + // protected get model() { + // return this.database.getClient().metric; + // } + // protected get instanceDb() { + // return this.database.getClient(); + // } + + // public async findMany(query: Prisma.MetricFindManyArgs): Promise { + // try { + // // Use Math.min to limit the number of rows fetched + // const limit = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + + // // Update the query with the limited limit + // const metrics = await this.model.findMany({ ...query, take: limit }); + // return ObjectHydrate.map(MetricEntity, metrics, { strategy: "exposeAll" }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + // } + + // public async findOne(metricEntity: Partial): Promise | null> { + // try { + // const metric = await this.model.findUnique({ where: metricEntity }); + // return ObjectHydrate.hydrate(new MetricEntity(), metric, { strategy: "exposeAll" }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + // } + + // public async create(metricEntity: Partial): Promise { + // try { + // const data = { ...metricEntity }; + // data.uuid = uuidv4(); + // const metric = (await this.model.create({ + // data: { + // path: data.path!, + // uuid: data.uuid!, + // remote_address: data.remote_address!, + // date_requested: data.date_requested!, + // project: { + // connect: { + // uuid: data.project!.uuid!, + // }, + // }, + // }, + // })) as MetricEntity; + // return ObjectHydrate.hydrate(new MetricEntity(), metric, { strategy: "exposeAll" }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + // } + + // // Create many metrics in bulk + // public async createMany(metricEntity: Partial): Promise { + // try { + // const result: MetricEntity[] = []; + + // this.instanceDb.$transaction(async (transaction: Prisma.TransactionClient) => { + // for (const item of metricEntity) { + // if (!item) continue; + // const data = { ...item }; + // data.uuid = uuidv4(); + // result.push( + // await transaction.metric.create({ + // data: { + // path: data.path!, + // uuid: data.uuid!, + // remote_address: data.remote_address!, + // date_requested: data.date_requested!, + // project: { + // connect: { + // uuid: data.projectUuid!, + // }, + // }, + // }, + // }), + // ); + // } + // }); + // return ObjectHydrate.map(MetricEntity, result, { strategy: "exposeAll" }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + // } + + // // Count Rpc path usage for a specific project + // public async countRpcPathUsage(ProjectUuid: string, from: Date, to: Date): Promise { + // try { + // const result: CountRpcPathUsage[] = []; + // const response = await this.model.groupBy({ + // by: ["path"], + // _count: { + // path: true, + // }, + // where: { + // projectUuid: ProjectUuid, + // date_requested: { + // gte: from, + // lte: to, + // }, + // }, + // }); + // response.forEach((item) => { + // result.push({ + // path: item.path, + // count: item._count.path, + // }); + // }); + // return ObjectHydrate.map(CountRpcPathUsage, response, { strategy: "exposeAll" }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + // } + + // // Last requests for a specific project + // public async findLastRequests(projectUuid: string, limit: number): Promise { + // try { + // // Use Math.min to limit the number of rows fetched + // const rows = Math.min(limit || this.defaultFetchRows, this.maxFetchRows); + // const metrics = await this.model.findMany({ + // where: { + // projectUuid: projectUuid, + // }, + // take: rows, + // orderBy: { + // date_requested: "desc", + // }, + // }); + // return ObjectHydrate.map(MetricEntity, metrics, { strategy: "exposeAll" }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + // } + + // // Find Requests by Day for a specific project + // public async findRequestsByDay(projectUuid: string, from: Date, to: Date): Promise { + // try { + // const result: RequestsByDayMetrics[] = []; + // const response = await this.model.groupBy({ + // by: ["date_requested"], + // _count: { + // date_requested: true, + // }, + // where: { + // projectUuid: projectUuid, + // date_requested: { + // gte: from, + // lte: to, + // }, + // }, + // }); + + // response.forEach((item) => { + // result.push({ + // date_requested: item.date_requested, + // count: item._count.date_requested, + // }); + // }); + // return ObjectHydrate.map(RequestsByDayMetrics, result, { strategy: "exposeAll" }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + // } + + // // Count all metrics by criterias for a specific project + // public async countAll(projectUuid: string): Promise { + // try { + // return this.model.count({ + // where: { + // projectUuid: projectUuid, + // }, + // }) as Promise; + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + // } + + // // Remove Three months old metrics + // public async removeOldMetricsBymonths(months: number): Promise { + // try { + // const date = new Date(); + // date.setMonth(date.getMonth() - months); + // this.model.deleteMany({ + // where: { + // date_requested: { + // lte: date, + // }, + // }, + // }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + // } +} + diff --git a/src/common/repositories/projects/ProjectsRepository.ts b/src/common/repositories/projects/ProjectsRepository.ts new file mode 100644 index 00000000..09cbcd50 --- /dev/null +++ b/src/common/repositories/projects/ProjectsRepository.ts @@ -0,0 +1,63 @@ +// import TezosLink from "@Common/databases/TezosLink"; +// import ObjectHydrate from "@Common/helpers/ObjectHydrate"; +import { ProjectEntity } from "@Common/ressources"; +// import { ORMBadQueryError } from "@Common/system/database/exceptions/ORMBadQueryError"; +import { Service } from "typedi"; +// import { v4 as uuidv4 } from "uuid"; +import BaseRepository from "../BaseRepository"; + +@Service() +export default class ProjectsRepository extends BaseRepository { + // constructor(private database: TezosLink) { + // super(); + // } + // protected get model() { + // return this.database.getClient().project; + // } + + // public async findMany(query: Prisma.ProjectFindManyArgs): Promise { + // try { + // // Use Math.min to limit the number of rows fetched + // const limit = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows); + + // // Update the query with the limited limit + // const projects = await this.model.findMany({ ...query, take: limit }); + // return ObjectHydrate.map(ProjectEntity, projects, { strategy: "exposeAll" }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + // } + + public async findOne(projectEntity: Partial) { + // try { + // const project = (await this.model.findFirst({ + // where: projectEntity, + // })) as ProjectEntity; + // return ObjectHydrate.hydrate(new ProjectEntity(), project, { strategy: "exposeAll" }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + } + + public async create(projectEntity: Partial) { + // try { + // const data = { ...projectEntity }; + // data.uuid = uuidv4(); + // const project = (await this.model.create({ + // data: { + // uuid: data.uuid, + // title: data.title!, + // network: data.network!, + // }, + // include: { + // // Include metrics + // Metrics: true, + // }, + // })) as ProjectEntity; + // return ObjectHydrate.hydrate(new ProjectEntity(), project, { strategy: "exposeAll" }); + // } catch (error) { + // throw new ORMBadQueryError((error as Error).message, error as Error); + // } + } +} + diff --git a/src/common/ressources/MetricEntity.ts b/src/common/ressources/MetricEntity.ts index ca8e40dd..9b584cc7 100644 --- a/src/common/ressources/MetricEntity.ts +++ b/src/common/ressources/MetricEntity.ts @@ -1,31 +1,36 @@ -import { IsNotEmpty, IsDate } from "class-validator"; import ProjectEntity from "./ProjectEntity"; export default class MetricEntity { - @IsNotEmpty() - public id!: number; - - @IsNotEmpty(({groups: ["create"]})) - public path!: string; - - @IsNotEmpty(({groups: ["create"]})) public uuid!: string; - @IsNotEmpty(({groups: ["create"]})) + public path!: string; + public remote_address!: string; - @IsNotEmpty(({groups: ["create"]})) public date_requested!: Date; - @IsNotEmpty(({groups: ["create"]})) - public projectId!: number; + public projectUuid!: string; - @IsNotEmpty(({groups: ["create"]})) public project!: ProjectEntity; - @IsDate() public createdAt?: Date; - @IsDate() public updatedAt?: Date; + + set remoteAddress(remote_address: string) { + this.remote_address = remote_address; + } + + get remoteAddress() { + return this.remote_address; + } + + set dateRequested(date_requested: Date) { + this.date_requested = date_requested; + } + + get dateRequested() { + return this.date_requested; + } } + diff --git a/src/common/ressources/ProjectEntity.ts b/src/common/ressources/ProjectEntity.ts index 8bfc5e01..5a7c7f13 100644 --- a/src/common/ressources/ProjectEntity.ts +++ b/src/common/ressources/ProjectEntity.ts @@ -1,25 +1,19 @@ -import { IsNotEmpty, IsOptional, IsDate } from "class-validator"; +import { IsNotEmpty } from "class-validator"; import MetricEntity from "./MetricEntity"; export default class ProjectEntity { - @IsNotEmpty() - public id!: number; - - @IsNotEmpty({groups: ["create"]}) + public uuid!: string; + + @IsNotEmpty({ groups: ["create"] }) public title!: string; - @IsNotEmpty() - public uuid!: string; - - @IsDate() public createdAt!: Date; - @IsDate() public updatedAt!: Date; - @IsNotEmpty({groups: ["create"]}) + @IsNotEmpty({ groups: ["create"] }) public network!: string; - @IsOptional() public metrics?: MetricEntity[]; -} \ No newline at end of file +} + diff --git a/src/common/services/BaseService.ts b/src/common/services/BaseService.ts index fb2c5ab3..4613dc92 100644 --- a/src/common/services/BaseService.ts +++ b/src/common/services/BaseService.ts @@ -1,2 +1,11 @@ -export default class BaseService {} +import { BackendVariables } from "@Common/config/variables/Variables"; +import Container from "typedi"; + +export default abstract class BaseService { + /** @TODO place methods in a config file */ + public static readonly whitelisted: string[] = ["/chains/main/blocks"]; + public static readonly blacklisted: string[] = ["/context/contracts", "/monitor", "/network"]; + public static readonly rollingPatterns: string[] = ["/head", "/injection/operation"]; + public static readonly network: string = Container.get(BackendVariables).TEZOS_NETWORK; +} diff --git a/src/common/services/metric/MetricService.ts b/src/common/services/metric/MetricService.ts deleted file mode 100644 index 76e9770b..00000000 --- a/src/common/services/metric/MetricService.ts +++ /dev/null @@ -1,88 +0,0 @@ -import ObjectHydrate from "@Common/helpers/ObjectHydrate"; -import MetricRepository from "@Common/repositories/MetricsRepository"; -import { MetricEntity } from "@Common/ressources"; -import { type processFindManyQuery } from "prisma-query"; -import { Service } from "typedi"; - -@Service() -export default class MetricService { - constructor(private metricRepository: MetricRepository) {} - - /** - * @throws {Error} If metrics are undefined - */ - public async getByCriterias(query: ReturnType) { - const metrics = await this.metricRepository.findMany(query); - return ObjectHydrate.hydrate>(new MetricEntity(), metrics); - } - /** - * @throws {Error} If metric is undefined - */ - public async getByUUID(metricEntity: Partial) { - const metric = await this.metricRepository.findOne(metricEntity); - if (!metric) return null; - return ObjectHydrate.hydrate>(new MetricEntity(), metric); - } - /** - * - * @throws {Error} If metric cannot be created - * @returns - */ - public async create(metricEntity: Partial) { - const metric = await this.metricRepository.create(metricEntity); - if (!metric) return null; - return ObjectHydrate.hydrate>(new MetricEntity(), metric); - } - - /** - * - * @throws {Error} If metric is undefined - * @returns - */ - public async getCountRpcPath(metricEntity: Partial, from: Date, to: Date) { - const pathsCount = await this.metricRepository.countRpcPathUsage(metricEntity.projectId!,from,to); - if (!pathsCount) return null; - return pathsCount; - } - /** - * - * @throws {Error} If metric is undefined - * @returns - */ - public async getCountAllMetrics(metricEntity: Partial) { - const count = await this.metricRepository.countAll(metricEntity.projectId!); - if (isNaN(count)) return null; - return count; - } - - /** - * - * @throws {Error} If metric is undefined - * @returns - */ - public async getLastMetrics(metricEntity: Partial, limit: number){ - const lastMetric = await this.metricRepository.findLastRequests(metricEntity.projectId!,limit); - return ObjectHydrate.hydrate>(new MetricEntity(), lastMetric); - } - - /** - * - * @throws {Error} If metric is undefined - * @returns - */ - public async getRequestsByDay(metricEntity: Partial, from: Date, to: Date){ - const requestByDay = await this.metricRepository.findRequestsByDay(metricEntity.projectId!,from,to); - return ObjectHydrate.hydrate>(new MetricEntity(), requestByDay); - } - - /** - * - * @throws {Error} If metric is undefined - * @returns - */ - public async removeThreeMontsOldMetrics() { - const months = 3; - await this.metricRepository.removeOldMetricsBymonths(months); - } -} - diff --git a/src/common/services/metric/MetricsService.ts b/src/common/services/metric/MetricsService.ts new file mode 100644 index 00000000..83d87a05 --- /dev/null +++ b/src/common/services/metric/MetricsService.ts @@ -0,0 +1,76 @@ +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; + +@Service() +export default class MetricsService extends BaseService { + constructor() { + super(); + } + + // /** + // * @throws {Error} If metrics are undefined + // */ + // public async getByCriterias(query: ReturnType): Promise { + // return await this.metricRepository.findMany(query); + // } + // /** + // * + // * @throws {Error} If metric cannot be created + // * @returns + // */ + // public async create(metricEntity: Partial): Promise> { + // const metric = await this.metricRepository.create(metricEntity); + // if (!metric) return Promise.reject(new Error("Cannot create metric")); + // return metric; + // } + + /** + * + * @throws {Error} If metric is undefined + * @returns + */ + // public async getCountRpcPath(uuid: string, from: Date, to: Date): Promise { + // const pathsCount = await this.metricRepository.countRpcPathUsage(uuid, from, to); + // if (!pathsCount) return Promise.reject(new Error("Cannot get count of rpc path")); + // return pathsCount; + // } + /** + * + * @throws {Error} If metric is undefined + * @returns + */ + // public async getCountAllMetrics(metricEntity: Partial): Promise { + // const count = await this.metricRepository.countAll(metricEntity.uuid!); + // if (isNaN(count)) Promise.reject(new Error("Cannot get count of metrics")); + // return count; + // } + + /** + * + * @throws {Error} If metric is undefined + * @returns + */ + // public async getLastMetrics(uuid: string, limit: number): Promise { + // return await this.metricRepository.findLastRequests(uuid, limit); + // } + + /** + * + * @throws {Error} If metric is undefined + * @returns + */ + // public async getRequestsByDay(uuid: string, from: Date, to: Date): Promise { + // return await this.metricRepository.findRequestsByDay(uuid, from, to); + // } + + /** + * + * @throws {Error} If metric is undefined + * @returns + */ + // public async removeThreeMontsOldMetrics(): Promise { + // const months = 3; + // await this.metricRepository.removeOldMetricsBymonths(months); + // } +} + diff --git a/src/common/services/project/ProjectService.ts b/src/common/services/project/ProjectService.ts deleted file mode 100644 index 40025318..00000000 --- a/src/common/services/project/ProjectService.ts +++ /dev/null @@ -1,39 +0,0 @@ -import ObjectHydrate from "@Common/helpers/ObjectHydrate"; -import ProjectRepository from "@Common/repositories/ProjectRepository"; -import { ProjectEntity } from "@Common/ressources"; -import { type processFindManyQuery } from "prisma-query"; -import { Service } from "typedi"; - - - -@Service() -export default class ProjectService { - constructor(private projectRepository: ProjectRepository) {} - - /** - * @throws {Error} If projects are undefined - */ - public async getByCriterias(query: ReturnType) { - const projects = await this.projectRepository.findMany(query); - return ObjectHydrate.hydrate>(new ProjectEntity(), projects); - } - /** - * @throws {Error} If project is undefined - */ - public async getByUUID(projectEntity: Partial) { - const project = await this.projectRepository.findOne(projectEntity); - if (!project) return null; - return ObjectHydrate.hydrate>(new ProjectEntity(), project); - } - /** - * - * @throws {Error} If project cannot be created - * @returns - */ - public async create(projectEntity: Partial) { - const project = await this.projectRepository.create(projectEntity); - if (!project) return null; - return ObjectHydrate.hydrate>(new ProjectEntity(), project); - } -} - diff --git a/src/common/services/project/ProjectsService.ts b/src/common/services/project/ProjectsService.ts new file mode 100644 index 00000000..dc4b8e49 --- /dev/null +++ b/src/common/services/project/ProjectsService.ts @@ -0,0 +1,37 @@ +// import ProjectsRepository from "@Common/repositories/projects/ProjectsRepository"; +import { ProjectEntity } from "@Common/ressources"; +import BaseService from "@Services/BaseService"; +import { Service } from "typedi"; + +@Service() +export default class ProjectsService extends BaseService { + constructor() { + super(); + } + + /** + * @throws {Error} If projects are undefined + */ + // public async getByCriterias(query: ReturnType): Promise { + // return this.projectRepository.findMany(query); + // } + /** + * @throws {Error} If project is undefined + */ + public async getByUUID(projectEntity: Partial){ + // const project = await this.projectRepository.findOne(projectEntity); + // if (!project) Promise.reject(new Error("Cannot get project by uuid")); + // return project; + } + /** + * + * @throws {Error} If project cannot be created + * @returns + */ + public async create(projectEntity: Partial){ + // const project = await this.projectRepository.create(projectEntity); + // if (!project) Promise.reject(new Error("Cannot create project")); + // return project; + } +} + diff --git a/src/common/services/proxy/ProxyService.ts b/src/common/services/proxy/ProxyService.ts new file mode 100644 index 00000000..54e207df --- /dev/null +++ b/src/common/services/proxy/ProxyService.ts @@ -0,0 +1,119 @@ +import MetricEntity from "@Common/ressources/MetricEntity"; +import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; +import { IHttpReponse, IStatusNode } from "@Common/system/interfaces/Interfaces"; +import BaseService from "@Services/BaseService"; +import axios from "axios"; +import { IsNotEmpty, IsUUID, Validate } from "class-validator"; +import { Service } from "typedi"; +import IsRpcPathAllowed from "./validators/IsRpcPathAllowed"; +import IsValidProject from "./validators/IsValidProject"; +import { BackendVariables } from "@Common/config/variables/Variables"; +import ProjectsRepository from "@Common/repositories/projects/ProjectsRepository"; + +export class RpcRequest { + @IsNotEmpty() + @Validate(IsRpcPathAllowed) + path!: string; + + @IsNotEmpty() + @IsUUID() + @Validate(IsValidProject, [{ network: BaseService.network }]) + uuid!: string; + + @IsNotEmpty() + remoteAddress!: string; +} + +@Service() +export default class ProxyService extends BaseService { + constructor(private projectRepository: ProjectsRepository, private variables: BackendVariables) { + super(); + } + /** + * @throws {Error} if url is undefined + */ + public getHttpServerResponse(): IHttpReponse { + return { + status: HttpCodes.SUCCESS, + reason: null, + } as IHttpReponse; + } + /** + * @throws {Error} if url is undefined + */ + public async getNodesStatus(): Promise { + const archiveTestURL = new URL(`${this.variables.ARCHIVE_NODES_URL}/chains/main/blocks/head`); + const rollingTestURL = new URL(`${this.variables.ROLLING_NODES_URL}/chains/main/blocks/head`); + + const archive_node = { + status: HttpCodes.INTERNAL_ERROR, + reason: null, + } as IHttpReponse; + const rolling_node = { + status: HttpCodes.INTERNAL_ERROR, + reason: null, + } as IHttpReponse; + + const [archive, rolling] = await Promise.allSettled([axios.get(archiveTestURL.toString()), axios.get(rollingTestURL.toString())]); + + if (archive.status === "fulfilled") archive_node.status = archive.value.status; + if (archive.status === "rejected") archive_node.reason = archive.reason; + + if (rolling.status === "fulfilled") rolling_node.status = rolling.value.status; + if (rolling.status === "rejected") rolling_node.reason = rolling.reason; + + return { + archive_node, + rolling_node, + }; + } + + /** + * + * @throws {Error} If metric cannot be created + * @returns + */ + // async saveMetric(metricEntity: Partial) { + // const metric = await this.metricsRepository.create(metricEntity); + // if (!metric) return null; + // return metric; + // } + + // Proxy proxy an http request to the right repositories + public async proxy(request: RpcRequest): Promise { + console.info(`Received proxy request for path: ${request.path}`); + + const project = await this.projectRepository.findOne({ uuid: request.uuid, network: BaseService.network }); + + // if (!project) { + // return Promise.reject(`Project uuid: ${request.uuid} with network: ${BaseService.network} does not exist`); + // } + + let response = ""; + + if (this.isRollingNodeRedirection(request.path)) { + console.info("Forwarding request directly to rolling node (as a reverse proxy)"); + const rollingURL = new URL(`${this.variables.ROLLING_NODES_URL}/${request.path}`); + const { data } = await axios.get(rollingURL.toString()); + response = data; + } else { + console.info("Forwarding request directly to archive node (as a reverse proxy)"); + const archiveURL = new URL(`${this.variables.ARCHIVE_NODES_URL}/${request.path}`); + const { data } = await axios.get(archiveURL.toString()); + response = data; + } + // Logger les metrics + const metric = new MetricEntity(); + Object.assign(metric, request, { project, dateRequested: new Date() }); + + // await this.saveMetric(metric); + return response; + } + + isRollingNodeRedirection(url: string): boolean { + const pureUrl = `/${url!.trim()}`; + console.info(`Checking if ${pureUrl} is a rolling node redirection`); + return Boolean(BaseService.rollingPatterns.find((rollingpattern) => pureUrl.includes(rollingpattern))); + } +} + diff --git a/src/common/services/proxy/validators/IsRpcPathAllowed.ts b/src/common/services/proxy/validators/IsRpcPathAllowed.ts new file mode 100644 index 00000000..450ec340 --- /dev/null +++ b/src/common/services/proxy/validators/IsRpcPathAllowed.ts @@ -0,0 +1,31 @@ +import BaseService from "@Services/BaseService"; +import { ValidatorConstraint, ValidatorConstraintInterface } from "class-validator"; + +@ValidatorConstraint({ name: "IsRpcPathAllowed" }) +export default class IsRpcPathAllowed implements ValidatorConstraintInterface { + public validate(path: string) { + return isAllowed(path); + } + + public defaultMessage() { + return `not a valid path!`; + } +} + +function isAllowed(path: string): boolean { + const pureUrl = `/${path!.trim()}`; + let nonWhitelistedPart = ""; + for (const whitelistPath of BaseService.whitelisted) { + if (pureUrl.includes(whitelistPath)) { + nonWhitelistedPart = pureUrl.slice(pureUrl.indexOf(whitelistPath) + whitelistPath.length); + break; + } + } + for (const blacklistPath of BaseService.blacklisted) { + if (nonWhitelistedPart.includes(blacklistPath) || pureUrl.includes(blacklistPath)) { + return false; + } + } + return true; +} + diff --git a/src/common/services/proxy/validators/IsValidProject.ts b/src/common/services/proxy/validators/IsValidProject.ts new file mode 100644 index 00000000..36e4890d --- /dev/null +++ b/src/common/services/proxy/validators/IsValidProject.ts @@ -0,0 +1,24 @@ +import BaseService from "@Services/BaseService"; +import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from "class-validator"; +import Container from "typedi"; +import { RpcRequest } from "../ProxyService"; +import ProjectsRepository from "@Common/repositories/projects/ProjectsRepository"; + +@ValidatorConstraint({ name: "IsValidProject" }) +export default class IsValidProject implements ValidatorConstraintInterface { + public async validate(uuid: string, args: ValidationArguments) { + const projectRepository = Container.get(ProjectsRepository); + + if (args.constraints?.[0]?.network) { + return Boolean(await projectRepository.findOne({ uuid, network: BaseService.network })); + } + return false; + } + + public defaultMessage(args: ValidationArguments) { + const network = args.constraints?.[0]!.network; + const uuid = (args.object as RpcRequest).uuid; + return `Project uuid: ${uuid} with network: ${network} does not exist`; + } +} + diff --git a/src/common/system/database/DbProvider.ts b/src/common/system/database/DbProvider.ts index 82a15a81..0037217b 100644 --- a/src/common/system/database/DbProvider.ts +++ b/src/common/system/database/DbProvider.ts @@ -1,24 +1,26 @@ import dotenv from "dotenv"; import { PrismaClient } from "@prisma/client"; -import IDatabaseConfig from "../../config/IDatabaseConfig"; +import IDatabaseConfig from "../../config/database/IDatabaseConfig"; +import { BackendVariables } from "@Common/config/variables/Variables"; +import Container from "typedi"; dotenv.config(); export default class DbProvider { + protected readonly variables = Container.get(BackendVariables); protected client = new PrismaClient({ datasources: { db: { - url: `postgres://${process.env["DATABASE_USER"]}:${process.env["DATABASE_PASSWORD"]}@${process.env["DATABASE_HOSTNAME"]}:${process.env["DATABASE_PORT"]}/${process.env["DATABASE_NAME"]}`, + url: `postgres://${this.variables.DATABASE_USER}:${this.variables.DATABASE_PASSWORD}@${this.variables.DATABASE_HOSTNAME}:${this.variables.DATABASE_PORT}/${this.variables.DATABASE_NAME}`, }, - }, + }, }); - constructor(protected config: IDatabaseConfig) { - } + constructor(protected config: IDatabaseConfig) {} public async connect(): Promise { await this.client.$connect(); - console.info(`⚡️[Prisma]: Connected to ${this.config.name}`);// A Logger middleware is to be added here + console.info(`⚡️[Prisma]: Connected to ${this.config.name}`); // A Logger middleware is to be added here } public getClient() { diff --git a/src/common/system/database/index.ts b/src/common/system/database/index.ts index 6fa84a21..6f728469 100644 --- a/src/common/system/database/index.ts +++ b/src/common/system/database/index.ts @@ -1,4 +1,4 @@ -import IDatabaseConfig from "@Common/config/IDatabaseConfig"; +import IDatabaseConfig from "@Common/config/database/IDatabaseConfig"; import DbProvider from "./DbProvider"; export type { IDatabaseConfig }; diff --git a/src/common/system/interfaces/Interfaces.ts b/src/common/system/interfaces/Interfaces.ts new file mode 100644 index 00000000..441df4a7 --- /dev/null +++ b/src/common/system/interfaces/Interfaces.ts @@ -0,0 +1,9 @@ +export interface IHttpReponse { + status: number; + reason: string | null; +} + +export interface IStatusNode { + archive_node: IHttpReponse; + rolling_node: IHttpReponse; +} \ No newline at end of file diff --git a/src/entries/Api.ts b/src/entries/Api.ts index 0545c9d1..e062259d 100644 --- a/src/entries/Api.ts +++ b/src/entries/Api.ts @@ -1,36 +1,34 @@ import "module-alias/register"; import "reflect-metadata"; -import dotenv from "dotenv"; import { Container } from "typedi"; import ExpressServer from "@Common/system/ExpressServer"; import routes from "@Api/controllers/index"; import cors from "cors"; import bodyParser from "body-parser"; -import TezosLink from "@Common/databases/TezosLink"; +// import TezosLink from "@Common/databases/TezosLink"; import errorHandler from "@Api/middlewares/ErrorHandler"; +import { BackendVariables } from "@Common/config/variables/Variables"; -dotenv.config(); - -const port = process.env["NEXT_PUBLIC_API_PORT"]; -const rootUrl = process.env["NEXT_PUBLIC_API_ROOT_URL"]; -const label = process.env["NEXT_PUBLIC_API_LABEL"] ?? "Unknown Service"; - -if (!port) throw new Error(`process.env Port is undefined`); -if (!rootUrl) throw new Error(`process.env RootUrl is undefined`); -Container.get(TezosLink).connect(); -Container.get(ExpressServer).init({ - label, - port: parseInt(port), - rootUrl, - middlwares: [ - cors({ origin: "*" }), - bodyParser.urlencoded({ extended: true }), - bodyParser.json(), - ], - errorHandler, -}); - -routes.start(); +(async () => { + try { + const variables = await Container.get(BackendVariables).validate(); + const port = variables.API_PORT; + const rootUrl = variables.API_ROOT_URL; + const label = variables.API_LABEL ?? "Unknown Service"; + + // Container.get(TezosLink).connect(); + Container.get(ExpressServer).init({ + label, + port: parseInt(port), + rootUrl, + middlwares: [cors({ origin: "*" }), bodyParser.urlencoded({ extended: true }), bodyParser.json()], + errorHandler, + }); + routes.start(); + } catch (e) { + console.error(e); + } +})(); diff --git a/src/entries/Web.ts b/src/entries/Web.ts index d1ee8274..14602733 100644 --- a/src/entries/Web.ts +++ b/src/entries/Web.ts @@ -1,21 +1,27 @@ import "module-alias/register"; import "reflect-metadata"; -import dotenv from "dotenv"; import { Container } from "typedi"; import NextServer from "@Common/system/NextJs"; +import dotenv from "dotenv"; +import { FrontendVariables } from "@Front/Config/VariablesFront"; -dotenv.config(); +(async () => { + try { + dotenv.config(); + const frontVariables = Container.get(FrontendVariables); -const port = process.env["WEB_PORT"]; -const rootUrl = process.env["WEB_ROOT_URL"]; -const label = process.env["WEB_LABEL"] ?? "Unknown Service"; + const port = frontVariables.WEB_PORT; + const rootUrl = frontVariables.WEB_ROOT_URL; + const label = frontVariables.WEB_LABEL ?? "Unknown Service"; -if (!port) throw new Error(`process.env Port is undefined`); -if (!rootUrl) throw new Error(`process.env RootUrl is undefined`); + Container.get(NextServer).init({ + label, + isDev: frontVariables.NODE_ENV !== "production", + port: parseInt(port), + rootUrl, + }); + } catch (e) { + console.error(e); + } +})(); -Container.get(NextServer).init({ - label, - isDev: process.env.NODE_ENV !== 'production', - port: parseInt(port), - rootUrl, -}); \ No newline at end of file diff --git a/src/front/Components/DesignSystem/CheckBox/classes.module.scss b/src/front/Components/DesignSystem/CheckBox/classes.module.scss index c10b9aaa..51db7a4a 100644 --- a/src/front/Components/DesignSystem/CheckBox/classes.module.scss +++ b/src/front/Components/DesignSystem/CheckBox/classes.module.scss @@ -10,7 +10,7 @@ background-color: transparent; width: 16px; height: 16px; - border: 1px solid $green-flash; + border: 1px solid var(green-flash); border-radius: 2px; margin-right: 16px; display: grid; @@ -23,7 +23,7 @@ display: grid; width: 16px; height: 16px; - background-color: $green-flash; + background-color: var(green-flash); border-radius: 2px; transform: scale(0); } diff --git a/src/front/Components/DesignSystem/Form/Elements/InputField/classes.module.scss b/src/front/Components/DesignSystem/Form/Elements/InputField/classes.module.scss index 713ab8d2..99ef920e 100644 --- a/src/front/Components/DesignSystem/Form/Elements/InputField/classes.module.scss +++ b/src/front/Components/DesignSystem/Form/Elements/InputField/classes.module.scss @@ -2,7 +2,16 @@ .root { position: relative; - + textarea{ + resize: none; + height: auto; + box-sizing: border-box; + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-size: 18px; + line-height: 22px; + } .input { z-index: 1; display: flex; @@ -10,7 +19,6 @@ align-items: center; padding: 24px; gap: 10px; - width: 530px; height: 70px; border: 1px solid $grey-medium; @@ -18,7 +26,7 @@ &:focus { ~ .fake-placeholder { transform: translateY(-35px); - transition: transform 0.5s ease; + transition: transform 0.3s ease-in-out; } } &:not([value=""]) { @@ -32,7 +40,7 @@ &:focus { ~ .fake-placeholder { transform: translateY(-35px); - transition: transform 0.5s ease; + transition: transform 0.3s ease-in-out; } } &:not([value=""]) { @@ -46,7 +54,7 @@ &:not([value=""]) { ~ .fake-placeholder { transform: translateY(-35px); - transition: transform 0.5s ease; + transition: transform 0.3s ease-in-out; } } diff --git a/src/front/Components/DesignSystem/Form/Elements/InputField/index.tsx b/src/front/Components/DesignSystem/Form/Elements/InputField/index.tsx index 3647a2db..9071adff 100644 --- a/src/front/Components/DesignSystem/Form/Elements/InputField/index.tsx +++ b/src/front/Components/DesignSystem/Form/Elements/InputField/index.tsx @@ -7,7 +7,7 @@ import classes from "./classes.module.scss"; export type IProps = IBaseFieldProps & { fakeplaceholder: string; - large?: boolean; + textarea?: boolean; }; // @ts-ignore TODO: typing error on IProps (validator class?? cf Massi 22/02/23) @@ -30,7 +30,7 @@ export default class InputField extends BaseField { // we always need to control the input so we need to set the value as "" by default const value = this.state.value ?? ""; - if (this.props.large === true) { + if (this.props.textarea === true) { return (
diff --git a/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/classes.module.scss b/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/classes.module.scss index 8afe36e8..b8af1a78 100644 --- a/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/classes.module.scss +++ b/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/classes.module.scss @@ -11,6 +11,16 @@ position: absolute; top: 107px; right: 56px; + animation: smooth-appear 0.2s ease forwards; + + @keyframes smooth-appear { + from { + opacity: 0; + } + to { + opacity: 1; + } + } .notification-header { width: 100%; diff --git a/src/front/Components/DesignSystem/Header/Profile/ProfileModal/classes.module.scss b/src/front/Components/DesignSystem/Header/Profile/ProfileModal/classes.module.scss index 12e7da61..3272c0e1 100644 --- a/src/front/Components/DesignSystem/Header/Profile/ProfileModal/classes.module.scss +++ b/src/front/Components/DesignSystem/Header/Profile/ProfileModal/classes.module.scss @@ -10,6 +10,17 @@ top: 107px; right: 66px; text-align: center; + animation: smooth-appear 0.2s ease forwards; + + @keyframes smooth-appear { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + > *:not(:last-child) { margin-bottom: 24px; } diff --git a/src/front/Components/DesignSystem/Modal/classes.module.scss b/src/front/Components/DesignSystem/Modal/classes.module.scss index 435a9a5c..1632ed19 100644 --- a/src/front/Components/DesignSystem/Modal/classes.module.scss +++ b/src/front/Components/DesignSystem/Modal/classes.module.scss @@ -18,6 +18,16 @@ width: 100%; height: 100%; background-color: $modal-background; + animation: smooth-appear 0.2s ease forwards; + + @keyframes smooth-appear { + from { + opacity: 0; + } + to { + opacity: 1; + } + } } .container { @@ -28,6 +38,16 @@ box-shadow: 0px 6px 12px rgba(255, 255, 255, 0.11); overflow: auto; padding: 32px; + animation: smooth-appear 0.2s ease forwards; + + @keyframes smooth-appear { + from { + opacity: 0; + } + to { + opacity: 1; + } + } @media (max-width: $screen-s) { width: 90%; diff --git a/src/front/Components/DesignSystem/RadioBox/classes.module.scss b/src/front/Components/DesignSystem/RadioBox/classes.module.scss index 2790b0ab..f6fecf6c 100644 --- a/src/front/Components/DesignSystem/RadioBox/classes.module.scss +++ b/src/front/Components/DesignSystem/RadioBox/classes.module.scss @@ -11,7 +11,7 @@ background-color: transparent; width: 16px; height: 16px; - border: 1px solid $green-flash; + border: 1px solid var(green-flash); border-radius: 100px; margin-right: 16px; display: grid; @@ -24,7 +24,7 @@ content: ""; width: 10px; height: 10px; - background-color: $green-flash; + background-color: var(green-flash); border-radius: 100px; transform: scale(0); } diff --git a/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/classes.module.scss b/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/classes.module.scss index 25705e51..7f5af7c2 100644 --- a/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/classes.module.scss +++ b/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/classes.module.scss @@ -31,7 +31,7 @@ border-radius: 5px; animation-name: slide-left; - animation-duration: 400ms; + animation-duration: 300ms; animation-timing-function: $custom-easing; animation-fill-mode: forwards; diff --git a/src/front/Components/DesignSystem/ToolTip/index.tsx b/src/front/Components/DesignSystem/ToolTip/index.tsx index 82a3f987..b0cbc06c 100644 --- a/src/front/Components/DesignSystem/ToolTip/index.tsx +++ b/src/front/Components/DesignSystem/ToolTip/index.tsx @@ -1,8 +1,8 @@ import React from "react"; import Image from "next/image"; import ToolTipIcon from "@Assets/icons/tool-tip.svg"; -import TooltipContent from "./Content"; -import Typography, { ITypo } from "../Typography"; +import TooltipMUI, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; +import styled from "@emotion/styled"; type IProps = { title?: string | JSX.Element; @@ -16,6 +16,19 @@ type IState = { event: React.MouseEvent | null; }; +const LightTooltip = styled(({ className, ...props }: TooltipProps) => ( + + ))(({ theme }) => ({ + [`& .${tooltipClasses.tooltip}`]: { + backgroundColor: "var(--colormerdum)", + color: "var(--colormerdum)", + //boxShadow: theme.shadows[1], + fontSize: 11, + },[`& .${tooltipClasses.arrow}`]: { + // color: theme.palette.common.black, + }, + })); + export default class Tooltip extends React.Component { static defaultProps: Partial = { isNotFlex: false, @@ -23,44 +36,17 @@ export default class Tooltip extends React.Component { public constructor(props: IProps) { super(props); - this.state = { - showContent: false, - event: null, - }; - this.togglePopup = this.togglePopup.bind(this); - this.moovePopup = this.moovePopup.bind(this); } public override render(): JSX.Element { return ( - <> + + style={!this.props.isNotFlex ? { display: "flex" } : {}}> toolTip icon - - - {this.props.text} - - - + ); } - - private togglePopup(e: React.MouseEvent): void { - this.setState({ - showContent: !this.state.showContent, - event: e, - }); - } - - private moovePopup(e: React.MouseEvent): void { - this.setState({ - event: e, - }); - } } diff --git a/src/front/Components/LayoutTemplates/DefaultLayout.tsx b/src/front/Components/LayoutTemplates/DefaultLayout.tsx index 66445bd6..e85fca61 100644 --- a/src/front/Components/LayoutTemplates/DefaultLayout.tsx +++ b/src/front/Components/LayoutTemplates/DefaultLayout.tsx @@ -1,6 +1,5 @@ import Head from "next/head"; import { ReactNode } from "react"; - type DefaultLayoutProps = { children: ReactNode }; export const DefaultLayout = ({ children }: DefaultLayoutProps) => { diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index 7026d158..6af1770e 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -121,7 +121,7 @@ export default class DesignSystem extends BasePage {
- +
diff --git a/src/front/Config/VariablesFront.ts b/src/front/Config/VariablesFront.ts new file mode 100644 index 00000000..b0b79ffc --- /dev/null +++ b/src/front/Config/VariablesFront.ts @@ -0,0 +1,37 @@ +import { Service } from "typedi"; + +@Service() +export class FrontendVariables { + private static instance: FrontendVariables; + + public readonly WEB_LABEL: string; + + public readonly WEB_PORT!: string; + + public readonly WEB_ROOT_URL!: string; + + public readonly NEXT_PUBLIC_API_URL!: string; + + public readonly NEXT_PUBLIC_RPC_GATEWAY_MAINNET_URL!: string; + + public readonly NEXT_PUBLIC_RPC_GATEWAY_TESTNET_URL!: string; + + public readonly NODE_ENV!: string; + + constructor() { + this.NODE_ENV = process.env["NODE_ENV"]!; + this.WEB_LABEL = process.env["WEB_LABEL"]!; + this.WEB_PORT = process.env["WEB_PORT"]!; + this.WEB_ROOT_URL = process.env["WEB_ROOT_URL"]!; + this.NEXT_PUBLIC_API_URL = process.env["NEXT_PUBLIC_API_URL"]!; + this.NEXT_PUBLIC_RPC_GATEWAY_MAINNET_URL = process.env["NEXT_PUBLIC_RPC_GATEWAY_MAINNET_URL"]!; + this.NEXT_PUBLIC_RPC_GATEWAY_TESTNET_URL = process.env["NEXT_PUBLIC_RPC_GATEWAY_TESTNET_URL"]!; + } + + public static getInstance(): FrontendVariables { + if (!this.instance) { + this.instance = new this(); + } + return this.instance; + } +} diff --git a/src/front/Themes/variables.scss b/src/front/Themes/variables.scss index 43a3d36c..6f817e8d 100644 --- a/src/front/Themes/variables.scss +++ b/src/front/Themes/variables.scss @@ -6,5 +6,29 @@ --root-padding: 64px 120px; --font-primary: "Inter", sans-serif; - --font-secondary: "Source Sans Pro", sans-serif; + + --colormerdum: blue; + + --green-flash: $green-flash; + --blue-flash: $blue-flash; + --turquoise-flash: $turquoise-flash; + --purple-flash: $purple-flash; + --purple-hover: $purple-hover; + --orange-flash: $orange-flash; + --red-flash: $red-flash; + --re-hover: $re-hover; + --pink-flash: $pink-flash; + --pink-hover: $pink-hover; + + --green-soft: $green-soft; + --blue-soft: $blue-soft; + --turquoise-soft: $turquoise-soft; + --purple-soft: $purple-soft; + --orange-soft: $orange-soft; + --red-soft: $red-soft; + --pink-soft: $pink-soft; + + --grey: $grey; + --grey-medium: $grey-medium; + --grey-soft: $grey-soft; } diff --git a/src/front/index.scss b/src/front/index.scss index ef522e58..b94f62a6 100644 --- a/src/front/index.scss +++ b/src/front/index.scss @@ -1,5 +1,6 @@ @import "@Themes/constants.scss"; @import "@Themes/fonts.scss"; +@import "@Themes/variables.scss"; * { box-sizing: border-box;