diff --git a/package-lock.json b/package-lock.json index 4fad5a4..0d07d19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,9 @@ "license": "GPL3", "dependencies": { "@dotfionn/logger": "^1.0.1", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@tailwindcss/forms": "^0.5.6", "axios": "^0.27.2", "body-parser": "^1.20.0", "cookie-parser": "^1.4.6", @@ -20,7 +23,12 @@ "jsonwebtoken": "^8.5.1", "module-alias": "^2.2.2", "mongoose": "^6.5.0", - "point-in-polygon": "^1.1.0" + "primeflex": "^3.3.1", + "primeicons": "^6.0.1", + "primereact": "^10.0.5", + "morgan": "1.10.0", + "point-in-polygon": "^1.1.0", + "winston": "3.11.0" }, "devDependencies": { "@headlessui/react": "^1.7.15", @@ -31,6 +39,7 @@ "@types/express": "^4.17.13", "@types/jest": "^27.5.2", "@types/jsonwebtoken": "^8.5.8", + "@types/morgan": "1.9.7", "@types/node": "^18.6.2", "@types/react": "^18.0.15", "@types/react-dom": "^18.0.6", @@ -44,14 +53,9 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-n": "^15.2.5", "eslint-plugin-promise": "^6.0.1", - "flowbite": "^1.6.5", - "flowbite-react": "^0.4.7", "highlight.js": "^11.6.0", "http-proxy-middleware": "^2.0.6", "postcss": "^8.4.24", - "primeflex": "^3.2.1", - "primeicons": "^5.0.0", - "primereact": "^8.3.0", "react": "^18.2.0", "react-data-table-component": "^7.5.3", "react-dom": "^18.2.0", @@ -82,7 +86,6 @@ }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -723,7 +726,6 @@ }, "node_modules/@babel/code-frame": { "version": "7.22.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/highlight": "^7.22.5" @@ -926,7 +928,6 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.22.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" @@ -1044,7 +1045,6 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.22.5", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1052,7 +1052,6 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.22.5", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1096,7 +1095,6 @@ }, "node_modules/@babel/highlight": { "version": "7.22.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.22.5", @@ -1109,7 +1107,6 @@ }, "node_modules/@babel/highlight/node_modules/ansi-styles": { "version": "3.2.1", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^1.9.0" @@ -1120,7 +1117,6 @@ }, "node_modules/@babel/highlight/node_modules/chalk": { "version": "2.4.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", @@ -1133,7 +1129,6 @@ }, "node_modules/@babel/highlight/node_modules/color-convert": { "version": "1.9.3", - "dev": true, "license": "MIT", "dependencies": { "color-name": "1.1.3" @@ -1141,12 +1136,10 @@ }, "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", - "dev": true, "license": "MIT" }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -1154,7 +1147,6 @@ }, "node_modules/@babel/highlight/node_modules/supports-color": { "version": "5.5.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^3.0.0" @@ -2588,11 +2580,11 @@ "peer": true }, "node_modules/@babel/runtime": { - "version": "7.22.6", - "dev": true, - "license": "MIT", + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", + "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -2633,7 +2625,6 @@ }, "node_modules/@babel/types": { "version": "7.22.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.22.5", @@ -2644,33 +2635,174 @@ "node": ">=6.9.0" } }, - "node_modules/@dotfionn/logger": { - "version": "1.0.1", - "license": "ISC", + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "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.2.0" + } + }, + "node_modules/@emotion/babel-plugin/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/@emotion/babel-plugin/node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", "dependencies": { - "typescript": "^4.6.3" + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" } }, + "node_modules/@emotion/cache/node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, "node_modules/@emotion/is-prop-valid": { "version": "1.2.1", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@emotion/memoize": "^0.8.1" } }, "node_modules/@emotion/memoize": { "version": "0.8.1", - "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz", + "integrity": "sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz", + "integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/styled": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", + "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/is-prop-valid": "^1.2.1", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } }, "node_modules/@emotion/unitless": { "version": "0.8.1", - "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" }, "node_modules/@esbuild/linux-x64": { "version": "0.18.11", @@ -2753,45 +2885,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@floating-ui/core": { - "version": "1.3.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@floating-ui/dom": { - "version": "1.4.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.3.1" - } - }, - "node_modules/@floating-ui/react": { - "version": "0.24.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.1", - "aria-hidden": "^1.2.3", - "tabbable": "^6.0.1" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@floating-ui/dom": "^1.3.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, "node_modules/@headlessui/react": { "version": "1.7.15", "dev": true, @@ -2847,7 +2940,6 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.1", @@ -2860,7 +2952,6 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2868,7 +2959,6 @@ }, "node_modules/@jridgewell/set-array": { "version": "1.1.2", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2876,12 +2966,10 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.18", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "3.1.0", @@ -2890,7 +2978,6 @@ }, "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", - "dev": true, "license": "MIT" }, "node_modules/@nicolo-ribaudo/chokidar-2": { @@ -2910,7 +2997,6 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -2922,7 +3008,6 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -2930,7 +3015,6 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -2940,15 +3024,6 @@ "node": ">= 8" } }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, "node_modules/@remix-run/router": { "version": "1.7.1", "dev": true, @@ -3433,6 +3508,17 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/forms": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.6.tgz", + "integrity": "sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==", + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" + } + }, "node_modules/@testing-library/dom": { "version": "9.3.1", "dev": true, @@ -3624,14 +3710,28 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/morgan": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.7.tgz", + "integrity": "sha512-4sJFBUBrIZkP5EvMm1L6VCXp3SQe8dnXqlVpe1jsmTjS1JQVmSjnpMNs8DosQd6omBi/K7BSKJ6z/Mc3ki0K9g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "18.16.19", "license": "MIT" }, + "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", - "dev": true, - "license": "MIT" + "version": "15.7.8", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", + "integrity": "sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -3645,7 +3745,6 @@ }, "node_modules/@types/react": { "version": "18.2.14", - "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -3662,16 +3761,15 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.6", - "dev": true, - "license": "MIT", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.8.tgz", + "integrity": "sha512-QmQ22q+Pb+HQSn04NL3HtrqHwYMf4h3QKArOy5F8U5nEVMaihBs3SR10WiOM1iwPz5jIo8x/u11al+iEGZZrvg==", "dependencies": { "@types/react": "*" } }, "node_modules/@types/scheduler": { "version": "0.16.3", - "dev": true, "license": "MIT" }, "node_modules/@types/semver": { @@ -3712,6 +3810,11 @@ "@types/jest": "*" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.4.tgz", + "integrity": "sha512-HlJjF3wxV4R2VQkFpKe0YqJLilYNgtRtsqqZtby7RkVsSs+i+vbyzjtUwpFEdUCKcrGzCiEJE7F/0mKjh0sunA==" + }, "node_modules/@types/webidl-conversions": { "version": "7.0.0", "license": "MIT" @@ -4089,12 +4192,10 @@ }, "node_modules/any-promise": { "version": "1.3.0", - "dev": true, "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", - "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -4106,7 +4207,6 @@ }, "node_modules/arg": { "version": "5.0.2", - "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -4114,17 +4214,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/aria-hidden": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/aria-query": { "version": "5.1.3", "dev": true, @@ -4209,6 +4298,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, "node_modules/asynckit": { "version": "0.4.0", "license": "MIT" @@ -4264,6 +4358,20 @@ "form-data": "^4.0.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/babel-plugin-polyfill-corejs2": { "version": "0.4.4", "dev": true, @@ -4305,7 +4413,6 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "dev": true, "license": "MIT" }, "node_modules/base64-js": { @@ -4326,9 +4433,24 @@ ], "license": "MIT" }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/binary-extensions": { "version": "2.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4374,7 +4496,6 @@ }, "node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -4383,7 +4504,6 @@ }, "node_modules/braces": { "version": "3.0.2", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.0.1" @@ -4517,7 +4637,6 @@ }, "node_modules/callsites": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4525,7 +4644,6 @@ }, "node_modules/camelcase-css": { "version": "2.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -4581,7 +4699,6 @@ }, "node_modules/chokidar": { "version": "3.5.3", - "dev": true, "funding": [ { "type": "individual", @@ -4605,16 +4722,20 @@ "fsevents": "~2.3.2" } }, - "node_modules/classnames": { - "version": "2.3.2", - "dev": true, - "license": "MIT" - }, "node_modules/client-only": { "version": "0.0.1", "dev": true, "license": "MIT" }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "dev": true, @@ -4628,9 +4749,39 @@ }, "node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/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/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/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "license": "MIT", @@ -4643,7 +4794,6 @@ }, "node_modules/commander": { "version": "4.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -4651,7 +4801,6 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "dev": true, "license": "MIT" }, "node_modules/confusing-browser-globals": { @@ -4678,7 +4827,6 @@ }, "node_modules/convert-source-map": { "version": "1.9.0", - "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -4727,6 +4875,29 @@ "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/cosmiconfig/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/cross-spawn": { "version": "7.0.3", "dev": true, @@ -4767,7 +4938,6 @@ }, "node_modules/cssesc": { "version": "3.0.0", - "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -4778,18 +4948,12 @@ }, "node_modules/csstype": { "version": "3.1.2", - "dev": true, "license": "MIT" }, "node_modules/dayjs": { "version": "1.11.9", "license": "MIT" }, - "node_modules/debounce": { - "version": "1.2.1", - "dev": true, - "license": "MIT" - }, "node_modules/debug": { "version": "4.3.4", "license": "MIT", @@ -4885,7 +5049,6 @@ }, "node_modules/didyoumean": { "version": "1.2.2", - "dev": true, "license": "Apache-2.0" }, "node_modules/diff-sequences": { @@ -4909,7 +5072,6 @@ }, "node_modules/dlv": { "version": "1.1.3", - "dev": true, "license": "MIT" }, "node_modules/doctrine": { @@ -4930,8 +5092,8 @@ }, "node_modules/dom-helpers": { "version": "5.2.1", - "dev": true, - "license": "MIT", + "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" @@ -4942,11 +5104,6 @@ "dev": true, "license": "MIT" }, - "node_modules/easy-bem": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "license": "Apache-2.0", @@ -4963,6 +5120,11 @@ "dev": true, "license": "ISC" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "license": "MIT", @@ -4970,6 +5132,14 @@ "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/es-abstract": { "version": "1.21.2", "dev": true, @@ -5123,7 +5293,6 @@ }, "node_modules/escape-string-regexp": { "version": "1.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -5729,7 +5898,6 @@ }, "node_modules/fast-glob": { "version": "3.3.0", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -5775,12 +5943,16 @@ }, "node_modules/fastq": { "version": "1.15.0", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "dev": true, @@ -5794,7 +5966,6 @@ }, "node_modules/fill-range": { "version": "7.0.1", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -5830,6 +6001,11 @@ "version": "2.0.0", "license": "MIT" }, + "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/find-up": { "version": "5.0.0", "dev": true, @@ -5862,32 +6038,6 @@ "dev": true, "license": "ISC" }, - "node_modules/flowbite": { - "version": "1.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@popperjs/core": "^2.9.3", - "mini-svg-data-uri": "^1.4.3" - } - }, - "node_modules/flowbite-react": { - "version": "0.4.10", - "dev": true, - "license": "MIT", - "dependencies": { - "@floating-ui/react": "^0.24.3", - "flowbite": "^1.6.6", - "react-icons": "^4.10.1", - "react-indiana-drag-scroll": "^2.2.0", - "tailwind-merge": "^1.13.2" - }, - "peerDependencies": { - "react": "^18", - "react-dom": "^18", - "tailwindcss": "^3" - } - }, "node_modules/follow-redirects": { "version": "1.15.2", "funding": [ @@ -5965,7 +6115,6 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", - "dev": true, "license": "ISC" }, "node_modules/function-bind": { @@ -6054,7 +6203,6 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -6214,6 +6362,19 @@ "node": ">=12.0.0" } }, + "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/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/http-errors": { "version": "2.0.0", "license": "MIT", @@ -6302,7 +6463,6 @@ }, "node_modules/import-fresh": { "version": "3.3.0", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -6333,7 +6493,6 @@ }, "node_modules/inflight": { "version": "1.0.6", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -6396,6 +6555,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-bigint": { "version": "1.0.4", "dev": true, @@ -6409,7 +6573,6 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -6446,7 +6609,6 @@ }, "node_modules/is-core-module": { "version": "2.12.1", - "dev": true, "license": "MIT", "dependencies": { "has": "^1.0.3" @@ -6471,7 +6633,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6479,7 +6640,6 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -6509,7 +6669,6 @@ }, "node_modules/is-number": { "version": "7.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -6582,6 +6741,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { "version": "1.0.7", "dev": true, @@ -6707,7 +6877,6 @@ }, "node_modules/jiti": { "version": "1.19.1", - "dev": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -6715,7 +6884,6 @@ }, "node_modules/js-tokens": { "version": "4.0.0", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -6740,6 +6908,11 @@ "node": ">=4" } }, + "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/json-schema-traverse": { "version": "0.4.1", "dev": true, @@ -6805,6 +6978,11 @@ "node": ">=12.0.0" } }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/levn": { "version": "0.4.1", "dev": true, @@ -6819,7 +6997,6 @@ }, "node_modules/lilconfig": { "version": "2.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -6827,7 +7004,6 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "dev": true, "license": "MIT" }, "node_modules/locate-path": { @@ -6888,9 +7064,24 @@ "version": "4.1.1", "license": "MIT" }, + "node_modules/logform": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/loose-envify": { "version": "1.4.0", - "dev": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -6950,7 +7141,6 @@ }, "node_modules/merge2": { "version": "1.4.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -6965,7 +7155,6 @@ }, "node_modules/micromatch": { "version": "4.0.5", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.2", @@ -7012,15 +7201,14 @@ }, "node_modules/mini-svg-data-uri": { "version": "1.4.4", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", "bin": { "mini-svg-data-uri": "cli.js" } }, "node_modules/minimatch": { "version": "3.1.2", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -7089,6 +7277,45 @@ "version": "2.1.3", "license": "MIT" }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/mpath": { "version": "0.9.0", "license": "MIT", @@ -7112,7 +7339,6 @@ }, "node_modules/mz": { "version": "2.7.0", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -7122,7 +7348,6 @@ }, "node_modules/nanoid": { "version": "3.3.6", - "dev": true, "funding": [ { "type": "github", @@ -7166,7 +7391,6 @@ }, "node_modules/normalize-path": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7189,7 +7413,6 @@ }, "node_modules/object-hash": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -7281,14 +7504,29 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/optionator": { "version": "0.9.3", "dev": true, @@ -7335,7 +7573,6 @@ }, "node_modules/parent-module": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -7344,6 +7581,23 @@ "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", "license": "MIT", @@ -7361,7 +7615,6 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7377,7 +7630,6 @@ }, "node_modules/path-parse": { "version": "1.0.7", - "dev": true, "license": "MIT" }, "node_modules/path-to-regexp": { @@ -7386,7 +7638,6 @@ }, "node_modules/path-type": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7405,12 +7656,10 @@ }, "node_modules/picocolors": { "version": "1.0.0", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -7430,7 +7679,6 @@ }, "node_modules/pirates": { "version": "4.0.6", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -7442,7 +7690,6 @@ }, "node_modules/postcss": { "version": "8.4.25", - "dev": true, "funding": [ { "type": "opencollective", @@ -7469,7 +7716,6 @@ }, "node_modules/postcss-import": { "version": "15.1.0", - "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -7485,7 +7731,6 @@ }, "node_modules/postcss-js": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" @@ -7503,7 +7748,6 @@ }, "node_modules/postcss-load-config": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "lilconfig": "^2.0.5", @@ -7531,7 +7775,6 @@ }, "node_modules/postcss-nested": { "version": "6.0.1", - "dev": true, "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.0.11" @@ -7549,7 +7792,6 @@ }, "node_modules/postcss-selector-parser": { "version": "6.0.13", - "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -7561,7 +7803,6 @@ }, "node_modules/postcss-value-parser": { "version": "4.2.0", - "dev": true, "license": "MIT" }, "node_modules/prelude-ls": { @@ -7598,25 +7839,24 @@ }, "node_modules/primeflex": { "version": "3.3.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/primeflex/-/primeflex-3.3.1.tgz", + "integrity": "sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ==" }, "node_modules/primeicons": { - "version": "5.0.0", - "dev": true, - "license": "MIT" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-6.0.1.tgz", + "integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA==" }, "node_modules/primereact": { - "version": "8.7.3", - "dev": true, - "license": "MIT", + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/primereact/-/primereact-10.0.5.tgz", + "integrity": "sha512-F7BNo5EYGp5035iAWX7Sb/xqwVN2qaId3BpplponlIbY+ODTmRwx/6hxmH8BgTlcoDq8bajA52/mWgF30b1rsQ==", "dependencies": { "@types/react-transition-group": "^4.4.1", "react-transition-group": "^4.4.1" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", - "primeicons": "^5.0.0 || ^6.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" }, @@ -7628,8 +7868,8 @@ }, "node_modules/prop-types": { "version": "15.8.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -7638,8 +7878,8 @@ }, "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/proxy-addr": { "version": "2.0.7", @@ -7688,7 +7928,6 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "dev": true, "funding": [ { "type": "github", @@ -7727,7 +7966,6 @@ }, "node_modules/react": { "version": "18.2.0", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -7750,7 +7988,6 @@ }, "node_modules/react-dom": { "version": "18.2.0", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", @@ -7760,32 +7997,6 @@ "react": "^18.2.0" } }, - "node_modules/react-icons": { - "version": "4.10.1", - "dev": true, - "license": "MIT", - "peerDependencies": { - "react": "*" - } - }, - "node_modules/react-indiana-drag-scroll": { - "version": "2.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "classnames": "^2.2.6", - "debounce": "^1.2.0", - "easy-bem": "^1.1.1" - }, - "engines": { - "node": ">=8", - "npm": ">=5" - }, - "peerDependencies": { - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/react-is": { "version": "17.0.2", "dev": true, @@ -7840,8 +8051,8 @@ }, "node_modules/react-transition-group": { "version": "4.4.5", - "dev": true, - "license": "BSD-3-Clause", + "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", @@ -7855,7 +8066,6 @@ }, "node_modules/read-cache": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "pify": "^2.3.0" @@ -7863,15 +8073,26 @@ }, "node_modules/read-cache/node_modules/pify": { "version": "2.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", - "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -7911,9 +8132,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "dev": true, - "license": "MIT" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/regenerator-transform": { "version": "0.15.1", @@ -7995,7 +8216,6 @@ }, "node_modules/resolve": { "version": "1.22.2", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.11.0", @@ -8011,7 +8231,6 @@ }, "node_modules/resolve-from": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -8045,7 +8264,6 @@ }, "node_modules/reusify": { "version": "1.0.4", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -8083,7 +8301,6 @@ }, "node_modules/run-parallel": { "version": "1.2.0", - "dev": true, "funding": [ { "type": "github", @@ -8134,6 +8351,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "license": "MIT" @@ -8151,7 +8376,6 @@ }, "node_modules/scheduler": { "version": "0.23.0", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -8259,6 +8483,14 @@ "version": "16.0.1", "license": "MIT" }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "2.0.0", "dev": true, @@ -8288,9 +8520,16 @@ "npm": ">= 3.0.0" } }, + "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", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -8315,6 +8554,14 @@ "node": "*" } }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "license": "MIT", @@ -8341,6 +8588,14 @@ "duplexer": "~0.1.1" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-argv": { "version": "0.1.2", "dev": true, @@ -8489,7 +8744,6 @@ }, "node_modules/sucrase": { "version": "3.32.0", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", @@ -8510,7 +8764,6 @@ }, "node_modules/sucrase/node_modules/glob": { "version": "7.1.6", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -8540,7 +8793,6 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8549,23 +8801,8 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tabbable": { - "version": "6.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/tailwind-merge": { - "version": "1.13.2", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, "node_modules/tailwindcss": { "version": "3.3.2", - "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -8602,7 +8839,6 @@ }, "node_modules/tailwindcss/node_modules/glob-parent": { "version": "6.0.2", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -8611,6 +8847,11 @@ "node": ">=10.13.0" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -8618,7 +8859,6 @@ }, "node_modules/thenify": { "version": "3.3.1", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -8626,7 +8866,6 @@ }, "node_modules/thenify-all": { "version": "1.6.0", - "dev": true, "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -8642,7 +8881,6 @@ }, "node_modules/to-fast-properties": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -8650,7 +8888,6 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -8676,9 +8913,16 @@ "node": ">=12" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", - "dev": true, "license": "Apache-2.0" }, "node_modules/tsc-watch": { @@ -8801,6 +9045,7 @@ }, "node_modules/typescript": { "version": "4.9.5", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -8910,7 +9155,6 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "dev": true, "license": "MIT" }, "node_modules/utils-merge": { @@ -9074,9 +9318,42 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/winston": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", + "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", + "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", - "dev": true, "license": "ISC" }, "node_modules/yallist": { @@ -9086,7 +9363,6 @@ }, "node_modules/yaml": { "version": "2.3.1", - "dev": true, "license": "ISC", "engines": { "node": ">= 14" diff --git a/package.json b/package.json index 7dd65f7..8b0f643 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,9 @@ "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "paths": "resolve-tspaths --out \"dist\"", - "start": "resolve-tspaths --out \"dist\" && node --inspect=0.0.0.0:9229 dist/backend/app.js", "dev": "tsc-watch -p ./tsconfig.node.json --onSuccess \"npm run start\" --onFailure \"echo WHOOPS! Server compilation failed\"", - "spa-dev": "vite --config=src/frontend/vite.config.ts", "spa-build": "vite --config=src/frontend/vite.config.ts build", "spa-preview": "vite --config=src/frontend/vite.config.ts preview" @@ -24,6 +21,9 @@ "license": "GPL3", "dependencies": { "@dotfionn/logger": "^1.0.1", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@tailwindcss/forms": "^0.5.6", "axios": "^0.27.2", "body-parser": "^1.20.0", "cookie-parser": "^1.4.6", @@ -34,7 +34,12 @@ "jsonwebtoken": "^8.5.1", "module-alias": "^2.2.2", "mongoose": "^6.5.0", - "point-in-polygon": "^1.1.0" + "morgan": "1.10.0", + "point-in-polygon": "^1.1.0", + "winston": "3.11.0", + "primeflex": "^3.3.1", + "primeicons": "^6.0.1", + "primereact": "^10.0.5" }, "devDependencies": { "@headlessui/react": "^1.7.15", @@ -45,6 +50,7 @@ "@types/express": "^4.17.13", "@types/jest": "^27.5.2", "@types/jsonwebtoken": "^8.5.8", + "@types/morgan": "1.9.7", "@types/node": "^18.6.2", "@types/react": "^18.0.15", "@types/react-dom": "^18.0.6", @@ -58,14 +64,9 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-n": "^15.2.5", "eslint-plugin-promise": "^6.0.1", - "flowbite": "^1.6.5", - "flowbite-react": "^0.4.7", "highlight.js": "^11.6.0", "http-proxy-middleware": "^2.0.6", "postcss": "^8.4.24", - "primeflex": "^3.2.1", - "primeicons": "^5.0.0", - "primereact": "^8.3.0", "react": "^18.2.0", "react-data-table-component": "^7.5.3", "react-dom": "^18.2.0", diff --git a/src/backend/app.ts b/src/backend/app.ts index cd5d3f1..9aec25e 100644 --- a/src/backend/app.ts +++ b/src/backend/app.ts @@ -1,18 +1,16 @@ -import Logger from '@dotfionn/logger'; import bodyparser from 'body-parser'; import cookieParser from 'cookie-parser'; import express from 'express'; import mongoose from 'mongoose'; import config from './config'; +import logger from './logger'; import router from './router'; import cdmService from './services/cdm.service'; import ecfmpService from './services/ecfmp.service'; import errors from '@/shared/errors'; -const logger = new Logger('vACDM:app'); - (async () => { logger.info('starting up'); @@ -20,6 +18,8 @@ const logger = new Logger('vACDM:app'); throw new Error('MONGO_URI has to be set!'); } + // TODO: default from mongoose7 will be false, needs to be checked + mongoose.set('strictQuery', true); await mongoose.connect(config().mongoUri); if (config().role == 'WORKER') { @@ -30,7 +30,7 @@ const logger = new Logger('vACDM:app'); try { await cdmService.cleanupPilots(); } catch (error) { - logger.error('error occurred when cleaning up pilots', error); + logger.error('error occurred when cleaning up pilots %o', error); } }, 10000); @@ -49,10 +49,9 @@ const logger = new Logger('vACDM:app'); try { await cdmService.cleanupUsers(); } catch (error) { - logger.error('error occurred when cleaning up users', error); + logger.error('error occurred when cleaning up users %o', error); } }, 6 * 60 * 60 * 1000); /* 6h */ - console.log(6 * 60 * 60 * 1000); // eslint-disable-next-line no-constant-condition while (true) { @@ -62,7 +61,7 @@ const logger = new Logger('vACDM:app'); try { await cdmService.optimizeBlockAssignments(); } catch (error) { - logger.error('error occurred when optimizing block assignments', error); + logger.error('error occurred when optimizing block assignments %o', error); } } @@ -89,7 +88,7 @@ const logger = new Logger('vACDM:app'); res: express.Response, next: express.NextFunction, ) => { - console.log(err); + logger.warn(err); if (err instanceof errors.APIError) { return res.status(err.responseCode).json(err); @@ -105,6 +104,6 @@ const logger = new Logger('vACDM:app'); const port = config().port; app.listen(port, () => { - logger.info('listening on port', port); + logger.info('listening on port %d', port); }); })(); diff --git a/src/backend/config.ts b/src/backend/config.ts index 7d668ef..cec9031 100644 --- a/src/backend/config.ts +++ b/src/backend/config.ts @@ -14,6 +14,11 @@ interface VacdmConfig { timeSinceLastLogin: number; }; + logging: { + levelConsole: string; + levelFile: string; + }; + eventUrl: string; eventPrio: number; eventPullInterval: number; @@ -62,6 +67,11 @@ export default function config(): VacdmConfig { timeSinceLastLogin: Number(process.env.TIME_LAST_LOGIN || 48) * 60 * 60 * 1000, }, + logging: { + levelConsole: process.env.LOG_LEVEL_CONSOLE || 'http', + levelFile: process.env.LOG_LEVEL_FILE || 'info', + }, + eventUrl: process.env.EVENT_URL || 'https://slots.vatsim-germany.org/api/events/', eventPrio: Number(process.env.EVENT_PRIO) || 5, eventPullInterval: Number(process.env.EVENT_PULL_INTERVAL || 5), diff --git a/src/backend/controllers/auth.controller.ts b/src/backend/controllers/auth.controller.ts index 5aaed08..749a15e 100644 --- a/src/backend/controllers/auth.controller.ts +++ b/src/backend/controllers/auth.controller.ts @@ -1,5 +1,6 @@ import { NextFunction, Request, Response } from 'express'; +import logger from '../logger'; import authService from '../services/auth.service'; import { UserDocument } from './../models/user.model'; @@ -23,7 +24,7 @@ export async function authUser( }); const user: UserDocument = await authService.getUserFromToken(response); - console.log('User is: ', user); + logger.debug('User is: %o', user); if (user.vacdm.atc || user.vacdm.admin) { return res.redirect('/atc'); @@ -42,7 +43,7 @@ export async function authUser( export async function getProfile( req: Request, res: Response, - next: NextFunction, + // next: NextFunction, ) { if (req.user) { req.user.access_token = ''; @@ -54,7 +55,7 @@ export async function getProfile( export async function logoutUser( req: Request, res: Response, - next: NextFunction, + // next: NextFunction, ) { res.clearCookie('vacdm_token'); res.json({ success: true }); diff --git a/src/backend/logger.ts b/src/backend/logger.ts new file mode 100644 index 0000000..8fe38e2 --- /dev/null +++ b/src/backend/logger.ts @@ -0,0 +1,42 @@ +import winston from 'winston'; + +import getConfig from './config'; + +const { logging } = getConfig(); + +const transports = [ + new winston.transports.File({ + filename: 'app.log', + level: logging.levelFile, + }), + new winston.transports.Console({ + level: logging.levelConsole, + format: winston.format.colorize({ all: true }), + }), +]; + +const logger = winston.createLogger({ + exitOnError: false, + format: winston.format.combine( + winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), + winston.format.splat(), + winston.format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`), + ), + transports, +}); + +winston.addColors({ + error: 'brightRed', + warn: 'yellow', + info: 'green', + http: 'magenta', + verbose: 'brightBlue', + debug: 'brightCyan', + silly: 'gray', +}); + +process.on('warning', e => logger.warn('%o', e)); +process.on('uncaughtException', e => logger.error('%o', e)); +process.on('unhandledRejection', e => logger.error('%o', e)); + +export default logger; diff --git a/src/backend/router.ts b/src/backend/router.ts index 5ee78f8..66f8495 100644 --- a/src/backend/router.ts +++ b/src/backend/router.ts @@ -1,4 +1,5 @@ import { NextFunction, Request, Response, Router } from 'express'; +import morgan from 'morgan'; import airportController from './controllers/airport.controller'; import authController from './controllers/auth.controller'; @@ -6,14 +7,14 @@ import flowController from './controllers/flow.controller'; import metaController from './controllers/meta.controller'; import miscController from './controllers/misc.controller'; import pilotController from './controllers/pilot.controller'; +import logger from './logger'; import authMiddleware from './middleware/auth.middleware'; -import requestloggerUtils from './utils/requestlogger.utils'; import { APIError } from '@/shared/errors'; const router = Router(); -router.use(requestloggerUtils); +router.use(morgan('short', { stream: { write: m => logger.http(m.trim()) } })); router.get('/version', metaController.getVersion); router.get('/config', metaController.getPluginConfig); diff --git a/src/backend/services/bookings.service.ts b/src/backend/services/bookings.service.ts index ec169fc..1b68f3c 100644 --- a/src/backend/services/bookings.service.ts +++ b/src/backend/services/bookings.service.ts @@ -1,10 +1,8 @@ -import Logger from '@dotfionn/logger'; import axios from 'axios'; import dayjs from 'dayjs'; import config from '../config'; - -const logger = new Logger('vACDM:services:booking'); +import logger from '../logger'; let lastPull: Date | null = null; let relevantBookings: any[] | null = null; @@ -40,7 +38,7 @@ export async function getAllBookings() { return relevantBookings; } catch (e) { - console.log('error getting all bookings', e); + logger.warn('error getting all bookings %o', e); throw e; } } @@ -51,7 +49,7 @@ export async function pilotHasBooking(cid: number): Promise { return bookings.findIndex((b) => b.user === cid) != -1; } catch (e) { - console.log('error checking if pilot has booking', cid, e); + logger.warn('error checking if pilot has booking %s %o', cid, e); throw e; } } diff --git a/src/backend/services/cdm.service.ts b/src/backend/services/cdm.service.ts index 11f4979..f2c017b 100644 --- a/src/backend/services/cdm.service.ts +++ b/src/backend/services/cdm.service.ts @@ -1,7 +1,7 @@ -import Logger from '@dotfionn/logger'; import dayjs from 'dayjs'; import config from '../config'; +import logger from '../logger'; import pilotModel, { PilotDocument } from '../models/pilot.model'; import userModel from '../models/user.model'; import blockUtils from '../utils/block.utils'; @@ -12,10 +12,7 @@ import bookingsService from './bookings.service'; import datafeedService from './datafeed.service'; import pilotService from './pilot.service'; - - import { AirportCapacity } from '@/shared/interfaces/airport.interface'; -const logger = new Logger('vACDM:services:cdm'); export function determineInitialBlock(pilot: PilotDocument): { initialBlock: number; @@ -183,11 +180,11 @@ export async function cleanupPilots() { }) .exec(); - logger.debug('pilotsToBeDeleted', pilotsToBeDeleted); + logger.debug('pilotsToBeDeleted %o', pilotsToBeDeleted); for (const pilot of pilotsToBeDeleted) { pilotService.deletePilot(pilot.callsign); - logger.debug('deleted inactive pilot', pilot.callsign); + logger.debug('deleted inactive pilot %o', pilot.callsign); } // deactivate long not seen pilots @@ -202,7 +199,7 @@ export async function cleanupPilots() { }) .exec(); - logger.debug('pilotsToBeDeactivated', pilotsToBeDeactivated); + logger.debug('pilotsToBeDeactivated %o', pilotsToBeDeactivated); for (const pilot of pilotsToBeDeactivated) { pilot.inactive = true; @@ -216,7 +213,7 @@ export async function cleanupPilots() { }, }); - logger.debug('deactivating pilot', pilot.callsign); + logger.debug('deactivating pilot %o', pilot.callsign); await pilot.save(); } @@ -325,7 +322,7 @@ export async function optimizeBlockAssignments() { pilot.vacdm.delay -= (144 + pilot.vacdm.blockId - firstBlockId) % 144; pilot.vacdm.blockId = firstBlockId; - console.log('==========>> setting pilot times', pilot.callsign); + logger.debug('==========>> setting pilot times %o', pilot.callsign); await setTime(pilot); } diff --git a/src/backend/utils/requestlogger.utils.ts b/src/backend/utils/requestlogger.utils.ts deleted file mode 100644 index 73d3c72..0000000 --- a/src/backend/utils/requestlogger.utils.ts +++ /dev/null @@ -1,22 +0,0 @@ -import Logger from '@dotfionn/logger'; -import { NextFunction, Request, Response } from 'express'; - -const logger = new Logger('vACDM:api:request'); - -function loggerMiddleware(req: Request, res: Response, next: NextFunction) { - logger.log(`request: ${new Date().toISOString()} | ${req.ip} | ${req.method} ${req.originalUrl || req.url}`); - - const stringifiedBody = JSON.stringify(req.body, undefined, 2); - - if (stringifiedBody != '{}') { - const bodyLines = stringifiedBody.split('\n'); - - for (const line of bodyLines) { - logger.debug(`body: ${line}`); - } - } - - next(); -} - -export default loggerMiddleware; diff --git a/src/frontend/src/App.css b/src/frontend/src/App.css index ca09f19..58be1a0 100644 --- a/src/frontend/src/App.css +++ b/src/frontend/src/App.css @@ -67,4 +67,74 @@ bottom: 0px; width:100%; z-index: 102; - } \ No newline at end of file + } + + + *[data-pd-ripple="true"]{ + overflow: hidden; + position: relative; +} +span[data-p-ink-active="true"]{ + animation: ripple 0.4s linear; +} +@keyframes ripple { + 100% { + opacity: 0; + transform: scale(2.5); + } +} + + + +@keyframes p-progress-spinner-dash{ + 0% { + stroke-dasharray: 1, 200; + stroke-dashoffset: 0; + } + + 50% { + stroke-dasharray: 89, 200; + stroke-dashoffset: -35px; + } + 100% { + stroke-dasharray: 89, 200; + stroke-dashoffset: -124px; + } +} +@keyframes p-progress-spinner-color { + 100%, 0% { + stroke: #ff5757; + } + 40% { + stroke: #696cff; + } + 66% { + stroke: #1ea97c; + } + 80%, 90% { + stroke: #cc8925; + } +} + +.progressbar-value-animate::after { + will-change: left, right; + animation: p-progressbar-indeterminate-anim-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; +} +.progressbar-value-animate::before { + will-change: left, right; + animation: p-progressbar-indeterminate-anim 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; +} +@keyframes p-progressbar-indeterminate-anim { + 0% { + left: -35%; + right: 100%; + } + 60% { + left: 100%; + right: -90%; + } + 100% { + left: 100%; + right: -90%; + } +} \ No newline at end of file diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 715f58f..f682314 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -1,5 +1,9 @@ +import 'primeicons/primeicons.css'; import './App.css'; +import { PrimeReactProvider } from 'primereact/api'; +import { usePassThrough } from 'primereact/passthrough'; +import Tailwind from 'primereact/passthrough/tailwind'; import { Suspense } from 'react'; import { BrowserRouter as Router, @@ -8,26 +12,58 @@ import { Navigate, } from 'react-router-dom'; -import AirportDetails from './components/AirportDetails'; -import AirportDetailsEditor from './components/AirportDetailsEditor'; -import Debug from './components/Debug'; + import DepartureBlocks from './components/DepartureBlocks'; import Loading from './components/Loading'; import Navbar from './components/Navbar'; import { AuthProvider } from './contexts/AuthProvider'; import { DarkModeProvider } from './contexts/DarkModeProvider'; +import AirportDetails from './pages/AirportDetails'; import Airports from './pages/Airports'; +import Debug from './pages/Debug'; import Delivery from './pages/Delivery'; import FlowManagement from './pages/FlowManagement'; import Landingpage from './pages/Landingpage'; -import Login from './pages/Login'; import Vdgs from './pages/VdgsNew'; +import { button } from './utils/ui/customDesign/button'; +import { card } from './utils/ui/customDesign/card'; +import { datatable } from './utils/ui/customDesign/datatable'; +import { dialog } from './utils/ui/customDesign/dialog'; +import { dropdown } from './utils/ui/customDesign/dropdown'; +import { global } from './utils/ui/customDesign/global'; +import { inputnumber } from './utils/ui/customDesign/inputnumber'; +import { inputtext } from './utils/ui/customDesign/inputtext'; +import { selectbutton } from './utils/ui/customDesign/selectbutton'; +import { toast } from './utils/ui/customDesign/toast'; +import { toolbar } from './utils/ui/customDesign/toolbar'; function App() { + + const CustomTailwind = usePassThrough( + Tailwind, + { + global: global, + toolbar: toolbar, + card: card, + datatable: datatable, + dialog: dialog, + button: button, + dropdown: dropdown, + toast: toast, + inputnumber: inputnumber, + inputtext: inputtext, + selectbutton: selectbutton, + + }, + { mergeSections: true, mergeProps: false }, + + ); + return ( <> +
@@ -35,10 +71,6 @@ function App() { } /> } /> - } - /> } /> } /> } /> } /> - } /> } /> } /> } /> @@ -56,6 +87,7 @@ function App() {
+
diff --git a/src/frontend/src/components/AirportDetails.tsx b/src/frontend/src/components/AirportDetails.tsx deleted file mode 100644 index 23cf1af..0000000 --- a/src/frontend/src/components/AirportDetails.tsx +++ /dev/null @@ -1,452 +0,0 @@ - -import { Badge } from 'primereact/badge'; -import { Button } from 'primereact/button'; -import { Card } from 'primereact/card'; -import { Column } from 'primereact/column'; -import { DataTable } from 'primereact/datatable'; -import { Dialog } from 'primereact/dialog'; -import { Dropdown } from 'primereact/dropdown'; -import { InputText } from 'primereact/inputtext'; -import { InputTextarea } from 'primereact/inputtextarea'; -import { RadioButton } from 'primereact/radiobutton'; -import { Toast } from 'primereact/toast'; -import { Toolbar } from 'primereact/toolbar'; -import { classNames } from 'primereact/utils'; -import React, { useState, useEffect, useRef } from 'react'; -import { useParams } from 'react-router-dom'; - -import AirportService from '../services/AirportService'; - -import Airport, { AirportTaxizone } from '@/shared/interfaces/airport.interface'; - -const AirportDetails = () => { - const emptyZone = { - label: '', - polygon: [], - taxiout: null, - }; - - const { icao } = useParams(); - const dt = useRef(null); - const toast = useRef(null); - const [airport, setAirport] = useState(); - const [zones, setZones] = useState([]); - const [loading, setLoading] = useState(true); - const [zone, setZone] = useState(); - const [zoneDialog, setZoneDialog] = useState(false); - const [selectedZones, setSelectedZones] = useState(null); - const [deleteZoneDialog, setDeleteZoneDialog] = useState(false); - const [submitted, setSubmitted] = useState(false); - const [value, setValue] = useState(''); - const [globalFilter, setGlobalFilter] = useState(null); - //const [expandedRows, setExpandedRows] = useState(null); - - useEffect(() => { - if (icao) - AirportService.getAirport(icao).then((data: Airport) => { - setAirport(data); - setZones(data.taxizones); - setLoading(false); - }); - }, []); - - const taxioutTemplate = (rowData: any) => { - return rowData.taxiout ? ( - - ) : ( - - ); - }; - - const saveZone = () => { - /* setSubmitted(true); - - if (zone?.label.trim()) { - let _zones = [...zones]; - let _zone = {...zone}; - if (zone.label) { - const index = findIndexByLabel(zone.label); - - _products[index] = _product; - toast.current.show({ severity: 'success', summary: 'Successful', detail: 'Zone Updated', life: 3000 }); - } - else { - _product.id = createId(); - _product.image = 'product-placeholder.svg'; - _products.push(_product); - toast.current.show({ severity: 'success', summary: 'Successful', detail: 'Zone Created', life: 3000 }); - } - - setProducts(_products); - setProductDialog(false); - setProduct(emptyProduct); - }; */ - }; - - const editZone = (relevantZone: any) => { - setZone({ ...relevantZone }); - setZoneDialog(true); - }; - - const deleteZone = () => { - /* let _zones = zones.filter(val => val.id !== zone?._id); - setProducts(_products); - setDeleteProductDialog(false); - setProduct(emptyProduct); - toast.current.show({ severity: 'success', summary: 'Successful', detail: 'Product Deleted', life: 3000 }); */ - }; - - const confirmDeleteZone = (relevantZone: any) => { - setZone(relevantZone); - setDeleteZoneDialog(true); - }; - const actionBodyTemplate = (rowData: AirportTaxizone) => { - return ( - - - - ); -} - - diff --git a/src/frontend/src/components/FeatureBox.tsx b/src/frontend/src/components/FeatureBox.tsx deleted file mode 100644 index 1556200..0000000 --- a/src/frontend/src/components/FeatureBox.tsx +++ /dev/null @@ -1,18 +0,0 @@ -const FeatureBox = (props: any) => { - return ( -
-
- {props.icon} -
- -

{props.headline}

- {props.children} -
- ); -}; - -export default FeatureBox; diff --git a/src/frontend/src/components/Navbar.tsx b/src/frontend/src/components/Navbar.tsx index 5a4cd20..540f53b 100644 --- a/src/frontend/src/components/Navbar.tsx +++ b/src/frontend/src/components/Navbar.tsx @@ -1,5 +1,6 @@ import { Disclosure, Menu, Transition } from '@headlessui/react'; import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'; +import { Button } from 'primereact/button'; import { Fragment, useContext, useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -8,8 +9,6 @@ import AuthContext from '../contexts/AuthProvider'; import DarkModeContext from '../contexts/DarkModeProvider'; import AuthService from '../services/AuthService'; -import Button from './ui/Button/Button'; - import { FrontendSettings } from '@/shared/interfaces/config.interface'; function classNames(...classes: any) { @@ -74,7 +73,6 @@ export default function NavbarWithDropdown(props: any) { window.location.protocol, '//', window.location.host, - //'localhost:3000', '/api/v1/auth/login', '&', 'response_type=code', @@ -200,7 +198,7 @@ export default function NavbarWithDropdown(props: any) {
- +
{/* Profile dropdown */} @@ -226,32 +224,6 @@ export default function NavbarWithDropdown(props: any) { leaveTo="transform opacity-0 scale-95" > - {/* - {({ active }) => ( - - Your Profile - - )} - - - {({ active }) => ( - - Settings - - )} - */} {({ active }) => ( { + + const toast = useRef(null); + const [taxizone, setTaxizone] = useState(props.taxizone); + const [visible, setVisible] = useState(false); + const [airport, setAirport] = useState(props.airport); + + + const submitForm = (e: FormEvent) => { + e.preventDefault(); + + }; + + useEffect(() => { + setVisible(props.visible); + setTaxizone(props.taxizone); + + setAirport(props.airport); + + }, []); + + const deleteTaxizone = async () => { + + const apt = { ...airport }; + const txz = { ...taxizone }; + + if (txz && apt.icao) { + if (apt && apt.taxizones) { + const index = apt.taxizones.findIndex(element => element._id === txz._id); + + if (index === -1) { + + toast.current?.show({ severity: 'error', summary: 'Error', detail: 'Something went wrong', life: 3000 }); + props.onHide(); + + } else { + + apt.taxizones.splice(index, 1); + + await AirportService.updateAirport(apt.icao, apt); + toast.current?.show({ severity: 'success', summary: 'Successful', detail: 'Zone Deleted', life: 3000 }); + props.onHide(); + } + } + } + }; + + const taxizoneDialogFooter = ( + +
+
+
+ ); + + return ( <> + +
+
+
+ +
+
+
+
+ + ); +}; + +export default TaxizoneDeleteDialog; diff --git a/src/frontend/src/components/TaxizoneDialog.tsx b/src/frontend/src/components/TaxizoneDialog.tsx new file mode 100644 index 0000000..370cccc --- /dev/null +++ b/src/frontend/src/components/TaxizoneDialog.tsx @@ -0,0 +1,215 @@ +import { Button } from 'primereact/button'; +import { Column } from 'primereact/column'; +import { DataTable } from 'primereact/datatable'; +import { Dialog } from 'primereact/dialog'; +import { InputNumber } from 'primereact/inputnumber'; +import { InputText } from 'primereact/inputtext'; +import { InputTextarea } from 'primereact/inputtextarea'; +import { SelectButton, SelectButtonChangeEvent } from 'primereact/selectbutton'; +import { Toast } from 'primereact/toast'; +import { FormEvent, useEffect, useRef, useState } from 'react'; +import React from 'react'; + +import { IAirport, IAirportTaxizone } from '../interfaces/airport.interface'; +import AirportService from '../services/AirportService'; + +type TaxizoneDialogProps = { + airport: IAirport | undefined + taxizone: IAirportTaxizone + visible: boolean + onHide(): void +}; + + +const TaxizoneDialog = (props: TaxizoneDialogProps) => { + + const toast = useRef(null); + const [taxizone, setTaxizone] = useState(props.taxizone); + //const [airport, setAirport] = useState(); + const [submitted, setSubmitted] = useState(false); + + + const submitForm = (e: FormEvent) => { + e.preventDefault(); + + }; + + useEffect(() => { + //setVisible(props.visible); + setTaxizone(props.taxizone); + + //setAirport(props.airport); + + }, [props.visible]); + + const saveTaxizone = async () => { + setSubmitted(true); + + if (taxizone?.label.trim()) { + + const apt = { ...props.airport }; + const txz = { ...taxizone }; + + if (txz && apt.icao) { + if (apt && apt.taxizones) { + const index = apt.taxizones.findIndex(element => element._id === txz._id); + + if (index !== -1) { + apt.taxizones[index] = txz; + + await AirportService.updateAirport(apt.icao, apt); + toast.current?.show({ severity: 'success', summary: 'Successful', detail: 'Zone Updated', life: 3000 }); + props.onHide(); + + + } else { + + apt.taxizones.push(txz); + await AirportService.updateAirport(apt.icao, apt); + toast.current?.show({ severity: 'success', summary: 'Successful', detail: 'Zone Created', life: 3000 }); + props.onHide(); + } + } + } + } + }; + + function deleteTaxitime(index: number) { + const newTxz = { ...taxizone }; + newTxz.taxitimes.splice(index, 1); + + setTaxizone(newTxz); + + } + + function taxitimeTemplate(rowData, rowIndex: number) { + return () => { + const newTxz = { ...taxizone }; + newTxz.taxitimes.map((c, i) => { + if (i === rowIndex) { + c.rwy_designator = e.target.value.toUpperCase(); + return c; + } else { + return c; + } + }); + setTaxizone(newTxz); + }}/>); + } + + function taxitimeMinutesTemplate(rowData, rowIndex: number) { + return () => { + const newTxz = { ...taxizone }; + newTxz.taxitimes.map((c, i) => { + if (i === rowIndex) { + c.minutes = Number(e.target.value); + return c; + } else { + return c; + } + }); + setTaxizone(newTxz); + }}/>); + } + + const taxitimesHeader = ( +
+
+ ); + + return ( <> + +
+
+
+
+ + ) => { + setTaxizone({ ...taxizone, label: e.target.value }); + }} + required + autoFocus + /> + {submitted && !taxizone?.label && Name is required.} +
+
+ + ) => { + const polygonValue = e.target.value.split('\n'); + setTaxizone({ ...taxizone, polygon: polygonValue }); + }} + required + rows={5} + cols={22} + /> +
+
+ + + { + const taxioutValue = (e.value === 'Yes') ? true : false; + setTaxizone({ ...taxizone, taxiout: taxioutValue }); + }} + /> + +
+
+
+ + taxitimeTemplate(rowData, rowIndex)} /> + taxitimeMinutesTemplate(rowData, rowIndex)} /> +
+
+
+
+
+
+ + ); +}; + +export default TaxizoneDialog; diff --git a/src/frontend/src/components/ui/Button/Button.props.ts b/src/frontend/src/components/ui/Button/Button.props.ts deleted file mode 100644 index 21dea31..0000000 --- a/src/frontend/src/components/ui/Button/Button.props.ts +++ /dev/null @@ -1,17 +0,0 @@ -import React, { ReactNode } from "react"; - -export type ButtonProps = { - style?: 'success' | 'danger' | 'warning' | 'alternative'; - disabled?: boolean; - icon?: ReactNode; - className?: string; - loading?: boolean; - type?: string; - - children?: ReactNode; - - - - // Functions - onClick?: (e: React.MouseEvent) => void; -}; \ No newline at end of file diff --git a/src/frontend/src/components/ui/Button/Button.tsx b/src/frontend/src/components/ui/Button/Button.tsx deleted file mode 100644 index 7f165df..0000000 --- a/src/frontend/src/components/ui/Button/Button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { joinClassNames } from '../../../utils/ui/classNameHelper'; -import { ButtonProps } from './Button.props'; - -function buttonStyle(style: string | undefined) { - switch (style) { - case 'success': - return 'focus:outline-none text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:ring-green-300 font-medium rounded-lg text-sm px-5 lg:py-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800'; - case 'warning': - return 'focus:outline-none text-white bg-yellow-600 hover:bg-yellow-700 focus:ring-4 focus:ring-yellow-300 font-medium rounded-lg text-sm px-5 lg:py-2 dark:focus:ring-yellow-900'; - case 'danger': - return 'focus:outline-none text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 lg:py-2 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900'; - case 'purple': - return 'focus:outline-none text-white bg-purple-700 hover:bg-purple-800 focus:ring-4 focus:ring-purple-300 font-medium rounded-lg text-sm px-5 lg:py-2 dark:bg-purple-600 dark:hover:bg-purple-700 dark:focus:ring-purple-900'; - case 'alternative': - return 'focus:outline-none text-white bg-purple-700 hover:bg-purple-800 focus:ring-4 focus:ring-purple-300 font-medium rounded-lg text-sm px-5 lg:py-2 dark:bg-purple-600 dark:hover:bg-purple-700 dark:focus:ring-purple-900'; - case 'light': - return 'text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-lg text-sm px-5 lg:py-2 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700'; - default: - return 'text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 lg:py-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800'; - } -} -const Button = (props: ButtonProps) => { - function handleClick(e: React.MouseEvent) { - if (props.disabled || props.loading) { - e.preventDefault(); - return; - } - props.onClick?.(e); - } - - const classes = joinClassNames(buttonStyle(props.style), 'md:py-1' , props.className || ''); - - - return ( - - ); -}; - -export default Button; diff --git a/src/frontend/src/components/ui/Card/Card.tsx b/src/frontend/src/components/ui/Card/Card.tsx deleted file mode 100644 index 41a9876..0000000 --- a/src/frontend/src/components/ui/Card/Card.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { joinClassNames } from '../../../utils/ui/classNameHelper'; - -const Card = (props: any) => { - const classes = joinClassNames( - 'block bg-white border border-gray-200 rounded-lg shadow dark:bg-zinc-800 dark:border-zinc-700 border', - props.className || '' - ); - - return ( - <> -
-

{props.title}

- {props.children} -
- - ); -}; - -export default Card; diff --git a/src/frontend/src/components/ui/Checkbox/Checkbox.props.ts b/src/frontend/src/components/ui/Checkbox/Checkbox.props.ts deleted file mode 100644 index 5dcd791..0000000 --- a/src/frontend/src/components/ui/Checkbox/Checkbox.props.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ReactElement } from "react"; - -export type CheckboxProps = { - className?: string; - disabled?: boolean; - checked?: boolean; - children?: ReactElement | ReactElement[] | string; - readOnly?: boolean; - onChange?: (e: boolean) => void; - id?: string; -}; \ No newline at end of file diff --git a/src/frontend/src/components/ui/Checkbox/Checkbox.tsx b/src/frontend/src/components/ui/Checkbox/Checkbox.tsx deleted file mode 100644 index d7a8ce4..0000000 --- a/src/frontend/src/components/ui/Checkbox/Checkbox.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { joinClassNames } from "../../../utils/ui/classNameHelper"; -import { CheckboxProps } from "./Checkbox.props"; -import React, { useEffect, useState } from "react"; - -export function Checkbox(props: CheckboxProps) { - const [checked, setChecked] = useState(false); - - useEffect(() => { - setChecked(props.checked ?? false); - }, [props.checked]); - - const labelClasses = joinClassNames("checkbox-label", props.disabled ? "disabled" : "", props.className ?? ""); - - const checkBoxClasses = joinClassNames("checkbox text-primary", props.disabled ? "disabled" : ""); - - function handleChange(e: React.ChangeEvent) { - const checkState = e.target.checked; - setChecked(checkState); - props.onChange?.(checkState); - } - - return ( - - ); -} \ No newline at end of file diff --git a/src/frontend/src/components/ui/Input/Input.props.ts b/src/frontend/src/components/ui/Input/Input.props.ts deleted file mode 100644 index 1899297..0000000 --- a/src/frontend/src/components/ui/Input/Input.props.ts +++ /dev/null @@ -1,31 +0,0 @@ -import React, {ReactElement} from "react"; - -export type InputProps = { - label?: string | ReactElement; - id?: string; - name?: string; - inputError?: boolean; - customInputErrorText?: string; - required?: boolean; - description?: string; - labelSmall?: boolean; - hideSpinner?: boolean; - className?: string; - inputClassName?: string; - type?: string; - value?: string; - maxLength?: number; - - placeholder?: string; - disabled?: boolean; - readOnly?: boolean; - loading?: boolean; - - dataFormType?: string; - onChange?: (e: React.ChangeEvent) => any; - - preIcon?: ReactElement; - regex?: RegExp; - regexMatchEmpty?: boolean; - regexCheckInitial?: boolean; -}; \ No newline at end of file diff --git a/src/frontend/src/components/ui/Input/Input.tsx b/src/frontend/src/components/ui/Input/Input.tsx deleted file mode 100644 index 83e73a5..0000000 --- a/src/frontend/src/components/ui/Input/Input.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { InputProps } from './Input.props'; -import { joinClassNames } from '../../../utils/ui/classNameHelper'; -import {Spinner} from "../Spinner/Spinner"; -import { useEffect, useState } from 'react';; - -export function Input(props: InputProps) { - const [inputVal, setInputVal] = useState(props.value ?? ''); - const [regexMatchFail, setRegexMatchFail] = useState(false); - - useEffect(() => { - setRegexMatchFail(false); - setInputVal(props.value ?? ''); - }, [props.value]); - - useEffect(() => { - if (props.regexCheckInitial) checkRegex(inputVal); - }, []); - - const inputDefaultClass = 'input'; - const inputFocusClass = `focus:ring-red-500 focus-within:ring-indigo-500 focus-within:border-indigo-500 focus:border-indigo-500 rounded px-1 text-black max-w-[100px] text-xl`; - const inputWrapperClass = `input-wrapper`; - - const classes = joinClassNames( - inputDefaultClass, - inputFocusClass, - inputWrapperClass, - props.inputError || regexMatchFail - ? 'border-2 border-red-400 dark:border-red-700' - : '', - props.disabled || props.loading ? 'input-disabled' : '', - props.preIcon || props.loading ? 'input-icon-pre' : '', - props.label ? 'input-label' : '' - ); - - const labelClasses = joinClassNames( - props.labelSmall ? 'text-sm' : '', - props.description == null ? 'mb-2' : '' - ); - - function checkRegex(input: string) { - if (props.regex == null) return; - - if ( - !input.match(props.regex) && - (input.length > 0 || props.regexMatchEmpty) - ) { - setRegexMatchFail(true); - } else { - setRegexMatchFail(false); - } - } - - return ( -
- {props.label && ( -
- {props.label}{' '} - {props.required && *} -
- )} - {props.description && ( -

- {props.description} -

- )} - -
- { - checkRegex(e.target.value); - setInputVal(e.target.value); - props.onChange?.(e); - }} - className={classes} - disabled={props.disabled || props.loading} - placeholder={props.placeholder} - /> - {(props.preIcon || props.loading) && ( -
- {props.loading && !props.hideSpinner && ( - - )} - {(!props.loading || props.hideSpinner) && props.preIcon} -
- )} -
- - {(props.inputError || regexMatchFail) && ( -

- - - - - {props.customInputErrorText ?? 'Input invalid.'} -

- )} -
- ); -} diff --git a/src/frontend/src/components/ui/Spinner/Spinner.props.ts b/src/frontend/src/components/ui/Spinner/Spinner.props.ts deleted file mode 100644 index 9b936e4..0000000 --- a/src/frontend/src/components/ui/Spinner/Spinner.props.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type SpinnerProps = { - size?: number; - color?: string; - borderWidth?: number; - className?: string; -}; \ No newline at end of file diff --git a/src/frontend/src/components/ui/Spinner/Spinner.tsx b/src/frontend/src/components/ui/Spinner/Spinner.tsx deleted file mode 100644 index 5112822..0000000 --- a/src/frontend/src/components/ui/Spinner/Spinner.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import {SpinnerProps} from "./Spinner.props"; - -import "./spinner.css"; - -export function Spinner(props: SpinnerProps) { - return ( -
- Loading... -
- ); -} \ No newline at end of file diff --git a/src/frontend/src/components/ui/Spinner/spinner.css b/src/frontend/src/components/ui/Spinner/spinner.css deleted file mode 100644 index 8466e80..0000000 --- a/src/frontend/src/components/ui/Spinner/spinner.css +++ /dev/null @@ -1,39 +0,0 @@ -.loader, .loader:after { - border-radius: 50%; - width: 40px; - height: 40px; - overflow: hidden; -} -.loader { - font-size: 10px; - position: relative; - text-indent: -9999em; - border-top: solid rgba(0,0,0, 0.05); - border-right: solid rgba(0,0,0, 0.05); - border-bottom: solid rgba(0,0,0, 0.05); - -webkit-transform: translateZ(0); - -ms-transform: translateZ(0); - transform: translateZ(0); - -webkit-animation: load8 1.1s infinite linear; - animation: load8 1.1s infinite linear; -} -@-webkit-keyframes load8 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } -} -@keyframes load8 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } -} \ No newline at end of file diff --git a/src/frontend/src/index.css b/src/frontend/src/index.css index bd6213e..751d75a 100644 --- a/src/frontend/src/index.css +++ b/src/frontend/src/index.css @@ -1,3 +1,10 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; \ No newline at end of file +@layer tailwind-base, primereact, tailwind-utilities; + +@layer tailwind-base { + @tailwind base; +} + +@layer tailwind-utilities { + @tailwind components; + @tailwind utilities; +} diff --git a/src/frontend/src/interfaces/airport.interface.ts b/src/frontend/src/interfaces/airport.interface.ts new file mode 100644 index 0000000..05298ca --- /dev/null +++ b/src/frontend/src/interfaces/airport.interface.ts @@ -0,0 +1,29 @@ +import Airport, { + AirportCapacity, + AirportTaxizone, +} from '@/shared/interfaces/airport.interface'; + +export interface IAirport extends Airport { + _id: string; + taxizones: IAirportTaxizone[]; + capacities: IAirportCapacity[]; +} + +export interface IAirportCapacity extends AirportCapacity { + _id: string | null; +} + +export interface IAirportTaxizone extends AirportTaxizone { + _id: string | null; + taxitimes: { + _id: string | null; + rwy_designator: string; + minutes: number; + }[]; +} + +export interface IAirportTaxizoneTaxitime extends AirportTaxizone { + _id: string | null; +} + + diff --git a/src/frontend/src/pages/AirportDetails.tsx b/src/frontend/src/pages/AirportDetails.tsx new file mode 100644 index 0000000..5be421a --- /dev/null +++ b/src/frontend/src/pages/AirportDetails.tsx @@ -0,0 +1,234 @@ +import { Button } from 'primereact/button'; +import { Card } from 'primereact/card'; +import { Column } from 'primereact/column'; +import { DataTable } from 'primereact/datatable/'; +import { Dialog } from 'primereact/dialog'; +import { Dropdown } from 'primereact/dropdown'; +import { InputText } from 'primereact/inputtext'; +import { InputTextarea } from 'primereact/inputtextarea'; +import { SelectButton, SelectButtonChangeEvent } from 'primereact/selectbutton'; +import { Toast } from 'primereact/toast'; +import { Toolbar } from 'primereact/toolbar'; +import { classNames } from 'primereact/utils'; +import { useState, useEffect, useContext, useRef } from 'react'; +import React from 'react'; +import { useParams } from 'react-router-dom'; + +import TaxizoneDeleteDialog from '../components/TaxizoneDeleteDialog'; +import TaxizoneForm from '../components/TaxizoneDialog'; +import TaxizoneDialog from '../components/TaxizoneDialog'; +import DarkModeContext from '../contexts/DarkModeProvider'; +import { + IAirport, + IAirportCapacity, + IAirportTaxizone, +} from '../interfaces/airport.interface'; +import AirportService from '../services/AirportService'; + +const AirpotDetailsTable = () => { + const emptyTaxizone: IAirportTaxizone = { + _id: null, + label: '', + polygon: [], + taxiout: false, + taxitimes: [], + }; + + const { icao } = useParams(); + const toast = useRef(null); + const [taxizoneDialog, setTaxizoneDialog] = useState(false); + const [deleteTaxizoneDialog, setDeleteTaxizoneDialog] = useState(false); + const [deleteTaxizonesDialog, setDeleteTaxizonesDialog] = useState(false); + const [airport, setAirport] = useState(); + const [selectedTaxizones, setSelectedTaxizones] = useState< + IAirportTaxizone[] + >([]); + const [selectedCapacities, setSelectedCapacities] = useState< + IAirportCapacity[] + >([]); + const [taxizone, setTaxizone] = useState(emptyTaxizone); + const [loading, setLoading] = useState(true); + + + async function fetchAirport() { + if (icao) { + AirportService.getAirport(icao).then((data) => { + if (data) { + setAirport(data); + setLoading(false); + } + }, + ); + } + } + + useEffect(() => { + //setLoading(true); + fetchAirport(); + }, []); + + + + const openNew = () => { + setTaxizone(emptyTaxizone); + setTaxizoneDialog(true); + }; + + + const hideDialog = () => { + setTaxizoneDialog(false); + setDeleteTaxizoneDialog(false); + setDeleteTaxizonesDialog(false); + //fetchAirport(); + }; + + + const confirmDeleteTaxizone = (_taxizone) => { + setTaxizone(_taxizone); + setDeleteTaxizoneDialog(true); + }; + + const confirmDeleteSelected = () => { + setDeleteTaxizonesDialog(true); + }; + + + const header = ( + +
+
+ ); + + const capacityHeader = ( +
+
+ ); + + const actionBodyTemplate = (rowData: IAirportTaxizone) => { + return ( + + + Current active Profile: + + + + + + + + + + + + + + ); +}; + +export default AirpotDetailsTable; diff --git a/src/frontend/src/pages/Airports.tsx b/src/frontend/src/pages/Airports.tsx index 00950d3..37dd354 100644 --- a/src/frontend/src/pages/Airports.tsx +++ b/src/frontend/src/pages/Airports.tsx @@ -1,10 +1,10 @@ -import { useState, useEffect, useContext } from 'react'; -import DataTable, { TableColumn } from 'react-data-table-component'; +import { Button } from 'primereact/button'; +import { Card } from 'primereact/card'; +import { Column } from 'primereact/column'; +import { DataTable } from 'primereact/datatable'; +import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import Button from '../components/ui/Button/Button'; -import Card from '../components/ui/Card/Card'; -import DarkModeContext from '../contexts/DarkModeProvider'; import AirportService from '../services/AirportService'; import Airport from '@/shared/interfaces/airport.interface'; @@ -12,44 +12,8 @@ import Airport from '@/shared/interfaces/airport.interface'; const AirpotsTable = () => { const [airports, setAirports] = useState([]); const [loading, setLoading] = useState(true); - const { darkMode } = useContext(DarkModeContext); const navigate = useNavigate(); - const columns: TableColumn[] = [ - { - name: 'ICAO', - selector: (row) => row.icao, - }, - { - name: 'Standard Taxitime', - selector: (row) => row.standard_taxitime, - }, - { - name: 'Taxizones', - selector: (row) => row.taxizones.length, - }, - { - name: 'Capacities', - selector: (row) => row.capacities.length, - }, - { - name: 'Details', - cell: (row) => ( - - ), - }, - { - name: 'Blocks', - cell: (row) => ( - - ), - }, - ]; - useEffect(() => { AirportService.getAirports().then((data: any[]) => { setAirports(data); @@ -57,17 +21,31 @@ const AirpotsTable = () => { }); }, []); + const adminBodyTemplate = (rowData: Airport) => { + return ; + }; + + const blocksBodyTemplate = (rowData: Airport) => { + return ; + }; + return (
+ value={airports} + size='small' + loading={loading} + > + + + + + + +
diff --git a/src/frontend/src/components/Debug.tsx b/src/frontend/src/pages/Debug.tsx similarity index 100% rename from src/frontend/src/components/Debug.tsx rename to src/frontend/src/pages/Debug.tsx diff --git a/src/frontend/src/pages/Delivery.tsx b/src/frontend/src/pages/Delivery.tsx index c27eec4..ca45ac6 100644 --- a/src/frontend/src/pages/Delivery.tsx +++ b/src/frontend/src/pages/Delivery.tsx @@ -1,13 +1,14 @@ import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import utc from 'dayjs/plugin/utc'; -import { useState, useEffect, useContext } from 'react'; -import DataTable, { TableColumn } from 'react-data-table-component'; +import { Button } from 'primereact/button'; +import { Card } from 'primereact/card'; +import { Column } from 'primereact/column'; +import { DataTable } from 'primereact/datatable'; +import { classNames } from 'primereact/utils'; +import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import Button from '../components/ui/Button/Button'; -import Card from '../components/ui/Card/Card'; -import DarkModeContext from '../contexts/DarkModeProvider'; import PilotService from '../services/PilotService'; import Pilot from '@/shared/interfaces/pilot.interface'; @@ -20,100 +21,8 @@ const Delivery = () => { const [departureAirports, setdepartureAirports] = useState([]); const [arrivalAirports, setarrivalAirports] = useState([]); const [loading, setLoading] = useState(true); - const { darkMode } = useContext(DarkModeContext); const navigate = useNavigate(); - const columns: TableColumn[] = [ - { - name: 'Callsign', - selector: (row) => row.callsign, - }, - { - name: 'EOBT', - selector: (row) => dayjs(row.vacdm.eobt).format('HH:mm'), - }, - { - name: 'TOBT', - selector: (row) => dayjs(row.vacdm.tobt).format('HH:mm'), - conditionalCellStyles: [ - { - when: (row) => - dayjs().diff(dayjs(row.vacdm.tobt).second(0), 'minute') > 5 || - dayjs(row.vacdm.asat).unix() !== -1, - classNames: ['text-gray-500'], - }, - ], - }, - { - name: 'TSAT', - selector: (row) => dayjs(row.vacdm.tsat).format('HH:mm'), - conditionalCellStyles: [ - { - when: (row) => dayjs(row.vacdm.asat).unix() !== -1, - classNames: ['text-gray-500'], - }, - { - when: (row) => - dayjs().diff(dayjs(row.vacdm.tsat).second(0), 'minutes') >= -5 && - dayjs().diff(dayjs(row.vacdm.tsat).second(0), 'minutes') <= 5, - classNames: ['bg-green-800'], - }, - { - when: (row) => - dayjs().diff(dayjs(row.vacdm.tsat).second(0), 'minute') > 5, - classNames: ['text-amber-500'], - }, - { - when: (row) => - dayjs().diff(dayjs(row.vacdm.tsat).second(0), 'minute') < -5, - classNames: ['text-green-300'], - }, - ], - }, - { - name: 'ASAT', - selector: (row) => dayjs(row.vacdm.asat).format('HH:mm'), - }, - { - name: 'EXOT', - selector: (row) => row.vacdm.exot, - }, - { - name: 'TTOT', - selector: (row) => dayjs(row.vacdm.ttot).format('HH:mm'), - }, - { - name: 'CTOT', - selector: (row) => dayjs(row.vacdm.ctot).format('HH:mm'), - }, - { - name: 'ADEP', - selector: (row) => row.flightplan.departure, - }, - { - name: 'SID+RWY', - selector: (row) => row.clearance.sid + ' ' + row.clearance.dep_rwy, - }, - { - name: 'ADES', - selector: (row) => row.flightplan.arrival, - }, - { - name: 'Taxizone', - selector: (row) => row.vacdm.taxizone, - }, - { - name: 'Debug', - cell: (row) => ( - - ), - }, - ]; useEffect(() => { async function loadData() { try { @@ -152,15 +61,59 @@ const Delivery = () => { return () => clearInterval(intervalId); }, []); + const tobtBodyTemplate = (rowData: Pilot) => { + const tobtClassName = (dayjs().diff(dayjs(rowData.vacdm.tobt).second(0), 'minute') > 5 || dayjs(rowData.vacdm.asat).unix() !== -1) ? 'text-gray-500' : ''; + + return
{dayjs(rowData.vacdm.tobt).format('HH:mm')}
; + }; + + const tsatBodyTemplate = (rowData: Pilot) => { + const tsatClassName = classNames('', { + 'text-gray-500' : dayjs(rowData.vacdm.asat).unix() !== -1, + 'bg-green-800' : dayjs().diff(dayjs(rowData.vacdm.tsat).second(0), 'minutes') >= -5 && dayjs().diff(dayjs(rowData.vacdm.tsat).second(0), 'minutes') <= 5, + 'text-amber-500' : dayjs().diff(dayjs(rowData.vacdm.tsat).second(0), 'minute') > 5, + 'text-green-300' : dayjs().diff(dayjs(rowData.vacdm.tsat).second(0), 'minute') < -5, + }); + return
{dayjs(rowData.vacdm.tsat).format('HH:mm')}
; + }; + + const sidRwyBodyTemplate = (rowData: Pilot) => { + return
{rowData.clearance.sid + ' (' + rowData.clearance.dep_rwy + ')'}
; + }; + + const debugBodyTemplate = (rowData: Pilot) => { + return ; + }; + + return (
+ value={pilots} + size='small' + loading={loading} + > + + dayjs(rowData.vacdm.eobt).format('HH:mm')}> + + + dayjs(rowData.vacdm.asat).format('HH:mm')}> + + dayjs(rowData.vacdm.ttot).format('HH:mm')}> + dayjs(rowData.vacdm.ctot).format('HH:mm')}> + + + + + +
); diff --git a/src/frontend/src/pages/FlowManagement.tsx b/src/frontend/src/pages/FlowManagement.tsx index 92a221b..bb69345 100644 --- a/src/frontend/src/pages/FlowManagement.tsx +++ b/src/frontend/src/pages/FlowManagement.tsx @@ -1,10 +1,10 @@ import dayjs from 'dayjs'; -import { useContext, useEffect, useState } from 'react'; -import DataTable, { TableColumn } from 'react-data-table-component'; +import { Card } from 'primereact/card'; +import { Checkbox } from 'primereact/checkbox'; +import { Column } from 'primereact/column'; +import { DataTable } from 'primereact/datatable'; +import { useEffect, useState } from 'react'; -import Card from '../components/ui/Card/Card'; -import { Checkbox } from '../components/ui/Checkbox/Checkbox'; -import DarkModeContext from '../contexts/DarkModeProvider'; import FlowService from '../services/FlowService'; import { EcfmpMeasure } from '@/shared/interfaces/ecfmp.interface'; @@ -12,7 +12,6 @@ import { EcfmpMeasure } from '@/shared/interfaces/ecfmp.interface'; const FlowManagement = () => { const [measures, setMeasures] = useState([]); const [loading, setLoading] = useState(true); - const { darkMode } = useContext(DarkModeContext); useEffect(() => { async function loadData() { @@ -32,10 +31,10 @@ const FlowManagement = () => { return () => clearInterval(intervalId); }, []); - const setMeasureEnabled = async (measure: EcfmpMeasure, checked: boolean) => { + const setMeasureEnabled = async (measure: EcfmpMeasure, checked?: boolean) => { const updatedMeasure = await FlowService.setMeasureEnable( measure.id, - checked, + checked ?? true, ); setMeasures((currentMeasures) => [ ...currentMeasures.filter((_measure) => _measure.id !== measure.id), @@ -44,83 +43,48 @@ const FlowManagement = () => { }; const enabledColumnTemplate = (rowData: EcfmpMeasure) => { - let checked = rowData.enabled; return ( { - setMeasureEnabled(rowData, e); - checked = e; + setMeasureEnabled(rowData, e.checked); }} /> ); }; - const filterColumns: TableColumn[] = [ - { - name: 'Type', - selector: (row) => row.type, - }, - { - name: 'Value', - selector: (row) => row.value, - }, - ]; + const filterValueTempate = (rowData) => { + return rowData.value.join(', '); + }; - const contraintsTemplate = (rowData: any) => { + const contraintsTemplate = (rowData: EcfmpMeasure) => { return ( + value={rowData.filters} + size='small' + > + + + ); }; - const columns: TableColumn[] = [ - { - name: 'Enabled', - cell: (row) => enabledColumnTemplate(row), - }, - { - name: 'Measure ID', - selector: (row) => row.ident, - }, - { - name: 'WEF', - selector: (row) => - dayjs(row.starttime).utc().format('dddd, DD.MM.YYYY HH:mm UTC'), - }, - { - name: 'UNT', - selector: (row) => - dayjs(row.endtime).utc().format('dddd, DD.MM.YYYY HH:mm UTC'), - }, - { - name: 'Measure', - cell: (row) => ( -
-
Type: {row.measure.type}
-
-
Value: {row.measure.value}
-
- ), - }, - { - name: 'Constraints', - cell: (row) => contraintsTemplate(row), - }, - ]; - return ( - + value={measures} + size='small' + loading={loading} + sortField='ident' + sortOrder={1} + > + + + dayjs(rowData.starttime).utc().format('dddd, DD.MM.YYYY HH:mm UTC')}> + dayjs(rowData.endtime).utc().format('dddd, DD.MM.YYYY HH:mm UTC')}> + + + ); }; diff --git a/src/frontend/src/pages/Landingpage.tsx b/src/frontend/src/pages/Landingpage.tsx index b66b8c6..97565ea 100644 --- a/src/frontend/src/pages/Landingpage.tsx +++ b/src/frontend/src/pages/Landingpage.tsx @@ -1,221 +1,91 @@ -import React, { useEffect } from 'react'; -import Typed from 'typed.js'; +import { Card } from 'primereact/card'; +import { Column } from 'primereact/column'; +import { DataTable } from 'primereact/datatable'; +import { useEffect, useState } from 'react'; + +import AirportService from '../services/AirportService'; +import PilotService from '../services/PilotService'; + -import cdm1 from '../assets/cdm1.png'; -import githubLogo from '../assets/github-mark-white.png'; -import Container from '../components/Container'; -import FeatureBox from '../components/FeatureBox'; -import Button from '../components/ui/Button/Button'; const Landingpage = () => { - const el = React.useRef(null); + + const [airports, setAirports] = useState(); + const [pilots, setPilots] = useState(); + const [loading, setLoading] = useState(true); + useEffect(() => { - const typed = new Typed(el.current, { - strings: [ - 'unlocking departure potential', - 'maximizing airport effincency', - 'event and booking slot adherence', - ], - typeSpeed: 50, - backDelay: 1000, - loop: true, - }); + async function loadData() { + + AirportService.getAirports().then((data) =>{ + setAirports(data); + setLoading(false); + }); + + PilotService.getPilots().then((data) => { + setPilots(data); + }); + } + + + const intervalId = setInterval(loadData, 30000); + + loadData(); return () => { - // Destroy Typed instance during cleanup to stop animation - typed.destroy(); + clearInterval(intervalId); }; }, []); + const numberOfPilotsTemplate = (rowData) => { + if (pilots) { + const number = pilots.filter((value) => value.flightplan.departure === rowData.icao); + return number.length; + } + }; + + const avgStartupDelayTemplate = (rowData) => { + if (pilots) { + let delay = 0; + const number = pilots.filter((pilot) => pilot.flightplan.departure === rowData.icao); + for (const pilot of number) { + delay = delay + pilot.vacdm.delay; + } + return number.length === 0 ? '' : Math.ceil(delay / number.length) + ' Minutes'; + } + }; + + const statusTemplate = (rowData) => { + if (pilots) { + const number = pilots.filter((value) => value.flightplan.departure === rowData.icao); + return (number.length !== 0 ? CDM in operation : no CDM operation); + } + }; + return ( <> -
- -

- vACDM -

-

- virtual Airport Collaborative Decision Making -

-
-

A VATSIM Tool for

- - {' '} - -
- -
- -
-
- - - - {/* mx-auto flex flex-wrap justify-evenly */} - - - - - } - > - vACDM is completely open source. We appreciate any support and - feedback. - - - - - } - > - vACDM supports MDI measures from ECFMP and calculates CTOT's - accordingly. - - - - - } - > - vACDM woks with geographic taxi zones that let you set taxi times - individually depending on parking position and runway. - - - - - } - > - vACDM is tatally customizable for your vACC needs. - - {/* - - - } - > - vACDM supports MDI measures from ECFMP and calculates CTOT's - accordingly - - - - - } - > - vACDM supports MDI measures from ECFMP and calculates CTOT's - accordingly - - - - - } - > - vACDM supports MDI measures from ECFMP and calculates CTOT's - accordingly - */} - - {/*