From 1e4c673c1cc611d8fbdb76e2eedf006f9ae0ad56 Mon Sep 17 00:00:00 2001 From: Aye <117931758+ayetza@users.noreply.github.com> Date: Tue, 14 Apr 2026 17:38:46 -0600 Subject: [PATCH 01/23] frontend sprint 2 --- .../src/main/frontend/package-lock.json | 514 +++++++++++- .../backend/src/main/frontend/package.json | 1 + .../backend/src/main/frontend/src/App.js | 442 +++++----- .../src/main/frontend/src/Dashboard.js | 269 ++++++ .../backend/src/main/frontend/src/NewItem.js | 60 +- .../backend/src/main/frontend/src/index.css | 794 +++++++++++++++--- 6 files changed, 1690 insertions(+), 390 deletions(-) create mode 100644 MtdrSpring/backend/src/main/frontend/src/Dashboard.js diff --git a/MtdrSpring/backend/src/main/frontend/package-lock.json b/MtdrSpring/backend/src/main/frontend/package-lock.json index 382891ec0..8ff1f4283 100644 --- a/MtdrSpring/backend/src/main/frontend/package-lock.json +++ b/MtdrSpring/backend/src/main/frontend/package-lock.json @@ -18,6 +18,7 @@ "react-dom": "^17.0.2", "react-moment": "^1.1.2", "react-scripts": "5.0.0", + "recharts": "^2.1.16", "typescript": "^4.6.4" } }, @@ -4087,6 +4088,51 @@ "@types/node": "*" } }, + "node_modules/@types/d3-color": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-2.0.6.tgz", + "integrity": "sha512-tbaFGDmJWHqnenvk3QGSvD3RVwr631BjKRD7Sc7VLRgrdX5mk5hTyoeBL6rXZaeoXzmZwIl1D2HPogEdt1rHBg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-2.0.5.tgz", + "integrity": "sha512-UINE41RDaUMbulp+bxQMDnhOi51rh5lA2dG+dWZU0UY/IwQiG/u2x8TfnWYU9+xwGdXsJoAvrBYUEQl0r91atg==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "^2" + } + }, + "node_modules/@types/d3-path": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-2.0.4.tgz", + "integrity": "sha512-jjZVLBjEX4q6xneKMmv62UocaFJFOTQSb/1aTzs3m3ICTOFoVaqGBHpNLm/4dVi0/FTltfBKgmOK1ECj3/gGjA==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.5.tgz", + "integrity": "sha512-YOpKj0kIEusRf7ofeJcSZQsvKbnTwpe1DUF+P2qsotqG53kEsjm7EzzliqQxMkAWdkZcHrg5rRhB4JiDOQPX+A==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "^2" + } + }, + "node_modules/@types/d3-shape": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-2.1.7.tgz", + "integrity": "sha512-HedHlfGHdwzKqX9+PiQVXZrdmGlwo7naoefJP7kCNk4Y7qcpQt1tUaoRa6qn0kbTdlaIHGO7111qLtb/6J8uuw==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "^2" + } + }, + "node_modules/@types/d3-time": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.4.tgz", + "integrity": "sha512-BTfLsxTeo7yFxI/haOOf1ZwJ6xKgQLT9dCp+EcmQv87Gox6X+oKl4mLKfO6fnWm3P22+A6DknMNEZany8ql2Rw==", + "license": "MIT" + }, "node_modules/@types/eslint": { "version": "8.40.2", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.2.tgz", @@ -5803,6 +5849,12 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/clean-css": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", @@ -6319,6 +6371,12 @@ "node": ">=0.10.0" } }, + "node_modules/css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==", + "license": "MIT" + }, "node_modules/css-vendor": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", @@ -6496,9 +6554,86 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" }, "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", + "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", + "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-interpolate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", + "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-color": "1 - 2" + } + }, + "node_modules/d3-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", + "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-scale": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz", + "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^2.3.0", + "d3-format": "1 - 2", + "d3-interpolate": "1.2.0 - 2", + "d3-time": "^2.1.1", + "d3-time-format": "2 - 3" + } + }, + "node_modules/d3-shape": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz", + "integrity": "sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1 - 2" + } + }, + "node_modules/d3-time": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", + "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "2" + } + }, + "node_modules/d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-time": "1 - 2" + } }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -6539,6 +6674,12 @@ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -7906,6 +8047,15 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -9112,6 +9262,12 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, "node_modules/ipaddr.js": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", @@ -14396,6 +14552,12 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "license": "MIT" + }, "node_modules/react-moment": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/react-moment/-/react-moment-1.1.3.tgz", @@ -14414,6 +14576,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-resize-detector": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz", + "integrity": "sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-scripts": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.0.tgz", @@ -14486,6 +14661,46 @@ } } }, + "node_modules/react-smooth": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.5.tgz", + "integrity": "sha512-BMP2Ad42tD60h0JW6BFaib+RJuV5dsXJK9Baxiv/HlNFjvRLqA9xrNKxVWnUIZPQfzUwGXIlU/dSYLU+54YGQA==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.0", + "react-transition-group": "2.9.0" + }, + "peerDependencies": { + "prop-types": "^15.6.0", + "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-smooth/node_modules/dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, + "node_modules/react-smooth/node_modules/react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "license": "BSD-3-Clause", + "dependencies": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0", + "react-dom": ">=15.0.0" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -14533,6 +14748,51 @@ "node": ">=8.10.0" } }, + "node_modules/recharts": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.1.16.tgz", + "integrity": "sha512-aYn1plTjYzRCo3UGxtWsduslwYd+Cuww3h/YAAEoRdGe0LRnBgYgaXSlVrNFkWOOSXrBavpmnli9h7pvRuk5wg==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "^2.0.0", + "@types/d3-scale": "^3.0.0", + "@types/d3-shape": "^2.0.0", + "classnames": "^2.2.5", + "d3-interpolate": "^2.0.0", + "d3-scale": "^3.0.0", + "d3-shape": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.19", + "react-is": "^16.10.2", + "react-resize-detector": "^7.1.2", + "react-smooth": "^2.0.1", + "recharts-scale": "^0.4.4", + "reduce-css-calc": "^2.1.8" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "prop-types": "^15.6.0", + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/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==", + "license": "MIT" + }, "node_modules/recursive-readdir": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", @@ -14544,6 +14804,22 @@ "node": ">=6.0.0" } }, + "node_modules/reduce-css-calc": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", + "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", + "license": "MIT", + "dependencies": { + "css-unit-converter": "^1.1.1", + "postcss-value-parser": "^3.3.0" + } + }, + "node_modules/reduce-css-calc/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "license": "MIT" + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -20029,6 +20305,45 @@ "@types/node": "*" } }, + "@types/d3-color": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-2.0.6.tgz", + "integrity": "sha512-tbaFGDmJWHqnenvk3QGSvD3RVwr631BjKRD7Sc7VLRgrdX5mk5hTyoeBL6rXZaeoXzmZwIl1D2HPogEdt1rHBg==" + }, + "@types/d3-interpolate": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-2.0.5.tgz", + "integrity": "sha512-UINE41RDaUMbulp+bxQMDnhOi51rh5lA2dG+dWZU0UY/IwQiG/u2x8TfnWYU9+xwGdXsJoAvrBYUEQl0r91atg==", + "requires": { + "@types/d3-color": "^2" + } + }, + "@types/d3-path": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-2.0.4.tgz", + "integrity": "sha512-jjZVLBjEX4q6xneKMmv62UocaFJFOTQSb/1aTzs3m3ICTOFoVaqGBHpNLm/4dVi0/FTltfBKgmOK1ECj3/gGjA==" + }, + "@types/d3-scale": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.5.tgz", + "integrity": "sha512-YOpKj0kIEusRf7ofeJcSZQsvKbnTwpe1DUF+P2qsotqG53kEsjm7EzzliqQxMkAWdkZcHrg5rRhB4JiDOQPX+A==", + "requires": { + "@types/d3-time": "^2" + } + }, + "@types/d3-shape": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-2.1.7.tgz", + "integrity": "sha512-HedHlfGHdwzKqX9+PiQVXZrdmGlwo7naoefJP7kCNk4Y7qcpQt1tUaoRa6qn0kbTdlaIHGO7111qLtb/6J8uuw==", + "requires": { + "@types/d3-path": "^2" + } + }, + "@types/d3-time": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.4.tgz", + "integrity": "sha512-BTfLsxTeo7yFxI/haOOf1ZwJ6xKgQLT9dCp+EcmQv87Gox6X+oKl4mLKfO6fnWm3P22+A6DknMNEZany8ql2Rw==" + }, "@types/eslint": { "version": "8.40.2", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.2.tgz", @@ -21335,6 +21650,11 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" }, + "classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "clean-css": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", @@ -21702,6 +22022,11 @@ } } }, + "css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" + }, "css-vendor": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", @@ -21828,9 +22153,76 @@ } }, "csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" + }, + "d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "requires": { + "internmap": "^1.0.0" + } + }, + "d3-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", + "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" + }, + "d3-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", + "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" + }, + "d3-interpolate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", + "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", + "requires": { + "d3-color": "1 - 2" + } + }, + "d3-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", + "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" + }, + "d3-scale": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz", + "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", + "requires": { + "d3-array": "^2.3.0", + "d3-format": "1 - 2", + "d3-interpolate": "1.2.0 - 2", + "d3-time": "^2.1.1", + "d3-time-format": "2 - 3" + } + }, + "d3-shape": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.1.0.tgz", + "integrity": "sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==", + "requires": { + "d3-path": "1 - 2" + } + }, + "d3-time": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", + "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", + "requires": { + "d3-array": "2" + } + }, + "d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "requires": { + "d3-time": "1 - 2" + } }, "damerau-levenshtein": { "version": "1.0.8", @@ -21860,6 +22252,11 @@ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, + "decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -22872,6 +23269,11 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==" + }, "fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -23736,6 +24138,11 @@ "side-channel": "^1.0.4" } }, + "internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + }, "ipaddr.js": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", @@ -27396,6 +27803,11 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, "react-moment": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/react-moment/-/react-moment-1.1.3.tgz", @@ -27407,6 +27819,14 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" }, + "react-resize-detector": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz", + "integrity": "sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw==", + "requires": { + "lodash": "^4.17.21" + } + }, "react-scripts": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.0.tgz", @@ -27462,6 +27882,36 @@ "workbox-webpack-plugin": "^6.4.1" } }, + "react-smooth": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.5.tgz", + "integrity": "sha512-BMP2Ad42tD60h0JW6BFaib+RJuV5dsXJK9Baxiv/HlNFjvRLqA9xrNKxVWnUIZPQfzUwGXIlU/dSYLU+54YGQA==", + "requires": { + "fast-equals": "^5.0.0", + "react-transition-group": "2.9.0" + }, + "dependencies": { + "dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, + "react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "requires": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + } + } + }, "react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -27499,6 +27949,42 @@ "picomatch": "^2.2.1" } }, + "recharts": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.1.16.tgz", + "integrity": "sha512-aYn1plTjYzRCo3UGxtWsduslwYd+Cuww3h/YAAEoRdGe0LRnBgYgaXSlVrNFkWOOSXrBavpmnli9h7pvRuk5wg==", + "requires": { + "@types/d3-interpolate": "^2.0.0", + "@types/d3-scale": "^3.0.0", + "@types/d3-shape": "^2.0.0", + "classnames": "^2.2.5", + "d3-interpolate": "^2.0.0", + "d3-scale": "^3.0.0", + "d3-shape": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.19", + "react-is": "^16.10.2", + "react-resize-detector": "^7.1.2", + "react-smooth": "^2.0.1", + "recharts-scale": "^0.4.4", + "reduce-css-calc": "^2.1.8" + }, + "dependencies": { + "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==" + } + } + }, + "recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "requires": { + "decimal.js-light": "^2.4.1" + } + }, "recursive-readdir": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", @@ -27507,6 +27993,22 @@ "minimatch": "^3.0.5" } }, + "reduce-css-calc": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", + "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", + "requires": { + "css-unit-converter": "^1.1.1", + "postcss-value-parser": "^3.3.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", diff --git a/MtdrSpring/backend/src/main/frontend/package.json b/MtdrSpring/backend/src/main/frontend/package.json index f92323cbe..1ec5bfd76 100644 --- a/MtdrSpring/backend/src/main/frontend/package.json +++ b/MtdrSpring/backend/src/main/frontend/package.json @@ -13,6 +13,7 @@ "react-dom": "^17.0.2", "react-moment": "^1.1.2", "react-scripts": "5.0.0", + "recharts": "^2.1.16", "typescript": "^4.6.4" }, "scripts": { diff --git a/MtdrSpring/backend/src/main/frontend/src/App.js b/MtdrSpring/backend/src/main/frontend/src/App.js index 21462dd91..6bcc9f457 100644 --- a/MtdrSpring/backend/src/main/frontend/src/App.js +++ b/MtdrSpring/backend/src/main/frontend/src/App.js @@ -1,240 +1,250 @@ - /* -## MyToDoReact version 1.0. -## -## Copyright (c) 2022 Oracle, Inc. -## Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ -*/ -/* - * This is the application main React component. We're using "function" - * components in this application. No "class" components should be used for - * consistency. - * @author jean.de.lavarene@oracle.com - */ import React, { useState, useEffect } from 'react'; import NewItem from './NewItem'; +import Dashboard from './Dashboard'; import API_LIST from './API'; import DeleteIcon from '@mui/icons-material/Delete'; -import { Button, TableBody, CircularProgress } from '@mui/material'; +import TaskAltIcon from '@mui/icons-material/TaskAlt'; +import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted'; +import BarChartIcon from '@mui/icons-material/BarChart'; +import { CircularProgress } from '@mui/material'; import Moment from 'react-moment'; -/* In this application we're using Function Components with the State Hooks - * to manage the states. See the doc: https://reactjs.org/docs/hooks-state.html - * This App component represents the entire app. It renders a NewItem component - * and two tables: one that lists the todo items that are to be done and another - * one with the items that are already done. - */ +const CARD_COLORS = ['#7C3AED', '#F59E0B', '#14B8A6', '#EC4899', '#3B82F6', '#EF4444']; + function App() { - // isLoading is true while waiting for the backend to return the list - // of items. We use this state to display a spinning circle: - const [isLoading, setLoading] = useState(false); - // Similar to isLoading, isInserting is true while waiting for the backend - // to insert a new item: - const [isInserting, setInserting] = useState(false); - // The list of todo items is stored in this state. It includes the "done" - // "not-done" items: - const [items, setItems] = useState([]); - // In case of an error during the API call: - const [error, setError] = useState(); - - function deleteItem(deleteId) { - // console.log("deleteItem("+deleteId+")") - fetch(API_LIST+"/"+deleteId, { - method: 'DELETE', + const [activeTab, setActiveTab] = useState('tasks'); + const [isLoading] = useState(false); + const [isInserting, setInserting] = useState(false); + const [items, setItems] = useState([]); + const [, setError] = useState(); + + function deleteItem(deleteId) { + fetch(API_LIST + "/" + deleteId, { method: 'DELETE' }) + .then(response => { + if (response.ok) return response; + throw new Error('Something went wrong ...'); }) + .then( + () => { setItems(prev => prev.filter(item => item.id !== deleteId)); }, + (err) => { setError(err); } + ); + } + + function toggleDone(event, id, description, done) { + event.preventDefault(); + modifyItem(id, description, done).then( + () => { reloadOneItem(id); }, + (err) => { setError(err); } + ); + } + + function reloadOneItem(id) { + fetch(API_LIST + "/" + id) .then(response => { - // console.log("response="); - // console.log(response); - if (response.ok) { - // console.log("deleteItem FETCH call is ok"); - return response; - } else { - throw new Error('Something went wrong ...'); - } + if (response.ok) return response.json(); + throw new Error('Something went wrong ...'); }) .then( (result) => { - const remainingItems = items.filter(item => item.id !== deleteId); - setItems(remainingItems); + setItems(prev => prev.map(x => + x.id === id ? { ...x, description: result.description, done: result.done } : x + )); }, - (error) => { - setError(error); - } + (err) => { setError(err); } ); - } - function toggleDone(event, id, description, done) { - event.preventDefault(); - modifyItem(id, description, done).then( - (result) => { reloadOneIteam(id); }, - (error) => { setError(error); } - ); - } - function reloadOneIteam(id){ - fetch(API_LIST+"/"+id) - .then(response => { - if (response.ok) { - return response.json(); - } else { - throw new Error('Something went wrong ...'); - } - }) - .then( - (result) => { - const items2 = items.map( - x => (x.id === id ? { - ...x, - 'description':result.description, - 'done': result.done - } : x)); - setItems(items2); - }, - (error) => { - setError(error); - }); - } - function modifyItem(id, description, done) { - // console.log("deleteItem("+deleteId+")") - var data = {"description": description, "done": done}; - return fetch(API_LIST+"/"+id, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(data) - }) + } + + function modifyItem(id, description, done) { + return fetch(API_LIST + "/" + id, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ description, done }), + }).then(response => { + if (response.ok) return response; + throw new Error('Something went wrong ...'); + }); + } + + useEffect(() => { + setItems([ + { id: 1, description: 'Design new dashboard layout', createdAt: '2026-04-14T09:00:00', done: false }, + { id: 2, description: 'Fix login bug on mobile', createdAt: '2026-04-14T10:30:00', done: false }, + { id: 3, description: 'Write unit tests for API', createdAt: '2026-04-13T15:00:00', done: false }, + { id: 4, description: 'Deploy to staging environment', createdAt: '2026-04-13T11:00:00', done: true }, + { id: 5, description: 'Review pull request #42', createdAt: '2026-04-12T08:00:00', done: true }, + ]); + }, []); + + function addItem(text) { + setInserting(true); + fetch(API_LIST, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ description: text }), + }) .then(response => { - // console.log("response="); - // console.log(response); - if (response.ok) { - // console.log("deleteItem FETCH call is ok"); - return response; - } else { - throw new Error('Something went wrong ...'); - } - }); - } - /* - To simulate slow network, call sleep before making API calls. - const sleep = (milliseconds) => { - return new Promise(resolve => setTimeout(resolve, milliseconds)) - } - */ - useEffect(() => { - setLoading(true); - // sleep(5000).then(() => { - fetch(API_LIST) - .then(response => { - if (response.ok) { - return response.json(); - } else { - throw new Error('Something went wrong ...'); - } - }) - .then( - (result) => { - setLoading(false); - setItems(result); - }, - (error) => { - setLoading(false); - setError(error); - }); - - //}) - }, - // https://en.reactjs.org/docs/faq-ajax.html - [] // empty deps array [] means - // this useEffect will run once - // similar to componentDidMount() - ); - function addItem(text){ - console.log("addItem("+text+")") - setInserting(true); - var data = {}; - console.log(data); - data.description = text; - fetch(API_LIST, { - method: 'POST', - // We convert the React state to JSON and send it as the POST body - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(data), - }).then((response) => { - // This API doens't return a JSON document - console.log(response); - console.log(); - console.log(response.headers.location); - // return response.json(); - if (response.ok) { - return response; - } else { - throw new Error('Something went wrong ...'); - } - }).then( + if (response.ok) return response; + throw new Error('Something went wrong ...'); + }) + .then( (result) => { - var id = result.headers.get('location'); - var newItem = {"id": id, "description": text} - setItems([newItem, ...items]); + const id = result.headers.get('location'); + setItems(prev => [{ id, description: text }, ...prev]); setInserting(false); }, - (error) => { - setInserting(false); - setError(error); - } + (err) => { setInserting(false); setError(err); } ); - } - return ( -
-

MY TODO LIST

- - { error && -

Error: {error.message}

- } - { isLoading && - - } - { !isLoading && -
- - - {items.map(item => ( - !item.done && ( - - - { /**/ } - - - - )))} - -
{item.description}{JSON.stringify(item, null, 2) }{item.createdAt}
-

- Done items -

- - - {items.map(item => ( - item.done && ( - - - - - - - - )))} - -
{item.description}{item.createdAt}
+ } + + const todoItems = items.filter(item => !item.done); + const doneItems = items.filter(item => item.done); + const donePercent = items.length > 0 ? Math.round((doneItems.length / items.length) * 100) : 0; + + return ( +
+
+ + {/* Left panel — header + stats */} +
+
+
+ +
+

My Tasks

+

Stay organized, stay focused

+
+
+ + {todoItems.length} pending +
+
+ + {doneItems.length} completed +
+
+
+ + {items.length > 0 && ( +
+
+ {doneItems.length} of {items.length} tasks completed + {donePercent}% +
+
+
+
+
+ )} +
+ + {/* Right panel — tasks */} +
+
+ + +
+ + {activeTab === 'analytics' ? ( + + ) : ( +
+ + + {isLoading ? ( +
+ +
+ ) : ( + <> +
+
+

To Do

+ + {todoItems.length} +
+ + {todoItems.length === 0 ? ( +
All caught up — nothing left to do!
+ ) : ( + todoItems.map((item, i) => ( +
+
+ )) + )} +
+ + {doneItems.length > 0 && ( +
+
+

Completed

+ {doneItems.length} +
+ {doneItems.map((item) => ( +
+ +
+
+ ))} + + )} + + )} +
+ )}
- }
- ); +
+ ); } + export default App; diff --git a/MtdrSpring/backend/src/main/frontend/src/Dashboard.js b/MtdrSpring/backend/src/main/frontend/src/Dashboard.js new file mode 100644 index 000000000..4cf63bc5b --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Dashboard.js @@ -0,0 +1,269 @@ +import React from 'react'; +import { + BarChart, Bar, XAxis, YAxis, CartesianGrid, + Tooltip, Legend, ResponsiveContainer +} from 'recharts'; + +// ── Mock data (swap for real API when backend is ready) ────────────────────── +const SPRINT_DATA = [ + { dev: 'Ana G.', s1: 5, s2: 6, s3: 4, h1: 14, h2: 16, h3: 12 }, + { dev: 'Carlos L.', s1: 3, s2: 5, s3: 6, h1: 11, h2: 14, h3: 13 }, + { dev: 'Maria R.', s1: 7, s2: 4, s3: 5, h1: 18, h2: 15, h3: 18 }, + { dev: 'Jorge M.', s1: 4, s2: 7, s3: 3, h1: 10, h2: 16, h3: 9 }, + { dev: 'Sofia C.', s1: 6, s2: 5, s3: 8, h1: 15, h2: 14, h3: 17 }, +]; + +// ── Derived KPIs ───────────────────────────────────────────────────────────── +const totalTasks = SPRINT_DATA.reduce((acc, d) => acc + d.s1 + d.s2 + d.s3, 0); +const totalHours = SPRINT_DATA.reduce((acc, d) => acc + d.h1 + d.h2 + d.h3, 0); +const avgTasksDev = (totalTasks / SPRINT_DATA.length).toFixed(1); +const avgHoursDev = (totalHours / SPRINT_DATA.length).toFixed(1); + +const KPI_CARDS = [ + { label: '# Tasks', value: totalTasks, color: '#7C3AED', bg: '#EDE9FE' }, + { label: 'Real Hours', value: `${totalHours}h`, color: '#F59E0B', bg: '#FEF3C7' }, + { label: 'Tasks / Dev', value: avgTasksDev, color: '#14B8A6', bg: '#CCFBF1' }, + { label: 'Hours / Dev', value: `${avgHoursDev}h`,color: '#EC4899', bg: '#FCE7F3' }, +]; + +// ── Auto-generated insights from data ──────────────────────────────────────── +function generateInsights() { + const withTotals = SPRINT_DATA.map(d => ({ + ...d, + totalTasks: d.s1 + d.s2 + d.s3, + totalHours: d.h1 + d.h2 + d.h3, + efficiency: (d.s1 + d.s2 + d.s3) / (d.h1 + d.h2 + d.h3), + trend: d.s3 - d.s1, + })); + + const topTasks = [...withTotals].sort((a, b) => b.totalTasks - a.totalTasks)[0]; + const topEff = [...withTotals].sort((a, b) => b.efficiency - a.efficiency)[0]; + const lowEff = [...withTotals].sort((a, b) => a.efficiency - b.efficiency)[0]; + const mostImproved = [...withTotals].sort((a, b) => b.trend - a.trend)[0]; + const declining = [...withTotals].sort((a, b) => a.trend - b.trend)[0]; + const mostHours = [...withTotals].sort((a, b) => b.totalHours - a.totalHours)[0]; + const leastHours = [...withTotals].sort((a, b) => a.totalHours - b.totalHours)[0]; + + const taskVariance = Math.max(...withTotals.map(d => d.totalTasks)) - + Math.min(...withTotals.map(d => d.totalTasks)); + + const insights = [ + { + type: 'success', + tag: 'Top Performer', + title: `${topTasks.dev} leads in productivity`, + body: `Completed ${topTasks.totalTasks} tasks in total — the highest count on the team.`, + }, + { + type: 'info', + tag: 'Efficiency', + title: `${topEff.dev} is the most efficient`, + body: `Achieves ${topEff.efficiency.toFixed(2)} tasks/hour — the best output-to-time ratio on the team.`, + }, + { + type: 'warning', + tag: 'Watch', + title: `${lowEff.dev} has the lowest efficiency`, + body: `Only ${lowEff.efficiency.toFixed(2)} tasks/hour. May be facing technical blockers or handling higher-complexity work.`, + }, + mostImproved.trend > 0 ? { + type: 'success', + tag: 'Positive Trend', + title: `${mostImproved.dev} is improving sprint over sprint`, + body: `Increased by ${mostImproved.trend} tasks from Sprint 1 to Sprint 3 — a strong learning curve.`, + } : null, + declining.trend < 0 ? { + type: 'danger', + tag: 'Declining Trend', + title: `${declining.dev} shows a drop in output`, + body: `Down ${Math.abs(declining.trend)} tasks from Sprint 1 to Sprint 3. Needs follow-up.`, + } : null, + taskVariance >= 4 ? { + type: 'warning', + tag: 'Imbalance', + title: `High variance across developers`, + body: `There is a ${taskVariance}-task gap between the highest and lowest contributor. Workload may not be evenly distributed.`, + } : null, + { + type: 'info', + tag: 'Workload', + title: `${mostHours.dev} is logging the most hours`, + body: `${mostHours.totalHours}h total vs ${leastHours.totalHours}h for ${leastHours.dev} — a ${mostHours.totalHours - leastHours.totalHours}h gap that may signal uneven task assignment.`, + }, + ].filter(Boolean); + + const actions = [ + { + priority: 'High', + color: '#EF4444', + bg: '#FEF2F2', + text: `Set up pair programming sessions between ${topEff.dev} and ${lowEff.dev} to share best practices and unblock bottlenecks.`, + }, + { + priority: 'High', + color: '#EF4444', + bg: '#FEF2F2', + text: declining.trend < 0 + ? `Schedule a 1-on-1 with ${declining.dev} to identify what caused the drop from Sprint 1 to Sprint 3 before the next sprint begins.` + : `Review task distribution — ensure no developer is assigned more than 130% of the team average.`, + }, + { + priority: 'Medium', + color: '#F59E0B', + bg: '#FEF3C7', + text: `Rebalance workload between ${mostHours.dev} and ${leastHours.dev} in the next sprint — the ${mostHours.totalHours - leastHours.totalHours}h difference is a burnout risk.`, + }, + { + priority: 'Medium', + color: '#F59E0B', + bg: '#FEF3C7', + text: `Use ${topTasks.dev}'s estimates as a baseline reference when assigning story points to the team.`, + }, + { + priority: 'Low', + color: '#14B8A6', + bg: '#CCFBF1', + text: `Publicly acknowledge ${mostImproved.dev}'s progress in the retrospective — reinforces a culture of continuous improvement.`, + }, + ]; + + return { insights, actions }; +} + +// ── Tooltips ───────────────────────────────────────────────────────────────── +const CustomTooltip = ({ active, payload, label }) => { + if (!active || !payload?.length) return null; + return ( +
+

