From 4c7f2864eee4c9a8328b62638f52e3abc6ebf553 Mon Sep 17 00:00:00 2001 From: UO287747 Date: Tue, 13 Feb 2024 00:07:21 +0100 Subject: [PATCH 01/15] First prototype frontend --- docker-compose.yml | 4 + package-lock.json | 989 ++++++++++++++++++++ package.json | 5 + webapp/src/App.css | 81 +- webapp/src/App.jsx | 22 + webapp/src/assets/react.svg | 1 + webapp/src/components/Game.jsx | 67 ++ webapp/src/components/Login.js | 2 +- webapp/src/components/Sesion.css | 38 + webapp/src/{App.js => components/Sesion.js} | 4 +- webapp/src/components/Start.jsx | 21 + webapp/src/index.css | 77 +- webapp/src/index.js | 21 +- 13 files changed, 1282 insertions(+), 50 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 webapp/src/App.jsx create mode 100644 webapp/src/assets/react.svg create mode 100644 webapp/src/components/Game.jsx create mode 100644 webapp/src/components/Sesion.css rename webapp/src/{App.js => components/Sesion.js} (93%) create mode 100644 webapp/src/components/Start.jsx diff --git a/docker-compose.yml b/docker-compose.yml index 446657e8..5cd37ef1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -61,6 +61,9 @@ services: image: ghcr.io/arquisoft/wiq_es3b/webapp:latest profiles: ["dev", "prod"] build: ./webapp + volumes: + - ./webapp:/app + - webapp_data:/app depends_on: - gatewayservice ports: @@ -102,6 +105,7 @@ services: volumes: mongodb_data: + webapp_data: prometheus_data: grafana_data: diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..2951e9ab --- /dev/null +++ b/package-lock.json @@ -0,0 +1,989 @@ +{ + "name": "wiq_es3b", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "serve": "^14.2.1" + } + }, + "node_modules/@zeit/schemas": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.29.0.tgz", + "integrity": "sha512-g5QiLIfbg3pLuYUJPlisNKY+epQJTcMDsOnVNkscrDP1oi7vmJnzOANYJI/1pZcVJ6umUkBv3aFtlg1UvUHGzA==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/boxen": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", + "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.0", + "chalk": "^5.0.1", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, + "node_modules/chalk-template/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk-template/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", + "integrity": "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==", + "dev": true, + "dependencies": { + "arch": "^2.2.0", + "execa": "^5.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dev": true, + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-port-reachable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-4.0.0.tgz", + "integrity": "sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=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==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", + "dev": true + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/registry-auth-token": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "dev": true, + "dependencies": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==", + "dev": true, + "dependencies": { + "rc": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true + }, + "node_modules/serve": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.1.tgz", + "integrity": "sha512-48er5fzHh7GCShLnNyPBRPEjs2I6QBozeGr02gaacROiyS/8ARADlj595j39iZXAqBbJHH/ivJJyPRWY9sQWZA==", + "dev": true, + "dependencies": { + "@zeit/schemas": "2.29.0", + "ajv": "8.11.0", + "arg": "5.0.2", + "boxen": "7.0.0", + "chalk": "5.0.1", + "chalk-template": "0.4.0", + "clipboardy": "3.0.0", + "compression": "1.7.4", + "is-port-reachable": "4.0.0", + "serve-handler": "6.1.5", + "update-check": "1.5.4" + }, + "bin": { + "serve": "build/main.js" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/serve-handler": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "dev": true, + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-handler/node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-check": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz", + "integrity": "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==", + "dev": true, + "dependencies": { + "registry-auth-token": "3.3.2", + "registry-url": "3.1.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..89335214 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "serve": "^14.2.1" + } +} diff --git a/webapp/src/App.css b/webapp/src/App.css index 74b5e053..a571b3ae 100644 --- a/webapp/src/App.css +++ b/webapp/src/App.css @@ -1,38 +1,43 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; + } + + .logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; + } + .logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); + } + .logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); + } + + @keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } + + @media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } + } + + .card { + padding: 2em; + } + + .read-the-docs { + color: #888; + } + \ No newline at end of file diff --git a/webapp/src/App.jsx b/webapp/src/App.jsx new file mode 100644 index 00000000..6282c8e8 --- /dev/null +++ b/webapp/src/App.jsx @@ -0,0 +1,22 @@ +import { useState } from 'react' +import './App.css' + +import { Start } from './components/Start' +import { Game } from './components/Game' + +function App() { + const [menuState, setMenuState] = useState(0) + + const goTo = (parameter) => { + setMenuState(parameter) + } + + return ( + <> + {menuState === 0 && goTo(x)}/>} + {menuState === 1 && goTo(x)}/>} + + ) +} + +export default App diff --git a/webapp/src/assets/react.svg b/webapp/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/webapp/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/src/components/Game.jsx b/webapp/src/components/Game.jsx new file mode 100644 index 00000000..a49a99b6 --- /dev/null +++ b/webapp/src/components/Game.jsx @@ -0,0 +1,67 @@ +import { Card, List, ListItem, ListItemButton, ListItemText, Typography } from '@mui/material' +import reactLogo from '../assets/react.svg' + +const Question = () => { + return( + + + + + ¿Cuál es la capital de España? + + + + + + + Londres + + + + + + + Madrid + + + + + + + Paris + + + + + + + Roma + + + + + + + ) +} + +export const Game = ({ goTo }) => { + + return ( + + <> + + React logo + + + React Quiz + + + goTo(0) }> + + Volver al menú + + + + ) +} diff --git a/webapp/src/components/Login.js b/webapp/src/components/Login.js index 0ad6268e..3dae6761 100644 --- a/webapp/src/components/Login.js +++ b/webapp/src/components/Login.js @@ -47,7 +47,7 @@ const Login = () => { ) : (
- Login + Login :D { + + return ( + + <> +
+ + React logo + +
+

Vite + React

+
+ +
+ + ) +} \ No newline at end of file diff --git a/webapp/src/index.css b/webapp/src/index.css index ec2585e8..bbe405db 100644 --- a/webapp/src/index.css +++ b/webapp/src/index.css @@ -1,13 +1,74 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; +@import url('https://fonts.cdnfonts.com/css/roboto-slab-2'); + +:root { + font-family: 'Roboto Slab', Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; +* { + font-family: 'Roboto Slab', Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } } diff --git a/webapp/src/index.js b/webapp/src/index.js index d563c0fb..5911ca3e 100644 --- a/webapp/src/index.js +++ b/webapp/src/index.js @@ -4,10 +4,29 @@ import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; +import CssBaseline from '@mui/material/CssBaseline'; + +const darkTheme = createTheme({ + palette: { + mode: 'dark', + }, + typography: { + fontFamily: 'Arial, sans-serif', + h1: { + fontSize: '2.5rem', + fontWeight: 700, + } + } +}); + const root = ReactDOM.createRoot(document.getElementById('root')); root.render( - + + + + ); From 4f1fdbceb7ff14c219baeba40c7a12cd1ce090f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20Molt=C3=B3?= <144908056+UO287747@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:50:40 +0100 Subject: [PATCH 02/15] System Scope and Context Doc First version --- docs/src/03_system_scope_and_context.adoc | 103 +++++++++++++--------- 1 file changed, 59 insertions(+), 44 deletions(-) diff --git a/docs/src/03_system_scope_and_context.adoc b/docs/src/03_system_scope_and_context.adoc index c528e907..ec9a5198 100644 --- a/docs/src/03_system_scope_and_context.adoc +++ b/docs/src/03_system_scope_and_context.adoc @@ -1,75 +1,90 @@ ifndef::imagesdir[:imagesdir: ../images] [[section-system-scope-and-context]] -== System Scope and Context +# System Scope and Context [role="arc42help"] -**** -.Contents -System scope and context - as the name suggests - delimits your system (i.e. your scope) from all its communication partners -(neighboring systems and users, i.e. the context of your system). It thereby specifies the external interfaces. +--- -If necessary, differentiate the business context (domain specific inputs and outputs) from the technical context (channels, protocols, hardware). +## Contents +### Scope and context -.Motivation -The domain interfaces and technical interfaces to communication partners are among your system's most critical aspects. Make sure that you completely understand them. +This project aims to develop a quiz game. +The main constraints are developing the game as a web app and using Wikidata to obtain the questions and answers. -.Form -Various options: +--- -* Context diagrams -* Lists of communication partners and their interfaces. +## Business Context +[role="arc42help"] -.Further Information +### Contents -See https://docs.arc42.org/section-3/[Context and Scope] in the arc42 documentation. +* *Users:* They interact directly with the application through the user interface provided by the frontend using React, HTML, CSS, and JavaScript. +* *Wikidata API:* The application communicates with the Wikidata service to obtain questions and answers related to different topics. Requests are made using the HTTP protocol, and response data is received in JSON format. -**** +--- +### Motivation -=== Business Context +Regarding the information exchanged with the application, it will require having a registered account to play, and it will also exchange information with a MongoDB database and Wikidata itself to obtain the questions. -[role="arc42help"] -**** -.Contents -Specification of *all* communication partners (users, IT-systems, ...) with explanations of domain specific inputs and outputs or interfaces. -Optionally you can add domain specific formats or communication protocols. +--- -.Motivation -All stakeholders should understand which data are exchanged with the environment of the system. +### Form -.Form -All kinds of diagrams that show the system as a black box and specify the domain interfaces to communication partners. +|=== -Alternatively (or additionally) you can use a table. -The title of the table is the name of your system, the three columns contain the name of the communication partner, the inputs, and the outputs. +| *Quiz Game* | *Comunication Partners* | *Inputs* | *Outputs* +| Users | User Interface | User answers | Game questions +| Wikidata API | API Service | Question requests | JSON Responses -**** +|=== -**** +--- -**** +### Context diagram +[plantuml, "context", png] +---- +component "App" as app -=== Technical Context +:User: -> [app]: Answer question +[app] -> User: Return result -[role="arc42help"] -**** -.Contents -Technical interfaces (channels and transmission media) linking your system to its environment. In addition a mapping of domain specific input/output to the channels, i.e. an explanation which I/O uses which channel. +database DB +[app] -> DB: Ask for question +DB -> [app]: Return question + +component "WikiData" as wd +[app] --> wd: Ask for keyword +wd --> [app]: Return keyword +---- -.Motivation -Many stakeholders make architectural decision based on the technical interfaces between the system and its context. Especially infrastructure or hardware designers decide these technical interfaces. +--- + +## Technical Context + +[role="arc42help"] -.Form -E.g. UML deployment diagram describing channels to neighboring systems, -together with a mapping table showing the relationships between channels and input/output. +### Contents -**** +* *HTTP Channel:* The application uses the HTTP protocol to communicate with the Wikidata API service. +* *MongoDB Data Channel:* Interactions with the MongoDB database allow for storing and retrieving questions and answers. -**** +--- -**** +### Deployment diagram +[plantuml, "deployment", png] +---- +node "Aplication Server" as app +node "DB Server" as db { +artifact "MongoDB Server" +} +node Wikidata as w +node Interface as i -**** +app - db +app -- w +app -- i +---- From 8f3d61bbb3ceb287e9c709f66fc9cc869c5aa271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20Molt=C3=B3?= <144908056+UO287747@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:51:20 +0100 Subject: [PATCH 03/15] Solution Strategy Doc First version --- docs/src/04_solution_strategy.adoc | 91 +++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 19 deletions(-) diff --git a/docs/src/04_solution_strategy.adoc b/docs/src/04_solution_strategy.adoc index 7bf03f7a..97a4dd76 100644 --- a/docs/src/04_solution_strategy.adoc +++ b/docs/src/04_solution_strategy.adoc @@ -1,32 +1,85 @@ ifndef::imagesdir[:imagesdir: ../images] [[section-solution-strategy]] -== Solution Strategy - +# Solution Strategy [role="arc42help"] -**** -.Contents -A short summary and explanation of the fundamental decisions and solution strategies, that shape system architecture. It includes +## Contents +This page contains a short summary and explanation of the fundamental decisions and solution strategies, that shape system architecture. + +--- + +### Technology Decisions +Below, all the technologies to be used in the development of the application are listed: + +* *JavaScript / React:* A JavaScript library designed to facilitate the development of web applications. +* *JavaScript / NodeJS:* An asynchronous runtime environment based on JavaScript. +* *MongoDB:* A document-oriented NoSQL database system. +* *Docker:* Used for deploying applications locally. +* *Azure:* Used for deploying applications on a server. + +--- + +### Top-Level Decisions +In this section, a summarized list of all decisions regarding the architecture of the application is included. + +|=== + +| *Architectural Pattern* | In this project, the pattern based on the Microservices model is used. +| *Frontend (Client)* | React: Building the user interface +| *Backend (Server)* | NodeJS: Building the server on the backend +| | Mongoose: Interaction with the database +| *Database* | MongoDB: NoSQL database storing data in BSON format +| *Deployment* | Azure cloud services + +|=== + +--- + +### Quality Goals +Next, several quality goals are established, along with the decisions made to achieve them. + +|=== +| *Quality Goal* | *Decisions* + +| Usability +| Creation of a responsive interface adaptable to all types of screens. + +| Accessibility +| Compliance with accessibility standards to ensure a usable application. + +| Maintainability +| A structured project that facilitates the maintainability of the application. + +| Testing +| Assurance of a fully functional and error-free application. + +|=== + +--- + +### Relevant Organizational +Regarding the organization of the team, we have decided to use agile methodologies for better and faster group work. In this project, we will follow the best practices of the SCRUM framework. -* technology decisions -* decisions about the top-level decomposition of the system, e.g. usage of an architectural pattern or design pattern -* decisions on how to achieve key quality goals -* relevant organizational decisions, e.g. selecting a development process or delegating certain tasks to third parties. +Practices to be followed: -.Motivation -These decisions form the cornerstones for your architecture. They are the foundation for many other detailed decisions or implementation rules. +* Division of the project into *tasks*. +* Equitable *assignment* of tasks. +* Frequent *meetings* on the progress of the application. +* Construction of *"Alpha"* versions before the final release. -.Form -Keep the explanations of such key decisions short. +Additionally, "Issues" and the GitHub-provided Kanban (ToDo - In Progress - Done) are used for communication. -Motivate what was decided and why it was decided that way, -based upon problem statement, quality goals and key constraints. -Refer to details in the following sections. +--- +### Motivation +This section addresses the fundamental decisions for the project's architecture. -.Further Information +|=== -See https://docs.arc42.org/section-4/[Solution Strategy] in the arc42 documentation. +| *Data Management* | +| *Deployment* | +| *Security* | +| *Monitoring* | -**** +|=== From 6594d7a221c53c2d3214df643706fab13cde5d76 Mon Sep 17 00:00:00 2001 From: UO287747 Date: Sun, 18 Feb 2024 23:18:02 +0100 Subject: [PATCH 04/15] Docker volumes --- docker-compose.yml | 9 ++++----- webapp/Dockerfile | 6 ++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5cd37ef1..e9d31238 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -61,13 +61,13 @@ services: image: ghcr.io/arquisoft/wiq_es3b/webapp:latest profiles: ["dev", "prod"] build: ./webapp - volumes: - - ./webapp:/app - - webapp_data:/app depends_on: - gatewayservice ports: - - "3000:3000" + - "3000:3000" + #volumes: + #- ./webapp:/app + prometheus: image: prom/prometheus @@ -105,7 +105,6 @@ services: volumes: mongodb_data: - webapp_data: prometheus_data: grafana_data: diff --git a/webapp/Dockerfile b/webapp/Dockerfile index 3cbad8b7..6422ea29 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -3,9 +3,15 @@ FROM node:20 COPY . /app WORKDIR /app +# Copy package.json and package-lock.json to the working directory +#COPY package*.json ./ + #Install the dependencies RUN npm install +# Copy the app source code to the working directory +#COPY . . + ARG API_URI="http://localhost:8000" ENV REACT_APP_API_ENDPOINT=$API_URI From 995fa9273982c084323645200c986f52031b4ffa Mon Sep 17 00:00:00 2001 From: UO287747 Date: Mon, 19 Feb 2024 16:12:59 +0100 Subject: [PATCH 05/15] =?UTF-8?q?Test=20interfaz=20de=20la=20aplicaci?= =?UTF-8?q?=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapp/src/App.css | 55 +++++++++++++++------------------ webapp/src/{App.jsx => App.js} | 6 ++-- webapp/src/components/Game.jsx | 2 +- webapp/src/components/Login.js | 7 +++-- webapp/src/components/Start.jsx | 2 +- webapp/src/components/User.css | 43 ++++++++++++++++++++++++++ webapp/src/components/User.jsx | 39 +++++++++++++++++++++++ 7 files changed, 117 insertions(+), 37 deletions(-) rename webapp/src/{App.jsx => App.js} (60%) create mode 100644 webapp/src/components/User.css create mode 100644 webapp/src/components/User.jsx diff --git a/webapp/src/App.css b/webapp/src/App.css index a571b3ae..e04c0cee 100644 --- a/webapp/src/App.css +++ b/webapp/src/App.css @@ -1,43 +1,38 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; +.App { text-align: center; } - .logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; + .App-logo { + height: 40vmin; + pointer-events: none; } - .logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); + + @media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } + } + + .App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; } - .logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); + + .App-link { + color: #61dafb; } - @keyframes logo-spin { + @keyframes App-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } - } - - @media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } - } - - .card { - padding: 2em; - } - - .read-the-docs { - color: #888; - } - \ No newline at end of file + } \ No newline at end of file diff --git a/webapp/src/App.jsx b/webapp/src/App.js similarity index 60% rename from webapp/src/App.jsx rename to webapp/src/App.js index 6282c8e8..12ebea99 100644 --- a/webapp/src/App.jsx +++ b/webapp/src/App.js @@ -3,6 +3,7 @@ import './App.css' import { Start } from './components/Start' import { Game } from './components/Game' +import User from './components/User' function App() { const [menuState, setMenuState] = useState(0) @@ -13,8 +14,9 @@ function App() { return ( <> - {menuState === 0 && goTo(x)}/>} - {menuState === 1 && goTo(x)}/>} + {menuState === 0 && goTo(x)}/>} + {menuState === 1 && goTo(x)}/>} + {menuState === 2 && goTo(x)}/>} ) } diff --git a/webapp/src/components/Game.jsx b/webapp/src/components/Game.jsx index a49a99b6..4cc1bd7a 100644 --- a/webapp/src/components/Game.jsx +++ b/webapp/src/components/Game.jsx @@ -57,7 +57,7 @@ export const Game = ({ goTo }) => { React Quiz - goTo(0) }> + goTo(1) }> Volver al menú diff --git a/webapp/src/components/Login.js b/webapp/src/components/Login.js index 3dae6761..4de58a10 100644 --- a/webapp/src/components/Login.js +++ b/webapp/src/components/Login.js @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import axios from 'axios'; import { Container, Typography, TextField, Button, Snackbar } from '@mui/material'; -const Login = () => { +const Login = ({ goTo }) => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); @@ -22,7 +22,7 @@ const Login = () => { setCreatedAt(userCreatedAt); setLoginSuccess(true); - + setOpenSnackbar(true); } catch (error) { setError(error.response.data.error); @@ -32,10 +32,11 @@ const Login = () => { const handleCloseSnackbar = () => { setOpenSnackbar(false); }; - + goTo(1); return ( {loginSuccess ? ( +
Hello {username}! diff --git a/webapp/src/components/Start.jsx b/webapp/src/components/Start.jsx index 1e047a44..a762ebc0 100644 --- a/webapp/src/components/Start.jsx +++ b/webapp/src/components/Start.jsx @@ -12,7 +12,7 @@ export const Start = ({ goTo }) => {

Vite + React

-
diff --git a/webapp/src/components/User.css b/webapp/src/components/User.css new file mode 100644 index 00000000..a571b3ae --- /dev/null +++ b/webapp/src/components/User.css @@ -0,0 +1,43 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; + } + + .logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; + } + .logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); + } + .logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); + } + + @keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } + + @media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } + } + + .card { + padding: 2em; + } + + .read-the-docs { + color: #888; + } + \ No newline at end of file diff --git a/webapp/src/components/User.jsx b/webapp/src/components/User.jsx new file mode 100644 index 00000000..45e2115d --- /dev/null +++ b/webapp/src/components/User.jsx @@ -0,0 +1,39 @@ + +import React, { useState } from 'react'; +import AddUser from './AddUser'; +import Login from './Login'; +import CssBaseline from '@mui/material/CssBaseline'; +import Container from '@mui/material/Container'; +import Typography from '@mui/material/Typography'; +import Link from '@mui/material/Link'; + +function User({ goTo }) { + const [showLogin, setShowLogin] = useState(true); + + const handleToggleView = () => { + setShowLogin(!showLogin); + }; + + return ( + + + + Welcome to the 2024 edition of the Software Architecture course + + {showLogin ? goTo(x)} /> : } + + {showLogin ? ( + + Don't have an account? Register here. + + ) : ( + + Already have an account? Login here. + + )} + + + ); +} + +export default User; \ No newline at end of file From b8b881fa824c85c026734e2eb003e964cb795e13 Mon Sep 17 00:00:00 2001 From: UO287747 Date: Mon, 19 Feb 2024 18:06:23 +0100 Subject: [PATCH 06/15] =?UTF-8?q?Primera=20versi=C3=B3n=20men=C3=BA=20inte?= =?UTF-8?q?ractivo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapp/src/App.css | 38 ------------------- webapp/src/App.js | 2 +- webapp/src/components/Login.js | 4 +- webapp/src/components/Sesion.css | 38 ------------------- webapp/src/components/Sesion.js | 38 ------------------- webapp/src/components/Start.jsx | 3 +- webapp/src/components/User.jsx | 1 - webapp/src/css/Start.css | 3 ++ webapp/src/{components => css}/User.css | 0 webapp/src/{ => css}/index.css | 2 +- webapp/src/index.js | 2 +- webapp/src/logo.svg | 1 - .../src/{components => test}/AddUser.test.js | 2 +- webapp/src/{components => test}/Login.test.js | 2 +- 14 files changed, 13 insertions(+), 123 deletions(-) delete mode 100644 webapp/src/App.css delete mode 100644 webapp/src/components/Sesion.css delete mode 100644 webapp/src/components/Sesion.js create mode 100644 webapp/src/css/Start.css rename webapp/src/{components => css}/User.css (100%) rename webapp/src/{ => css}/index.css (93%) delete mode 100644 webapp/src/logo.svg rename webapp/src/{components => test}/AddUser.test.js (97%) rename webapp/src/{components => test}/Login.test.js (98%) diff --git a/webapp/src/App.css b/webapp/src/App.css deleted file mode 100644 index e04c0cee..00000000 --- a/webapp/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; - } - - .App-logo { - height: 40vmin; - pointer-events: none; - } - - @media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } - } - - .App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; - } - - .App-link { - color: #61dafb; - } - - @keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } - } \ No newline at end of file diff --git a/webapp/src/App.js b/webapp/src/App.js index 12ebea99..1cb45c01 100644 --- a/webapp/src/App.js +++ b/webapp/src/App.js @@ -1,5 +1,5 @@ import { useState } from 'react' -import './App.css' + import { Start } from './components/Start' import { Game } from './components/Game' diff --git a/webapp/src/components/Login.js b/webapp/src/components/Login.js index 4de58a10..5810344a 100644 --- a/webapp/src/components/Login.js +++ b/webapp/src/components/Login.js @@ -32,7 +32,9 @@ const Login = ({ goTo }) => { const handleCloseSnackbar = () => { setOpenSnackbar(false); }; - goTo(1); + + if (loginSuccess) { goTo(1); } + return ( {loginSuccess ? ( diff --git a/webapp/src/components/Sesion.css b/webapp/src/components/Sesion.css deleted file mode 100644 index 74b5e053..00000000 --- a/webapp/src/components/Sesion.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/webapp/src/components/Sesion.js b/webapp/src/components/Sesion.js deleted file mode 100644 index 98ad1a61..00000000 --- a/webapp/src/components/Sesion.js +++ /dev/null @@ -1,38 +0,0 @@ -import React, { useState } from 'react'; -import AddUser from './AddUser'; -import Login from './Login'; -import CssBaseline from '@mui/material/CssBaseline'; -import Container from '@mui/material/Container'; -import Typography from '@mui/material/Typography'; -import Link from '@mui/material/Link'; - -function App() { - const [showLogin, setShowLogin] = useState(true); - - const handleToggleView = () => { - setShowLogin(!showLogin); - }; - - return ( - - - - Welcome to the 2024 edition of the Software Architecture course - - {showLogin ? : } - - {showLogin ? ( - - Don't have an account? Register here. - - ) : ( - - Already have an account? Login here. - - )} - - - ); -} - -export default App; diff --git a/webapp/src/components/Start.jsx b/webapp/src/components/Start.jsx index a762ebc0..a597b763 100644 --- a/webapp/src/components/Start.jsx +++ b/webapp/src/components/Start.jsx @@ -1,4 +1,5 @@ import reactLogo from '../assets/react.svg' +import "../css/Start.css" export const Start = ({ goTo }) => { @@ -10,7 +11,7 @@ export const Start = ({ goTo }) => { React logo
-

Vite + React

+

Quiz ASW

+
+ ); + }; diff --git a/webapp/src/test/Participation.test.js b/webapp/src/test/Participation.test.js new file mode 100644 index 00000000..97cb6954 --- /dev/null +++ b/webapp/src/test/Participation.test.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { Participation } from '../components/Participation'; + +describe('Participation component', () => { + test('renders correctly', () => { + render( {}} />); + + // Verificar que el texto "Participation" se muestra correctamente + const titleText = screen.getByText(/Participation/i); + expect(titleText).toBeInTheDocument(); + + // Verificar que el botón "Menu" se muestra correctamente + const menuButton = screen.getByRole('button', { name: /Menu/i }); + expect(menuButton).toBeInTheDocument(); + }); + + test('clicking "Menu" button calls goTo function with correct argument', () => { + const goToMock = jest.fn(); + render(); + + // Simular clic en el botón "Menu" + fireEvent.click(screen.getByText('Menu')); + + // Verificar que la función goTo se llamó con el argumento correcto (en este caso, 0) + expect(goToMock).toHaveBeenCalledWith(0); + }); +}); From 1b7c693a953ff7fdd98ad6ca44c179832d4fca44 Mon Sep 17 00:00:00 2001 From: Alfonso Date: Thu, 22 Feb 2024 13:18:32 +0100 Subject: [PATCH 14/15] Added first version of question model --- questionsservice/question-model.js | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 questionsservice/question-model.js diff --git a/questionsservice/question-model.js b/questionsservice/question-model.js new file mode 100644 index 00000000..89bf65ed --- /dev/null +++ b/questionsservice/question-model.js @@ -0,0 +1,32 @@ +const mongoose = require('mongoose'); + +const questionSchema = new mongoose.Schema({ + question: { + type: String, + required: true, + }, + options: { + type: [String], + required: true, + validate: { + validator: function (options) { + return options.length >= 2 && options.length <= 4; + }, + message: 'Options must have between 2 and 4 elements.', + }, + }, + correctOptionIndex: { + type: Number, + required: true, + validate: { + validator: function (index) { + return index >= 0 && index < 4; // Max of 4 options + }, + message: 'Correct option index must be between 0 and 3.', + }, + }, +}); + +const Question = mongoose.model('Question', questionSchema); + +module.exports = Question; From b21f986a4313d65836e565518cf2a746c5fe351c Mon Sep 17 00:00:00 2001 From: Alfonso Date: Thu, 22 Feb 2024 15:42:23 +0100 Subject: [PATCH 15/15] Added first version of question service --- README.md | 2 +- docker-compose.yml | 14 ++++++ gatewayservice/gateway-service.js | 12 ++++++ questionservice/.dockerignore | 2 + questionservice/Dockerfile | 20 +++++++++ questionservice/package.json | 20 +++++++++ .../question-model.js | 0 questionservice/question-service.js | 43 +++++++++++++++++++ 8 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 questionservice/.dockerignore create mode 100644 questionservice/Dockerfile create mode 100644 questionservice/package.json rename {questionsservice => questionservice}/question-model.js (100%) create mode 100644 questionservice/question-service.js diff --git a/README.md b/README.md index 1b3ae97b..0cde912d 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ The deploy action is the following: deploy: name: Deploy over SSH runs-on: ubuntu-latest - needs: [docker-push-userservice,docker-push-authservice,docker-push-gatewayservice,docker-push-webapp] + needs: [docker-push-userservice,docker-push-authservice,docker-push-gatewayservice,docker-push-webapp,docker-push-questionservice] steps: - name: Deploy over SSH uses: fifsky/ssh-action@master diff --git a/docker-compose.yml b/docker-compose.yml index e9d31238..d718e6c3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,6 +39,20 @@ services: environment: MONGODB_URI: mongodb://mongodb:27017/userdb + questionservice: + container_name: questionservice-${teamname:-defaultASW} + image: ghcr.io/arquisoft/wiq_es3b/questionservice:latest + profiles: ["dev", "prod"] + build: ./questionservice + depends_on: + - mongodb + ports: + - "8003:8003" + networks: + - mynetwork + environment: + MONGODB_URI: mongodb://mongodb:27017/questionsdb + gatewayservice: container_name: gatewayservice-${teamname:-defaultASW} image: ghcr.io/arquisoft/wiq_es3b/gatewayservice:latest diff --git a/gatewayservice/gateway-service.js b/gatewayservice/gateway-service.js index 88b84c8f..b60f271e 100644 --- a/gatewayservice/gateway-service.js +++ b/gatewayservice/gateway-service.js @@ -8,6 +8,7 @@ const port = 8000; const authServiceUrl = process.env.AUTH_SERVICE_URL || 'http://localhost:8002'; const userServiceUrl = process.env.USER_SERVICE_URL || 'http://localhost:8001'; +const questionServiceUrl = process.env.QUESTIONS_SERVICE_URL || 'http://localhost:8003'; // URL preguntas app.use(cors()); app.use(express.json()); @@ -41,6 +42,17 @@ app.post('/adduser', async (req, res) => { } }); +// Ruta para agregar una nueva pregunta +app.post('/addquestion', async (req, res) => { + try { + // Forward the add question request to the questions service + const questionResponse = await axios.post(questionServiceUrl + '/addquestion', req.body); + res.json(questionResponse.data); + } catch (error) { + res.status(error.response.status).json({ error: error.response.data.error }); + } +}); + // Start the gateway service const server = app.listen(port, () => { console.log(`Gateway Service listening at http://localhost:${port}`); diff --git a/questionservice/.dockerignore b/questionservice/.dockerignore new file mode 100644 index 00000000..3091757a --- /dev/null +++ b/questionservice/.dockerignore @@ -0,0 +1,2 @@ +node_modules +coverage \ No newline at end of file diff --git a/questionservice/Dockerfile b/questionservice/Dockerfile new file mode 100644 index 00000000..ae8f3e41 --- /dev/null +++ b/questionservice/Dockerfile @@ -0,0 +1,20 @@ +# Use an official Node.js runtime as a parent image +FROM node:20 + +# Set the working directory in the container +WORKDIR /usr/src/questionservice + +# Copy package.json and package-lock.json to the working directory +COPY package*.json ./ + +# Install app dependencies +RUN npm install + +# Copy the app source code to the working directory +COPY . . + +# Expose the port the app runs on +EXPOSE 8003 + +# Define the command to run your app +CMD ["node", "question-service.js"] diff --git a/questionservice/package.json b/questionservice/package.json new file mode 100644 index 00000000..82096e9c --- /dev/null +++ b/questionservice/package.json @@ -0,0 +1,20 @@ +{ + "name": "questionservice", + "version": "1.0.0", + "description": "Question service, in charge of adding the questions to the application", + "main": "service.js", + "scripts": { + "start": "node question-service.js", + "test": "jest" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/arquisoft/wiq_es3b.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/arquisoft/wiq_es3b/issues" + }, + "homepage": "https://github.com/arquisoft/wiq_es3b#readme" +} diff --git a/questionsservice/question-model.js b/questionservice/question-model.js similarity index 100% rename from questionsservice/question-model.js rename to questionservice/question-model.js diff --git a/questionservice/question-service.js b/questionservice/question-service.js new file mode 100644 index 00000000..4f29384d --- /dev/null +++ b/questionservice/question-service.js @@ -0,0 +1,43 @@ +const express = require('express'); +const mongoose = require('mongoose'); +const Question = require('./question-model'); // Importa el modelo de preguntas + +const app = express(); +const port = 8003; // Puerto para el servicio de preguntas + +app.use(express.json()); + +// Ruta para agregar una nueva pregunta +app.post('/addquestion', async (req, res) => { + try { + validateRequiredFields(req, ['question', 'options', 'correctOptionIndex']); + + const { question, options, correctOptionIndex } = req.body; + + // Crea una nueva instancia del modelo de preguntas + const newQuestion = new Question({ + question, + options, + correctOptionIndex, + }); + + // Guarda la nueva pregunta en la base de datos + const savedQuestion = await newQuestion.save(); + + res.status(201).json(savedQuestion); + } catch (error) { + res.status(500).json({ error: 'Internal Server Error' }); + } +}); + +// logica para preguntas?? + +// Conecta a la base de datos de preguntas +const mongoUri = process.env.MONGODB_QUESTIONS_URI || 'mongodb://localhost:27017/questionsdb'; +mongoose.connect(mongoUri); + +const server = app.listen(port, () => { + console.log(`Questions Service listening at http://localhost:${port}`); +}); + +module.exports = server; \ No newline at end of file