diff --git a/.github/agents/frontend-ui-developer.md b/.github/agents/frontend-ui-developer.md
new file mode 100644
index 000000000..3b954526d
--- /dev/null
+++ b/.github/agents/frontend-ui-developer.md
@@ -0,0 +1,72 @@
+---
+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/context/project-overview.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.
+- For complex pages or heavy state-based interfaces, prefer to use a viewModel in a separate file to avoid big useState soups.
+
+## 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.
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.
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..34ff10e49
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/craco.config.js
@@ -0,0 +1,23 @@
+const path = require('path');
+
+module.exports = {
+ webpack: {
+ alias: {
+ '@': path.resolve(__dirname, 'src'),
+ },
+ },
+ 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 382891ec0..8ca352f2d 100644
--- a/MtdrSpring/backend/src/main/frontend/package-lock.json
+++ b/MtdrSpring/backend/src/main/frontend/package-lock.json
@@ -8,23 +8,33 @@
"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",
+ "lucide-react": "^1.8.0",
"moment": "^2.29.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-moment": "^1.1.2",
"react-scripts": "5.0.0",
- "typescript": "^4.6.4"
+ "recharts": "^2.1.16"
+ },
+ "devDependencies": {
+ "autoprefixer": "^10.5.0",
+ "postcss": "^8.5.10",
+ "tailwindcss": "^3.4.19",
+ "typescript": "~4.9.5"
}
},
"node_modules/@alloc/quick-lru": {
"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"
},
@@ -2016,6 +2026,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",
@@ -2286,6 +2342,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",
@@ -3214,16 +3301,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": {
@@ -3234,14 +3328,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",
@@ -3252,24 +3338,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",
@@ -3556,6 +3639,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",
@@ -3616,6 +3717,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",
@@ -3682,6 +3793,13 @@
"url": "https://opencollective.com/popperjs"
}
},
+ "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",
@@ -4000,6 +4118,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",
@@ -4016,6 +4421,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",
@@ -4087,6 +4526,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",
@@ -4190,9 +4674,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",
@@ -4715,9 +5203,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"
},
@@ -4906,7 +5395,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",
@@ -4923,7 +5413,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",
@@ -5077,9 +5568,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",
@@ -5088,14 +5579,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": {
@@ -5420,6 +5915,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",
@@ -5541,11 +6048,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"
@@ -5557,9 +6065,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",
@@ -5574,11 +6082,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"
@@ -5663,6 +6173,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"
}
@@ -5679,9 +6190,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",
@@ -5695,7 +6206,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",
@@ -5740,15 +6252,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",
@@ -5761,6 +6268,9 @@
"engines": {
"node": ">= 8.10.0"
},
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
"optionalDependencies": {
"fsevents": "~2.3.2"
}
@@ -5803,6 +6313,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",
@@ -5832,6 +6348,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",
@@ -6080,9 +6610,43 @@
"node": ">=10"
}
},
- "node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "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",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dependencies": {
"path-key": "^3.1.0",
@@ -6319,6 +6883,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",
@@ -6438,6 +7008,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",
@@ -6496,9 +7075,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 +7195,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",
@@ -6624,6 +7286,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",
@@ -6669,7 +7340,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",
@@ -6693,7 +7374,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",
@@ -6856,9 +7538,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",
@@ -6893,12 +7576,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"
@@ -6980,6 +7664,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",
@@ -7023,9 +7716,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"
}
@@ -7906,16 +8600,26 @@
"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",
- "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"
@@ -8035,9 +8739,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"
},
@@ -8111,6 +8816,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",
@@ -8311,6 +9025,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",
@@ -8333,15 +9056,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": {
@@ -8376,10 +9100,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"
@@ -8389,9 +9114,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",
@@ -8722,6 +9451,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",
@@ -9112,6 +9853,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",
@@ -9187,11 +9934,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"
@@ -9285,6 +10036,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"
}
@@ -9330,6 +10082,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",
@@ -9471,6 +10235,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",
@@ -11521,9 +12294,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"
}
@@ -11811,6 +12585,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",
@@ -11916,6 +12939,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",
@@ -11946,6 +12978,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",
@@ -12005,11 +13043,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": {
@@ -12185,6 +13224,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",
@@ -12192,15 +13232,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"
},
@@ -12254,9 +13295,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",
@@ -12266,14 +13308,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",
@@ -12324,6 +13358,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"
}
@@ -12669,9 +13704,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",
@@ -12688,6 +13724,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"
}
@@ -12827,9 +13864,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",
@@ -12844,10 +13881,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"
@@ -13225,6 +14263,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",
@@ -13246,19 +14285,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"
}
@@ -13283,39 +14329,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": {
@@ -13509,19 +14573,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"
}
@@ -13907,9 +14978,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"
@@ -14396,6 +15468,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 +15492,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 +15577,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",
@@ -14505,6 +15636,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"
}
@@ -14533,6 +15665,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 +15721,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",
@@ -14671,17 +15864,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"
}
@@ -14808,6 +16006,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",
@@ -15221,6 +16453,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",
@@ -15303,9 +16547,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"
}
@@ -15622,16 +16867,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": {
@@ -15639,36 +16885,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",
@@ -15813,33 +17041,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",
@@ -15849,12 +17077,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": {
@@ -15985,6 +17230,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"
}
@@ -15993,6 +17239,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"
},
@@ -16015,6 +17262,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",
@@ -16032,6 +17324,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"
},
@@ -16088,7 +17381,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",
@@ -16211,6 +17566,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"
@@ -16233,6 +17589,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",
@@ -16311,9 +17673,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",
@@ -16328,9 +17690,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"
@@ -16396,6 +17759,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",
@@ -16425,6 +17794,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",
@@ -16760,6 +18220,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",
@@ -16899,6 +18373,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",
@@ -17307,14 +18787,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",
@@ -17340,6 +18812,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",
@@ -18685,6 +20166,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",
@@ -18811,6 +20325,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",
@@ -19500,13 +21042,21 @@
}
},
"@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": {
@@ -19514,11 +21064,6 @@
"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=="
- },
"@jridgewell/source-map": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz",
@@ -19529,24 +21074,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": {
@@ -19679,6 +21217,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",
@@ -19726,6 +21273,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",
@@ -19754,6 +21307,12 @@
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
},
+ "@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",
@@ -19948,6 +21507,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",
@@ -19958,6 +21667,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",
@@ -20029,6 +21767,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",
@@ -20132,9 +21909,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",
@@ -20551,9 +22331,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",
@@ -20817,15 +22597,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"
}
},
@@ -21064,6 +22843,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",
@@ -21168,11 +22952,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": {
@@ -21181,14 +22965,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": {
@@ -21259,9 +23044,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",
@@ -21296,9 +23081,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",
@@ -21335,6 +23120,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",
@@ -21360,6 +23150,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",
@@ -21554,8 +23354,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",
@@ -21702,6 +23523,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",
@@ -21734,6 +23560,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": {
@@ -21828,9 +23661,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 +23760,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",
@@ -21917,6 +23822,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",
@@ -21956,6 +23866,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",
@@ -22098,9 +24013,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",
@@ -22123,12 +24038,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": {
@@ -22198,6 +24113,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",
@@ -22232,9 +24152,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",
@@ -22872,16 +24792,21 @@
"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",
- "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": {
@@ -22977,9 +24902,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"
}
@@ -23037,6 +24962,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",
@@ -23164,6 +25094,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=="
}
}
},
@@ -23183,9 +25118,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",
@@ -23213,15 +25148,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",
@@ -23449,6 +25384,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",
@@ -23736,6 +25679,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",
@@ -23787,11 +25735,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": {
@@ -23873,6 +25821,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",
@@ -23969,6 +25925,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",
@@ -25467,9 +27428,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",
@@ -25701,6 +27662,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",
@@ -25788,6 +27834,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",
@@ -25811,6 +27863,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",
@@ -25858,11 +27915,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"
}
},
@@ -25990,9 +28047,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",
@@ -26034,20 +28091,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",
@@ -26326,9 +28378,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",
@@ -26437,13 +28489,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": {
@@ -26653,9 +28705,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"
}
@@ -26670,18 +28722,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=="
}
}
},
@@ -26796,11 +28847,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": {
@@ -27027,9 +29078,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"
@@ -27396,6 +29447,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 +29463,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 +29526,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 +29593,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 +29637,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",
@@ -27609,11 +29755,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"
}
@@ -27694,6 +29841,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",
@@ -27993,6 +30165,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",
@@ -28057,9 +30237,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",
@@ -28295,16 +30475,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": {
@@ -28312,19 +30492,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"
- }
}
}
},
@@ -28447,39 +30614,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",
@@ -28589,6 +30762,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",
@@ -28648,6 +30843,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",
@@ -28755,6 +30985,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",
@@ -28808,12 +31043,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": {
@@ -28864,6 +31099,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",
@@ -28886,6 +31126,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",
@@ -29133,6 +31395,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",
@@ -29224,6 +31496,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",
@@ -29574,11 +31851,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",
@@ -29598,6 +31870,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 f92323cbe..077b10ff0 100644
--- a/MtdrSpring/backend/src/main/frontend/package.json
+++ b/MtdrSpring/backend/src/main/frontend/package.json
@@ -3,21 +3,25 @@
"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",
+ "lucide-react": "^1.8.0",
"moment": "^2.29.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-moment": "^1.1.2",
"react-scripts": "5.0.0",
- "typescript": "^4.6.4"
+ "recharts": "^2.1.16"
},
+ "proxy": "http://localhost:8080",
"scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build"
+ "start": "craco start",
+ "build": "craco build"
},
"eslintConfig": {
"extends": "react-app"
@@ -25,5 +29,11 @@
"browserslist": [
"last 5 versions"
],
- "homepage": "."
+ "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
deleted file mode 100644
index 21462dd91..000000000
--- a/MtdrSpring/backend/src/main/frontend/src/App.js
+++ /dev/null
@@ -1,240 +0,0 @@
- /*
-## 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 API_LIST from './API';
-import DeleteIcon from '@mui/icons-material/Delete';
-import { Button, TableBody, 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.
- */
-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',
- })
- .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 ...');
- }
- })
- .then(
- (result) => {
- const remainingItems = items.filter(item => item.id !== deleteId);
- setItems(remainingItems);
- },
- (error) => {
- setError(error);
- }
- );
- }
- 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)
- })
- .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(
- (result) => {
- var id = result.headers.get('location');
- var newItem = {"id": id, "description": text}
- setItems([newItem, ...items]);
- setInserting(false);
- },
- (error) => {
- setInserting(false);
- setError(error);
- }
- );
- }
- 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} |
- |
- } variant="contained" className="DeleteButton" onClick={() => deleteItem(item.id)} size="small">
- Delete
- |
-
- )))}
-
-
-
- }
-
-
- );
-}
-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..d31527d77
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/App.tsx
@@ -0,0 +1,7 @@
+import { WorkItemDashboardPage } from '@/features/work-items/pages/work-item-dashboard-page';
+
+function App() {
+ return ;
+}
+
+export default App;
\ No newline at end of file
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
deleted file mode 100644
index c52158419..000000000
--- a/MtdrSpring/backend/src/main/frontend/src/NewItem.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-## 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:
- props.addItem(item);
- setItem("");
- e.preventDefault();
- }
- function handleChange(e) {
- setItem(e.target.value);
- }
- return (
-
-
-
- );
-}
-
-export default NewItem;
\ No newline at end of file
diff --git a/MtdrSpring/backend/src/main/frontend/src/NewItem.tsx b/MtdrSpring/backend/src/main/frontend/src/NewItem.tsx
new file mode 100644
index 000000000..c116bd23c
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/NewItem.tsx
@@ -0,0 +1,36 @@
+import React, { useState } from "react";
+
+function NewItem(props: { isInserting: boolean, addItem: (item: any) => void }) {
+ const [item, setItem] = useState('');
+
+ function handleSubmit(e: any) {
+ e.preventDefault();
+ if (!item.trim()) return;
+ props.addItem(item);
+ setItem("");
+ }
+
+ return (
+
+ +
+ setItem(e.target.value)}
+ onKeyDown={e => { if (e.key === 'Enter') handleSubmit(e); }}
+ />
+
+
+ );
+}
+
+export default NewItem;
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/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..e5c7c0c2b
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/kanban-view.tsx
@@ -0,0 +1,192 @@
+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,
+ getPriorityBadgeClasses,
+ getTypeBadgeClasses,
+ getStatusDotColor,
+ getStatusTextColor,
+ 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 */}
+
+
+
+ {formatStatusLabel(status)}
+
+
+ {colItems.length}
+
+
+
+ {/* Cards */}
+
+ {colItems.length === 0 && (
+
+ )}
+ {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 (
+
+ );
+}
+
+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">
+
+
+
+
+ {/* 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 */}
+
+
+
+ );
+}
diff --git a/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-list-view.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-list-view.tsx
new file mode 100644
index 000000000..0cea0b7c7
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/components/dashboard/work-item-list-view.tsx
@@ -0,0 +1,202 @@
+import React from 'react';
+import { CheckCircle2, Pencil, Eye } 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 WorkItemListViewProps {
+ items: WorkItemDetailDto[];
+ onEdit: (item: WorkItemDetailDto) => void;
+ onComplete: (item: WorkItemDetailDto) => void;
+ onViewDetail: (item: WorkItemDetailDto) => void;
+}
+
+function Pill({ children, className }: { children: React.ReactNode; className?: string }) {
+ return (
+
+ {children}
+
+ );
+}
+
+function AvatarStack({ names }: { names: string[] }) {
+ if (names.length === 0) {
+ return Unassigned;
+ }
+ return (
+
+ {names.slice(0, 3).map((name, i) => (
+
+ {getInitials(name)}
+
+ ))}
+ {names.length > 3 && (
+
+ +{names.length - 3}
+
+ )}
+
+ );
+}
+
+function ProgressBar({ value }: { value: number }) {
+ return (
+
+ );
+}
+
+export function WorkItemListView({ items, onEdit, onComplete, onViewDetail }: WorkItemListViewProps) {
+ if (items.length === 0) {
+ return (
+
+
+
No tasks found
+
Try adjusting your filters or create a new task.
+
+ );
+ }
+
+ return (
+
+ {/* Table header */}
+
+ Title
+ Type
+ Status
+ Priority
+ Assignees
+ Due Date
+ Sprint
+ Progress
+ Actions
+
+
+
+ {items.map((item) => {
+ const progress = calcProgress(item.totalLoggedMinutes, item.estimatedMinutes);
+ const overdue = isOverdue(item.dueDate, item.status);
+ const assigneeNames = item.assignees.map((a) => a.user.name);
+ const isDone = item.status === 'DONE';
+
+ return (
+
+ {/* Title */}
+
+
+ {item.id}
+
+
+ {/* Type */}
+
+ {formatTypeLabel(item.type)}
+
+
+ {/* Status */}
+
+ {formatStatusLabel(item.status)}
+
+
+ {/* Priority */}
+
+ {formatPriorityLabel(item.priority)}
+
+
+ {/* Assignees */}
+
+
+ {/* Due Date */}
+
+ {formatDate(item.dueDate)}
+
+
+ {/* Sprint */}
+
+ {getSprintLabel(item.sprintId)}
+
+
+ {/* Progress */}
+
+
+ {/* Actions */}
+
+
+
+ {!isDone && (
+
+ )}
+
+
+ );
+ })}
+
+
+ );
+}
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) => (
+
+ ))}
+
+
+
+
+ );
+}
\ 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/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/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..c9efd9be8
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/create-work-item.dto.ts
@@ -0,0 +1,27 @@
+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 { BugDetails } from "../model/bug-details.model";
+
+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?: BugDetails;
+};
\ 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/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-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
new file mode 100644
index 000000000..abddc34bb
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/dtos/work-item-detail.dto.ts
@@ -0,0 +1,41 @@
+import type { TagDto } from '@/shared/dtos/tag.dto';
+import type { UserSummaryDto } from '@/shared/dtos/user-summary.dto';
+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';
+import type { FeatureDetails } from "@/features/work-items/model/feature-details.model";
+import type { IssueDetails } from "@/features/work-items/model/issue-details.model";
+import type { BugDetails } from "@/features/work-items/model/bug-details.model";
+
+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: Assignee[];
+ tags: TagDto[];
+ featureDetails?: FeatureDetails;
+ issueDetails?: IssueDetails;
+ bugDetails?: BugDetails;
+};
+
+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/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-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/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
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..06fcb9a44
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/enums/work-item-status.enum.ts
@@ -0,0 +1,23 @@
+export const WORK_ITEM_STATUSES = [
+ 'TODO',
+ 'NEW',
+ 'IN_PROGRESS',
+ 'BLOCKED',
+ 'DONE'
+] as const;
+
+export type WorkItemStatus = (typeof WORK_ITEM_STATUSES)[number];
+
+/** Backend stores 'NEW'; the UI treats it as 'TODO'. */
+export function normalizeStatus(raw: string | null | undefined): WorkItemStatus {
+ if (!raw) return 'TODO';
+ const upper = raw.toUpperCase();
+ if (upper === 'NEW') return 'TODO';
+ if (WORK_ITEM_STATUSES.includes(upper as WorkItemStatus)) return upper as WorkItemStatus;
+ return 'TODO';
+}
+
+/** Convert frontend status back to backend format for API calls. */
+export function toBackendStatus(status: WorkItemStatus): string {
+ return status === 'TODO' ? 'NEW' : status;
+}
\ 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/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/dashboard-ui.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/lib/dashboard-ui.ts
new file mode 100644
index 000000000..ebb38c67b
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/lib/dashboard-ui.ts
@@ -0,0 +1,132 @@
+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 function cx(...classes: Array): string {
+ return classes.filter(Boolean).join(' ');
+}
+
+export function getInitials(name: string): string {
+ return name
+ .split(' ')
+ .map((part) => part[0])
+ .join('')
+ .slice(0, 2)
+ .toUpperCase();
+}
+
+export function formatStatusLabel(status: WorkItemStatus): string {
+ switch (status) {
+ case 'TODO': return 'Todo';
+ case 'NEW': return 'Todo';
+ case 'IN_PROGRESS': return 'In Progress';
+ case 'BLOCKED': return 'Blocked';
+ case 'DONE': return 'Done';
+ default: return status;
+ }
+}
+
+export function formatTypeLabel(type: WorkItemType): string {
+ switch (type) {
+ case 'FEATURE': return 'Feature';
+ case 'BUG': return 'Bug';
+ case 'ISSUE': return 'Issue';
+ case 'TASK': return 'Task';
+ default: return type;
+ }
+}
+
+export function formatPriorityLabel(priority: WorkItemPriority): string {
+ switch (priority) {
+ case 'LOW': return 'Low';
+ case 'MEDIUM': return 'Medium';
+ case 'HIGH': return 'High';
+ case 'CRITICAL': return 'Critical';
+ default: return priority;
+ }
+}
+
+export function getStatusBadgeClasses(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-400';
+ }
+}
+
+export function getPriorityBadgeClasses(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-400';
+ }
+}
+
+export function getTypeBadgeClasses(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 getStatusTextColor(status: WorkItemStatus): string {
+ switch (status) {
+ case 'DONE': return 'text-emerald-300';
+ case 'BLOCKED': return 'text-rose-300';
+ case 'IN_PROGRESS': return 'text-sky-300';
+ case 'TODO': return 'text-zinc-400';
+ default: return 'text-zinc-300';
+ }
+}
+
+export function getStatusDotColor(status: WorkItemStatus): string {
+ switch (status) {
+ case 'DONE': return 'bg-emerald-400';
+ case 'BLOCKED': return 'bg-rose-400';
+ case 'IN_PROGRESS': return 'bg-sky-400';
+ case 'TODO': return 'bg-zinc-500';
+ default: return 'bg-zinc-500';
+ }
+}
+
+export function calcProgress(logged: number, estimated?: number): number {
+ if (!estimated || estimated === 0) return 0;
+ return Math.min(100, Math.round((logged / estimated) * 100));
+}
+
+export function isOverdue(dueDate?: string, status?: WorkItemStatus): boolean {
+ if (!dueDate || status === 'DONE') return false;
+ const today = new Date().toISOString().slice(0, 10);
+ return dueDate < today;
+}
+
+export function formatDate(dateStr?: string): string {
+ if (!dateStr) return '—';
+ const d = new Date(dateStr);
+ return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
+}
+
+export function getSprintLabel(sprintId?: string, sprintMap?: Record): string {
+ if (!sprintId) return '—';
+ if (sprintMap && sprintMap[sprintId]) return sprintMap[sprintId];
+ return sprintId;
+}
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/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/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/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..4f3d5bc1c
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/mock/work-items.mock.ts
@@ -0,0 +1,362 @@
+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.'
+ }
+ },
+ {
+ id: 'wrk-004',
+ sprintId: 'spr-001',
+ title: 'Set up CI pipeline for frontend builds',
+ description: 'Configure GitHub Actions workflow to lint, test, and build the React app on each push.',
+ type: 'TASK',
+ status: 'DONE',
+ priority: 'HIGH',
+ estimatedMinutes: 240,
+ totalLoggedMinutes: 210,
+ dueDate: '2026-04-12',
+ createdAt: '2026-04-08T10:00:00Z',
+ updatedAt: '2026-04-12T15:00:00Z',
+ completedAt: '2026-04-12T15:00:00Z',
+ createdBy: {
+ id: 'usr-001',
+ name: 'Bernardo Manager',
+ email: 'bernardo.manager@demo.com',
+ telegramUserId: 'tg_bernardo_manager'
+ },
+ assignees: [
+ {
+ id: 'asg-004',
+ user: {
+ id: 'usr-003',
+ name: 'Luis Developer',
+ email: 'luis.dev@demo.com',
+ telegramUserId: 'tg_luis_dev'
+ },
+ role: 'OWNER',
+ assignedAt: '2026-04-08T11:00:00Z'
+ }
+ ],
+ tags: [
+ {
+ id: 'tag-001',
+ name: 'Frontend',
+ color: '#3B82F6',
+ description: 'UI and client-side work'
+ }
+ ]
+ },
+ {
+ id: 'wrk-005',
+ sprintId: 'spr-001',
+ title: 'Design shared component library tokens',
+ description: 'Define color, spacing, and typography tokens used across the design system.',
+ type: 'FEATURE',
+ status: 'DONE',
+ priority: 'MEDIUM',
+ estimatedMinutes: 300,
+ totalLoggedMinutes: 300,
+ dueDate: '2026-04-14',
+ createdAt: '2026-04-09T08:00:00Z',
+ updatedAt: '2026-04-14T12:00:00Z',
+ completedAt: '2026-04-14T12:00:00Z',
+ createdBy: {
+ id: 'usr-002',
+ name: 'Ana Developer',
+ email: 'ana.dev@demo.com',
+ telegramUserId: 'tg_ana_dev'
+ },
+ assignees: [
+ {
+ id: 'asg-005',
+ user: {
+ id: 'usr-002',
+ name: 'Ana Developer',
+ email: 'ana.dev@demo.com',
+ telegramUserId: 'tg_ana_dev'
+ },
+ role: 'OWNER',
+ assignedAt: '2026-04-09T08:30:00Z'
+ }
+ ],
+ tags: [
+ {
+ id: 'tag-001',
+ name: 'Frontend',
+ color: '#3B82F6',
+ description: 'UI and client-side work'
+ }
+ ],
+ featureDetails: {
+ businessValue: 'Ensures visual consistency across all UI components.',
+ acceptanceCriteria: 'Tokens documented and applied in at least 3 shared components.'
+ }
+ },
+ {
+ id: 'wrk-006',
+ sprintId: 'spr-002',
+ title: 'Implement sprint progress API endpoint',
+ description: 'Expose a REST endpoint returning current sprint completion percentage and item breakdown.',
+ type: 'FEATURE',
+ status: 'TODO',
+ priority: 'HIGH',
+ estimatedMinutes: 480,
+ totalLoggedMinutes: 0,
+ dueDate: '2026-04-30',
+ createdAt: '2026-04-15T09:00:00Z',
+ updatedAt: '2026-04-15T09:00:00Z',
+ createdBy: {
+ id: 'usr-001',
+ name: 'Bernardo Manager',
+ email: 'bernardo.manager@demo.com',
+ telegramUserId: 'tg_bernardo_manager'
+ },
+ assignees: [
+ {
+ id: 'asg-006',
+ user: {
+ id: 'usr-003',
+ name: 'Luis Developer',
+ email: 'luis.dev@demo.com',
+ telegramUserId: 'tg_luis_dev'
+ },
+ role: 'ASSIGNEE',
+ assignedAt: '2026-04-15T09:30:00Z'
+ }
+ ],
+ tags: [
+ {
+ id: 'tag-002',
+ name: 'Backend',
+ color: '#10B981',
+ description: 'API and service work'
+ }
+ ],
+ featureDetails: {
+ businessValue: 'Enables real-time sprint dashboards for managers.',
+ acceptanceCriteria: 'Endpoint returns 200 with correct data shape. Validated with integration tests.'
+ }
+ },
+ {
+ id: 'wrk-007',
+ sprintId: 'spr-002',
+ title: 'Fix date timezone offset in due date display',
+ description: 'Due dates appear one day off when the user is in UTC-5 or earlier timezones.',
+ type: 'BUG',
+ status: 'IN_PROGRESS',
+ priority: 'MEDIUM',
+ estimatedMinutes: 120,
+ totalLoggedMinutes: 60,
+ dueDate: '2026-04-17',
+ createdAt: '2026-04-13T14:00:00Z',
+ updatedAt: '2026-04-15T11:00:00Z',
+ createdBy: {
+ id: 'usr-003',
+ name: 'Luis Developer',
+ email: 'luis.dev@demo.com',
+ telegramUserId: 'tg_luis_dev'
+ },
+ assignees: [
+ {
+ id: 'asg-007',
+ user: {
+ id: 'usr-002',
+ name: 'Ana Developer',
+ email: 'ana.dev@demo.com',
+ telegramUserId: 'tg_ana_dev'
+ },
+ role: 'OWNER',
+ assignedAt: '2026-04-13T15:00:00Z'
+ }
+ ],
+ tags: [
+ {
+ id: 'tag-003',
+ name: 'Bug',
+ color: '#EF4444',
+ description: 'Defect or error'
+ },
+ {
+ id: 'tag-001',
+ name: 'Frontend',
+ color: '#3B82F6',
+ description: 'UI and client-side work'
+ }
+ ],
+ bugDetails: {
+ severity: 'MEDIUM',
+ environment: 'Web Portal / Production',
+ isReproducible: true,
+ steps: 'Set browser timezone to UTC-5. Open any task with a due date. Observe offset.'
+ }
+ },
+ {
+ id: 'wrk-008',
+ sprintId: 'spr-001',
+ title: 'Write onboarding documentation for new developers',
+ description: 'Create a concise getting-started guide covering setup, conventions, and key workflows.',
+ type: 'TASK',
+ status: 'TODO',
+ priority: 'LOW',
+ estimatedMinutes: 150,
+ totalLoggedMinutes: 0,
+ dueDate: '2026-05-01',
+ createdAt: '2026-04-15T10:00:00Z',
+ updatedAt: '2026-04-15T10:00:00Z',
+ createdBy: {
+ id: 'usr-001',
+ name: 'Bernardo Manager',
+ email: 'bernardo.manager@demo.com',
+ telegramUserId: 'tg_bernardo_manager'
+ },
+ assignees: [],
+ tags: [
+ {
+ id: 'tag-002',
+ name: 'Backend',
+ color: '#10B981',
+ description: 'API and service work'
+ }
+ ]
+ }
+];
\ 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/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..0c598175d
--- /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-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-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/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
new file mode 100644
index 000000000..a14bc443f
--- /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/pages/work-item-dashboard-page.tsx b/MtdrSpring/backend/src/main/frontend/src/features/work-items/pages/work-item-dashboard-page.tsx
new file mode 100644
index 000000000..1fdc1edee
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/pages/work-item-dashboard-page.tsx
@@ -0,0 +1,103 @@
+import { Layers } from 'lucide-react';
+import { mockTags } from '@/shared/mock/tags.mock';
+import { DashboardSummaryCards } from '../components/dashboard/dashboard-summary-cards';
+import { DashboardToolbar } from '../components/dashboard/dashboard-toolbar';
+import { WorkItemListView } from '../components/dashboard/work-item-list-view';
+import { KanbanView } from '../components/dashboard/kanban-view';
+import { WorkItemFormModal } from '../components/dashboard/work-item-form-modal';
+import { WorkItemDetailModal } from '../components/dashboard/work-item-detail-modal';
+import { useWorkItemsViewModel } from "@/features/work-items/viewModels/useWorkItemsViewModel";
+import type { IWorkItemsViewModel } from "@/features/work-items/viewModels/useWorkItemsViewModel";
+
+export function WorkItemDashboardPage() {
+ const viewModel: IWorkItemsViewModel = useWorkItemsViewModel();
+
+ return (
+
+
+
+ {/* Page header */}
+
+
+
+
+
+
+
Work Items
+
Sprint 1 · Talos OCI DevOps Project
+
+
+
+
+ {/* Summary cards */}
+
+
+
+
+ {/* Toolbar */}
+
+
+
+
+ {/* Results count */}
+
+ {viewModel.loading
+ ? 'Loading…'
+ : `${viewModel.items.length} of ${viewModel.totalItemCount()} task${viewModel.totalItemCount() !== 1 ? 's' : ''}`}
+
+
+ {/* View area */}
+ {viewModel.loading ? (
+
+ ) : viewModel.viewMode === 'list' ? (
+
+ ) : (
+
+ )}
+
+
+ {/* Create / Edit modal */}
+
+
+ {/* Detail preview modal */}
+
+
+ );
+}
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/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
new file mode 100644
index 000000000..eadb07ee8
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/services/work-item.service.ts
@@ -0,0 +1,224 @@
+import type { ApiResult } from '@/shared/dtos/api-result.dto';
+import type { PagedResult } from '@/shared/dtos/paged-result.dto';
+import type { CreateWorkItemDto } from '../dtos/create-work-item.dto';
+import type { UpdateWorkItemDto } from '../dtos/update-work-item.dto';
+import type { WorkItemDetailDto, Assignee } 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 type { UserSummaryDto } from '@/shared/dtos/user-summary.dto';
+import type { WorkItemType } from '../enums/work-item-type.enum';
+import type { WorkItemPriority } from '../enums/work-item-priority.enum';
+import { normalizeStatus, toBackendStatus } from '../enums/work-item-status.enum';
+import { apiClient } from '@/shared/services/api-client';
+
+// ─── Backend response shape from WorkItemController ──────────────
+
+interface BackendWorkItemRow {
+ WORK_ITEM_ID: string;
+ TITLE: string;
+ DESCRIPTION?: string;
+ STATUS: string;
+ PRIORITY: string;
+ WORK_TYPE: string;
+ DUE_DATE?: string;
+ CREATED_AT: string;
+ ESTIMATED_MINUTES?: number;
+ SPRINT_NAME?: string;
+ SPRINT_ID?: string;
+ ASSIGNEE_NAME?: string;
+ ASSIGNEE_ID?: string;
+}
+
+// ─── Mappers ─────────────────────────────────────────────────────
+
+function mapBackendRowToDetailDto(row: BackendWorkItemRow): WorkItemDetailDto {
+ const assignees: Assignee[] = [];
+ if (row.ASSIGNEE_ID && row.ASSIGNEE_NAME) {
+ assignees.push({
+ id: `asg-${row.ASSIGNEE_ID}`,
+ user: {
+ id: row.ASSIGNEE_ID,
+ name: row.ASSIGNEE_NAME,
+ },
+ role: 'ASSIGNEE',
+ assignedAt: row.CREATED_AT,
+ });
+ }
+
+ return {
+ id: row.WORK_ITEM_ID,
+ sprintId: row.SPRINT_ID,
+ title: row.TITLE,
+ description: row.DESCRIPTION ?? undefined,
+ type: (row.WORK_TYPE ?? 'TASK') as WorkItemType,
+ status: normalizeStatus(row.STATUS),
+ priority: (row.PRIORITY ?? 'MEDIUM') as WorkItemPriority,
+ estimatedMinutes: row.ESTIMATED_MINUTES ?? undefined,
+ totalLoggedMinutes: 0,
+ dueDate: row.DUE_DATE ? String(row.DUE_DATE).slice(0, 10) : undefined,
+ createdAt: row.CREATED_AT,
+ updatedAt: row.CREATED_AT,
+ createdBy: { id: 'system', name: 'System' },
+ assignees,
+ tags: [],
+ };
+}
+
+function mapToListItemDto(detail: WorkItemDetailDto): WorkItemListItemDto {
+ return {
+ id: detail.id,
+ sprintId: detail.sprintId,
+ title: detail.title,
+ type: detail.type,
+ status: detail.status,
+ priority: detail.priority,
+ estimatedMinutes: detail.estimatedMinutes,
+ totalLoggedMinutes: detail.totalLoggedMinutes,
+ dueDate: detail.dueDate,
+ createdAt: detail.createdAt,
+ updatedAt: detail.updatedAt,
+ createdBy: detail.createdBy,
+ assignees: detail.assignees.map((a: Assignee): UserSummaryDto => a.user),
+ tags: detail.tags,
+ };
+}
+
+function applyClientSideFilters(
+ items: WorkItemDetailDto[],
+ filters?: WorkItemFiltersDto
+): WorkItemDetailDto[] {
+ if (!filters) return items;
+
+ return items.filter((item) => {
+ const matchesSearch =
+ !filters.search ||
+ item.title.toLowerCase().includes(filters.search.toLowerCase()) ||
+ (item.description ?? '').toLowerCase().includes(filters.search.toLowerCase());
+
+ const matchesSprint = !filters.sprintId || item.sprintId === filters.sprintId;
+ const matchesType = !filters.type || item.type === filters.type;
+ const matchesStatus = !filters.status || item.status === filters.status;
+ const matchesPriority = !filters.priority || item.priority === filters.priority;
+
+ const matchesAssignee =
+ !filters.assigneeUserId ||
+ item.assignees.some((a) => a.user.id === filters.assigneeUserId);
+
+ return matchesSearch && matchesSprint && matchesType && matchesStatus && matchesPriority && matchesAssignee;
+ });
+}
+
+// ─── Service (real HTTP calls) ───────────────────────────────────
+
+export const workItemService = {
+ async getWorkItems(
+ filters?: WorkItemFiltersDto
+ ): Promise>> {
+ const result = await apiClient.get('/workitems');
+
+ if (!result.success) {
+ return {
+ success: false,
+ data: { items: [], total: 0, page: 1, pageSize: 10, totalPages: 0 },
+ message: result.message,
+ };
+ }
+
+ const allDetails = result.data.map(mapBackendRowToDetailDto);
+ const filtered = applyClientSideFilters(allDetails, filters);
+
+ const page = filters?.page ?? 1;
+ const pageSize = filters?.pageSize ?? 100;
+ const start = (page - 1) * pageSize;
+ const paged = filtered.slice(start, start + pageSize).map(mapToListItemDto);
+
+ return {
+ success: true,
+ data: {
+ items: paged,
+ total: filtered.length,
+ page,
+ pageSize,
+ totalPages: Math.max(1, Math.ceil(filtered.length / pageSize)),
+ },
+ };
+ },
+
+ async getWorkItemById(id: string): Promise> {
+ // The backend doesn't have a single-item endpoint, so fetch all and filter.
+ const result = await apiClient.get('/workitems');
+
+ if (!result.success) {
+ return { success: false, data: null, message: result.message };
+ }
+
+ const row = result.data.find((r) => r.WORK_ITEM_ID === id);
+ if (!row) return { success: true, data: null };
+
+ return { success: true, data: mapBackendRowToDetailDto(row) };
+ },
+
+ async createWorkItem(input: CreateWorkItemDto): Promise> {
+ const body = {
+ title: input.title,
+ description: input.description ?? '',
+ workType: input.type ?? 'TASK',
+ priority: input.priority ?? 'MEDIUM',
+ sprintId: input.sprintId ?? null,
+ dueDateStr: input.dueDate ?? null,
+ assigneeUserId: input.assigneeUserIds?.[0] ?? null,
+ };
+
+ const result = await apiClient.post<{ workItemId: string }>('/workitems', body);
+
+ if (!result.success) {
+ return { success: false, data: null as unknown as WorkItemDetailDto, message: result.message };
+ }
+
+ // Build an optimistic local object so the UI updates immediately
+ const now = new Date().toISOString();
+ const created: WorkItemDetailDto = {
+ id: result.data.workItemId,
+ sprintId: input.sprintId,
+ title: input.title,
+ description: input.description,
+ type: input.type,
+ status: 'TODO',
+ priority: input.priority,
+ estimatedMinutes: input.estimatedMinutes,
+ totalLoggedMinutes: 0,
+ dueDate: input.dueDate,
+ createdAt: now,
+ updatedAt: now,
+ createdBy: { id: 'current', name: 'Current User' },
+ assignees: [],
+ tags: [],
+ };
+
+ return { success: true, data: created };
+ },
+
+ async updateWorkItem(
+ id: string,
+ input: UpdateWorkItemDto
+ ): Promise> {
+ // The backend currently only supports status updates via PUT /workitems/{id}/status
+ if (input.status) {
+ const statusResult = await apiClient.put<{ workItemId: string; status: string }>(
+ `/workitems/${id}/status`,
+ { status: toBackendStatus(input.status) }
+ );
+ if (!statusResult.success) {
+ return { success: false, data: null, message: statusResult.message };
+ }
+ }
+
+ // Re-fetch to get the updated item
+ return this.getWorkItemById(id);
+ },
+
+ async deleteWorkItem(id: string): Promise> {
+ const result = await apiClient.delete(`/workitems/${id}`);
+ return { success: result.success, data: result.success, message: result.message };
+ },
+};
\ 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/src/features/work-items/viewModels/useWorkItemsViewModel.ts b/MtdrSpring/backend/src/main/frontend/src/features/work-items/viewModels/useWorkItemsViewModel.ts
new file mode 100644
index 000000000..e271d7e7b
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/features/work-items/viewModels/useWorkItemsViewModel.ts
@@ -0,0 +1,180 @@
+import { useState, useCallback, useEffect, useMemo } from 'react';
+import { workItemService } from '../services/work-item.service';
+import { foundationService } from '@/shared/services/foundation.service';
+import type { SprintDto } from '@/shared/services/foundation.service';
+import type { ViewMode } from "@/features/work-items/components/dashboard/dashboard-toolbar";
+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 { WorkItemStatus } from '../enums/work-item-status.enum';
+import type { UserSummaryDto } from '@/shared/dtos/user-summary.dto';
+
+export const useWorkItemsViewModel = () => {
+ // 1. Data State
+ const [items, setItems] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [users, setUsers] = useState([]);
+ const [sprints, setSprints] = useState([]);
+
+ // 2. UI State (Grouped logically)
+ const [filters, setFilters] = useState({
+ search: '',
+ status: '' as WorkItemStatus | '',
+ assignee: '',
+ });
+ const [viewMode, setViewMode] = useState('list');
+
+ // 3. Modal/Overlay State
+ const [modals, setModals] = useState({
+ formOpen: false,
+ detailOpen: false,
+ editingItem: null as WorkItemDetailDto | null,
+ detailItem: null as WorkItemDetailDto | null,
+ });
+
+ // --- Actions ---
+
+ const loadItems = useCallback(async () => {
+ setLoading(true);
+ try {
+ // Single API call — the service maps backend rows to WorkItemDetailDto
+ const result = await workItemService.getWorkItems({ page: 1, pageSize: 100 });
+ if (result.success) {
+ // getWorkItems now returns mapped DTOs directly; fetch full detail set
+ const ids = result.data.items.map((i) => i.id);
+ const details = await Promise.all(ids.map((id) => workItemService.getWorkItemById(id)));
+ const fullItems = details
+ .filter((r) => r.success && r.data !== null)
+ .map((r) => r.data as WorkItemDetailDto);
+ setItems(fullItems);
+ }
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ const loadFoundationData = useCallback(async () => {
+ const [usersResult, sprintsResult] = await Promise.all([
+ foundationService.getUsers(),
+ foundationService.getSprints(),
+ ]);
+ if (usersResult.success) setUsers(usersResult.data);
+ if (sprintsResult.success) setSprints(sprintsResult.data);
+ }, []);
+
+ useEffect(() => {
+ loadFoundationData().then();
+ loadItems().then();
+ }, [loadItems, loadFoundationData]);
+
+ // Derived State (SwiftUI "Computed Properties")
+ const filteredItems = useMemo(() => {
+ return items.filter((item) => {
+ const matchesSearch = !filters.search ||
+ item.title.toLowerCase().includes(filters.search.toLowerCase()) ||
+ (item.description ?? '').toLowerCase().includes(filters.search.toLowerCase());
+ const matchesStatus = !filters.status || item.status === filters.status;
+ const matchesAssignee = !filters.assignee ||
+ item.assignees.some((a) => a.user.id === filters.assignee);
+
+ return matchesSearch && matchesStatus && matchesAssignee;
+ });
+ }, [items, filters]);
+
+ // --- Handlers ---
+ const handleCreate = async (dto: CreateWorkItemDto) => {
+ const result = await workItemService.createWorkItem(dto);
+ if (result.success) setItems((prev) => [result.data, ...prev]);
+ };
+
+ const handleUpdate = async (id: string, dto: UpdateWorkItemDto) => {
+ const result = await workItemService.updateWorkItem(id, dto);
+ if (result.success && result.data) {
+ const updated = result.data;
+ setItems((prev) => prev.map((item) => (item.id === id ? updated : item)));
+ if (modals.detailItem?.id === id) {
+ setModals(m => ({ ...m, detailItem: updated }));
+ }
+ }
+ };
+
+ const handleEdit = useCallback((item: WorkItemDetailDto) => {
+ setModals({
+ formOpen: true,
+ detailOpen: false,
+ editingItem: item,
+ detailItem: null,
+ });
+ }, []);
+
+ const handleComplete = async (item: WorkItemDetailDto) => {
+ await handleUpdate(item.id, {
+ status: 'DONE',
+ completedAt: new Date().toISOString()
+ });
+ };
+
+ // UI Navigation / Modal Handlers
+ const openNew = () =>
+ setModals({ ...modals, editingItem: null, formOpen: true});
+
+ const openEdit = (item: WorkItemDetailDto) =>
+ setModals({ ...modals, editingItem: item, formOpen: true, detailOpen: false });
+
+ const openDetail = (item: WorkItemDetailDto) =>
+ setModals({ ...modals, detailItem: item, detailOpen: true });
+
+ const closeAll = () =>
+ setModals({ ...modals, formOpen: false, detailOpen: false, editingItem: null, detailItem: null });
+
+ const handleEditFromDetail = useCallback((item: WorkItemDetailDto) => {
+ closeAll();
+ handleEdit(item);
+ }, [handleEdit, closeAll]);
+
+ const handleCompleteFromDetail = useCallback(async (item: WorkItemDetailDto) => {
+ await handleComplete(item);
+ closeAll();
+ }, [handleComplete, closeAll]);
+
+ // --- Final API ---
+ return {
+ // Data
+ items: filteredItems,
+ totalItemCount: () => { return items.length },
+ loading,
+ viewMode,
+ setViewMode,
+ users,
+ sprints,
+
+ // UI State
+ search: filters.search,
+ statusFilter: filters.status,
+ assigneeFilter: filters.assignee,
+ setSearch: (search: string) => setFilters(f => ({ ...f, search })),
+ setStatusFilter: (status: WorkItemStatus | '') => setFilters(f => ({ ...f, status })),
+ setAssigneeFilter: (assignee: string) => setFilters(f => ({ ...f, assignee })),
+
+ // Modal state
+ ...modals,
+ editingItem: modals.editingItem,
+
+ // Actions
+ actions: {
+ loadItems,
+ openNew,
+ handleCreate,
+ handleUpdate,
+ handleComplete,
+ handleEdit,
+ handleEditFromDetail,
+ handleCompleteFromDetail,
+ openEdit,
+ openDetail,
+ closeAll
+ }
+ };
+};
+
+export type IWorkItemsViewModel = ReturnType;
\ No newline at end of file
diff --git a/MtdrSpring/backend/src/main/frontend/src/index.css b/MtdrSpring/backend/src/main/frontend/src/index.css
index b82c4de13..fef409449 100644
--- a/MtdrSpring/backend/src/main/frontend/src/index.css
+++ b/MtdrSpring/backend/src/main/frontend/src/index.css
@@ -1,134 +1,7 @@
-/*
-** 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/
-*/
-body {
- /* from the redwood theme */
- background-color: #3A3632;
- width: 100%;
- max-width: 50rem;
- 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;
- }
- .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;
- }
- 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;
- 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;
- }
- button.AddButton:hover {
- background-color: #6F915D;
- }
- button.DeleteButton {
- color: #FEF9F2;
- background-color: #D63B25;
- }
- button.DeleteButton:hover {
- background-color: #EC4F3A
- }
- button.DoneButton {
- background-color: #FBF9F8;
- }
- button.DoneButton:hover {
- background-color: #D4CFCA;
- }
\ No newline at end of file
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+.test-tailwind {
+ @apply bg-orange-500 p-10 text-white font-bold;
+}
\ 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
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/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/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..a1611870f
--- /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 | null
+ telegramUserId?: string | null
+}
\ No newline at end of file
diff --git a/MtdrSpring/backend/src/main/frontend/src/shared/services/api-client.ts b/MtdrSpring/backend/src/main/frontend/src/shared/services/api-client.ts
new file mode 100644
index 000000000..e370844a4
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/shared/services/api-client.ts
@@ -0,0 +1,57 @@
+import type { ApiResult } from '../dtos/api-result.dto';
+
+/**
+ * Generic HTTP client for the Spring Boot backend.
+ * The React dev-server proxy (package.json → "proxy": "http://localhost:8080")
+ * forwards all unmatched requests to the backend, so we use relative URLs.
+ */
+
+async function request(
+ url: string,
+ options: RequestInit = {}
+): Promise> {
+ try {
+ const res = await fetch(url, {
+ headers: { 'Content-Type': 'application/json', ...options.headers },
+ ...options,
+ });
+
+ if (!res.ok) {
+ const errorText = await res.text().catch(() => res.statusText);
+ return {
+ success: false,
+ data: null as unknown as T,
+ message: `HTTP ${res.status}: ${errorText}`,
+ };
+ }
+
+ // Handle 204 No Content
+ if (res.status === 204) {
+ return { success: true, data: null as unknown as T };
+ }
+
+ const data: T = await res.json();
+ return { success: true, data };
+ } catch (err: unknown) {
+ const message = err instanceof Error ? err.message : 'Network error';
+ return { success: false, data: null as unknown as T, message };
+ }
+}
+
+export const apiClient = {
+ get(url: string): Promise> {
+ return request(url);
+ },
+
+ post(url: string, body: unknown): Promise> {
+ return request(url, { method: 'POST', body: JSON.stringify(body) });
+ },
+
+ put(url: string, body: unknown): Promise> {
+ return request(url, { method: 'PUT', body: JSON.stringify(body) });
+ },
+
+ delete(url: string): Promise> {
+ return request(url, { method: 'DELETE' });
+ },
+};
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..6c4d44a20
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/src/shared/services/foundation.service.ts
@@ -0,0 +1,76 @@
+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 { apiClient } from './api-client';
+import { mockTags } from '../mock/tags.mock';
+import { mockTeams } from '../mock/teams.mock';
+
+// ─── Sprint DTO for UI consumption ──────────────────────────────
+export interface SprintDto {
+ sprintId: string;
+ name: string;
+ status?: string;
+ startDate?: string;
+ endDate?: string;
+}
+
+export const foundationService = {
+ /** Fetch real users from backend /appusers endpoint */
+ async getUsers(): Promise> {
+ const result = await apiClient.get('/appusers');
+ if (!result.success) {
+ return { success: false, data: [], message: result.message };
+ }
+ // Backend already returns camelCase thanks to SQL aliases
+ return { success: true, data: result.data };
+ },
+
+ /** Fetch real sprints from backend /sprints endpoint */
+ async getSprints(): Promise> {
+ const result = await apiClient.get('/sprints');
+ if (!result.success) {
+ return { success: false, data: [], message: result.message };
+ }
+ return { success: true, data: result.data };
+ },
+
+ /** Tags are not stored in the backend yet — still local */
+ async getTags(): Promise> {
+ return { success: true, data: structuredClone(mockTags) };
+ },
+
+ /** Teams are not stored in the backend yet — still local */
+ async getTeams(): Promise> {
+ return { success: true, data: structuredClone(mockTeams) };
+ },
+
+ async getUserOptions(): Promise> {
+ const usersResult = await this.getUsers();
+ if (!usersResult.success) {
+ return { success: false, data: [], message: usersResult.message };
+ }
+ const options: SelectOption[] = usersResult.data.map((user) => ({
+ value: user.id,
+ label: user.name,
+ }));
+ return { success: true, data: options };
+ },
+
+ async getTagOptions(): Promise> {
+ const options: SelectOption[] = mockTags.map((tag) => ({
+ value: tag.id,
+ label: tag.name,
+ }));
+ return { success: true, data: options };
+ },
+
+ async getTeamOptions(): Promise> {
+ const options: SelectOption[] = mockTeams.map((team) => ({
+ value: team.id,
+ label: team.name,
+ }));
+ return { success: true, data: 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
diff --git a/MtdrSpring/backend/src/main/frontend/tailwind.config.js b/MtdrSpring/backend/src/main/frontend/tailwind.config.js
new file mode 100644
index 000000000..84e50559c
--- /dev/null
+++ b/MtdrSpring/backend/src/main/frontend/tailwind.config.js
@@ -0,0 +1,11 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ './src/**/*.{js,jsx,ts,tsx}',
+ './public/index.html',
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};
diff --git a/MtdrSpring/backend/src/main/frontend/tsconfig.json b/MtdrSpring/backend/src/main/frontend/tsconfig.json
new file mode 100644
index 000000000..1d61ef4e1
--- /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. */
+ }
+}
diff --git a/MtdrSpring/backend/src/main/java/com/springboot/MyTodoList/config/OracleConfiguration.java b/MtdrSpring/backend/src/main/java/com/springboot/MyTodoList/config/OracleConfiguration.java
index b672e55f3..91fc40234 100644
--- a/MtdrSpring/backend/src/main/java/com/springboot/MyTodoList/config/OracleConfiguration.java
+++ b/MtdrSpring/backend/src/main/java/com/springboot/MyTodoList/config/OracleConfiguration.java
@@ -7,44 +7,33 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.Environment;
-
import javax.sql.DataSource;
import java.sql.SQLException;
-///*
-// This class grabs the appropriate values for OracleDataSource,
-// The method that uses env, grabs it from the environment variables set
-// in the docker container. The method that uses dbSettings is for local testing
-// @author: peter.song@oracle.com
-// */
-//
-//
+
@Configuration
public class OracleConfiguration {
Logger logger = LoggerFactory.getLogger(DbSettings.class);
@Autowired
private DbSettings dbSettings;
- @Autowired
- private Environment env;
@Bean
public DataSource dataSource() throws SQLException{
OracleDataSource ds = new OracleDataSource();
- ds.setDriverType(env.getProperty("driver_class_name"));
- logger.info("Using Driver " + env.getProperty("driver_class_name"));
- ds.setURL(env.getProperty("db_url"));
- logger.info("Using URL: " + env.getProperty("db_url"));
- ds.setUser(env.getProperty("db_user"));
- logger.info("Using Username " + env.getProperty("db_user"));
- ds.setPassword(env.getProperty("dbpassword"));
// For local testing
-// ds.setDriverType(dbSettings.getDriver_class_name());
-// logger.info("Using Driver " + dbSettings.getDriver_class_name());
-// ds.setURL(dbSettings.getUrl());
-// logger.info("Using URL: " + dbSettings.getUrl());
-// ds.setUser(dbSettings.getUsername());
-// logger.info("Using Username: " + dbSettings.getUsername());
-// ds.setPassword(dbSettings.getPassword());
+ ds.setDriverType(dbSettings.getDriver_class_name());
+ logger.info("Using Driver " + dbSettings.getDriver_class_name());
+ ds.setURL(dbSettings.getUrl());
+ logger.info("Using URL: " + dbSettings.getUrl());
+ ds.setUser(dbSettings.getUsername());
+ logger.info("Using Username: " + dbSettings.getUsername());
+ ds.setPassword(dbSettings.getPassword());
+// ds.setDriverType(env.getProperty("driver_class_name"));
+// logger.info("Using Driver " + env.getProperty("driver_class_name"));
+// ds.setURL(env.getProperty("db_url"));
+// logger.info("Using URL: " + env.getProperty("db_url"));
+// ds.setUser(env.getProperty("db_user"));
+// logger.info("Using Username " + env.getProperty("db_user"));
+// ds.setPassword(env.getProperty("dbpassword"));
return ds;
}
}
diff --git a/MtdrSpring/backend/src/main/java/com/springboot/MyTodoList/controller/AnalyticsController.java b/MtdrSpring/backend/src/main/java/com/springboot/MyTodoList/controller/AnalyticsController.java
new file mode 100644
index 000000000..fbd0a5660
--- /dev/null
+++ b/MtdrSpring/backend/src/main/java/com/springboot/MyTodoList/controller/AnalyticsController.java
@@ -0,0 +1,83 @@
+package com.springboot.MyTodoList.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+
+@RestController
+public class AnalyticsController {
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ @GetMapping("/analytics/dashboard")
+ public Map getDashboardData() {
+
+ String sql =
+ "SELECT " +
+ " u.NAME AS developer, " +
+ " s.NAME AS sprint_name, " +
+ " COUNT(DISTINCT wi.WORK_ITEM_ID) AS tasks_completed, " +
+ " NVL(SUM(te.sprint_minutes), 0) / 60.0 AS real_hours " +
+ "FROM CHATBOT_USER.WORK_ITEM wi " +
+ "JOIN CHATBOT_USER.WORK_ITEM_ASSIGNMENT wia ON wi.WORK_ITEM_ID = wia.WORK_ITEM_ID " +
+ "JOIN CHATBOT_USER.APP_USER u ON wia.USER_ID = u.USER_ID " +
+ "JOIN CHATBOT_USER.SPRINT s ON wi.SPRINT_ID = s.SPRINT_ID " +
+ "LEFT JOIN ( " +
+ " SELECT WORK_ITEM_ID, SUM(MINUTES) AS sprint_minutes " +
+ " FROM CHATBOT_USER.TIME_ENTRY " +
+ " GROUP BY WORK_ITEM_ID " +
+ ") te ON wi.WORK_ITEM_ID = te.WORK_ITEM_ID " +
+ "WHERE wi.STATUS IN ('DONE', 'COMPLETED', 'CLOSED') " +
+ "GROUP BY u.NAME, s.NAME " +
+ "ORDER BY u.NAME, s.NAME";
+
+ List