{label}

+ {payload.map(p => ( +

{p.name}: {p.value} tasks

+ ))} +
+ ); +}; + +const HoursTooltip = ({ active, payload, label }) => { + if (!active || !payload?.length) return null; + return ( +
+

{label}

+ {payload.map(p => ( +

{p.name}: {p.value}h

+ ))} +
+ ); +}; + +const INSIGHT_STYLES = { + success: { border: '#22C55E', bg: '#F0FDF4', tag: '#16A34A' }, + info: { border: '#3B82F6', bg: '#EFF6FF', tag: '#1D4ED8' }, + warning: { border: '#F59E0B', bg: '#FFFBEB', tag: '#B45309' }, + danger: { border: '#EF4444', bg: '#FEF2F2', tag: '#B91C1C' }, +}; + +// ── Component ───────────────────────────────────────────────────────────────── +function Dashboard() { + const { insights, actions } = generateInsights(); + + return ( +
+ + {/* KPI Cards */} +
+ {KPI_CARDS.map(card => ( +
+ {card.value} + {card.label} +
+ ))} +
+ + {/* Chart 1 — Tasks by developer/sprint */} +
+
+

Completed Tasks by Developer

+

Comparative analysis per sprint

+
+
+ + + + + + } cursor={{ fill: 'rgba(124,58,237,0.04)' }} /> + + + + + + +
+
+ + {/* Chart 2 — Real hours by developer/sprint */} +
+
+

Real Hours by Developer

+

Comparative analysis per sprint

+
+
+ + + + + + } cursor={{ fill: 'rgba(124,58,237,0.04)' }} /> + + + + + + +
+
+ + {/* Insights */} +
+
+

Insights

+

Patterns automatically detected from the data

+
+
+ {insights.map((ins, i) => { + const s = INSIGHT_STYLES[ins.type]; + return ( +
+ {ins.tag} +

{ins.title}

+

{ins.body}

+
+ ); + })} +
+
+ + {/* Improvement Actions */} +
+
+

Improvement Actions

+

Concrete recommendations for the next sprint

