feat(frontend): slice 8 — remove MUI/@emotion deps + update REQUIREMENTS

Web UI rework. Final slice.
- Remove from package.json: @mui/material, @mui/icons-material,
  @mui/x-data-grid, @emotion/react, @emotion/styled (zero consumers
  remain in src after slices 1-7b; grep-verified).
- Update docs/REQUIREMENTS.md (+63 lines): single design system
  (shadcn/ui + Tailwind v4 + lucide-react), thin-dashboard observability
  model (no in-app charts; Grafana deep-links), TanStack tables
  (visibility-only parity), reconciled IA (Backups top-level nav;
  Media at /media with /applications redirect), repurposed chart-*
  status cues, removed deps list.
- Note: AGENTS.md 'node --test tests' invocation is a pre-existing
  broken command (treats tests/ as a module); correct form is
  'node --test' (auto-discover, 5/5 pass) — verified identical at
  pre-rework baseline ef5311b.

Gate: build + lint + vitest (23/64) + node --test (5/5) green.
Web UI rework complete.
This commit is contained in:
Developer
2026-06-17 18:52:27 +00:00
parent 3dc1b31fc3
commit 9de2d5b8d2
5 changed files with 323 additions and 621 deletions
+63 -2
View File
@@ -10,6 +10,61 @@ Build Manage, a compact web application for browsing a remote Jellyfin media lib
Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server monitoring, and safe job templates. Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server monitoring, and safe job templates.
## Frontend Design System & Architecture
The Manage frontend is a React + TypeScript SPA built on a **single design system**.
The legacy Material UI (MUI v9) / Emotion / recharts / D3 / `theme.ts` stack has been
fully removed (web-ui-rework; see decision log 2026-06-17).
### Design system
- **shadcn/ui** components + **Tailwind CSS v4** + **lucide-react** icons are the only UI layer.
- Design tokens live as CSS `@theme` tokens in `frontend/src/index.css` (light + `.dark`),
with the primary brand color `#4f8cff`.
- The `chart-1`..`chart-5` color tokens are **repurposed as status / Grafana-link color
cues** (not charts): `chart-1`=info/brand, `chart-2`=success/healthy, `chart-3`=warning,
`chart-4`=destructive, `chart-5`=neutral accent. No token value changed.
- Removed from the frontend dependency tree: `@mui/material`, `@mui/icons-material`,
`@mui/x-data-grid`, `@emotion/react`, `@emotion/styled`, `recharts`, `d3`, and the
no-op `src/theme.ts` shim.
### Thin-dashboard observability model
- The app does **no in-app charting**. Metrics, charts, and logs live in the external,
decoupled observability stack (Prometheus / Loki / Grafana / Alertmanager).
- In-app observability surfaces (`/observability`) show **Alertmanager alerts, Prometheus
target health, machine health, and Grafana deep-links** (per-machine metric/log panels),
not rendered graphs.
- The legacy in-app D3 monitoring charts and the POSIX remote resource collector are
superseded by this Grafana-based model (see decision log 2026-06-13 and 2026-06-17).
### Tables
- Tabular surfaces use **TanStack Table** (`@tanstack/react-table`) behind a `DataTable`
wrapper (`components/ui/data-table.tsx`).
- Parity is **visibility-only**: pagination, row selection, row click, and column
visibility are supported. There is **no client sorting and no column resizing**.
- Media uses **server-driven pagination** (`manualPagination` + `rowCount`); the File
Browser renders the full listing without pagination.
- The Media and File Browser tables previously used `@mui/x-data-grid`; both now use the
TanStack `DataTable` (earlier "AG Grid" / `@mui/x-data-grid` references are superseded).
### Reconciled information architecture
- **Backups** is a top-level navigation item at `/backups`.
- The media/applications surface is named **Media** and lives at `/media`; `/applications`
redirects to `/media`, mirroring the existing `/monitoring``/observability` redirect.
- User deep-links (`/users?user=<id>`), dashboard shortcut deep-links, and the Media →
File Browser row-click navigation are preserved under the reconciled routes.
### Frontend testing
- Component tests run on **Vitest + @testing-library/react** (`npm test`), with the
`@testing-library/jest-dom` matchers.
- Legacy plain-Node suites (`frontend/tests/*.test.mjs`) run via
`node --test tests/*.test.mjs` (npm script `test:node`).
- The build/lint gate is `npm run build` (`tsc -b` + `vite build`) + `npm run lint` (ESLint).
## Core Requirements ## Core Requirements
### Jellyfin Library ### Jellyfin Library
@@ -82,7 +137,7 @@ Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server mo
- Support manual path entry and refresh. - Support manual path entry and refresh.
- Remote file listing must be compact, structured, and navigable. - Remote file listing must be compact, structured, and navigable.
- The file table should be read-only. - The file table should be read-only.
- The file table should use row selection (single-select) in an AG Grid format consistent with the Media tab. - The file table should use row selection (single-select) in a TanStack `DataTable` format consistent with the Media tab (both migrated off the legacy `@mui/x-data-grid`/AG Grid).
- The file table should not expose a visible checkbox selection column. - The file table should not expose a visible checkbox selection column.
- The file table should not show a visible `selected` column. - The file table should not show a visible `selected` column.
- Include a top `[UP] ..` row, when not at `/`, to navigate to the parent directory. - Include a top `[UP] ..` row, when not at `/`, to navigate to the parent directory.
@@ -166,7 +221,7 @@ Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server mo
- The dashboard should present disk space as a single combined card with the progress/fill bar embedded inside the card and the size breakdown laid out clearly, with centered sub-card text for the Used/Free/Total breakdown and consistent vertical spacing across the dashboard cards. - The dashboard should present disk space as a single combined card with the progress/fill bar embedded inside the card and the size breakdown laid out clearly, with centered sub-card text for the Used/Free/Total breakdown and consistent vertical spacing across the dashboard cards.
- The disk usage bar should change color as usage increases so high utilization is easy to notice at a glance. - The disk usage bar should change color as usage increases so high utilization is easy to notice at a glance.
- The disk usage card should avoid redundant percentage labels next to the bar if the bar itself already communicates the value. - The disk usage card should avoid redundant percentage labels next to the bar if the bar itself already communicates the value.
- Render Monitoring charts directly with D3 so the UI can support brush-based range selection, hover tooltips with a moving vertical cursor and snapped point markers, summary chips, and moving averages without a separate wrapper library. - (Superseded by the thin-dashboard observability model — 2026-06-17.) The app no longer renders in-app monitoring charts with D3; metrics/charts/logs live in the external Grafana stack, and the in-app Observability page surfaces Alertmanager alerts, Prometheus target health, and Grafana deep-links.
- Use a lightweight remote collector that reads Linux `/proc`, `/sys/block`, and `df` data into a JSONL file under `/tmp`. - Use a lightweight remote collector that reads Linux `/proc`, `/sys/block`, and `df` data into a JSONL file under `/tmp`.
- The collector should rotate/prune its JSONL metrics file so it does not grow unbounded; default retention is 7 days with a 70,000-line safety cap. - The collector should rotate/prune its JSONL metrics file so it does not grow unbounded; default retention is 7 days with a 70,000-line safety cap.
- The collector should be startable/stoppable/restartable from the dashboard and should not require installing a full monitoring stack. - The collector should be startable/stoppable/restartable from the dashboard and should not require installing a full monitoring stack.
@@ -197,6 +252,7 @@ Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server mo
## Decision Log ## Decision Log
- 2026-06-17: Completed the web UI rework to a single design system. The frontend now uses **shadcn/ui + Tailwind CSS v4 + lucide-react** exclusively, with CSS `@theme` tokens in `src/index.css` (primary `#4f8cff`; `chart-1..5` repurposed as status/Grafana-link cues). Removed `@mui/material`, `@mui/icons-material`, `@mui/x-data-grid`, `@emotion/react`, `@emotion/styled`, `recharts`, `d3`, and the `src/theme.ts` shim. Tables moved from `@mui/x-data-grid`/AG Grid to a visibility-only TanStack `DataTable` wrapper (pagination, row selection, row click, column visibility — no sorting/resizing). Adopted the thin-dashboard observability model (no in-app charts; Alertmanager alerts + Prometheus target health + Grafana deep-links). Reconciled the information architecture: Backups is a top-level nav item at `/backups`, and the media surface is named Media at `/media` with `/applications` redirecting to `/media` (mirroring `/monitoring``/observability`). Frontend tests moved to Vitest + @testing-library/react (`npm test`), with legacy node suites in `frontend/tests`.
- 2026-06-13: Adopted a dedicated, self-hosted observability subsystem based on Prometheus, Grafana Loki, Grafana, and Alertmanager. Metrics will be pulled from Node Exporter on machines and from application exporters in containers; logs will be structured JSON shipped by Promtail/Grafana Alloy. The existing POSIX remote collector will be removed and backup alerts migrated to Alertmanager rules. See `docs/monitoring-logging-design.md`. - 2026-06-13: Adopted a dedicated, self-hosted observability subsystem based on Prometheus, Grafana Loki, Grafana, and Alertmanager. Metrics will be pulled from Node Exporter on machines and from application exporters in containers; logs will be structured JSON shipped by Promtail/Grafana Alloy. The existing POSIX remote collector will be removed and backup alerts migrated to Alertmanager rules. See `docs/monitoring-logging-design.md`.
- 2026-06-13 (Phase 1): Added Prometheus, Loki, Grafana Alloy, Grafana, Alertmanager, and Node Exporter services to `docker-compose.yml` and `docker-compose.dev.yml`. Provisioned Grafana datasources and an initial `Manage Overview` dashboard as code. Configured Alloy to tail Docker logs and ship to Loki. Added Grafana generic OAuth configuration via `monitoring/grafana/grafana.ini` and a dedicated Traefik host rule. Added Alertmanager email routing with env-var interpolation. Added `/grafana` proxy to the Vite dev server for iframe embedding. - 2026-06-13 (Phase 1): Added Prometheus, Loki, Grafana Alloy, Grafana, Alertmanager, and Node Exporter services to `docker-compose.yml` and `docker-compose.dev.yml`. Provisioned Grafana datasources and an initial `Manage Overview` dashboard as code. Configured Alloy to tail Docker logs and ship to Loki. Added Grafana generic OAuth configuration via `monitoring/grafana/grafana.ini` and a dedicated Traefik host rule. Added Alertmanager email routing with env-var interpolation. Added `/grafana` proxy to the Vite dev server for iframe embedding.
- 2026-06-13 (Phase 2): Extended machine settings with `node_exporter_enabled`, `node_exporter_port`, and `node_exporter_scrape_host`. Added Node Exporter install/restart/status job templates to `jobs.py`. Implemented `media_library_viewer_api.services.targets` to generate Prometheus file-SD target files and wired target regeneration into machine create/update/delete. Added `/api/monitoring/prometheus-targets` for live target previews. Configured Prometheus with a `node-exporter-remote` job reading file SD from the backend cache volume. Added a minimal `Node Exporter Overview` Grafana dashboard. Added unit and integration tests for target generation and the new endpoint. - 2026-06-13 (Phase 2): Extended machine settings with `node_exporter_enabled`, `node_exporter_port`, and `node_exporter_scrape_host`. Added Node Exporter install/restart/status job templates to `jobs.py`. Implemented `media_library_viewer_api.services.targets` to generate Prometheus file-SD target files and wired target regeneration into machine create/update/delete. Added `/api/monitoring/prometheus-targets` for live target previews. Configured Prometheus with a `node-exporter-remote` job reading file SD from the backend cache volume. Added a minimal `Node Exporter Overview` Grafana dashboard. Added unit and integration tests for target generation and the new endpoint.
@@ -289,9 +345,11 @@ Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server mo
## Backup Monitoring ## Backup Monitoring
### Overview ### Overview
The system receives backup execution reports from an external backup tool via HTTP API, stores job and run history, and provides alerting on failures, missed schedules, and anomalies. The system receives backup execution reports from an external backup tool via HTTP API, stores job and run history, and provides alerting on failures, missed schedules, and anomalies.
### API ### API
- `POST /api/backups/report` — Submit backup run (Bearer token auth) - `POST /api/backups/report` — Submit backup run (Bearer token auth)
- `POST /api/backups/report/start` — Mark backup as in_progress - `POST /api/backups/report/start` — Mark backup as in_progress
- `GET /api/backups/jobs` — List jobs - `GET /api/backups/jobs` — List jobs
@@ -301,16 +359,19 @@ The system receives backup execution reports from an external backup tool via HT
- `GET /api/dashboard/backups` — Dashboard summary - `GET /api/dashboard/backups` — Dashboard summary
### Data Model ### Data Model
- **BackupJob**: id, name, source, target, schedule_interval_seconds, created_at - **BackupJob**: id, name, source, target, schedule_interval_seconds, created_at
- **BackupRun**: id, job_id, started_at, ended_at, status, bytes_transferred, duration_ms, error_message, details_json - **BackupRun**: id, job_id, started_at, ended_at, status, bytes_transferred, duration_ms, error_message, details_json
- **BackupAlert**: id, job_id, run_id, alert_type, severity, message, acknowledged, resolved_at - **BackupAlert**: id, job_id, run_id, alert_type, severity, message, acknowledged, resolved_at
### Alert Types ### Alert Types
- `failed_status` — Backup reported failure (critical) - `failed_status` — Backup reported failure (critical)
- `missed_schedule` — No run within 1.5x expected interval (warning) - `missed_schedule` — No run within 1.5x expected interval (warning)
- `anomaly_size` — Size is 0 or <10% / >300% of 7-day median (warning) - `anomaly_size` — Size is 0 or <10% / >300% of 7-day median (warning)
- `anomaly_duration` — Duration >300% of 7-day median (warning) - `anomaly_duration` — Duration >300% of 7-day median (warning)
### Authentication ### Authentication
- Backup tool uses auto-generated Bearer API key - Backup tool uses auto-generated Bearer API key
- Frontend uses existing OIDC/JWT auth - Frontend uses existing OIDC/JWT auth
+24 -602
View File
@@ -8,12 +8,7 @@
"name": "frontend", "name": "frontend",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@fontsource-variable/geist": "^5.2.8", "@fontsource-variable/geist": "^5.2.8",
"@mui/icons-material": "^9.0.0",
"@mui/material": "^9.0.0",
"@mui/x-data-grid": "^9.0.4",
"@tanstack/react-query": "^5.100.6", "@tanstack/react-query": "^5.100.6",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
@@ -489,6 +484,7 @@
"version": "7.29.2", "version": "7.29.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
"integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
"devOptional": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -895,158 +891,6 @@
"tslib": "^2.4.0" "tslib": "^2.4.0"
} }
}, },
"node_modules/@emotion/babel-plugin": {
"version": "11.13.5",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
"integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.16.7",
"@babel/runtime": "^7.18.3",
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/serialize": "^1.3.3",
"babel-plugin-macros": "^3.1.0",
"convert-source-map": "^1.5.0",
"escape-string-regexp": "^4.0.0",
"find-root": "^1.1.0",
"source-map": "^0.5.7",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
"license": "MIT"
},
"node_modules/@emotion/cache": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz",
"integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==",
"license": "MIT",
"dependencies": {
"@emotion/memoize": "^0.9.0",
"@emotion/sheet": "^1.4.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/hash": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
"license": "MIT"
},
"node_modules/@emotion/is-prop-valid": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz",
"integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==",
"license": "MIT",
"dependencies": {
"@emotion/memoize": "^0.9.0"
}
},
"node_modules/@emotion/memoize": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
"license": "MIT"
},
"node_modules/@emotion/react": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/cache": "^11.14.0",
"@emotion/serialize": "^1.3.3",
"@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"hoist-non-react-statics": "^3.3.1"
},
"peerDependencies": {
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/serialize": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
"integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
"license": "MIT",
"dependencies": {
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/unitless": "^0.10.0",
"@emotion/utils": "^1.4.2",
"csstype": "^3.0.2"
}
},
"node_modules/@emotion/sheet": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
"license": "MIT"
},
"node_modules/@emotion/styled": {
"version": "11.14.1",
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
"integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/is-prop-valid": "^1.3.0",
"@emotion/serialize": "^1.3.3",
"@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
"@emotion/utils": "^1.4.2"
},
"peerDependencies": {
"@emotion/react": "^11.0.0-rc.0",
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/unitless": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
"license": "MIT"
},
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz",
"integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@emotion/utils": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
"integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
"license": "MIT"
},
"node_modules/@emotion/weak-memoize": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
"license": "MIT"
},
"node_modules/@eslint-community/eslint-utils": { "node_modules/@eslint-community/eslint-utils": {
"version": "4.9.1", "version": "4.9.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
@@ -1530,321 +1374,6 @@
"integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@mui/core-downloads-tracker": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-9.0.0.tgz",
"integrity": "sha512-uwQNGkhv0lf7ufxw6QXev77BW6pWbW+7uxYjU5+rfp4lBkFtMEgJCsarTM3Tn+i0lGx6+Ol2u88JdGXr0GDskA==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
}
},
"node_modules/@mui/icons-material": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-9.0.0.tgz",
"integrity": "sha512-oDwyvI6LgjWRC9MBcSGvLkPud9S9ELgSBQFYxa1rYcZn6Br55dn22SyvsPDMsn0G8OndFk53iMT45W5mNqrogw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@mui/material": "^9.0.0",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/material": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-9.0.0.tgz",
"integrity": "sha512-+VP/oQCDhDR87NQQgXnNBG8dwy6GNuQLnenS1pZvkbn2dKFSxRSRMybTpH9xUxXP+316mlYDy5CSbYtusnCWtw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"@mui/core-downloads-tracker": "^9.0.0",
"@mui/system": "^9.0.0",
"@mui/types": "^9.0.0",
"@mui/utils": "^9.0.0",
"@popperjs/core": "^2.11.8",
"@types/react-transition-group": "^4.4.12",
"clsx": "^2.1.1",
"csstype": "^3.2.3",
"prop-types": "^15.8.1",
"react-is": "^19.2.4",
"react-transition-group": "^4.4.5"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@mui/material-pigment-css": "^9.0.0",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"@mui/material-pigment-css": {
"optional": true
},
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/private-theming": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-9.0.0.tgz",
"integrity": "sha512-JtuZoaiCqwD6vjgYu6Xp3T7DZkrxJlgtDz5yESzhI34fEX5hHMh2VJUbuL9UOg8xrfIFMrq6dcYoH/7Zi4G0RA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"@mui/utils": "^9.0.0",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/styled-engine": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-9.0.0.tgz",
"integrity": "sha512-9RLGdX4Jg0aQPRuvqh/OLzYSPlgd5zyEw5/1HIRfdavSiOd03WtUaGZH9/w1RoTYuRKwpgy0hpIFaMHIqPVIWg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"@emotion/cache": "^11.14.0",
"@emotion/serialize": "^1.3.3",
"@emotion/sheet": "^1.4.0",
"csstype": "^3.2.3",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
}
}
},
"node_modules/@mui/system": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-9.0.0.tgz",
"integrity": "sha512-YnC5Zg6j04IxiLc/boAKs0464jfZlLFVa7mf5E8lF0XOtZVUvG6R6gJK50lgUYdaaLdyLfxF6xR7LaPuEpeT/g==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"@mui/private-theming": "^9.0.0",
"@mui/styled-engine": "^9.0.0",
"@mui/types": "^9.0.0",
"@mui/utils": "^9.0.0",
"clsx": "^2.1.1",
"csstype": "^3.2.3",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/types": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-9.0.0.tgz",
"integrity": "sha512-i1cuFCAWN44b3AJWO7mh7tuh1sqbQSeVr/94oG0TX5uXivac8XalgE4/6fQZcmGZigzbQ35IXxj/4jLpRIBYZg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/utils": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.0.0.tgz",
"integrity": "sha512-bQcqyg/gjULUqTuyUjSAFr6LQGLvtkNtDbJerAtoUn9kGZ0hg5QJiN1PLHMLbeFpe3te1831uq7GFl2ITokGdg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"@mui/types": "^9.0.0",
"@types/prop-types": "^15.7.15",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-is": "^19.2.4"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/x-data-grid": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-9.0.4.tgz",
"integrity": "sha512-XhjewU6EGFPXDhVJ48ILA7PXYdGVbIwvy6g3SYkm7yMygb/ScA6k+Uac2zi09OMxJDCK8nRiuhj+ONY4uZZIYQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"@mui/utils": "9.0.0",
"@mui/x-internals": "^9.0.4",
"@mui/x-virtualizer": "9.0.0-alpha.2",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"use-sync-external-store": "^1.6.0"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@mui/material": "^7.3.0 || ^9.0.0",
"@mui/system": "^7.3.0 || ^9.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
}
}
},
"node_modules/@mui/x-internals": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-9.0.4.tgz",
"integrity": "sha512-I84xcPZOEmN29syfAjgsv25kpW7GX9+F7n2xXKEX5C7VdyXITbAW2RomwXt3guud4KwGhkAGuGDPK7Wi20EoCg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"@mui/utils": "9.0.0",
"reselect": "^5.1.1",
"use-sync-external-store": "^1.6.0"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/@mui/x-virtualizer": {
"version": "9.0.0-alpha.2",
"resolved": "https://registry.npmjs.org/@mui/x-virtualizer/-/x-virtualizer-9.0.0-alpha.2.tgz",
"integrity": "sha512-L/7I81NzdQ6a+iu74bkOyVILbwVdAEeCMQLDdmBS77lXVmSZSn3E664oQVdE8uoiSjbOuF0U2LGyM7wH9Ae/nA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"@mui/utils": "9.0.0",
"@mui/x-internals": "^9.0.4"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/@napi-rs/wasm-runtime": { "node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
@@ -1970,16 +1499,6 @@
"url": "https://github.com/sponsors/Boshen" "url": "https://github.com/sponsors/Boshen"
} }
}, },
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@radix-ui/number": { "node_modules/@radix-ui/number": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
@@ -4294,18 +3813,15 @@
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
"license": "MIT" "license": "MIT",
}, "optional": true,
"node_modules/@types/prop-types": { "peer": true
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
"license": "MIT"
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "19.2.14", "version": "19.2.14",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
"devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"csstype": "^3.2.2" "csstype": "^3.2.2"
@@ -4321,15 +3837,6 @@
"@types/react": "^19.2.0" "@types/react": "^19.2.0"
} }
}, },
"node_modules/@types/react-transition-group": {
"version": "4.4.12",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
"integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*"
}
},
"node_modules/@types/set-cookie-parser": { "node_modules/@types/set-cookie-parser": {
"version": "2.4.10", "version": "2.4.10",
"resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.10.tgz", "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.10.tgz",
@@ -4953,6 +4460,8 @@
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"cosmiconfig": "^7.0.0", "cosmiconfig": "^7.0.0",
@@ -5403,6 +4912,8 @@
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"dependencies": { "dependencies": {
"@types/parse-json": "^4.0.0", "@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1", "import-fresh": "^3.2.1",
@@ -5419,6 +4930,8 @@
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz",
"integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==",
"license": "ISC", "license": "ISC",
"optional": true,
"peer": true,
"engines": { "engines": {
"node": ">= 6" "node": ">= 6"
} }
@@ -5474,6 +4987,7 @@
"version": "3.2.3", "version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"devOptional": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/data-uri-to-buffer": { "node_modules/data-uri-to-buffer": {
@@ -5645,16 +5159,6 @@
"license": "MIT", "license": "MIT",
"peer": true "peer": true
}, },
"node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"node_modules/dotenv": { "node_modules/dotenv": {
"version": "17.4.2", "version": "17.4.2",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
@@ -5826,6 +5330,7 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
@@ -6373,12 +5878,6 @@
"url": "https://opencollective.com/express" "url": "https://opencollective.com/express"
} }
}, },
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
"license": "MIT"
},
"node_modules/find-up": { "node_modules/find-up": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -6719,21 +6218,6 @@
"hermes-estree": "0.25.1" "hermes-estree": "0.25.1"
} }
}, },
"node_modules/hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"license": "BSD-3-Clause",
"dependencies": {
"react-is": "^16.7.0"
}
},
"node_modules/hoist-non-react-statics/node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
"node_modules/hono": { "node_modules/hono": {
"version": "4.12.18", "version": "4.12.18",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz",
@@ -6878,6 +6362,8 @@
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"dependencies": { "dependencies": {
"hasown": "^2.0.2" "hasown": "^2.0.2"
}, },
@@ -7584,18 +7070,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"license": "MIT",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -8241,7 +7715,9 @@
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"license": "MIT" "license": "MIT",
"optional": true,
"peer": true
}, },
"node_modules/path-to-regexp": { "node_modules/path-to-regexp": {
"version": "6.3.0", "version": "6.3.0",
@@ -8254,6 +7730,8 @@
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@@ -8435,23 +7913,6 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/prop-types/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/proxy-addr": { "node_modules/proxy-addr": {
"version": "2.0.7", "version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -8648,12 +8109,6 @@
"react": "^19.2.5" "react": "^19.2.5"
} }
}, },
"node_modules/react-is": {
"version": "19.2.5",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.5.tgz",
"integrity": "sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==",
"license": "MIT"
},
"node_modules/react-oidc-context": { "node_modules/react-oidc-context": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/react-oidc-context/-/react-oidc-context-3.3.1.tgz", "resolved": "https://registry.npmjs.org/react-oidc-context/-/react-oidc-context-3.3.1.tgz",
@@ -8774,22 +8229,6 @@
} }
} }
}, },
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
"license": "BSD-3-Clause",
"dependencies": {
"@babel/runtime": "^7.5.5",
"dom-helpers": "^5.0.1",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": ">=16.6.0",
"react-dom": ">=16.6.0"
}
},
"node_modules/recast": { "node_modules/recast": {
"version": "0.23.11", "version": "0.23.11",
"resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz",
@@ -8847,17 +8286,13 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/reselect": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
"license": "MIT"
},
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.12", "version": "1.22.12",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
"integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==",
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"dependencies": { "dependencies": {
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"is-core-module": "^2.16.1", "is-core-module": "^2.16.1",
@@ -9328,15 +8763,6 @@
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -9470,17 +8896,13 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
"license": "MIT"
},
"node_modules/supports-preserve-symlinks-flag": { "node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
}, },
-5
View File
@@ -13,12 +13,7 @@
"test:node": "node --test tests/*.test.mjs" "test:node": "node --test tests/*.test.mjs"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@fontsource-variable/geist": "^5.2.8", "@fontsource-variable/geist": "^5.2.8",
"@mui/icons-material": "^9.0.0",
"@mui/material": "^9.0.0",
"@mui/x-data-grid": "^9.0.4",
"@tanstack/react-query": "^5.100.6", "@tanstack/react-query": "^5.100.6",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
@@ -1389,3 +1389,227 @@ Slice 7b is complete (59/71). The remaining 12 unchecked lines are:
`docs/REQUIREMENTS.md`, exit gate). `docs/REQUIREMENTS.md`, exit gate).
No slice-7b work remains. No slice-7b work remains.
## Slice 6b reconciliation (stale checkboxes fixed during Slice 8) — COMPLETE
When Slice 8 began, `tasks.md` reported Slice 6b as 5 unchecked lines and the
`apply-progress.md` Slice 7b section listed 6b as still-pending ("`UsersPage.impl.tsx`
still uses `@mui/icons-material` (9) + `@mui/material`"). **However the actual source
was already fully migrated**: a later session had landed Slice 6b (compose dialog →
shadcn `Dialog` family, the 9 lucide icons, `Input`/`Textarea`/`Separator`, and the
`insertMarkup`/`FormData`/queue/send behavior) and added a header comment
("Slice 6b: … The file is now fully @mui-free"), but never flipped the `tasks.md`
checkboxes or appended a 6b progress section.
Verification of the completed 6b work (run during Slice 8):
- `grep -rlE '@mui/(material|icons-material|x-data-grid)' --include='*.ts' --include='*.tsx' src`
**ZERO-MUI-IN-SOURCE** (zero `@mui` imports in any source file, including
`UsersPage.impl.tsx`).
- `UsersPage.impl.tsx` imports the 9 lucide icons (`X, Paperclip, Bold, Italic, Link,
List, Mail, Send, Trash2`), the shadcn `Dialog`/`DialogContent`/`DialogDescription`/
`DialogFooter`/`DialogHeader`/`DialogTitle`, plus `Input`/`Textarea`/`Separator`/`Label`.
- `src/pages/__tests__/UsersPage.test.tsx` contains the 6b-required tests:
selection toggle ("toggles row selection and reflects the selected-count badge"),
drawer open ("opens the user drawer when a row is clicked"), and a compose
formatting action (`describe("UsersPage (slice 6b — compose dialog formatting
actions)")` → "opens compose and inserts bold markup into the html body").
Per the **Persisted Task Checkbox Contract** ("Before returning … ensure completed
work is visibly marked `- [x]`; if the artifact still shows a completed task as
`- [ ]`, fix the checkbox"), the 5 stale Slice 6b checkboxes were reconciled to
`- [x]`. **No `frontend/src` source file was edited for this reconciliation** — it
is pure bookkeeping for verifiably-complete prior work (the parent prompt declared
"Slices 17b DONE and committed" and "All MUI component migration is complete",
which matches the source). Change task progress after this reconciliation:
59 → **64/71** (the 5 6b lines), then Slice 8 → **71/71**.
## Slice 8 — Cleanup + docs (remove MUI/@emotion, final gates, docs) — COMPLETE
Final slice. All MUI component migration was already complete (slices 17b), so
this slice removed the now-unused `@mui/*` + `@emotion/*` dependencies, reconciled
the last stale generated docs so the literal zero-MUI grep gate passes, ran the
final gates, and updated `docs/REQUIREMENTS.md`. All 7 Slice 8 task lines in
`tasks.md` are now `- [x]`. **Cumulative change task progress: 64 → 71/71 (complete).**
### Status context consumed
- `applyState` reported by the status engine: **blocked** (`blockedReasons`:
domain specs missing/partial; legacy flat `spec.md` present without domain specs).
Same planning-completeness gap as slices 17b — **not** a safety or `actionContext`
blocker. `design.md`/`tasks.md` are authoritative for this slice.
- `actionContext`: `mode: repo-local`, `workspaceRoot: /home/user/Manage_01`,
`allowedEditRoots: ["/home/user/Manage_01"]`, `warnings: []` — safe.
- This run executed the explicitly delegated **Slice 8 (Cleanup + docs)** scope per
the parent acceptance contract, which also supplied the resolved delivery path
(single PR, ≤400 lines). `instructions.apply`: "Implement only unchecked tasks
from the tasks artifact."
- `artifactStore: openspec`; persisted task checkboxes updated in `tasks.md`
(Slice 8: 0 → 7 `[x]`; plus the 5 reconciled Slice 6b lines).
### Part A — Remove unused MUI/@emotion deps
1. **Pre-uninstall consumer grep:** `grep -rlE '@mui/(material|icons-material|x-data-grid)|@emotion/(react|styled)' --include='*.ts' --include='*.tsx' frontend/src`
→ **ZERO-MUI-IN-SOURCE** (no source consumer remained; safe to uninstall).
2. **Removed from `frontend/package.json`** via
`npm uninstall @mui/material @mui/icons-material @mui/x-data-grid @emotion/react @emotion/styled`
→ "removed 40 packages"; `package-lock.json` regenerated. `deps-grep` runtime
check confirms all 7 targets (`@mui/material`, `@mui/icons-material`,
`@mui/x-data-grid`, `@emotion/react`, `@emotion/styled`, `recharts`, `d3`) now
report **removed**.
3. **recharts / d3 re-confirmation (carry-over from slice 1):** absent from
`package.json` and `grep -rlE "from ['\"](recharts|d3|d3-)" frontend/src` →
**ZERO-RECHARTS-D3**.
4. **theme.ts re-confirmation (carry-over from slice 1):** `test ! -e
frontend/src/theme.ts` → **gone**; `grep -rln 'getAppTheme' frontend/src` →
**NO-THEME-REFS**.
### Generated-doc reconciliation (so the literal zero-MUI grep gate passes)
After all 7 source-level migrations, the only remaining `@mui`/`@emotion` text under
`frontend/src` was in two **gitignored generated** `.pi-map.md` docs
(`src/components/.pi-map.md`, `src/pages/.pi-map.md`) — 15 + 7 stale dependency tokens
left over from before the migration. The parent's literal runtime gate
`grep -rlE '@mui/(material|icons-material|x-data-grid)|@emotion/(react|styled)' src`
matches these `.md` files, so (per the slice-1 precedent of minimally reconciling these
generated maps when `project_map_patch` is unavailable) the stale `@mui/*`/
`@emotion/*` dependency tokens were stripped from both files. After reconciliation:
`grep … src` → **ZERO-MUI-IN-SRC**. These are gitignored generated artifacts; a full
`project_map` regeneration is recommended later (the `project_map_patch` tool was
unavailable in this session). No source `.ts`/`.tsx` file was touched.
### Part B — Final zero-MUI gate (all four green)
Run from `frontend/`:
| Command | Result | Notes |
|---|---|---|
| `npm run build` (`tsc -b && vite build`) | **pass (exit 0)** | 1959 modules; pre-existing >500 kB chunk-size warning only (not a failure). |
| `npm run lint` (`eslint .`) | **pass (exit 0)** | 0 errors. 2 **pre-existing** `react-hooks/exhaustive-deps` warnings in `UsersPage.impl.tsx` (present since before slice 1; warnings, not errors). |
| `npm test` (`vitest run`) | **pass (exit 0)** | **23 files / 64 tests** passed (no flake this run). |
| `node --test tests/*.test.mjs` (`npm run test:node`) | **pass (exit 0)** | 4/4 legacy node suites green. |
> `node --test tests` (bare-directory form) fails with `Cannot find module '…/tests'` —
> the documented **pre-existing Node 22.22.2 invocation quirk** (a bare directory arg is
> resolved as a CJS/ESM module entry, not a test directory) noted in every prior slice.
> The legacy mjs suites themselves are green via the package's canonical command
> `node --test tests/*.test.mjs` (npm script `test:node`, 4/4). The acceptance intent
> ("legacy mjs suites green") is satisfied; the bare form is a Node invocation quirk,
> not a suite failure. `frontend/package.json` and `frontend/tests/` were not modified
> this slice.
### Part C — Update `docs/REQUIREMENTS.md` (per `AGENTS.md`)
Added a new top-level **"Frontend Design System & Architecture"** section (after
"Current Phase") and a **2026-06-17 decision-log** entry documenting: the single design
system (shadcn/ui + Tailwind v4 + lucide-react; CSS `@theme` tokens in `src/index.css`,
primary `#4f8cff`); the **thin-dashboard observability model** (no in-app charting;
Alertmanager alerts + Prometheus target health + Grafana deep-links; the legacy D3
charts/POSIX collector superseded); **TanStack Table** behind a `DataTable` wrapper with
**visibility-only parity** (pagination, row selection, row click, column visibility;
no sorting/resizing; Media server-driven pagination); the **reconciled IA**
(`/backups` top-level nav; Media at `/media` with `/applications` redirect mirroring
`/monitoring`→`/observability`); the **repurposed `chart-1..5`** status/Grafana-link
color cues; the **removal** of `@mui/*`, `@emotion/*`, `recharts`, `d3`, `theme.ts`;
and the **Vitest + @testing-library/react** test harness (plus legacy node suites).
Also updated two directly-contradicted "current requirement" bullets (AG-Grid file
table → TanStack `DataTable`; the D3 monitoring-charts bullet → superseded note
pointing to the Grafana model). `grep -lE 'shadcn|TanStack|Grafana' docs/REQUIREMENTS.md`
→ **docs-updated** (shadcn×3, TanStack×4, Grafana×11, lucide-react×2). Historical
D3/decision-log entries were preserved (history), only superseded by the new entry.
### Files changed (tracked)
- `frontend/package.json` (removed `@mui/material`, `@mui/icons-material`,
`@mui/x-data-grid`, `@emotion/react`, `@emotion/styled`).
- `frontend/package-lock.json` (regenerated by `npm uninstall`; 40 packages removed).
- `docs/REQUIREMENTS.md` (new "Frontend Design System & Architecture" section +
2026-06-17 decision-log entry + 2 superseded-bullet updates).
- `openspec/changes/web-ui-rework/tasks.md` (Slice 8: 7 `[ ]`→`[x]`; Slice 6b: 5 stale
`[ ]`→`[x]` reconciliation).
- `openspec/changes/web-ui-rework/apply-progress.md` (this section).
Gitignored (generated docs, not tracked) — reconciled to clear the literal gate:
- `frontend/src/components/.pi-map.md`, `frontend/src/pages/.pi-map.md` (stripped stale
`@mui/*` / `@emotion/*` dependency tokens).
**Untouched (scope respected):** no `frontend/src/**/*.{ts,tsx}` source file was
edited this slice — all component migration was already complete (slices 17b).
`frontend/package.json` `scripts`/`tests/` were not modified.
### Slice boundary / PR
Single cleanup PR, well under the 400-line budget: `package.json` (5 lines),
lockfile churn (npm-managed), ~60 lines of docs additions, and OpenSpec checkbox/
progress edits. No sub-split needed. The parent owns the commit/PR; nothing committed
here.
## Overall migration completion summary (Slices 18)
The **web-ui-rework** change is fully applied: **71/71 tasks `[x]`**, `frontend/src` is
100% free of `@mui/*` and `@emotion/*`, and the entire frontend runs on the single
shadcn/ui + Tailwind v4 + lucide-react design system.
- **Slice 1** — Foundation: 13 shadcn primitives, `@tanstack/react-table`, the Vitest +
Testing Library harness, `success`/`warning` Badge variants, `chart-1..5` role
comments; removed `recharts`/`d3`/`theme.ts`.
- **Slice 2** — 11 shared components MUI-free (cards/dialogs/tables/panels) + 11 tests.
- **Slice 3** — Backups cluster (5 components) MUI-free + reconciled IA (`/backups`
top-level nav; Media at `/media`; `/applications` redirect).
- **Slice 4** — Dashboard + Applications/Media shell MUI-free.
- **Slice 5** — Settings + Actions (form-heavy pair) MUI-free, no form library.
- **Slice 6a/6b** — Users directory surface + drawer + rich-text compose dialog + 9
lucide icons MUI-free.
- **Slice 7a/7b** — `DataTable` (TanStack Table, visibility-only) wrapper + FileBrowser
- Media (server-driven pagination) off `@mui/x-data-grid`.
- **Slice 8** — Removed `@mui/*`/`@emotion/*` deps, reconciled stale generated docs,
final gates green, `docs/REQUIREMENTS.md` updated.
Final gate (post-uninstall): `npm run build` ✅, `npm run lint` ✅ (0 errors),
`npm test` ✅ (23 files / 64 tests), `node --test tests/*.test.mjs` ✅ (4/4).
`grep '@mui/…|@emotion/…' frontend/src` → **zero**.
## Residual risks / notes for sdd-verify
- **`node --test tests` (bare) vs `node --test tests/*.test.mjs`:** the literal
`node --test tests` invocation in the tasks.md exit-gate line fails on Node
22.22.2 (`Cannot find module '…/tests'`) — a pre-existing invocation quirk, not a
suite failure. The legacy mjs suites pass via the package script `test:node` =
`node --test tests/*.test.mjs` (4/4). `sdd-verify` should treat `test:node` as
canonical; the bare form is expected to fail on this Node version across every slice.
- **2 pre-existing `react-hooks/exhaustive-deps` warnings** in
`UsersPage.impl.tsx` (`baseRows` + `metrics` memos) — present since before slice 1,
warnings not errors, lint exits 0. Out of cleanup-slice scope (would be a separate
code-quality fix; behavior is correct).
- **Known vitest flake** on `UsersPage.test.tsx` "opens compose and inserts bold
markup" under parallel load (documented in the 6a/7a/7b notes). It passes in
isolation and the full suite was 23/23 this run; `sdd-verify` may see an occasional
parallel-load flake — re-run resolves it.
- **Generated `.pi-map.md` reconciliation is a minimal token strip**, not a full
`project_map` regeneration (the `project_map_patch` tool was unavailable this
session). The dep summaries in `src/components/.pi-map.md` and `src/pages/.pi-map.md`
no longer list `@mui/*`/`@emotion/*` (clearing the gate) but are otherwise stale;
a proper `project_map` regeneration is recommended before the next freshness-
sensitive architectural handoff.
- **Change `applyState` is still reported `blocked`** by the status engine (domain
specs missing/partial; legacy flat `spec.md` without domain specs). With all 71/71
implementation tasks now `[x]`, this is the **only** remaining blocker for
`sdd-verify`→sync→archive. It is a planning/spec-format gap (not a code/`actionContext`
issue): resolve by converting/supplementing the flat `spec.md` into domain specs, or
by having the orchestrator confirm the flat spec is acceptable, before archiving.
- **`npm audit`** reports 8 vulnerabilities in the dependency tree (1 low, 3 moderate,
4 high) — pre-existing and unrelated to this slice (the MUI/emotion removal did not
introduce them); out of scope.
- **Slice 6b checkbox reconciliation:** the 5 Slice 6b checkboxes were flipped during
Slice 8 because the source/tests proved the work complete but the prior session left
them unchecked. `sdd-verify` should spot-check `UsersPage.impl.tsx` (zero `@mui`
imports, 9 lucide icons, shadcn `Dialog`) and `UsersPage.test.tsx` (compose-bold
test) to confirm the reconciliation was correct — no new code was written for 6b in
this slice.
### Next recommended
`sdd-verify` — all implementation tasks are complete (71/71), the final gates are
green, and `frontend/src` is MUI/`@emotion`-free. After verification, resolve the
legacy-flat-`spec.md`/domain-specs planning gap, then `sdd-sync` + `sdd-archive`.
+12 -12
View File
@@ -199,11 +199,11 @@ Each slice section restates this gate as its final task.
### Slice 6b — compose dialog, formatting actions, attachments ### Slice 6b — compose dialog, formatting actions, attachments
- [ ] Migrate the compose dialog (`Dialog`/`DialogActions`/`DialogContent`/`DialogTitle` + `TextField`/`Divider`/`IconButton`) → shadcn `Dialog` family + `Input`/`Textarea`/`Separator` + `Button variant="ghost" size="icon"`. - [x] Migrate the compose dialog (`Dialog`/`DialogActions`/`DialogContent`/`DialogTitle` + `TextField`/`Divider`/`IconButton`) → shadcn `Dialog` family + `Input`/`Textarea`/`Separator` + `Button variant="ghost" size="icon"`.
- [ ] Replace the 9 `@mui/icons-material` icons with lucide per design §5: `Close→X`, `AttachFile→Paperclip`, `FormatBold→Bold`, `FormatItalic→Italic`, `Link→Link`, `FormatListBulleted→List`, `MailOutlined→Mail`, `Send→Send`, `DeleteOutlined→Trash2`. - [x] Replace the 9 `@mui/icons-material` icons with lucide per design §5: `Close→X`, `AttachFile→Paperclip`, `FormatBold→Bold`, `FormatItalic→Italic`, `Link→Link`, `FormatListBulleted→List`, `MailOutlined→Mail`, `Send→Send`, `DeleteOutlined→Trash2`.
- [ ] Preserve the rich-text compose behavior: subject + html body, markup insertion actions (bold/italic/link/list), file attachments (FormData), queue-status polling (`useUserMessageQueueStatus`), and send (`useSendUserMessage`). - [x] Preserve the rich-text compose behavior: subject + html body, markup insertion actions (bold/italic/link/list), file attachments (FormData), queue-status polling (`useUserMessageQueueStatus`), and send (`useSendUserMessage`).
- [ ] Add component tests for selection toggle, drawer open, and at least one compose formatting action. - [x] Add component tests for selection toggle, drawer open, and at least one compose formatting action.
- [ ] **Exit gate (6a+6b):** `UsersPage.impl.tsx` fully MUI/icon-MUI-free; drawer, selection-across-pages, and compose/send behavior preserved; `npm run build` + `npm run lint` + `npm test` + `node --test tests` green on each sub-PR. - [x] **Exit gate (6a+6b):** `UsersPage.impl.tsx` fully MUI/icon-MUI-free; drawer, selection-across-pages, and compose/send behavior preserved; `npm run build` + `npm run lint` + `npm test` + `node --test tests` green on each sub-PR.
--- ---
@@ -239,13 +239,13 @@ Each slice section restates this gate as its final task.
> ~80160 lines, single PR. Depends on all prior slices. `@mui/*` + `@emotion/*` are > ~80160 lines, single PR. Depends on all prior slices. `@mui/*` + `@emotion/*` are
> removed only after every consumer is gone. > removed only after every consumer is gone.
- [ ] Remove from `frontend/package.json`: `@mui/material`, `@mui/icons-material`, `@mui/x-data-grid`, `@emotion/react`, `@emotion/styled` (run `npm install`/regenerate the lockfile). - [x] Remove from `frontend/package.json`: `@mui/material`, `@mui/icons-material`, `@mui/x-data-grid`, `@emotion/react`, `@emotion/styled` (run `npm install`/regenerate the lockfile).
- [ ] Grep-verify ZERO remaining imports: recursive search of `frontend/src` for `@mui/material`, `@mui/icons-material`, `@mui/x-data-grid`, `@emotion/react`, `@emotion/styled` returns no matches (hard gate for the spec "No MUI imports remain" scenario). - [x] Grep-verify ZERO remaining imports: recursive search of `frontend/src` for `@mui/material`, `@mui/icons-material`, `@mui/x-data-grid`, `@emotion/react`, `@emotion/styled` returns no matches (hard gate for the spec "No MUI imports remain" scenario).
- [ ] Grep-verify `recharts`, `d3`, `d3-*` have zero imports and are absent from `package.json` (carry-over from slice 1; re-confirm). - [x] Grep-verify `recharts`, `d3`, `d3-*` have zero imports and are absent from `package.json` (carry-over from slice 1; re-confirm).
- [ ] Confirm `frontend/src/theme.ts` does not exist and no `theme`/`getAppTheme` import remains. - [x] Confirm `frontend/src/theme.ts` does not exist and no `theme`/`getAppTheme` import remains.
- [ ] Run final gates from `frontend/`: `npm run build` (tsc -b + vite build), `npm run lint`, `npm test`, and `node --test tests` — all green. - [x] Run final gates from `frontend/`: `npm run build` (tsc -b + vite build), `npm run lint`, `npm test`, and `node --test tests` — all green.
- [ ] Update `docs/REQUIREMENTS.md` per `AGENTS.md`: document the single design system (shadcn/ui + Tailwind v4 + lucide-react), the thin-dashboard observability model (no in-app charts; Grafana deep-links), TanStack tables (visibility-only parity), the reconciled IA (Backups top-level nav; Media at `/media` with `/applications` redirect), the repurposed `chart-*` status cues, and the removal of `@mui/*`/`@emotion/*`/`recharts`/`d3`/`theme.ts`. - [x] Update `docs/REQUIREMENTS.md` per `AGENTS.md`: document the single design system (shadcn/ui + Tailwind v4 + lucide-react), the thin-dashboard observability model (no in-app charts; Grafana deep-links), TanStack tables (visibility-only parity), the reconciled IA (Backups top-level nav; Media at `/media` with `/applications` redirect), the repurposed `chart-*` status cues, and the removal of `@mui/*`/`@emotion/*`/`recharts`/`d3`/`theme.ts`.
- [ ] **Exit gate:** recursive search of `frontend/src` for `@mui/*` and `@emotion/*` returns zero; requirements doc updated; `npm run build` + `npm run lint` + `npm test` + `node --test tests` all green. - [x] **Exit gate:** recursive search of `frontend/src` for `@mui/*` and `@emotion/*` returns zero; requirements doc updated; `npm run build` + `npm run lint` + `npm test` + `node --test tests` all green.
--- ---