+
+
+ {actions.map((action, i) => ( +
+ {action.priority} +

{action.text}

+
+ ))} +
+
+ +
+ ); +} + +export default Dashboard; diff --git a/MtdrSpring/backend/src/main/frontend/src/NewItem.js b/MtdrSpring/backend/src/main/frontend/src/NewItem.js index c52158419..565e86411 100644 --- a/MtdrSpring/backend/src/main/frontend/src/NewItem.js +++ b/MtdrSpring/backend/src/main/frontend/src/NewItem.js @@ -1,64 +1,36 @@ -/* -## MyToDoReact version 1.0. -## -## Copyright (c) 2022 Oracle, Inc. -## Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ -*/ -/* - * Component that supports creating a new todo item. - * @author jean.de.lavarene@oracle.com - */ - import React, { useState } from "react"; -import Button from '@mui/material/Button'; - function NewItem(props) { const [item, setItem] = useState(''); + function handleSubmit(e) { - // console.log("NewItem.handleSubmit("+e+")"); - if (!item.trim()) { - return; - } - // addItem makes the REST API call: + e.preventDefault(); + if (!item.trim()) return; props.addItem(item); setItem(""); - e.preventDefault(); - } - function handleChange(e) { - setItem(e.target.value); } + return ( -
-
+
+ + { - if (event.key === 'Enter') { - handleSubmit(event); - } - }} + onChange={e => setItem(e.target.value)} + onKeyDown={e => { if (e.key === 'Enter') handleSubmit(e); }} /> -    - - +
); } -export default NewItem; \ No newline at end of file +export default NewItem; diff --git a/MtdrSpring/backend/src/main/frontend/src/index.css b/MtdrSpring/backend/src/main/frontend/src/index.css index b82c4de13..ae5ada450 100644 --- a/MtdrSpring/backend/src/main/frontend/src/index.css +++ b/MtdrSpring/backend/src/main/frontend/src/index.css @@ -1,134 +1,680 @@ -/* -** Todo application version 1.0. -** -** Copyright (c) 2020, Oracle and/or its affiliates. -** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ -*/ +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap'); + +/* ── Design tokens ─────────────────────────────────────────────────────────── */ +:root { + --purple: #7C3AED; + --purple-dark: #5B21B6; + --purple-mid: #6D28D9; + --purple-light: #EDE9FE; + --purple-soft: #F5F3FF; + --yellow: #FCD34D; + --teal: #14B8A6; + --green: #22C55E; + --danger: #EF4444; + --danger-light: #FEF2F2; + --text-primary: #1F1D2E; + --text-secondary: #9CA3AF; + --text-light: #C4B5FD; + --surface: #FFFFFF; + --bg: #F5F3FF; + --border: #EDE9FE; + --shadow-card: 0 2px 12px rgba(124,58,237,0.08); + --shadow-lg: 0 8px 32px rgba(124,58,237,0.18); + --radius-xl: 24px; + --radius-lg: 16px; + --radius-md: 12px; + --radius-sm: 8px; + --radius-pill: 99px; + + /* Fluid spacing scale */ + --space-xs: clamp(6px, 1vw, 8px); + --space-sm: clamp(10px, 2vw, 14px); + --space-md: clamp(14px, 3vw, 20px); + --space-lg: clamp(20px, 4vw, 32px); + --space-xl: clamp(28px, 5vw, 48px); + + /* Fluid type scale */ + --text-xs: clamp(10px, 1.5vw, 11px); + --text-sm: clamp(11px, 1.8vw, 13px); + --text-base: clamp(13px, 2vw, 15px); + --text-lg: clamp(16px, 2.5vw, 20px); + --text-xl: clamp(20px, 3.5vw, 28px); + --text-2xl: clamp(22px, 4vw, 32px); +} + +/* ── Reset ─────────────────────────────────────────────────────────────────── */ +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +html { -webkit-text-size-adjust: 100%; } + body { - /* from the redwood theme */ - background-color: #3A3632; - width: 100%; - max-width: 50rem; + background: var(--bg); + font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + color: var(--text-primary); + min-height: 100vh; + overflow-x: hidden; +} + +/* ── Layout shell ───────────────────────────────────────────────────────────── */ +.app-wrapper { min-height: 100vh; } + +/* Default: mobile — full-width stacked */ +.layout { + display: flex; + flex-direction: column; + min-height: 100vh; +} + +.left-panel { flex-shrink: 0; } + +.right-panel { + flex: 1; + min-width: 0; + padding: clamp(14px, 4vw, 20px) clamp(14px, 4vw, 16px) 60px; +} + +/* Remove right-panel padding on tablet+ since layout handles it */ +@media (min-width: 640px) { + .right-panel { padding: 0; } +} + +/* ─ Tablet portrait (≥ 640px) ─ */ +@media (min-width: 640px) { + .layout { + max-width: 600px; margin: 0 auto; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + padding: var(--space-lg) var(--space-md) 60px; } - .App { - background: #201E1C; - color: #FEF9F2; - display: flex; - flex-direction: column; - align-items: center; - font-size: max(12px,min(2vw, 18px)); /*calc(1vw + 1vmin);*/ - margin: 2rem 0 4rem 0; - padding: 1rem; - position: relative; - box-shadow: 0 10px 18px 0 rgba(0, 0, 0, 0.2), 0 4.5rem 8rem 0 rgba(0, 0, 0, 0.1); - border-radius: 0.5rem; + .app-header { + border-radius: var(--radius-xl) !important; + padding: var(--space-lg) var(--space-lg) var(--space-md) !important; } - div#maincontent, div#newinputform form { - width: 95%; - } - div#maincontent { - margin: 0; - padding: 0; - } - h1 { - margin: 0.5rem 0 1rem 0; - padding: 0; - } - h2 { - margin: 0.1rem 0 0.1rem 0; - padding: 0; - } - #newiteminput { - width: 100%; - } - div#newinputform { - width: 100%; - } - div#newinputform form{ - display: flex; + .progress-wrap { margin: var(--space-sm) 0 0 !important; border-radius: var(--radius-lg); } + .app-body { padding: var(--space-md) 0 0 !important; } +} + +/* ─ Tablet landscape (≥ 768px) ─ */ +@media (min-width: 768px) { + .layout { max-width: 720px; } +} + +/* ─ Small desktop (≥ 1024px) — switch to two-column ─ */ +@media (min-width: 1024px) { + .layout { flex-direction: row; - margin: 0 auto; - } - #donelist { - margin: 0; - padding: 0; - } - table#itemlistNotDone { - margin-bottom: 2rem; - } - table#itemlistDone { - margin-bottom: 3rem; - } - table.itemlist { - margin-top: 0.7rem; - border-collapse: collapse; - margin-bottom: 1rem; - } - table.itemlist td { - border-bottom: solid 1px #5B5652; - padding: .5rem; - } - table.itemlist td.description { - width: 100%; - padding-left: 1rem; - padding-right: 1rem; - } - table.itemlist td.date { - font-size: max(10px,min(1.5vw, 14px)); - color: grey; - white-space: nowrap; - padding-right: 0; - padding-left: 0; - } - table.itemlist tr:hover { - background-color: #161513; - } - input { - font-family: inherit; - font-size: 100%; - line-height: 1; - margin: 0; - } - button, - input { - overflow: visible; - } - input[type="text"] { - border-radius: 0.3rem; - padding-left: 10px; - } - button.AddButton, - button.DeleteButton, - button.AddButton, - button.DoneButton { - font-size: max(8px,min(2vw, 12px)); - padding: 0.35em 0.5em; - color:#161513; - } - /* from the redwood theme */ - button.AddButton { - color: #FEF9F2; - background-color: #5F7D4F; + align-items: flex-start; + max-width: 1000px; + padding: var(--space-xl) var(--space-lg) 80px; + gap: var(--space-lg); } - button.AddButton:hover { - background-color: #6F915D; + .left-panel { + width: 290px; + position: sticky; + top: var(--space-xl); } - button.DeleteButton { - color: #FEF9F2; - background-color: #D63B25; + .app-header { + border-radius: var(--radius-xl) !important; + padding: var(--space-lg) var(--space-md) var(--space-md) !important; } - button.DeleteButton:hover { - background-color: #EC4F3A + .progress-wrap { margin: var(--space-sm) 0 0 !important; border-radius: var(--radius-lg); } + .app-body { padding: 0 !important; } +} + +/* ─ Large desktop (≥ 1280px) ─ */ +@media (min-width: 1280px) { + .layout { + max-width: 1160px; + gap: 40px; } - button.DoneButton { - background-color: #FBF9F8; + .left-panel { width: 320px; } +} + +/* ─ Extra large (≥ 1536px) ─ */ +@media (min-width: 1536px) { + .layout { max-width: 1360px; } + .left-panel { width: 360px; } +} + +/* ── Header ─────────────────────────────────────────────────────────────────── */ +.app-header { + background: linear-gradient(140deg, #7C3AED 0%, #5B21B6 100%); + border-radius: 0 0 28px 28px; + padding: clamp(40px, 8vw, 52px) clamp(20px, 5vw, 28px) clamp(24px, 5vw, 36px); + color: white; + position: relative; + overflow: hidden; +} + +.app-header::before { + content: ''; + position: absolute; + top: -40px; right: -40px; + width: clamp(120px, 20vw, 180px); + height: clamp(120px, 20vw, 180px); + background: rgba(255,255,255,0.06); + border-radius: 50%; +} + +.app-header::after { + content: ''; + position: absolute; + bottom: -60px; right: 40px; + width: clamp(80px, 14vw, 120px); + height: clamp(80px, 14vw, 120px); + background: rgba(255,255,255,0.04); + border-radius: 50%; +} + +.header-logo { + width: clamp(44px, 7vw, 52px); + height: clamp(44px, 7vw, 52px); + background: rgba(255,255,255,0.18); + border-radius: var(--radius-md); + display: flex; + align-items: center; + justify-content: center; + margin-bottom: var(--space-md); + backdrop-filter: blur(8px); + flex-shrink: 0; +} + +.header-logo svg { font-size: clamp(22px, 4vw, 28px) !important; color: var(--yellow); } + +.app-header h1 { + font-size: var(--text-2xl); + font-weight: 700; + letter-spacing: -0.5px; + margin-bottom: 4px; + line-height: 1.2; +} + +.app-header .subtitle { + font-size: var(--text-sm); + font-weight: 400; + color: var(--text-light); + margin-bottom: var(--space-md); +} + +/* ── Stats row ──────────────────────────────────────────────────────────────── */ +.stats-row { display: flex; gap: 10px; flex-wrap: wrap; } + +.stat-chip { + background: rgba(255,255,255,0.14); + border-radius: var(--radius-pill); + padding: 5px 12px; + font-size: var(--text-sm); + font-weight: 600; + color: white; + display: flex; + align-items: center; + gap: 6px; + backdrop-filter: blur(8px); +} + +.stat-chip .dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; } +.dot-pending { background: var(--yellow); } +.dot-done { background: var(--green); } + +/* ── Progress ───────────────────────────────────────────────────────────────── */ +.progress-wrap { + margin: clamp(14px, 3vw, 20px) clamp(14px, 4vw, 16px) 0; + background: var(--surface); + border-radius: var(--radius-lg); + padding: clamp(12px, 2.5vw, 16px) clamp(14px, 3vw, 20px); + box-shadow: var(--shadow-card); +} + +@media (min-width: 640px) { + .progress-wrap { margin: clamp(14px, 3vw, 20px) 0 0; } +} + +.progress-label { + display: flex; + justify-content: space-between; + align-items: center; + font-size: var(--text-sm); + font-weight: 600; + color: var(--text-secondary); + margin-bottom: 10px; +} + +.progress-label .pct { color: var(--purple); } + +.progress-track { + height: clamp(5px, 1vw, 8px); + background: var(--border); + border-radius: var(--radius-pill); + overflow: hidden; +} + +.progress-fill { + height: 100%; + background: linear-gradient(90deg, var(--purple), #A78BFA); + border-radius: var(--radius-pill); + transition: width 0.5s cubic-bezier(0.4,0,0.2,1); +} + +/* ── App body ───────────────────────────────────────────────────────────────── */ +.app-body { + padding: clamp(14px, 3vw, 20px) 0 0; +} + +/* On tablet+ the right-panel has no padding, so app-body needs its own horizontal */ +@media (min-width: 640px) { + .app-body { + padding: clamp(16px, 3vw, 20px) 0 0; } - button.DoneButton:hover { - background-color: #D4CFCA; - } \ No newline at end of file +} + +/* ── New item form ──────────────────────────────────────────────────────────── */ +.new-item-wrap { + background: var(--surface); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-card); + border: 1.5px solid var(--border); + margin-bottom: clamp(16px, 3vw, 24px); + display: flex; + align-items: center; + overflow: hidden; + transition: border-color 0.2s, box-shadow 0.2s; +} + +.new-item-wrap:focus-within { + border-color: var(--purple); + box-shadow: 0 0 0 4px rgba(124,58,237,0.1); +} + +.new-item-prefix { + padding: 0 4px 0 clamp(12px, 3vw, 18px); + color: var(--purple); + font-size: clamp(18px, 3vw, 22px); + font-weight: 300; + display: flex; + align-items: center; + flex-shrink: 0; + user-select: none; +} + +.new-item-input { + flex: 1; + min-width: 0; + border: none; + outline: none; + background: transparent; + font-family: inherit; + font-size: var(--text-base); + font-weight: 500; + color: var(--text-primary); + padding: clamp(12px, 2.5vw, 15px) 8px; +} + +.new-item-input::placeholder { color: var(--text-secondary); font-weight: 400; } + +.add-btn { + flex-shrink: 0; + margin: 6px; + padding: clamp(7px, 1.5vw, 9px) clamp(14px, 3vw, 20px); + background: linear-gradient(135deg, var(--purple), var(--purple-mid)); + color: white; + border: none; + border-radius: var(--radius-md); + font-family: inherit; + font-size: var(--text-sm); + font-weight: 600; + cursor: pointer; + transition: opacity 0.15s, transform 0.1s, box-shadow 0.15s; + white-space: nowrap; + box-shadow: 0 4px 12px rgba(124,58,237,0.3); + /* min touch target */ + min-height: 36px; +} + +.add-btn:hover:not(:disabled) { opacity: 0.9; transform: translateY(-1px); box-shadow: 0 6px 16px rgba(124,58,237,0.4); } +.add-btn:active:not(:disabled) { transform: translateY(0); } +.add-btn:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; } + +/* ── Task sections ──────────────────────────────────────────────────────────── */ +.tasks-section { margin-bottom: clamp(18px, 4vw, 28px); } + +.section-header { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: clamp(8px, 2vw, 12px); +} + +.section-header h2 { + font-size: var(--text-xs); + font-weight: 700; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.8px; +} + +.count-badge { + background: var(--purple-light); + color: var(--purple); + font-size: var(--text-xs); + font-weight: 700; + padding: 2px 9px; + border-radius: var(--radius-pill); +} + +/* ── Task card ──────────────────────────────────────────────────────────────── */ +.task-card { + background: var(--surface); + border-radius: var(--radius-md); + padding: clamp(10px, 2vw, 14px) clamp(12px, 2.5vw, 16px); + margin-bottom: clamp(6px, 1.5vw, 10px); + box-shadow: var(--shadow-card); + display: flex; + align-items: center; + gap: clamp(10px, 2vw, 14px); + border: 1.5px solid transparent; + transition: box-shadow 0.15s, border-color 0.15s, transform 0.1s; + position: relative; + overflow: hidden; +} + +.task-card::before { + content: ''; + position: absolute; + left: 0; top: 0; bottom: 0; + width: 4px; + background: var(--card-accent, var(--purple)); + border-radius: 4px 0 0 4px; +} + +.task-card:hover { box-shadow: var(--shadow-lg); border-color: var(--border); transform: translateY(-1px); } +.task-card:hover .task-actions { opacity: 1; } + +.task-card.is-done { background: #FAFAFA; box-shadow: none; border-color: var(--border); } +.task-card.is-done::before { background: var(--green); } +.task-card.is-done:hover { transform: none; box-shadow: var(--shadow-card); } + +/* On touch devices always show actions (no hover) */ +@media (hover: none) { + .task-actions { opacity: 1; } + .task-card:hover { transform: none; box-shadow: var(--shadow-card); } +} + +/* ── Checkbox ───────────────────────────────────────────────────────────────── */ +.task-checkbox { + flex-shrink: 0; + width: clamp(20px, 3.5vw, 24px); + height: clamp(20px, 3.5vw, 24px); + border-radius: 50%; + border: 2px solid #D1D5DB; + background: transparent; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s; + padding: 0; + outline: none; + /* min touch target */ + position: relative; +} + +.task-checkbox::after { + content: ''; + position: absolute; + inset: -8px; +} + +.task-checkbox:hover { border-color: var(--purple); background: var(--purple-light); } + +.task-checkbox.checked { background: var(--green); border-color: var(--green); } +.task-checkbox.checked::after { + content: '✓'; + position: static; + color: white; + font-size: clamp(10px, 1.8vw, 13px); + font-weight: 700; + line-height: 1; +} + +/* ── Task body ──────────────────────────────────────────────────────────────── */ +.task-body { flex: 1; min-width: 0; } + +.task-description { + font-size: var(--text-base); + font-weight: 500; + color: var(--text-primary); + display: block; + line-height: 1.4; + word-break: break-word; +} + +.task-card.is-done .task-description { + color: #9CA3AF; + text-decoration: line-through; + font-weight: 400; +} + +.task-date { + font-size: var(--text-xs); + color: var(--text-secondary); + display: block; + margin-top: 3px; + font-weight: 400; +} + +/* ── Task actions ───────────────────────────────────────────────────────────── */ +.task-actions { + display: flex; + align-items: center; + gap: 4px; + opacity: 0; + transition: opacity 0.15s; + flex-shrink: 0; +} + +.action-btn { + width: clamp(30px, 5vw, 34px); + height: clamp(30px, 5vw, 34px); + border-radius: var(--radius-sm); + border: none; + background: transparent; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-secondary); + transition: background 0.12s, color 0.12s; + outline: none; +} + +.action-btn:hover { background: var(--border); color: var(--text-primary); } +.action-btn.delete:hover { background: var(--danger-light); color: var(--danger); } + +/* ── Empty state ────────────────────────────────────────────────────────────── */ +.empty-state { + text-align: center; + padding: clamp(24px, 5vw, 36px) 0 clamp(20px, 4vw, 28px); + color: var(--text-secondary); + font-size: var(--text-base); + font-weight: 500; +} + +/* ── Tabs ───────────────────────────────────────────────────────────────────── */ +.tabs { + display: flex; + gap: 5px; + margin-bottom: clamp(14px, 3vw, 20px); + background: var(--surface); + border-radius: var(--radius-lg); + padding: 5px; + box-shadow: var(--shadow-card); +} + +.tab-btn { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + padding: clamp(8px, 1.8vw, 10px) clamp(10px, 2.5vw, 16px); + border: none; + border-radius: var(--radius-md); + background: transparent; + font-family: inherit; + font-size: var(--text-sm); + font-weight: 600; + color: var(--text-secondary); + cursor: pointer; + transition: all 0.18s; + min-height: 40px; +} + +.tab-btn svg { flex-shrink: 0; } + +.tab-btn:hover { background: var(--purple-soft); color: var(--purple); } +.tab-btn.active { background: var(--purple); color: white; box-shadow: 0 4px 12px rgba(124,58,237,0.3); } + +/* Hide icon labels on very small screens */ +@media (max-width: 359px) { + .tab-btn span { display: none; } +} + +/* ── Dashboard ──────────────────────────────────────────────────────────────── */ +.dashboard { + display: flex; + flex-direction: column; + gap: clamp(12px, 2.5vw, 16px); +} + +/* KPI grid: 2 cols on mobile → 4 cols on sm+ */ +.kpi-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: clamp(8px, 2vw, 12px); +} + +@media (min-width: 480px) { .kpi-grid { grid-template-columns: repeat(4, 1fr); } } + +.kpi-card { + background: var(--kpi-bg); + border-radius: var(--radius-lg); + padding: clamp(14px, 2.5vw, 18px) clamp(12px, 2.5vw, 16px); + display: flex; + flex-direction: column; + gap: 4px; +} + +.kpi-value { + font-size: clamp(20px, 4vw, 28px); + font-weight: 700; + color: var(--kpi-color); + line-height: 1; +} + +.kpi-label { + font-size: var(--text-xs); + font-weight: 600; + color: var(--kpi-color); + opacity: 0.7; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +/* ── Chart card ─────────────────────────────────────────────────────────────── */ +.chart-card { + background: var(--surface); + border-radius: var(--radius-lg); + padding: clamp(14px, 3vw, 20px); + box-shadow: var(--shadow-card); + /* prevent chart overflow on small screens */ + overflow: hidden; +} + +.chart-header { margin-bottom: clamp(10px, 2vw, 16px); } + +.chart-header h3 { + font-size: var(--text-base); + font-weight: 700; + color: var(--text-primary); + margin-bottom: 2px; +} + +.chart-header p { font-size: var(--text-xs); color: var(--text-secondary); font-weight: 400; } + +.chart-wrap { width: 100%; overflow: hidden; } + +.chart-tooltip { + background: white; + border-radius: 12px; + padding: 10px 14px; + box-shadow: 0 8px 32px rgba(124,58,237,0.15); + font-family: 'Poppins', sans-serif; + font-size: 12px; + border: none; +} + +.tooltip-label { font-weight: 700; color: var(--text-primary); margin-bottom: 6px; font-size: 13px; } + +/* ── Insights ───────────────────────────────────────────────────────────────── */ +.insights-section { margin-top: 4px; } + +.insights-header { margin-bottom: clamp(8px, 2vw, 12px); } + +.insights-header h3 { font-size: var(--text-base); font-weight: 700; color: var(--text-primary); margin-bottom: 2px; } +.insights-header p { font-size: var(--text-xs); color: var(--text-secondary); } + +/* 1 col mobile → 2 cols sm+ */ +.insights-grid { + display: grid; + grid-template-columns: 1fr; + gap: clamp(8px, 2vw, 10px); +} + +@media (min-width: 560px) { .insights-grid { grid-template-columns: repeat(2, 1fr); } } + +.insight-card { + background: var(--ins-bg); + border-left: 4px solid var(--ins-border); + border-radius: var(--radius-md); + padding: clamp(10px, 2vw, 14px) clamp(12px, 2.5vw, 16px); + display: flex; + flex-direction: column; + gap: 5px; +} + +.insight-tag { font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px; color: var(--ins-tag); } +.insight-title { font-size: var(--text-sm); font-weight: 700; color: var(--text-primary); line-height: 1.3; } +.insight-body { font-size: var(--text-xs); color: var(--text-secondary); line-height: 1.5; } + +/* ── Actions ────────────────────────────────────────────────────────────────── */ +.actions-list { display: flex; flex-direction: column; gap: clamp(6px, 1.5vw, 8px); } + +.action-item { + background: var(--act-bg); + border-radius: var(--radius-md); + padding: clamp(10px, 2vw, 12px) clamp(12px, 2.5vw, 16px); + display: flex; + align-items: flex-start; + gap: clamp(8px, 2vw, 12px); +} + +.action-priority { + flex-shrink: 0; + font-size: var(--text-xs); + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--act-color); + background: white; + border: 1.5px solid var(--act-color); + border-radius: var(--radius-pill); + padding: 2px 8px; + margin-top: 2px; + white-space: nowrap; +} + +.action-text { font-size: var(--text-sm); color: var(--text-primary); line-height: 1.5; } + +/* ── Loading ────────────────────────────────────────────────────────────────── */ +.loading-wrap { display: flex; justify-content: center; padding: clamp(32px, 6vw, 48px) 0; } From d29a461cf295ff3e5f5072f97b8c3215b9a8ce21 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago Date: Wed, 15 Apr 2026 09:32:52 -0600 Subject: [PATCH 02/23] Migration to typescript --- MtdrSpring/backend/src/main/frontend/package-lock.json | 7 +++++-- MtdrSpring/backend/src/main/frontend/package.json | 8 +++++--- .../src/main/frontend/src/{NewItem.js => NewItem.tsx} | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) rename MtdrSpring/backend/src/main/frontend/src/{NewItem.js => NewItem.tsx} (87%) diff --git a/MtdrSpring/backend/src/main/frontend/package-lock.json b/MtdrSpring/backend/src/main/frontend/package-lock.json index 8ff1f4283..95581a441 100644 --- a/MtdrSpring/backend/src/main/frontend/package-lock.json +++ b/MtdrSpring/backend/src/main/frontend/package-lock.json @@ -18,8 +18,10 @@ "react-dom": "^17.0.2", "react-moment": "^1.1.2", "react-scripts": "5.0.0", - "recharts": "^2.1.16", - "typescript": "^4.6.4" + "recharts": "^2.1.16" + }, + "devDependencies": { + "typescript": "~4.9.5" } }, "node_modules/@alloc/quick-lru": { @@ -16487,6 +16489,7 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/MtdrSpring/backend/src/main/frontend/package.json b/MtdrSpring/backend/src/main/frontend/package.json index 1ec5bfd76..04dd8b8aa 100644 --- a/MtdrSpring/backend/src/main/frontend/package.json +++ b/MtdrSpring/backend/src/main/frontend/package.json @@ -13,8 +13,7 @@ "react-dom": "^17.0.2", "react-moment": "^1.1.2", "react-scripts": "5.0.0", - "recharts": "^2.1.16", - "typescript": "^4.6.4" + "recharts": "^2.1.16" }, "scripts": { "start": "react-scripts start", @@ -26,5 +25,8 @@ "browserslist": [ "last 5 versions" ], - "homepage": "." + "homepage": ".", + "devDependencies": { + "typescript": "~4.9.5" + } } diff --git a/MtdrSpring/backend/src/main/frontend/src/NewItem.js b/MtdrSpring/backend/src/main/frontend/src/NewItem.tsx similarity index 87% rename from MtdrSpring/backend/src/main/frontend/src/NewItem.js rename to MtdrSpring/backend/src/main/frontend/src/NewItem.tsx index 565e86411..c116bd23c 100644 --- a/MtdrSpring/backend/src/main/frontend/src/NewItem.js +++ b/MtdrSpring/backend/src/main/frontend/src/NewItem.tsx @@ -1,9 +1,9 @@ import React, { useState } from "react"; -function NewItem(props) { +function NewItem(props: { isInserting: boolean, addItem: (item: any) => void }) { const [item, setItem] = useState(''); - function handleSubmit(e) { + function handleSubmit(e: any) { e.preventDefault(); if (!item.trim()) return; props.addItem(item); From c067903f96340488c4b01f69ca54392d07a8f94d Mon Sep 17 00:00:00 2001 From: Bernardo Santiago Date: Wed, 15 Apr 2026 09:34:16 -0600 Subject: [PATCH 03/23] Base models, dtos and services for shared functionality --- .../src/Shared/dtos/api-result.dto.ts | 6 +++ .../src/Shared/dtos/paged-result.dto.ts | 7 +++ .../main/frontend/src/Shared/dtos/tag.dto.ts | 6 +++ .../src/Shared/dtos/team-summary.dto.ts | 5 ++ .../src/Shared/dtos/user-summary.dto.ts | 6 +++ .../frontend/src/Shared/enum/team-role.ts | 3 ++ .../frontend/src/Shared/mock/tags.mock.ts | 28 +++++++++++ .../frontend/src/Shared/mock/teams.mock.ts | 9 ++++ .../frontend/src/Shared/mock/users.mock.ts | 22 ++++++++ .../src/Shared/models/select-option.model.ts | 5 ++ .../frontend/src/Shared/models/tag.model.ts | 6 +++ .../src/Shared/models/team-summary.model.ts | 5 ++ .../src/Shared/models/user-summary.model.ts | 6 +++ .../src/Shared/services/foundation.service.ts | 50 +++++++++++++++++++ .../frontend/src/Shared/services/mock-api.ts | 15 ++++++ 15 files changed, 179 insertions(+) create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/dtos/api-result.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/dtos/paged-result.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/dtos/tag.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/dtos/team-summary.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/dtos/user-summary.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/enum/team-role.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/mock/tags.mock.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/mock/teams.mock.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/mock/users.mock.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/models/select-option.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/models/tag.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/models/team-summary.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/models/user-summary.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/services/foundation.service.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/Shared/services/mock-api.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/api-result.dto.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/api-result.dto.ts new file mode 100644 index 000000000..4fe2957f3 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/api-result.dto.ts @@ -0,0 +1,6 @@ +export type ApiResult = { + success: boolean + data: T + message?: string + errors?: string[] +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/paged-result.dto.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/paged-result.dto.ts new file mode 100644 index 000000000..1edeb8737 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/paged-result.dto.ts @@ -0,0 +1,7 @@ +export type PagedResult = { + items: T[] + total: number + page: number + pageSize: number + totalPages: number +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/tag.dto.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/tag.dto.ts new file mode 100644 index 000000000..21e1881a0 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/tag.dto.ts @@ -0,0 +1,6 @@ +export type TagDto = { + id: string + name: string + color: string + description?: string +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/team-summary.dto.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/team-summary.dto.ts new file mode 100644 index 000000000..a34dbdc47 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/team-summary.dto.ts @@ -0,0 +1,5 @@ +export type TeamSummaryDto = { + id: string + name: string + createdAt?: string +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/user-summary.dto.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/user-summary.dto.ts new file mode 100644 index 000000000..aa6537b77 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/user-summary.dto.ts @@ -0,0 +1,6 @@ +export type UserSummaryDto = { + id: string + name: string + email?: string + telegramUserId?: string +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/enum/team-role.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/enum/team-role.ts new file mode 100644 index 000000000..54193d056 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/enum/team-role.ts @@ -0,0 +1,3 @@ +export const TEAM_ROLES = ['MANAGER', 'DEVELOPER'] as const + +export type TeamRole = (typeof TEAM_ROLES)[number] \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/mock/tags.mock.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/mock/tags.mock.ts new file mode 100644 index 000000000..498d51921 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/mock/tags.mock.ts @@ -0,0 +1,28 @@ +import type { TagDto } from '../dtos/tag.dto' + +export const mockTags: TagDto[] = [ + { + id: 'tag-001', + name: 'Frontend', + color: '#3B82F6', + description: 'UI and client-side work' + }, + { + id: 'tag-002', + name: 'Backend', + color: '#10B981', + description: 'API and service work' + }, + { + id: 'tag-003', + name: 'Bug', + color: '#EF4444', + description: 'Defect or error' + }, + { + id: 'tag-004', + name: 'High Priority', + color: '#F59E0B', + description: 'Needs quick attention' + } +] \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/mock/teams.mock.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/mock/teams.mock.ts new file mode 100644 index 000000000..d916e3df2 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/mock/teams.mock.ts @@ -0,0 +1,9 @@ +import type { TeamSummaryDto } from '../dtos/team-summary.dto' + +export const mockTeams: TeamSummaryDto[] = [ + { + id: 'team-001', + name: 'Core Platform', + createdAt: '2026-03-01T10:00:00Z' + } +] \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/mock/users.mock.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/mock/users.mock.ts new file mode 100644 index 000000000..a50f37187 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/mock/users.mock.ts @@ -0,0 +1,22 @@ +import type { UserSummaryDto } from '../dtos/user-summary.dto' + +export const mockUsers: UserSummaryDto[] = [ + { + id: 'usr-001', + name: 'Bernardo Manager', + email: 'bernardo.manager@demo.com', + telegramUserId: 'tg_bernardo_manager' + }, + { + id: 'usr-002', + name: 'Ana Developer', + email: 'ana.dev@demo.com', + telegramUserId: 'tg_ana_dev' + }, + { + id: 'usr-003', + name: 'Luis Developer', + email: 'luis.dev@demo.com', + telegramUserId: 'tg_luis_dev' + } +] \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/models/select-option.model.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/models/select-option.model.ts new file mode 100644 index 000000000..697da4c32 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/models/select-option.model.ts @@ -0,0 +1,5 @@ +export type SelectOption = { + value: TValue + label: string + disabled?: boolean +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/models/tag.model.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/models/tag.model.ts new file mode 100644 index 000000000..aa695942d --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/models/tag.model.ts @@ -0,0 +1,6 @@ +export type Tag = { + id: string + name: string + color: string + description?: string +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/models/team-summary.model.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/models/team-summary.model.ts new file mode 100644 index 000000000..d437eab3c --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/models/team-summary.model.ts @@ -0,0 +1,5 @@ +export type TeamSummary = { + id: string + name: string + createdAt?: string +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/models/user-summary.model.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/models/user-summary.model.ts new file mode 100644 index 000000000..faf2c61d2 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/models/user-summary.model.ts @@ -0,0 +1,6 @@ +export type UserSummary = { + id: string + name: string + email?: string + telegramUserId?: string +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/services/foundation.service.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/services/foundation.service.ts new file mode 100644 index 000000000..48c8d5622 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/services/foundation.service.ts @@ -0,0 +1,50 @@ +import type { ApiResult } from '../dtos/api-result.dto'; +import type { SelectOption } from '../models/select-option.model'; +import type { UserSummaryDto } from '../dtos/user-summary.dto'; +import type { TagDto } from '../dtos/tag.dto'; +import type { TeamSummaryDto } from '../dtos/team-summary.dto'; +import { mockApi } from './mock-api'; +import { mockUsers } from '../mock/users.mock'; +import { mockTags } from '../mock/tags.mock'; +import { mockTeams } from '../mock/teams.mock'; + +export const foundationService = { + async getUsers(): Promise> { + return mockApi(mockUsers); + }, + + async getTags(): Promise> { + return mockApi(mockTags); + }, + + async getTeams(): Promise> { + return mockApi(mockTeams); + }, + + async getUserOptions(): Promise> { + const options: SelectOption[] = mockUsers.map((user) => ({ + value: user.id, + label: user.name + })); + + return mockApi(options); + }, + + async getTagOptions(): Promise> { + const options: SelectOption[] = mockTags.map((tag) => ({ + value: tag.id, + label: tag.name + })) + + return mockApi(options); + }, + + async getTeamOptions(): Promise> { + const options: SelectOption[] = mockTeams.map((team) => ({ + value: team.id, + label: team.name + })) + + return mockApi(options); + } +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/services/mock-api.ts b/MtdrSpring/backend/src/main/frontend/src/Shared/services/mock-api.ts new file mode 100644 index 000000000..238d744e9 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/Shared/services/mock-api.ts @@ -0,0 +1,15 @@ +import type { ApiResult } from '../dtos/api-result.dto' + +const DEFAULT_DELAY_MS = 250 + +export async function mockApi( + data: T, + delayMs: number = DEFAULT_DELAY_MS +): Promise> { + await new Promise((resolve) => setTimeout(resolve, delayMs)); + + return { + success: true, + data: structuredClone(data) + }; +} \ No newline at end of file From e1eb1994f6ef17dd87eb1dba4ba54c34f1e1a947 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago Date: Wed, 15 Apr 2026 09:40:28 -0600 Subject: [PATCH 04/23] Work item enums --- .../src/features/work-items/enums/assignment-role.enum.ts | 3 +++ .../src/features/work-items/enums/bug-severity.enum.ts | 3 +++ .../features/work-items/enums/work-item-priority.enum.ts | 3 +++ .../features/work-items/enums/work-item-status.enum.ts | 8 ++++++++ .../src/features/work-items/enums/work-item-type.enum.ts | 3 +++ .../src/{Shared => shared}/dtos/api-result.dto.ts | 0 .../src/{Shared => shared}/dtos/paged-result.dto.ts | 0 .../main/frontend/src/{Shared => shared}/dtos/tag.dto.ts | 0 .../src/{Shared => shared}/dtos/team-summary.dto.ts | 0 .../src/{Shared => shared}/dtos/user-summary.dto.ts | 0 .../frontend/src/{Shared => shared}/enum/team-role.ts | 0 .../frontend/src/{Shared => shared}/mock/tags.mock.ts | 0 .../frontend/src/{Shared => shared}/mock/teams.mock.ts | 0 .../frontend/src/{Shared => shared}/mock/users.mock.ts | 0 .../src/{Shared => shared}/models/select-option.model.ts | 0 .../frontend/src/{Shared => shared}/models/tag.model.ts | 0 .../src/{Shared => shared}/models/team-summary.model.ts | 0 .../src/{Shared => shared}/models/user-summary.model.ts | 0 .../src/{Shared => shared}/services/foundation.service.ts | 0 .../frontend/src/{Shared => shared}/services/mock-api.ts | 0 20 files changed, 20 insertions(+) create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/assignment-role.enum.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/bug-severity.enum.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-priority.enum.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-status.enum.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-type.enum.ts rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/dtos/api-result.dto.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/dtos/paged-result.dto.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/dtos/tag.dto.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/dtos/team-summary.dto.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/dtos/user-summary.dto.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/enum/team-role.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/mock/tags.mock.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/mock/teams.mock.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/mock/users.mock.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/models/select-option.model.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/models/tag.model.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/models/team-summary.model.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/models/user-summary.model.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/services/foundation.service.ts (100%) rename MtdrSpring/backend/src/main/frontend/src/{Shared => shared}/services/mock-api.ts (100%) diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/assignment-role.enum.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/assignment-role.enum.ts new file mode 100644 index 000000000..4e7e18a34 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/assignment-role.enum.ts @@ -0,0 +1,3 @@ +export const ASSIGNMENT_ROLES = ['OWNER', 'ASSIGNEE', 'REVIEWER'] as const; + +export type AssignmentRole = (typeof ASSIGNMENT_ROLES)[number]; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/bug-severity.enum.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/bug-severity.enum.ts new file mode 100644 index 000000000..b990a97ef --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/bug-severity.enum.ts @@ -0,0 +1,3 @@ +export const BUG_SEVERITIES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] as const; + +export type BugSeverity = (typeof BUG_SEVERITIES)[number]; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-priority.enum.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-priority.enum.ts new file mode 100644 index 000000000..beb475572 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-priority.enum.ts @@ -0,0 +1,3 @@ +export const WORK_ITEM_PRIORITIES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] as const; + +export type WorkItemPriority = (typeof WORK_ITEM_PRIORITIES)[number]; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-status.enum.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-status.enum.ts new file mode 100644 index 000000000..ff8728b42 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-status.enum.ts @@ -0,0 +1,8 @@ +export const WORK_ITEM_STATUSES = [ + 'TODO', + 'IN_PROGRESS', + 'BLOCKED', + 'DONE' +] as const; + +export type WorkItemStatus = (typeof WORK_ITEM_STATUSES)[number]; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-type.enum.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-type.enum.ts new file mode 100644 index 000000000..da8f877ce --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-type.enum.ts @@ -0,0 +1,3 @@ +export const WORK_ITEM_TYPES = ['FEATURE', 'ISSUE', 'BUG', 'TASK'] as const; + +export type WorkItemType = (typeof WORK_ITEM_TYPES)[number]; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/api-result.dto.ts b/MtdrSpring/backend/src/main/frontend/src/shared/dtos/api-result.dto.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/dtos/api-result.dto.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/dtos/api-result.dto.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/paged-result.dto.ts b/MtdrSpring/backend/src/main/frontend/src/shared/dtos/paged-result.dto.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/dtos/paged-result.dto.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/dtos/paged-result.dto.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/tag.dto.ts b/MtdrSpring/backend/src/main/frontend/src/shared/dtos/tag.dto.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/dtos/tag.dto.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/dtos/tag.dto.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/team-summary.dto.ts b/MtdrSpring/backend/src/main/frontend/src/shared/dtos/team-summary.dto.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/dtos/team-summary.dto.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/dtos/team-summary.dto.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/dtos/user-summary.dto.ts b/MtdrSpring/backend/src/main/frontend/src/shared/dtos/user-summary.dto.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/dtos/user-summary.dto.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/dtos/user-summary.dto.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/enum/team-role.ts b/MtdrSpring/backend/src/main/frontend/src/shared/enum/team-role.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/enum/team-role.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/enum/team-role.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/mock/tags.mock.ts b/MtdrSpring/backend/src/main/frontend/src/shared/mock/tags.mock.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/mock/tags.mock.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/mock/tags.mock.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/mock/teams.mock.ts b/MtdrSpring/backend/src/main/frontend/src/shared/mock/teams.mock.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/mock/teams.mock.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/mock/teams.mock.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/mock/users.mock.ts b/MtdrSpring/backend/src/main/frontend/src/shared/mock/users.mock.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/mock/users.mock.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/mock/users.mock.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/models/select-option.model.ts b/MtdrSpring/backend/src/main/frontend/src/shared/models/select-option.model.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/models/select-option.model.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/models/select-option.model.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/models/tag.model.ts b/MtdrSpring/backend/src/main/frontend/src/shared/models/tag.model.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/models/tag.model.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/models/tag.model.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/models/team-summary.model.ts b/MtdrSpring/backend/src/main/frontend/src/shared/models/team-summary.model.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/models/team-summary.model.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/models/team-summary.model.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/models/user-summary.model.ts b/MtdrSpring/backend/src/main/frontend/src/shared/models/user-summary.model.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/models/user-summary.model.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/models/user-summary.model.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/services/foundation.service.ts b/MtdrSpring/backend/src/main/frontend/src/shared/services/foundation.service.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/services/foundation.service.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/services/foundation.service.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/Shared/services/mock-api.ts b/MtdrSpring/backend/src/main/frontend/src/shared/services/mock-api.ts similarity index 100% rename from MtdrSpring/backend/src/main/frontend/src/Shared/services/mock-api.ts rename to MtdrSpring/backend/src/main/frontend/src/shared/services/mock-api.ts From f6f4c42489e76b3d10ebf2c60a3cc88f5a42a9d0 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago Date: Wed, 15 Apr 2026 09:45:10 -0600 Subject: [PATCH 05/23] CRUD dtos --- .../work-items/dtos/create-work-item.dto.ts | 32 +++++++++++++ .../work-items/dtos/update-work-item.dto.ts | 30 ++++++++++++ .../work-items/dtos/work-item-detail.dto.ts | 48 +++++++++++++++++++ .../work-items/dtos/work-item-filters.dto.ts | 18 +++++++ .../dtos/work-item-list-item.dto.ts | 22 +++++++++ 5 files changed, 150 insertions(+) create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/update-work-item.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-filters.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-list-item.dto.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item.dto.ts new file mode 100644 index 000000000..f7d087717 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item.dto.ts @@ -0,0 +1,32 @@ +import type { WorkItemPriority } from '../enums/work-item-priority.enum'; +import type { WorkItemStatus } from '../enums/work-item-status.enum'; +import type { WorkItemType } from '../enums/work-item-type.enum'; +import type { BugSeverity } from '../enums/bug-severity.enum'; + +export type CreateWorkItemDto = { + sprintId?: string; + title: string; + description?: string; + type: WorkItemType; + status?: WorkItemStatus; + priority: WorkItemPriority; + externalLink?: string; + estimatedMinutes?: number; + dueDate?: string; + assigneeUserIds?: string[]; + tagIds?: string[]; + featureDetails?: { + businessValue?: string; + acceptanceCriteria?: string; + }; + issueDetails?: { + environment?: string; + reproductionSteps?: string; + }; + bugDetails?: { + severity?: BugSeverity; + environment?: string; + isReproducible?: boolean; + steps?: string; + }; +}; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/update-work-item.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/update-work-item.dto.ts new file mode 100644 index 000000000..8042c0710 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/update-work-item.dto.ts @@ -0,0 +1,30 @@ +import type { WorkItemPriority } from '../enums/work-item-priority.enum'; +import type { WorkItemStatus } from '../enums/work-item-status.enum'; +import type { BugSeverity } from '../enums/bug-severity.enum'; + +export type UpdateWorkItemDto = { + title?: string; + description?: string; + status?: WorkItemStatus; + priority?: WorkItemPriority; + externalLink?: string; + estimatedMinutes?: number; + dueDate?: string; + completedAt?: string; + assigneeUserIds?: string[]; + tagIds?: string[]; + featureDetails?: { + businessValue?: string; + acceptanceCriteria?: string; + }; + issueDetails?: { + environment?: string; + reproductionSteps?: string; + }; + bugDetails?: { + severity?: BugSeverity; + environment?: string; + isReproducible?: boolean; + steps?: string; + }; +}; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts new file mode 100644 index 000000000..b41095bd6 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts @@ -0,0 +1,48 @@ +import type { TagDto } from '../../../shared/dtos/tag.dto'; +import type { UserSummaryDto } from '../../../shared/dtos/user-summary.dto'; +import type { BugSeverity } from '../enums/bug-severity.enum'; +import type { AssignmentRole } from '../enums/assignment-role.enum'; +import type { WorkItemPriority } from '../enums/work-item-priority.enum'; +import type { WorkItemStatus } from '../enums/work-item-status.enum'; +import type { WorkItemType } from '../enums/work-item-type.enum'; + +export type WorkItemDetailDto = { + id: string; + sprintId?: string; + title: string; + description?: string; + type: WorkItemType; + status: WorkItemStatus; + priority: WorkItemPriority; + externalLink?: string; + estimatedMinutes?: number; + totalLoggedMinutes: number; + dueDate?: string; + createdAt: string; + updatedAt: string; + completedAt?: string; + createdBy: UserSummaryDto; + assignees: Array<{ + id: string; + user: UserSummaryDto; + role: AssignmentRole; + assignedAt: string; + unassignedAt?: string; + assignedByUserId?: string; + }>; + tags: TagDto[]; + featureDetails?: { + businessValue?: string; + acceptanceCriteria?: string; + }; + issueDetails?: { + environment?: string; + reproductionSteps?: string; + }; + bugDetails?: { + severity?: BugSeverity; + environment?: string; + isReproducible?: boolean; + steps?: string; + }; +}; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-filters.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-filters.dto.ts new file mode 100644 index 000000000..d66118b80 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-filters.dto.ts @@ -0,0 +1,18 @@ +import type { WorkItemPriority } from '../enums/work-item-priority.enum'; +import type { WorkItemStatus } from '../enums/work-item-status.enum'; +import type { WorkItemType } from '../enums/work-item-type.enum'; + +export type WorkItemFiltersDto = { + search?: string; + sprintId?: string; + assigneeUserId?: string; + createdByUserId?: string; + type?: WorkItemType; + status?: WorkItemStatus; + priority?: WorkItemPriority; + tagIds?: string[]; + dueDateFrom?: string; + dueDateTo?: string; + page?: number; + pageSize?: number; +}; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-list-item.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-list-item.dto.ts new file mode 100644 index 000000000..105933b01 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-list-item.dto.ts @@ -0,0 +1,22 @@ +import type { TagDto } from '../../../shared/dtos/tag.dto'; +import type { UserSummaryDto } from '../../../shared/dtos/user-summary.dto'; +import type { WorkItemPriority } from '../enums/work-item-priority.enum'; +import type { WorkItemStatus } from '../enums/work-item-status.enum'; +import type { WorkItemType } from '../enums/work-item-type.enum'; + +export type WorkItemListItemDto = { + id: string; + sprintId?: string; + title: string; + type: WorkItemType; + status: WorkItemStatus; + priority: WorkItemPriority; + estimatedMinutes?: number; + totalLoggedMinutes: number; + dueDate?: string; + createdAt: string; + updatedAt: string; + createdBy: UserSummaryDto; + assignees: UserSummaryDto[]; + tags: TagDto[]; +}; \ No newline at end of file From 69525c83431133e3543d4db07d7d726d5248bd69 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago Date: Wed, 15 Apr 2026 09:45:39 -0600 Subject: [PATCH 06/23] Mock data for development --- .../work-items/mock/work-items.mock.ts | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/work-items.mock.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/work-items.mock.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/work-items.mock.ts new file mode 100644 index 000000000..1a5f5eb05 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/work-items.mock.ts @@ -0,0 +1,147 @@ +import type { WorkItemDetailDto } from '../dtos/work-item-detail.dto'; + +export const mockWorkItems: WorkItemDetailDto[] = [ + { + id: 'wrk-001', + sprintId: 'spr-001', + title: 'Build work item board UI', + description: 'Create the first kanban-style board for visualizing work items.', + type: 'FEATURE', + status: 'IN_PROGRESS', + priority: 'HIGH', + externalLink: 'https://example.com/specs/board-ui', + estimatedMinutes: 720, + totalLoggedMinutes: 360, + dueDate: '2026-04-25', + createdAt: '2026-04-10T09:00:00Z', + updatedAt: '2026-04-15T16:30:00Z', + createdBy: { + id: 'usr-001', + name: 'Bernardo Manager', + email: 'bernardo.manager@demo.com', + telegramUserId: 'tg_bernardo_manager' + }, + assignees: [ + { + id: 'asg-001', + user: { + id: 'usr-002', + name: 'Ana Developer', + email: 'ana.dev@demo.com', + telegramUserId: 'tg_ana_dev' + }, + role: 'OWNER', + assignedAt: '2026-04-10T10:00:00Z' + } + ], + tags: [ + { + id: 'tag-001', + name: 'Frontend', + color: '#3B82F6', + description: 'UI and client-side work' + } + ], + featureDetails: { + businessValue: 'Allows managers and developers to quickly visualize sprint progress.', + acceptanceCriteria: 'Board must show grouped work items by status and support filtering.' + } + }, + { + id: 'wrk-002', + sprintId: 'spr-001', + title: 'Telegram task list command fails on empty response', + description: 'Investigate why the bot returns no visible output when the task list is empty.', + type: 'BUG', + status: 'TODO', + priority: 'CRITICAL', + estimatedMinutes: 180, + totalLoggedMinutes: 0, + dueDate: '2026-04-18', + createdAt: '2026-04-14T11:00:00Z', + updatedAt: '2026-04-14T11:00:00Z', + createdBy: { + id: 'usr-001', + name: 'Bernardo Manager', + email: 'bernardo.manager@demo.com', + telegramUserId: 'tg_bernardo_manager' + }, + assignees: [ + { + id: 'asg-002', + user: { + id: 'usr-003', + name: 'Luis Developer', + email: 'luis.dev@demo.com', + telegramUserId: 'tg_luis_dev' + }, + role: 'OWNER', + assignedAt: '2026-04-14T12:00:00Z' + } + ], + tags: [ + { + id: 'tag-003', + name: 'Bug', + color: '#EF4444', + description: 'Defect or error' + }, + { + id: 'tag-004', + name: 'High Priority', + color: '#F59E0B', + description: 'Needs quick attention' + } + ], + bugDetails: { + severity: 'HIGH', + environment: 'Telegram Bot / Dev', + isReproducible: true, + steps: 'Run /todo for a user with zero active tasks.' + } + }, + { + id: 'wrk-003', + title: 'Document assignee filtering behavior', + description: 'Clarify how assignee filters should behave across board and table views.', + type: 'ISSUE', + status: 'BLOCKED', + priority: 'MEDIUM', + estimatedMinutes: 90, + totalLoggedMinutes: 45, + dueDate: '2026-04-20', + createdAt: '2026-04-12T08:30:00Z', + updatedAt: '2026-04-15T13:15:00Z', + createdBy: { + id: 'usr-002', + name: 'Ana Developer', + email: 'ana.dev@demo.com', + telegramUserId: 'tg_ana_dev' + }, + assignees: [ + { + id: 'asg-003', + user: { + id: 'usr-002', + name: 'Ana Developer', + email: 'ana.dev@demo.com', + telegramUserId: 'tg_ana_dev' + }, + role: 'OWNER', + assignedAt: '2026-04-12T09:00:00Z' + } + ], + tags: [ + { + id: 'tag-002', + name: 'Backend', + color: '#10B981', + description: 'API and service work' + } + ], + issueDetails: { + environment: 'Web Portal / Requirements', + reproductionSteps: 'Compare board filtering and list filtering expected behavior.' + } + } +]; \ No newline at end of file From 5a97e86fafdc35261223abb44fe7c8be2634b4b5 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago Date: Wed, 15 Apr 2026 10:02:01 -0600 Subject: [PATCH 07/23] Work Item models and service --- .../work-items/dtos/create-work-item.dto.ts | 9 +- .../work-items/dtos/work-item-detail.dto.ts | 20 ++- .../work-items/model/bug-details.model.ts | 8 + .../work-items/model/feature-details.model.ts | 4 + .../work-items/model/issue-details.model.ts | 4 + .../model/work-item-assignee.model.ts | 11 ++ .../work-items/model/work-item.model.ts | 32 ++++ .../work-items/services/work-item.service.ts | 162 ++++++++++++++++++ 8 files changed, 234 insertions(+), 16 deletions(-) create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/model/bug-details.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/model/feature-details.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/model/issue-details.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-assignee.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item.service.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item.dto.ts index f7d087717..c9efd9be8 100644 --- a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item.dto.ts +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item.dto.ts @@ -1,7 +1,7 @@ import type { WorkItemPriority } from '../enums/work-item-priority.enum'; import type { WorkItemStatus } from '../enums/work-item-status.enum'; import type { WorkItemType } from '../enums/work-item-type.enum'; -import type { BugSeverity } from '../enums/bug-severity.enum'; +import { BugDetails } from "../model/bug-details.model"; export type CreateWorkItemDto = { sprintId?: string; @@ -23,10 +23,5 @@ export type CreateWorkItemDto = { environment?: string; reproductionSteps?: string; }; - bugDetails?: { - severity?: BugSeverity; - environment?: string; - isReproducible?: boolean; - steps?: string; - }; + bugDetails?: BugDetails; }; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts index b41095bd6..e25232042 100644 --- a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts @@ -22,14 +22,7 @@ export type WorkItemDetailDto = { updatedAt: string; completedAt?: string; createdBy: UserSummaryDto; - assignees: Array<{ - id: string; - user: UserSummaryDto; - role: AssignmentRole; - assignedAt: string; - unassignedAt?: string; - assignedByUserId?: string; - }>; + assignees: Array; tags: TagDto[]; featureDetails?: { businessValue?: string; @@ -45,4 +38,13 @@ export type WorkItemDetailDto = { isReproducible?: boolean; steps?: string; }; -}; \ No newline at end of file +}; + +export type Assignee = { + id: string; + user: UserSummaryDto; + role: AssignmentRole; + assignedAt: string; + unassignedAt?: string; + assignedByUserId?: string; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/bug-details.model.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/bug-details.model.ts new file mode 100644 index 000000000..971856e92 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/bug-details.model.ts @@ -0,0 +1,8 @@ +import type { BugSeverity } from '../enums/bug-severity.enum'; + +export type BugDetails = { + severity?: BugSeverity; + environment?: string; + isReproducible?: boolean; + steps?: string; +}; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/feature-details.model.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/feature-details.model.ts new file mode 100644 index 000000000..3b05a8118 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/feature-details.model.ts @@ -0,0 +1,4 @@ +export type FeatureDetails = { + businessValue?: string; + acceptanceCriteria?: string; +}; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/issue-details.model.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/issue-details.model.ts new file mode 100644 index 000000000..b97f3c343 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/issue-details.model.ts @@ -0,0 +1,4 @@ +export type IssueDetails = { + environment?: string; + reproductionSteps?: string; +}; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-assignee.model.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-assignee.model.ts new file mode 100644 index 000000000..40390bb02 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-assignee.model.ts @@ -0,0 +1,11 @@ +import type { AssignmentRole } from '../enums/assignment-role.enum'; +import type { UserSummary } from '../../../shared/models/user-summary.model'; + +export type WorkItemAssignee = { + id: string; + user: UserSummary; + role: AssignmentRole; + assignedAt: string; + unassignedAt?: string; + assignedByUserId?: string; +}; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item.model.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item.model.ts new file mode 100644 index 000000000..b0fa2591a --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item.model.ts @@ -0,0 +1,32 @@ +import type { Tag } from '../../../shared/models/tag.model'; +import type { UserSummary } from '../../../shared/models/user-summary.model'; +import type { WorkItemPriority } from '../enums/work-item-priority.enum'; +import type { WorkItemStatus } from '../enums/work-item-status.enum'; +import type { WorkItemType } from '../enums/work-item-type.enum'; +import type { BugDetails } from './bug-details.model'; +import type { FeatureDetails } from './feature-details.model'; +import type { IssueDetails } from './issue-details.model'; +import type { WorkItemAssignee } from './work-item-assignee.model'; + +export type WorkItem = { + id: string; + sprintId?: string; + title: string; + description?: string; + type: WorkItemType; + status: WorkItemStatus; + priority: WorkItemPriority; + externalLink?: string; + estimatedMinutes?: number; + totalLoggedMinutes: number; + dueDate?: string; + createdAt: string; + updatedAt: string; + completedAt?: string; + createdBy: UserSummary; + assignees: WorkItemAssignee[]; + tags: Tag[]; + featureDetails?: FeatureDetails; + issueDetails?: IssueDetails; + bugDetails?: BugDetails; +}; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item.service.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item.service.ts new file mode 100644 index 000000000..6f32a8320 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item.service.ts @@ -0,0 +1,162 @@ +import type { ApiResult } from '../../../shared/dtos/api-result.dto'; +import type { PagedResult } from '../../../shared/dtos/paged-result.dto'; +import { mockApi } from '../../../shared/services/mock-api'; +import { mockWorkItems } from '../mock/work-items.mock'; +import type { CreateWorkItemDto } from '../dtos/create-work-item.dto'; +import type { UpdateWorkItemDto } from '../dtos/update-work-item.dto'; +import type { Assignee, WorkItemDetailDto } from '../dtos/work-item-detail.dto'; +import type { WorkItemFiltersDto } from '../dtos/work-item-filters.dto'; +import type { WorkItemListItemDto } from '../dtos/work-item-list-item.dto'; +import { UserSummaryDto } from "../../../shared/dtos/user-summary.dto"; +import {WorkItem} from "../model/work-item.model"; + +function toListItemDto(item: WorkItemDetailDto): WorkItemListItemDto { + return { + id: item.id, + sprintId: item.sprintId, + title: item.title, + type: item.type, + status: item.status, + priority: item.priority, + estimatedMinutes: item.estimatedMinutes, + totalLoggedMinutes: item.totalLoggedMinutes, + dueDate: item.dueDate, + createdAt: item.createdAt, + updatedAt: item.updatedAt, + createdBy: item.createdBy, + assignees: item.assignees.map((assignment: Assignee): UserSummaryDto => assignment.user), + tags: item.tags + }; +} + +function applyFilters( + items: WorkItemDetailDto[], + filters?: WorkItemFiltersDto +): WorkItemDetailDto[] { + if (!filters) { + return items; + } + + return items.filter((item: WorkItemDetailDto): boolean => { + const matchesSearch: boolean = + !filters.search || + item.title.toLowerCase().includes(filters.search.toLowerCase()) || + (item.description ?? '').toLowerCase().includes(filters.search.toLowerCase()); + + const matchesSprint: boolean = !filters.sprintId || item.sprintId === filters.sprintId; + const matchesType: boolean = !filters.type || item.type === filters.type; + const matchesStatus: boolean = !filters.status || item.status === filters.status; + const matchesPriority: boolean = !filters.priority || item.priority === filters.priority; + + const matchesAssignee: boolean = + !filters.assigneeUserId || + item.assignees.some((assignment) => assignment.user.id === filters.assigneeUserId); + + const matchesCreatedBy: boolean = + !filters.createdByUserId || item.createdBy.id === filters.createdByUserId; + + const matchesTags: boolean = + !filters.tagIds?.length || + filters.tagIds.every((tagId) => item.tags.some((tag) => tag.id === tagId)); + + return ( + matchesSearch && + matchesSprint && + matchesType && + matchesStatus && + matchesPriority && + matchesAssignee && + matchesCreatedBy && + matchesTags + ); + }); +} + +export const workItemService = { + async getWorkItems( + filters?: WorkItemFiltersDto + ): Promise>> { + const filtered: WorkItemDetailDto[] = applyFilters(mockWorkItems, filters); + const page = filters?.page ?? 1; + const pageSize = filters?.pageSize ?? 10; + + const start = (page - 1) * pageSize; + const end = start + pageSize; + const pagedItems: WorkItemListItemDto[] = filtered.slice(start, end).map(toListItemDto); + + return mockApi({ + items: pagedItems, + total: filtered.length, + page, + pageSize, + totalPages: Math.max(1, Math.ceil(filtered.length / pageSize)) + }); + }, + + async getWorkItemById(id: string): Promise> { + const found = mockWorkItems.find((item) => item.id === id) ?? null; + + return mockApi(found); + }, + + async createWorkItem(input: CreateWorkItemDto): Promise> { + const now = new Date().toISOString(); + + const created: WorkItemDetailDto = { + id: `wrk-${crypto.randomUUID()}`, + sprintId: input.sprintId, + title: input.title, + description: input.description, + type: input.type, + status: input.status ?? 'TODO', + priority: input.priority, + externalLink: input.externalLink, + estimatedMinutes: input.estimatedMinutes, + totalLoggedMinutes: 0, + dueDate: input.dueDate, + createdAt: now, + updatedAt: now, + createdBy: { + id: 'usr-001', + name: 'Bernardo Manager', + email: 'bernardo.manager@demo.com', + telegramUserId: 'tg_bernardo_manager' + }, + assignees: [], + tags: [], + featureDetails: input.featureDetails, + issueDetails: input.issueDetails, + bugDetails: input.bugDetails + }; + + mockWorkItems.unshift(created); + + return mockApi(created); + }, + + async updateWorkItem( + id: string, + input: UpdateWorkItemDto + ): Promise> { + const index = mockWorkItems.findIndex((item) => item.id === id); + + if (index === -1) { + return mockApi(null); + } + + const current: WorkItemDetailDto = mockWorkItems[index]; + + const updated: WorkItemDetailDto = { + ...current, + ...input, + updatedAt: new Date().toISOString(), + featureDetails: input.featureDetails ?? current.featureDetails, + issueDetails: input.issueDetails ?? current.issueDetails, + bugDetails: input.bugDetails ?? current.bugDetails + }; + + mockWorkItems[index] = updated; + + return mockApi(updated); + } +}; \ No newline at end of file From 3bbe75f5c08df800fd0a1ed0e65a37f5d662c1a3 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago Date: Wed, 15 Apr 2026 10:19:30 -0600 Subject: [PATCH 08/23] Added Work Item links, comments, dtos and data service layer --- .../work-items/dtos/activity-log-item.dto.ts | 12 +++++ .../dtos/create-work-item-comment.dto.ts | 6 +++ .../dtos/create-work-item-link.dto.ts | 6 +++ .../dtos/update-work-item-comment.dto.ts | 4 ++ .../work-items/dtos/work-item-comment.dto.ts | 12 +++++ .../work-items/dtos/work-item-detail.dto.ts | 4 +- .../work-items/dtos/work-item-link.dto.ts | 16 ++++++ .../mock/mock-activity-log-items.ts | 49 +++++++++++++++++++ .../mock/mock-work-item-comments.ts | 40 +++++++++++++++ .../work-items/mock/mock-work-item-links.ts | 36 ++++++++++++++ .../model/activity-log-item.model.ts | 34 +++++++++++++ .../model/work-item-assignee.model.ts | 2 +- .../model/work-item-comment.model.ts | 13 +++++ .../work-items/model/work-item-link.model.ts | 25 ++++++++++ .../work-items/model/work-item.model.ts | 4 +- .../work-item-collaboration.service.ts | 17 +++++++ .../work-items/services/work-item.service.ts | 9 ++-- 17 files changed, 279 insertions(+), 10 deletions(-) create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/activity-log-item.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item-comment.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item-link.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/update-work-item-comment.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-comment.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-link.dto.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-activity-log-items.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-work-item-comments.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-work-item-links.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/model/activity-log-item.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-comment.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-link.model.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item-collaboration.service.ts diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/activity-log-item.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/activity-log-item.dto.ts new file mode 100644 index 000000000..4002fb5f4 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/activity-log-item.dto.ts @@ -0,0 +1,12 @@ +export interface ActivityLogItemDto { + activityId: string; + workItemId: string; + actorUserId: string; + actorName: string; + actorEmail: string | null; + actorTelegramUserId: string | null; + actionType: string; + occurredAt: string; + summary: string; + contextJson: string | null; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item-comment.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item-comment.dto.ts new file mode 100644 index 000000000..e6742cbba --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item-comment.dto.ts @@ -0,0 +1,6 @@ +export interface CreateWorkItemCommentDto { + workItemId: string; + authorUserId: string; + content: string; + parentCommentId?: string | null; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item-link.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item-link.dto.ts new file mode 100644 index 000000000..48105c944 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item-link.dto.ts @@ -0,0 +1,6 @@ +export interface CreateWorkItemLinkDto { + fromWorkItemId: string; + toWorkItemId: string; + type: string; + createdByUserId: string; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/update-work-item-comment.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/update-work-item-comment.dto.ts new file mode 100644 index 000000000..44dd528ff --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/update-work-item-comment.dto.ts @@ -0,0 +1,4 @@ +export interface UpdateWorkItemCommentDto { + commentId: string; + content: string; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-comment.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-comment.dto.ts new file mode 100644 index 000000000..6ca3e5af0 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-comment.dto.ts @@ -0,0 +1,12 @@ +export interface WorkItemCommentDto { + commentId: string; + workItemId: string; + authorUserId: string; + authorName: string; + authorEmail: string | null; + authorTelegramUserId: string | null; + parentCommentId: string | null; + content: string; + createdAt: string; + editedAt: string | null; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts index e25232042..ea0464cbf 100644 --- a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts @@ -1,5 +1,5 @@ -import type { TagDto } from '../../../shared/dtos/tag.dto'; -import type { UserSummaryDto } from '../../../shared/dtos/user-summary.dto'; +import type { TagDto } from '@/shared/dtos/tag.dto'; +import type { UserSummaryDto } from '@/shared/dtos/user-summary.dto'; import type { BugSeverity } from '../enums/bug-severity.enum'; import type { AssignmentRole } from '../enums/assignment-role.enum'; import type { WorkItemPriority } from '../enums/work-item-priority.enum'; diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-link.dto.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-link.dto.ts new file mode 100644 index 000000000..019301bd9 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-link.dto.ts @@ -0,0 +1,16 @@ +export interface WorkItemLinkDto { + linkId: string; + type: string; + fromWorkItemId: string; + fromWorkItemTitle: string; + fromWorkItemType: string; + fromWorkItemStatus: string; + fromWorkItemPriority: string; + toWorkItemId: string; + toWorkItemTitle: string; + toWorkItemType: string; + toWorkItemStatus: string; + toWorkItemPriority: string; + createdAt: string; + createdByUserId: string; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-activity-log-items.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-activity-log-items.ts new file mode 100644 index 000000000..374d88dab --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-activity-log-items.ts @@ -0,0 +1,49 @@ +import type { ActivityLogItemDto } from '@/features/work-items/dtos/activity-log-item.dto'; + +export const mockActivityLogItems: ActivityLogItemDto[] = [ + { + activityId: 'activity-001', + workItemId: 'work-item-001', + actorUserId: 'user-001', + actorName: 'Bernardo Marin', + actorEmail: 'bernardo@company.com', + actorTelegramUserId: 'bernardo_pm', + actionType: 'status_changed', + occurredAt: '2026-04-15T08:05:00Z', + summary: 'Status changed from Todo to In Progress.', + contextJson: JSON.stringify({ + fieldName: 'status', + oldValue: 'todo', + newValue: 'in_progress', + }), + }, + { + activityId: 'activity-002', + workItemId: 'work-item-001', + actorUserId: 'user-002', + actorName: 'Ana Torres', + actorEmail: 'ana@company.com', + actorTelegramUserId: 'ana_torres_dev', + actionType: 'comment_added', + occurredAt: '2026-04-15T09:10:00Z', + summary: 'Added a new comment.', + contextJson: JSON.stringify({ + commentId: 'comment-001', + }), + }, + { + activityId: 'activity-003', + workItemId: 'work-item-001', + actorUserId: 'user-001', + actorName: 'Bernardo Marin', + actorEmail: 'bernardo@company.com', + actorTelegramUserId: 'bernardo_pm', + actionType: 'link_added', + occurredAt: '2026-04-15T09:25:00Z', + summary: 'Linked this work item as blocked by another issue.', + contextJson: JSON.stringify({ + linkId: 'link-001', + relatedWorkItemId: 'work-item-004', + }), + }, +]; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-work-item-comments.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-work-item-comments.ts new file mode 100644 index 000000000..37dedcb74 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-work-item-comments.ts @@ -0,0 +1,40 @@ +import type { WorkItemCommentDto } from '@/features/work-items/dtos/work-item-comment.dto'; + +export const mockWorkItemComments: WorkItemCommentDto[] = [ + { + commentId: 'comment-001', + workItemId: 'work-item-001', + authorUserId: 'user-002', + authorName: 'Ana Torres', + authorEmail: 'ana@company.com', + authorTelegramUserId: 'ana_torres_dev', + parentCommentId: null, + content: 'I already reproduced the issue in staging. The problem appears after saving twice.', + createdAt: '2026-04-15T09:10:00Z', + editedAt: null, + }, + { + commentId: 'comment-002', + workItemId: 'work-item-001', + authorUserId: 'user-001', + authorName: 'Bernardo Marin', + authorEmail: 'bernardo@company.com', + authorTelegramUserId: 'bernardo_pm', + parentCommentId: 'comment-001', + content: 'Perfect. Please add the exact repro steps in the issue detail afterwards.', + createdAt: '2026-04-15T09:18:00Z', + editedAt: null, + }, + { + commentId: 'comment-003', + workItemId: 'work-item-002', + authorUserId: 'user-003', + authorName: 'Luis Vega', + authorEmail: 'luis@company.com', + authorTelegramUserId: 'luis_backend', + parentCommentId: null, + content: 'The endpoint contract is ready. Frontend can start consuming the mock shape.', + createdAt: '2026-04-14T16:45:00Z', + editedAt: '2026-04-14T17:00:00Z', + }, +]; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-work-item-links.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-work-item-links.ts new file mode 100644 index 000000000..af23b169b --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/mock-work-item-links.ts @@ -0,0 +1,36 @@ +import type { WorkItemLinkDto } from '@/features/work-items/dtos/work-item-link.dto'; + +export const mockWorkItemLinks: WorkItemLinkDto[] = [ + { + linkId: 'link-001', + type: 'blocks', + fromWorkItemId: 'work-item-001', + fromWorkItemTitle: 'Implement Telegram sprint summary command', + fromWorkItemType: 'feature', + fromWorkItemStatus: 'in_progress', + fromWorkItemPriority: 'high', + toWorkItemId: 'work-item-004', + toWorkItemTitle: 'Fix sprint metrics aggregation bug', + toWorkItemType: 'bug', + toWorkItemStatus: 'open', + toWorkItemPriority: 'critical', + createdAt: '2026-04-15T08:00:00Z', + createdByUserId: 'user-001', + }, + { + linkId: 'link-002', + type: 'relates_to', + fromWorkItemId: 'work-item-002', + fromWorkItemTitle: 'Create work item detail page', + fromWorkItemType: 'feature', + fromWorkItemStatus: 'todo', + fromWorkItemPriority: 'medium', + toWorkItemId: 'work-item-003', + toWorkItemTitle: 'Design comment thread card UI', + toWorkItemType: 'task', + toWorkItemStatus: 'todo', + toWorkItemPriority: 'medium', + createdAt: '2026-04-14T11:30:00Z', + createdByUserId: 'user-002', + }, +]; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/activity-log-item.model.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/activity-log-item.model.ts new file mode 100644 index 000000000..e2a02a200 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/activity-log-item.model.ts @@ -0,0 +1,34 @@ +import type { UserSummary } from '@/shared/models/user-summary.model'; + +export type ActivityActionType = + | 'work_item_created' + | 'work_item_updated' + | 'status_changed' + | 'priority_changed' + | 'assignee_added' + | 'assignee_removed' + | 'comment_added' + | 'comment_updated' + | 'link_added' + | 'time_logged' + | 'work_item_completed'; + +export interface ActivityContext { + fieldName?: string; + oldValue?: string | number | boolean | null; + newValue?: string | number | boolean | null; + commentId?: string; + linkId?: string; + relatedWorkItemId?: string; + minutesLogged?: number; +} + +export interface ActivityLogItem { + id: string; + workItemId: string; + actor: UserSummary; + actionType: ActivityActionType; + occurredAt: string; + summary: string; + context: ActivityContext | null; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-assignee.model.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-assignee.model.ts index 40390bb02..0c598175d 100644 --- a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-assignee.model.ts +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-assignee.model.ts @@ -1,5 +1,5 @@ import type { AssignmentRole } from '../enums/assignment-role.enum'; -import type { UserSummary } from '../../../shared/models/user-summary.model'; +import type { UserSummary } from '@/shared/models/user-summary.model'; export type WorkItemAssignee = { id: string; diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-comment.model.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-comment.model.ts new file mode 100644 index 000000000..a5a443a9d --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-comment.model.ts @@ -0,0 +1,13 @@ +import type { UserSummary } from '@/shared/models/user-summary.model'; + +export interface WorkItemComment { + id: string; + workItemId: string; + author: UserSummary; + parentCommentId: string | null; + content: string; + createdAt: string; + editedAt: string | null; + isEdited: boolean; + replies: WorkItemComment[]; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-link.model.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-link.model.ts new file mode 100644 index 000000000..9883ca7b0 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-link.model.ts @@ -0,0 +1,25 @@ +export type WorkItemLinkType = + | 'blocks' + | 'is_blocked_by' + | 'relates_to' + | 'duplicates' + | 'is_duplicated_by' + | 'depends_on' + | 'is_dependency_of'; + +export interface RelatedWorkItemSummary { + id: string; + title: string; + type: 'feature' | 'issue' | 'bug' | 'task'; + status: string; + priority: string; +} + +export interface WorkItemLink { + id: string; + type: WorkItemLinkType; + fromWorkItem: RelatedWorkItemSummary; + toWorkItem: RelatedWorkItemSummary; + createdAt: string; + createdByUserId: string; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item.model.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item.model.ts index b0fa2591a..a14bc443f 100644 --- a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item.model.ts +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item.model.ts @@ -1,5 +1,5 @@ -import type { Tag } from '../../../shared/models/tag.model'; -import type { UserSummary } from '../../../shared/models/user-summary.model'; +import type { Tag } from '@/shared/models/tag.model'; +import type { UserSummary } from '@/shared/models/user-summary.model'; import type { WorkItemPriority } from '../enums/work-item-priority.enum'; import type { WorkItemStatus } from '../enums/work-item-status.enum'; import type { WorkItemType } from '../enums/work-item-type.enum'; diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item-collaboration.service.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item-collaboration.service.ts new file mode 100644 index 000000000..f17ceaff8 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item-collaboration.service.ts @@ -0,0 +1,17 @@ +import type { ActivityLogItemDto } from '@/features/work-items/dtos/activity-log-item.dto'; +import type { CreateWorkItemCommentDto } from '@/features/work-items/dtos/create-work-item-comment.dto'; +import type { CreateWorkItemLinkDto } from '@/features/work-items/dtos/create-work-item-link.dto'; +import type { UpdateWorkItemCommentDto } from '@/features/work-items/dtos/update-work-item-comment.dto'; +import type { WorkItemCommentDto } from '@/features/work-items/dtos/work-item-comment.dto'; +import type { WorkItemLinkDto } from '@/features/work-items/dtos/work-item-link.dto'; + +export interface WorkItemCollaborationService { + getCommentsByWorkItemId(workItemId: string): Promise; + createComment(input: CreateWorkItemCommentDto): Promise; + updateComment(input: UpdateWorkItemCommentDto): Promise; + + getLinksByWorkItemId(workItemId: string): Promise; + createLink(input: CreateWorkItemLinkDto): Promise; + + getActivityByWorkItemId(workItemId: string): Promise; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item.service.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item.service.ts index 6f32a8320..2a51c73ea 100644 --- a/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item.service.ts +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item.service.ts @@ -1,14 +1,13 @@ -import type { ApiResult } from '../../../shared/dtos/api-result.dto'; -import type { PagedResult } from '../../../shared/dtos/paged-result.dto'; -import { mockApi } from '../../../shared/services/mock-api'; +import type { ApiResult } from '@/shared/dtos/api-result.dto'; +import type { PagedResult } from '@/shared/dtos/paged-result.dto'; +import { mockApi } from '@/shared/services/mock-api'; import { mockWorkItems } from '../mock/work-items.mock'; import type { CreateWorkItemDto } from '../dtos/create-work-item.dto'; import type { UpdateWorkItemDto } from '../dtos/update-work-item.dto'; import type { Assignee, WorkItemDetailDto } from '../dtos/work-item-detail.dto'; import type { WorkItemFiltersDto } from '../dtos/work-item-filters.dto'; import type { WorkItemListItemDto } from '../dtos/work-item-list-item.dto'; -import { UserSummaryDto } from "../../../shared/dtos/user-summary.dto"; -import {WorkItem} from "../model/work-item.model"; +import { UserSummaryDto } from "@/shared/dtos/user-summary.dto"; function toListItemDto(item: WorkItemDetailDto): WorkItemListItemDto { return { From a68b7dbc1fd2ccab0ef57da124038140c731b7a6 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago Date: Wed, 15 Apr 2026 11:23:39 -0600 Subject: [PATCH 09/23] Work item mappers --- .../mappers/activity-log-item.mapper.ts | 67 +++++++++++ .../mappers/work-item-comment.mapper.ts | 72 ++++++++++++ .../mappers/work-item-link.mapper.ts | 82 ++++++++++++++ .../src/shared/mappers/user-summary.mapper.ts | 49 ++++++++ .../src/shared/models/user-summary.model.ts | 4 +- .../backend/src/main/frontend/tsconfig.json | 105 ++++++++++++++++++ 6 files changed, 377 insertions(+), 2 deletions(-) create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/activity-log-item.mapper.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/work-item-comment.mapper.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/work-item-link.mapper.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/shared/mappers/user-summary.mapper.ts create mode 100644 MtdrSpring/backend/src/main/frontend/tsconfig.json diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/activity-log-item.mapper.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/activity-log-item.mapper.ts new file mode 100644 index 000000000..90c3a9977 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/activity-log-item.mapper.ts @@ -0,0 +1,67 @@ +import type { ActivityLogItemDto } from '@/features/work-items/dtos/activity-log-item.dto'; +import type { + ActivityActionType, + ActivityContext, + ActivityLogItem, +} from '@/features/work-items/model/activity-log-item.model'; +import { mapUserSummaryFromSource } from '@/shared/mappers/user-summary.mapper'; + +const ALLOWED_ACTIVITY_ACTION_TYPES: ActivityActionType[] = [ + 'work_item_created', + 'work_item_updated', + 'status_changed', + 'priority_changed', + 'assignee_added', + 'assignee_removed', + 'comment_added', + 'comment_updated', + 'link_added', + 'time_logged', + 'work_item_completed', +]; + +function isActivityActionType(value: string): value is ActivityActionType { + return ALLOWED_ACTIVITY_ACTION_TYPES.includes(value as ActivityActionType); +} + +function parseActivityContext(contextJson: string | null): ActivityContext | null { + if (!contextJson) { + return null; + } + + try { + const parsed = JSON.parse(contextJson); + + if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { + return null; + } + + return parsed as ActivityContext; + } catch { + return null; + } +} + +export function mapActivityLogItemDtoToModel(dto: ActivityLogItemDto): ActivityLogItem { + if (!isActivityActionType(dto.actionType)) { + throw new Error(`Unsupported activity action type: ${dto.actionType}`); + } + + return { + id: dto.activityId, + workItemId: dto.workItemId, + actor: mapUserSummaryFromSource(dto), + actionType: dto.actionType, + occurredAt: dto.occurredAt, + summary: dto.summary, + context: parseActivityContext(dto.contextJson), + }; +} + +export function mapActivityLogItemDtosToModels(dtos: ActivityLogItemDto[]): ActivityLogItem[] { + return [...dtos] + .map(mapActivityLogItemDtoToModel) + .sort((a, b) => { + return new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime(); + }); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/work-item-comment.mapper.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/work-item-comment.mapper.ts new file mode 100644 index 000000000..768342c8b --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/work-item-comment.mapper.ts @@ -0,0 +1,72 @@ +import type { WorkItemCommentDto } from '@/features/work-items/dtos/work-item-comment.dto'; +import type { WorkItemComment } from '@/features/work-items/model/work-item-comment.model'; +import { mapUserSummaryFromSource } from '@/shared/mappers/user-summary.mapper'; + +function sortCommentsByCreatedAtAsc(comments: WorkItemComment[]): WorkItemComment[] { + return [...comments].sort((a, b) => { + return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); + }); +} + +export function mapWorkItemCommentDtoToModel(dto: WorkItemCommentDto): WorkItemComment { + return { + id: dto.commentId, + workItemId: dto.workItemId, + author: mapUserSummaryFromSource(dto), + parentCommentId: dto.parentCommentId, + content: dto.content, + createdAt: dto.createdAt, + editedAt: dto.editedAt, + isEdited: dto.editedAt !== null, + replies: [], + }; +} + +export function mapWorkItemCommentDtosToTree(dtos: WorkItemCommentDto[]): WorkItemComment[] { + const sortedDtos = [...dtos].sort((a, b) => { + return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); + }); + + const commentMap = new Map( + sortedDtos.map((dto) => { + const comment = mapWorkItemCommentDtoToModel(dto); + + return [comment.id, comment]; + }), + ); + + const rootComments: WorkItemComment[] = []; + + for (const dto of sortedDtos) { + const currentComment = commentMap.get(dto.commentId); + + if (!currentComment) { + continue; + } + + if (!dto.parentCommentId) { + rootComments.push(currentComment); + continue; + } + + const parentComment = commentMap.get(dto.parentCommentId); + + if (!parentComment) { + rootComments.push(currentComment); + continue; + } + + parentComment.replies.push(currentComment); + } + + const sortRepliesRecursively = (comments: WorkItemComment[]): WorkItemComment[] => { + return sortCommentsByCreatedAtAsc(comments).map((comment) => { + return { + ...comment, + replies: sortRepliesRecursively(comment.replies), + }; + }); + }; + + return sortRepliesRecursively(rootComments); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/work-item-link.mapper.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/work-item-link.mapper.ts new file mode 100644 index 000000000..64383e7c5 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mappers/work-item-link.mapper.ts @@ -0,0 +1,82 @@ +import type { WorkItemLinkDto } from '@/features/work-items/dtos/work-item-link.dto'; +import type { + RelatedWorkItemSummary, + WorkItemLink, + WorkItemLinkType, +} from '@/features/work-items/model/work-item-link.model'; + +const ALLOWED_WORK_ITEM_LINK_TYPES: WorkItemLinkType[] = [ + 'blocks', + 'is_blocked_by', + 'relates_to', + 'duplicates', + 'is_duplicated_by', + 'depends_on', + 'is_dependency_of', +]; + +const ALLOWED_RELATED_WORK_ITEM_TYPES: RelatedWorkItemSummary['type'][] = [ + 'feature', + 'issue', + 'bug', + 'task', +]; + +function isWorkItemLinkType(value: string): value is WorkItemLinkType { + return ALLOWED_WORK_ITEM_LINK_TYPES.includes(value as WorkItemLinkType); +} + +function isRelatedWorkItemType(value: string): value is RelatedWorkItemSummary['type'] { + return ALLOWED_RELATED_WORK_ITEM_TYPES.includes(value as RelatedWorkItemSummary['type']); +} + +function mapRelatedWorkItemSummary(params: { + id: string; + title: string; + type: string; + status: string; + priority: string; +}): RelatedWorkItemSummary { + if (!isRelatedWorkItemType(params.type)) { + throw new Error(`Unsupported related work item type: ${params.type}`); + } + + return { + id: params.id, + title: params.title, + type: params.type, + status: params.status, + priority: params.priority, + }; +} + +export function mapWorkItemLinkDtoToModel(dto: WorkItemLinkDto): WorkItemLink { + if (!isWorkItemLinkType(dto.type)) { + throw new Error(`Unsupported work item link type: ${dto.type}`); + } + + return { + id: dto.linkId, + type: dto.type, + fromWorkItem: mapRelatedWorkItemSummary({ + id: dto.fromWorkItemId, + title: dto.fromWorkItemTitle, + type: dto.fromWorkItemType, + status: dto.fromWorkItemStatus, + priority: dto.fromWorkItemPriority, + }), + toWorkItem: mapRelatedWorkItemSummary({ + id: dto.toWorkItemId, + title: dto.toWorkItemTitle, + type: dto.toWorkItemType, + status: dto.toWorkItemStatus, + priority: dto.toWorkItemPriority, + }), + createdAt: dto.createdAt, + createdByUserId: dto.createdByUserId, + }; +} + +export function mapWorkItemLinkDtosToModels(dtos: WorkItemLinkDto[]): WorkItemLink[] { + return dtos.map(mapWorkItemLinkDtoToModel); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/shared/mappers/user-summary.mapper.ts b/MtdrSpring/backend/src/main/frontend/src/shared/mappers/user-summary.mapper.ts new file mode 100644 index 000000000..4861f9b2d --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/shared/mappers/user-summary.mapper.ts @@ -0,0 +1,49 @@ +import type { UserSummary } from '@/shared/models/user-summary.model'; + +interface UserSummarySource { + authorUserId?: string; + authorName?: string; + authorEmail?: string | null; + authorTelegramUserId?: string | null; + actorUserId?: string; + actorName?: string; + actorEmail?: string | null; + actorTelegramUserId?: string | null; + userId?: string; + userName?: string; + userEmail?: string | null; + userTelegramUserId?: string | null; +} + +export function mapUserSummaryFromSource(source: UserSummarySource): UserSummary { + const id = + source.authorUserId ?? + source.actorUserId ?? + source.userId ?? + ''; + + const name = + source.authorName ?? + source.actorName ?? + source.userName ?? + ''; + + const email = + source.authorEmail ?? + source.actorEmail ?? + source.userEmail ?? + null; + + const telegramUserId = + source.authorTelegramUserId ?? + source.actorTelegramUserId ?? + source.userTelegramUserId ?? + null; + + return { + id, + name, + email, + telegramUserId, + }; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/shared/models/user-summary.model.ts b/MtdrSpring/backend/src/main/frontend/src/shared/models/user-summary.model.ts index faf2c61d2..a1611870f 100644 --- a/MtdrSpring/backend/src/main/frontend/src/shared/models/user-summary.model.ts +++ b/MtdrSpring/backend/src/main/frontend/src/shared/models/user-summary.model.ts @@ -1,6 +1,6 @@ export type UserSummary = { id: string name: string - email?: string - telegramUserId?: string + email?: string | null + telegramUserId?: string | null } \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/tsconfig.json b/MtdrSpring/backend/src/main/frontend/tsconfig.json new file mode 100644 index 000000000..84ad7aecf --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/tsconfig.json @@ -0,0 +1,105 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "lib": ["DOM", "DOM.Iterable", "ESNext"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "jsx": "react-jsx", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "ESNext", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "paths": { + "@/*": ["./src/*"] + }, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} From e33c66bb680152ecc8231e6406d835c3812687f8 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago Date: Wed, 15 Apr 2026 12:46:20 -0600 Subject: [PATCH 10/23] added tailwind --- MtdrSpring/backend/MyTodoList.iml | 130 - .../backend/src/main/frontend/craco.config.js | 16 + .../src/main/frontend/package-lock.json | 2965 ++++++++++++++--- .../backend/src/main/frontend/package.json | 9 +- .../backend/src/main/frontend/src/App.js | 2 + .../backend/src/main/frontend/src/index.css | 685 +--- 6 files changed, 2575 insertions(+), 1232 deletions(-) delete mode 100644 MtdrSpring/backend/MyTodoList.iml create mode 100644 MtdrSpring/backend/src/main/frontend/craco.config.js diff --git a/MtdrSpring/backend/MyTodoList.iml b/MtdrSpring/backend/MyTodoList.iml deleted file mode 100644 index c040de809..000000000 --- a/MtdrSpring/backend/MyTodoList.iml +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/craco.config.js b/MtdrSpring/backend/src/main/frontend/craco.config.js new file mode 100644 index 000000000..c92370e1d --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/craco.config.js @@ -0,0 +1,16 @@ +module.exports = { + style: { + postcss: { + mode: "extends", + loaderOptions: { + postcssOptions: { + ident: 'postcss', + plugins: [ + require('tailwindcss'), + require('autoprefixer'), + ], + }, + }, + }, + }, +}; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/package-lock.json b/MtdrSpring/backend/src/main/frontend/package-lock.json index 95581a441..5330eaa09 100644 --- a/MtdrSpring/backend/src/main/frontend/package-lock.json +++ b/MtdrSpring/backend/src/main/frontend/package-lock.json @@ -8,11 +8,13 @@ "name": "todolistapp-react", "version": "0.1.0", "dependencies": { + "@craco/craco": "^7.1.0", "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", "@mui/icons-material": "^5.8.0", "@mui/material": "^5.8.0", "@mui/styles": "^5.7.0", + "@tailwindcss/vite": "^4.2.2", "moment": "^2.29.3", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -21,6 +23,9 @@ "recharts": "^2.1.16" }, "devDependencies": { + "autoprefixer": "^10.5.0", + "postcss": "^8.5.10", + "tailwindcss": "^3.4.19", "typescript": "~4.9.5" } }, @@ -28,6 +33,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -2019,6 +2025,52 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, + "node_modules/@craco/craco": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@craco/craco/-/craco-7.1.0.tgz", + "integrity": "sha512-oRAcPIKYrfPXp9rSzlsDNeOaVtDiKhoyqSXUoqiK24jCkHr4T8m/a2f74yXIzCbIheoUWDOIfWZyRgFgT+cpqA==", + "license": "Apache-2.0", + "dependencies": { + "autoprefixer": "^10.4.12", + "cosmiconfig": "^7.0.1", + "cosmiconfig-typescript-loader": "^1.0.0", + "cross-spawn": "^7.0.3", + "lodash": "^4.17.21", + "semver": "^7.3.7", + "webpack-merge": "^5.8.0" + }, + "bin": { + "craco": "dist/bin/craco.js" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "react-scripts": "^5.0.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@csstools/normalize.css": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", @@ -2289,6 +2341,37 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.11.0", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", @@ -3217,16 +3300,23 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, "node_modules/@jridgewell/resolve-uri": { @@ -3237,14 +3327,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/source-map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", @@ -3255,24 +3337,21 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -3559,6 +3638,24 @@ "react": "^17.0.0 || ^18.0.0" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -3619,6 +3716,16 @@ "node": ">= 8" } }, + "node_modules/@oxc-project/types": { + "version": "0.124.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", + "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.10", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", @@ -3685,6 +3792,270 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", + "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", + "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", + "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "license": "MIT", + "peer": true + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -4003,6 +4374,293 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@tailwindcss/node": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", + "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.2" + } + }, + "node_modules/@tailwindcss/node/node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@tailwindcss/node/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/@tailwindcss/node/node_modules/tailwindcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", + "license": "MIT" + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz", + "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-x64": "4.2.2", + "@tailwindcss/oxide-freebsd-x64": "4.2.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-x64-musl": "4.2.2", + "@tailwindcss/oxide-wasm32-wasi": "4.2.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz", + "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz", + "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz", + "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz", + "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz", + "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz", + "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz", + "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz", + "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz", + "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz", + "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz", + "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz", + "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.2.tgz", + "integrity": "sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.2.2", + "@tailwindcss/oxide": "4.2.2", + "tailwindcss": "4.2.2" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@tailwindcss/vite/node_modules/tailwindcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", + "license": "MIT" + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -4019,6 +4677,40 @@ "node": ">=10.13.0" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/babel__core": { "version": "7.20.1", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", @@ -4238,9 +4930,13 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "node_modules/@types/node": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", - "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==" + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -4763,9 +5459,10 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -4954,7 +5651,8 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", @@ -4971,7 +5669,8 @@ "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==" + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" }, "node_modules/argparse": { "version": "1.0.10", @@ -5125,9 +5824,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", "funding": [ { "type": "opencollective", @@ -5136,14 +5835,18 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -5468,6 +6171,18 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.19.tgz", + "integrity": "sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -5589,11 +6304,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -5605,9 +6321,9 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, "node_modules/browserslist": { - "version": "4.21.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.8.tgz", - "integrity": "sha512-j+7xYe+v+q2Id9qbBeCI8WX5NmZSRe8es1+0xntD/+gaWXznP8tFEkv5IgSaHf5dS1YwVMbX/4W6m937mj+wQw==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "funding": [ { "type": "opencollective", @@ -5622,11 +6338,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001502", - "electron-to-chromium": "^1.4.428", - "node-releases": "^2.0.12", - "update-browserslist-db": "^1.0.11" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -5711,6 +6429,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", "engines": { "node": ">= 6" } @@ -5727,9 +6446,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001502", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001502.tgz", - "integrity": "sha512-AZ+9tFXw1sS0o0jcpJQIXvFTOB/xGiQ4OQ2t98QX3NDn2EZTSRBC801gxrsGgViuq2ak/NLkNgSNEPtCr5lfKg==", + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", "funding": [ { "type": "opencollective", @@ -5743,7 +6462,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/case-sensitive-paths-webpack-plugin": { "version": "2.4.0", @@ -5788,15 +6508,10 @@ "integrity": "sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==" }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -5809,6 +6524,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -5886,6 +6604,20 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -6134,6 +6866,40 @@ "node": ">=10" } }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-1.0.9.tgz", + "integrity": "sha512-tRuMRhxN4m1Y8hP9SNYfz7jRwt8lZdWxdjg/ohg5esKmsndJIn4yT96oJVcf5x0eA11taXl+sIp+ielu529k6g==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^7", + "ts-node": "^10.7.0" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=7", + "typescript": ">=3" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -6498,6 +7264,15 @@ "postcss": "^8.2.15" } }, + "node_modules/cssnano/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/csso": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", @@ -6767,6 +7542,15 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -6812,7 +7596,17 @@ "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } }, "node_modules/diff-sequences": { "version": "27.5.1", @@ -6836,7 +7630,8 @@ "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" }, "node_modules/dns-equal": { "version": "1.0.0", @@ -6999,9 +7794,10 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.428", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.428.tgz", - "integrity": "sha512-L7uUknyY286of0AYC8CKfgWstD0Smk2DvHDi9F0GWQhSH90Bzi7iDrmCbZKz75tYJxeGSAc7TYeKpmbjMDoh1w==" + "version": "1.5.336", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.336.tgz", + "integrity": "sha512-AbH9q9J455r/nLmdNZes0G0ZKcRX73FicwowalLs6ijwOmCJSRRrLX63lcAlzy9ux3dWK1w1+1nsBJEWN11hcQ==", + "license": "ISC" }, "node_modules/emittery": { "version": "0.8.1", @@ -7036,12 +7832,13 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" @@ -7123,6 +7920,15 @@ "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", @@ -7166,9 +7972,10 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -8059,15 +8866,16 @@ } }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -8187,9 +8995,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -8263,6 +9072,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -8463,6 +9281,15 @@ "node": ">=6" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", @@ -8485,15 +9312,16 @@ } }, "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "license": "MIT", "engines": { "node": "*" }, "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" + "type": "github", + "url": "https://github.com/sponsors/rawify" } }, "node_modules/fresh": { @@ -8528,10 +9356,11 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -8541,9 +9370,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -8874,6 +9707,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -9345,11 +10190,15 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9443,6 +10292,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -9488,6 +10338,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -9629,6 +10491,15 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -11679,9 +12550,10 @@ } }, "node_modules/jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", "bin": { "jiti": "bin/jiti.js" } @@ -11969,6 +12841,255 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -12104,6 +13225,12 @@ "semver": "bin/semver.js" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "license": "ISC" + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -12163,11 +13290,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -12343,6 +13471,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -12350,15 +13479,16 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -12412,9 +13542,10 @@ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -12424,14 +13555,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", @@ -12482,6 +13605,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", "engines": { "node": ">= 6" } @@ -12827,9 +13951,10 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -12846,6 +13971,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -12985,9 +14111,9 @@ } }, "node_modules/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "funding": [ { "type": "opencollective", @@ -13002,10 +14128,11 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -13383,6 +14510,7 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -13404,19 +14532,26 @@ } }, "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" }, "engines": { "node": "^12 || ^14 || >= 16" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.4.21" } @@ -13441,39 +14576,57 @@ } }, "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" + "lilconfig": "^3.1.1" }, "engines": { - "node": ">= 14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">= 18" }, "peerDependencies": { + "jiti": ">=1.21.0", "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { + "jiti": { + "optional": true + }, "postcss": { "optional": true }, - "ts-node": { + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } }, - "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", "engines": { - "node": ">= 14" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/postcss-loader": { @@ -13667,19 +14820,26 @@ } }, "node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.11" + "postcss-selector-parser": "^6.1.1" }, "engines": { "node": ">=12.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.2.14" } @@ -14065,9 +15225,10 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -14722,6 +15883,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", "dependencies": { "pify": "^2.3.0" } @@ -14949,17 +16111,22 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", "dependencies": { - "is-core-module": "^2.11.0", + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -15086,6 +16253,40 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rolldown": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", + "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oxc-project/types": "=0.124.0", + "@rolldown/pluginutils": "1.0.0-rc.15" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-x64": "1.0.0-rc.15", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + } + }, "node_modules/rollup": { "version": "2.79.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", @@ -15499,6 +16700,18 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -15581,9 +16794,10 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -15900,16 +17114,17 @@ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, "node_modules/sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", - "glob": "7.1.6", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { @@ -15917,36 +17132,18 @@ "sucrase-node": "bin/sucrase-node" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/sucrase/node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", "engines": { "node": ">= 6" } }, - "node_modules/sucrase/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -16091,33 +17288,33 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "node_modules/tailwindcss": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", - "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", - "chokidar": "^3.5.3", + "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", @@ -16127,12 +17324,29 @@ "node": ">=14.0.0" } }, + "node_modules/tailwindcss/node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz", + "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==", + "license": "MIT", "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/temp-dir": { @@ -16263,6 +17477,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", "dependencies": { "any-promise": "^1.0.0" } @@ -16271,6 +17486,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -16293,6 +17509,51 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -16310,6 +17571,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -16366,7 +17628,69 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "license": "MIT" }, "node_modules/tsconfig-paths": { "version": "3.14.2", @@ -16512,6 +17836,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "license": "MIT" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -16590,9 +17920,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "funding": [ { "type": "opencollective", @@ -16607,9 +17937,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -16675,6 +18006,12 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "license": "MIT" + }, "node_modules/v8-to-istanbul": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", @@ -16704,6 +18041,97 @@ "node": ">= 0.8" } }, + "node_modules/vite": { + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", + "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", + "license": "MIT", + "peer": true, + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.15", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -17039,6 +18467,20 @@ "node": ">=10.13.0" } }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", @@ -17178,6 +18620,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "license": "MIT" + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -17586,14 +19034,6 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, - "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/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -17619,6 +19059,15 @@ "node": ">=10" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -18964,6 +20413,39 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, + "@craco/craco": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@craco/craco/-/craco-7.1.0.tgz", + "integrity": "sha512-oRAcPIKYrfPXp9rSzlsDNeOaVtDiKhoyqSXUoqiK24jCkHr4T8m/a2f74yXIzCbIheoUWDOIfWZyRgFgT+cpqA==", + "requires": { + "autoprefixer": "^10.4.12", + "cosmiconfig": "^7.0.1", + "cosmiconfig-typescript-loader": "^1.0.0", + "cross-spawn": "^7.0.3", + "lodash": "^4.17.21", + "semver": "^7.3.7", + "webpack-merge": "^5.8.0" + } + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@csstools/normalize.css": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", @@ -19090,6 +20572,34 @@ "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", "requires": {} }, + "@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "optional": true, + "requires": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "optional": true, + "requires": { + "tslib": "^2.4.0" + } + }, + "@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "optional": true, + "requires": { + "tslib": "^2.4.0" + } + }, "@emotion/babel-plugin": { "version": "11.11.0", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", @@ -19779,24 +21289,27 @@ } }, "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, "@jridgewell/resolve-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" }, "@jridgewell/source-map": { "version": "0.3.3", @@ -19808,24 +21321,17 @@ } }, "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" }, "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - } + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@leichtgewicht/ip-codec": { @@ -19958,6 +21464,15 @@ "react-is": "^18.2.0" } }, + "@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "optional": true, + "requires": { + "@tybys/wasm-util": "^0.10.1" + } + }, "@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -20005,6 +21520,12 @@ "fastq": "^1.6.0" } }, + "@oxc-project/types": { + "version": "0.124.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", + "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "peer": true + }, "@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.10", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", @@ -20033,6 +21554,122 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, + "@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "optional": true, + "peer": true + }, + "@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "optional": true, + "peer": true + }, + "@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "optional": true, + "peer": true + }, + "@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "optional": true, + "peer": true + }, + "@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", + "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "optional": true, + "peer": true + }, + "@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "optional": true, + "peer": true + }, + "@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "optional": true, + "peer": true + }, + "@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "optional": true, + "peer": true + }, + "@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "optional": true, + "peer": true + }, + "@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "optional": true, + "peer": true + }, + "@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "optional": true, + "peer": true + }, + "@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "optional": true, + "peer": true + }, + "@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", + "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "optional": true, + "peer": true, + "requires": { + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.3" + } + }, + "@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "optional": true, + "peer": true + }, + "@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "optional": true, + "peer": true + }, + "@rolldown/pluginutils": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", + "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "peer": true + }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -20227,6 +21864,156 @@ "loader-utils": "^2.0.0" } }, + "@tailwindcss/node": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", + "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==", + "requires": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.2" + }, + "dependencies": { + "jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==" + }, + "magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "tailwindcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==" + } + } + }, + "@tailwindcss/oxide": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz", + "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==", + "requires": { + "@tailwindcss/oxide-android-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-x64": "4.2.2", + "@tailwindcss/oxide-freebsd-x64": "4.2.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-x64-musl": "4.2.2", + "@tailwindcss/oxide-wasm32-wasi": "4.2.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" + } + }, + "@tailwindcss/oxide-android-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz", + "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==", + "optional": true + }, + "@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz", + "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==", + "optional": true + }, + "@tailwindcss/oxide-darwin-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz", + "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==", + "optional": true + }, + "@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz", + "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==", + "optional": true + }, + "@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz", + "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==", + "optional": true + }, + "@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz", + "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==", + "optional": true + }, + "@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz", + "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==", + "optional": true + }, + "@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz", + "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==", + "optional": true + }, + "@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz", + "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==", + "optional": true + }, + "@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz", + "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==", + "optional": true, + "requires": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + } + }, + "@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz", + "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==", + "optional": true + }, + "@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz", + "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==", + "optional": true + }, + "@tailwindcss/vite": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.2.tgz", + "integrity": "sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==", + "requires": { + "@tailwindcss/node": "4.2.2", + "@tailwindcss/oxide": "4.2.2", + "tailwindcss": "4.2.2" + }, + "dependencies": { + "tailwindcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==" + } + } + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -20237,6 +22024,35 @@ "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" }, + "@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==" + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" + }, + "@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "optional": true, + "requires": { + "tslib": "^2.4.0" + } + }, "@types/babel__core": { "version": "7.20.1", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", @@ -20450,9 +22266,12 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "@types/node": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", - "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==" + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "requires": { + "undici-types": "~7.19.0" + } }, "@types/parse-json": { "version": "4.0.0", @@ -20869,9 +22688,9 @@ } }, "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==" + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==" }, "acorn-globals": { "version": "6.0.0", @@ -21135,15 +22954,14 @@ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" }, "autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "requires": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "requires": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" } }, @@ -21382,6 +23200,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "baseline-browser-mapping": { + "version": "2.10.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.19.tgz", + "integrity": "sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==" + }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -21486,11 +23309,11 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browser-process-hrtime": { @@ -21499,14 +23322,15 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, "browserslist": { - "version": "4.21.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.8.tgz", - "integrity": "sha512-j+7xYe+v+q2Id9qbBeCI8WX5NmZSRe8es1+0xntD/+gaWXznP8tFEkv5IgSaHf5dS1YwVMbX/4W6m937mj+wQw==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "requires": { - "caniuse-lite": "^1.0.30001502", - "electron-to-chromium": "^1.4.428", - "node-releases": "^2.0.12", - "update-browserslist-db": "^1.0.11" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" } }, "bser": { @@ -21577,9 +23401,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001502", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001502.tgz", - "integrity": "sha512-AZ+9tFXw1sS0o0jcpJQIXvFTOB/xGiQ4OQ2t98QX3NDn2EZTSRBC801gxrsGgViuq2ak/NLkNgSNEPtCr5lfKg==" + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==" }, "case-sensitive-paths-webpack-plugin": { "version": "2.4.0", @@ -21614,9 +23438,9 @@ "integrity": "sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==" }, "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -21683,6 +23507,16 @@ "wrap-ansi": "^7.0.0" } }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, "clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -21877,8 +23711,29 @@ "parse-json": "^5.0.0", "path-type": "^4.0.0", "yaml": "^1.10.0" + }, + "dependencies": { + "yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==" + } + } + }, + "cosmiconfig-typescript-loader": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-1.0.9.tgz", + "integrity": "sha512-tRuMRhxN4m1Y8hP9SNYfz7jRwt8lZdWxdjg/ohg5esKmsndJIn4yT96oJVcf5x0eA11taXl+sIp+ielu529k6g==", + "requires": { + "cosmiconfig": "^7", + "ts-node": "^10.7.0" } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -22062,6 +23917,13 @@ "cssnano-preset-default": "^5.2.14", "lilconfig": "^2.0.3", "yaml": "^1.10.2" + }, + "dependencies": { + "yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==" + } } }, "cssnano-preset-default": { @@ -22317,6 +24179,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==" + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -22356,6 +24223,11 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, + "diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==" + }, "diff-sequences": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", @@ -22498,9 +24370,9 @@ } }, "electron-to-chromium": { - "version": "1.4.428", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.428.tgz", - "integrity": "sha512-L7uUknyY286of0AYC8CKfgWstD0Smk2DvHDi9F0GWQhSH90Bzi7iDrmCbZKz75tYJxeGSAc7TYeKpmbjMDoh1w==" + "version": "1.5.336", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.336.tgz", + "integrity": "sha512-AbH9q9J455r/nLmdNZes0G0ZKcRX73FicwowalLs6ijwOmCJSRRrLX63lcAlzy9ux3dWK1w1+1nsBJEWN11hcQ==" }, "emittery": { "version": "0.8.1", @@ -22523,12 +24395,12 @@ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", "requires": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" } }, "entities": { @@ -22598,6 +24470,11 @@ "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, "es-module-lexer": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", @@ -22632,9 +24509,9 @@ } }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" }, "escape-html": { "version": "1.0.3", @@ -23278,15 +25155,15 @@ "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==" }, "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "dependencies": { "glob-parent": { @@ -23382,9 +25259,9 @@ "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==" }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "requires": { "to-regex-range": "^5.0.1" } @@ -23442,6 +25319,11 @@ "path-exists": "^4.0.0" } }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -23569,6 +25451,11 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + }, + "yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==" } } }, @@ -23588,9 +25475,9 @@ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" }, "fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==" + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==" }, "fresh": { "version": "0.5.2", @@ -23618,15 +25505,15 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "function.prototype.name": { "version": "1.1.5", @@ -23854,6 +25741,14 @@ "has-symbols": "^1.0.2" } }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -24197,11 +26092,11 @@ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" }, "is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "requires": { - "has": "^1.0.3" + "hasown": "^2.0.2" } }, "is-date-object": { @@ -24283,6 +26178,14 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, "is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -24379,6 +26282,11 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + }, "istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -25877,9 +27785,9 @@ } }, "jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==" + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==" }, "js-tokens": { "version": "4.0.0", @@ -26111,6 +28019,91 @@ "type-check": "~0.4.0" } }, + "lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "requires": { + "detect-libc": "^2.0.3", + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "optional": true + }, + "lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "optional": true + }, + "lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "optional": true + }, + "lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "optional": true + }, + "lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "optional": true + }, + "lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "optional": true + }, + "lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "optional": true + }, + "lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "optional": true + }, + "lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "optional": true + }, + "lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "optional": true + }, + "lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "optional": true + }, "lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -26221,6 +28214,11 @@ } } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -26268,11 +28266,11 @@ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "requires": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" } }, @@ -26400,9 +28398,9 @@ } }, "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==" }, "natural-compare": { "version": "1.4.0", @@ -26444,20 +28442,15 @@ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==" }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" - }, "normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", @@ -26736,9 +28729,9 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "picomatch": { "version": "2.3.1", @@ -26847,13 +28840,13 @@ } }, "postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" } }, "postcss-attribute-case-insensitive": { @@ -27063,9 +29056,9 @@ "requires": {} }, "postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", "requires": { "camelcase-css": "^2.0.1" } @@ -27080,18 +29073,17 @@ } }, "postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", "requires": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" + "lilconfig": "^3.1.1" }, "dependencies": { - "yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==" + "lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==" } } }, @@ -27206,11 +29198,11 @@ } }, "postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", "requires": { - "postcss-selector-parser": "^6.0.11" + "postcss-selector-parser": "^6.1.1" } }, "postcss-nesting": { @@ -27437,9 +29429,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -28114,11 +30106,12 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "requires": { - "is-core-module": "^2.11.0", + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -28199,6 +30192,31 @@ "glob": "^7.1.3" } }, + "rolldown": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", + "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "peer": true, + "requires": { + "@oxc-project/types": "=0.124.0", + "@rolldown/binding-android-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-x64": "1.0.0-rc.15", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15", + "@rolldown/pluginutils": "1.0.0-rc.15" + } + }, "rollup": { "version": "2.79.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", @@ -28498,6 +30516,14 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "requires": { + "kind-of": "^6.0.2" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -28562,9 +30588,9 @@ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" }, "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" }, "source-map-loader": { "version": "3.0.2", @@ -28800,16 +30826,16 @@ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, "sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", "requires": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", - "glob": "7.1.6", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "dependencies": { @@ -28817,19 +30843,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } } } }, @@ -28952,39 +30965,45 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "tailwindcss": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", - "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "requires": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", - "chokidar": "^3.5.3", + "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "dependencies": { + "lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==" + } } }, "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz", + "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==" }, "temp-dir": { "version": "2.0.0", @@ -29094,6 +31113,28 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, + "tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "requires": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "dependencies": { + "fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "requires": {} + }, + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==" + } + } + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -29153,6 +31194,41 @@ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, + "ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "requires": { + "acorn": "^8.11.0" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + } + } + }, "tsconfig-paths": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", @@ -29260,6 +31336,11 @@ "which-boxed-primitive": "^1.0.2" } }, + "undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==" + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -29313,12 +31394,12 @@ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" }, "update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" } }, "uri-js": { @@ -29369,6 +31450,11 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, "v8-to-istanbul": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", @@ -29391,6 +31477,28 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, + "vite": { + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", + "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", + "peer": true, + "requires": { + "fsevents": "~2.3.3", + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.15", + "tinyglobby": "^0.2.15" + }, + "dependencies": { + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "peer": true + } + } + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -29638,6 +31746,16 @@ } } }, + "webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "requires": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + } + }, "webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", @@ -29729,6 +31847,11 @@ "is-typed-array": "^1.1.10" } }, + "wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -30079,11 +32202,6 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" - }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -30103,6 +32221,11 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/MtdrSpring/backend/src/main/frontend/package.json b/MtdrSpring/backend/src/main/frontend/package.json index 04dd8b8aa..39c31ab63 100644 --- a/MtdrSpring/backend/src/main/frontend/package.json +++ b/MtdrSpring/backend/src/main/frontend/package.json @@ -3,11 +3,13 @@ "version": "0.1.0", "private": true, "dependencies": { + "@craco/craco": "^7.1.0", "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", "@mui/icons-material": "^5.8.0", "@mui/material": "^5.8.0", "@mui/styles": "^5.7.0", + "@tailwindcss/vite": "^4.2.2", "moment": "^2.29.3", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -16,8 +18,8 @@ "recharts": "^2.1.16" }, "scripts": { - "start": "react-scripts start", - "build": "react-scripts build" + "start": "craco start", + "build": "craco build" }, "eslintConfig": { "extends": "react-app" @@ -27,6 +29,9 @@ ], "homepage": ".", "devDependencies": { + "autoprefixer": "^10.5.0", + "postcss": "^8.5.10", + "tailwindcss": "^3.4.19", "typescript": "~4.9.5" } } diff --git a/MtdrSpring/backend/src/main/frontend/src/App.js b/MtdrSpring/backend/src/main/frontend/src/App.js index 6bcc9f457..18897dfb2 100644 --- a/MtdrSpring/backend/src/main/frontend/src/App.js +++ b/MtdrSpring/backend/src/main/frontend/src/App.js @@ -111,6 +111,8 @@ function App() {

My Tasks

+
Is this orange?
+
Is this orange?

Stay organized, stay focused

diff --git a/MtdrSpring/backend/src/main/frontend/src/index.css b/MtdrSpring/backend/src/main/frontend/src/index.css index ae5ada450..fef409449 100644 --- a/MtdrSpring/backend/src/main/frontend/src/index.css +++ b/MtdrSpring/backend/src/main/frontend/src/index.css @@ -1,680 +1,7 @@ -@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap'); +@tailwind base; +@tailwind components; +@tailwind utilities; -/* ── Design tokens ─────────────────────────────────────────────────────────── */ -:root { - --purple: #7C3AED; - --purple-dark: #5B21B6; - --purple-mid: #6D28D9; - --purple-light: #EDE9FE; - --purple-soft: #F5F3FF; - --yellow: #FCD34D; - --teal: #14B8A6; - --green: #22C55E; - --danger: #EF4444; - --danger-light: #FEF2F2; - --text-primary: #1F1D2E; - --text-secondary: #9CA3AF; - --text-light: #C4B5FD; - --surface: #FFFFFF; - --bg: #F5F3FF; - --border: #EDE9FE; - --shadow-card: 0 2px 12px rgba(124,58,237,0.08); - --shadow-lg: 0 8px 32px rgba(124,58,237,0.18); - --radius-xl: 24px; - --radius-lg: 16px; - --radius-md: 12px; - --radius-sm: 8px; - --radius-pill: 99px; - - /* Fluid spacing scale */ - --space-xs: clamp(6px, 1vw, 8px); - --space-sm: clamp(10px, 2vw, 14px); - --space-md: clamp(14px, 3vw, 20px); - --space-lg: clamp(20px, 4vw, 32px); - --space-xl: clamp(28px, 5vw, 48px); - - /* Fluid type scale */ - --text-xs: clamp(10px, 1.5vw, 11px); - --text-sm: clamp(11px, 1.8vw, 13px); - --text-base: clamp(13px, 2vw, 15px); - --text-lg: clamp(16px, 2.5vw, 20px); - --text-xl: clamp(20px, 3.5vw, 28px); - --text-2xl: clamp(22px, 4vw, 32px); -} - -/* ── Reset ─────────────────────────────────────────────────────────────────── */ -*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } - -html { -webkit-text-size-adjust: 100%; } - -body { - background: var(--bg); - font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - color: var(--text-primary); - min-height: 100vh; - overflow-x: hidden; -} - -/* ── Layout shell ───────────────────────────────────────────────────────────── */ -.app-wrapper { min-height: 100vh; } - -/* Default: mobile — full-width stacked */ -.layout { - display: flex; - flex-direction: column; - min-height: 100vh; -} - -.left-panel { flex-shrink: 0; } - -.right-panel { - flex: 1; - min-width: 0; - padding: clamp(14px, 4vw, 20px) clamp(14px, 4vw, 16px) 60px; -} - -/* Remove right-panel padding on tablet+ since layout handles it */ -@media (min-width: 640px) { - .right-panel { padding: 0; } -} - -/* ─ Tablet portrait (≥ 640px) ─ */ -@media (min-width: 640px) { - .layout { - max-width: 600px; - margin: 0 auto; - padding: var(--space-lg) var(--space-md) 60px; - } - .app-header { - border-radius: var(--radius-xl) !important; - padding: var(--space-lg) var(--space-lg) var(--space-md) !important; - } - .progress-wrap { margin: var(--space-sm) 0 0 !important; border-radius: var(--radius-lg); } - .app-body { padding: var(--space-md) 0 0 !important; } -} - -/* ─ Tablet landscape (≥ 768px) ─ */ -@media (min-width: 768px) { - .layout { max-width: 720px; } -} - -/* ─ Small desktop (≥ 1024px) — switch to two-column ─ */ -@media (min-width: 1024px) { - .layout { - flex-direction: row; - align-items: flex-start; - max-width: 1000px; - padding: var(--space-xl) var(--space-lg) 80px; - gap: var(--space-lg); - } - .left-panel { - width: 290px; - position: sticky; - top: var(--space-xl); - } - .app-header { - border-radius: var(--radius-xl) !important; - padding: var(--space-lg) var(--space-md) var(--space-md) !important; - } - .progress-wrap { margin: var(--space-sm) 0 0 !important; border-radius: var(--radius-lg); } - .app-body { padding: 0 !important; } -} - -/* ─ Large desktop (≥ 1280px) ─ */ -@media (min-width: 1280px) { - .layout { - max-width: 1160px; - gap: 40px; - } - .left-panel { width: 320px; } -} - -/* ─ Extra large (≥ 1536px) ─ */ -@media (min-width: 1536px) { - .layout { max-width: 1360px; } - .left-panel { width: 360px; } -} - -/* ── Header ─────────────────────────────────────────────────────────────────── */ -.app-header { - background: linear-gradient(140deg, #7C3AED 0%, #5B21B6 100%); - border-radius: 0 0 28px 28px; - padding: clamp(40px, 8vw, 52px) clamp(20px, 5vw, 28px) clamp(24px, 5vw, 36px); - color: white; - position: relative; - overflow: hidden; -} - -.app-header::before { - content: ''; - position: absolute; - top: -40px; right: -40px; - width: clamp(120px, 20vw, 180px); - height: clamp(120px, 20vw, 180px); - background: rgba(255,255,255,0.06); - border-radius: 50%; -} - -.app-header::after { - content: ''; - position: absolute; - bottom: -60px; right: 40px; - width: clamp(80px, 14vw, 120px); - height: clamp(80px, 14vw, 120px); - background: rgba(255,255,255,0.04); - border-radius: 50%; -} - -.header-logo { - width: clamp(44px, 7vw, 52px); - height: clamp(44px, 7vw, 52px); - background: rgba(255,255,255,0.18); - border-radius: var(--radius-md); - display: flex; - align-items: center; - justify-content: center; - margin-bottom: var(--space-md); - backdrop-filter: blur(8px); - flex-shrink: 0; -} - -.header-logo svg { font-size: clamp(22px, 4vw, 28px) !important; color: var(--yellow); } - -.app-header h1 { - font-size: var(--text-2xl); - font-weight: 700; - letter-spacing: -0.5px; - margin-bottom: 4px; - line-height: 1.2; -} - -.app-header .subtitle { - font-size: var(--text-sm); - font-weight: 400; - color: var(--text-light); - margin-bottom: var(--space-md); -} - -/* ── Stats row ──────────────────────────────────────────────────────────────── */ -.stats-row { display: flex; gap: 10px; flex-wrap: wrap; } - -.stat-chip { - background: rgba(255,255,255,0.14); - border-radius: var(--radius-pill); - padding: 5px 12px; - font-size: var(--text-sm); - font-weight: 600; - color: white; - display: flex; - align-items: center; - gap: 6px; - backdrop-filter: blur(8px); -} - -.stat-chip .dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; } -.dot-pending { background: var(--yellow); } -.dot-done { background: var(--green); } - -/* ── Progress ───────────────────────────────────────────────────────────────── */ -.progress-wrap { - margin: clamp(14px, 3vw, 20px) clamp(14px, 4vw, 16px) 0; - background: var(--surface); - border-radius: var(--radius-lg); - padding: clamp(12px, 2.5vw, 16px) clamp(14px, 3vw, 20px); - box-shadow: var(--shadow-card); -} - -@media (min-width: 640px) { - .progress-wrap { margin: clamp(14px, 3vw, 20px) 0 0; } -} - -.progress-label { - display: flex; - justify-content: space-between; - align-items: center; - font-size: var(--text-sm); - font-weight: 600; - color: var(--text-secondary); - margin-bottom: 10px; -} - -.progress-label .pct { color: var(--purple); } - -.progress-track { - height: clamp(5px, 1vw, 8px); - background: var(--border); - border-radius: var(--radius-pill); - overflow: hidden; -} - -.progress-fill { - height: 100%; - background: linear-gradient(90deg, var(--purple), #A78BFA); - border-radius: var(--radius-pill); - transition: width 0.5s cubic-bezier(0.4,0,0.2,1); -} - -/* ── App body ───────────────────────────────────────────────────────────────── */ -.app-body { - padding: clamp(14px, 3vw, 20px) 0 0; -} - -/* On tablet+ the right-panel has no padding, so app-body needs its own horizontal */ -@media (min-width: 640px) { - .app-body { - padding: clamp(16px, 3vw, 20px) 0 0; - } -} - -/* ── New item form ──────────────────────────────────────────────────────────── */ -.new-item-wrap { - background: var(--surface); - border-radius: var(--radius-lg); - box-shadow: var(--shadow-card); - border: 1.5px solid var(--border); - margin-bottom: clamp(16px, 3vw, 24px); - display: flex; - align-items: center; - overflow: hidden; - transition: border-color 0.2s, box-shadow 0.2s; -} - -.new-item-wrap:focus-within { - border-color: var(--purple); - box-shadow: 0 0 0 4px rgba(124,58,237,0.1); -} - -.new-item-prefix { - padding: 0 4px 0 clamp(12px, 3vw, 18px); - color: var(--purple); - font-size: clamp(18px, 3vw, 22px); - font-weight: 300; - display: flex; - align-items: center; - flex-shrink: 0; - user-select: none; -} - -.new-item-input { - flex: 1; - min-width: 0; - border: none; - outline: none; - background: transparent; - font-family: inherit; - font-size: var(--text-base); - font-weight: 500; - color: var(--text-primary); - padding: clamp(12px, 2.5vw, 15px) 8px; -} - -.new-item-input::placeholder { color: var(--text-secondary); font-weight: 400; } - -.add-btn { - flex-shrink: 0; - margin: 6px; - padding: clamp(7px, 1.5vw, 9px) clamp(14px, 3vw, 20px); - background: linear-gradient(135deg, var(--purple), var(--purple-mid)); - color: white; - border: none; - border-radius: var(--radius-md); - font-family: inherit; - font-size: var(--text-sm); - font-weight: 600; - cursor: pointer; - transition: opacity 0.15s, transform 0.1s, box-shadow 0.15s; - white-space: nowrap; - box-shadow: 0 4px 12px rgba(124,58,237,0.3); - /* min touch target */ - min-height: 36px; -} - -.add-btn:hover:not(:disabled) { opacity: 0.9; transform: translateY(-1px); box-shadow: 0 6px 16px rgba(124,58,237,0.4); } -.add-btn:active:not(:disabled) { transform: translateY(0); } -.add-btn:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; } - -/* ── Task sections ──────────────────────────────────────────────────────────── */ -.tasks-section { margin-bottom: clamp(18px, 4vw, 28px); } - -.section-header { - display: flex; - align-items: center; - gap: 8px; - margin-bottom: clamp(8px, 2vw, 12px); -} - -.section-header h2 { - font-size: var(--text-xs); - font-weight: 700; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.8px; -} - -.count-badge { - background: var(--purple-light); - color: var(--purple); - font-size: var(--text-xs); - font-weight: 700; - padding: 2px 9px; - border-radius: var(--radius-pill); -} - -/* ── Task card ──────────────────────────────────────────────────────────────── */ -.task-card { - background: var(--surface); - border-radius: var(--radius-md); - padding: clamp(10px, 2vw, 14px) clamp(12px, 2.5vw, 16px); - margin-bottom: clamp(6px, 1.5vw, 10px); - box-shadow: var(--shadow-card); - display: flex; - align-items: center; - gap: clamp(10px, 2vw, 14px); - border: 1.5px solid transparent; - transition: box-shadow 0.15s, border-color 0.15s, transform 0.1s; - position: relative; - overflow: hidden; -} - -.task-card::before { - content: ''; - position: absolute; - left: 0; top: 0; bottom: 0; - width: 4px; - background: var(--card-accent, var(--purple)); - border-radius: 4px 0 0 4px; -} - -.task-card:hover { box-shadow: var(--shadow-lg); border-color: var(--border); transform: translateY(-1px); } -.task-card:hover .task-actions { opacity: 1; } - -.task-card.is-done { background: #FAFAFA; box-shadow: none; border-color: var(--border); } -.task-card.is-done::before { background: var(--green); } -.task-card.is-done:hover { transform: none; box-shadow: var(--shadow-card); } - -/* On touch devices always show actions (no hover) */ -@media (hover: none) { - .task-actions { opacity: 1; } - .task-card:hover { transform: none; box-shadow: var(--shadow-card); } -} - -/* ── Checkbox ───────────────────────────────────────────────────────────────── */ -.task-checkbox { - flex-shrink: 0; - width: clamp(20px, 3.5vw, 24px); - height: clamp(20px, 3.5vw, 24px); - border-radius: 50%; - border: 2px solid #D1D5DB; - background: transparent; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.2s; - padding: 0; - outline: none; - /* min touch target */ - position: relative; -} - -.task-checkbox::after { - content: ''; - position: absolute; - inset: -8px; -} - -.task-checkbox:hover { border-color: var(--purple); background: var(--purple-light); } - -.task-checkbox.checked { background: var(--green); border-color: var(--green); } -.task-checkbox.checked::after { - content: '✓'; - position: static; - color: white; - font-size: clamp(10px, 1.8vw, 13px); - font-weight: 700; - line-height: 1; -} - -/* ── Task body ──────────────────────────────────────────────────────────────── */ -.task-body { flex: 1; min-width: 0; } - -.task-description { - font-size: var(--text-base); - font-weight: 500; - color: var(--text-primary); - display: block; - line-height: 1.4; - word-break: break-word; -} - -.task-card.is-done .task-description { - color: #9CA3AF; - text-decoration: line-through; - font-weight: 400; -} - -.task-date { - font-size: var(--text-xs); - color: var(--text-secondary); - display: block; - margin-top: 3px; - font-weight: 400; -} - -/* ── Task actions ───────────────────────────────────────────────────────────── */ -.task-actions { - display: flex; - align-items: center; - gap: 4px; - opacity: 0; - transition: opacity 0.15s; - flex-shrink: 0; -} - -.action-btn { - width: clamp(30px, 5vw, 34px); - height: clamp(30px, 5vw, 34px); - border-radius: var(--radius-sm); - border: none; - background: transparent; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - color: var(--text-secondary); - transition: background 0.12s, color 0.12s; - outline: none; -} - -.action-btn:hover { background: var(--border); color: var(--text-primary); } -.action-btn.delete:hover { background: var(--danger-light); color: var(--danger); } - -/* ── Empty state ────────────────────────────────────────────────────────────── */ -.empty-state { - text-align: center; - padding: clamp(24px, 5vw, 36px) 0 clamp(20px, 4vw, 28px); - color: var(--text-secondary); - font-size: var(--text-base); - font-weight: 500; -} - -/* ── Tabs ───────────────────────────────────────────────────────────────────── */ -.tabs { - display: flex; - gap: 5px; - margin-bottom: clamp(14px, 3vw, 20px); - background: var(--surface); - border-radius: var(--radius-lg); - padding: 5px; - box-shadow: var(--shadow-card); -} - -.tab-btn { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - gap: 6px; - padding: clamp(8px, 1.8vw, 10px) clamp(10px, 2.5vw, 16px); - border: none; - border-radius: var(--radius-md); - background: transparent; - font-family: inherit; - font-size: var(--text-sm); - font-weight: 600; - color: var(--text-secondary); - cursor: pointer; - transition: all 0.18s; - min-height: 40px; -} - -.tab-btn svg { flex-shrink: 0; } - -.tab-btn:hover { background: var(--purple-soft); color: var(--purple); } -.tab-btn.active { background: var(--purple); color: white; box-shadow: 0 4px 12px rgba(124,58,237,0.3); } - -/* Hide icon labels on very small screens */ -@media (max-width: 359px) { - .tab-btn span { display: none; } -} - -/* ── Dashboard ──────────────────────────────────────────────────────────────── */ -.dashboard { - display: flex; - flex-direction: column; - gap: clamp(12px, 2.5vw, 16px); -} - -/* KPI grid: 2 cols on mobile → 4 cols on sm+ */ -.kpi-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: clamp(8px, 2vw, 12px); -} - -@media (min-width: 480px) { .kpi-grid { grid-template-columns: repeat(4, 1fr); } } - -.kpi-card { - background: var(--kpi-bg); - border-radius: var(--radius-lg); - padding: clamp(14px, 2.5vw, 18px) clamp(12px, 2.5vw, 16px); - display: flex; - flex-direction: column; - gap: 4px; -} - -.kpi-value { - font-size: clamp(20px, 4vw, 28px); - font-weight: 700; - color: var(--kpi-color); - line-height: 1; -} - -.kpi-label { - font-size: var(--text-xs); - font-weight: 600; - color: var(--kpi-color); - opacity: 0.7; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -/* ── Chart card ─────────────────────────────────────────────────────────────── */ -.chart-card { - background: var(--surface); - border-radius: var(--radius-lg); - padding: clamp(14px, 3vw, 20px); - box-shadow: var(--shadow-card); - /* prevent chart overflow on small screens */ - overflow: hidden; -} - -.chart-header { margin-bottom: clamp(10px, 2vw, 16px); } - -.chart-header h3 { - font-size: var(--text-base); - font-weight: 700; - color: var(--text-primary); - margin-bottom: 2px; -} - -.chart-header p { font-size: var(--text-xs); color: var(--text-secondary); font-weight: 400; } - -.chart-wrap { width: 100%; overflow: hidden; } - -.chart-tooltip { - background: white; - border-radius: 12px; - padding: 10px 14px; - box-shadow: 0 8px 32px rgba(124,58,237,0.15); - font-family: 'Poppins', sans-serif; - font-size: 12px; - border: none; -} - -.tooltip-label { font-weight: 700; color: var(--text-primary); margin-bottom: 6px; font-size: 13px; } - -/* ── Insights ───────────────────────────────────────────────────────────────── */ -.insights-section { margin-top: 4px; } - -.insights-header { margin-bottom: clamp(8px, 2vw, 12px); } - -.insights-header h3 { font-size: var(--text-base); font-weight: 700; color: var(--text-primary); margin-bottom: 2px; } -.insights-header p { font-size: var(--text-xs); color: var(--text-secondary); } - -/* 1 col mobile → 2 cols sm+ */ -.insights-grid { - display: grid; - grid-template-columns: 1fr; - gap: clamp(8px, 2vw, 10px); -} - -@media (min-width: 560px) { .insights-grid { grid-template-columns: repeat(2, 1fr); } } - -.insight-card { - background: var(--ins-bg); - border-left: 4px solid var(--ins-border); - border-radius: var(--radius-md); - padding: clamp(10px, 2vw, 14px) clamp(12px, 2.5vw, 16px); - display: flex; - flex-direction: column; - gap: 5px; -} - -.insight-tag { font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px; color: var(--ins-tag); } -.insight-title { font-size: var(--text-sm); font-weight: 700; color: var(--text-primary); line-height: 1.3; } -.insight-body { font-size: var(--text-xs); color: var(--text-secondary); line-height: 1.5; } - -/* ── Actions ────────────────────────────────────────────────────────────────── */ -.actions-list { display: flex; flex-direction: column; gap: clamp(6px, 1.5vw, 8px); } - -.action-item { - background: var(--act-bg); - border-radius: var(--radius-md); - padding: clamp(10px, 2vw, 12px) clamp(12px, 2.5vw, 16px); - display: flex; - align-items: flex-start; - gap: clamp(8px, 2vw, 12px); -} - -.action-priority { - flex-shrink: 0; - font-size: var(--text-xs); - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--act-color); - background: white; - border: 1.5px solid var(--act-color); - border-radius: var(--radius-pill); - padding: 2px 8px; - margin-top: 2px; - white-space: nowrap; -} - -.action-text { font-size: var(--text-sm); color: var(--text-primary); line-height: 1.5; } - -/* ── Loading ────────────────────────────────────────────────────────────────── */ -.loading-wrap { display: flex; justify-content: center; padding: clamp(32px, 6vw, 48px) 0; } +.test-tailwind { + @apply bg-orange-500 p-10 text-white font-bold; +} \ No newline at end of file From 41d495de38a59e7c579661fad22706a7b9860428 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago Date: Wed, 15 Apr 2026 13:51:07 -0600 Subject: [PATCH 11/23] Work item components --- .../backend/src/main/frontend/craco.config.js | 7 + .../src/main/frontend/package-lock.json | 16 ++ .../backend/src/main/frontend/package.json | 1 + .../backend/src/main/frontend/src/App.js | 252 ------------------ .../backend/src/main/frontend/src/App.tsx | 45 ++++ .../work-items/components/comment-item.tsx | 0 .../work-items/components/comment-thread.tsx | 0 .../components/shared/metric-card.tsx | 28 ++ .../components/shared/person-avatar.tsx | 24 ++ .../components/shared/person-stack.tsx | 29 ++ .../components/shared/work-item-badge-row.tsx | 44 +++ .../components/work-item-activity-panel.tsx | 0 .../components/work-item-comments-panel.tsx | 0 .../components/work-item-context-card.tsx | 45 ++++ .../components/work-item-detail-header.tsx | 93 +++++++ .../components/work-item-detail-summary.tsx | 0 .../components/work-item-links-panel.tsx | 0 .../components/work-item-meta-card.tsx | 25 ++ .../components/work-item-metrics.tsx | 41 +++ .../components/work-item-progress-card.tsx | 34 +++ .../facades/work-item-detail.facade.impl.ts | 0 .../facades/work-item-detail.facade.ts | 0 .../features/work-items/lib/work-item-ui.ts | 65 +++++ .../model/work-item-detail-screen-data.ts | 0 .../model/work-item-detail-state.ts | 0 .../pages/work-item-detail-page.tsx | 0 .../pages/work-item-detail-ui-prototype.tsx | 43 +++ .../work-items/types/work-item-ui.types.ts | 31 +++ .../backend/src/main/frontend/tsconfig.json | 4 +- 29 files changed, 573 insertions(+), 254 deletions(-) delete mode 100644 MtdrSpring/backend/src/main/frontend/src/App.js create mode 100644 MtdrSpring/backend/src/main/frontend/src/App.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/comment-item.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/comment-thread.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/metric-card.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/person-avatar.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/person-stack.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/work-item-badge-row.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-activity-panel.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-comments-panel.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-context-card.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-detail-header.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-detail-summary.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-links-panel.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-meta-card.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-metrics.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-progress-card.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/facades/work-item-detail.facade.impl.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/facades/work-item-detail.facade.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/lib/work-item-ui.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-detail-screen-data.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-detail-state.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/pages/work-item-detail-page.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/pages/work-item-detail-ui-prototype.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/types/work-item-ui.types.ts diff --git a/MtdrSpring/backend/src/main/frontend/craco.config.js b/MtdrSpring/backend/src/main/frontend/craco.config.js index c92370e1d..34ff10e49 100644 --- a/MtdrSpring/backend/src/main/frontend/craco.config.js +++ b/MtdrSpring/backend/src/main/frontend/craco.config.js @@ -1,4 +1,11 @@ +const path = require('path'); + module.exports = { + webpack: { + alias: { + '@': path.resolve(__dirname, 'src'), + }, + }, style: { postcss: { mode: "extends", diff --git a/MtdrSpring/backend/src/main/frontend/package-lock.json b/MtdrSpring/backend/src/main/frontend/package-lock.json index 5330eaa09..8a45b839d 100644 --- a/MtdrSpring/backend/src/main/frontend/package-lock.json +++ b/MtdrSpring/backend/src/main/frontend/package-lock.json @@ -15,6 +15,7 @@ "@mui/material": "^5.8.0", "@mui/styles": "^5.7.0", "@tailwindcss/vite": "^4.2.2", + "lucide-react": "^1.8.0", "moment": "^2.29.3", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -13195,6 +13196,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.8.0.tgz", + "integrity": "sha512-WuvlsjngSk7TnTBJ1hsCy3ql9V9VOdcPkd3PKcSmM34vJD8KG6molxz7m7zbYFgICwsanQWmJ13JlYs4Zp7Arw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -28191,6 +28201,12 @@ "yallist": "^3.0.2" } }, + "lucide-react": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.8.0.tgz", + "integrity": "sha512-WuvlsjngSk7TnTBJ1hsCy3ql9V9VOdcPkd3PKcSmM34vJD8KG6molxz7m7zbYFgICwsanQWmJ13JlYs4Zp7Arw==", + "requires": {} + }, "magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", diff --git a/MtdrSpring/backend/src/main/frontend/package.json b/MtdrSpring/backend/src/main/frontend/package.json index 39c31ab63..9157d88f9 100644 --- a/MtdrSpring/backend/src/main/frontend/package.json +++ b/MtdrSpring/backend/src/main/frontend/package.json @@ -10,6 +10,7 @@ "@mui/material": "^5.8.0", "@mui/styles": "^5.7.0", "@tailwindcss/vite": "^4.2.2", + "lucide-react": "^1.8.0", "moment": "^2.29.3", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/MtdrSpring/backend/src/main/frontend/src/App.js b/MtdrSpring/backend/src/main/frontend/src/App.js deleted file mode 100644 index 18897dfb2..000000000 --- a/MtdrSpring/backend/src/main/frontend/src/App.js +++ /dev/null @@ -1,252 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import NewItem from './NewItem'; -import Dashboard from './Dashboard'; -import API_LIST from './API'; -import DeleteIcon from '@mui/icons-material/Delete'; -import TaskAltIcon from '@mui/icons-material/TaskAlt'; -import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted'; -import BarChartIcon from '@mui/icons-material/BarChart'; -import { CircularProgress } from '@mui/material'; -import Moment from 'react-moment'; - -const CARD_COLORS = ['#7C3AED', '#F59E0B', '#14B8A6', '#EC4899', '#3B82F6', '#EF4444']; - -function App() { - const [activeTab, setActiveTab] = useState('tasks'); - const [isLoading] = useState(false); - const [isInserting, setInserting] = useState(false); - const [items, setItems] = useState([]); - const [, setError] = useState(); - - function deleteItem(deleteId) { - fetch(API_LIST + "/" + deleteId, { method: 'DELETE' }) - .then(response => { - if (response.ok) return response; - throw new Error('Something went wrong ...'); - }) - .then( - () => { setItems(prev => prev.filter(item => item.id !== deleteId)); }, - (err) => { setError(err); } - ); - } - - function toggleDone(event, id, description, done) { - event.preventDefault(); - modifyItem(id, description, done).then( - () => { reloadOneItem(id); }, - (err) => { setError(err); } - ); - } - - function reloadOneItem(id) { - fetch(API_LIST + "/" + id) - .then(response => { - if (response.ok) return response.json(); - throw new Error('Something went wrong ...'); - }) - .then( - (result) => { - setItems(prev => prev.map(x => - x.id === id ? { ...x, description: result.description, done: result.done } : x - )); - }, - (err) => { setError(err); } - ); - } - - function modifyItem(id, description, done) { - return fetch(API_LIST + "/" + id, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ description, done }), - }).then(response => { - if (response.ok) return response; - throw new Error('Something went wrong ...'); - }); - } - - useEffect(() => { - setItems([ - { id: 1, description: 'Design new dashboard layout', createdAt: '2026-04-14T09:00:00', done: false }, - { id: 2, description: 'Fix login bug on mobile', createdAt: '2026-04-14T10:30:00', done: false }, - { id: 3, description: 'Write unit tests for API', createdAt: '2026-04-13T15:00:00', done: false }, - { id: 4, description: 'Deploy to staging environment', createdAt: '2026-04-13T11:00:00', done: true }, - { id: 5, description: 'Review pull request #42', createdAt: '2026-04-12T08:00:00', done: true }, - ]); - }, []); - - function addItem(text) { - setInserting(true); - fetch(API_LIST, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ description: text }), - }) - .then(response => { - if (response.ok) return response; - throw new Error('Something went wrong ...'); - }) - .then( - (result) => { - const id = result.headers.get('location'); - setItems(prev => [{ id, description: text }, ...prev]); - setInserting(false); - }, - (err) => { setInserting(false); setError(err); } - ); - } - - const todoItems = items.filter(item => !item.done); - const doneItems = items.filter(item => item.done); - const donePercent = items.length > 0 ? Math.round((doneItems.length / items.length) * 100) : 0; - - return ( -
-
- - {/* Left panel — header + stats */} -
-
-
- -
-

My Tasks

-
Is this orange?
-
Is this orange?
-

Stay organized, stay focused

-
-
- - {todoItems.length} pending -
-
- - {doneItems.length} completed -
-
-
- - {items.length > 0 && ( -
-
- {doneItems.length} of {items.length} tasks completed - {donePercent}% -
-
-
-
-
- )} -
- - {/* Right panel — tasks */} -
-
- - -
- - {activeTab === 'analytics' ? ( - - ) : ( -
- - - {isLoading ? ( -
- -
- ) : ( - <> -
-
-

To Do

- - {todoItems.length} -
- - {todoItems.length === 0 ? ( -
All caught up — nothing left to do!
- ) : ( - todoItems.map((item, i) => ( -
-
- )) - )} -
- - {doneItems.length > 0 && ( -
-
-

Completed

- {doneItems.length} -
- {doneItems.map((item) => ( -
- -
-
- ))} - - )} - - )} -
- )} -
- -
-
- ); -} - -export default App; diff --git a/MtdrSpring/backend/src/main/frontend/src/App.tsx b/MtdrSpring/backend/src/main/frontend/src/App.tsx new file mode 100644 index 000000000..8b0638f1d --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/App.tsx @@ -0,0 +1,45 @@ +import { WorkItemContextCard } from '@/features/work-items/components/work-item-context-card'; +import { WorkItemDetailHeader } from '@/features/work-items/components/work-item-detail-header'; +import type { WorkItemDetail } from '@/features/work-items/types/work-item-ui.types'; + +const mockWorkItem: WorkItemDetail = { + id: 'WI-102', + title: 'Create work item detail experience for managers and developers', + type: 'feature', + status: 'in_progress', + priority: 'high', + sprintName: 'Sprint 04 · Frontend Foundations', + estimatedHours: 12, + loggedHours: 7.5, + dueDate: 'Apr 22, 2026', + description: + 'Design and implement a polished work item detail screen that consolidates task context, assignees, discussion, related items, and activity history.', + acceptanceCriteria: [ + 'Header shows title, type, status, priority, sprint, and main actions.', + 'The layout supports comments, related links, and activity in distinct reusable panels.', + 'The visual hierarchy is strong enough for manager visibility and quick developer execution.', + ], + tags: ['frontend', 'design-system', 'mvp'], + assignees: [ + { id: 'u1', name: 'Bernardo', role: 'Manager' }, + { id: 'u2', name: 'Ana Torres', role: 'Frontend Dev' }, + { id: 'u3', name: 'Luis Vega', role: 'Backend Dev' }, + ], + reporter: { id: 'u4', name: 'Sofia Ruiz', role: 'Product Owner' }, + externalLink: 'https://example.com/spec/work-item-detail', + commentsCount: 6, + linkedItemsCount: 3, +}; + +function App() { + return ( +
+
+ + +
+
+ ); +} + +export default App; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/comment-item.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/comment-item.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/comment-thread.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/comment-thread.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/metric-card.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/metric-card.tsx new file mode 100644 index 000000000..edcaabc14 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/metric-card.tsx @@ -0,0 +1,28 @@ +import React from "react"; + +interface MetricCardProps { + icon: React.ReactNode; + label: string; + value: string; + hint: string; +} + +export function MetricCard({ icon, label, value, hint }: MetricCardProps) { + return ( +
+
+
+ {icon} +
+ +
+

+ {label} +

+

{value}

+

{hint}

+
+
+
+ ); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/person-avatar.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/person-avatar.tsx new file mode 100644 index 000000000..529018f02 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/person-avatar.tsx @@ -0,0 +1,24 @@ +import type { Person } from '../../types/work-item-ui.types'; +import { getPersonInitials, joinClasses } from '../../lib/work-item-ui'; + +interface PersonAvatarProps { + person: Person; + className?: string; +} + +export function PersonAvatar({ person, className }: PersonAvatarProps) { + return ( +
+ + {getPersonInitials(person)} + +
+ ); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/person-stack.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/person-stack.tsx new file mode 100644 index 000000000..69736afdc --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/person-stack.tsx @@ -0,0 +1,29 @@ +import type { Person } from '../../types/work-item-ui.types'; +import { PersonAvatar } from './person-avatar'; + +interface PersonStackProps { + people: Person[]; +} + +export function PersonStack({ people }: PersonStackProps) { + return ( +
+
+ {people.map((person) => ( + + ))} +
+ +
+

+ {people.length} collaborators +

+

Cross-functional ownership

+
+
+ ); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/work-item-badge-row.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/work-item-badge-row.tsx new file mode 100644 index 000000000..e497d2468 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/shared/work-item-badge-row.tsx @@ -0,0 +1,44 @@ +import type { + WorkItemPriority, + WorkItemStatus, + WorkItemType, +} from '../../types/work-item-ui.types'; +import { + formatStatus, + getPriorityClasses, + getStatusClasses, + getTypeClasses, + joinClasses, +} from '../../lib/work-item-ui'; +import React from "react"; + +interface WorkItemBadgeRowProps { + id: string; + type: WorkItemType; + status: WorkItemStatus; + priority: WorkItemPriority; +} + +function Pill({children, className}: { children: React.ReactNode; className?: string; }) { + return ( + + {children} + + ); +} + +export function WorkItemBadgeRow({id, type, status, priority,}: WorkItemBadgeRowProps) { + return ( +
+ {type} + {formatStatus(status)} + {priority} priority + {id} +
+ ); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-activity-panel.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-activity-panel.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-comments-panel.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-comments-panel.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-context-card.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-context-card.tsx new file mode 100644 index 000000000..c0bbd1228 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-context-card.tsx @@ -0,0 +1,45 @@ +import { CheckCircle2 } from 'lucide-react'; +import type { WorkItemDetail } from '../types/work-item-ui.types'; + +interface WorkItemContextCardProps { + item: WorkItemDetail; +} + +export function WorkItemContextCard({ item }: WorkItemContextCardProps) { + return ( +
+
+

Work context

+
+ +
+
+

Description

+

+ {item.description} +

+
+ +
+ +
+

+ Acceptance criteria +

+ +
+ {item.acceptanceCriteria?.map((criterion) => ( +
+ +

{criterion}

+
+ ))} +
+
+
+
+ ); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-detail-header.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-detail-header.tsx new file mode 100644 index 000000000..d8bd121da --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-detail-header.tsx @@ -0,0 +1,93 @@ +import { CalendarDays, ExternalLink, Flag, UserRound } from 'lucide-react'; +import type { WorkItemDetail } from '../types/work-item-ui.types'; +import { WorkItemBadgeRow } from './shared/work-item-badge-row'; +import { WorkItemMetaCard } from './work-item-meta-card'; +import { WorkItemMetrics } from './work-item-metrics'; +import { WorkItemProgressCard } from './work-item-progress-card'; + +interface WorkItemDetailHeaderProps { + item: WorkItemDetail; + onMarkDone?: () => void; + onLogTime?: () => void; + onOpenExternal?: () => void; +} + +export function WorkItemDetailHeader({ item, onMarkDone, onLogTime, onOpenExternal,}: WorkItemDetailHeaderProps) { + return ( +
+
+
+
+ + +
+

+ {item.title} +

+ +

+ {item.description} +

+
+ +
+
+ + {item.dueDate} +
+ +
+ + {item.sprintName} +
+ +
+ + Reporter: {item.reporter.name} +
+
+
+ +
+ + + + + +
+
+ + + +
+ + +
+
+
+ ); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-detail-summary.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-detail-summary.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-links-panel.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-links-panel.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-meta-card.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-meta-card.tsx new file mode 100644 index 000000000..f4a36aee9 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-meta-card.tsx @@ -0,0 +1,25 @@ +import type { WorkItemDetail } from '../types/work-item-ui.types'; +import { PersonStack } from './shared/person-stack'; + +interface WorkItemMetaCardProps { + item: WorkItemDetail; +} + +export function WorkItemMetaCard({ item }: WorkItemMetaCardProps) { + return ( +
+ + +
+ {item.tags.map((tag) => ( + + #{tag} + + ))} +
+
+ ); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-metrics.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-metrics.tsx new file mode 100644 index 000000000..4a0ad2fd6 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-metrics.tsx @@ -0,0 +1,41 @@ +import { Clock3, Link2, MessageSquare, Timer } from 'lucide-react'; +import type { WorkItemDetail } from '../types/work-item-ui.types'; +import { MetricCard } from './shared/metric-card'; + +interface WorkItemMetricsProps { + item: WorkItemDetail; +} + +export function WorkItemMetrics({ item }: WorkItemMetricsProps) { + return ( +
+ } + label="Estimate" + value={`${item.estimatedHours}h`} + hint="Original planning effort" + /> + + } + label="Logged" + value={`${item.loggedHours}h`} + hint="Actual work captured" + /> + + } + label="Discussion" + value={`${item.commentsCount}`} + hint="Active collaboration" + /> + + } + label="Linked items" + value={`${item.linkedItemsCount}`} + hint="Dependencies and blockers" + /> +
+ ); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-progress-card.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-progress-card.tsx new file mode 100644 index 000000000..5b4d38393 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/work-item-progress-card.tsx @@ -0,0 +1,34 @@ +import type { WorkItemDetail } from '../types/work-item-ui.types'; + +interface WorkItemProgressCardProps { + item: WorkItemDetail; +} + +export function WorkItemProgressCard({ item }: WorkItemProgressCardProps) { + const progress = Math.min( + 100, + Math.round((item.loggedHours / item.estimatedHours) * 100), + ); + + return ( +
+
+
+

Execution progress

+

+ Logged effort versus original estimate +

+
+ +

{progress}%

+
+ +
+
+
+
+ ); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/facades/work-item-detail.facade.impl.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/facades/work-item-detail.facade.impl.ts new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/facades/work-item-detail.facade.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/facades/work-item-detail.facade.ts new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/lib/work-item-ui.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/lib/work-item-ui.ts new file mode 100644 index 000000000..6c0e7bd64 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/lib/work-item-ui.ts @@ -0,0 +1,65 @@ +import type { + Person, + WorkItemPriority, + WorkItemStatus, + WorkItemType, +} from '../types/work-item-ui.types'; + +export function joinClasses(...values: Array): string { + return values.filter(Boolean).join(' '); +} + +export function getPersonInitials(person: Person): string { + return person.name + .split(' ') + .map((part) => part[0]) + .join('') + .slice(0, 2) + .toUpperCase(); +} + +export function formatStatus(status: WorkItemStatus): string { + return status.replace('_', ' '); +} + +export function getTypeClasses(type: WorkItemType): string { + switch (type) { + case 'feature': + return 'border-cyan-400/30 bg-cyan-500/15 text-cyan-300'; + case 'bug': + return 'border-rose-400/30 bg-rose-500/15 text-rose-300'; + case 'issue': + return 'border-orange-400/30 bg-orange-500/15 text-orange-300'; + case 'task': + default: + return 'border-indigo-400/30 bg-indigo-500/15 text-indigo-300'; + } +} + +export function getStatusClasses(status: WorkItemStatus): string { + switch (status) { + case 'done': + return 'border-emerald-400/30 bg-emerald-500/15 text-emerald-300'; + case 'blocked': + return 'border-rose-400/30 bg-rose-500/15 text-rose-300'; + case 'in_progress': + return 'border-sky-400/30 bg-sky-500/15 text-sky-300'; + case 'todo': + default: + return 'border-zinc-400/30 bg-zinc-500/15 text-zinc-300'; + } +} + +export function getPriorityClasses(priority: WorkItemPriority): string { + switch (priority) { + case 'critical': + return 'border-rose-400/30 bg-rose-500/15 text-rose-300'; + case 'high': + return 'border-amber-400/30 bg-amber-500/15 text-amber-300'; + case 'medium': + return 'border-violet-400/30 bg-violet-500/15 text-violet-300'; + case 'low': + default: + return 'border-zinc-400/30 bg-zinc-500/15 text-zinc-300'; + } +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-detail-screen-data.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-detail-screen-data.ts new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-detail-state.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/model/work-item-detail-state.ts new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/pages/work-item-detail-page.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/pages/work-item-detail-page.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/pages/work-item-detail-ui-prototype.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/pages/work-item-detail-ui-prototype.tsx new file mode 100644 index 000000000..65ce3f326 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/pages/work-item-detail-ui-prototype.tsx @@ -0,0 +1,43 @@ +import { WorkItemContextCard } from '@/features/work-items/components/work-item-context-card'; +import { WorkItemDetailHeader } from '@/features/work-items/components/work-item-detail-header'; +import type { WorkItemDetail } from '@/features/work-items/types/work-item-ui.types'; + +const mockWorkItem: WorkItemDetail = { + id: 'WI-102', + title: 'Create work item detail experience for managers and developers', + type: 'feature', + status: 'in_progress', + priority: 'high', + sprintName: 'Sprint 04 · Frontend Foundations', + estimatedHours: 12, + loggedHours: 7.5, + dueDate: 'Apr 22, 2026', + description: + 'Design and implement a polished work item detail screen that consolidates task context, assignees, discussion, related items, and activity history.', + acceptanceCriteria: [ + 'Header shows title, type, status, priority, sprint, and main actions.', + 'The layout supports comments, related links, and activity in distinct reusable panels.', + 'The visual hierarchy is strong enough for manager visibility and quick developer execution.', + ], + tags: ['frontend', 'design-system', 'mvp'], + assignees: [ + { id: 'u1', name: 'Bernardo', role: 'Manager' }, + { id: 'u2', name: 'Ana Torres', role: 'Frontend Dev' }, + { id: 'u3', name: 'Luis Vega', role: 'Backend Dev' }, + ], + reporter: { id: 'u4', name: 'Sofia Ruiz', role: 'Product Owner' }, + externalLink: 'https://example.com/spec/work-item-detail', + commentsCount: 6, + linkedItemsCount: 3, +}; + +export function WorkItemPrototypePage() { + return ( +
+
+ + +
+
+ ); +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/types/work-item-ui.types.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/types/work-item-ui.types.ts new file mode 100644 index 000000000..48c8285dc --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/types/work-item-ui.types.ts @@ -0,0 +1,31 @@ +export type WorkItemType = 'feature' | 'issue' | 'bug' | 'task'; + +export type WorkItemStatus = 'todo' | 'in_progress' | 'blocked' | 'done'; + +export type WorkItemPriority = 'low' | 'medium' | 'high' | 'critical'; + +export interface Person { + id: string; + name: string; + role: string; +} + +export interface WorkItemDetail { + id: string; + title: string; + type: WorkItemType; + status: WorkItemStatus; + priority: WorkItemPriority; + sprintName: string; + estimatedHours: number; + loggedHours: number; + dueDate: string; + description: string; + acceptanceCriteria?: string[]; + tags: string[]; + assignees: Person[]; + reporter: Person; + externalLink?: string; + commentsCount: number; + linkedItemsCount: number; +} \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/tsconfig.json b/MtdrSpring/backend/src/main/frontend/tsconfig.json index 84ad7aecf..1d61ef4e1 100644 --- a/MtdrSpring/backend/src/main/frontend/tsconfig.json +++ b/MtdrSpring/backend/src/main/frontend/tsconfig.json @@ -28,9 +28,9 @@ "module": "ESNext", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "baseUrl": ".", /* Specify the base directory to resolve non-relative module names. */ "paths": { - "@/*": ["./src/*"] + "@/*": ["src/*"] }, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ From 4412948195b826fdabf35af3b0cdeb9eeea26fef Mon Sep 17 00:00:00 2001 From: Bernardo Santiago <63428964+bernardosantiago44@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:01:46 -0600 Subject: [PATCH 12/23] Enhance Frontend UI Developer agent documentation Updated the Frontend UI Developer agent with detailed mission, scope, working rules, UI expectations, data integration, and done criteria. --- .github/agents/frontend-ui-developer.md | 74 +++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 .github/agents/frontend-ui-developer.md diff --git a/.github/agents/frontend-ui-developer.md b/.github/agents/frontend-ui-developer.md new file mode 100644 index 000000000..5d82107ad --- /dev/null +++ b/.github/agents/frontend-ui-developer.md @@ -0,0 +1,74 @@ +--- +name: Frontend UI Developer +description: Designs and implements frontend UI interfaces for the React + TypeScript application only. Focuses on reusable components, pages, layouts, and mock-driven frontend flows. Does not modify backend, database, infrastructure, or API contracts unless explicitly instructed by a human. +--- + +# Frontend UI Developer + +## Mission +Build and refine the frontend user interface for the project using React + TypeScript. + +Prioritize: +- clear and reusable UI components; +- clean page composition; +- frontend-first development with mock data/services when needed; +- consistency with existing project styles and structure. + +## Read first +Before making changes, check: + +1. `.github/copilot-instructions.md` +2. `.github/context/project-overview.md` +3. `.github/context/frontend-boundaries.md` +4. `.github/context/ui-conventions.md` + +## Scope +You may: +- create and update React components, pages, layouts, hooks, mappers, view models, mock data, and frontend services; +- improve visual hierarchy, spacing, responsiveness, and usability; +- connect UI to existing frontend DTOs and mock service layers; +- prepare the UI so real backend integration can be wired later with minimal refactoring. +- Work in the `/MtdrSpring/backend/src/main/frontend/` React subdirectory. +- Read the `/MtdrSpring/backend/src/main/java/com/springboot/MyTodoList/` java package for guidance about the response types of the backend. + +You must not: +- modify backend code, database scripts, infrastructure, CI/CD, Telegram bot code, or API contracts on your own; +- invent backend behavior without clearly isolating it behind mock services or typed interfaces; +- couple UI components directly to backend implementation details; +- introduce large dependencies unless already used in the repo or clearly justified. + +## Working rules +- Stay inside the frontend area of the repository. +- Prefer small, composable, reusable components over large page-specific ones. +- Follow existing folder and naming conventions. +- Use TypeScript interfaces/types for domain-facing data models and component props. +- Use semicolons. +- Strongly type where it improves readability and safety; avoid unnecessary noise. +- Reuse shared UI patterns before creating new ones. +- Keep components presentational when possible; place mapping/transformation logic outside UI components. +- Support loading, empty, error, and populated states where relevant. +- Keep accessibility in mind: semantic HTML, labels, keyboard navigation, and sensible contrast. +- Keep styling consistent with the project’s Tailwind and design patterns. + +## UI expectations +- Design for clarity first, then polish. +- Prefer simple layouts with strong hierarchy and consistent spacing. +- Build interfaces that are easy to extend later. +- When creating new screens, think in terms of: + - page shell; + - section blocks; + - reusable cards/lists/forms/dialogs; + - typed mock data flow. + +## Data and integration +- Assume the frontend may use mock services before real backend integration. +- Keep DTOs, view models, and mappers explicit when the transformation adds clarity. +- If backend data is missing or unclear, do not change backend assumptions; isolate the uncertainty in mock data or adapters. + +## Done criteria +A task is complete when: +- the UI works locally and is coherent with surrounding screens; +- the code is readable and reusable; +- the component/page handles its main visual states; +- changes stay within frontend scope only; +- the implementation is ready to be connected to real backend data later without major rewrites. From 66699ddffbe372eb13153f6294482bb563e8f0c8 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago <63428964+bernardosantiago44@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:06:39 -0600 Subject: [PATCH 13/23] Add project overview documentation Added a comprehensive project overview detailing the platform's objectives, user groups, architecture, and MVP focus. --- .github/context/project-overview.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/context/project-overview.md diff --git a/.github/context/project-overview.md b/.github/context/project-overview.md new file mode 100644 index 000000000..4fe6794a7 --- /dev/null +++ b/.github/context/project-overview.md @@ -0,0 +1,23 @@ +# Project Overview + +This repository contains a project management platform designed to improve productivity and activity visibility for remote and +hybrid software development teams. The system’s stated objective is to increase team productivity and visibility by 20% through +task automation, structured work tracking, and KPI reporting. The platform serves two main user groups: developers and managers. +Developers interact primarily through Telegram to review and manage their personal work, while managers need broader visibility +across the team, including progress, blockers, and estimated-versus-actual effort. + +The solution is composed of two delivery channels: a web portal and a Telegram chatbot service. The overall system follows a +cloud-native approach and is intended to run on Oracle Cloud Infrastructure with Oracle Autonomous Database, Docker, Kubernetes, +CI/CD pipelines, and infrastructure as code. The backend is planned around Java, Spring Boot, microservices, and REST-based +integrations. For frontend work, this context matters only to understand the product and data flow; frontend changes should remain +isolated from backend, infrastructure, and database implementation details. + +At the domain level, the core workflow revolves around users, teams, sprints, and work items. A work item may represent a feature, +issue, or bug, and can include assignments, tags, links to other work items, comments, time entries, and activity logs. The data model +also includes sprint baselines and KPI definitions/snapshots so the system can track productivity and reporting over time. This means +the frontend should be designed around a project/work management experience rather than a generic dashboard shell. + +From a product perspective, the MVP focuses on work item management, sprint tracking, manager visibility, Telegram-based developer +interaction, and basic KPI reporting. The frontend should therefore prioritize interfaces such as work item lists, sprint views, +detail panels, assignments, comments, time tracking, and lightweight KPI summaries. The UI should be structured so mock services +can be used first and later replaced by real backend integrations with minimal refactoring. From 1700c9f21a141deda5d34925499b89a77b6e77f1 Mon Sep 17 00:00:00 2001 From: Bernardo Santiago <63428964+bernardosantiago44@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:07:17 -0600 Subject: [PATCH 14/23] Simplify read first section in frontend-ui-developer.md Removed redundant instructions for checking files before making changes. --- .github/agents/frontend-ui-developer.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/agents/frontend-ui-developer.md b/.github/agents/frontend-ui-developer.md index 5d82107ad..e25dd9d11 100644 --- a/.github/agents/frontend-ui-developer.md +++ b/.github/agents/frontend-ui-developer.md @@ -17,10 +17,7 @@ Prioritize: ## Read first Before making changes, check: -1. `.github/copilot-instructions.md` -2. `.github/context/project-overview.md` -3. `.github/context/frontend-boundaries.md` -4. `.github/context/ui-conventions.md` +1. `.github/context/project-overview.md` ## Scope You may: From e57dd34991f6c340f19ee1e98f3a876b6f2bd7e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 20:29:24 +0000 Subject: [PATCH 15/23] Initial plan From 0cad99714854291ab19c66a56696cefbe1bdddd2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 20:50:02 +0000 Subject: [PATCH 16/23] feat: add work item dashboard with list/kanban views, create/edit/detail modals, and filters Agent-Logs-Url: https://github.com/bernardosantiago44/talos_oci_devops_project/sessions/e230285c-35dc-4860-b9c9-a10c2761acb6 Co-authored-by: bernardosantiago44 <63428964+bernardosantiago44@users.noreply.github.com> --- .../backend/src/main/frontend/src/App.tsx | 42 +- .../dashboard/dashboard-summary-cards.tsx | 94 +++++ .../dashboard/dashboard-toolbar.tsx | 114 ++++++ .../components/dashboard/kanban-view.tsx | 197 +++++++++ .../dashboard/work-item-detail-modal.tsx | 241 +++++++++++ .../dashboard/work-item-form-modal.tsx | 384 ++++++++++++++++++ .../dashboard/work-item-list-view.tsx | 202 +++++++++ .../features/work-items/lib/dashboard-ui.ts | 124 ++++++ .../work-items/mock/work-items.mock.ts | 215 ++++++++++ .../pages/work-item-dashboard-page.tsx | 234 +++++++++++ .../work-items/services/work-item.service.ts | 32 +- .../src/main/frontend/tailwind.config.js | 11 + 12 files changed, 1847 insertions(+), 43 deletions(-) create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/dashboard-summary-cards.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/dashboard-toolbar.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/kanban-view.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-detail-modal.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-form-modal.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-list-view.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/lib/dashboard-ui.ts create mode 100644 MtdrSpring/backend/src/main/frontend/src/features/work-items/pages/work-item-dashboard-page.tsx create mode 100644 MtdrSpring/backend/src/main/frontend/tailwind.config.js diff --git a/MtdrSpring/backend/src/main/frontend/src/App.tsx b/MtdrSpring/backend/src/main/frontend/src/App.tsx index 8b0638f1d..d31527d77 100644 --- a/MtdrSpring/backend/src/main/frontend/src/App.tsx +++ b/MtdrSpring/backend/src/main/frontend/src/App.tsx @@ -1,45 +1,7 @@ -import { WorkItemContextCard } from '@/features/work-items/components/work-item-context-card'; -import { WorkItemDetailHeader } from '@/features/work-items/components/work-item-detail-header'; -import type { WorkItemDetail } from '@/features/work-items/types/work-item-ui.types'; - -const mockWorkItem: WorkItemDetail = { - id: 'WI-102', - title: 'Create work item detail experience for managers and developers', - type: 'feature', - status: 'in_progress', - priority: 'high', - sprintName: 'Sprint 04 · Frontend Foundations', - estimatedHours: 12, - loggedHours: 7.5, - dueDate: 'Apr 22, 2026', - description: - 'Design and implement a polished work item detail screen that consolidates task context, assignees, discussion, related items, and activity history.', - acceptanceCriteria: [ - 'Header shows title, type, status, priority, sprint, and main actions.', - 'The layout supports comments, related links, and activity in distinct reusable panels.', - 'The visual hierarchy is strong enough for manager visibility and quick developer execution.', - ], - tags: ['frontend', 'design-system', 'mvp'], - assignees: [ - { id: 'u1', name: 'Bernardo', role: 'Manager' }, - { id: 'u2', name: 'Ana Torres', role: 'Frontend Dev' }, - { id: 'u3', name: 'Luis Vega', role: 'Backend Dev' }, - ], - reporter: { id: 'u4', name: 'Sofia Ruiz', role: 'Product Owner' }, - externalLink: 'https://example.com/spec/work-item-detail', - commentsCount: 6, - linkedItemsCount: 3, -}; +import { WorkItemDashboardPage } from '@/features/work-items/pages/work-item-dashboard-page'; function App() { - return ( -
-
- - -
-
- ); + return ; } export default App; \ No newline at end of file diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/dashboard-summary-cards.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/dashboard-summary-cards.tsx new file mode 100644 index 000000000..b34c6b4be --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/dashboard-summary-cards.tsx @@ -0,0 +1,94 @@ +import React from 'react'; +import { CheckSquare, Clock, AlertCircle, CheckCircle2, AlertTriangle } from 'lucide-react'; +import type { WorkItemDetailDto } from '../../dtos/work-item-detail.dto'; +import { isOverdue } from '../../lib/dashboard-ui'; + +interface SummaryCardsProps { + items: WorkItemDetailDto[]; +} + +interface StatCard { + label: string; + value: number; + icon: React.ReactNode; + color: string; + bg: string; + border: string; +} + +export function DashboardSummaryCards({ items }: SummaryCardsProps) { + const total = items.length; + const todo = items.filter((i) => i.status === 'TODO').length; + const inProgress = items.filter((i) => i.status === 'IN_PROGRESS').length; + const blocked = items.filter((i) => i.status === 'BLOCKED').length; + const done = items.filter((i) => i.status === 'DONE').length; + const overdue = items.filter((i) => isOverdue(i.dueDate, i.status)).length; + + const cards: StatCard[] = [ + { + label: 'Total Tasks', + value: total, + icon: , + color: 'text-zinc-300', + bg: 'bg-zinc-800/60', + border: 'border-zinc-700/50', + }, + { + label: 'Todo', + value: todo, + icon: , + color: 'text-zinc-400', + bg: 'bg-zinc-800/60', + border: 'border-zinc-700/50', + }, + { + label: 'In Progress', + value: inProgress, + icon: , + color: 'text-sky-300', + bg: 'bg-sky-500/10', + border: 'border-sky-500/20', + }, + { + label: 'Blocked', + value: blocked, + icon: , + color: 'text-rose-300', + bg: 'bg-rose-500/10', + border: 'border-rose-500/20', + }, + { + label: 'Done', + value: done, + icon: , + color: 'text-emerald-300', + bg: 'bg-emerald-500/10', + border: 'border-emerald-500/20', + }, + { + label: 'Overdue', + value: overdue, + icon: , + color: 'text-amber-300', + bg: 'bg-amber-500/10', + border: 'border-amber-500/20', + }, + ]; + + return ( +
+ {cards.map((card) => ( +
+
+ {card.icon} + {card.value} +
+

{card.label}

+
+ ))} +
+ ); +} diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/dashboard-toolbar.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/dashboard-toolbar.tsx new file mode 100644 index 000000000..dec751696 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/dashboard-toolbar.tsx @@ -0,0 +1,114 @@ +import React from 'react'; +import { Search, ListIcon, LayoutGrid, Plus } from 'lucide-react'; +import type { WorkItemStatus } from '../../enums/work-item-status.enum'; +import type { UserSummaryDto } from '@/shared/dtos/user-summary.dto'; +import { WORK_ITEM_STATUSES } from '../../enums/work-item-status.enum'; +import { formatStatusLabel } from '../../lib/dashboard-ui'; + +export type ViewMode = 'list' | 'kanban'; + +interface DashboardToolbarProps { + search: string; + onSearchChange: (v: string) => void; + statusFilter: WorkItemStatus | ''; + onStatusFilterChange: (v: WorkItemStatus | '') => void; + assigneeFilter: string; + onAssigneeFilterChange: (v: string) => void; + viewMode: ViewMode; + onViewModeChange: (v: ViewMode) => void; + onCreateClick: () => void; + users: UserSummaryDto[]; +} + +export function DashboardToolbar({ + search, + onSearchChange, + statusFilter, + onStatusFilterChange, + assigneeFilter, + onAssigneeFilterChange, + viewMode, + onViewModeChange, + onCreateClick, + users, +}: DashboardToolbarProps) { + return ( +
+ {/* Search */} +
+ + onSearchChange(e.target.value)} + className="w-full rounded-xl border border-zinc-700/60 bg-zinc-800/60 py-2 pl-9 pr-4 text-sm text-zinc-200 placeholder-zinc-500 outline-none focus:border-sky-500/60 focus:ring-1 focus:ring-sky-500/30" + /> +
+ + {/* Status filter */} + + + {/* Assignee filter */} + + + {/* View toggle */} +
+ + +
+ + {/* Create button */} + +
+ ); +} diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/kanban-view.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/kanban-view.tsx new file mode 100644 index 000000000..571696b0d --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/kanban-view.tsx @@ -0,0 +1,197 @@ +import React from 'react'; +import { CheckCircle2, Pencil, Eye } from 'lucide-react'; +import type { WorkItemDetailDto } from '../../dtos/work-item-detail.dto'; +import type { WorkItemStatus } from '../../enums/work-item-status.enum'; +import { + formatStatusLabel, + formatTypeLabel, + formatPriorityLabel, + getStatusBadgeClasses, + getPriorityBadgeClasses, + getTypeBadgeClasses, + getStatusDotColor, + calcProgress, + isOverdue, + formatDate, + getInitials, + cx, +} from '../../lib/dashboard-ui'; + +interface KanbanViewProps { + items: WorkItemDetailDto[]; + onEdit: (item: WorkItemDetailDto) => void; + onComplete: (item: WorkItemDetailDto) => void; + onViewDetail: (item: WorkItemDetailDto) => void; +} + +const COLUMNS: { status: WorkItemStatus; label: string }[] = [ + { status: 'TODO', label: 'Todo' }, + { status: 'IN_PROGRESS', label: 'In Progress' }, + { status: 'BLOCKED', label: 'Blocked' }, + { status: 'DONE', label: 'Done' }, +]; + +function KanbanCard({ + item, + onEdit, + onComplete, + onViewDetail, +}: { + item: WorkItemDetailDto; + onEdit: (item: WorkItemDetailDto) => void; + onComplete: (item: WorkItemDetailDto) => void; + onViewDetail: (item: WorkItemDetailDto) => void; +}) { + const progress = calcProgress(item.totalLoggedMinutes, item.estimatedMinutes); + const overdue = isOverdue(item.dueDate, item.status); + const isDone = item.status === 'DONE'; + + return ( +
+ {/* Type + Priority badges */} +
+ + {formatTypeLabel(item.type)} + + + {formatPriorityLabel(item.priority)} + +
+ + {/* Title */} + + + {/* Due date */} + {item.dueDate && ( +

+ Due {formatDate(item.dueDate)} +

+ )} + + {/* Progress bar */} + {item.estimatedMinutes && item.estimatedMinutes > 0 && ( +
+
+
+
+
+ )} + + {/* Footer: assignees + actions */} +
+
+ {item.assignees.length === 0 && ( + Unassigned + )} + {item.assignees.slice(0, 3).map((a, i) => ( +
+ {getInitials(a.user.name)} +
+ ))} +
+ +
+ + + {!isDone && ( + + )} +
+
+
+ ); +} + +export function KanbanView({ items, onEdit, onComplete, onViewDetail }: KanbanViewProps) { + return ( +
+ {COLUMNS.map(({ status, label }) => { + const colItems = items.filter((i) => i.status === status); + return ( +
+ {/* Column header */} +
+ + c.startsWith('text-')) ?? 'text-zinc-300', + )} + > + {formatStatusLabel(status)} + + + {colItems.length} + +
+ + {/* Cards */} +
+ {colItems.length === 0 && ( +
+

No items

+
+ )} + {colItems.map((item) => ( + + ))} +
+
+ ); + })} +
+ ); +} diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-detail-modal.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-detail-modal.tsx new file mode 100644 index 000000000..7edd961b5 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-detail-modal.tsx @@ -0,0 +1,241 @@ +import React from 'react'; +import { X, Calendar, Flag, Clock, Tag, Users, CheckCircle2 } from 'lucide-react'; +import type { WorkItemDetailDto } from '../../dtos/work-item-detail.dto'; +import { + formatStatusLabel, + formatTypeLabel, + formatPriorityLabel, + getStatusBadgeClasses, + getPriorityBadgeClasses, + getTypeBadgeClasses, + calcProgress, + isOverdue, + formatDate, + getSprintLabel, + getInitials, + cx, +} from '../../lib/dashboard-ui'; + +interface WorkItemDetailModalProps { + isOpen: boolean; + item: WorkItemDetailDto | null; + onClose: () => void; + onEdit: (item: WorkItemDetailDto) => void; + onComplete: (item: WorkItemDetailDto) => void; +} + +function DetailRow({ icon, label, children }: { + icon: React.ReactNode; + label: string; + children: React.ReactNode; +}) { + return ( +
+
{icon}
+
+

{label}

+
{children}
+
+
+ ); +} + +export function WorkItemDetailModal({ + isOpen, + item, + onClose, + onEdit, + onComplete, +}: WorkItemDetailModalProps) { + if (!isOpen || !item) return null; + + const progress = calcProgress(item.totalLoggedMinutes, item.estimatedMinutes); + const overdue = isOverdue(item.dueDate, item.status); + const isDone = item.status === 'DONE'; + + return ( +
+ {/* Overlay */} +
+ + {/* Panel */} +
+ {/* Header */} +
+
+
+
+ + {formatTypeLabel(item.type)} + + + {formatStatusLabel(item.status)} + + + {formatPriorityLabel(item.priority)} + +
+

+ {item.title} +

+

{item.id}

+
+ +
+
+ + {/* Body */} +
+
+ {/* Description */} + {item.description && ( +
+

Description

+

+ {item.description} +

+
+ )} + + {/* Meta grid */} +
+ } label="Due Date"> + + {formatDate(item.dueDate)} + {overdue && ' · Overdue'} + + + + } label="Sprint"> + {getSprintLabel(item.sprintId)} + + + } label="Time"> + + {item.totalLoggedMinutes} + {item.estimatedMinutes ? `/${item.estimatedMinutes}` : ''} min + + + + } label="Progress"> +
+
+
+
+ {progress}% +
+ +
+ + {/* Assignees */} + } label="Assignees"> + {item.assignees.length === 0 ? ( + Unassigned + ) : ( +
+ {item.assignees.map((a) => ( +
+
+ {getInitials(a.user.name)} +
+
+

{a.user.name}

+

{a.role}

+
+
+ ))} +
+ )} +
+ + {/* Tags */} + {item.tags.length > 0 && ( + } label="Tags"> +
+ {item.tags.map((tag) => ( + + #{tag.name} + + ))} +
+
+ )} + + {/* Comments placeholder */} +
+

Activity

+

+ Comments and activity history will appear here once connected to the backend. +

+
+
+
+ + {/* Footer */} +
+ + {!isDone && ( + + )} +
+
+
+ ); +} diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-form-modal.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-form-modal.tsx new file mode 100644 index 000000000..0d3002619 --- /dev/null +++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-form-modal.tsx @@ -0,0 +1,384 @@ +import React, { useEffect, useState } from 'react'; +import { X } from 'lucide-react'; +import type { WorkItemDetailDto } from '../../dtos/work-item-detail.dto'; +import type { CreateWorkItemDto } from '../../dtos/create-work-item.dto'; +import type { UpdateWorkItemDto } from '../../dtos/update-work-item.dto'; +import type { WorkItemType } from '../../enums/work-item-type.enum'; +import type { WorkItemStatus } from '../../enums/work-item-status.enum'; +import type { WorkItemPriority } from '../../enums/work-item-priority.enum'; +import type { UserSummaryDto } from '@/shared/dtos/user-summary.dto'; +import type { TagDto } from '@/shared/dtos/tag.dto'; +import { WORK_ITEM_TYPES } from '../../enums/work-item-type.enum'; +import { WORK_ITEM_STATUSES } from '../../enums/work-item-status.enum'; +import { WORK_ITEM_PRIORITIES } from '../../enums/work-item-priority.enum'; +import { + formatTypeLabel, + formatStatusLabel, + formatPriorityLabel, +} from '../../lib/dashboard-ui'; + +interface WorkItemFormModalProps { + isOpen: boolean; + item?: WorkItemDetailDto | null; + users: UserSummaryDto[]; + tags: TagDto[]; + onClose: () => void; + onCreate: (dto: CreateWorkItemDto) => Promise; + onUpdate: (id: string, dto: UpdateWorkItemDto) => Promise; +} + +interface FormState { + title: string; + description: string; + type: WorkItemType; + status: WorkItemStatus; + priority: WorkItemPriority; + dueDate: string; + estimatedMinutes: string; + sprintId: string; + assigneeUserIds: string[]; + tagIds: string[]; +} + +const DEFAULT_FORM: FormState = { + title: '', + description: '', + type: 'TASK', + status: 'TODO', + priority: 'MEDIUM', + dueDate: '', + estimatedMinutes: '', + sprintId: '', + assigneeUserIds: [], + tagIds: [], +}; + +const SPRINT_OPTIONS = [ + { id: '', label: 'No Sprint' }, + { id: 'spr-001', label: 'Sprint 1' }, + { id: 'spr-002', label: 'Sprint 2' }, + { id: 'spr-003', label: 'Sprint 3' }, +]; + +function Label({ children }: { children: React.ReactNode }) { + return ; +} + +function Input({ value, onChange, placeholder, type = 'text' }: { + value: string; + onChange: (v: string) => void; + placeholder?: string; + type?: string; +}) { + return ( + onChange(e.target.value)} + placeholder={placeholder} + className="w-full rounded-xl border border-zinc-700/60 bg-zinc-800/60 px-3 py-2 text-sm text-zinc-200 placeholder-zinc-600 outline-none focus:border-sky-500/60 focus:ring-1 focus:ring-sky-500/30" + /> + ); +} + +function Select({ value, onChange, children }: { + value: string; + onChange: (v: string) => void; + children: React.ReactNode; +}) { + return ( + + ); +} + +export function WorkItemFormModal({ + isOpen, + item, + users, + tags, + onClose, + onCreate, + onUpdate, +}: WorkItemFormModalProps) { + const isEditing = !!item; + const [form, setForm] = useState(DEFAULT_FORM); + const [saving, setSaving] = useState(false); + const [error, setError] = useState(''); + + useEffect(() => { + if (!isOpen) return; + if (item) { + setForm({ + title: item.title, + description: item.description ?? '', + type: item.type, + status: item.status, + priority: item.priority, + dueDate: item.dueDate ?? '', + estimatedMinutes: item.estimatedMinutes?.toString() ?? '', + sprintId: item.sprintId ?? '', + assigneeUserIds: item.assignees.map((a) => a.user.id), + tagIds: item.tags.map((t) => t.id), + }); + } else { + setForm(DEFAULT_FORM); + } + setError(''); + }, [isOpen, item]); + + function set(key: K, value: FormState[K]) { + setForm((prev) => ({ ...prev, [key]: value })); + } + + function toggleArrayItem(key: 'assigneeUserIds' | 'tagIds', id: string) { + setForm((prev) => { + const arr = prev[key] as string[]; + return { + ...prev, + [key]: arr.includes(id) ? arr.filter((x) => x !== id) : [...arr, id], + }; + }); + } + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + if (!form.title.trim()) { + setError('Title is required.'); + return; + } + setSaving(true); + setError(''); + try { + const minutes = form.estimatedMinutes ? parseInt(form.estimatedMinutes, 10) : undefined; + if (isEditing && item) { + const dto: UpdateWorkItemDto = { + title: form.title.trim(), + description: form.description.trim() || undefined, + status: form.status, + priority: form.priority, + dueDate: form.dueDate || undefined, + estimatedMinutes: minutes, + assigneeUserIds: form.assigneeUserIds, + tagIds: form.tagIds, + }; + await onUpdate(item.id, dto); + } else { + const dto: CreateWorkItemDto = { + title: form.title.trim(), + description: form.description.trim() || undefined, + type: form.type, + status: form.status, + priority: form.priority, + dueDate: form.dueDate || undefined, + estimatedMinutes: minutes, + sprintId: form.sprintId || undefined, + assigneeUserIds: form.assigneeUserIds, + tagIds: form.tagIds, + }; + await onCreate(dto); + } + onClose(); + } catch { + setError('Something went wrong. Please try again.'); + } finally { + setSaving(false); + } + } + + if (!isOpen) return null; + + return ( +
+ {/* Overlay */} +
+ + {/* Panel */} +
+ {/* Header */} +
+

+ {isEditing ? 'Edit Task' : 'New Task'} +

+ +
+ + {/* Form */} +
+ {error && ( +

+ {error} +

+ )} + +
+ {/* Title */} +
+ + set('title', v)} + placeholder="Task title…" + /> +
+ + {/* Description */} +
+ +